diff --git a/README.md b/README.md
index 5de6a90..3be3b01 100644
--- a/README.md
+++ b/README.md
@@ -15,18 +15,18 @@ demonstrating the usage of Riko. Feel free to use it as a starter for your own p
com.github.rishabh9
riko
- 2.0.2-SNAPSHOT
+ 3.0.0-SNAPSHOT
```
### For Gradle based project
```groovy
dependencies {
- implementation 'com.github.rishabh9:riko:2.0.2-SNAPSHOT'
+ implementation 'com.github.rishabh9:riko:3.0.0-SNAPSHOT'
}
```
### For SBT based project
```scala
-libraryDependencies += "com.github.rishabh9" % "riko" % "2.0.2-SNAPSHOT"
+libraryDependencies += "com.github.rishabh9" % "riko" % "3.0.0-SNAPSHOT"
```
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index b4cc428..cbc9d40 100644
--- a/build.gradle
+++ b/build.gradle
@@ -47,7 +47,7 @@ dependencyManagement {
// GroupId
group = 'com.github.rishabh9'
// Version
-version = '2.0.2-SNAPSHOT'
+version = '3.0.0-SNAPSHOT'
archivesBaseName = 'riko'
dependencies {
@@ -56,7 +56,7 @@ dependencies {
// These dependencies are used internally, and not exposed to consumers on their own compile classpath.
// Developer's toolkit
- implementation 'com.google.guava:guava:23.0'
+ implementation 'com.google.guava:guava:27.0.1-jre'
implementation 'net.jodah:failsafe:1.1.1'
// Making API calls
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/common/RetryPolicyFactory.java b/src/main/java/com/github/rishabh9/riko/upstox/common/RetryPolicyFactory.java
new file mode 100644
index 0000000..46ac49c
--- /dev/null
+++ b/src/main/java/com/github/rishabh9/riko/upstox/common/RetryPolicyFactory.java
@@ -0,0 +1,55 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 Rishabh Joshi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.rishabh9.riko.upstox.common;
+
+import net.jodah.failsafe.RetryPolicy;
+
+import javax.annotation.Nonnull;
+import java.util.Optional;
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * A simple factory to create policies for retrying when an API call fails.
+ * Riko uses the open source Failsafe
+ * library for implementing retries.
+ *
+ * @see RikoRetryPolicyFactory
+ */
+public interface RetryPolicyFactory {
+
+ /**
+ * @return A {@link RetryPolicy} that expresses when retries should be performed.
+ * An {@code empty} {@link RetryPolicy} indicates retries should be disabled.
+ */
+ @Nonnull
+ Optional createRetryPolicy();
+
+ /**
+ * @return A {@link ScheduledExecutorService} to allow for asynchronous executions.
+ * Cannot be {@code null}.
+ */
+ @Nonnull
+ ScheduledExecutorService createExecutorService();
+}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/common/RikoRetryPolicyFactory.java b/src/main/java/com/github/rishabh9/riko/upstox/common/RikoRetryPolicyFactory.java
new file mode 100644
index 0000000..bbbe7cb
--- /dev/null
+++ b/src/main/java/com/github/rishabh9/riko/upstox/common/RikoRetryPolicyFactory.java
@@ -0,0 +1,59 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 Rishabh Joshi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.rishabh9.riko.upstox.common;
+
+import net.jodah.failsafe.RetryPolicy;
+
+import java.util.Optional;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * The Riko's default retry policy factory.
+ *
+ * @see RetryPolicyFactory
+ */
+public class RikoRetryPolicyFactory implements RetryPolicyFactory {
+
+ /**
+ * @return The default {@link RetryPolicy}
+ */
+ @Override
+ public Optional createRetryPolicy() {
+ return Optional.of(new RetryPolicy()
+ .retryOn(Throwable.class)
+ .withBackoff(1, 5, TimeUnit.SECONDS)
+ .withMaxRetries(3));
+ }
+
+ /**
+ * @return The default {@link ScheduledExecutorService} to be used by {@link RetryPolicy}.
+ */
+ @Override
+ public ScheduledExecutorService createExecutorService() {
+ return Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
+ }
+}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/common/Service.java b/src/main/java/com/github/rishabh9/riko/upstox/common/Service.java
index a2df7f9..b787c0b 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/common/Service.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/common/Service.java
@@ -27,11 +27,13 @@
import com.github.rishabh9.riko.upstox.common.models.ApiCredentials;
import com.github.rishabh9.riko.upstox.common.models.AuthHeaders;
import com.github.rishabh9.riko.upstox.login.models.AccessToken;
+import net.jodah.failsafe.RetryPolicy;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import java.util.Objects;
+import java.util.concurrent.ScheduledExecutorService;
/**
* Parent class for every Service class. Holds common methods.
@@ -41,13 +43,20 @@ public abstract class Service {
private static final Logger log = LogManager.getLogger(Service.class);
protected final UpstoxAuthService upstoxAuthService;
+ protected final RetryPolicy retryPolicy;
+ protected final ScheduledExecutorService retryExecutor;
/**
* @param upstoxAuthService The service to retrieve authentication details
*/
- public Service(@Nonnull final UpstoxAuthService upstoxAuthService) {
+ public Service(@Nonnull final UpstoxAuthService upstoxAuthService,
+ @Nonnull final RetryPolicyFactory retryPolicyFactory) {
this.upstoxAuthService = Objects.requireNonNull(upstoxAuthService);
+ this.retryPolicy = Objects.requireNonNull(retryPolicyFactory).createRetryPolicy()
+ // The default behaviour is not to re-try.
+ .orElse(new RetryPolicy().withMaxRetries(0));
+ this.retryExecutor = Objects.requireNonNull(retryPolicyFactory).createExecutorService();
}
protected T prepareServiceApi(@Nonnull final Class type) {
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/common/ServiceGenerator.java b/src/main/java/com/github/rishabh9/riko/upstox/common/ServiceGenerator.java
index 1f97d45..d0ceb73 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/common/ServiceGenerator.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/common/ServiceGenerator.java
@@ -128,7 +128,7 @@ public void rebuildWithUrl(HttpUrl url) {
public S createService(@Nonnull final Class serviceClass) {
log.debug("Creating service without authentication");
- return createService(Objects.requireNonNull(serviceClass), null, null);
+ return createService(Objects.requireNonNull(serviceClass), null);
}
/**
@@ -141,19 +141,14 @@ public S createService(@Nonnull final Class serviceClass) {
* @return The retrofitted service
*/
public S createService(@Nonnull final Class serviceClass,
- @Nullable final String username,
- @Nullable final String password) {
+ @Nonnull final String username,
+ @Nonnull final String password) {
- if (!Strings.isNullOrEmpty(username)
- && !Strings.isNullOrEmpty(password)) {
final String authToken = Credentials.basic(username, password);
log.debug("Creating service with Basic authentication");
return createService(
Objects.requireNonNull(serviceClass),
- new AuthHeaders(authToken, username));
- }
- // Setup request headers without any auth
- return createService(Objects.requireNonNull(serviceClass), null);
+ new AuthHeaders(Objects.requireNonNull(authToken), Objects.requireNonNull(username)));
}
/**
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/common/constants/LiveFeedType.java b/src/main/java/com/github/rishabh9/riko/upstox/common/constants/LiveFeedType.java
index 3a277ca..ca1e5a5 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/common/constants/LiveFeedType.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/common/constants/LiveFeedType.java
@@ -25,6 +25,7 @@
package com.github.rishabh9.riko.upstox.common.constants;
public final class LiveFeedType {
- public static final String LTP = "LTP";
- public static final String FULL = "Full";
+ public static final String LTP = "ltp";
+ public static final String FULL = "full";
+ public static final String ALL = "all";
}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/common/constants/PropertyKeys.java b/src/main/java/com/github/rishabh9/riko/upstox/common/constants/PropertyKeys.java
index e350943..aa449cd 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/common/constants/PropertyKeys.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/common/constants/PropertyKeys.java
@@ -53,5 +53,5 @@ public class PropertyKeys {
public static final int RIKO_WS_SERVER_PORT_DEFAULT = 443;
public static final String RIKO_WS_RECONNECT = "riko.ws.reconnect";
- public static final String RIKO_WS_RECONNECT_DEFAULT = "true";
+ public static final String RIKO_WS_RECONNECT_DEFAULT = "false";
}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/common/constants/RateLimits.java b/src/main/java/com/github/rishabh9/riko/upstox/common/constants/RateLimits.java
new file mode 100644
index 0000000..21f8d18
--- /dev/null
+++ b/src/main/java/com/github/rishabh9/riko/upstox/common/constants/RateLimits.java
@@ -0,0 +1,48 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 Rishabh Joshi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.rishabh9.riko.upstox.common.constants;
+
+public class RateLimits {
+ public static final double LIVE_FEED_RATE_LIMIT = 1.0D;
+ public static final double SUBSCRIBE_RATE_LIMIT = 1.0D;
+ public static final double UNSUBSCRIBE_RATE_LIMIT = 1.0D;
+ public static final double SYMBOLS_SUBSCRIBED_RATE_LIMIT = 1.0D;
+ public static final double HISTORICAL_RATE_LIMIT = 10.0D;
+ public static final double LOGIN_RATE_LIMIT = 1.0D;
+ public static final double ORDER_HISTORY_RATE_LIMIT = 1.0D;
+ public static final double ORDER_DETAILS_RATE_LIMIT = 1.0D;
+ public static final double TRADE_BOOK_RATE_LIMIT = 1.0D;
+ public static final double TRADE_HISTORY_RATE_LIMIT = 1.0D;
+ public static final double PLACE_ORDER_RATE_LIMIT = 10.0D;
+ public static final double MODIFY_ORDER_RATE_LIMIT = 1.0D;
+ public static final double CANCEL_ORDER_RATE_LIMIT = 1.0D;
+ public static final double PROFILE_RATE_LIMIT = 1.0D;
+ public static final double BALANCE_RATE_LIMIT = 1.0D;
+ public static final double POSITIONS_RATE_LIMIT = 1.0D;
+ public static final double HOLDINGS_RATE_LIMIT = 1.0D;
+ public static final double MASTER_CONTRACT_RATE_LIMIT = 1.0D;
+ public static final double WS_PARAMS_RATE_LIMIT = 1.0D;
+ public static final double WEB_SOCKET_RATE_LIMIT = 1.0D;
+}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/feed/FeedApi.java b/src/main/java/com/github/rishabh9/riko/upstox/feed/FeedApi.java
index 7aa9a87..872a793 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/feed/FeedApi.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/feed/FeedApi.java
@@ -26,6 +26,7 @@
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
import com.github.rishabh9.riko.upstox.feed.models.Feed;
+import com.github.rishabh9.riko.upstox.feed.models.Subscription;
import com.github.rishabh9.riko.upstox.feed.models.SubscriptionResponse;
import retrofit2.http.GET;
import retrofit2.http.Path;
@@ -76,4 +77,13 @@ CompletableFuture> subscribe(@Path("type")
CompletableFuture> unsubscribe(@Path("type") String type,
@Path("exchange") String exchange,
@Query("symbol") String symbolsCsv);
+
+ /**
+ * Get list of symbols subscribed.
+ *
+ * @param type 'all' or 'ltp' or 'full'.
+ * @return A CompletableFuture to execute the request (a)synchronously.
+ */
+ @GET("/live/feed/{type}")
+ CompletableFuture> symbolsSubscribed(@Path("type") String type);
}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/feed/FeedService.java b/src/main/java/com/github/rishabh9/riko/upstox/feed/FeedService.java
index cb9634f..ab2113f 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/feed/FeedService.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/feed/FeedService.java
@@ -24,28 +24,41 @@
package com.github.rishabh9.riko.upstox.feed;
+import com.github.rishabh9.riko.upstox.common.RetryPolicyFactory;
import com.github.rishabh9.riko.upstox.common.Service;
import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
import com.github.rishabh9.riko.upstox.feed.models.Feed;
+import com.github.rishabh9.riko.upstox.feed.models.Subscription;
import com.github.rishabh9.riko.upstox.feed.models.SubscriptionResponse;
import com.google.common.base.Strings;
+import com.google.common.util.concurrent.RateLimiter;
+import net.jodah.failsafe.Failsafe;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import java.util.concurrent.CompletableFuture;
+import static com.github.rishabh9.riko.upstox.common.constants.RateLimits.*;
+
+@SuppressWarnings("UnstableApiUsage")
public class FeedService extends Service {
private static final Logger log = LogManager.getLogger(FeedService.class);
+ private static final RateLimiter liveFeedRateLimiter = RateLimiter.create(LIVE_FEED_RATE_LIMIT);
+ private static final RateLimiter subscribeRateLimiter = RateLimiter.create(SUBSCRIBE_RATE_LIMIT);
+ private static final RateLimiter unsubscribeRateLimiter = RateLimiter.create(UNSUBSCRIBE_RATE_LIMIT);
+ private static final RateLimiter symbolsSubscribedRateLimiter = RateLimiter.create(SYMBOLS_SUBSCRIBED_RATE_LIMIT);
+
/**
* @param upstoxAuthService The service to retrieve authentication details
*/
- public FeedService(@Nonnull final UpstoxAuthService upstoxAuthService) {
+ public FeedService(@Nonnull final UpstoxAuthService upstoxAuthService,
+ @Nonnull final RetryPolicyFactory retryPolicyFactory) {
- super(upstoxAuthService);
+ super(upstoxAuthService, retryPolicyFactory);
}
/**
@@ -67,7 +80,17 @@ public CompletableFuture> liveFeed(@Nonnull final String ex
final FeedApi api = prepareServiceApi(FeedApi.class);
log.debug("Making request - GET Live Feed");
- return api.liveFeed(exchange, symbol, type);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Live Feed.", failure))
+ .onSuccess(response -> log.debug("GET Live Feed successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Live Feed, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ liveFeedRateLimiter.acquire(1);
+ return api.liveFeed(exchange, symbol, type);
+ });
}
/**
@@ -89,7 +112,17 @@ public CompletableFuture> subscribe(@Nonnul
final FeedApi api = prepareServiceApi(FeedApi.class);
log.debug("Making request - GET Subscribe");
- return api.subscribe(type, exchange, symbolsCsv);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Subscribe.", failure))
+ .onSuccess(response -> log.debug("GET Subscribe successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Subscribe, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ subscribeRateLimiter.acquire(1);
+ return api.subscribe(type, exchange, symbolsCsv);
+ });
}
/**
@@ -111,7 +144,46 @@ public CompletableFuture> unsubscribe(@Nonn
final FeedApi api = prepareServiceApi(FeedApi.class);
log.debug("Making request - GET Unsubscribe");
- return api.unsubscribe(type, exchange, symbolsCsv);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Unsubscribe.", failure))
+ .onSuccess(response -> log.debug("GET Unsubscribe successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Unsubscribe, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ unsubscribeRateLimiter.acquire(1);
+ return api.unsubscribe(type, exchange, symbolsCsv);
+ });
+ }
+
+
+ /**
+ * Get list of symbols subscribed.
+ *
+ * @param type 'all' or 'ltp' or 'full'. Any. Mandatory.
+ * @return List of symbols subscribed
+ */
+ public CompletableFuture> symbolsSubscribed(@Nonnull final String type) {
+
+ log.debug("Validate parameters - GET Symbols Subscribed");
+ validatePathParameter(type);
+
+ log.debug("Preparing service - GET Symbols Subscribed");
+ final FeedApi api = prepareServiceApi(FeedApi.class);
+
+ log.debug("Making request - GET Symbols Subscribed");
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Symbols Subscribed.", failure))
+ .onSuccess(response -> log.debug("GET Symbols Subscribed successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Symbols Subscribed, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ symbolsSubscribedRateLimiter.acquire(1);
+ return api.symbolsSubscribed(type);
+ });
}
private void validatePathParameters(String... values) {
@@ -125,4 +197,11 @@ private void validatePathParameters(String... values) {
}
}
}
+
+ private void validatePathParameter(String value) {
+ if (Strings.isNullOrEmpty(value)) {
+ log.error("Argument validation failed. Arguments 'type' is mandatory.");
+ throw new IllegalArgumentException("Argument validation failed. Arguments 'type' is mandatory.");
+ }
+ }
}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/feed/models/Subscription.java b/src/main/java/com/github/rishabh9/riko/upstox/feed/models/Subscription.java
new file mode 100644
index 0000000..8b27a4c
--- /dev/null
+++ b/src/main/java/com/github/rishabh9/riko/upstox/feed/models/Subscription.java
@@ -0,0 +1,77 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 Rishabh Joshi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.rishabh9.riko.upstox.feed.models;
+
+import com.google.common.base.MoreObjects;
+import com.google.gson.annotations.SerializedName;
+
+import java.util.List;
+import java.util.Objects;
+
+public class Subscription {
+
+ @SerializedName("LTP")
+ private List ltp;
+ @SerializedName("FULL")
+ private List full;
+
+ public List getLtp() {
+ return ltp;
+ }
+
+ public void setLtp(List ltp) {
+ this.ltp = ltp;
+ }
+
+ public List getFull() {
+ return full;
+ }
+
+ public void setFull(List full) {
+ this.full = full;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Subscription that = (Subscription) o;
+ return Objects.equals(ltp, that.ltp) &&
+ Objects.equals(full, that.full);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ltp, full);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("ltp", ltp)
+ .add("full", full)
+ .toString();
+ }
+}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/feed/models/SymbolSubscribed.java b/src/main/java/com/github/rishabh9/riko/upstox/feed/models/SymbolSubscribed.java
new file mode 100644
index 0000000..f505064
--- /dev/null
+++ b/src/main/java/com/github/rishabh9/riko/upstox/feed/models/SymbolSubscribed.java
@@ -0,0 +1,73 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 Rishabh Joshi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.rishabh9.riko.upstox.feed.models;
+
+import com.google.common.base.MoreObjects;
+
+import java.util.Objects;
+
+public class SymbolSubscribed {
+
+ private String exchange;
+ private String symbol;
+
+ public String getExchange() {
+ return exchange;
+ }
+
+ public void setExchange(String exchange) {
+ this.exchange = exchange;
+ }
+
+ public String getSymbol() {
+ return symbol;
+ }
+
+ public void setSymbol(String symbol) {
+ this.symbol = symbol;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SymbolSubscribed that = (SymbolSubscribed) o;
+ return Objects.equals(exchange, that.exchange) &&
+ Objects.equals(symbol, that.symbol);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(exchange, symbol);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("exchange", exchange)
+ .add("symbol", symbol)
+ .toString();
+ }
+}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/historical/HistoricalApi.java b/src/main/java/com/github/rishabh9/riko/upstox/historical/HistoricalApi.java
index 452a183..e3db144 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/historical/HistoricalApi.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/historical/HistoricalApi.java
@@ -45,24 +45,26 @@ public interface HistoricalApi {
* @param symbol Trading symbol. Mandatory.
* @param interval Allowed Values:
*
- * 1MINUTE
- * 5MINUTE
- * 10MINUTE
- * 30MINUTE
- * 60MINUTE
- * 1DAY
(default)
- * 1WEEK
- * 1MONTH
+ * 1
+ * 3
+ * 5
+ * 10
+ * 15
+ * 30
+ * 60
+ * day
+ * week
+ * month
*
- * @param startDate Date in the format: DD-MM-YYYY
. Default value is 15 days before today.
+ * @param startDate Date in the format: DD-MM-YYYY
. Default value is 7 days before today.
* @param endDate Date in the format: DD-MM-YYYY
. Default value is today.
* @param format Response format - 'csv' or 'json'.
* @return A Call to execute the request (a)synchronously.
*/
- @GET("/historical/ohlc/{exchange}/{symbol}")
+ @GET("/historical/ohlc/{exchange}/{symbol}/{interval}")
CompletableFuture>> getOhlc(@Path("exchange") String exchange,
@Path("symbol") String symbol,
- @Query("interval") String interval,
+ @Path("interval") String interval,
@Query("start_date") String startDate,
@Query("end_date") String endDate,
@Query("format") String format);
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/historical/HistoricalService.java b/src/main/java/com/github/rishabh9/riko/upstox/historical/HistoricalService.java
index ffa7280..8038bcc 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/historical/HistoricalService.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/historical/HistoricalService.java
@@ -24,11 +24,14 @@
package com.github.rishabh9.riko.upstox.historical;
+import com.github.rishabh9.riko.upstox.common.RetryPolicyFactory;
import com.github.rishabh9.riko.upstox.common.Service;
import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
import com.github.rishabh9.riko.upstox.historical.models.Candle;
import com.google.common.base.Strings;
+import com.google.common.util.concurrent.RateLimiter;
+import net.jodah.failsafe.Failsafe;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -36,16 +39,22 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
+import static com.github.rishabh9.riko.upstox.common.constants.RateLimits.HISTORICAL_RATE_LIMIT;
+
+@SuppressWarnings("UnstableApiUsage")
public class HistoricalService extends Service {
private static final Logger log = LogManager.getLogger(HistoricalService.class);
+ private static final RateLimiter historicalRateLimiter = RateLimiter.create(HISTORICAL_RATE_LIMIT);
+
/**
* @param upstoxAuthService The service to retrieve authentication details
*/
- public HistoricalService(@Nonnull final UpstoxAuthService upstoxAuthService) {
+ public HistoricalService(@Nonnull final UpstoxAuthService upstoxAuthService,
+ @Nonnull final RetryPolicyFactory retryPolicyFactory) {
- super(upstoxAuthService);
+ super(upstoxAuthService, retryPolicyFactory);
}
/**
@@ -55,43 +64,55 @@ public HistoricalService(@Nonnull final UpstoxAuthService upstoxAuthService) {
* @param symbol Trading symbol. Mandatory.
* @param interval Allowed Values:
*
- * 1MINUTE
- * 5MINUTE
- * 10MINUTE
- * 30MINUTE
- * 60MINUTE
- * 1DAY
(default)
- * 1WEEK
- * 1MONTH
+ * 1
+ * 3
+ * 5
+ * 10
+ * 15
+ * 30
+ * 60
+ * day
+ * week
+ * month
*
* @param startDate Date in the format: DD-MM-YYYY
.
- * Default value is 15 days before today.
+ * Default value is 7 days before today.
* @param endDate Date in the format: DD-MM-YYYY
.
* Default value is today.
* @return List of Candle
*/
public CompletableFuture>> getOhlc(@Nonnull final String exchange,
@Nonnull final String symbol,
- final String interval,
+ @Nonnull final String interval,
final String startDate,
final String endDate) {
log.debug("Validate parameters - GET OHLC");
- validatePathParameters(exchange, symbol);
+ validatePathParameters(exchange, symbol, interval);
log.debug("Preparing service - GET OHLC");
final HistoricalApi api = prepareServiceApi(HistoricalApi.class);
log.debug("Making request - GET OHLC");
- return api.getOhlc(exchange, symbol, interval, startDate, endDate, "json");
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET OHLC.", failure))
+ .onSuccess(response -> log.debug("GET OHLC successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET OHLC, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ historicalRateLimiter.acquire(1);
+ return api.getOhlc(exchange, symbol, interval, startDate, endDate, "json");
+ });
}
private void validatePathParameters(String... values) {
for (String value : values) {
if (Strings.isNullOrEmpty(value)) {
- log.error("Argument validation failed. Arguments 'exchange' and 'symbol' are mandatory.");
+ log.error("Argument validation failed. Arguments 'exchange', 'symbol' and 'interval' are mandatory.");
throw new IllegalArgumentException(
- "Arguments 'exchange' and 'symbol' are mandatory. They cannot be null nor empty.");
+ "Arguments 'exchange', 'symbol' and 'interval' are mandatory. They cannot be null nor empty.");
}
}
}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/login/LoginService.java b/src/main/java/com/github/rishabh9/riko/upstox/login/LoginService.java
index 3faf582..dc2beef 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/login/LoginService.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/login/LoginService.java
@@ -24,11 +24,15 @@
package com.github.rishabh9.riko.upstox.login;
+import com.github.rishabh9.riko.upstox.common.RetryPolicyFactory;
+import com.github.rishabh9.riko.upstox.common.Service;
import com.github.rishabh9.riko.upstox.common.ServiceGenerator;
import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
import com.github.rishabh9.riko.upstox.login.models.AccessToken;
import com.github.rishabh9.riko.upstox.login.models.TokenRequest;
import com.google.common.base.Strings;
+import com.google.common.util.concurrent.RateLimiter;
+import net.jodah.failsafe.Failsafe;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -36,18 +40,22 @@
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
-public class LoginService {
+import static com.github.rishabh9.riko.upstox.common.constants.RateLimits.LOGIN_RATE_LIMIT;
+
+@SuppressWarnings("UnstableApiUsage")
+public class LoginService extends Service {
private static final Logger log = LogManager.getLogger(LoginService.class);
- private final UpstoxAuthService upstoxAuthService;
+ private static final RateLimiter loginRateLimiter = RateLimiter.create(LOGIN_RATE_LIMIT);
/**
* @param upstoxAuthService The service to retrieve authentication details.
*/
- public LoginService(@Nonnull final UpstoxAuthService upstoxAuthService) {
+ public LoginService(@Nonnull final UpstoxAuthService upstoxAuthService,
+ @Nonnull final RetryPolicyFactory retryPolicyFactory) {
- this.upstoxAuthService = Objects.requireNonNull(upstoxAuthService);
+ super(upstoxAuthService, retryPolicyFactory);
}
/**
@@ -71,6 +79,16 @@ public CompletableFuture getAccessToken(@Nonnull final TokenRequest
upstoxAuthService.getApiCredentials().getApiKey(),
upstoxAuthService.getApiCredentials().getApiSecret());
- return loginApi.getAccessToken(request);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET AccessToken.", failure))
+ .onSuccess(response -> log.debug("GET AccessToken successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET AccessToken, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ loginRateLimiter.acquire(1);
+ return loginApi.getAccessToken(request);
+ });
}
}
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/orders/OrderService.java b/src/main/java/com/github/rishabh9/riko/upstox/orders/OrderService.java
index af6c3a8..72f77c2 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/orders/OrderService.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/orders/OrderService.java
@@ -24,6 +24,7 @@
package com.github.rishabh9.riko.upstox.orders;
+import com.github.rishabh9.riko.upstox.common.RetryPolicyFactory;
import com.github.rishabh9.riko.upstox.common.Service;
import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
@@ -31,6 +32,8 @@
import com.github.rishabh9.riko.upstox.orders.models.OrderRequest;
import com.github.rishabh9.riko.upstox.orders.models.Trade;
import com.google.common.base.Strings;
+import com.google.common.util.concurrent.RateLimiter;
+import net.jodah.failsafe.Failsafe;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -38,16 +41,28 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
+import static com.github.rishabh9.riko.upstox.common.constants.RateLimits.*;
+
+@SuppressWarnings("UnstableApiUsage")
public class OrderService extends Service {
private static final Logger log = LogManager.getLogger(OrderService.class);
+ private static final RateLimiter orderHistoryRateLimiter = RateLimiter.create(ORDER_HISTORY_RATE_LIMIT);
+ private static final RateLimiter orderDetailsRateLimiter = RateLimiter.create(ORDER_DETAILS_RATE_LIMIT);
+ private static final RateLimiter tradeBookRateLimiter = RateLimiter.create(TRADE_BOOK_RATE_LIMIT);
+ private static final RateLimiter tradeHistoryRateLimiter = RateLimiter.create(TRADE_HISTORY_RATE_LIMIT);
+ private static final RateLimiter placeOrderRateLimiter = RateLimiter.create(PLACE_ORDER_RATE_LIMIT);
+ private static final RateLimiter modifyOrderRateLimiter = RateLimiter.create(MODIFY_ORDER_RATE_LIMIT);
+ private static final RateLimiter cancelOrderRateLimiter = RateLimiter.create(CANCEL_ORDER_RATE_LIMIT);
+
/**
* @param upstoxAuthService The service to retrieve authentication details
*/
- public OrderService(@Nonnull final UpstoxAuthService upstoxAuthService) {
+ public OrderService(@Nonnull final UpstoxAuthService upstoxAuthService,
+ @Nonnull final RetryPolicyFactory retryPolicyFactory) {
- super(upstoxAuthService);
+ super(upstoxAuthService, retryPolicyFactory);
}
/**
@@ -61,7 +76,17 @@ public CompletableFuture>> getOrderHistory() {
final OrderApi api = prepareServiceApi(OrderApi.class);
log.debug("Making request - GET Order History");
- return api.getOrderHistory();
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Order History.", failure))
+ .onSuccess(response -> log.debug("GET Order History successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Order History, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ orderHistoryRateLimiter.acquire(1);
+ return api.getOrderHistory();
+ });
}
/**
@@ -79,7 +104,17 @@ public CompletableFuture>> getOrderDetails(@Nonnull f
final OrderApi api = prepareServiceApi(OrderApi.class);
log.debug("Making request - GET Order Details");
- return api.getOrderDetails(orderId);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Order Details. ", failure))
+ .onSuccess(response -> log.debug("GET Order Details successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Order Details, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ orderDetailsRateLimiter.acquire(1);
+ return api.getOrderDetails(orderId);
+ });
}
/**
@@ -93,7 +128,17 @@ public CompletableFuture>> getTradeBook() {
final OrderApi api = prepareServiceApi(OrderApi.class);
log.debug("Making request - GET Trade Book");
- return api.getTradeBook();
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Trade Book. ", failure))
+ .onSuccess(response -> log.debug("GET Trade Book successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Trade Book, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ tradeBookRateLimiter.acquire(1);
+ return api.getTradeBook();
+ });
}
/**
@@ -111,7 +156,17 @@ public CompletableFuture>> getTradeHistory(@Nonnull f
final OrderApi api = prepareServiceApi(OrderApi.class);
log.debug("Making request - GET Trade History");
- return api.getTradeHistory(orderId);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Trade History. ", failure))
+ .onSuccess(response -> log.debug("GET Trade History successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Trade History, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ tradeHistoryRateLimiter.acquire(1);
+ return api.getTradeHistory(orderId);
+ });
}
/**
@@ -129,7 +184,17 @@ public CompletableFuture> placeOrder(@Nonnull final OrderR
final OrderApi api = prepareServiceApi(OrderApi.class);
log.debug("Making request - POST Place Order");
- return api.placeOrder(request);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to POST Place Order.", failure))
+ .onSuccess(response -> log.debug("POST Place Order successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to POST Place Order, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ placeOrderRateLimiter.acquire(1);
+ return api.placeOrder(request);
+ });
}
/**
@@ -150,7 +215,17 @@ public CompletableFuture> modifyOrder(@Nonnull final Strin
final OrderApi api = prepareServiceApi(OrderApi.class);
log.debug("Making request - PUT Modify Order");
- return api.modifyOrder(orderId, request);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to PUT Modify Order.", failure))
+ .onSuccess(response -> log.debug("PUT Modify Order successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to PUT Modify Order, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ modifyOrderRateLimiter.acquire(1);
+ return api.modifyOrder(orderId, request);
+ });
}
/**
@@ -168,7 +243,17 @@ public CompletableFuture> cancelOrders(@Nonnull final Str
final OrderApi api = prepareServiceApi(OrderApi.class);
log.debug("Making request - DELETE Orders");
- return api.cancelOrders(orderIdsCsv);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to DELETE Orders.", failure))
+ .onSuccess(response -> log.debug("DELETE Orders successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to DELETE Orders, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ cancelOrderRateLimiter.acquire(1);
+ return api.cancelOrders(orderIdsCsv);
+ });
}
/**
@@ -182,7 +267,17 @@ public CompletableFuture> cancelAllOrders() {
OrderApi api = prepareServiceApi(OrderApi.class);
log.debug("Making request - DELETE All Orders");
- return api.cancelAllOrders();
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to DELETE All Orders.", failure))
+ .onSuccess(response -> log.debug("DELETE All Orders successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to DELETE All Orders, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ cancelOrderRateLimiter.acquire(1);
+ return api.cancelAllOrders();
+ });
}
private void validateOrderRequest(OrderRequest request) {
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/users/UserService.java b/src/main/java/com/github/rishabh9/riko/upstox/users/UserService.java
index f1bd4d1..c96c1d5 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/users/UserService.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/users/UserService.java
@@ -24,11 +24,14 @@
package com.github.rishabh9.riko.upstox.users;
+import com.github.rishabh9.riko.upstox.common.RetryPolicyFactory;
import com.github.rishabh9.riko.upstox.common.Service;
import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
import com.github.rishabh9.riko.upstox.users.models.*;
import com.google.common.base.Strings;
+import com.google.common.util.concurrent.RateLimiter;
+import net.jodah.failsafe.Failsafe;
import okhttp3.ResponseBody;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -39,16 +42,26 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
+import static com.github.rishabh9.riko.upstox.common.constants.RateLimits.*;
+
+@SuppressWarnings("UnstableApiUsage")
public class UserService extends Service {
private static final Logger log = LogManager.getLogger(UserService.class);
+ private static final RateLimiter profileRateLimiter = RateLimiter.create(PROFILE_RATE_LIMIT);
+ private static final RateLimiter balanceRateLimiter = RateLimiter.create(BALANCE_RATE_LIMIT);
+ private static final RateLimiter positionsRateLimiter = RateLimiter.create(POSITIONS_RATE_LIMIT);
+ private static final RateLimiter holdingsRateLimiter = RateLimiter.create(HOLDINGS_RATE_LIMIT);
+ private static final RateLimiter masterContractRateLimiter = RateLimiter.create(MASTER_CONTRACT_RATE_LIMIT);
+
/**
* @param upstoxAuthService The service to retrieve authentication details
*/
- public UserService(@Nonnull final UpstoxAuthService upstoxAuthService) {
+ public UserService(@Nonnull final UpstoxAuthService upstoxAuthService,
+ @Nonnull final RetryPolicyFactory retryPolicyFactory) {
- super(upstoxAuthService);
+ super(upstoxAuthService, retryPolicyFactory);
}
/**
@@ -62,7 +75,17 @@ public CompletableFuture> getProfile() {
final UsersApi api = prepareServiceApi(UsersApi.class);
log.debug("Making request - GET Profile");
- return api.getProfile();
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Profile.", failure))
+ .onSuccess(response -> log.debug("GET Profile successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Profile, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ profileRateLimiter.acquire(1);
+ return api.getProfile();
+ });
}
/**
@@ -78,7 +101,17 @@ public CompletableFuture> getProfileBalance(
final UsersApi api = prepareServiceApi(UsersApi.class);
log.debug("Making request - GET Profile Balance");
- return api.getProfileBalance(accountType);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Profile Balance.", failure))
+ .onSuccess(response -> log.debug("GET Profile Balance successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Profile Balance, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ balanceRateLimiter.acquire(1);
+ return api.getProfileBalance(accountType);
+ });
}
/**
@@ -92,7 +125,17 @@ public CompletableFuture>> getPositions() {
final UsersApi api = prepareServiceApi(UsersApi.class);
log.debug("Making request - GET Positions");
- return api.getPositions();
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Positions.", failure))
+ .onSuccess(response -> log.debug("GET Positions successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Positions, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ positionsRateLimiter.acquire(1);
+ return api.getPositions();
+ });
}
/**
@@ -106,7 +149,17 @@ public CompletableFuture>> getHoldings() {
final UsersApi api = prepareServiceApi(UsersApi.class);
log.debug("Making request - GET Holdings");
- return api.getHoldings();
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Holdings.", failure))
+ .onSuccess(response -> log.debug("GET Holdings successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Holdings, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ holdingsRateLimiter.acquire(1);
+ return api.getHoldings();
+ });
}
/**
@@ -139,7 +192,17 @@ public CompletableFuture getAllMasterContracts(@Nonnull final Strin
final UsersApi api = prepareServiceApi(UsersApi.class);
log.debug("Making request - GET All Contracts");
- return api.getAllMasterContracts(exchange)
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET All Contracts.", failure))
+ .onSuccess(response -> log.debug("GET All Contracts successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET All Contracts, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ masterContractRateLimiter.acquire(1);
+ return api.getAllMasterContracts(exchange);
+ })
.thenApply(ResponseBody::byteStream);
}
@@ -164,8 +227,8 @@ public CompletableFuture getAllMasterContracts(@Nonnull final Strin
* Also, if both symbol and token are null or empty.
*/
public CompletableFuture> getMasterContract(@Nonnull final String exchange,
- @Nullable final String symbol,
- @Nullable final String token) {
+ final String symbol,
+ final String token) {
log.debug("Validate parameters - GET Contract");
validateExchange(exchange);
@@ -175,7 +238,17 @@ public CompletableFuture> getMasterContract(@Nonnull fi
final UsersApi api = prepareServiceApi(UsersApi.class);
log.debug("Making request - GET Contract");
- return api.getMasterContract(exchange, symbol, token);
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to GET Contract.", failure))
+ .onSuccess(response -> log.debug("GET Contract successful!", response))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to GET Contract, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ masterContractRateLimiter.acquire(1);
+ return api.getMasterContract(exchange, symbol, token);
+ });
}
private void validateSymbolAndToken(final String symbol, final String token) {
diff --git a/src/main/java/com/github/rishabh9/riko/upstox/websockets/WebSocketService.java b/src/main/java/com/github/rishabh9/riko/upstox/websockets/WebSocketService.java
index 786987c..c625612 100644
--- a/src/main/java/com/github/rishabh9/riko/upstox/websockets/WebSocketService.java
+++ b/src/main/java/com/github/rishabh9/riko/upstox/websockets/WebSocketService.java
@@ -24,6 +24,7 @@
package com.github.rishabh9.riko.upstox.websockets;
+import com.github.rishabh9.riko.upstox.common.RetryPolicyFactory;
import com.github.rishabh9.riko.upstox.common.Service;
import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
import com.github.rishabh9.riko.upstox.common.models.ApiCredentials;
@@ -32,8 +33,8 @@
import com.github.rishabh9.riko.upstox.websockets.models.WebsocketParameters;
import com.github.rishabh9.riko.upstox.websockets.models.WrappedWebSocket;
import com.google.common.base.Strings;
+import com.google.common.util.concurrent.RateLimiter;
import net.jodah.failsafe.Failsafe;
-import net.jodah.failsafe.RetryPolicy;
import okhttp3.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -41,29 +42,27 @@
import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static com.github.rishabh9.riko.upstox.common.constants.PropertyKeys.*;
+import static com.github.rishabh9.riko.upstox.common.constants.RateLimits.WEB_SOCKET_RATE_LIMIT;
+import static com.github.rishabh9.riko.upstox.common.constants.RateLimits.WS_PARAMS_RATE_LIMIT;
+@SuppressWarnings("UnstableApiUsage")
public class WebSocketService extends Service {
private static final Logger log = LogManager.getLogger(WebSocketService.class);
- private final RetryPolicy retryPolicy;
- private final ScheduledExecutorService executorService;
+ private static final RateLimiter wsParamsRateLimiter = RateLimiter.create(WS_PARAMS_RATE_LIMIT);
+ private static final RateLimiter webSocketRateLimiter = RateLimiter.create(WEB_SOCKET_RATE_LIMIT);
/**
* @param upstoxAuthService The service to retrieve authentication details
*/
- public WebSocketService(@Nonnull final UpstoxAuthService upstoxAuthService) {
- super(upstoxAuthService);
- retryPolicy = new RetryPolicy()
- .retryOn(Throwable.class)
- .withBackoff(1, 180, TimeUnit.SECONDS)
- .withMaxRetries(10);
- this.executorService = Executors.newScheduledThreadPool(4);
+ public WebSocketService(@Nonnull final UpstoxAuthService upstoxAuthService,
+ @Nonnull final RetryPolicyFactory retryPolicyFactory) {
+
+ super(upstoxAuthService, retryPolicyFactory);
}
private CompletableFuture> getWebsocketParameters() {
@@ -91,9 +90,8 @@ public WrappedWebSocket connect(final List subscribers) throw
throw new IllegalArgumentException("Subscribers not provided. Not connecting to the socket.");
}
- // Step 1: Retrieve the webSocket parameters before connecting, as per Upstox documentation.
- final UpstoxResponse response = Failsafe.with(retryPolicy)
- .with(executorService)
+ return Failsafe.with(retryPolicy)
+ .with(retryExecutor)
.onFailure(failure -> {
log.fatal("Failed completely to retrieve web-socket parameters. ", failure);
})
@@ -103,19 +101,26 @@ public WrappedWebSocket connect(final List subscribers) throw
})
.onRetry((c, f, ctx) ->
log.warn("Failure #" + ctx.getExecutions()
- + ". Unable to retrieve web-socket parameters, retrying.", f))
- .future(this::getWebsocketParameters)
- .get();
-
- // Step 2: Make connection
- return Failsafe.with(retryPolicy)
- .with(executorService)
- .onFailure(failure -> log.fatal("Failed completely to make web-socket connection. ", failure))
- .onSuccess(connection -> log.info("WebSocket connection is successful!"))
- .onRetry((c, f, ctx) ->
- log.warn("Failure #" + ctx.getExecutions() + ". Unable to connect to web-socket, retrying.", f))
- .get(() -> this.makeConnection(response.getData(), subscribers))
- .get();
+ + ". Unable to retrieve web-socket parameters, retrying. REASON: {}", f.getCause().getMessage()))
+ .future(() -> {
+ // Step 1: Retrieve the webSocket parameters before connecting, as per Upstox documentation.
+ wsParamsRateLimiter.acquire(1);
+ return getWebsocketParameters();
+ })
+ .thenApply(paramResponse -> Failsafe.with(retryPolicy)
+ .with(retryExecutor)
+ .onFailure(failure -> log.fatal("Failed completely to make web-socket connection. ", failure))
+ .onSuccess(connection -> log.info("WebSocket connection is successful!"))
+ .onRetry((c, f, ctx) ->
+ log.warn("Failure #" + ctx.getExecutions()
+ + ". Unable to connect to web-socket, retrying. REASON: {}", f.getCause().getMessage()))
+ .get(() -> {
+ // Step 2: Make connection
+ webSocketRateLimiter.acquire(1);
+ return this.makeConnection(paramResponse.getData(), subscribers);
+ }))
+ .get()
+ .get(); // block until complete
}
private WrappedWebSocket makeConnection(final WebsocketParameters parameters,
diff --git a/src/test/java/com/github/rishabh9/riko/upstox/BaseTest.java b/src/test/java/com/github/rishabh9/riko/upstox/BaseTest.java
new file mode 100644
index 0000000..90eb7ff
--- /dev/null
+++ b/src/test/java/com/github/rishabh9/riko/upstox/BaseTest.java
@@ -0,0 +1,51 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 Rishabh Joshi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.rishabh9.riko.upstox;
+
+import com.github.rishabh9.riko.upstox.common.RetryPolicyFactory;
+import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
+import com.github.rishabh9.riko.upstox.common.models.ApiCredentials;
+import com.github.rishabh9.riko.upstox.login.models.AccessToken;
+
+public class BaseTest {
+
+ protected RetryPolicyFactory retryPolicyFactory = new TestRetryPolicyFactory();
+
+ protected UpstoxAuthService upstoxAuthService = new UpstoxAuthService() {
+ @Override
+ public ApiCredentials getApiCredentials() {
+ return new ApiCredentials("secretApiKey", "secret-secret");
+ }
+
+ @Override
+ public AccessToken getAccessToken() {
+ AccessToken token = new AccessToken();
+ token.setExpiresIn(86400L);
+ token.setType("Bearer");
+ token.setToken("access_token_123456789");
+ return token;
+ }
+ };
+}
diff --git a/src/test/java/com/github/rishabh9/riko/upstox/TestRetryPolicyFactory.java b/src/test/java/com/github/rishabh9/riko/upstox/TestRetryPolicyFactory.java
new file mode 100644
index 0000000..6bc23d4
--- /dev/null
+++ b/src/test/java/com/github/rishabh9/riko/upstox/TestRetryPolicyFactory.java
@@ -0,0 +1,56 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 Rishabh Joshi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.github.rishabh9.riko.upstox;
+
+import com.github.rishabh9.riko.upstox.common.RetryPolicyFactory;
+import net.jodah.failsafe.RetryPolicy;
+
+import java.util.Optional;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * The Riko's default retry policy factory for running tests
+ *
+ * @see RetryPolicyFactory
+ */
+public class TestRetryPolicyFactory implements RetryPolicyFactory {
+
+ /**
+ * @return The default {@link RetryPolicy}
+ */
+ @Override
+ public Optional createRetryPolicy() {
+ return Optional.empty();
+ }
+
+ /**
+ * @return The default {@link ScheduledExecutorService} to be used by {@link RetryPolicy}.
+ */
+ @Override
+ public ScheduledExecutorService createExecutorService() {
+ return Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
+ }
+}
diff --git a/src/test/java/com/github/rishabh9/riko/upstox/feed/FeedServiceTest.java b/src/test/java/com/github/rishabh9/riko/upstox/feed/FeedServiceTest.java
index 28532cc..e299acc 100644
--- a/src/test/java/com/github/rishabh9/riko/upstox/feed/FeedServiceTest.java
+++ b/src/test/java/com/github/rishabh9/riko/upstox/feed/FeedServiceTest.java
@@ -24,13 +24,13 @@
package com.github.rishabh9.riko.upstox.feed;
+import com.github.rishabh9.riko.upstox.BaseTest;
import com.github.rishabh9.riko.upstox.common.ServiceGenerator;
-import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
-import com.github.rishabh9.riko.upstox.common.models.ApiCredentials;
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
import com.github.rishabh9.riko.upstox.feed.models.Feed;
+import com.github.rishabh9.riko.upstox.feed.models.Subscription;
import com.github.rishabh9.riko.upstox.feed.models.SubscriptionResponse;
-import com.github.rishabh9.riko.upstox.login.models.AccessToken;
+import com.github.rishabh9.riko.upstox.feed.models.SymbolSubscribed;
import com.google.gson.Gson;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
@@ -39,31 +39,16 @@
import org.junit.jupiter.api.Test;
import java.io.IOException;
+import java.util.List;
import java.util.concurrent.ExecutionException;
import static okhttp3.mockwebserver.SocketPolicy.DISCONNECT_AFTER_REQUEST;
import static org.junit.jupiter.api.Assertions.*;
-class FeedServiceTest {
+class FeedServiceTest extends BaseTest {
private static final Logger log = LogManager.getLogger(FeedServiceTest.class);
- private UpstoxAuthService upstoxAuthService = new UpstoxAuthService() {
- @Override
- public ApiCredentials getApiCredentials() {
- return new ApiCredentials("secretApiKey", "secret-secret");
- }
-
- @Override
- public AccessToken getAccessToken() {
- AccessToken token = new AccessToken();
- token.setExpiresIn(86400L);
- token.setType("Bearer");
- token.setToken("access_token_123456789");
- return token;
- }
- };
-
@Test
void liveFeed_success_whenAllParametersAreCorrect() throws IOException {
MockWebServer server = new MockWebServer();
@@ -82,11 +67,11 @@ void liveFeed_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse serverResponse =
- service.liveFeed("NSE", "RELIANCE", "TYPE")
+ service.liveFeed("NSE", "RELIANCE", "FULL")
.get();
assertEquals(response, serverResponse);
} catch (ExecutionException | InterruptedException e) {
@@ -113,10 +98,10 @@ void liveFeed_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class,
- service.liveFeed("NSE", "RELIANCE", "TYPE")::get);
+ service.liveFeed("NSE", "RELIANCE", "FULL")::get);
server.shutdown();
}
@@ -131,10 +116,10 @@ void liveFeed_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
try {
- service.liveFeed("NSE", "RELIANCE", "TYPE").get();
+ service.liveFeed("NSE", "RELIANCE", "FULL").get();
} catch (ExecutionException | InterruptedException e) {
assertTrue(e.getCause() instanceof IOException);
} finally {
@@ -144,7 +129,7 @@ void liveFeed_failure_onNetworkError() throws IOException {
@Test
void liveFeed_throwIAE_whenRequiredParametersAreMissing() {
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.liveFeed(null, null, null),
@@ -183,7 +168,7 @@ void liveFeed_throwIAE_whenRequiredParametersAreMissing() {
void liveFeed_throwNPE_whenServiceParametersAreMissing() {
assertThrows(NullPointerException.class,
- () -> new FeedService(null),
+ () -> new FeedService(null, retryPolicyFactory),
"Null check missing for 'UpstoxAuthService' from FeedService constructor");
}
@@ -205,7 +190,7 @@ void subscribe_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse subResponse =
@@ -236,7 +221,7 @@ void subscribe_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class,
service.subscribe("TYPE", "NSE", "ACC,RELIANCE")::get);
@@ -254,7 +239,7 @@ void subscribe_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
try {
service.subscribe("TYPE", "NSE", "RELIANCE,ACC").get();
@@ -267,7 +252,7 @@ void subscribe_failure_onNetworkError() throws IOException {
@Test
void subscribe_throwIAE_whenRequiredParametersAreMissing() {
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.subscribe(null, null, null),
@@ -320,7 +305,7 @@ void unsubscribe_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse unsubResponse =
@@ -351,7 +336,7 @@ void unsubscribe_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class,
service.unsubscribe("TYPE", "NSE", "ACC,RELIANCE")::get);
@@ -369,7 +354,7 @@ void unsubscribe_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
try {
service.unsubscribe("TYPE", "NSE", "RELIANCE,ACC").get();
@@ -382,7 +367,7 @@ void unsubscribe_failure_onNetworkError() throws IOException {
@Test
void unsubscribe_throwIAE_whenRequiredParametersAreMissing() {
- FeedService service = new FeedService(upstoxAuthService);
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.unsubscribe(null, null, null),
@@ -416,4 +401,96 @@ void unsubscribe_throwIAE_whenRequiredParametersAreMissing() {
service.unsubscribe("TYPE", "NSE", ""),
"Symbols cannot be empty. Mandatory validation missing.");
}
+
+ @Test
+ void symbolsSubscribed_success_whenAllParametersAreCorrect() throws IOException {
+ MockWebServer server = new MockWebServer();
+
+ Subscription subscription = new Subscription();
+ SymbolSubscribed symbolSubscribed = new SymbolSubscribed();
+ symbolSubscribed.setExchange("NSE");
+ symbolSubscribed.setSymbol("ACC");
+ subscription.setFull(List.of(symbolSubscribed));
+ UpstoxResponse response = new UpstoxResponse<>();
+ response.setCode(200);
+ response.setData(subscription);
+
+ server.enqueue(
+ new MockResponse().setBody(
+ new Gson().toJson(response)));
+
+ server.start();
+
+ ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
+
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
+
+ try {
+ UpstoxResponse serverResponse = service.symbolsSubscribed("FULL").get();
+ assertEquals(response, serverResponse);
+ } catch (ExecutionException | InterruptedException e) {
+ log.fatal(e);
+ fail();
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ @Test
+ void symbolsSubscribed_failure_whenUpstoxReturnsError() throws IOException {
+ MockWebServer server = new MockWebServer();
+
+ server.enqueue(new MockResponse()
+ .setResponseCode(400)
+ .setBody("{\"code\":400," +
+ "\"status\":\"Bad Request\"," +
+ "\"timestamp\":\"2018-06-19T20:11:57+05:30\"," +
+ "\"message\":\"Random error\"," +
+ "\"error\":{\"name\":\"Error\",\"reason\":\"Random error\"}}"));
+
+ server.start();
+
+ ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
+
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
+
+ assertThrows(ExecutionException.class, service.symbolsSubscribed("FULL")::get);
+
+ server.shutdown();
+ }
+
+ @Test
+ void symbolsSubscribed_failure_onNetworkError() throws IOException {
+ MockWebServer server = new MockWebServer();
+
+ server.enqueue(new MockResponse().setSocketPolicy(DISCONNECT_AFTER_REQUEST));
+
+ server.start();
+
+ ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
+
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
+
+ try {
+ service.symbolsSubscribed("FULL").get();
+ } catch (ExecutionException | InterruptedException e) {
+ assertTrue(e.getCause() instanceof IOException);
+ } finally {
+ server.shutdown();
+ }
+ }
+
+ @Test
+ void symbolsSubscribed_throwIAE_whenRequiredParametersAreMissing() {
+ FeedService service = new FeedService(upstoxAuthService, retryPolicyFactory);
+
+ assertThrows(IllegalArgumentException.class, () ->
+ service.symbolsSubscribed(null),
+ "Type cannot be null. Mandatory validation missing.");
+
+ assertThrows(IllegalArgumentException.class, () ->
+ service.symbolsSubscribed(""),
+ "Type cannot be empty. Mandatory validation missing.");
+ }
+
}
\ No newline at end of file
diff --git a/src/test/java/com/github/rishabh9/riko/upstox/historical/HistoricalServiceTest.java b/src/test/java/com/github/rishabh9/riko/upstox/historical/HistoricalServiceTest.java
index ad1daa8..d1605aa 100644
--- a/src/test/java/com/github/rishabh9/riko/upstox/historical/HistoricalServiceTest.java
+++ b/src/test/java/com/github/rishabh9/riko/upstox/historical/HistoricalServiceTest.java
@@ -24,12 +24,10 @@
package com.github.rishabh9.riko.upstox.historical;
+import com.github.rishabh9.riko.upstox.BaseTest;
import com.github.rishabh9.riko.upstox.common.ServiceGenerator;
-import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
-import com.github.rishabh9.riko.upstox.common.models.ApiCredentials;
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
import com.github.rishabh9.riko.upstox.historical.models.Candle;
-import com.github.rishabh9.riko.upstox.login.models.AccessToken;
import com.google.gson.Gson;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
@@ -45,26 +43,10 @@
import static okhttp3.mockwebserver.SocketPolicy.DISCONNECT_AFTER_REQUEST;
import static org.junit.jupiter.api.Assertions.*;
-class HistoricalServiceTest {
+class HistoricalServiceTest extends BaseTest {
private static final Logger log = LogManager.getLogger(HistoricalServiceTest.class);
- private UpstoxAuthService upstoxAuthService = new UpstoxAuthService() {
- @Override
- public ApiCredentials getApiCredentials() {
- return new ApiCredentials("secretApiKey", "secret-secret");
- }
-
- @Override
- public AccessToken getAccessToken() {
- AccessToken token = new AccessToken();
- token.setExpiresIn(86400L);
- token.setType("Bearer");
- token.setToken("access_token_123456789");
- return token;
- }
- };
-
@Test
void getOhlc_success_whenAllParametersAreCorrect() throws IOException {
MockWebServer server = new MockWebServer();
@@ -85,11 +67,11 @@ void getOhlc_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- HistoricalService service = new HistoricalService(upstoxAuthService);
+ HistoricalService service = new HistoricalService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse> serverResponse =
- service.getOhlc("NSE", "RELIANCE", "", "", "")
+ service.getOhlc("NSE", "RELIANCE", "1", "", "")
.get();
assertEquals(response, serverResponse);
} catch (ExecutionException | InterruptedException e) {
@@ -116,10 +98,10 @@ void getOhlc_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- HistoricalService service = new HistoricalService(upstoxAuthService);
+ HistoricalService service = new HistoricalService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class,
- service.getOhlc("NSE", "RELIANCE", null, null, null)::get);
+ service.getOhlc("NSE", "RELIANCE", "1", null, null)::get);
server.shutdown();
}
@@ -134,10 +116,10 @@ void getOhlc_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- HistoricalService service = new HistoricalService(upstoxAuthService);
+ HistoricalService service = new HistoricalService(upstoxAuthService, retryPolicyFactory);
try {
- service.getOhlc("NSE", "RELIANCE", null, null, null).get();
+ service.getOhlc("NSE", "RELIANCE", "1", null, null).get();
} catch (ExecutionException | InterruptedException e) {
assertTrue(e.getCause() instanceof IOException);
} finally {
@@ -147,7 +129,7 @@ void getOhlc_failure_onNetworkError() throws IOException {
@Test
void getOhlc_throwIAE_whenRequiredParametersAreMissing() {
- HistoricalService service = new HistoricalService(upstoxAuthService);
+ HistoricalService service = new HistoricalService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.getOhlc(null, null, null, null, null),
@@ -178,7 +160,7 @@ void getOhlc_throwIAE_whenRequiredParametersAreMissing() {
void getOhlc_throwNPE_whenServiceParametersAreMissing() {
assertThrows(NullPointerException.class,
- () -> new HistoricalService(null),
+ () -> new HistoricalService(null, retryPolicyFactory),
"Null check missing for 'UpstoxAuthService' from HistoricalService constructor");
}
}
\ No newline at end of file
diff --git a/src/test/java/com/github/rishabh9/riko/upstox/login/LoginServiceTest.java b/src/test/java/com/github/rishabh9/riko/upstox/login/LoginServiceTest.java
index 34b908f..e3a260a 100644
--- a/src/test/java/com/github/rishabh9/riko/upstox/login/LoginServiceTest.java
+++ b/src/test/java/com/github/rishabh9/riko/upstox/login/LoginServiceTest.java
@@ -24,6 +24,7 @@
package com.github.rishabh9.riko.upstox.login;
+import com.github.rishabh9.riko.upstox.BaseTest;
import com.github.rishabh9.riko.upstox.common.ServiceGenerator;
import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
import com.github.rishabh9.riko.upstox.common.models.ApiCredentials;
@@ -41,7 +42,7 @@
import static okhttp3.mockwebserver.SocketPolicy.DISCONNECT_AFTER_REQUEST;
import static org.junit.jupiter.api.Assertions.*;
-class LoginServiceTest {
+class LoginServiceTest extends BaseTest {
private static final Logger log = LogManager.getLogger(LoginServiceTest.class);
@@ -73,7 +74,7 @@ public AccessToken getAccessToken() {
}
};
- LoginService service = new LoginService(upstoxAuthService);
+ LoginService service = new LoginService(upstoxAuthService, retryPolicyFactory);
try {
AccessToken accessToken = service.getAccessToken(request).get();
@@ -121,7 +122,7 @@ public AccessToken getAccessToken() {
}
};
- LoginService service = new LoginService(upstoxAuthService);
+ LoginService service = new LoginService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, () -> service.getAccessToken(request).get());
@@ -154,7 +155,7 @@ public AccessToken getAccessToken() {
}
};
- LoginService service = new LoginService(upstoxAuthService);
+ LoginService service = new LoginService(upstoxAuthService, retryPolicyFactory);
try {
service.getAccessToken(request).get();
@@ -180,7 +181,7 @@ public AccessToken getAccessToken() {
}
};
- LoginService service = new LoginService(upstoxAuthService);
+ LoginService service = new LoginService(upstoxAuthService, retryPolicyFactory);
assertThrows(NullPointerException.class,
() -> service.getAccessToken(null),
"Null check missing for 'TokenRequest' from LoginService constructor");
diff --git a/src/test/java/com/github/rishabh9/riko/upstox/orders/OrderServiceTest.java b/src/test/java/com/github/rishabh9/riko/upstox/orders/OrderServiceTest.java
index afe440a..0fe2931 100644
--- a/src/test/java/com/github/rishabh9/riko/upstox/orders/OrderServiceTest.java
+++ b/src/test/java/com/github/rishabh9/riko/upstox/orders/OrderServiceTest.java
@@ -24,11 +24,9 @@
package com.github.rishabh9.riko.upstox.orders;
+import com.github.rishabh9.riko.upstox.BaseTest;
import com.github.rishabh9.riko.upstox.common.ServiceGenerator;
-import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
-import com.github.rishabh9.riko.upstox.common.models.ApiCredentials;
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
-import com.github.rishabh9.riko.upstox.login.models.AccessToken;
import com.github.rishabh9.riko.upstox.orders.models.Order;
import com.github.rishabh9.riko.upstox.orders.models.OrderRequest;
import com.github.rishabh9.riko.upstox.orders.models.Trade;
@@ -47,26 +45,10 @@
import static okhttp3.mockwebserver.SocketPolicy.DISCONNECT_AFTER_REQUEST;
import static org.junit.jupiter.api.Assertions.*;
-class OrderServiceTest {
+class OrderServiceTest extends BaseTest {
private static final Logger log = LogManager.getLogger(OrderServiceTest.class);
- private UpstoxAuthService upstoxAuthService = new UpstoxAuthService() {
- @Override
- public ApiCredentials getApiCredentials() {
- return new ApiCredentials("secretApiKey", "secret-secret");
- }
-
- @Override
- public AccessToken getAccessToken() {
- AccessToken token = new AccessToken();
- token.setExpiresIn(86400L);
- token.setType("Bearer");
- token.setToken("access_token_123456789");
- return token;
- }
- };
-
@Test
void getOrderHistory_success_whenAllParametersAreCorrect() throws IOException {
MockWebServer server = new MockWebServer();
@@ -87,7 +69,7 @@ void getOrderHistory_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse> serverResponse = service.getOrderHistory().get();
@@ -116,7 +98,7 @@ void getOrderHistory_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.getOrderHistory()::get);
@@ -133,7 +115,7 @@ void getOrderHistory_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
service.getOrderHistory().get();
@@ -165,7 +147,7 @@ void getOrderDetails_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse> serverResponse =
@@ -195,7 +177,7 @@ void getOrderDetails_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.getOrderDetails("ORD_ID_1")::get);
@@ -212,7 +194,7 @@ void getOrderDetails_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
service.getOrderDetails("ORD_ID_1").get();
@@ -226,7 +208,7 @@ void getOrderDetails_failure_onNetworkError() throws IOException {
@Test
void getOrderDetails_throwIAE_whenRequiredParametersAreMissing() {
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.getOrderDetails(null),
@@ -257,7 +239,7 @@ void getTradeBook_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse> serverResponse = service.getTradeBook().get();
@@ -286,7 +268,7 @@ void getTradeBook_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.getTradeBook()::get);
@@ -303,7 +285,7 @@ void getTradeBook_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
service.getTradeBook().get();
@@ -335,7 +317,7 @@ void getTradeHistory_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse> serverResponse =
@@ -365,7 +347,7 @@ void getTradeHistory_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.getTradeHistory("ORD_ID_1")::get);
@@ -382,7 +364,7 @@ void getTradeHistory_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
service.getTradeHistory("ORD_ID_1").get();
@@ -396,7 +378,7 @@ void getTradeHistory_failure_onNetworkError() throws IOException {
@Test
void getTradeHistory_throwIAE_whenRequiredParametersAreMissing() {
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.getTradeHistory(null),
@@ -425,7 +407,7 @@ void placeOrder_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
OrderRequest request = new OrderRequest();
request.setOrderId("ORD_ID_1");
@@ -457,7 +439,7 @@ void placeOrder_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.placeOrder(new OrderRequest())::get);
@@ -474,7 +456,7 @@ void placeOrder_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
service.placeOrder(new OrderRequest()).get();
@@ -488,7 +470,7 @@ void placeOrder_failure_onNetworkError() throws IOException {
@Test
void placeOrder_throwIAE_whenRequiredParametersAreMissing() {
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.placeOrder(null),
@@ -513,7 +495,7 @@ void modifyOrder_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
OrderRequest request = new OrderRequest();
request.setOrderId("ORD_ID_1");
@@ -546,7 +528,7 @@ void modifyOrder_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class,
service.modifyOrder("ORD_ID_1", new OrderRequest())::get);
@@ -564,7 +546,7 @@ void modifyOrder_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
service.modifyOrder("ORD_ID_1", new OrderRequest()).get();
@@ -578,7 +560,7 @@ void modifyOrder_failure_onNetworkError() throws IOException {
@Test
void modifyOrder_throwIAE_whenRequiredParametersAreMissing() {
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.modifyOrder(null, new OrderRequest()),
@@ -609,7 +591,7 @@ void cancelOrders_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse serverResponse =
@@ -639,7 +621,7 @@ void cancelOrders_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.cancelOrders("ORDER_ID_1")::get);
@@ -656,7 +638,7 @@ void cancelOrders_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
service.cancelOrders("ORD_ID_1,ORD_ID_2").get();
@@ -670,7 +652,7 @@ void cancelOrders_failure_onNetworkError() throws IOException {
@Test
void cancelOrders_throwIAE_whenRequiredParametersAreMissing() {
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.cancelOrders(null),
@@ -697,7 +679,7 @@ void cancelAllOrders_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse serverResponse = service.cancelAllOrders().get();
@@ -726,7 +708,7 @@ void cancelAllOrders_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.cancelAllOrders()::get);
@@ -743,7 +725,7 @@ void cancelAllOrders_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- OrderService service = new OrderService(upstoxAuthService);
+ OrderService service = new OrderService(upstoxAuthService, retryPolicyFactory);
try {
service.cancelAllOrders().get();
@@ -758,7 +740,7 @@ void cancelAllOrders_failure_onNetworkError() throws IOException {
@Test
void cancelAllOrders_throwNPE_whenServiceParametersAreMissing() {
assertThrows(NullPointerException.class,
- () -> new OrderService(null),
+ () -> new OrderService(null, retryPolicyFactory),
"Null check missing for 'UpstoxAuthService' from OrderService constructor");
}
}
\ No newline at end of file
diff --git a/src/test/java/com/github/rishabh9/riko/upstox/users/UserServiceTest.java b/src/test/java/com/github/rishabh9/riko/upstox/users/UserServiceTest.java
index 298ae36..832b977 100644
--- a/src/test/java/com/github/rishabh9/riko/upstox/users/UserServiceTest.java
+++ b/src/test/java/com/github/rishabh9/riko/upstox/users/UserServiceTest.java
@@ -24,11 +24,9 @@
package com.github.rishabh9.riko.upstox.users;
+import com.github.rishabh9.riko.upstox.BaseTest;
import com.github.rishabh9.riko.upstox.common.ServiceGenerator;
-import com.github.rishabh9.riko.upstox.common.UpstoxAuthService;
-import com.github.rishabh9.riko.upstox.common.models.ApiCredentials;
import com.github.rishabh9.riko.upstox.common.models.UpstoxResponse;
-import com.github.rishabh9.riko.upstox.login.models.AccessToken;
import com.github.rishabh9.riko.upstox.users.models.*;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
@@ -52,26 +50,10 @@
import static okhttp3.mockwebserver.SocketPolicy.DISCONNECT_AFTER_REQUEST;
import static org.junit.jupiter.api.Assertions.*;
-class UserServiceTest {
+class UserServiceTest extends BaseTest {
private static final Logger log = LogManager.getLogger(UserServiceTest.class);
- private UpstoxAuthService upstoxAuthService = new UpstoxAuthService() {
- @Override
- public ApiCredentials getApiCredentials() {
- return new ApiCredentials("secretApiKey", "secret-secret");
- }
-
- @Override
- public AccessToken getAccessToken() {
- AccessToken token = new AccessToken();
- token.setExpiresIn(86400L);
- token.setType("Bearer");
- token.setToken("access_token_123456789");
- return token;
- }
- };
-
@Test
void getProfile_success_whenAllParametersAreCorrect() throws IOException {
MockWebServer server = new MockWebServer();
@@ -90,7 +72,7 @@ void getProfile_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse serverResponse = service.getProfile().get();
@@ -119,7 +101,7 @@ void getProfile_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.getProfile()::get);
@@ -136,7 +118,7 @@ void getProfile_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
service.getProfile().get();
@@ -167,7 +149,7 @@ void getProfileBalance_success_whenAllParametersAreCorrect() throws IOException
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse serverResponse =
@@ -197,7 +179,7 @@ void getProfileBalance_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.getProfileBalance(null)::get);
@@ -214,7 +196,7 @@ void getProfileBalance_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
service.getProfileBalance(null).get();
@@ -245,7 +227,7 @@ void getPositions_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse> serverResponse = service.getPositions().get();
@@ -274,7 +256,7 @@ void getPositions_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.getPositions()::get);
@@ -291,7 +273,7 @@ void getPositions_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
service.getPositions().get();
@@ -322,7 +304,7 @@ void getHoldings_success_whenAllParametersAreCorrect() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse> serverResponse = service.getHoldings().get();
@@ -351,7 +333,7 @@ void getHoldings_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class, service.getHoldings()::get);
@@ -368,7 +350,7 @@ void getHoldings_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
service.getHoldings().get();
@@ -398,7 +380,7 @@ void getAllMasterContracts_success_whenAllParametersAreCorrect() throws IOExcept
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
InputStream inputStream =
@@ -449,7 +431,7 @@ void getAllMasterContracts_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class,
service.getAllMasterContracts("NSE")::get);
@@ -467,7 +449,7 @@ void getAllMasterContracts_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
service.getAllMasterContracts("NSE").get();
@@ -480,7 +462,7 @@ void getAllMasterContracts_failure_onNetworkError() throws IOException {
@Test
void getAllMasterContracts_throwIAE_whenRequiredParametersAreMissing() {
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.getAllMasterContracts(null),
@@ -509,7 +491,7 @@ void getMasterContract_success_whenAllParametersAreCorrect() throws IOException
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
UpstoxResponse serverResponse =
@@ -540,7 +522,7 @@ void getMasterContract_failure_whenUpstoxReturnsError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
assertThrows(ExecutionException.class,
service.getMasterContract("NSE", "RELIANCE", null)::get);
@@ -558,7 +540,7 @@ void getMasterContract_failure_onNetworkError() throws IOException {
ServiceGenerator.getInstance().rebuildWithUrl(server.url("/"));
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
try {
service.getMasterContract("NSE", "RELIANCE", null).get();
@@ -571,7 +553,7 @@ void getMasterContract_failure_onNetworkError() throws IOException {
@Test
void getMasterContract_throwIAE_whenRequiredParametersAreMissing() {
- UserService service = new UserService(upstoxAuthService);
+ UserService service = new UserService(upstoxAuthService, retryPolicyFactory);
assertThrows(IllegalArgumentException.class, () ->
service.getMasterContract(null, null, null),
@@ -605,7 +587,7 @@ void getMasterContract_throwIAE_whenRequiredParametersAreMissing() {
@Test
void getMasterContract_throwNPE_whenServiceParametersAreMissing() {
assertThrows(NullPointerException.class,
- () -> new UserService(null),
+ () -> new UserService(null, retryPolicyFactory),
"Null check missing for 'UpstoxAuthService' from UserService constructor");
}
}
\ No newline at end of file