<|start_filename|>src/test/java/de/elbatya/cryptocoins/bittrexclient/api/BittrexAccountApiTest.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.api;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.elbatya.cryptocoins.bittrexclient.api.model.accountapi.*;
import de.elbatya.cryptocoins.bittrexclient.api.model.common.ApiResult;
import de.elbatya.cryptocoins.bittrexclient.config.ObjectMapperConfigurer;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.mock.HttpMethod;
import feign.mock.MockClient;
import feign.mock.MockTarget;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * @author <EMAIL>
 */
public class BittrexAccountApiTest {

    public static final String MARKET = "btc-eth";
    public static final String CURRENCY = "btc";

    private MockClient mockClient;
    private BittrexAccountApi api;

    private InputStream load(String file) {
        return getClass().getClassLoader().getResourceAsStream("accountapi/"+file);
    }

    @Before
    public void setUp() throws Exception {
        ClassLoader cl = getClass().getClassLoader();

        mockClient = new MockClient()
                .ok(HttpMethod.GET, "/account/getbalances", load("getbalances.json"))
                .ok(HttpMethod.GET, "/account/getbalance?currency=btc", load("getbalance.json"))
                .ok(HttpMethod.GET, "/account/getdepositaddress?currency=btc", load("getdepositaddress.json"))
                .ok(HttpMethod.GET, "/account/getdeposithistory", load("getdeposithistory.json"))
                .ok(HttpMethod.GET, "/account/getdeposithistory?currency=btc", load("getdeposithistory.json"))
                .ok(HttpMethod.GET, "/account/getorder?uuid=1234", load("getorder.json"))
                .ok(HttpMethod.GET, "/account/getorderhistory", load("getorderhistory.json"))
                .ok(HttpMethod.GET, "/account/getorderhistory?market=btc-eth", load("getorderhistoryformarket.json"))
                .ok(HttpMethod.GET, "/account/getwithdrawalhistory?currency=btc", load("getwithdrawalhistory.json"))
                .ok(HttpMethod.GET, "/account/getwithdrawalhistory", load("getwithdrawalhistory.json"))
                .ok(HttpMethod.GET, "/account/withdraw?currency=btc&quantity=11.0&address=BTC_ADDRESS", load("withdraw.json"))
                .ok(HttpMethod.GET, "/account/withdraw?currency=btc&quantity=11.0&address=BTC_ADDRESS&paymentid=note", load("withdraw.json"))
        ;

        ObjectMapper strictMapper = ObjectMapperConfigurer.configure(new ObjectMapper());
        strictMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

        api = Feign.builder()
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder(strictMapper))
                .client(mockClient)
                .target(new MockTarget<>(BittrexAccountApi.class));
    }

    @Test
    public void getBalances() throws Exception {
        ApiResult<List<Balance>> balances = api.getBalances();
        assertThat(balances).isNotNull();
        assertThat(balances.isSuccess()).isTrue();
        assertThat(balances.getResult()).isNotEmpty();
    }

    @Test
    public void getBalance() throws Exception {
        ApiResult<Balance> balance = api.getBalance(CURRENCY);
        assertThat(balance).isNotNull();
        assertThat(balance.isSuccess()).isTrue();
        assertThat(balance.getResult()).isNotNull();
    }

    @Test
    public void getDepositAddress() throws Exception {
        ApiResult<DepositAddress> depositAddress = api.getDepositAddress(CURRENCY);
        assertThat(depositAddress).isNotNull();
        assertThat(depositAddress.isSuccess()).isTrue();
        assertThat(depositAddress.getResult()).isNotNull();
    }

    @Test
    public void getOrder() throws Exception {
        ApiResult<Order> order = api.getOrder("1234");
        assertThat(order).isNotNull();
        assertThat(order.isSuccess()).isTrue();
        assertThat(order.getResult()).isNotNull();
    }

    @Test
    public void getOrderHistory() throws Exception {
        ApiResult<List<OrderHistoryEntry>> orderHistory = api.getOrderHistory();
        assertThat(orderHistory).isNotNull();
        assertThat(orderHistory.isSuccess()).isTrue();
        assertThat(orderHistory.getResult()).isNotEmpty();
    }

    @Test
    public void getOrderHistoryForMarket() throws Exception {
        ApiResult<List<OrderHistoryEntry>> orderHistory = api.getOrderHistory(MARKET);
        assertThat(orderHistory).isNotNull();
        assertThat(orderHistory.isSuccess()).isTrue();
        assertThat(orderHistory.getResult()).isNotEmpty();
    }

    @Test
    public void getWithdrawalHistory() throws Exception {
        ApiResult<List<WithdrawalHistoryEntry>> orderHistory = api.getWithdrawalHistory();
        assertThat(orderHistory).isNotNull();
        assertThat(orderHistory.isSuccess()).isTrue();
        assertThat(orderHistory.getResult()).isNotEmpty();
    }

    @Test
    public void getWithdrawalHistoryForMarket() throws Exception {
        ApiResult<List<WithdrawalHistoryEntry>> orderHistory = api.getWithdrawalHistory(CURRENCY);
        assertThat(orderHistory).isNotNull();
        assertThat(orderHistory.isSuccess()).isTrue();
        assertThat(orderHistory.getResult()).isNotEmpty();
    }

    @Test
    public void getDepositHistory() throws Exception {
        ApiResult<List<DepositHistoryEntry>> depositHistory = api.getDepositHistory();
        assertThat(depositHistory).isNotNull();
        assertThat(depositHistory.isSuccess()).isTrue();
        assertThat(depositHistory.getResult()).isNotEmpty();
    }

    @Test
    public void getDepositHistoryForCurrency() throws Exception {
        ApiResult<List<DepositHistoryEntry>> depositHistory = api.getDepositHistory(CURRENCY);
        assertThat(depositHistory).isNotNull();
        assertThat(depositHistory.isSuccess()).isTrue();
        assertThat(depositHistory.getResult()).isNotEmpty();
    }


    @Test
    public void withdraw() throws Exception {
        ApiResult<WithdrawalRequested> depositHistory = api.withdraw(
                CURRENCY,
                BigDecimal.valueOf(11.0),
                "BTC_ADDRESS");
        assertThat(depositHistory).isNotNull();
        assertThat(depositHistory.isSuccess()).isTrue();
        assertThat(depositHistory.getResult()).isNotNull();
    }


    @Test
    public void withdrawWithPaymentId() throws Exception {
        ApiResult<WithdrawalRequested> depositHistory = api.withdraw(
                CURRENCY,
                BigDecimal.valueOf(11.0),
                "BTC_ADDRESS",
                "note"
        );
        assertThat(depositHistory).isNotNull();
        assertThat(depositHistory.isSuccess()).isTrue();
        assertThat(depositHistory.getResult()).isNotNull();
    }



}

<|start_filename|>src/main/java/de/elbatya/cryptocoins/bittrexclient/api/BittrexMarketApi.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.api;

import de.elbatya.cryptocoins.bittrexclient.api.model.common.ApiResult;
import de.elbatya.cryptocoins.bittrexclient.api.model.marketapi.OpenOrder;
import de.elbatya.cryptocoins.bittrexclient.api.model.marketapi.OrderCreated;
import feign.Param;
import feign.RequestLine;

import java.math.BigDecimal;
import java.util.List;

/**
 * @author <EMAIL>
 */
public interface BittrexMarketApi {

    @RequestLine("GET /market/getopenorders")
    ApiResult<List<OpenOrder>> getOpenOrders();

    @RequestLine("GET /market/getopenorders?market={market}")
    ApiResult<List<OpenOrder>> getOpenOrders(@Param("market") String market);

    @RequestLine("GET /market/cancel?uuid={orderUuid}")
    ApiResult<Void> cancelOrder(@Param("orderUuid") String orderUuid);

    @RequestLine("GET /market/selllimit?market={market}&quantity={quantity}&rate={rate}")
    ApiResult<OrderCreated> sellLimit(
            @Param("market") String market,
            @Param("quantity") BigDecimal quantity,
            @Param("rate") BigDecimal rate
    );

    @RequestLine("GET /market/buylimit?market={market}&quantity={quantity}&rate={rate}")
    ApiResult<OrderCreated> buyLimit(
            @Param("market") String market,
            @Param("quantity") BigDecimal quantity,
            @Param("rate") BigDecimal rate
    );


}


<|start_filename|>src/main/java/de/elbatya/cryptocoins/bittrexclient/api/model/common/BittrexApiException.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.api.model.common;

/**
 * @author <EMAIL>
 */
public class BittrexApiException extends RuntimeException {

    public BittrexApiException() {
    }

    public BittrexApiException(String message) {
        super(message);
    }

    public BittrexApiException(String message, Throwable cause) {
        super(message, cause);
    }

    public BittrexApiException(Throwable cause) {
        super(cause);
    }

    public BittrexApiException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}


<|start_filename|>src/main/java/de/elbatya/cryptocoins/bittrexclient/config/ApiCredentials.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.config;

/**
 * @author <EMAIL>
 */
public class ApiCredentials {

    private String key;
    private String secret;

    public ApiCredentials() {
    }

    public ApiCredentials(String key, String secret) {
        this.key = key;
        this.secret = secret;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }
}


<|start_filename|>src/main/java/de/elbatya/cryptocoins/bittrexclient/BittrexClient.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient;


import de.elbatya.cryptocoins.bittrexclient.api.BittrexAccountApi;
import de.elbatya.cryptocoins.bittrexclient.api.BittrexMarketApi;
import de.elbatya.cryptocoins.bittrexclient.api.BittrexPublicApi;
import de.elbatya.cryptocoins.bittrexclient.config.ApiBuilderFactory;
import de.elbatya.cryptocoins.bittrexclient.config.ApiCredentials;
import feign.Feign;
import feign.Logger;
import feign.Util;
import feign.slf4j.Slf4jLogger;

import javax.annotation.Nullable;

/**
 * @author <EMAIL>
 */
public class BittrexClient {

    public static final String DEFAULT_BASE_URL = "https://bittrex.com/api/v1.1";

    private BittrexPublicApi publicApi;
    private BittrexMarketApi marketApi;
    private BittrexAccountApi accountApi;

    private boolean credentialsAvailable = true;

    public BittrexClient() {
        this(DEFAULT_BASE_URL, null, null);
    }

    public BittrexClient(@Nullable Logger.Level logLevel) {
        this(DEFAULT_BASE_URL, null, logLevel);
    }

    public BittrexClient(@Nullable ApiCredentials credentials) {
        this(DEFAULT_BASE_URL, credentials, null);
    }

    public BittrexClient(@Nullable ApiCredentials credentials, @Nullable Logger.Level logLevel) {
        this(DEFAULT_BASE_URL, credentials, logLevel);
    }


    public BittrexClient(
            String baseUrl,
            @Nullable ApiCredentials credentials,
            @Nullable Logger.Level logLevel)
    {
        Util.checkNotNull(baseUrl, "The baseUrl must not be null!");

        ApiBuilderFactory apiBuilderFactory = new ApiBuilderFactory(baseUrl);

        Feign.Builder apiBuilder = apiBuilderFactory.createApiBuilder(credentials);

        if (logLevel != null) {
            apiBuilder
                    .logger(new Slf4jLogger(BittrexClient.class))
                    .logLevel(logLevel);
        }

        publicApi = apiBuilder.target(BittrexPublicApi.class, baseUrl);

        credentialsAvailable = credentials != null;

        if(credentialsAvailable) {
            marketApi = apiBuilder.target(BittrexMarketApi.class, baseUrl);
            accountApi = apiBuilder.target(BittrexAccountApi.class, baseUrl);
        }
    }

    public BittrexPublicApi getPublicApi() {
        return publicApi;
    }
    public BittrexMarketApi getMarketApi() {
        failIfNoCredentials("You can't use the MarketAPI without credentials.");
        return marketApi;
    }
    public BittrexAccountApi getAccountApi() {
        failIfNoCredentials("You can't use the AccountAPI without credentials.");
        return accountApi;
    }

    private void failIfNoCredentials(String message){
        if(!credentialsAvailable){
            throw new RuntimeException(message);
        }
    }
}


<|start_filename|>src/main/java/de/elbatya/cryptocoins/bittrexclient/config/ObjectMapperConfigurer.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.config;


import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

/**
 * @author <EMAIL>
 */
public class ObjectMapperConfigurer {

    public static ObjectMapper configure(ObjectMapper mapper){

    return mapper
        .registerModule(new ParameterNamesModule())
        .registerModule(new Jdk8Module())
        .registerModule(new JavaTimeModule())
        .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
    }

}


<|start_filename|>src/test/java/de/elbatya/cryptocoins/bittrexclient/util/ApiKeySigningUtilTest.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.util;

import org.junit.Test;

import java.util.stream.IntStream;

import static org.assertj.core.api.Assertions.assertThat;


/**
 * @author <EMAIL>
 */
public class ApiKeySigningUtilTest {

    @Test
    public void createNonce() throws Exception {
        long count = IntStream.range(0,100000)
                .mapToObj(i -> ApiKeySigningUtil.createNonce())
                .distinct()
                .count();

        assertThat(count).isEqualTo(100000L);
    }

    @Test
    public void createSign() throws Exception {
        String sign = ApiKeySigningUtil.createSign("test","secret");
        String expectedSign =
                "f8a4f0a209167bc192a1bffaa01ecdb0" +
                "9e06c57f96530d92ec9ccea0090d290e" +
                "55071306d6b654f26ae0c8721f7e48a2" +
                "d7130b881151f2cec8d61d941a6be88a";

        assertThat(sign).isEqualTo(expectedSign);
    }

}

<|start_filename|>src/main/java/de/elbatya/cryptocoins/bittrexclient/api/BittrexAccountApi.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.api;

import de.elbatya.cryptocoins.bittrexclient.api.model.accountapi.*;
import de.elbatya.cryptocoins.bittrexclient.api.model.common.ApiResult;
import feign.Param;
import feign.RequestLine;

import java.math.BigDecimal;
import java.util.List;

/**
 * @author <EMAIL>
 */
public interface BittrexAccountApi {

    @RequestLine("GET /account/getbalances")
    ApiResult<List<Balance>> getBalances();

    @RequestLine("GET /account/getbalance?currency={currency}")
    ApiResult<Balance> getBalance(@Param("currency") String currency);

    @RequestLine("GET /account/getdepositaddress?currency={currency}")
    ApiResult<DepositAddress> getDepositAddress(@Param("currency") String currency);

    @RequestLine("GET /account/withdraw?currency={currency}&quantity={quantity}&address={address}&paymentid={paymentid}")
    ApiResult<WithdrawalRequested> withdraw(
            @Param("currency") String currency,
            @Param("quantity") BigDecimal quantity,
            @Param("address") String address,
            @Param("paymentid") String paymentId
    );

    @RequestLine("GET /account/withdraw?currency={currency}&quantity={quantity}&address={address}")
    ApiResult<WithdrawalRequested> withdraw(
            @Param("currency") String currency,
            @Param("quantity") BigDecimal quantity,
            @Param("address") String address
    );

    @RequestLine("GET /account/getorder?uuid={uuid}")
    ApiResult<Order> getOrder(@Param("uuid") String uuid);

    @RequestLine("GET /account/getorderhistory?market={market}")
    ApiResult<List<OrderHistoryEntry>> getOrderHistory(@Param("market") String market);

    @RequestLine("GET /account/getorderhistory")
    ApiResult<List<OrderHistoryEntry>> getOrderHistory();

    @RequestLine("GET /account/getwithdrawalhistory?currency={currency}")
    ApiResult<List<WithdrawalHistoryEntry>> getWithdrawalHistory(@Param("currency") String currency);

    @RequestLine("GET /account/getwithdrawalhistory")
    ApiResult<List<WithdrawalHistoryEntry>> getWithdrawalHistory();

    @RequestLine("GET /account/getdeposithistory?currency={currency}")
    ApiResult<List<DepositHistoryEntry>> getDepositHistory(@Param("currency") String currency);

    @RequestLine("GET /account/getdeposithistory")
    ApiResult<List<DepositHistoryEntry>> getDepositHistory();

}


<|start_filename|>src/main/java/de/elbatya/cryptocoins/bittrexclient/api/model/common/ApiResult.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.api.model.common;

import java.util.Optional;

/**
 * @author <EMAIL>
 */
public class ApiResult<T> {
    private boolean success;
    private String message;
    private T result;

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getResult() {
        return result;
    }

    public Optional<T> getResultAsOptional() {
        return Optional.ofNullable(result);
    }

    public T unwrap() throws BittrexApiException {
        if (result == null) {
            String errorMessage = String.format("Message from Bittrex server: %s", this.message);
            throw new BittrexApiException(errorMessage);
        }
        return result;
    }

}


<|start_filename|>src/main/java/de/elbatya/cryptocoins/bittrexclient/api/BittrexPublicApi.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.api;

import de.elbatya.cryptocoins.bittrexclient.api.model.common.ApiResult;
import de.elbatya.cryptocoins.bittrexclient.api.model.publicapi.*;
import feign.Param;
import feign.RequestLine;

import java.util.List;

/**
 * @author <EMAIL>
 */
public interface BittrexPublicApi {

    @RequestLine("GET /public/getmarkets")
    ApiResult<List<Market>> getMarkets();

    @RequestLine("GET /public/getcurrencies ")
    ApiResult<List<Currency>> getCurrencies();

    @RequestLine("GET /public/getticker?market={market}")
    ApiResult<Ticker> getTicker(@Param("market") String market);

    @RequestLine("GET /public/getmarketsummaries")
    ApiResult<List<MarketSummary>> getMarketSummaries();

    @RequestLine("GET /public/getmarketsummary?market={market}")
    ApiResult<List<MarketSummary>> getMarketSummary(@Param("market") String market);

    @RequestLine("GET /public/getorderbook?type=both&market={market}&depth={depth}")
    ApiResult<OrderBook> getOrderBook(
            @Param("market") String market,
            @Param("depth") int depth
    );

    @RequestLine("GET /public/getorderbook?type=both&market={market}")
    ApiResult<OrderBook> getOrderBook(
            @Param("market") String market
    );

    @RequestLine("GET /public/getorderbook?type=sell&market={market}&depth={depth}")
    ApiResult<List<OrderBookEntry>> getOrderBookForSell(
            @Param("market") String market,
            @Param("depth") int depth
    );

    @RequestLine("GET /public/getorderbook?type=sell&market={market}")
    ApiResult<List<OrderBookEntry>> getOrderBookForSell(
            @Param("market") String market
    );

    @RequestLine("GET /public/getorderbook?type=buy&market={market}&depth={depth}")
    ApiResult<List<OrderBookEntry>> getOrderBookForBuy(
            @Param("market") String market,
            @Param("depth") int depth
    );

    @RequestLine("GET /public/getorderbook?type=buy&market={market}")
    ApiResult<List<OrderBookEntry>> getOrderBookForBuy(
            @Param("market") String market
    );


    @RequestLine("GET /public/getmarkethistory?market={market}")
    ApiResult<List<MarketHistoryEntry>> getMarketHistory(@Param("market") String market);
}


<|start_filename|>src/test/java/de/elbatya/cryptocoins/bittrexclient/api/BittrexPublicApiTest.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.api;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.elbatya.cryptocoins.bittrexclient.api.model.common.ApiResult;
import de.elbatya.cryptocoins.bittrexclient.api.model.publicapi.*;
import de.elbatya.cryptocoins.bittrexclient.config.ObjectMapperConfigurer;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.mock.HttpMethod;
import feign.mock.MockClient;
import feign.mock.MockTarget;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;


/**
 * @author <EMAIL>
 */
public class BittrexPublicApiTest {

    private MockClient mockClient;
    private BittrexPublicApi api;
    private final static String MARKET = "btc-eth";

    private InputStream load(String file) {
        return getClass().getClassLoader().getResourceAsStream("publicapi/"+file);
    }

    @Before
    public void setUp() throws Exception {

        ClassLoader cl = getClass().getClassLoader();

        mockClient = new MockClient()
        .ok(HttpMethod.GET, "/public/getmarkets", load("getmarkets.json"))
        .ok(HttpMethod.GET, "/public/getcurrencies", load("getcurrencies.json"))
        .ok(HttpMethod.GET, "/public/getticker?market=btc-eth", load("getticker.json"))
        .ok(HttpMethod.GET, "/public/getmarketsummaries", load("getmarketsummaries.json"))
        .ok(HttpMethod.GET, "/public/getmarketsummary?market=btc-eth", load("getmarketsummary.json"))
        .ok(HttpMethod.GET, "/public/getorderbook?type=both&market=btc-eth", load("getorderbookboth.json"))
        .ok(HttpMethod.GET, "/public/getorderbook?type=both&market=btc-eth&depth=10", load("getorderbookboth.json"))
        .ok(HttpMethod.GET, "/public/getorderbook?type=sell&market=btc-eth", load("getorderbooksell.json"))
        .ok(HttpMethod.GET, "/public/getorderbook?type=sell&market=btc-eth&depth=10", load("getorderbooksell.json"))
        .ok(HttpMethod.GET, "/public/getorderbook?type=buy&market=btc-eth", load("getorderbookbuy.json"))
        .ok(HttpMethod.GET, "/public/getorderbook?type=buy&market=btc-eth&depth=10", load("getorderbookbuy.json"))
        .ok(HttpMethod.GET, "/public/getmarkethistory?market=btc-eth", load("getmarkethistory.json"));


        ObjectMapper strictMapper = ObjectMapperConfigurer.configure(new ObjectMapper());
        strictMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

        api = Feign.builder()
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder(strictMapper))
                .client(mockClient)
                .target(new MockTarget<>(BittrexPublicApi.class));
    }

    @Test
    public void getMarkets() throws Exception {
        ApiResult<List<Market>> markets = api.getMarkets();
        assertThat(markets).isNotNull();
        assertThat(markets.isSuccess()).isTrue();
        assertThat(markets.getResult()).isNotEmpty();
    }

    @Test
    public void getCurrencies() throws Exception {
        ApiResult<List<Currency>> currencies = api.getCurrencies();
        assertThat(currencies).isNotNull();
        assertThat(currencies.isSuccess()).isTrue();
        assertThat(currencies.getResult()).isNotEmpty();
    }

    @Test
    public void getTicker() throws Exception {
        ApiResult<Ticker> ticker = api.getTicker(MARKET);
        assertThat(ticker).isNotNull();
        assertThat(ticker.isSuccess()).isTrue();
        assertThat(ticker.getResult()).isNotNull();
    }

    @Test
    public void getMarketSummaries() throws Exception {
        ApiResult<List<MarketSummary>> marketSummaries = api.getMarketSummaries();
        assertThat(marketSummaries).isNotNull();
        assertThat(marketSummaries.isSuccess()).isTrue();
        assertThat(marketSummaries.getResult()).isNotEmpty();
    }

    @Test
    public void getMarketSummary() throws Exception {
        ApiResult<List<MarketSummary>> marketSummary = api.getMarketSummary(MARKET);
        assertThat(marketSummary).isNotNull();
        assertThat(marketSummary.isSuccess()).isTrue();
        assertThat(marketSummary.getResult()).isNotEmpty();
    }

    @Test
    public void getOrderBook() throws Exception {
        ApiResult<OrderBook> orderBook = api.getOrderBook(MARKET);
        assertThat(orderBook).isNotNull();
        assertThat(orderBook.isSuccess()).isTrue();
        assertThat(orderBook.getResult()).isNotNull();
        assertThat(orderBook.getResult().getBuy()).isNotEmpty();
        assertThat(orderBook.getResult().getSell()).isNotEmpty();
    }

    @Test
    public void getOrderBookWithDepth() throws Exception {
        ApiResult<OrderBook> orderBook = api.getOrderBook(MARKET, 10);
        assertThat(orderBook).isNotNull();
        assertThat(orderBook.isSuccess()).isTrue();
        assertThat(orderBook.getResult()).isNotNull();
    }

    @Test
    public void getOrderBookForSell() throws Exception {
        ApiResult<List<OrderBookEntry>> orderBookForSell = api.getOrderBookForSell(MARKET);
        assertThat(orderBookForSell).isNotNull();
        assertThat(orderBookForSell.isSuccess()).isTrue();
        assertThat(orderBookForSell.getResult()).isNotEmpty();
    }

    @Test
    public void getOrderBookForSellWithDepth() throws Exception {
        ApiResult<List<OrderBookEntry>> orderBookForSell = api.getOrderBookForSell(MARKET, 10);
        assertThat(orderBookForSell).isNotNull();
        assertThat(orderBookForSell.isSuccess()).isTrue();
        assertThat(orderBookForSell.getResult()).isNotEmpty();
    }

    @Test
    public void getOrderBookForBuy() throws Exception {
        ApiResult<List<OrderBookEntry>> orderBookForBuy = api.getOrderBookForBuy(MARKET);
        assertThat(orderBookForBuy).isNotNull();
        assertThat(orderBookForBuy.isSuccess()).isTrue();
        assertThat(orderBookForBuy.getResult()).isNotEmpty();
    }

    @Test
    public void getOrderBookForBuyWithDepth() throws Exception {
        ApiResult<List<OrderBookEntry>> orderBookForBuy = api.getOrderBookForBuy(MARKET, 10);
        assertThat(orderBookForBuy).isNotNull();
        assertThat(orderBookForBuy.isSuccess()).isTrue();
        assertThat(orderBookForBuy.getResult()).isNotEmpty();
    }

    @Test
    public void getMarketHistory() throws Exception {
        ApiResult<List<MarketHistoryEntry>> marketHistory = api.getMarketHistory(MARKET);
        assertThat(marketHistory).isNotNull();
        assertThat(marketHistory.isSuccess()).isTrue();
        assertThat(marketHistory.getResult()).isNotEmpty();
    }

}

<|start_filename|>src/test/java/de/elbatya/cryptocoins/bittrexclient/api/BittrexMarketApiTest.java<|end_filename|>
package de.elbatya.cryptocoins.bittrexclient.api;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.elbatya.cryptocoins.bittrexclient.api.model.common.ApiResult;
import de.elbatya.cryptocoins.bittrexclient.api.model.marketapi.OpenOrder;
import de.elbatya.cryptocoins.bittrexclient.api.model.marketapi.OrderCreated;
import de.elbatya.cryptocoins.bittrexclient.config.ObjectMapperConfigurer;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.mock.HttpMethod;
import feign.mock.MockClient;
import feign.mock.MockTarget;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * @author <EMAIL>
 */
public class BittrexMarketApiTest {


    public static final String MARKET = "btc-eth";
    private MockClient mockClient;
    private BittrexMarketApi api;

    private InputStream load(String file) {
        return getClass().getClassLoader().getResourceAsStream("marketapi/"+file);
    }

    @Before
    public void setUp() throws Exception {
        ClassLoader cl = getClass().getClassLoader();

        mockClient = new MockClient()
        .ok(HttpMethod.GET, "/market/getopenorders", load("getopenorders.json"))
        .ok(HttpMethod.GET, "/market/getopenorders?market=btc-eth", load("getopenorders.json"))
        .ok(HttpMethod.GET, "/market/cancel?uuid=1234", load("cancelorder.json"))
        .ok(HttpMethod.GET, "/market/selllimit?market=btc-eth&quantity=1&rate=2", load("selllimit.json"))
        .ok(HttpMethod.GET, "/market/buylimit?market=btc-eth&quantity=3&rate=4", load("buylimit.json"));

        ObjectMapper strictMapper = ObjectMapperConfigurer.configure(new ObjectMapper());
        strictMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

        api = Feign.builder()
                    .encoder(new JacksonEncoder())
                    .decoder(new JacksonDecoder(strictMapper))
                    .client(mockClient)
                    .target(new MockTarget<>(BittrexMarketApi.class));
    }

    @Test
    public void getOpenOrders() throws Exception {
        ApiResult<List<OpenOrder>> openOrders = api.getOpenOrders();
        assertThat(openOrders).isNotNull();
        assertThat(openOrders.isSuccess()).isTrue();
        assertThat(openOrders.getResult()).isNotEmpty();
    }

    @Test
    public void getOpenOrdersForMarket() throws Exception {
        ApiResult<List<OpenOrder>> openOrders = api.getOpenOrders(MARKET);
        assertThat(openOrders).isNotNull();
        assertThat(openOrders.isSuccess()).isTrue();
        assertThat(openOrders.getResult()).isNotEmpty();
    }

    @Test
    public void cancelOrder() throws Exception {
        ApiResult<Void> openOrders = api.cancelOrder("1234");
        assertThat(openOrders).isNotNull();
        assertThat(openOrders.isSuccess()).isTrue();
    }

    @Test
    public void sellLimit() throws Exception {
        ApiResult<OrderCreated> sellOrder = api.sellLimit(MARKET, BigDecimal.ONE, BigDecimal.valueOf(2));
        assertThat(sellOrder).isNotNull();
        assertThat(sellOrder.isSuccess()).isTrue();
        assertThat(sellOrder.unwrap().getUuid()).isEqualTo("selluuid");
    }

    @Test
    public void buyLimit() throws Exception {
        ApiResult<OrderCreated> buyOrder = api.buyLimit(MARKET, BigDecimal.valueOf(3), BigDecimal.valueOf(4));
        assertThat(buyOrder).isNotNull();
        assertThat(buyOrder.isSuccess()).isTrue();
        assertThat(buyOrder.unwrap().getUuid()).isEqualTo("buyuuid");
    }


}