diff --git a/README.md b/README.md index ab8bf73b..89c82adb 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ https://github.com/switcherapi/switcher-api - Able to work local using a snapshot file pulled from your remote Switcher-API Domain. - Silent mode is a hybrid configuration that automatically enables contingent sub-processes in case of any connectivity issue. - Built-in test annotation for clear and easy implementation of automated testing. -- Easy to setup. Switcher Context is responsible to manage all the configuration complexity between your application and API. +- Easy to set up. Switcher Context is responsible to manage all the configuration complexity between your application and API. # Usage @@ -70,6 +70,7 @@ switcher.domain -> Domain name #optional switcher.environment -> Environment name switcher.local -> true/false When local, it will only use a local snapshot +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.skipvalidation -> true/false Skip snapshotValidation() that can be used for UT executions @@ -250,9 +251,7 @@ MyAppFeatures.scheduleSnapshotAutoUpdate("5s", new SnapshotCallback() { }); ``` - - -## Real-time snapshot updater +## Real-time snapshot reload 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. diff --git a/pom.xml b/pom.xml index 515b0987..2281843e 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,7 @@ 2.47 2.47 2.47 + 1.2.0 2.13.1 @@ -109,6 +110,11 @@ jersey-media-json-jackson ${jersey-media-json-jackson.version} + + javax.activation + javax.activation-api + ${javax.activation-api.version} + com.google.code.gson diff --git a/src/main/java/com/github/switcherapi/client/ContextBuilder.java b/src/main/java/com/github/switcherapi/client/ContextBuilder.java index fda61419..cb0fad81 100644 --- a/src/main/java/com/github/switcherapi/client/ContextBuilder.java +++ b/src/main/java/com/github/switcherapi/client/ContextBuilder.java @@ -182,6 +182,15 @@ public ContextBuilder local(boolean local) { return this; } + /** + * @param restrictRelay true/false When true, it will check snapshot relay status + * @return ContextBuilder + */ + public ContextBuilder restrictRelay(boolean restrictRelay) { + switcherProperties.setValue(ContextKey.RESTRICT_RELAY, restrictRelay); + return this; + } + /** * @param truststorePath Path to the truststore file * @return ContextBuilder diff --git a/src/main/java/com/github/switcherapi/client/SwitcherPropertiesImpl.java b/src/main/java/com/github/switcherapi/client/SwitcherPropertiesImpl.java index 1cbf40c2..d8ee7d94 100644 --- a/src/main/java/com/github/switcherapi/client/SwitcherPropertiesImpl.java +++ b/src/main/java/com/github/switcherapi/client/SwitcherPropertiesImpl.java @@ -23,6 +23,7 @@ public SwitcherPropertiesImpl() { setValue(ContextKey.SNAPSHOT_AUTO_LOAD, false); setValue(ContextKey.SNAPSHOT_SKIP_VALIDATION, false); setValue(ContextKey.LOCAL_MODE, false); + setValue(ContextKey.RESTRICT_RELAY, true); } @Override @@ -39,6 +40,7 @@ public void loadFromProperties(Properties prop) { 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.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)); 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 d551e872..e0d62279 100644 --- a/src/main/java/com/github/switcherapi/client/model/ContextKey.java +++ b/src/main/java/com/github/switcherapi/client/model/ContextKey.java @@ -69,6 +69,11 @@ public enum ContextKey { */ LOCAL_MODE("switcher.local"), + /** + * (boolean) Defines if client will trigger local snapshot relay verification (default is true) + */ + RESTRICT_RELAY("switcher.relay.restrict"), + /** * (Number) Defines the Timed Match regex time out. */ diff --git a/src/main/java/com/github/switcherapi/client/model/EntryOperation.java b/src/main/java/com/github/switcherapi/client/model/EntryOperation.java index 882fac59..2d3ab6c2 100644 --- a/src/main/java/com/github/switcherapi/client/model/EntryOperation.java +++ b/src/main/java/com/github/switcherapi/client/model/EntryOperation.java @@ -1,7 +1,6 @@ package com.github.switcherapi.client.model; public enum EntryOperation { - EQUAL, NOT_EQUAL, EXIST, @@ -12,5 +11,4 @@ public enum EntryOperation { HAS_ONE, HAS_ALL, INVALID - } diff --git a/src/main/java/com/github/switcherapi/client/model/RelayType.java b/src/main/java/com/github/switcherapi/client/model/RelayType.java new file mode 100644 index 00000000..83e72e81 --- /dev/null +++ b/src/main/java/com/github/switcherapi/client/model/RelayType.java @@ -0,0 +1,10 @@ +package com.github.switcherapi.client.model; + +/** + * @author Roger Floriano (petruki) + * @since 2025-06-13 + */ +public enum RelayType { + NOTIFICATION, + WEBHOOK +} diff --git a/src/main/java/com/github/switcherapi/client/model/SwitcherBuilder.java b/src/main/java/com/github/switcherapi/client/model/SwitcherBuilder.java index 82aef0bc..478dbed2 100644 --- a/src/main/java/com/github/switcherapi/client/model/SwitcherBuilder.java +++ b/src/main/java/com/github/switcherapi/client/model/SwitcherBuilder.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Builder class that simplifies how input are programmatically wrapped inside the Switcher. @@ -23,6 +24,8 @@ public abstract class SwitcherBuilder implements Switcher { protected boolean bypassMetrics; + protected Boolean restrictRelay; + protected String defaultResult; protected List entry; @@ -71,7 +74,18 @@ public SwitcherBuilder defaultResult(boolean defaultResult) { this.defaultResult = String.valueOf(defaultResult); return this; } - + + /** + * Allow local snapshots to ignore or require Relay verification. + * + * @param restrictRelay true to restrict Relay verification + * @return {@link SwitcherBuilder} + */ + public SwitcherBuilder restrictRelay(boolean restrictRelay) { + this.restrictRelay = restrictRelay; + return this; + } + /** * Add a validation to the entry stack * @@ -171,6 +185,14 @@ public boolean isRemote() { return remote; } + public boolean isRelayRestricted() { + return restrictRelay; + } + + public boolean isRestrictRelaySet() { + return Objects.nonNull(restrictRelay); + } + public String getDefaultResult() { return defaultResult; } diff --git a/src/main/java/com/github/switcherapi/client/model/SwitcherRequest.java b/src/main/java/com/github/switcherapi/client/model/SwitcherRequest.java index c1dd188a..b2bf34df 100644 --- a/src/main/java/com/github/switcherapi/client/model/SwitcherRequest.java +++ b/src/main/java/com/github/switcherapi/client/model/SwitcherRequest.java @@ -111,6 +111,10 @@ public SwitcherResult submit() throws SwitcherException { @Override public SwitcherResult executeCriteria() { + if (!isRestrictRelaySet()) { + this.restrictRelay(properties.getBoolean(ContextKey.RESTRICT_RELAY)); + } + return this.switcherExecutor.executeCriteria(this); } diff --git a/src/main/java/com/github/switcherapi/client/model/criteria/Config.java b/src/main/java/com/github/switcherapi/client/model/criteria/Config.java index 4db582fb..eb4ae1f9 100644 --- a/src/main/java/com/github/switcherapi/client/model/criteria/Config.java +++ b/src/main/java/com/github/switcherapi/client/model/criteria/Config.java @@ -1,6 +1,7 @@ package com.github.switcherapi.client.model.criteria; import java.util.Arrays; +import java.util.Objects; /** * @author Roger Floriano (petruki) @@ -8,34 +9,45 @@ */ public class Config extends SwitcherElement { - private String key; + private final String key; - private Strategy[] strategies; + private final Strategy[] strategies; - private String[] components; + private final String[] components; - public String getKey() { - return key; + private final Relay relay; + + public Config(String key, String description, boolean activated, Strategy[] strategies, String[] components, + Relay relay) { + super(description, activated); + this.key = key; + this.strategies = strategies; + this.components = components; + this.relay = relay; } - public Strategy[] getStrategies() { - return strategies; + public Config() { + this(null, null, false, null, null, null); } - public void setKey(String key) { - this.key = key; + public boolean hasRelayEnabled() { + return Objects.nonNull(relay) && relay.isActivated(); } - public void setStrategies(Strategy[] strategies) { - this.strategies = strategies; + public String getKey() { + return key; } - public String[] getComponents() { - return components; + public Relay getRelay() { + return relay; } - public void setComponents(String[] components) { - this.components = components; + public Strategy[] getStrategies() { + return strategies; + } + + public String[] getComponents() { + return components; } @Override diff --git a/src/main/java/com/github/switcherapi/client/model/criteria/Domain.java b/src/main/java/com/github/switcherapi/client/model/criteria/Domain.java index 0fd0ff5d..a827b989 100644 --- a/src/main/java/com/github/switcherapi/client/model/criteria/Domain.java +++ b/src/main/java/com/github/switcherapi/client/model/criteria/Domain.java @@ -8,36 +8,35 @@ */ public class Domain extends SwitcherElement { - private String name; + private final String name; - private long version; + private final long version; - private Group[] group; + private final Group[] group; - public Group[] getGroup() { - return group; + public Domain(String name, String description, boolean activated, long version, Group[] group) { + super(description, activated); + this.name = name; + this.version = version; + this.group = group; } - public void setGroup(Group[] group) { - this.group = group; + public Domain() { + this(null, null, false, 0L, null); } - public String getName() { - return name; + public Group[] getGroup() { + return group; } - public void setName(String name) { - this.name = name; + public String getName() { + return name; } public long getVersion() { return version; } - public void setVersion(long version) { - this.version = version; - } - @Override public String toString() { return String.format("Domain [name = %s, description = %s, activated = %s, version = %s, group = %s]", name, diff --git a/src/main/java/com/github/switcherapi/client/model/criteria/Group.java b/src/main/java/com/github/switcherapi/client/model/criteria/Group.java index 026491b8..2768ad72 100644 --- a/src/main/java/com/github/switcherapi/client/model/criteria/Group.java +++ b/src/main/java/com/github/switcherapi/client/model/criteria/Group.java @@ -8,24 +8,26 @@ */ public class Group extends SwitcherElement { - private String name; + private final String name; - private Config[] config; + private final Config[] config; - public Config[] getConfig() { - return config; + public Group(String name, String description, boolean activated, Config[] config) { + super(description, activated); + this.name = name; + this.config = config; } - public void setConfig(Config[] config) { - this.config = config; + public Group() { + this(null, null, false, null); } - public String getName() { - return name; + public Config[] getConfig() { + return config; } - public void setName(String name) { - this.name = name; + public String getName() { + return name; } @Override diff --git a/src/main/java/com/github/switcherapi/client/model/criteria/Relay.java b/src/main/java/com/github/switcherapi/client/model/criteria/Relay.java new file mode 100644 index 00000000..0d00fcb9 --- /dev/null +++ b/src/main/java/com/github/switcherapi/client/model/criteria/Relay.java @@ -0,0 +1,35 @@ +package com.github.switcherapi.client.model.criteria; + +/** + * @author Roger Floriano (petruki) + * @since 2025-06-13 + */ +public class Relay { + + private final String type; + + private final boolean activated; + + public Relay(String type, boolean activated) { + this.type = type; + this.activated = activated; + } + + public Relay() { + this(null, false); + } + + public boolean isActivated() { + return activated; + } + + public String getType() { + return type; + } + + @Override + public String toString() { + return String.format("Relay [type = %s, activated = %s]", type, activated); + } + +} diff --git a/src/main/java/com/github/switcherapi/client/model/criteria/Strategy.java b/src/main/java/com/github/switcherapi/client/model/criteria/Strategy.java index b1c5e041..7bcdb4c3 100644 --- a/src/main/java/com/github/switcherapi/client/model/criteria/Strategy.java +++ b/src/main/java/com/github/switcherapi/client/model/criteria/Strategy.java @@ -11,11 +11,22 @@ */ public class Strategy extends SwitcherElement { - private String strategy; + private final String strategy; - private String operation; + private final String operation; - private String[] values; + private final String[] values; + + public Strategy(String strategy, String operation, String description, boolean activated, String[] values) { + super(description, activated); + this.strategy = strategy; + this.operation = operation; + this.values = values; + } + + public Strategy() { + this(null, null, null, false, null); + } public EntryOperation getEntryOperation() { return Arrays.stream(EntryOperation.values()) @@ -39,22 +50,10 @@ public String getOperation() { return operation; } - public void setOperation(String operation) { - this.operation = operation; - } - public String[] getValues() { return values; } - public void setStrategy(String strategy) { - this.strategy = strategy; - } - - public void setValues(String[] values) { - this.values = values; - } - @Override public String toString() { return String.format("Strategy [strategy = %s, operation = %s, description = %s, activated = %s, values = %s]", diff --git a/src/main/java/com/github/switcherapi/client/model/criteria/SwitcherElement.java b/src/main/java/com/github/switcherapi/client/model/criteria/SwitcherElement.java index 67a6dcbe..f65a024f 100644 --- a/src/main/java/com/github/switcherapi/client/model/criteria/SwitcherElement.java +++ b/src/main/java/com/github/switcherapi/client/model/criteria/SwitcherElement.java @@ -6,9 +6,14 @@ */ abstract class SwitcherElement { - protected String description; + protected final String description; - protected boolean activated; + protected final boolean activated; + + protected SwitcherElement(String description, boolean activated) { + this.description = description; + this.activated = activated; + } public String getDescription() { return description; @@ -18,12 +23,4 @@ public boolean isActivated() { return activated; } - public void setDescription(String description) { - this.description = description; - } - - public void setActivated(boolean activated) { - this.activated = activated; - } - } diff --git a/src/main/java/com/github/switcherapi/client/remote/Constants.java b/src/main/java/com/github/switcherapi/client/remote/Constants.java index c61772ea..0ac1e60d 100644 --- a/src/main/java/com/github/switcherapi/client/remote/Constants.java +++ b/src/main/java/com/github/switcherapi/client/remote/Constants.java @@ -18,6 +18,7 @@ public final class Constants { "group { name description activated " + "config { key description activated " + "strategies { strategy activated operation values } " + + "relay { type activated } " + "components } } } }\"}"; private Constants() {} diff --git a/src/main/java/com/github/switcherapi/client/service/local/ClientLocalService.java b/src/main/java/com/github/switcherapi/client/service/local/ClientLocalService.java index dd2dae25..1e231f77 100644 --- a/src/main/java/com/github/switcherapi/client/service/local/ClientLocalService.java +++ b/src/main/java/com/github/switcherapi/client/service/local/ClientLocalService.java @@ -35,6 +35,7 @@ public class ClientLocalService implements ClientLocal { public static final String DISABLED_DOMAIN = "Domain disabled"; public static final String DISABLED_GROUP = "Group disabled"; public static final String DISABLED_CONFIG = "Config disabled"; + public static final String HAS_RELAY = "Config has Relay enabled"; private static final String STRATEGY_FAIL_PATTERN = "Strategy %s does not agree"; private static final String STRATEGY_FAIL_NO_INPUT_PATTERN = "Strategy %s did not receive any input"; @@ -88,6 +89,10 @@ private SwitcherResult getSwitcherResult(SwitcherRequest switcher, Group group, return SwitcherFactory.buildResultFail(DISABLED_CONFIG, switcher); } + if (config.hasRelayEnabled() && switcher.isRelayRestricted()) { + return SwitcherFactory.buildResultFail(HAS_RELAY, switcher); + } + if (ArrayUtils.isNotEmpty(config.getStrategies())) { return this.processOperation(config.getStrategies(), switcher.getEntry(), switcher); } diff --git a/src/main/java/com/github/switcherapi/client/utils/SnapshotLoader.java b/src/main/java/com/github/switcherapi/client/utils/SnapshotLoader.java index 150b3778..428ab9fa 100644 --- a/src/main/java/com/github/switcherapi/client/utils/SnapshotLoader.java +++ b/src/main/java/com/github/switcherapi/client/utils/SnapshotLoader.java @@ -104,16 +104,13 @@ private static Domain loadSnapshotFromResources(final String snapshotLocation, f public static void saveSnapshot(final Snapshot snapshot, final String snapshotLocation, final String environment) throws SwitcherSnapshotWriteException { - final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + final Gson gson = new GsonBuilder() + .setPrettyPrinting() + .registerTypeAdapter(Domain.class, new SnapshotSerializer()) + .create(); + + createDirectoryPath(snapshotLocation, environment); - try { - Path path = Paths.get(snapshotLocation); - if (!path.toFile().exists()) - Files.createDirectories(path); - } catch (Exception e) { - throw new SwitcherSnapshotWriteException(String.format(SNAPSHOT_FILE_FORMAT, snapshotLocation, environment), e); - } - try ( final FileWriter fileWriter = new FileWriter(String.format(SNAPSHOT_FILE_FORMAT, snapshotLocation, environment)); final BufferedWriter bw = new BufferedWriter(fileWriter); @@ -124,4 +121,15 @@ public static void saveSnapshot(final Snapshot snapshot, final String snapshotLo } } + private static void createDirectoryPath(String snapshotLocation, String environment) { + try { + Path path = Paths.get(snapshotLocation); + if (!path.toFile().exists()) { + Files.createDirectories(path); + } + } catch (Exception e) { + throw new SwitcherSnapshotWriteException(String.format(SNAPSHOT_FILE_FORMAT, snapshotLocation, environment), e); + } + } + } diff --git a/src/main/java/com/github/switcherapi/client/utils/SnapshotSerializer.java b/src/main/java/com/github/switcherapi/client/utils/SnapshotSerializer.java new file mode 100644 index 00000000..6b7289c8 --- /dev/null +++ b/src/main/java/com/github/switcherapi/client/utils/SnapshotSerializer.java @@ -0,0 +1,108 @@ +package com.github.switcherapi.client.utils; + +import com.github.switcherapi.client.model.criteria.Config; +import com.github.switcherapi.client.model.criteria.Domain; +import com.github.switcherapi.client.model.criteria.Group; +import com.github.switcherapi.client.model.criteria.Strategy; +import com.google.gson.*; + +import java.lang.reflect.Type; +import java.util.Objects; + +class SnapshotSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(Domain domain, Type typeOfSrc, JsonSerializationContext context) { + JsonObject jsonObject = new JsonObject(); + + jsonObject.add(Field.NAME.value(), context.serialize(domain.getName())); + jsonObject.add(Field.DESCRIPTION.value(), context.serialize(domain.getDescription())); + jsonObject.add(Field.ACTIVATED.value(), context.serialize(domain.isActivated())); + jsonObject.add(Field.VERSION.value(), context.serialize(domain.getVersion())); + jsonObject.add(Field.GROUP.value(), serializeGroup(domain, context)); + + return jsonObject; + } + + private JsonArray serializeGroup(Domain domain, JsonSerializationContext context) { + JsonArray groupArray = new JsonArray(); + + if (Objects.nonNull(domain.getGroup())) { + for (Group group : domain.getGroup()) { + JsonObject groupObject = new JsonObject(); + groupObject.add(Field.NAME.value(), context.serialize(group.getName())); + groupObject.add(Field.DESCRIPTION.value(), context.serialize(group.getDescription())); + groupObject.add(Field.ACTIVATED.value(), context.serialize(group.isActivated())); + groupObject.add(Field.CONFIG.value(), serializeConfig(group, context)); + groupArray.add(groupObject); + } + } + + return groupArray; + } + + private JsonArray serializeConfig(Group group, JsonSerializationContext context) { + JsonArray configArray = new JsonArray(); + + if (Objects.nonNull(group.getConfig())) { + for (Config config : group.getConfig()) { + JsonObject configObject = new JsonObject(); + configObject.add(Field.KEY.value(), context.serialize(config.getKey())); + configObject.add(Field.DESCRIPTION.value(), context.serialize(config.getDescription())); + configObject.add(Field.ACTIVATED.value(), context.serialize(config.isActivated())); + configObject.add(Field.STRATEGIES.value(), serializeStrategies(config, context)); + configObject.add(Field.RELAY.value(), context.serialize(config.getRelay())); + configObject.add(Field.COMPONENTS.value(), context.serialize(config.getComponents())); + + configArray.add(configObject); + } + } + + return configArray; + } + + private JsonArray serializeStrategies(Config config, JsonSerializationContext context) { + JsonArray strategiesArray = new JsonArray(); + + if (Objects.nonNull(config.getStrategies())) { + for (Strategy strategy : config.getStrategies()) { + JsonObject strategyObject = new JsonObject(); + strategyObject.add(Field.STRATEGY.value(), context.serialize(strategy.getStrategy())); + strategyObject.add(Field.OPERATION.value(), context.serialize(strategy.getOperation())); + strategyObject.add(Field.DESCRIPTION.value(), context.serialize(strategy.getDescription())); + strategyObject.add(Field.ACTIVATED.value(), context.serialize(strategy.isActivated())); + strategyObject.add(Field.VALUES.value(), context.serialize(strategy.getValues())); + strategiesArray.add(strategyObject); + } + } + + return strategiesArray; + } + + private enum Field { + NAME("name"), + DESCRIPTION("description"), + ACTIVATED("activated"), + VERSION("version"), + GROUP("group"), + CONFIG("config"), + KEY("key"), + COMPONENTS("components"), + STRATEGIES("strategies"), + RELAY("relay"), + STRATEGY("strategy"), + OPERATION("operation"), + VALUES("values"); + + private final String value; + + Field(String value) { + this.value = value; + } + + public String value() { + return value; + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/switcherapi/Switchers.java b/src/test/java/com/github/switcherapi/Switchers.java index 5789b8df..9b98a10e 100644 --- a/src/test/java/com/github/switcherapi/Switchers.java +++ b/src/test/java/com/github/switcherapi/Switchers.java @@ -134,6 +134,12 @@ public class Switchers extends SwitcherContext { @SwitcherKey public static final String USECASE102 = "USECASE102"; + @SwitcherKey + public static final String USECASE103 = "USECASE103"; + + @SwitcherKey + public static final String USECASE104 = "USECASE104"; + @SwitcherKey public static final String NOT_FOUND_KEY = "NOT_FOUND_KEY"; } diff --git a/src/test/java/com/github/switcherapi/client/SwitcherLocal1Test.java b/src/test/java/com/github/switcherapi/client/SwitcherLocal1Test.java index 1c57691c..1f20e9f7 100644 --- a/src/test/java/com/github/switcherapi/client/SwitcherLocal1Test.java +++ b/src/test/java/com/github/switcherapi/client/SwitcherLocal1Test.java @@ -4,10 +4,7 @@ import com.github.switcherapi.client.exception.SwitcherInvalidNumericFormat; import com.github.switcherapi.client.exception.SwitcherInvalidTimeFormat; import com.github.switcherapi.client.exception.SwitcherKeyNotFoundException; -import com.github.switcherapi.client.model.ContextKey; -import com.github.switcherapi.client.model.Entry; -import com.github.switcherapi.client.model.StrategyValidator; -import com.github.switcherapi.client.model.SwitcherRequest; +import com.github.switcherapi.client.model.*; import com.github.switcherapi.fixture.Product; import com.google.gson.Gson; import org.apache.commons.lang3.StringUtils; @@ -360,4 +357,41 @@ void localShouldTestChained_payloadValidation(String useCaseKey, String input, b assertEquals(expected, switcher.checkPayload(input).isItOn()); } + static Stream relayTestArguments() { + return Stream.of( + // Relay enabled should cause local to return false + Arguments.of(Switchers.USECASE103, true, false), + // Relay enabled should cause local to return true when Switcher restrictRelay is set false + Arguments.of(Switchers.USECASE103, false, true), + // Relay disabled should cause local to return true + Arguments.of(Switchers.USECASE104, false, true), + // Relay disabled should cause local to return true regardless of Switcher restrictRelay + Arguments.of(Switchers.USECASE104, true, true) + ); + } + + @ParameterizedTest() + @MethodSource("relayTestArguments") + void localShouldTest_relayValidation(String useCaseKey, Boolean restrictRelay, boolean expected) { + SwitcherContext.configure(ContextBuilder.builder() + .restrictRelay(restrictRelay)); + + SwitcherContext.initializeClient(); + + SwitcherRequest switcher = Switchers.getSwitcher(useCaseKey); + assertEquals(expected, switcher.isItOn()); + } + + @Test + void localShouldReturnFalse_relayRestrictDefaultEnabled() { + SwitcherRequest switcher = Switchers.getSwitcher(Switchers.USECASE103); + assertFalse(switcher.isItOn()); + } + + @Test + void localShouldReturnTrue_relayRestrictProgrammaticallyDisabled() { + SwitcherRequest switcher = Switchers.getSwitcher(Switchers.USECASE103); + assertTrue(switcher.restrictRelay(false).isItOn()); + } + } diff --git a/src/test/java/com/github/switcherapi/client/model/ModelTest.java b/src/test/java/com/github/switcherapi/client/model/ModelTest.java index 85ce136c..6b726f17 100644 --- a/src/test/java/com/github/switcherapi/client/model/ModelTest.java +++ b/src/test/java/com/github/switcherapi/client/model/ModelTest.java @@ -1,14 +1,8 @@ package com.github.switcherapi.client.model; +import com.github.switcherapi.client.model.criteria.*; import org.junit.jupiter.api.Test; -import com.github.switcherapi.client.model.criteria.Config; -import com.github.switcherapi.client.model.criteria.Data; -import com.github.switcherapi.client.model.criteria.Domain; -import com.github.switcherapi.client.model.criteria.Group; -import com.github.switcherapi.client.model.criteria.Snapshot; -import com.github.switcherapi.client.model.criteria.Strategy; - import static org.junit.jupiter.api.Assertions.*; class ModelTest { @@ -25,51 +19,57 @@ void testModelEntry() { @Test void testCriteriaPackage() { - final Strategy strategy = new Strategy(); - strategy.setActivated(true); - strategy.setDescription("Description"); - strategy.setOperation("Operation"); - strategy.setStrategy("Strategy"); String[] strategyValues = new String[] { "Value" }; - strategy.setValues(strategyValues); + final Strategy strategy = new Strategy( + "Strategy", + "Operation", + "Description", + true, + strategyValues + ); assertSame("Description", strategy.getDescription()); assertSame("Operation", strategy.getOperation()); assertSame("Strategy", strategy.getStrategy()); assertSame(strategyValues, strategy.getValues()); - - final Config config = new Config(); - config.setActivated(true); - config.setKey("Key"); - config.setDescription("Description"); - String[] configComponents = new String[] { "Component" }; - config.setComponents(configComponents); + Strategy[] strategies = new Strategy[] { strategy }; - config.setStrategies(strategies); + String[] configComponents = new String[] { "Component" }; + Relay relay = new Relay(RelayType.NOTIFICATION.name(), false); + final Config config = new Config( + "Key", + "Description", + true, + strategies, + configComponents, + relay + ); assertSame("Description", config.getDescription()); assertSame("Key", config.getKey()); assertSame(configComponents, config.getComponents()); assertSame(strategies, config.getStrategies()); - - final Group group = new Group(); - group.setActivated(true); - group.setDescription("Description"); - group.setName("Name"); + Config[] configs = new Config[] { config }; - group.setConfig(configs); + final Group group = new Group( + "Name", + "Description", + true, + configs + ); assertSame("Description", group.getDescription()); assertSame("Name", group.getName()); assertSame(configs, group.getConfig()); - - final Domain domain = new Domain(); - domain.setActivated(true); - domain.setDescription("Description"); - domain.setName("Name"); - domain.setVersion(10000000000L); + Group[] groups = new Group[] { group }; - domain.setGroup(groups); + final Domain domain = new Domain( + "Name", + "Description", + true, + 10000000000L, + groups + ); assertSame("Description", domain.getDescription()); assertSame("Name", domain.getName()); 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 e3d6468f..5dbdc486 100644 --- a/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherTest.java +++ b/src/test/java/com/github/switcherapi/client/utils/SnapshotWatcherTest.java @@ -4,6 +4,7 @@ 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; @@ -76,8 +77,13 @@ void changeFixture() { final Data data = new Data(); data.setDomain(SnapshotLoader.loadSnapshot(SNAPSHOTS_LOCAL + "/snapshot_watcher.json")); mockedSnapshot.setData(data); - - data.getDomain().setActivated(false); + + 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)); diff --git a/src/test/java/com/github/switcherapi/client/validator/RegexValidatorV8Test.java b/src/test/java/com/github/switcherapi/client/validator/RegexValidatorV8Test.java index d4ac5321..e623aa90 100644 --- a/src/test/java/com/github/switcherapi/client/validator/RegexValidatorV8Test.java +++ b/src/test/java/com/github/switcherapi/client/validator/RegexValidatorV8Test.java @@ -105,12 +105,13 @@ void shouldCompleteWorkerThreadsAfterTimeout() { } private Strategy givenStrategy(EntryOperation operation, List values) { - Strategy strategy = new Strategy(); - strategy.setStrategy(StrategyValidator.REGEX.toString()); - strategy.setOperation(operation.toString()); - strategy.setValues(values.toArray(new String[0])); - - return strategy; + return new Strategy( + StrategyValidator.REGEX.toString(), + operation.toString(), + "Regex validator strategy for test", + Boolean.TRUE, + values.toArray(new String[0]) + ); } private void assertWorkerNotExists() { diff --git a/src/test/java/com/github/switcherapi/client/validator/ValidatorsTest.java b/src/test/java/com/github/switcherapi/client/validator/ValidatorsTest.java index c22431ea..e6d6f88d 100644 --- a/src/test/java/com/github/switcherapi/client/validator/ValidatorsTest.java +++ b/src/test/java/com/github/switcherapi/client/validator/ValidatorsTest.java @@ -14,8 +14,13 @@ class ValidatorsTest { @Test void shouldRegisterCustomValidator() { assertDoesNotThrow(() -> service.registerValidator(new CustomValidator())); - Strategy strategy = new Strategy(); - strategy.setStrategy("CUSTOM"); + Strategy strategy = new Strategy( + "CUSTOM", + "INVALID", + "Custom Validator Test", + true, + new String[] { "Value1", "Value2" } + ); assertTrue(service.execute(strategy, null)); } diff --git a/src/test/resources/default.json b/src/test/resources/default.json index 1c5d5d41..4d4bcba6 100644 --- a/src/test/resources/default.json +++ b/src/test/resources/default.json @@ -2,346 +2,36 @@ "data": { "domain": { "name": "switcher-domain", + "description": "Description of the domain", + "activated": true, "version": 1588557288037, "group": [ { "name": "Group 1", + "description": "Description of the group", + "activated": true, "config": [ { "key": "USECASE11", - "components": [ - "switcher-client" - ], - "description": "Simple test - Config enabled", - "activated": true - }, - { - "key": "USECASE12", - "components": [ - "switcher-client" - ], - "description": "Simple test - Config disabled", - "activated": false - } - ], - "description": "Simple test", - "activated": true - }, - { - "name": "Group 2", - "config": [ - { - "key": "USECASE21", - "components": [ - "switcher-client" - ], - "description": "Simple test - Config enabled", - "activated": true - } - ], - "description": "Simple test - Group disabled", - "activated": false - }, - { - "name": "Group 3", - "config": [ - { - "key": "USECASE31", - "strategies": [ - { - "strategy": "DATE_VALIDATION", - "operation": "GREATER", - "values": [ - "2019-12-10" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Date Validation [GREATER]", - "activated": true - }, - { - "key": "USECASE32", - "strategies": [ - { - "strategy": "DATE_VALIDATION", - "operation": "LOWER", - "values": [ - "2019-12-10" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Date Validation [LOWER]", - "activated": true - }, - { - "key": "USECASE33", - "strategies": [ - { - "strategy": "DATE_VALIDATION", - "operation": "BETWEEN", - "values": [ - "2019-12-10", - "2019-12-12" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Date Validation [BETWEEN]", - "activated": true - } - ], - "description": "Date Validation", - "activated": true - }, - { - "name": "Group 4", - "config": [ - { - "key": "USECASE41", - "strategies": [ - { - "strategy": "VALUE_VALIDATION", - "operation": "EXIST", - "values": [ - "Value1", - "Value2", - "Value3" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Value Validation [EXIST]", - "activated": true - }, - { - "key": "USECASE42", - "strategies": [ - { - "strategy": "VALUE_VALIDATION", - "operation": "NOT_EXIST", - "values": [ - "Value1", - "Value2", - "Value3" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Value Validation [NOT_EXIST]", - "activated": true - }, - { - "key": "USECASE43", + "description": "Simple test - Domain disabled", + "activated": true, "strategies": [ { "strategy": "VALUE_VALIDATION", "operation": "EQUAL", + "activated": false, "values": [ "Value1" - ], - "activated": true + ] } ], "components": [ "switcher-client" - ], - "description": "Config with Value Validation [EQUAL]", - "activated": true - }, - { - "key": "USECASE44", - "strategies": [ - { - "strategy": "VALUE_VALIDATION", - "operation": "NOT_EQUAL", - "values": [ - "Value1" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Value Validation [NOT_EQUAL]", - "activated": true - } - ], - "description": "Value Validation", - "activated": true - }, - { - "name": "Group 5", - "config": [ - { - "key": "USECASE51", - "strategies": [ - { - "strategy": "TIME_VALIDATION", - "operation": "GREATER", - "values": [ - "10:00" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Time Validation [GREATER]", - "activated": true - }, - { - "key": "USECASE52", - "strategies": [ - { - "strategy": "TIME_VALIDATION", - "operation": "LOWER", - "values": [ - "10:00" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Time Validation [LOWER]", - "activated": true - }, - { - "key": "USECASE53", - "strategies": [ - { - "strategy": "TIME_VALIDATION", - "operation": "BETWEEN", - "values": [ - "10:00", - "16:00" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Time Validation [BETWEEN]", - "activated": true - } - ], - "description": "Time Validation", - "activated": true - }, - { - "name": "Group 6", - "config": [ - { - "key": "USECASE61", - "strategies": [ - { - "strategy": "NETWORK_VALIDATION", - "operation": "EXIST", - "values": [ - "10.0.0.0/29" - ], - "description": "From 10.0.0.0 to 10.0.0.7", - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Network Validation [EXIST]", - "activated": true - }, - { - "key": "USECASE62", - "strategies": [ - { - "strategy": "NETWORK_VALIDATION", - "operation": "NOT_EXIST", - "values": [ - "10.0.0.0/29" - ], - "description": "From 10.0.0.0 to 10.0.0.7", - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Network Validation [NOT_EXIST]", - "activated": true - }, - { - "key": "USECASE63", - "strategies": [ - { - "strategy": "NETWORK_VALIDATION", - "operation": "EXIST", - "values": [ - "10.0.0.1", - "10.0.0.2", - "10.0.0.3" - ], - "activated": true - } - ], - "components": [ - "switcher-client" - ], - "description": "Config with Network Validation [EXIST]", - "activated": true - } - ], - "description": "Network Validation", - "activated": true - }, - { - "name": "Group 7", - "config": [ - { - "key": "USECASE71", - "strategies": [ - { - "strategy": "VALUE_VALIDATION", - "operation": "EQUAL", - "values": [ - "Value1" - ], - "activated": false - } - ], - "components": [ - "switcher-client" - ], - "description": "Simple test - Config enabled", - "activated": true + ] } - ], - "description": "Simple test - Strategy disabled", - "activated": true + ] } - ], - "description": "Fixture #1", - "activated": true + ] } } } \ No newline at end of file diff --git a/src/test/resources/snapshot/fixture1.json b/src/test/resources/snapshot/fixture1.json index 6f9a8df3..a74bdcc5 100644 --- a/src/test/resources/snapshot/fixture1.json +++ b/src/test/resources/snapshot/fixture1.json @@ -15,13 +15,17 @@ "key": "USECASE11", "description": "Simple test - Config enabled", "activated": true, - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE12", "description": "Simple test - Config disabled", "activated": false, - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -34,7 +38,9 @@ "key": "USECASE21", "description": "Simple test - Config enabled", "activated": true, - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -57,7 +63,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE32", @@ -73,7 +81,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE33", @@ -90,7 +100,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -109,11 +121,15 @@ "activated": true, "operation": "EXIST", "values": [ - "Value1", "Value2", "Value3" + "Value1", + "Value2", + "Value3" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE42", @@ -125,11 +141,15 @@ "activated": true, "operation": "NOT_EXIST", "values": [ - "Value1", "Value2", "Value3" + "Value1", + "Value2", + "Value3" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE43", @@ -145,7 +165,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE44", @@ -161,7 +183,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -184,7 +208,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE52", @@ -200,7 +226,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE53", @@ -217,7 +245,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -241,7 +271,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE62", @@ -258,7 +290,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE63", @@ -270,11 +304,15 @@ "activated": true, "operation": "EXIST", "values": [ - "10.0.0.1", "10.0.0.2", "10.0.0.3" + "10.0.0.1", + "10.0.0.2", + "10.0.0.3" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -297,7 +335,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -316,11 +356,15 @@ "activated": true, "operation": "EXIST", "values": [ - "1", "2", "3" + "1", + "2", + "3" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE82", @@ -332,11 +376,15 @@ "activated": true, "operation": "NOT_EXIST", "values": [ - "1", "2", "3" + "1", + "2", + "3" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE83", @@ -352,7 +400,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE84", @@ -368,7 +418,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE85", @@ -384,7 +436,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE86", @@ -400,7 +454,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE87", @@ -412,11 +468,14 @@ "activated": true, "operation": "BETWEEN", "values": [ - "1", "3" + "1", + "3" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -435,11 +494,14 @@ "activated": true, "operation": "EXIST", "values": [ - "\\bUSER_[0-9]{1,2}\\b", "\\buser-[0-9]{1,2}\\b" + "\\bUSER_[0-9]{1,2}\\b", + "\\buser-[0-9]{1,2}\\b" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE92", @@ -451,11 +513,14 @@ "activated": true, "operation": "NOT_EXIST", "values": [ - "\\bUSER_[0-9]{1,2}\\b", "\\buser-[0-9]{1,2}\\b" + "\\bUSER_[0-9]{1,2}\\b", + "\\buser-[0-9]{1,2}\\b" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE93", @@ -467,11 +532,13 @@ "activated": true, "operation": "EQUAL", "values": [ - "USER_[0-9]{1,2}" + "USER_[0-9]{1,2}" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE94", @@ -487,7 +554,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE95", @@ -503,7 +572,9 @@ ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] } ] }, @@ -522,11 +593,14 @@ "activated": true, "operation": "HAS_ONE", "values": [ - "order.tracking.status", "order.tracking.date" + "order.tracking.status", + "order.tracking.date" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE101", @@ -538,11 +612,13 @@ "activated": true, "operation": "HAS_ONE", "values": [ - "product" + "product" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] }, { "key": "USECASE102", @@ -554,17 +630,50 @@ "activated": true, "operation": "HAS_ALL", "values": [ - "name", - "categories", - "order", - "order.qty", - "order.tracking", + "name", + "categories", + "order", + "order.qty", + "order.tracking", "order.tracking.status", "order.tracking.comments" ] } ], - "components": ["switcher-client"] + "components": [ + "switcher-client" + ] + } + ] + }, + { + "name": "Group 11", + "description": "Relay group", + "activated": true, + "config": [ + { + "key": "USECASE103", + "description": "Relay enabled", + "activated": true, + "relay": { + "type": "VALIDATOR", + "activated": true + }, + "components": [ + "switcher-client" + ] + }, + { + "key": "USECASE104", + "description": "Relay disabled", + "relay": { + "type": "VALIDATOR", + "activated": false + }, + "activated": true, + "components": [ + "switcher-client" + ] } ] } diff --git a/src/test/resources/test.json b/src/test/resources/test.json index b03705d0..52cd0c8e 100644 --- a/src/test/resources/test.json +++ b/src/test/resources/test.json @@ -2,17 +2,14 @@ "data": { "domain": { "name": "switcher-domain", - "description": "Test Snapshot", "activated": true, "group": [ { "name": "Group 1", - "description": "Simple test", "activated": true, "config": [ { "key": "USECASE11", - "description": "Simple test - Domain disabled", "activated": true, "components": ["switcher-client"] }