From 20cde708d7d7c5dc879085ec06defebe75637649 Mon Sep 17 00:00:00 2001
From: Roger Floriano <31597636+petruki@users.noreply.github.com>
Date: Sat, 21 Jun 2025 12:21:51 -0700
Subject: [PATCH 1/2] Added switcher.snapshot.watcher configuration (#347)
---
README.md | 15 +++-
.../switcherapi/client/ContextBuilder.java | 9 +++
.../switcherapi/client/SwitcherConfig.java | 10 +++
.../client/SwitcherContextBase.java | 22 +++++-
.../client/SwitcherPropertiesImpl.java | 46 ++++++-----
.../switcherapi/client/model/ContextKey.java | 5 ++
.../client/utils/SnapshotTest.java | 77 +++++++++++++++++++
.../utils/SnapshotWatcherContextTest.java | 69 +++++++++++++++++
.../client/utils/SnapshotWatcherTest.java | 65 +---------------
.../utils/SnapshotWatcherWorkerTest.java | 19 +----
src/test/resources/switcherapi.properties | 1 +
11 files changed, 231 insertions(+), 107 deletions(-)
create mode 100644 src/test/java/com/github/switcherapi/client/utils/SnapshotTest.java
create mode 100644 src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherContextTest.java
diff --git a/README.md b/README.md
index 9b33a3f..5cb5c87 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ switcher.check -> true/false When true, it will check Switcher Keys
switcher.relay.restrict -> true/false When true, it will check snapshot relay status
switcher.snapshot.location -> Folder from where snapshots will be saved/read
switcher.snapshot.auto -> true/false Automated lookup for snapshot when initializing the client
+switcher.snapshot.watcher -> true/false Enable the watcher to monitor the snapshot file for changes during runtime
switcher.snapshot.skipvalidation -> true/false Skip snapshotValidation() that can be used for UT executions
switcher.snapshot.updateinterval -> Enable the Snapshot Auto Update given an interval of time - e.g. 1s (s: seconds, m: minutes)
switcher.silent -> Enable contigency given the time for the client to retry - e.g. 5s (s: seconds - m: minutes - h: hours)
@@ -252,9 +253,9 @@ MyAppFeatures.scheduleSnapshotAutoUpdate("5s", new SnapshotCallback() {
});
```
-## Real-time snapshot reload
+## Real-time snapshot reload (Hot-swapping)
Let the Switcher Client manage your application local snapshot.
-These features allow you to configure the SDK to automatically update the snapshot in the background.
+These features allow you to configure the SDK to automatically update the snapshot during runtime.
1. This feature will update the in-memory Snapshot every time the file is modified.
@@ -263,6 +264,15 @@ MyAppFeatures.watchSnapshot();
MyAppFeatures.stopWatchingSnapshot();
```
+Alternatively, you can also set the Switcher Context configuration to start watching the snapshot file during the client initialization.
+
+```java
+MyAppFeatures.configure(ContextBuilder.builder()
+ .snapshotWatcher(true));
+
+MyAppFeatures.initializeClient();
+```
+
2. You can also perform snapshot update validation to verify if there are changes to be pulled.
```java
@@ -319,7 +329,6 @@ Alternatively, you can also set the Switcher Context configuration to check duri
```java
MyAppFeatures.configure(ContextBuilder.builder()
- ...
.checkSwitchers(true));
MyAppFeatures.initializeClient();
diff --git a/src/main/java/com/github/switcherapi/client/ContextBuilder.java b/src/main/java/com/github/switcherapi/client/ContextBuilder.java
index 15b5139..7d3930c 100644
--- a/src/main/java/com/github/switcherapi/client/ContextBuilder.java
+++ b/src/main/java/com/github/switcherapi/client/ContextBuilder.java
@@ -159,6 +159,15 @@ public ContextBuilder snapshotSkipValidation(boolean snapshotSkipValidation) {
return this;
}
+ /**
+ * @param snapshotWatcher true/false When true, it will watch the snapshot file for changes and update the switchers accordingly
+ * @return ContextBuilder
+ */
+ public ContextBuilder snapshotWatcher(boolean snapshotWatcher) {
+ switcherProperties.setValue(ContextKey.SNAPSHOT_WATCHER, snapshotWatcher);
+ return this;
+ }
+
/**
* @param retryAfter Enable contingency given the time for the client to retry - e.g. 5s (s: seconds - m: minutes - h: hours)
* @return ContextBuilder
diff --git a/src/main/java/com/github/switcherapi/client/SwitcherConfig.java b/src/main/java/com/github/switcherapi/client/SwitcherConfig.java
index e7db78d..b3dee9e 100644
--- a/src/main/java/com/github/switcherapi/client/SwitcherConfig.java
+++ b/src/main/java/com/github/switcherapi/client/SwitcherConfig.java
@@ -51,6 +51,7 @@ protected void updateSwitcherConfig(SwitcherProperties properties) {
snapshotConfig.setLocation(properties.getValue(ContextKey.SNAPSHOT_LOCATION));
snapshotConfig.setAuto(properties.getBoolean(ContextKey.SNAPSHOT_AUTO_LOAD));
snapshotConfig.setSkipValidation(properties.getBoolean(ContextKey.SNAPSHOT_SKIP_VALIDATION));
+ snapshotConfig.setWatcher(properties.getBoolean(ContextKey.SNAPSHOT_WATCHER));
snapshotConfig.setUpdateInterval(properties.getValue(ContextKey.SNAPSHOT_AUTO_UPDATE_INTERVAL));
setSnapshot(snapshotConfig);
@@ -148,6 +149,7 @@ public static class SnapshotConfig {
private String location;
private boolean auto;
private boolean skipValidation;
+ private boolean watcher;
private String updateInterval;
public String getLocation() {
@@ -174,6 +176,14 @@ public void setSkipValidation(boolean skipValidation) {
this.skipValidation = skipValidation;
}
+ public boolean isWatcher() {
+ return watcher;
+ }
+
+ public void setWatcher(boolean watcher) {
+ this.watcher = watcher;
+ }
+
public String getUpdateInterval() {
return updateInterval;
}
diff --git a/src/main/java/com/github/switcherapi/client/SwitcherContextBase.java b/src/main/java/com/github/switcherapi/client/SwitcherContextBase.java
index f7f7aba..b5013ab 100644
--- a/src/main/java/com/github/switcherapi/client/SwitcherContextBase.java
+++ b/src/main/java/com/github/switcherapi/client/SwitcherContextBase.java
@@ -115,6 +115,7 @@ protected void configureClient() {
.poolConnectionSize(poolSize)
.snapshotLocation(snapshot.getLocation())
.snapshotAutoLoad(snapshot.isAuto())
+ .snapshotWatcher(snapshot.isWatcher())
.snapshotSkipValidation(snapshot.isSkipValidation())
.snapshotAutoUpdateInterval(snapshot.getUpdateInterval())
.truststorePath(truststore.getPath())
@@ -185,6 +186,7 @@ public static void initializeClient() {
switcherExecutor = buildInstance();
loadSwitchers();
+ scheduleSnapshotWatcher();
scheduleSnapshotAutoUpdate(contextStr(ContextKey.SNAPSHOT_AUTO_UPDATE_INTERVAL));
ContextBuilder.preConfigure(switcherProperties);
SwitcherUtils.debug(logger, "Switcher Client initialized");
@@ -270,6 +272,18 @@ private static void loadSwitchers() throws SwitchersValidationException {
}
}
+ /**
+ * Schedule a task to watch the snapshot file for modifications.
+ * The task will be executed in a single thread executor service.
+ *
+ * (*) Requires client to use local settings
+ */
+ private static void scheduleSnapshotWatcher() {
+ if (contextBol(ContextKey.SNAPSHOT_WATCHER)) {
+ watchSnapshot();
+ }
+ }
+
/**
* Schedule a task to update the snapshot automatically.
* The task will be executed in a single thread executor service.
@@ -388,8 +402,8 @@ public static SwitcherRequest getSwitcher(String key) {
}
/**
- * Validate if the snapshot version is the same as the one in the API.
- * If the version is different, it will update the snapshot in memory.
+ * Validate if the local snapshot version is the same as remote.
+ * If the version is different, it will update the local snapshot.
*
* @return true if snapshot was updated
*/
@@ -404,7 +418,7 @@ public static boolean validateSnapshot() {
/**
* Start watching snapshot files for modifications.
- * When the file is modified the in-memory snapshot will reload
+ * When the file is modified the local snapshot will reload
*
*
* (*) Requires client to use local settings
@@ -415,7 +429,7 @@ public static void watchSnapshot() {
/**
* Start watching snapshot files for modifications.
- * When the file is modified the in-memory snapshot will reload
+ * When the file is modified the local snapshot will reload
*
*
* (*) Requires client to use local settings
diff --git a/src/main/java/com/github/switcherapi/client/SwitcherPropertiesImpl.java b/src/main/java/com/github/switcherapi/client/SwitcherPropertiesImpl.java
index ea0f88e..8c832c1 100644
--- a/src/main/java/com/github/switcherapi/client/SwitcherPropertiesImpl.java
+++ b/src/main/java/com/github/switcherapi/client/SwitcherPropertiesImpl.java
@@ -2,7 +2,6 @@
import com.github.switcherapi.client.exception.SwitcherContextException;
import com.github.switcherapi.client.model.ContextKey;
-import com.github.switcherapi.client.utils.SwitcherUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
@@ -10,18 +9,24 @@
import java.util.Properties;
import static com.github.switcherapi.client.remote.Constants.*;
+import static com.github.switcherapi.client.utils.SwitcherUtils.*;
public class SwitcherPropertiesImpl implements SwitcherProperties {
private final Map properties = new HashMap<>();
public SwitcherPropertiesImpl() {
+ initDefaults();
+ }
+
+ private void initDefaults() {
setValue(ContextKey.ENVIRONMENT, DEFAULT_ENV);
setValue(ContextKey.REGEX_TIMEOUT, DEFAULT_REGEX_TIMEOUT);
setValue(ContextKey.TIMEOUT_MS, DEFAULT_TIMEOUT);
setValue(ContextKey.POOL_CONNECTION_SIZE, DEFAULT_POOL_SIZE);
setValue(ContextKey.SNAPSHOT_AUTO_LOAD, false);
setValue(ContextKey.SNAPSHOT_SKIP_VALIDATION, false);
+ setValue(ContextKey.SNAPSHOT_WATCHER, false);
setValue(ContextKey.LOCAL_MODE, false);
setValue(ContextKey.CHECK_SWITCHERS, false);
setValue(ContextKey.RESTRICT_RELAY, true);
@@ -29,25 +34,26 @@ public SwitcherPropertiesImpl() {
@Override
public void loadFromProperties(Properties prop) {
- setValue(ContextKey.CONTEXT_LOCATION, SwitcherUtils.resolveProperties(ContextKey.CONTEXT_LOCATION.getParam(), prop));
- setValue(ContextKey.URL, SwitcherUtils.resolveProperties(ContextKey.URL.getParam(), prop));
- setValue(ContextKey.APIKEY, SwitcherUtils.resolveProperties(ContextKey.APIKEY.getParam(), prop));
- setValue(ContextKey.DOMAIN, SwitcherUtils.resolveProperties(ContextKey.DOMAIN.getParam(), prop));
- setValue(ContextKey.COMPONENT, SwitcherUtils.resolveProperties(ContextKey.COMPONENT.getParam(), prop));
- setValue(ContextKey.ENVIRONMENT, getValueDefault(SwitcherUtils.resolveProperties(ContextKey.ENVIRONMENT.getParam(), prop), DEFAULT_ENV));
- setValue(ContextKey.SNAPSHOT_LOCATION, SwitcherUtils.resolveProperties(ContextKey.SNAPSHOT_LOCATION.getParam(), prop));
- setValue(ContextKey.SNAPSHOT_SKIP_VALIDATION, getBoolDefault(SwitcherUtils.resolveProperties(ContextKey.SNAPSHOT_SKIP_VALIDATION.getParam(), prop), false));
- setValue(ContextKey.SNAPSHOT_AUTO_LOAD, getBoolDefault(SwitcherUtils.resolveProperties(ContextKey.SNAPSHOT_AUTO_LOAD.getParam(), prop), false));
- setValue(ContextKey.SNAPSHOT_AUTO_UPDATE_INTERVAL, SwitcherUtils.resolveProperties(ContextKey.SNAPSHOT_AUTO_UPDATE_INTERVAL.getParam(), prop));
- setValue(ContextKey.SILENT_MODE, SwitcherUtils.resolveProperties(ContextKey.SILENT_MODE.getParam(), prop));
- setValue(ContextKey.LOCAL_MODE, getBoolDefault(SwitcherUtils.resolveProperties(ContextKey.LOCAL_MODE.getParam(), prop), false));
- setValue(ContextKey.CHECK_SWITCHERS, getBoolDefault(SwitcherUtils.resolveProperties(ContextKey.CHECK_SWITCHERS.getParam(), prop), false));
- setValue(ContextKey.RESTRICT_RELAY, getBoolDefault(SwitcherUtils.resolveProperties(ContextKey.RESTRICT_RELAY.getParam(), prop), true));
- setValue(ContextKey.REGEX_TIMEOUT, getIntDefault(SwitcherUtils.resolveProperties(ContextKey.REGEX_TIMEOUT.getParam(), prop), DEFAULT_REGEX_TIMEOUT));
- setValue(ContextKey.TRUSTSTORE_PATH, SwitcherUtils.resolveProperties(ContextKey.TRUSTSTORE_PATH.getParam(), prop));
- setValue(ContextKey.TRUSTSTORE_PASSWORD, SwitcherUtils.resolveProperties(ContextKey.TRUSTSTORE_PASSWORD.getParam(), prop));
- setValue(ContextKey.TIMEOUT_MS, getIntDefault(SwitcherUtils.resolveProperties(ContextKey.TIMEOUT_MS.getParam(), prop), DEFAULT_TIMEOUT));
- setValue(ContextKey.POOL_CONNECTION_SIZE, getIntDefault(SwitcherUtils.resolveProperties(ContextKey.POOL_CONNECTION_SIZE.getParam(), prop), DEFAULT_POOL_SIZE));
+ setValue(ContextKey.CONTEXT_LOCATION, resolveProperties(ContextKey.CONTEXT_LOCATION.getParam(), prop));
+ setValue(ContextKey.URL, resolveProperties(ContextKey.URL.getParam(), prop));
+ setValue(ContextKey.APIKEY, resolveProperties(ContextKey.APIKEY.getParam(), prop));
+ setValue(ContextKey.DOMAIN, resolveProperties(ContextKey.DOMAIN.getParam(), prop));
+ setValue(ContextKey.COMPONENT, resolveProperties(ContextKey.COMPONENT.getParam(), prop));
+ setValue(ContextKey.ENVIRONMENT, getValueDefault(resolveProperties(ContextKey.ENVIRONMENT.getParam(), prop), DEFAULT_ENV));
+ setValue(ContextKey.SNAPSHOT_LOCATION, resolveProperties(ContextKey.SNAPSHOT_LOCATION.getParam(), prop));
+ setValue(ContextKey.SNAPSHOT_SKIP_VALIDATION, getBoolDefault(resolveProperties(ContextKey.SNAPSHOT_SKIP_VALIDATION.getParam(), prop), false));
+ setValue(ContextKey.SNAPSHOT_AUTO_LOAD, getBoolDefault(resolveProperties(ContextKey.SNAPSHOT_AUTO_LOAD.getParam(), prop), false));
+ setValue(ContextKey.SNAPSHOT_AUTO_UPDATE_INTERVAL, resolveProperties(ContextKey.SNAPSHOT_AUTO_UPDATE_INTERVAL.getParam(), prop));
+ setValue(ContextKey.SNAPSHOT_WATCHER, getBoolDefault(resolveProperties(ContextKey.SNAPSHOT_WATCHER.getParam(), prop), false));
+ setValue(ContextKey.SILENT_MODE, resolveProperties(ContextKey.SILENT_MODE.getParam(), 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.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));
+ setValue(ContextKey.TIMEOUT_MS, getIntDefault(resolveProperties(ContextKey.TIMEOUT_MS.getParam(), prop), DEFAULT_TIMEOUT));
+ setValue(ContextKey.POOL_CONNECTION_SIZE, getIntDefault(resolveProperties(ContextKey.POOL_CONNECTION_SIZE.getParam(), prop), DEFAULT_POOL_SIZE));
}
@Override
diff --git a/src/main/java/com/github/switcherapi/client/model/ContextKey.java b/src/main/java/com/github/switcherapi/client/model/ContextKey.java
index a87f75f..1e1cca7 100644
--- a/src/main/java/com/github/switcherapi/client/model/ContextKey.java
+++ b/src/main/java/com/github/switcherapi/client/model/ContextKey.java
@@ -58,6 +58,11 @@ public enum ContextKey {
* (String) Interval given to the library to update the snapshot
*/
SNAPSHOT_AUTO_UPDATE_INTERVAL("switcher.snapshot.updateinterval"),
+
+ /**
+ * (boolean) Defines if the client will watch the snapshot file for changes and update the switchers accordingly. (default is false)
+ */
+ SNAPSHOT_WATCHER("switcher.snapshot.watcher"),
/**
* (String) Defines if client will work in silent mode by specifying the time interval to retry
diff --git a/src/test/java/com/github/switcherapi/client/utils/SnapshotTest.java b/src/test/java/com/github/switcherapi/client/utils/SnapshotTest.java
new file mode 100644
index 0000000..419d502
--- /dev/null
+++ b/src/test/java/com/github/switcherapi/client/utils/SnapshotTest.java
@@ -0,0 +1,77 @@
+package com.github.switcherapi.client.utils;
+
+import com.github.switcherapi.SwitchersBase;
+import com.github.switcherapi.client.model.criteria.Data;
+import com.github.switcherapi.client.model.criteria.Domain;
+import com.github.switcherapi.client.model.criteria.Snapshot;
+import com.github.switcherapi.client.service.WorkerName;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+abstract class SnapshotTest {
+
+ private static final Logger logger = LoggerFactory.getLogger(SnapshotTest.class);
+
+ protected static final String SNAPSHOTS_LOCAL = Paths.get(StringUtils.EMPTY).toAbsolutePath() + "/src/test/resources";
+
+ protected static void removeGeneratedFiles() throws IOException {
+ SwitchersBase.stopWatchingSnapshot();
+ Files.deleteIfExists(Paths.get(SNAPSHOTS_LOCAL + "\\generated_watcher_default.json"));
+ }
+
+ protected static void generateFixture() {
+ final Snapshot mockedSnapshot = new Snapshot();
+ final Data data = new Data();
+ data.setDomain(SnapshotLoader.loadSnapshot(SNAPSHOTS_LOCAL + "/snapshot_watcher.json"));
+ mockedSnapshot.setData(data);
+
+ SnapshotLoader.saveSnapshot(mockedSnapshot, SNAPSHOTS_LOCAL, "generated_watcher_default");
+ }
+
+ protected void changeFixture() {
+ final Snapshot mockedSnapshot = new Snapshot();
+ final Data data = new Data();
+ data.setDomain(SnapshotLoader.loadSnapshot(SNAPSHOTS_LOCAL + "/snapshot_watcher.json"));
+ mockedSnapshot.setData(data);
+
+ data.setDomain(new Domain(
+ data.getDomain().getName(),
+ data.getDomain().getDescription(),
+ !data.getDomain().isActivated(),
+ data.getDomain().getVersion(),
+ data.getDomain().getGroup()));
+
+ final Gson gson = new GsonBuilder().setPrettyPrinting().create();
+ writeFixture(gson.toJson(mockedSnapshot));
+ }
+
+ protected void writeFixture(String content) {
+ try (
+ final FileWriter fileWriter = new FileWriter(
+ String.format("%s/%s.json", SNAPSHOTS_LOCAL, "generated_watcher_default"));
+
+ final BufferedWriter bw = new BufferedWriter(fileWriter);
+ final PrintWriter wr = new PrintWriter(bw)) {
+ wr.write(content);
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ protected void assertWorker(boolean exists) {
+ assertEquals(exists, Thread.getAllStackTraces().keySet().stream()
+ .anyMatch(t -> t.getName().equals(WorkerName.SNAPSHOT_WATCH_WORKER.toString())));
+ }
+}
diff --git a/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherContextTest.java b/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherContextTest.java
new file mode 100644
index 0000000..b44c7ba
--- /dev/null
+++ b/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherContextTest.java
@@ -0,0 +1,69 @@
+package com.github.switcherapi.client.utils;
+
+import com.github.switcherapi.SwitchersBase;
+import com.github.switcherapi.client.ContextBuilder;
+import com.github.switcherapi.client.model.SwitcherRequest;
+import com.github.switcherapi.fixture.CountDownHelper;
+import org.junit.jupiter.api.*;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class SnapshotWatcherContextTest extends SnapshotTest {
+
+ @BeforeAll
+ static void setupContext() throws IOException {
+ removeGeneratedFiles();
+ generateFixture();
+
+ SwitchersBase.configure(ContextBuilder.builder(true)
+ .context(SwitchersBase.class.getCanonicalName())
+ .environment("generated_watcher_default")
+ .snapshotLocation(SNAPSHOTS_LOCAL)
+ .snapshotWatcher(true)
+ .local(true));
+
+ SwitchersBase.initializeClient();
+ }
+
+ @AfterAll
+ static void tearDown() {
+ SwitchersBase.stopWatchingSnapshot();
+ }
+
+ @BeforeEach
+ void prepareTest() {
+ generateFixture();
+ }
+
+ @AfterEach
+ void afterEach() {
+ SwitchersBase.stopWatchingSnapshot();
+ assertWorker(false);
+ }
+
+ @Test
+ void shouldReloadDomainAfterChangingSnapshot() {
+ //verify that the worker is running
+ assertWorker(true);
+
+ //given
+ SwitcherRequest switcher = SwitchersBase.getSwitcher(SwitchersBase.USECASE11);
+
+ //initial value is true
+ assertTrue(switcher.isItOn());
+
+ CountDownHelper.wait(1);
+
+ //when we change the fixture
+ this.changeFixture();
+
+ CountDownHelper.wait(2);
+
+ //snapshot file updated - triggered domain reload
+ assertFalse(switcher.isItOn());
+ }
+
+}
diff --git a/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherTest.java b/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherTest.java
index 5dbdc48..ae82a9b 100644
--- a/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherTest.java
+++ b/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherTest.java
@@ -3,36 +3,19 @@
import com.github.switcherapi.SwitchersBase;
import com.github.switcherapi.client.ContextBuilder;
import com.github.switcherapi.client.model.SwitcherRequest;
-import com.github.switcherapi.client.model.criteria.Data;
-import com.github.switcherapi.client.model.criteria.Domain;
-import com.github.switcherapi.client.model.criteria.Snapshot;
import com.github.switcherapi.fixture.CountDownHelper;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.io.BufferedWriter;
-import java.io.FileWriter;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.nio.file.Paths;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
-class SnapshotWatcherTest {
-
- private static final Logger logger = LoggerFactory.getLogger(SnapshotWatcherTest.class);
-
- private static final String SNAPSHOTS_LOCAL = Paths.get(StringUtils.EMPTY).toAbsolutePath() + "/src/test/resources";
-
+class SnapshotWatcherTest extends SnapshotTest {
+
@BeforeAll
static void setupContext() throws IOException {
removeGeneratedFiles();
@@ -58,50 +41,6 @@ void prepareTest() {
SwitchersBase.watchSnapshot();
}
- static void removeGeneratedFiles() throws IOException {
- SwitchersBase.stopWatchingSnapshot();
- Files.deleteIfExists(Paths.get(SNAPSHOTS_LOCAL + "\\generated_watcher_default.json"));
- }
-
- static void generateFixture() {
- final Snapshot mockedSnapshot = new Snapshot();
- final Data data = new Data();
- data.setDomain(SnapshotLoader.loadSnapshot(SNAPSHOTS_LOCAL + "/snapshot_watcher.json"));
- mockedSnapshot.setData(data);
-
- SnapshotLoader.saveSnapshot(mockedSnapshot, SNAPSHOTS_LOCAL, "generated_watcher_default");
- }
-
- void changeFixture() {
- final Snapshot mockedSnapshot = new Snapshot();
- final Data data = new Data();
- data.setDomain(SnapshotLoader.loadSnapshot(SNAPSHOTS_LOCAL + "/snapshot_watcher.json"));
- mockedSnapshot.setData(data);
-
- data.setDomain(new Domain(
- data.getDomain().getName(),
- data.getDomain().getDescription(),
- !data.getDomain().isActivated(),
- data.getDomain().getVersion(),
- data.getDomain().getGroup()));
-
- final Gson gson = new GsonBuilder().setPrettyPrinting().create();
- writeFixture(gson.toJson(mockedSnapshot));
- }
-
- void writeFixture(String content) {
- try (
- final FileWriter fileWriter = new FileWriter(
- String.format("%s/%s.json", SNAPSHOTS_LOCAL, "generated_watcher_default"));
-
- final BufferedWriter bw = new BufferedWriter(fileWriter);
- final PrintWriter wr = new PrintWriter(bw)) {
- wr.write(content);
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
- }
-
@Test
void shouldNotReloadDomainAfterChangingSnapshot() {
SwitcherRequest switcher = SwitchersBase.getSwitcher(SwitchersBase.USECASE11);
diff --git a/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherWorkerTest.java b/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherWorkerTest.java
index 950b571..102f23c 100644
--- a/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherWorkerTest.java
+++ b/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherWorkerTest.java
@@ -2,36 +2,21 @@
import com.github.switcherapi.SwitchersBase;
import com.github.switcherapi.client.ContextBuilder;
-import com.github.switcherapi.client.service.WorkerName;
import com.github.switcherapi.fixture.CountDownHelper;
-import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
-import java.nio.file.Paths;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-class SnapshotWatcherWorkerTest {
-
- private static final String SNAPSHOTS_LOCAL = Paths.get(StringUtils.EMPTY).toAbsolutePath() + "/src/test/resources";
+class SnapshotWatcherWorkerTest extends SnapshotTest {
@BeforeAll
static void setupContext() {
- SwitchersBase.configure(ContextBuilder.builder()
+ SwitchersBase.configure(ContextBuilder.builder(true)
.context(SwitchersBase.class.getCanonicalName())
.snapshotLocation(SNAPSHOTS_LOCAL)
.environment("default")
- .silentMode(null)
.local(true));
SwitchersBase.initializeClient();
- SwitchersBase.stopWatchingSnapshot();
- }
-
- void assertWorker(boolean exists) {
- assertEquals(exists, Thread.getAllStackTraces().keySet().stream()
- .anyMatch(t -> t.getName().equals(WorkerName.SNAPSHOT_WATCH_WORKER.toString())));
}
@Test
diff --git a/src/test/resources/switcherapi.properties b/src/test/resources/switcherapi.properties
index 9215354..61028de 100644
--- a/src/test/resources/switcherapi.properties
+++ b/src/test/resources/switcherapi.properties
@@ -12,6 +12,7 @@ switcher.relay.restrict=
switcher.snapshot.location=
switcher.snapshot.auto=
switcher.snapshot.updateinterval=
+switcher.snapshot.watcher=
switcher.silent=
switcher.timeout=
switcher.poolsize=
\ No newline at end of file
From d8562e44117f70336e1309adfaa861a256a7b35f Mon Sep 17 00:00:00 2001
From: petruki <31597636+petruki@users.noreply.github.com>
Date: Sat, 21 Jun 2025 12:33:31 -0700
Subject: [PATCH 2/2] chore: bump test deps
---
pom.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index 2281843..e863f07 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,9 +65,9 @@
5.0.0-alpha.16
- 5.13.0
+ 5.13.1
1.9.1
- 1.13.0
+ 1.13.1
3.14.0