diff --git a/README.md b/README.md index 6efc253..a03295c 100644 --- a/README.md +++ b/README.md @@ -135,28 +135,29 @@ switcher.poolsize=2 ### Configuration Properties Reference -| Property | Required | Default | Description | -|-------------------------------------|----------|---------|--------------------------------------------------------------------------------------| -| `switcher.context` | ✅ | - | Fully qualified class name extending SwitcherContext | -| `switcher.url` | ✅ | - | Switcher API endpoint URL | -| `switcher.apikey` | ✅ | - | API key for authentication | -| `switcher.component` | ✅ | - | Your application/component identifier | -| `switcher.domain` | ✅ | - | Domain name in Switcher API | -| `switcher.environment` | ❌ | default | Environment name (dev, staging, default) | -| `switcher.local` | ❌ | false | Enable local-only mode | -| `switcher.check` | ❌ | false | Validate switcher keys on startup | -| `switcher.relay.restrict` | ❌ | true | Defines if client will trigger local snapshot relay verification | -| `switcher.snapshot.location` | ❌ | - | Directory for snapshot files | -| `switcher.snapshot.auto` | ❌ | false | Auto-load snapshots on startup | -| `switcher.snapshot.skipvalidation` | ❌ | false | Skip snapshot validation on load | -| `switcher.snapshot.updateinterval` | ❌ | - | Interval for automatic snapshot updates (e.g., "5s", "2m") | -| `switcher.snapshot.watcher` | ❌ | false | Monitor snapshot files for changes | -| `switcher.silent` | ❌ | - | Enable silent mode (e.g., "5s", "2m") | -| `switcher.timeout` | ❌ | 3000 | API timeout in milliseconds | -| `switcher.poolsize` | ❌ | 2 | Thread pool size for API calls | -| `switcher.regextimeout` (v1-only) | ❌ | 3000 | Time in ms given to Timed Match Worker used for local Regex (ReDoS safety mechanism) | -| `switcher.truststore.path` | ❌ | - | Path to custom truststore file | -| `switcher.truststore.password` | ❌ | - | Password for custom truststore | +| Property | Required | Default | Description | +|------------------------------------|----------|---------|--------------------------------------------------------------------------------------| +| `switcher.context` | ✅ | - | Fully qualified class name extending SwitcherContext | +| `switcher.url` | ✅ | - | Switcher API endpoint URL | +| `switcher.apikey` | ✅ | - | API key for authentication | +| `switcher.component` | ✅ | - | Your application/component identifier | +| `switcher.domain` | ✅ | - | Domain name in Switcher API | +| `switcher.environment` | ❌ | default | Environment name (dev, staging, default) | +| `switcher.local` | ❌ | false | Enable local-only mode | +| `switcher.check` | ❌ | false | Validate switcher keys on startup | +| `switcher.autorefreshtoken` | ❌ | false | Automatically refresh API token before expiration | +| `switcher.relay.restrict` | ❌ | true | Defines if client will trigger local snapshot relay verification | +| `switcher.snapshot.location` | ❌ | - | Directory for snapshot files | +| `switcher.snapshot.auto` | ❌ | false | Auto-load snapshots on startup | +| `switcher.snapshot.skipvalidation` | ❌ | false | Skip snapshot validation on load | +| `switcher.snapshot.updateinterval` | ❌ | - | Interval for automatic snapshot updates (e.g., "5s", "2m") | +| `switcher.snapshot.watcher` | ❌ | false | Monitor snapshot files for changes | +| `switcher.silent` | ❌ | - | Enable silent mode (e.g., "5s", "2m") | +| `switcher.timeout` | ❌ | 3000 | API timeout in milliseconds | +| `switcher.poolsize` | ❌ | 2 | Thread pool size for API calls | +| `switcher.regextimeout` (v1-only) | ❌ | 3000 | Time in ms given to Timed Match Worker used for local Regex (ReDoS safety mechanism) | +| `switcher.truststore.path` | ❌ | - | Path to custom truststore file | +| `switcher.truststore.password` | ❌ | - | Password for custom truststore | > 💡 **Environment Variables**: Use `${ENV_VAR:default_value}` syntax for environment variable substitution. diff --git a/pom.xml b/pom.xml index addeb1e..ef77451 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.switcherapi switcher-client jar - 2.5.3-SNAPSHOT + 2.6.0-SNAPSHOT Switcher Client Switcher Client SDK for working with Switcher API diff --git a/src/main/java/com/switcherapi/client/ContextBuilder.java b/src/main/java/com/switcherapi/client/ContextBuilder.java index f483ba0..6f49290 100644 --- a/src/main/java/com/switcherapi/client/ContextBuilder.java +++ b/src/main/java/com/switcherapi/client/ContextBuilder.java @@ -234,4 +234,9 @@ public ContextBuilder poolConnectionSize(Integer poolSize) { Optional.ofNullable(poolSize).orElse(DEFAULT_POOL_SIZE)); return this; } + + public ContextBuilder autoRefreshToken(boolean autoRefreshToken) { + switcherProperties.setValue(ContextKey.AUTO_REFRESH_TOKEN, autoRefreshToken); + return this; + } } diff --git a/src/main/java/com/switcherapi/client/SwitcherConfig.java b/src/main/java/com/switcherapi/client/SwitcherConfig.java index 0658c64..98b7b3c 100644 --- a/src/main/java/com/switcherapi/client/SwitcherConfig.java +++ b/src/main/java/com/switcherapi/client/SwitcherConfig.java @@ -12,6 +12,7 @@ abstract class SwitcherConfig { protected boolean local; protected boolean check; + protected boolean autoRefreshToken; protected String silent; protected Integer timeout; protected Integer poolSize; @@ -38,6 +39,7 @@ protected void updateSwitcherConfig(SwitcherProperties properties) { setEnvironment(properties.getValue(ContextKey.ENVIRONMENT)); setLocal(properties.getBoolean(ContextKey.LOCAL_MODE)); setCheck(properties.getBoolean(ContextKey.CHECK_SWITCHERS)); + setAutoRefreshToken(properties.getBoolean(ContextKey.AUTO_REFRESH_TOKEN)); setSilent(properties.getValue(ContextKey.SILENT_MODE)); setTimeout(properties.getInt(ContextKey.TIMEOUT_MS)); setPoolSize(properties.getInt(ContextKey.POOL_CONNECTION_SIZE)); @@ -105,6 +107,10 @@ public void setCheck(boolean check) { this.check = check; } + public void setAutoRefreshToken(boolean autoRefreshToken) { + this.autoRefreshToken = autoRefreshToken; + } + public void setSilent(String silent) { this.silent = silent; } diff --git a/src/main/java/com/switcherapi/client/SwitcherContextBase.java b/src/main/java/com/switcherapi/client/SwitcherContextBase.java index d4ae7f8..50e9f23 100644 --- a/src/main/java/com/switcherapi/client/SwitcherContextBase.java +++ b/src/main/java/com/switcherapi/client/SwitcherContextBase.java @@ -87,7 +87,8 @@ public abstract class SwitcherContextBase extends SwitcherConfig { protected static Set switcherKeys; protected static Map switchers; protected static SwitcherExecutor switcherExecutor; - private static ScheduledExecutorService scheduledExecutorService; + private static ScheduledExecutorService scheduledSnapshotExecutorService; + private static ScheduledExecutorService scheduledTokenExecutorService; private static ExecutorService watcherExecutorService; private static SnapshotWatcher watcherSnapshot; protected static SwitcherContextBase contextBase; @@ -111,6 +112,7 @@ protected void configureClient() { .restrictRelay(relay.isRestrict()) .silentMode(silent) .timeoutMs(timeout) + .autoRefreshToken(autoRefreshToken) .poolConnectionSize(poolSize) .snapshotLocation(snapshot.getLocation()) .snapshotAutoLoad(snapshot.isAuto()) @@ -197,9 +199,12 @@ public static void initializeClient() { * @return SwitcherExecutor instance */ private static SwitcherExecutor buildInstance() { + initTokenExecutorService(); + final ClientWS clientWS = initRemotePoolExecutorService(); final SwitcherValidator validatorService = new ValidatorService(); - final ClientRemote clientRemote = new ClientRemoteService(clientWS, switcherProperties); + final ClientRemote clientRemote = new ClientRemoteService( + clientWS, switcherProperties, scheduledTokenExecutorService); final ClientLocal clientLocal = new ClientLocalService(validatorService); if (contextBol(ContextKey.LOCAL_MODE)) { @@ -306,7 +311,7 @@ public static ScheduledFuture scheduleSnapshotAutoUpdate(String intervalValue return null; } - if (Objects.nonNull(scheduledExecutorService)) { + if (Objects.nonNull(scheduledSnapshotExecutorService)) { terminateSnapshotAutoUpdateWorker(); } @@ -324,7 +329,7 @@ public static ScheduledFuture scheduleSnapshotAutoUpdate(String intervalValue }; initSnapshotExecutorService(); - return scheduledExecutorService.scheduleAtFixedRate(runnableSnapshotValidate, 0, interval, TimeUnit.MILLISECONDS); + return scheduledSnapshotExecutorService.scheduleAtFixedRate(runnableSnapshotValidate, 0, interval, TimeUnit.MILLISECONDS); } /** @@ -339,10 +344,10 @@ public static ScheduledFuture scheduleSnapshotAutoUpdate(String intervalValue } /** - * Configure Executor Service for Snapshot Update Worker + * Configure Scheduled Executor Service for Snapshot Update Worker */ private static void initSnapshotExecutorService() { - scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(r -> { + scheduledSnapshotExecutorService = Executors.newSingleThreadScheduledExecutor(r -> { Thread thread = new Thread(r); thread.setName(WorkerName.SNAPSHOT_UPDATE_WORKER.toString()); thread.setDaemon(true); @@ -350,6 +355,18 @@ private static void initSnapshotExecutorService() { }); } + /** + * Configure Scheduled Executor Service for Token Refresh Worker + */ + private static void initTokenExecutorService() { + scheduledTokenExecutorService = Executors.newSingleThreadScheduledExecutor(r -> { + Thread thread = new Thread(r); + thread.setName(WorkerName.SWITCHER_TOKEN_WORKER.toString()); + thread.setDaemon(true); + return thread; + }); + } + /** * Configure Executor Service for Snapshot Watch Worker */ @@ -538,9 +555,19 @@ public static void configure(ContextBuilder builder) { * Cancel existing scheduled task for updating local Snapshot */ public static void terminateSnapshotAutoUpdateWorker() { - if (Objects.nonNull(scheduledExecutorService)) { - scheduledExecutorService.shutdownNow(); - scheduledExecutorService = null; + if (Objects.nonNull(scheduledSnapshotExecutorService)) { + scheduledSnapshotExecutorService.shutdownNow(); + scheduledSnapshotExecutorService = null; + } + } + + /** + * Cancel existing scheduled task for token refresh + */ + public static void terminateTokenRefreshWorker() { + if (Objects.nonNull(scheduledTokenExecutorService)) { + scheduledTokenExecutorService.shutdownNow(); + scheduledTokenExecutorService = null; } } diff --git a/src/main/java/com/switcherapi/client/SwitcherPropertiesImpl.java b/src/main/java/com/switcherapi/client/SwitcherPropertiesImpl.java index d6d74e7..8d18b06 100644 --- a/src/main/java/com/switcherapi/client/SwitcherPropertiesImpl.java +++ b/src/main/java/com/switcherapi/client/SwitcherPropertiesImpl.java @@ -30,6 +30,7 @@ private void initDefaults() { setValue(ContextKey.LOCAL_MODE, false); setValue(ContextKey.CHECK_SWITCHERS, false); setValue(ContextKey.RESTRICT_RELAY, true); + setValue(ContextKey.AUTO_REFRESH_TOKEN, false); } @Override @@ -49,6 +50,7 @@ public void loadFromProperties(Properties prop) { setValue(ContextKey.LOCAL_MODE, getBoolDefault(resolveProperties(ContextKey.LOCAL_MODE.getParam(), prop), false)); setValue(ContextKey.CHECK_SWITCHERS, getBoolDefault(resolveProperties(ContextKey.CHECK_SWITCHERS.getParam(), prop), false)); setValue(ContextKey.RESTRICT_RELAY, getBoolDefault(resolveProperties(ContextKey.RESTRICT_RELAY.getParam(), prop), true)); + setValue(ContextKey.AUTO_REFRESH_TOKEN, getBoolDefault(resolveProperties(ContextKey.AUTO_REFRESH_TOKEN.getParam(), prop), false)); setValue(ContextKey.REGEX_TIMEOUT, getIntDefault(resolveProperties(ContextKey.REGEX_TIMEOUT.getParam(), prop), DEFAULT_REGEX_TIMEOUT)); setValue(ContextKey.TRUSTSTORE_PATH, resolveProperties(ContextKey.TRUSTSTORE_PATH.getParam(), prop)); setValue(ContextKey.TRUSTSTORE_PASSWORD, resolveProperties(ContextKey.TRUSTSTORE_PASSWORD.getParam(), prop)); diff --git a/src/main/java/com/switcherapi/client/model/ContextKey.java b/src/main/java/com/switcherapi/client/model/ContextKey.java index 1d1b3c1..e89d67e 100644 --- a/src/main/java/com/switcherapi/client/model/ContextKey.java +++ b/src/main/java/com/switcherapi/client/model/ContextKey.java @@ -109,8 +109,13 @@ public enum ContextKey { /** * (Number) Defines a fixed number of threads for the pool connection (default is 2). */ - POOL_CONNECTION_SIZE("switcher.poolsize"); - + POOL_CONNECTION_SIZE("switcher.poolsize"), + + /** + * (boolean) Enables automatic refresh of authentication token (default is false) + */ + AUTO_REFRESH_TOKEN("switcher.autorefreshtoken"); + private final String param; ContextKey(String param) { diff --git a/src/main/java/com/switcherapi/client/remote/dto/AuthResponse.java b/src/main/java/com/switcherapi/client/remote/dto/AuthResponse.java index 1ed8f6e..2196941 100644 --- a/src/main/java/com/switcherapi/client/remote/dto/AuthResponse.java +++ b/src/main/java/com/switcherapi/client/remote/dto/AuthResponse.java @@ -26,6 +26,10 @@ public boolean isExpired() { return (this.exp * 1000) < System.currentTimeMillis(); } + public long getExp() { + return this.exp; + } + @Override public String toString() { return "AuthResponse{" + diff --git a/src/main/java/com/switcherapi/client/service/WorkerName.java b/src/main/java/com/switcherapi/client/service/WorkerName.java index 83f0720..8b75d6c 100644 --- a/src/main/java/com/switcherapi/client/service/WorkerName.java +++ b/src/main/java/com/switcherapi/client/service/WorkerName.java @@ -5,7 +5,8 @@ public enum WorkerName { SNAPSHOT_WATCH_WORKER("switcherapi-snapshot-watcher"), SNAPSHOT_UPDATE_WORKER("switcherapi-snapshot-update"), SWITCHER_REMOTE_WORKER("switcherapi-remote-pool"), - SWITCHER_ASYNC_WORKER("switcherapi-async"); + SWITCHER_ASYNC_WORKER("switcherapi-async"), + SWITCHER_TOKEN_WORKER("switcherapi-token-refresh"); private final String name; diff --git a/src/main/java/com/switcherapi/client/service/remote/ClientRemoteService.java b/src/main/java/com/switcherapi/client/service/remote/ClientRemoteService.java index d094622..5e798dd 100644 --- a/src/main/java/com/switcherapi/client/service/remote/ClientRemoteService.java +++ b/src/main/java/com/switcherapi/client/service/remote/ClientRemoteService.java @@ -6,14 +6,24 @@ import com.switcherapi.client.exception.SwitcherRemoteException; import com.switcherapi.client.model.ContextKey; import com.switcherapi.client.model.criteria.Snapshot; -import com.switcherapi.client.remote.dto.*; import com.switcherapi.client.remote.ClientWS; +import com.switcherapi.client.remote.dto.AuthResponse; +import com.switcherapi.client.remote.dto.CriteriaRequest; +import com.switcherapi.client.remote.dto.CriteriaResponse; +import com.switcherapi.client.remote.dto.SnapshotVersionResponse; +import com.switcherapi.client.remote.dto.SwitchersCheck; import com.switcherapi.client.utils.SwitcherUtils; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Date; +import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; /** * @author Roger Floriano (petruki) @@ -21,19 +31,27 @@ */ public class ClientRemoteService implements ClientRemote { + private static final Logger log = LoggerFactory.getLogger(ClientRemoteService.class); + + private final ScheduledExecutorService scheduledExecutorService; + private final SwitcherProperties switcherProperties; - + private final ClientWS clientWs; private AuthResponse authResponse; + private ScheduledFuture refreshFuture; + private enum TokenStatus { VALID, INVALID, SILENT } - public ClientRemoteService(ClientWS clientWs, SwitcherProperties switcherProperties) { + public ClientRemoteService(ClientWS clientWs, SwitcherProperties switcherProperties, + ScheduledExecutorService scheduledExecutorService) { this.clientWs = clientWs; this.switcherProperties = switcherProperties; + this.scheduledExecutorService = scheduledExecutorService; } @Override @@ -92,7 +110,12 @@ public SwitchersCheck checkSwitchers(final Set switchers) { private void auth(TokenStatus tokenStatus) { if (tokenStatus == TokenStatus.INVALID) { + log.debug("Auth token is invalid or expired. Attempting to authenticate..."); this.authResponse = this.clientWs.auth().orElseGet(AuthResponse::new); + + if (isAutoRefreshable()) { + scheduleNextAuth(); + } } if (tokenStatus == TokenStatus.SILENT) { @@ -109,7 +132,7 @@ private TokenStatus isTokenValid() throws SwitcherRemoteException, return TokenStatus.INVALID; } - if (optAuthResponse.get().getToken().equals(ContextKey.SILENT_MODE.getParam()) + if (ContextKey.SILENT_MODE.getParam().equals(optAuthResponse.get().getToken()) && !optAuthResponse.get().isExpired()) { return TokenStatus.SILENT; } @@ -129,4 +152,35 @@ private void setSilentModeExpiration() throws SwitcherInvalidDateTimeArgumentExc } } + private void scheduleNextAuth() { + long msUntilExpiry = (authResponse.getExp() * 1000L) - (System.currentTimeMillis()); + long refreshAt = Math.max(msUntilExpiry - 5000, 0); // 5s before expiry + + terminateAutoRefresh(); + refreshFuture = scheduledExecutorService.schedule(() -> { + try { + log.debug("Auto-refreshing auth token..."); + this.authResponse = this.clientWs.auth().orElseGet(AuthResponse::new); + scheduleNextAuth(); + } catch (Exception e) { + log.error("Failed to auto-refresh auth token: {}", e.getMessage()); + terminateAutoRefresh(); + } + }, refreshAt, TimeUnit.MILLISECONDS); + } + + private boolean isAutoRefreshable() { + return switcherProperties.getBoolean(ContextKey.AUTO_REFRESH_TOKEN) && + (Objects.isNull(refreshFuture) || refreshFuture.isDone()); + } + + private void terminateAutoRefresh() { + if (Objects.nonNull(refreshFuture)) { + refreshFuture.cancel(true); + refreshFuture = null; + log.debug("Terminated existing auto-refresh task."); + } + } } + + diff --git a/src/test/java/com/switcherapi/client/SwitcherBasicCriteriaResponseTest.java b/src/test/java/com/switcherapi/client/SwitcherBasicCriteriaResponseTest.java index bce8261..9ea0adf 100644 --- a/src/test/java/com/switcherapi/client/SwitcherBasicCriteriaResponseTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherBasicCriteriaResponseTest.java @@ -24,7 +24,7 @@ class SwitcherBasicCriteriaResponseTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); // Load default properties from resources Switchers.configure(ContextBuilder.builder() // Override default properties @@ -40,7 +40,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @BeforeEach diff --git a/src/test/java/com/switcherapi/client/SwitcherBasicTest.java b/src/test/java/com/switcherapi/client/SwitcherBasicTest.java index ec6dba0..300166e 100644 --- a/src/test/java/com/switcherapi/client/SwitcherBasicTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherBasicTest.java @@ -21,7 +21,7 @@ class SwitcherBasicTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); // Load default properties from resources Switchers.configure(ContextBuilder.builder() // Override default properties @@ -37,7 +37,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @BeforeEach diff --git a/src/test/java/com/switcherapi/client/SwitcherConfigNativeTest.java b/src/test/java/com/switcherapi/client/SwitcherConfigNativeTest.java index 1b696fa..f86277c 100644 --- a/src/test/java/com/switcherapi/client/SwitcherConfigNativeTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherConfigNativeTest.java @@ -16,12 +16,12 @@ class SwitcherConfigNativeTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); } @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @Test diff --git a/src/test/java/com/switcherapi/client/SwitcherContextRemoteExecutorTest.java b/src/test/java/com/switcherapi/client/SwitcherContextRemoteExecutorTest.java index 66dfb78..6f85bd6 100644 --- a/src/test/java/com/switcherapi/client/SwitcherContextRemoteExecutorTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherContextRemoteExecutorTest.java @@ -19,12 +19,12 @@ class SwitcherContextRemoteExecutorTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); } @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @Test diff --git a/src/test/java/com/switcherapi/client/SwitcherFail1Test.java b/src/test/java/com/switcherapi/client/SwitcherFail1Test.java index 77e2a37..1e197ab 100644 --- a/src/test/java/com/switcherapi/client/SwitcherFail1Test.java +++ b/src/test/java/com/switcherapi/client/SwitcherFail1Test.java @@ -21,7 +21,7 @@ class SwitcherFail1Test extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -30,7 +30,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); //clean generated outputs SwitcherContext.stopWatchingSnapshot(); diff --git a/src/test/java/com/switcherapi/client/SwitcherFail2Test.java b/src/test/java/com/switcherapi/client/SwitcherFail2Test.java index f8cbe96..217c369 100644 --- a/src/test/java/com/switcherapi/client/SwitcherFail2Test.java +++ b/src/test/java/com/switcherapi/client/SwitcherFail2Test.java @@ -21,7 +21,7 @@ class SwitcherFail2Test extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -30,7 +30,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @BeforeEach diff --git a/src/test/java/com/switcherapi/client/SwitcherForceResolveTest.java b/src/test/java/com/switcherapi/client/SwitcherForceResolveTest.java index d3629cf..f78c32d 100644 --- a/src/test/java/com/switcherapi/client/SwitcherForceResolveTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherForceResolveTest.java @@ -1,6 +1,6 @@ package com.switcherapi.client; -import com.switcherapi.Switchers; +import com.switcherapi.SwitchersBase; import com.switcherapi.client.model.SwitcherRequest; import com.switcherapi.fixture.MockWebServerHelper; import mockwebserver3.QueueDispatcher; @@ -19,10 +19,13 @@ class SwitcherForceResolveTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); - Switchers.loadProperties(); // Load default properties from resources - Switchers.configure(ContextBuilder.builder() // Override default properties + SwitchersBase.configure(ContextBuilder.builder(true) // Override default properties + .context(SwitchersBase.class.getName()) + .domain("domain") + .apiKey("apiKey") + .component("component") .url(String.format("http://localhost:%s", mockBackEnd.getPort())) .local(true) .snapshotLocation(SNAPSHOTS_LOCAL) @@ -31,12 +34,12 @@ static void setup() throws IOException { .snapshotAutoUpdateInterval(null) .environment("fixture1")); - Switchers.initializeClient(); + SwitchersBase.initializeClient(); } @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @BeforeEach @@ -46,7 +49,7 @@ void restoreStubs() { @Test void shouldResolveLocally() { - SwitcherRequest switcher = Switchers.getSwitcher(Switchers.USECASE11); + SwitcherRequest switcher = SwitchersBase.getSwitcher(SwitchersBase.USECASE11); assertTrue(switcher.remote(false).isItOn()); } @@ -59,7 +62,7 @@ void shouldForceResolveRemotely() { givenResponse(generateCriteriaResponse("false", false)); //test - SwitcherRequest switcher = Switchers.getSwitcher(Switchers.USECASE11); + SwitcherRequest switcher = SwitchersBase.getSwitcher(SwitchersBase.USECASE11); assertFalse(switcher.remote(true).isItOn()); } diff --git a/src/test/java/com/switcherapi/client/SwitcherLocal3Test.java b/src/test/java/com/switcherapi/client/SwitcherLocal3Test.java index 52a23a1..347ea4f 100644 --- a/src/test/java/com/switcherapi/client/SwitcherLocal3Test.java +++ b/src/test/java/com/switcherapi/client/SwitcherLocal3Test.java @@ -5,6 +5,7 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.stream.Stream; import com.switcherapi.client.remote.ClientWS; @@ -40,10 +41,13 @@ class SwitcherLocal3Test { private static final String SNAPSHOTS_LOCAL = Paths.get(StringUtils.EMPTY).toAbsolutePath() + "/src/test/resources/snapshot"; private static ExecutorService executorService; + + private static ScheduledExecutorService scheduledExecutorService; @BeforeAll static void setupContext() { executorService = Executors.newSingleThreadExecutor(); + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); SwitcherContext.loadProperties(); SwitcherContext.configure(ContextBuilder.builder() .snapshotLocation(SNAPSHOTS_LOCAL) @@ -56,6 +60,7 @@ static void setupContext() { @AfterAll static void tearDown() { executorService.shutdown(); + scheduledExecutorService.shutdownNow(); } static Stream failTestArguments() { @@ -96,7 +101,7 @@ void localShouldCheckSwitchers() { ClientWS clientWS = ClientWSImpl.build(switcherProperties, executorService, DEFAULT_TIMEOUT); SwitcherValidator validatorService = new ValidatorService(); SwitcherLocalService switcherLocal = new SwitcherLocalService( - new ClientRemoteService(clientWS, switcherProperties), + new ClientRemoteService(clientWS, switcherProperties, scheduledExecutorService), new ClientLocalService(validatorService), switcherProperties); switcherLocal.init(); @@ -114,7 +119,7 @@ void localShouldCheckSwitchers_notFound() { ClientWS clientWS = ClientWSImpl.build(switcherProperties, executorService, DEFAULT_TIMEOUT); SwitcherValidator validatorService = new ValidatorService(); SwitcherLocalService switcherLocal = new SwitcherLocalService( - new ClientRemoteService(clientWS, switcherProperties), + new ClientRemoteService(clientWS, switcherProperties, scheduledExecutorService), new ClientLocalService(validatorService), switcherProperties); switcherLocal.init(); diff --git a/src/test/java/com/switcherapi/client/SwitcherRemoteAutoRefreshTokenTest.java b/src/test/java/com/switcherapi/client/SwitcherRemoteAutoRefreshTokenTest.java new file mode 100644 index 0000000..948a954 --- /dev/null +++ b/src/test/java/com/switcherapi/client/SwitcherRemoteAutoRefreshTokenTest.java @@ -0,0 +1,98 @@ +package com.switcherapi.client; + +import com.switcherapi.SwitchersBase; +import com.switcherapi.client.exception.SwitcherRemoteException; +import com.switcherapi.client.model.SwitcherRequest; +import com.switcherapi.fixture.CountDownHelper; +import com.switcherapi.fixture.MockWebServerHelper; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class SwitcherRemoteAutoRefreshTokenTest extends MockWebServerHelper { + + @BeforeEach + void setup() throws IOException { + setupMockServer(); + } + + @AfterEach + void tearDown() { + tearDownMockServer(); + SwitchersBase.terminateTokenRefreshWorker(); + } + + /** + * The scheduled refresh worker operates using a 5s buffer to trigger the refresh before the token expires, + * so we need to set the token expiration time accordingly to test the auto-refresh behavior. + */ + @Test + void shouldAutoRefreshAuthToken() { + //auth - 1st (regular auth) - 2nd (scheduled refresh) + givenResponse(generateMockAuth(7)); // 5s buffer - 7s exp = 2s for async refresh + givenResponse(generateCriteriaResponse("true", false)); + givenResponse(generateMockAuth(60)); + givenResponse(generateCriteriaResponse("true", false)); + + //when + givenAutoRefreshToken(true); + + //test + SwitcherRequest switcher = SwitchersBase.getSwitcher(SwitchersBase.USECASE11); + assertTrue(switcher.isItOn()); + CountDownHelper.wait(2); + assertTrue(switcher.isItOn()); + } + + @Test + void shouldNotAutoRefreshAuthTokenWhenDisabled() { + //auth - 1st (regular auth) - 2nd (regular auth) + givenResponse(generateMockAuth(1)); + givenResponse(generateCriteriaResponse("true", false)); + givenResponse(generateMockAuth(60)); + givenResponse(generateCriteriaResponse("true", false)); + + //when + givenAutoRefreshToken(false); + + //test + SwitcherRequest switcher = SwitchersBase.getSwitcher(SwitchersBase.USECASE11); + assertTrue(switcher.isItOn()); + CountDownHelper.wait(1); + assertTrue(switcher.isItOn()); + } + + @Test + void shouldNotAutoRefreshAuthTokenWhenAuthFails() { + //auth - 1st (regular auth) - 2nd (scheduled refresh) + givenResponse(generateMockAuth(7)); // 5s buffer - 6s exp = 1s for async refresh + givenResponse(generateCriteriaResponse("true", false)); + givenResponse(generateStatusResponse("500")); + + //when + givenAutoRefreshToken(true); + + //test + SwitcherRequest switcher = SwitchersBase.getSwitcher(SwitchersBase.USECASE11); + assertTrue(switcher.isItOn()); + CountDownHelper.wait(2); + assertThrows(SwitcherRemoteException.class, switcher::isItOn); + } + + private void givenAutoRefreshToken(boolean enabled) { + SwitchersBase.configure(ContextBuilder.builder(true) + .context(SwitchersBase.class.getName()) + .url(String.format("http://localhost:%s", mockBackEnd.getPort())) + .domain("domain") + .apiKey("apiKey") + .component("component") + .autoRefreshToken(enabled)); + + SwitchersBase.initializeClient(); + } +} diff --git a/src/test/java/com/switcherapi/client/SwitcherSilentModeTest.java b/src/test/java/com/switcherapi/client/SwitcherSilentModeTest.java index 1b7d2a1..870695a 100644 --- a/src/test/java/com/switcherapi/client/SwitcherSilentModeTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherSilentModeTest.java @@ -23,7 +23,7 @@ class SwitcherSilentModeTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -31,7 +31,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @BeforeEach diff --git a/src/test/java/com/switcherapi/client/SwitcherSnapshotLookupTest.java b/src/test/java/com/switcherapi/client/SwitcherSnapshotLookupTest.java index 07241d4..bd6694e 100644 --- a/src/test/java/com/switcherapi/client/SwitcherSnapshotLookupTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherSnapshotLookupTest.java @@ -28,7 +28,7 @@ static void setup() throws IOException { Files.deleteIfExists(Paths.get(RESOURCES_PATH + "/new_folder")); Files.deleteIfExists(Paths.get(RESOURCES_PATH + "/generated_mock_default.json")); - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -36,7 +36,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() throws IOException { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); //clean generated outputs SwitcherContext.stopWatchingSnapshot(); diff --git a/src/test/java/com/switcherapi/client/SwitcherSnapshotValidationFailTest.java b/src/test/java/com/switcherapi/client/SwitcherSnapshotValidationFailTest.java index 42e6b8c..e72379b 100644 --- a/src/test/java/com/switcherapi/client/SwitcherSnapshotValidationFailTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherSnapshotValidationFailTest.java @@ -25,7 +25,7 @@ class SwitcherSnapshotValidationFailTest extends MockWebServerHelper { static void setup() throws IOException { Files.deleteIfExists(Paths.get(RESOURCES_PATH + "/not_accessible")); - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -33,7 +33,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); //clean generated outputs SwitcherContext.stopWatchingSnapshot(); diff --git a/src/test/java/com/switcherapi/client/SwitcherSnapshotValidationTest.java b/src/test/java/com/switcherapi/client/SwitcherSnapshotValidationTest.java index 5900e94..dcd4597 100644 --- a/src/test/java/com/switcherapi/client/SwitcherSnapshotValidationTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherSnapshotValidationTest.java @@ -22,7 +22,7 @@ class SwitcherSnapshotValidationTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -30,7 +30,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); //clean generated outputs SwitcherContext.stopWatchingSnapshot(); diff --git a/src/test/java/com/switcherapi/client/SwitcherThrottle1Test.java b/src/test/java/com/switcherapi/client/SwitcherThrottle1Test.java index 75eb1de..7378d19 100644 --- a/src/test/java/com/switcherapi/client/SwitcherThrottle1Test.java +++ b/src/test/java/com/switcherapi/client/SwitcherThrottle1Test.java @@ -18,7 +18,7 @@ class SwitcherThrottle1Test extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); SwitchersBase.configure(ContextBuilder.builder(true) .context(SwitchersBase.class.getName()) @@ -33,7 +33,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @Test @@ -54,7 +54,7 @@ void shouldReturnTrue_withThrottle() { .checkValue("value") .throttle(1000); - for (int i = 0; i < 100; i++) { + for (int i = 0; i < 50; i++) { assertTrue(switcher.isItOn()); } diff --git a/src/test/java/com/switcherapi/client/SwitcherThrottle2Test.java b/src/test/java/com/switcherapi/client/SwitcherThrottle2Test.java index 33d2783..c61804d 100644 --- a/src/test/java/com/switcherapi/client/SwitcherThrottle2Test.java +++ b/src/test/java/com/switcherapi/client/SwitcherThrottle2Test.java @@ -17,7 +17,7 @@ class SwitcherThrottle2Test extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); SwitchersBase.configure(ContextBuilder.builder(true) .context(SwitchersBase.class.getName()) @@ -32,7 +32,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); } @Test diff --git a/src/test/java/com/switcherapi/client/SwitcherValidateTest.java b/src/test/java/com/switcherapi/client/SwitcherValidateTest.java index eac35c3..e8dcb70 100644 --- a/src/test/java/com/switcherapi/client/SwitcherValidateTest.java +++ b/src/test/java/com/switcherapi/client/SwitcherValidateTest.java @@ -20,7 +20,7 @@ class SwitcherValidateTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -29,7 +29,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); //clean generated outputs SwitcherContext.stopWatchingSnapshot(); diff --git a/src/test/java/com/switcherapi/client/remote/ClientRemoteTest.java b/src/test/java/com/switcherapi/client/remote/ClientRemoteTest.java index c833481..7ac6436 100644 --- a/src/test/java/com/switcherapi/client/remote/ClientRemoteTest.java +++ b/src/test/java/com/switcherapi/client/remote/ClientRemoteTest.java @@ -29,6 +29,7 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import static com.switcherapi.client.remote.Constants.DEFAULT_TIMEOUT; import static org.junit.jupiter.api.Assertions.*; @@ -37,12 +38,15 @@ class ClientRemoteTest extends MockWebServerHelper { private static ExecutorService executorService; + private static ScheduledExecutorService scheduledExecutorService; + private ClientRemote clientRemote; @BeforeAll static void setup() throws IOException { executorService = Executors.newSingleThreadExecutor(); - MockWebServerHelper.setupMockServer(); + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -51,14 +55,16 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); executorService.shutdown(); + scheduledExecutorService.shutdownNow(); } @BeforeEach void resetSwitcherContextState() { SwitcherProperties switcherProperties = Switchers.getSwitcherProperties(); - clientRemote = new ClientRemoteService(ClientWSImpl.build(switcherProperties, executorService, DEFAULT_TIMEOUT), switcherProperties); + clientRemote = new ClientRemoteService(ClientWSImpl.build(switcherProperties, executorService, DEFAULT_TIMEOUT), + switcherProperties, scheduledExecutorService); ((QueueDispatcher) mockBackEnd.getDispatcher()).clear(); Switchers.configure(ContextBuilder.builder().checkSwitchers(false)); diff --git a/src/test/java/com/switcherapi/client/remote/ClientWSBuilderTest.java b/src/test/java/com/switcherapi/client/remote/ClientWSBuilderTest.java index 96e2e00..2b05b9b 100644 --- a/src/test/java/com/switcherapi/client/remote/ClientWSBuilderTest.java +++ b/src/test/java/com/switcherapi/client/remote/ClientWSBuilderTest.java @@ -32,14 +32,14 @@ static void tearDown() { @Test void shouldCreateClientBuilder() { - // given + //given SwitcherContextBase.configure(ContextBuilder.builder() .truststorePath("") .truststorePassword("")); SwitcherProperties properties = SwitcherContextBase.getSwitcherProperties(); - // test + //test HttpClient.Builder clientBuilder = ClientWSBuilder.builder(executorService, properties); assertNotNull(clientBuilder); @@ -50,7 +50,7 @@ void shouldCreateClientBuilder() { @Test void shouldCreateClientBuilderSSL() { - // given + //given String truststorePath = Objects.requireNonNull(getClass().getClassLoader() .getResource("keystore.jks")).getPath(); @@ -60,7 +60,7 @@ void shouldCreateClientBuilderSSL() { SwitcherProperties properties = SwitcherContextBase.getSwitcherProperties(); - // test + //test HttpClient.Builder clientBuilder = ClientWSBuilder.builder(executorService, properties); assertNotNull(clientBuilder); @@ -71,7 +71,7 @@ void shouldCreateClientBuilderSSL() { @Test void shouldNotCreateClientBuilderSSL_invalidKeystorePassword() { - // given + //given String truststorePath = Objects.requireNonNull(getClass().getClassLoader() .getResource("keystore.jks")).getPath(); @@ -81,20 +81,20 @@ void shouldNotCreateClientBuilderSSL_invalidKeystorePassword() { SwitcherProperties properties = SwitcherContextBase.getSwitcherProperties(); - // test + //test assertThrows(SwitcherException.class, () -> ClientWSBuilder.builder(executorService, properties)); } @Test void shouldNotCreateClientBuilderSSL_invalidKeystorePath() { - // given + //given SwitcherContextBase.configure(ContextBuilder.builder() .truststorePath("INVALID") .truststorePassword("changeit")); SwitcherProperties properties = SwitcherContextBase.getSwitcherProperties(); - // test + //test assertThrows(SwitcherException.class, () -> ClientWSBuilder.builder(executorService, properties)); } } diff --git a/src/test/java/com/switcherapi/client/remote/ClientWSTest.java b/src/test/java/com/switcherapi/client/remote/ClientWSTest.java index f0fdc9f..8653937 100644 --- a/src/test/java/com/switcherapi/client/remote/ClientWSTest.java +++ b/src/test/java/com/switcherapi/client/remote/ClientWSTest.java @@ -24,7 +24,7 @@ class ClientWSTest extends MockWebServerHelper { @BeforeAll static void setup() throws IOException { executorService = Executors.newSingleThreadExecutor(); - MockWebServerHelper.setupMockServer(); + setupMockServer(); Switchers.loadProperties(); Switchers.configure(ContextBuilder.builder().url(String.format("http://localhost:%s", mockBackEnd.getPort()))); @@ -33,7 +33,7 @@ static void setup() throws IOException { @AfterAll static void tearDown() { - MockWebServerHelper.tearDownMockServer(); + tearDownMockServer(); executorService.shutdown(); } @@ -47,22 +47,22 @@ void resetSwitcherContextState() { @Test void shouldBeAlive() { - // given + //given ClientWS clientWS = ClientWSImpl.build(Switchers.getSwitcherProperties(), executorService, DEFAULT_TIMEOUT); givenResponse(generateTimeOut(100)); - // test + //test boolean response = clientWS.isAlive(); assertTrue(response); } @Test void shouldTimeOut() { - // given + //given ClientWS clientWS = ClientWSImpl.build(Switchers.getSwitcherProperties(), executorService, DEFAULT_TIMEOUT); givenResponse(generateTimeOut(3500)); - // test + //test boolean response = clientWS.isAlive(); assertFalse(response); } @@ -72,7 +72,7 @@ void shouldExtendTimeOut() { ClientWS clientWS = ClientWSImpl.build(Switchers.getSwitcherProperties(), executorService, 4000); givenResponse(generateTimeOut(3500)); - // test + //test boolean response = clientWS.isAlive(); assertTrue(response); } diff --git a/src/test/java/com/switcherapi/client/service/local/SwitcherLocalServiceTest.java b/src/test/java/com/switcherapi/client/service/local/SwitcherLocalServiceTest.java index 4fc8307..d6ef92f 100644 --- a/src/test/java/com/switcherapi/client/service/local/SwitcherLocalServiceTest.java +++ b/src/test/java/com/switcherapi/client/service/local/SwitcherLocalServiceTest.java @@ -8,6 +8,7 @@ import java.nio.file.Paths; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicBoolean; import com.switcherapi.client.SwitcherProperties; @@ -31,12 +32,15 @@ class SwitcherLocalServiceTest { private static final String SNAPSHOTS_LOCAL = Paths.get(StringUtils.EMPTY).toAbsolutePath() + "/src/test/resources"; private static ExecutorService executorService; + + private static ScheduledExecutorService scheduledExecutorService; private static SwitcherLocalService service; @BeforeAll static void init() { executorService = Executors.newSingleThreadExecutor(); + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); SwitchersBase.configure(ContextBuilder.builder() .context(SwitchersBase.class.getName()) .snapshotLocation(SNAPSHOTS_LOCAL) @@ -47,13 +51,14 @@ static void init() { ClientWS clientWS = ClientWSImpl.build(properties, executorService, DEFAULT_TIMEOUT); SwitcherValidator validatorService = new ValidatorService(); service = new SwitcherLocalService( - new ClientRemoteService(clientWS, properties), + new ClientRemoteService(clientWS, properties, scheduledExecutorService), new ClientLocalService(validatorService), properties); } @AfterAll static void tearDown() { executorService.shutdown(); + scheduledExecutorService.shutdownNow(); } @Test diff --git a/src/test/java/com/switcherapi/playground/ClientPlayground.java b/src/test/java/com/switcherapi/playground/ClientPlayground.java index 0277ddd..3c797b7 100644 --- a/src/test/java/com/switcherapi/playground/ClientPlayground.java +++ b/src/test/java/com/switcherapi/playground/ClientPlayground.java @@ -19,18 +19,16 @@ public class ClientPlayground { public static void test() { new Features().configureClient(); - Switcher switcher = getSwitcher(CLIENT_JAVA_FEATURE) - .bypassMetrics(); + Switcher switcher = getSwitcher(CLIENT_JAVA_FEATURE).bypassMetrics(); scheduler.scheduleAtFixedRate(() -> { try { long time = System.currentTimeMillis(); - logger.info("Switcher is on: {}", switcher.isItOn()); - logger.info("Time elapsed: {}", System.currentTimeMillis() - time); + logger.info("Switcher is on: {} - {} ms", switcher.isItOn(), System.currentTimeMillis() - time); } catch (Exception e) { logger.error(e.getMessage(), e); } - }, 0, 5, TimeUnit.SECONDS); + }, 0, 500, TimeUnit.MILLISECONDS); } public static void main(String[] args) { diff --git a/src/test/java/com/switcherapi/playground/Features.java b/src/test/java/com/switcherapi/playground/Features.java index 6d8a728..e7a4299 100644 --- a/src/test/java/com/switcherapi/playground/Features.java +++ b/src/test/java/com/switcherapi/playground/Features.java @@ -13,12 +13,11 @@ public class Features extends SwitcherContextBase { protected void configureClient() { configure(ContextBuilder.builder() .context(Features.class.getName()) - .url("https://api.switcherapi.com") + .url("http://localhost:3001") .apiKey(System.getenv("switcher.api.key")) .component(System.getenv("switcher.component")) .domain(System.getenv("switcher.domain")) - .local(true) - .snapshotLocation("./src/test/resources/snapshot/playground")); + .autoRefreshToken(true)); initializeClient(); }