Skip to content
Open
Show file tree
Hide file tree
Changes from 12 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
17 changes: 17 additions & 0 deletions src/main/java/dev/openfeature/sdk/FeatureProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@
return new ArrayList<>();
}

/**
* Returns all hooks that support the given flag value type.
*
* @param flagType the flag value type to support
* @return a list of hooks that support the given flag value type
*/
default List<Hook> getProviderHooks(FlagValueType flagType) {

Check warning on line 24 in src/main/java/dev/openfeature/sdk/FeatureProvider.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk6baie-DOkKWNIU&open=AZqiIk6baie-DOkKWNIU&pullRequest=1734
var allHooks = getProviderHooks();
var filteredHooks = new ArrayList<Hook>(allHooks.size());

Check warning on line 26 in src/main/java/dev/openfeature/sdk/FeatureProvider.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk6baie-DOkKWNIV&open=AZqiIk6baie-DOkKWNIV&pullRequest=1734
for (Hook hook : allHooks) {

Check warning on line 27 in src/main/java/dev/openfeature/sdk/FeatureProvider.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk6baie-DOkKWNIW&open=AZqiIk6baie-DOkKWNIW&pullRequest=1734
if (hook.supportsFlagValueType(flagType)) {
filteredHooks.add(hook);
}
}
return filteredHooks;
}

ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx);

ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx);
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dev.openfeature.sdk;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -15,4 +17,18 @@

@Builder.Default
Map<String, Object> hookHints = new HashMap<>();

List<Hook> getHooks(FlagValueType flagValueType) {

Check warning on line 21 in src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk9haie-DOkKWNIX&open=AZqiIk9haie-DOkKWNIX&pullRequest=1734
if (hooks == null || hooks.isEmpty()) {
return Collections.emptyList();
}

var result = new ArrayList<Hook>(hooks.size());

Check warning on line 26 in src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk9haie-DOkKWNIY&open=AZqiIk9haie-DOkKWNIY&pullRequest=1734
for (var hook : hooks) {
if (hook.supportsFlagValueType(flagValueType)) {
result.add(hook);
}
}
return result;
}
}
89 changes: 73 additions & 16 deletions src/main/java/dev/openfeature/sdk/HookSupport.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package dev.openfeature.sdk;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentLinkedQueue;
import lombok.extern.slf4j.Slf4j;

/**
Expand All @@ -17,26 +20,59 @@
* Sets the {@link Hook}-{@link HookContext}-{@link Pair} list in the given data object with {@link HookContext}
* set to null. Filters hooks by supported {@link FlagValueType}.
*
* @param hookSupportData the data object to modify
* @param hooks the hooks to set
* @param type the flag value type to filter unsupported hooks
* @param hookSupportData the data object to modify
* @param providerHooks the hooks filtered for the proper flag value type from the respective layer
* @param flagOptionsHooks the hooks filtered for the proper flag value type from the respective layer
* @param clientHooks the hooks filtered for the proper flag value type from the respective layer
* @param apiHooks the hooks filtered for the proper flag value type from the respective layer
*/
public void setHooks(HookSupportData hookSupportData, List<Hook> hooks, FlagValueType type) {
List<Pair<Hook, HookContext>> hookContextPairs = new ArrayList<>();
for (Hook hook : hooks) {
if (hook.supportsFlagValueType(type)) {
hookContextPairs.add(Pair.of(hook, null));
}
public void setHooks(
HookSupportData hookSupportData,
List<Hook> providerHooks,

Check warning on line 31 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIb&open=AZqiIk_Eaie-DOkKWNIb&pullRequest=1734
List<Hook> flagOptionsHooks,

Check warning on line 32 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIc&open=AZqiIk_Eaie-DOkKWNIc&pullRequest=1734
ConcurrentLinkedQueue<Hook> clientHooks,

Check warning on line 33 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

The type of "clientHooks" should be an interface such as "Queue" rather than the implementation "ConcurrentLinkedQueue".

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIZ&open=AZqiIk_Eaie-DOkKWNIZ&pullRequest=1734

Check warning on line 33 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNId&open=AZqiIk_Eaie-DOkKWNId&pullRequest=1734
ConcurrentLinkedQueue<Hook> apiHooks) {

Check warning on line 34 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIe&open=AZqiIk_Eaie-DOkKWNIe&pullRequest=1734

Check warning on line 34 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

The type of "apiHooks" should be an interface such as "Queue" rather than the implementation "ConcurrentLinkedQueue".

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIa&open=AZqiIk_Eaie-DOkKWNIa&pullRequest=1734
var lengthEstimate = 0;

if (providerHooks != null) {
lengthEstimate += providerHooks.size();
}
if (flagOptionsHooks != null) {
lengthEstimate += flagOptionsHooks.size();
}
if (clientHooks != null) {
lengthEstimate += clientHooks.size();
}
if (apiHooks != null) {
lengthEstimate += apiHooks.size();
}

ArrayList<Pair<Hook, HookContext>> hookContextPairs = new ArrayList<>(lengthEstimate);

Check warning on line 50 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIg&open=AZqiIk_Eaie-DOkKWNIg&pullRequest=1734

Check warning on line 50 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIf&open=AZqiIk_Eaie-DOkKWNIf&pullRequest=1734

addAll(hookContextPairs, providerHooks);
addAll(hookContextPairs, flagOptionsHooks);
addAll(hookContextPairs, clientHooks);
addAll(hookContextPairs, apiHooks);

hookSupportData.hooks = hookContextPairs;
}

private void addAll(List<Pair<Hook, HookContext>> accumulator, Collection<Hook> toAdd) {

Check warning on line 60 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIi&open=AZqiIk_Eaie-DOkKWNIi&pullRequest=1734

Check warning on line 60 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Faie-DOkKWNIj&open=AZqiIk_Faie-DOkKWNIj&pullRequest=1734

Check warning on line 60 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Eaie-DOkKWNIh&open=AZqiIk_Eaie-DOkKWNIh&pullRequest=1734
if (toAdd == null || toAdd.isEmpty()) {
return;
}

for (Hook hook : toAdd) {

Check warning on line 65 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIk_Faie-DOkKWNIk&open=AZqiIk_Faie-DOkKWNIk&pullRequest=1734
accumulator.add(Pair.of(hook, null));
}
}

/**
* Creates & sets a {@link HookContext} for every {@link Hook}-{@link HookContext}-{@link Pair}
* in the given data object with a new {@link HookData} instance.
*
* @param hookSupportData the data object to modify
* @param sharedContext the shared context from which the new {@link HookContext} is created
* @param hookSupportData the data object to modify
* @param sharedContext the shared context from which the new {@link HookContext} is created
*/
public void setHookContexts(HookSupportData hookSupportData, SharedHookContext sharedContext) {
for (int i = 0; i < hookSupportData.hooks.size(); i++) {
Expand Down Expand Up @@ -66,10 +102,9 @@

public void executeBeforeHooks(HookSupportData data) {
// These traverse backwards from normal.
List<Pair<Hook, HookContext>> reversedHooks = new ArrayList<>(data.getHooks());
Collections.reverse(reversedHooks);

for (Pair<Hook, HookContext> hookContextPair : reversedHooks) {
var hooks = data.getHooks();
for (int i = hooks.size() - 1; i >= 0; i--) {
var hookContextPair = hooks.get(i);
var hook = hookContextPair.getKey();
var hookContext = hookContextPair.getValue();

Expand Down Expand Up @@ -123,4 +158,26 @@
}
}
}

static void addHooks(Map<FlagValueType, ConcurrentLinkedQueue<Hook>> hookMap, Hook... hooksToAdd) {

Check warning on line 162 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZq1D1F8EzQ6q8saNcpy&open=AZq1D1F8EzQ6q8saNcpy&pullRequest=1734
var types = FlagValueType.values();
for (int i = 0; i < hooksToAdd.length; i++) {
var current = hooksToAdd[i];
for (int j = 0; j < types.length; j++) {
var type = types[j];
if (current.supportsFlagValueType(type)) {
hookMap.get(type).add(current);
}
}
}
}

static ArrayList<Hook> getAllUniqueHooks(Map<FlagValueType, ConcurrentLinkedQueue<Hook>> hookMap) {

Check warning on line 175 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZq1D1F8EzQ6q8saNcpz&open=AZq1D1F8EzQ6q8saNcpz&pullRequest=1734

Check warning on line 175 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZq1D1F8EzQ6q8saNcp0&open=AZq1D1F8EzQ6q8saNcp0&pullRequest=1734
// Hooks can be duplicated if they support multiple FlagValueTypes
var allHooks = new HashSet<Hook>();

Check warning on line 177 in src/main/java/dev/openfeature/sdk/HookSupport.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZq1D1F8EzQ6q8saNcp1&open=AZq1D1F8EzQ6q8saNcp1&pullRequest=1734
for (var queue : hookMap.values()) {
allHooks.addAll(queue);
}
return new ArrayList<>(allHooks);
}
}
4 changes: 2 additions & 2 deletions src/main/java/dev/openfeature/sdk/HookSupportData.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.openfeature.sdk;

import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import lombok.Getter;

Expand All @@ -10,7 +10,7 @@
@Getter
class HookSupportData {

List<Pair<Hook, HookContext>> hooks;
ArrayList<Pair<Hook, HookContext>> hooks;
EvaluationContext evaluationContext;
Map<String, Object> hints;

Expand Down
24 changes: 13 additions & 11 deletions src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
import dev.openfeature.sdk.exceptions.OpenFeatureError;
import dev.openfeature.sdk.internal.AutoCloseableLock;
import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
Expand All @@ -24,14 +22,18 @@
public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
// package-private multi-read/single-write lock
static AutoCloseableReentrantReadWriteLock lock = new AutoCloseableReentrantReadWriteLock();
private final ConcurrentLinkedQueue<Hook> apiHooks;
private final ConcurrentHashMap<FlagValueType, ConcurrentLinkedQueue<Hook>> apiHooks;

Check warning on line 25 in src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZq1D1JpEzQ6q8saNcp2&open=AZq1D1JpEzQ6q8saNcp2&pullRequest=1734
private ProviderRepository providerRepository;
private EventSupport eventSupport;
private final AtomicReference<EvaluationContext> evaluationContext = new AtomicReference<>();
private TransactionContextPropagator transactionContextPropagator;

protected OpenFeatureAPI() {
apiHooks = new ConcurrentLinkedQueue<>();
var values = FlagValueType.values();
apiHooks = new ConcurrentHashMap<>(values.length);
for (FlagValueType value : values) {
apiHooks.put(value, new ConcurrentLinkedQueue<>());
}
providerRepository = new ProviderRepository(this);
eventSupport = new EventSupport();
transactionContextPropagator = new NoOpTransactionContextPropagator();
Expand Down Expand Up @@ -304,7 +306,7 @@
* @param hooks The hook to add.
*/
public void addHooks(Hook... hooks) {
this.apiHooks.addAll(Arrays.asList(hooks));
HookSupport.addHooks(apiHooks, hooks);
}

/**
Expand All @@ -313,16 +315,16 @@
* @return A list of {@link Hook}s.
*/
public List<Hook> getHooks() {
return new ArrayList<>(this.apiHooks);
return HookSupport.getAllUniqueHooks(apiHooks);
}

/**
* Returns a reference to the collection of {@link Hook}s.
* Fetch the hooks associated to this client, that support the given FlagValueType.
*
* @return The collection of {@link Hook}s.
* @return A list of {@link Hook}s.
*/
Collection<Hook> getMutableHooks() {
return this.apiHooks;
ConcurrentLinkedQueue<Hook> getHooks(FlagValueType type) {

Check warning on line 326 in src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Provide the parametrized type for this generic.

See more on https://sonarcloud.io/project/issues?id=open-feature_java-sdk&issues=AZqiIlADaie-DOkKWNIm&open=AZqiIlADaie-DOkKWNIm&pullRequest=1734
return apiHooks.get(type);
}

/**
Expand Down
24 changes: 15 additions & 9 deletions src/main/java/dev/openfeature/sdk/OpenFeatureClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
import dev.openfeature.sdk.exceptions.ProviderNotReadyError;
import dev.openfeature.sdk.internal.ObjectUtils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
Expand Down Expand Up @@ -47,7 +46,7 @@ public class OpenFeatureClient implements Client {
@Getter
private final String version;

private final ConcurrentLinkedQueue<Hook> clientHooks;
private final ConcurrentHashMap<FlagValueType, ConcurrentLinkedQueue<Hook>> clientHooks;
private final AtomicReference<EvaluationContext> evaluationContext = new AtomicReference<>();

private final HookSupport hookSupport;
Expand All @@ -69,7 +68,11 @@ public OpenFeatureClient(OpenFeatureAPI openFeatureAPI, String domain, String ve
this.domain = domain;
this.version = version;
this.hookSupport = new HookSupport();
this.clientHooks = new ConcurrentLinkedQueue<>();
var values = FlagValueType.values();
this.clientHooks = new ConcurrentHashMap<>(values.length);
for (FlagValueType value : values) {
this.clientHooks.put(value, new ConcurrentLinkedQueue<>());
}
}

/**
Expand Down Expand Up @@ -125,7 +128,7 @@ public void track(String trackingEventName, EvaluationContext context, TrackingE
*/
@Override
public OpenFeatureClient addHooks(Hook... hooks) {
this.clientHooks.addAll(Arrays.asList(hooks));
HookSupport.addHooks(clientHooks, hooks);
return this;
}

Expand All @@ -134,7 +137,7 @@ public OpenFeatureClient addHooks(Hook... hooks) {
*/
@Override
public List<Hook> getHooks() {
return new ArrayList<>(this.clientHooks);
return HookSupport.getAllUniqueHooks(clientHooks);
}

/**
Expand Down Expand Up @@ -174,9 +177,12 @@ private <T> FlagEvaluationDetails<T> evaluateFlag(
final var state = stateManager.getState();

// Hooks are initialized as early as possible to enable the execution of error stages
var mergedHooks = ObjectUtils.merge(
provider.getProviderHooks(), flagOptions.getHooks(), clientHooks, openfeatureApi.getMutableHooks());
hookSupport.setHooks(hookSupportData, mergedHooks, type);
hookSupport.setHooks(
hookSupportData,
provider.getProviderHooks(type),
flagOptions.getHooks(type),
clientHooks.get(type),
openfeatureApi.getHooks(type));

var sharedHookContext =
new SharedHookContext(key, type, this.getMetadata(), provider.getMetadata(), defaultValue);
Expand Down
24 changes: 15 additions & 9 deletions src/test/java/dev/openfeature/sdk/DeveloperExperienceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand All @@ -14,6 +15,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.SneakyThrows;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -101,9 +103,10 @@ void brokenProvider() {
void providerLockedPerTransaction() {

final String defaultValue = "string-value";
final OpenFeatureAPI api = new OpenFeatureAPI();
var provider1 = TestProvider.builder().initsToReady();
var provider2 = TestProvider.builder().initsToReady();
final OpenFeatureAPI testApi = new OpenFeatureAPI();
final var provider1 = TestProvider.builder().initsToReady();
final var provider2 = TestProvider.builder().initsToReady();
final var wasHookCalled = new AtomicBoolean(false);

class MutatingHook implements Hook {

Expand All @@ -112,24 +115,27 @@ class MutatingHook implements Hook {
// change the provider during a before hook - this should not impact the evaluation in progress
public Optional before(HookContext ctx, Map hints) {

api.setProviderAndWait(provider2);

testApi.setProviderAndWait(provider2);
wasHookCalled.set(true);
return Optional.empty();
}
}

final Client client = api.getClient();
api.setProviderAndWait(provider1);
api.addHooks(new MutatingHook());
final Client client = testApi.getClient();
testApi.setProviderAndWait(provider1);
testApi.addHooks(new MutatingHook());

// if provider is changed during an evaluation transaction it should proceed with the original provider
client.getStringValue("val", defaultValue);
assertEquals(1, provider1.getFlagEvaluations().size());
assertEquals(0, provider2.getFlagEvaluations().size());
assertTrue(wasHookCalled.get());

api.clearHooks();
testApi.clearHooks();

// subsequent evaluations should now use new provider set by hook
client.getStringValue("val", defaultValue);
assertEquals(1, provider1.getFlagEvaluations().size());
assertEquals(1, provider2.getFlagEvaluations().size());
}

Expand Down
Loading
Loading