fix: hooks not run in NOT_READY/FATAL (#1392)
* fix: hooks not run in NOT_READY/FATAL Signed-off-by: Todd Baert <todd.baert@dynatrace.com> --------- Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
This commit is contained in:
parent
753667925a
commit
24ef9dd290
|
|
@ -178,12 +178,6 @@ public class OpenFeatureClient implements Client {
|
|||
// provider must be accessed once to maintain a consistent reference
|
||||
provider = stateManager.getProvider();
|
||||
ProviderState state = stateManager.getState();
|
||||
if (ProviderState.NOT_READY.equals(state)) {
|
||||
throw new ProviderNotReadyError("provider not yet initialized");
|
||||
}
|
||||
if (ProviderState.FATAL.equals(state)) {
|
||||
throw new FatalError("provider is in an irrecoverable error state");
|
||||
}
|
||||
|
||||
mergedHooks = ObjectUtils.merge(
|
||||
provider.getProviderHooks(), flagOptions.getHooks(), clientHooks, openfeatureApi.getHooks());
|
||||
|
|
@ -203,6 +197,14 @@ public class OpenFeatureClient implements Client {
|
|||
afterHookContext =
|
||||
HookContext.from(key, type, this.getMetadata(), provider.getMetadata(), mergedCtx, defaultValue);
|
||||
|
||||
// "short circuit" if the provider is in NOT_READY or FATAL state
|
||||
if (ProviderState.NOT_READY.equals(state)) {
|
||||
throw new ProviderNotReadyError("Provider not yet initialized");
|
||||
}
|
||||
if (ProviderState.FATAL.equals(state)) {
|
||||
throw new FatalError("Provider is in an irrecoverable error state");
|
||||
}
|
||||
|
||||
ProviderEvaluation<T> providerEval =
|
||||
(ProviderEvaluation<T>) createProviderEvaluation(type, key, defaultValue, provider, mergedCtx);
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
package dev.openfeature.sdk;
|
||||
|
||||
import dev.openfeature.sdk.exceptions.FatalError;
|
||||
import dev.openfeature.sdk.exceptions.GeneralError;
|
||||
|
||||
public class FatalErrorProvider implements FeatureProvider {
|
||||
|
||||
private final String name = "fatal";
|
||||
|
||||
@Override
|
||||
public Metadata getMetadata() {
|
||||
return () -> name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(EvaluationContext evaluationContext) throws Exception {
|
||||
throw new FatalError(); // throw a fatal error on startup (this will cause the SDK to short circuit evaluations)
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx) {
|
||||
throw new GeneralError(TestConstants.BROKEN_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx) {
|
||||
throw new GeneralError(TestConstants.BROKEN_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx) {
|
||||
throw new GeneralError(TestConstants.BROKEN_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx) {
|
||||
throw new GeneralError(TestConstants.BROKEN_MESSAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderEvaluation<Value> getObjectEvaluation(
|
||||
String key, Value defaultValue, EvaluationContext invocationContext) {
|
||||
throw new GeneralError(TestConstants.BROKEN_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
|
@ -594,6 +594,25 @@ class HookSpecTest implements HookFixtures {
|
|||
assertThat(evaluationDetails.getValue()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shortCircuit_flagResolution_runsHooksWithAllFields() {
|
||||
String domain = "shortCircuit_flagResolution_setsAppropriateFieldsInFlagEvaluationDetails";
|
||||
api.setProvider(domain, new FatalErrorProvider());
|
||||
|
||||
Hook hook = mockBooleanHook();
|
||||
String flagKey = "test-flag-key";
|
||||
Client client = api.getClient(domain);
|
||||
client.getBooleanValue(
|
||||
flagKey,
|
||||
true,
|
||||
new ImmutableContext(),
|
||||
FlagEvaluationOptions.builder().hook(hook).build());
|
||||
|
||||
verify(hook).before(any(), any());
|
||||
verify(hook).error(any(HookContext.class), any(Exception.class), any(Map.class));
|
||||
verify(hook).finallyAfter(any(HookContext.class), any(FlagEvaluationDetails.class), any(Map.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void successful_flagResolution_setsAppropriateFieldsInFlagEvaluationDetails() {
|
||||
Hook hook = mockBooleanHook();
|
||||
|
|
|
|||
Loading…
Reference in New Issue