Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,10 @@ Write automated tests using this built-in test annotation to guide your test sce
```java
Switcher switcher = MyAppFeatures.getSwitcher(FEATURE01);

SwitcherExecutor.assume(FEATURE01, false);
SwitcherBypass.assume(FEATURE01, false);
switcher.isItOn(); // 'false'

SwitcherExecutor.forget(FEATURE01);
SwitcherBypass.forget(FEATURE01);
switcher.isItOn(); // Now, it's going to return the result retrieved from the API or the Snapshot file
```

Expand All @@ -297,7 +297,7 @@ For more complex scenarios where you need to test features based on specific inp
```java
Switcher switcher = MyAppFeatures.getSwitcher(FEATURE01).checkValue("My value").build();

SwitcherExecutor.assume(FEATURE01, true).when(StrategyValidator.VALUE, "My value");
SwitcherBypass.assume(FEATURE01, true).when(StrategyValidator.VALUE, "My value");
switcher.isItOn(); // 'true'

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public static void checkSwitchers() {
* @return snapshot version
*/
public static long getSnapshotVersion() {
return SwitcherContextBase.instance.getSnapshotVersion();
return SwitcherContextBase.switcherExecutor.getSnapshotVersion();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public abstract class SwitcherContextBase extends SwitcherConfig {
protected static SwitcherProperties switcherProperties;
protected static Set<String> switcherKeys;
protected static Map<String, SwitcherRequest> switchers;
protected static SwitcherExecutor instance;
protected static SwitcherExecutor switcherExecutor;
private static ScheduledExecutorService scheduledExecutorService;
private static ExecutorService watcherExecutorService;
private static SnapshotWatcher watcherSnapshot;
Expand Down Expand Up @@ -180,7 +180,7 @@ public static void loadProperties(String contextFilename) {
public static void initializeClient() {
validateContext();
registerSwitcherKeys();
instance = buildInstance();
switcherExecutor = buildInstance();

loadSwitchers();
scheduleSnapshotAutoUpdate(contextStr(ContextKey.SNAPSHOT_AUTO_UPDATE_INTERVAL));
Expand Down Expand Up @@ -258,7 +258,7 @@ private static void loadSwitchers() {

switchers.clear();
for (String key : switcherKeys) {
switchers.put(key, new SwitcherRequest(key, instance));
switchers.put(key, new SwitcherRequest(key, switcherExecutor, switcherProperties));
}
}

Expand All @@ -280,7 +280,7 @@ public static ScheduledFuture<?> scheduleSnapshotAutoUpdate(String intervalValue
final Runnable runnableSnapshotValidate = () -> {
try {
if (validateSnapshot()) {
callbackFinal.onSnapshotUpdate(instance.getSnapshotVersion());
callbackFinal.onSnapshotUpdate(switcherExecutor.getSnapshotVersion());
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
Expand Down Expand Up @@ -386,11 +386,11 @@ public static SwitcherRequest getSwitcher(String key) {
* @return true if snapshot was updated
*/
public static boolean validateSnapshot() {
if (contextBol(ContextKey.SNAPSHOT_SKIP_VALIDATION) || instance.checkSnapshotVersion()) {
if (contextBol(ContextKey.SNAPSHOT_SKIP_VALIDATION) || switcherExecutor.checkSnapshotVersion()) {
return false;
}

instance.updateSnapshot();
switcherExecutor.updateSnapshot();
return true;
}

Expand All @@ -416,12 +416,12 @@ public static void watchSnapshot() {
* @throws SwitcherException if using remote service
*/
public static void watchSnapshot(SnapshotEventHandler handler) {
if (!(instance instanceof SwitcherLocalService)) {
if (!(switcherExecutor instanceof SwitcherLocalService)) {
throw new SwitcherException("Cannot watch snapshot when using remote", new UnsupportedOperationException());
}

if (Objects.isNull(watcherSnapshot)) {
watcherSnapshot = new SnapshotWatcher((SwitcherLocalService) instance, handler,
watcherSnapshot = new SnapshotWatcher((SwitcherLocalService) switcherExecutor, handler,
contextStr(ContextKey.SNAPSHOT_LOCATION));
}

Expand All @@ -448,7 +448,7 @@ public static void stopWatchingSnapshot() {
* @throws SwitchersValidationException when one or more Switcher Key is not found
*/
public static void checkSwitchers() {
instance.checkSwitchers(switcherKeys);
switcherExecutor.checkSwitchers(switcherKeys);
}

/**
Expand Down
122 changes: 19 additions & 103 deletions src/main/java/com/github/switcherapi/client/SwitcherExecutor.java
Original file line number Diff line number Diff line change
@@ -1,157 +1,73 @@
package com.github.switcherapi.client;

import com.github.switcherapi.client.exception.SwitcherRemoteException;
import com.github.switcherapi.client.exception.SwitcherSnapshotWriteException;
import com.github.switcherapi.client.model.ContextKey;
import com.github.switcherapi.client.model.SwitcherRequest;
import com.github.switcherapi.client.model.criteria.Domain;
import com.github.switcherapi.client.model.criteria.Snapshot;
import com.github.switcherapi.client.model.SwitcherResult;
import com.github.switcherapi.client.service.remote.ClientRemote;
import com.github.switcherapi.client.utils.SnapshotLoader;
import com.github.switcherapi.client.utils.SwitcherUtils;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.switcherapi.client.model.criteria.Domain;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
* The Executor provides an API to handle Remote and Local functionalities that
* An Executor provides the API to handle Remote and Local operations that
* should be available for both Services implementations.
*
* @author Roger Floriano (petruki)
* @since 2019-12-24
*/
public abstract class SwitcherExecutor {

private static final Logger logger = LoggerFactory.getLogger(SwitcherExecutor.class);

private static final Map<String, SwitcherResult> bypass = new HashMap<>();

protected final SwitcherProperties switcherProperties;

protected Domain domain;
public interface SwitcherExecutor {

protected SwitcherExecutor(final SwitcherProperties switcherProperties) {
this.switcherProperties = switcherProperties;
}

/**
* Execute criteria based on the Switcher configuration
*
* @param switcher to be evaluated
* @return Criteria response containing the evaluation details
*/
public abstract SwitcherResult executeCriteria(final SwitcherRequest switcher);
SwitcherResult executeCriteria(final SwitcherRequest switcher);

/**
* Check the snapshot versions against the Remote configuration.
*
* @return True if snapshot is up-to-date
*/
public abstract boolean checkSnapshotVersion();
boolean checkSnapshotVersion();

/**
* Retrieve updated snapshot from the remote API
*/
public abstract void updateSnapshot();
void updateSnapshot();

/**
* Check set of Switchers if they are properly configured.
*
* @param switchers To be validated
*/
public abstract void checkSwitchers(final Set<String> switchers);
void checkSwitchers(final Set<String> switchers);

/**
* Retrieve local snapshot version
*
* @return snapshot version
*/
public abstract long getSnapshotVersion();

protected boolean checkSnapshotVersion(ClientRemote clientRemote, final Domain domain) {
final String environment = switcherProperties.getValue(ContextKey.ENVIRONMENT);
SwitcherUtils.debug(logger, "verifying snapshot version - environment: {}", environment);

return clientRemote.checkSnapshotVersion(domain.getVersion());
}

protected Domain initializeSnapshotFromAPI(ClientRemote clientRemote)
throws SwitcherRemoteException, SwitcherSnapshotWriteException {
final String environment = switcherProperties.getValue(ContextKey.ENVIRONMENT);
SwitcherUtils.debug(logger, "initializing snapshot from API - environment: {}", environment);

final Snapshot snapshot = clientRemote.resolveSnapshot();
final String snapshotLocation = switcherProperties.getValue(ContextKey.SNAPSHOT_LOCATION);
long getSnapshotVersion();

if (Objects.nonNull(snapshotLocation)) {
SnapshotLoader.saveSnapshot(snapshot, snapshotLocation, environment);
}

return snapshot.getDomain();
}

/**
* It manipulates the result of a given Switcher key.
*
* @param key name of the key that you want to change the result
* @param expectedResult that will be returned when performing isItOn
* @return SwitcherResult with the manipulated result
* Retrieve the Domain object from the current snapshot
*
* @return Domain object
*/
public static SwitcherResult assume(final String key, boolean expectedResult) {
return assume(key, expectedResult, null);
}
Domain getDomain();

/**
* It manipulates the result of a given Switcher key.
* Set the Domain object from the current snapshot
*
* @param key name of the key that you want to change the result
* @param metadata additional information about the assumption (JSON)
* @param expectedResult that will be returned when performing isItOn
* @return SwitcherResult with the manipulated result
* @param domain to be set
*/
public static SwitcherResult assume(final String key, boolean expectedResult, String metadata) {
SwitcherResult switcherResult = new SwitcherResult();
switcherResult.setResult(expectedResult);
switcherResult.setReason("Switcher bypassed");

if (StringUtils.isNotBlank(metadata)) {
Gson gson = new Gson();
switcherResult.setMetadata(gson.fromJson(metadata, Object.class));
}
void setDomain(Domain domain);

bypass.put(key, switcherResult);
return switcherResult;
}

/**
* It will clean up any result manipulation added before by invoking {@link SwitcherExecutor#assume(String, boolean)}
*
* @param key name of the key you want to remove
* Retrieve the Switcher properties configured for the executor
*
* @return SwitcherProperties object
*/
public static void forget(final String key) {
bypass.remove(key);
}

public static Map<String, SwitcherResult> getBypass() {
return bypass;
}

public SwitcherProperties getSwitcherProperties() {
return switcherProperties;
}

public Domain getDomain() {
return domain;
}
SwitcherProperties getSwitcherProperties();

public void setDomain(Domain domain) {
this.domain = domain;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.github.switcherapi.client;

import com.github.switcherapi.client.exception.SwitcherRemoteException;
import com.github.switcherapi.client.exception.SwitcherSnapshotWriteException;
import com.github.switcherapi.client.model.ContextKey;
import com.github.switcherapi.client.model.criteria.Domain;
import com.github.switcherapi.client.model.criteria.Snapshot;
import com.github.switcherapi.client.service.remote.ClientRemote;
import com.github.switcherapi.client.utils.SnapshotLoader;
import com.github.switcherapi.client.utils.SwitcherUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;

public abstract class SwitcherExecutorImpl implements SwitcherExecutor {

private static final Logger logger = LoggerFactory.getLogger(SwitcherExecutorImpl.class);

protected final SwitcherProperties switcherProperties;

protected Domain domain;

protected SwitcherExecutorImpl(final SwitcherProperties switcherProperties) {
this.switcherProperties = switcherProperties;
}

protected boolean checkSnapshotVersion(ClientRemote clientRemote, final Domain domain) {
final String environment = switcherProperties.getValue(ContextKey.ENVIRONMENT);
SwitcherUtils.debug(logger, "verifying snapshot version - environment: {}", environment);

return clientRemote.checkSnapshotVersion(domain.getVersion());
}

protected Domain initializeSnapshotFromAPI(ClientRemote clientRemote)
throws SwitcherRemoteException, SwitcherSnapshotWriteException {
final String environment = switcherProperties.getValue(ContextKey.ENVIRONMENT);
SwitcherUtils.debug(logger, "initializing snapshot from API - environment: {}", environment);

final Snapshot snapshot = clientRemote.resolveSnapshot();
final String snapshotLocation = switcherProperties.getValue(ContextKey.SNAPSHOT_LOCATION);

if (Objects.nonNull(snapshotLocation)) {
SnapshotLoader.saveSnapshot(snapshot, snapshotLocation, environment);
}

return snapshot.getDomain();
}

@Override
public SwitcherProperties getSwitcherProperties() {
return switcherProperties;
}

@Override
public Domain getDomain() {
return domain;
}

@Override
public void setDomain(Domain domain) {
this.domain = domain;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.github.switcherapi.client.SwitcherContext;
import com.github.switcherapi.client.SwitcherExecutor;
import com.github.switcherapi.client.SwitcherProperties;
import com.github.switcherapi.client.exception.SwitcherException;
import com.github.switcherapi.client.test.SwitcherBypass;

import java.util.*;

Expand Down Expand Up @@ -37,9 +39,12 @@ public final class SwitcherRequest extends SwitcherBuilder {
*
* @param switcherKey name of the key created
* @param switcherExecutor client context in which the switcher will be executed (local/remote)
* @param switcherProperties properties to be used with executor operations
*/
public SwitcherRequest(final String switcherKey, final SwitcherExecutor switcherExecutor) {
super(switcherExecutor.getSwitcherProperties());
public SwitcherRequest(final String switcherKey,
final SwitcherExecutor switcherExecutor,
final SwitcherProperties switcherProperties) {
super(switcherProperties);
this.switcherExecutor = switcherExecutor;
this.switcherKey = switcherKey;
this.historyExecution = new HashSet<>();
Expand Down Expand Up @@ -83,8 +88,8 @@ public boolean isItOn() throws SwitcherException {

@Override
public SwitcherResult submit() throws SwitcherException {
if (SwitcherExecutor.getBypass().containsKey(switcherKey)) {
return SwitcherExecutor.getBypass().get(switcherKey).buildFromSwitcher(switcherKey, entry);
if (SwitcherBypass.getBypass().containsKey(switcherKey)) {
return SwitcherBypass.getBypass().get(switcherKey).buildFromSwitcher(switcherKey, entry);
}

if (canUseAsync()) {
Expand Down
Loading