From b1afd9e971168147fef508dfbcae236ed82ba901 Mon Sep 17 00:00:00 2001 From: Simon Schrottner Date: Tue, 10 Sep 2024 09:21:21 +0200 Subject: [PATCH 1/3] chore(style): add editorconfig for easier configuration Signed-off-by: Simon Schrottner --- .editorconfig | 72 ++++++ .../openfeature/sdk/AbstractStructure.java | 2 +- .../dev/openfeature/sdk/BaseEvaluation.java | 6 + .../java/dev/openfeature/sdk/BooleanHook.java | 2 +- src/main/java/dev/openfeature/sdk/Client.java | 3 + .../java/dev/openfeature/sdk/DoubleHook.java | 4 +- .../java/dev/openfeature/sdk/EventBus.java | 26 +-- .../dev/openfeature/sdk/EventProvider.java | 13 +- .../dev/openfeature/sdk/EventSupport.java | 30 +-- .../dev/openfeature/sdk/FeatureProvider.java | 4 +- .../java/dev/openfeature/sdk/Features.java | 8 +- .../java/dev/openfeature/sdk/HookContext.java | 31 ++- .../java/dev/openfeature/sdk/HookSupport.java | 2 +- .../dev/openfeature/sdk/ImmutableContext.java | 4 +- .../openfeature/sdk/ImmutableStructure.java | 10 +- .../java/dev/openfeature/sdk/IntegerHook.java | 2 +- .../dev/openfeature/sdk/MutableStructure.java | 4 +- .../dev/openfeature/sdk/NoOpProvider.java | 2 +- .../sdk/NoOpTransactionContextPropagator.java | 1 + .../dev/openfeature/sdk/OpenFeatureAPI.java | 17 +- .../openfeature/sdk/OpenFeatureClient.java | 6 +- .../openfeature/sdk/ProviderEventDetails.java | 3 +- .../openfeature/sdk/ProviderRepository.java | 17 +- .../dev/openfeature/sdk/ProviderState.java | 2 +- .../java/dev/openfeature/sdk/StringHook.java | 2 +- .../java/dev/openfeature/sdk/Structure.java | 20 +- src/main/java/dev/openfeature/sdk/Value.java | 111 ++++----- .../sdk/exceptions/ExceptionUtils.java | 3 +- .../sdk/exceptions/FlagNotFoundError.java | 3 +- .../sdk/exceptions/InvalidContextError.java | 3 +- .../sdk/exceptions/ParseError.java | 3 +- .../sdk/exceptions/ProviderNotReadyError.java | 3 +- .../exceptions/TargetingKeyMissingError.java | 3 +- .../sdk/exceptions/TypeMismatchError.java | 3 +- .../sdk/hooks/logging/LoggingHook.java | 8 +- .../sdk/internal/AutoCloseableLock.java | 2 +- .../AutoCloseableReentrantReadWriteLock.java | 4 +- .../openfeature/sdk/internal/ObjectUtils.java | 26 ++- .../openfeature/sdk/internal/TriConsumer.java | 4 +- .../providers/memory/ContextEvaluator.java | 1 + .../providers/memory/InMemoryProvider.java | 23 +- .../sdk/DeveloperExperienceTest.java | 19 +- .../openfeature/sdk/DoSomethingProvider.java | 5 +- .../dev/openfeature/sdk/EvalContextTest.java | 98 ++++---- .../openfeature/sdk/EventProviderTest.java | 4 +- .../java/dev/openfeature/sdk/EventsTest.java | 28 ++- .../sdk/FlagEvaluationDetailsTest.java | 22 +- .../sdk/FlagEvaluationSpecTest.java | 213 +++++++++++------- .../dev/openfeature/sdk/HookContextTest.java | 14 +- .../dev/openfeature/sdk/HookSpecTest.java | 205 +++++++++-------- .../dev/openfeature/sdk/HookSupportTest.java | 21 +- .../openfeature/sdk/ImmutableContextTest.java | 32 +-- .../sdk/ImmutableStructureTest.java | 27 ++- .../sdk/InitializeBehaviorSpecTest.java | 27 +-- .../java/dev/openfeature/sdk/LockingTest.java | 10 +- .../dev/openfeature/sdk/MetadataTest.java | 6 +- .../openfeature/sdk/MutableContextTest.java | 32 +-- .../dev/openfeature/sdk/NoOpProviderTest.java | 15 +- .../sdk/NotImplementedException.java | 2 +- .../openfeature/sdk/OpenFeatureAPITest.java | 2 +- .../sdk/OpenFeatureClientTest.java | 19 +- .../sdk/ProviderEvaluationTest.java | 12 +- .../sdk/ProviderRepositoryTest.java | 12 +- .../dev/openfeature/sdk/Specification.java | 1 + .../dev/openfeature/sdk/StructureTest.java | 13 +- .../java/dev/openfeature/sdk/ValueTest.java | 53 +++-- .../openfeature/sdk/e2e/RunCucumberTest.java | 2 +- .../sdk/hooks/logging/LoggingHookTest.java | 8 +- .../memory/InMemoryProviderTest.java | 19 +- .../testutils/FeatureProviderTestUtils.java | 9 +- .../sdk/testutils/TestFlagsUtils.java | 79 +++---- 71 files changed, 880 insertions(+), 622 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..5bffb8ae0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,72 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +tab_width = 4 +trim_trailing_whitespace = true + +ij_continuation_indent_size = 8 + +[*.md] +max_line_length = off +trim_trailing_whitespace = false + +# Following the rules of the Google Java Style Guide. +# See https://google.github.io/styleguide/javaguide.html +[*.java] +max_line_length = 120 + +ij_java_do_not_wrap_after_single_annotation_in_parameter = true +ij_java_insert_inner_class_imports = false +ij_java_class_count_to_use_import_on_demand = 999 +ij_java_names_count_to_use_import_on_demand = 999 +ij_java_packages_to_use_import_on_demand = unset +ij_java_imports_layout = $*,|,* +ij_java_doc_align_param_comments = true +ij_java_doc_align_exception_comments = true +ij_java_doc_add_p_tag_on_empty_lines = false +ij_java_doc_do_not_wrap_if_one_line = true +ij_java_doc_keep_empty_parameter_tag = false +ij_java_doc_keep_empty_throws_tag = false +ij_java_doc_keep_empty_return_tag = false +ij_java_doc_preserve_line_breaks = true +ij_java_doc_indent_on_continuation = true +ij_java_keep_control_statement_in_one_line = false +ij_java_keep_blank_lines_in_code = 1 +ij_java_align_multiline_parameters = false +ij_java_align_multiline_resources = false +ij_java_align_multiline_for = true +ij_java_space_before_array_initializer_left_brace = true +ij_java_call_parameters_wrap = normal +ij_java_method_parameters_wrap = normal +ij_java_extends_list_wrap = normal +ij_java_throws_keyword_wrap = normal +ij_java_method_call_chain_wrap = normal +ij_java_binary_operation_wrap = normal +ij_java_binary_operation_sign_on_next_line = true +ij_java_ternary_operation_wrap = normal +ij_java_ternary_operation_signs_on_next_line = true +ij_java_keep_simple_methods_in_one_line = true +ij_java_keep_simple_lambdas_in_one_line = true +ij_java_keep_simple_classes_in_one_line = true +ij_java_for_statement_wrap = normal +ij_java_array_initializer_wrap = normal +ij_java_wrap_comments = true +ij_java_if_brace_force = always +ij_java_do_while_brace_force = always +ij_java_while_brace_force = always +ij_java_for_brace_force = always +ij_java_space_after_closing_angle_bracket_in_type_argument = false + +[{*.json,*.json5}] +indent_size = 2 +tab_width = 2 +ij_smart_tabs = false + +[*.yaml] +indent_size = 2 +tab_width = 2 diff --git a/src/main/java/dev/openfeature/sdk/AbstractStructure.java b/src/main/java/dev/openfeature/sdk/AbstractStructure.java index e50fbe920..88a4dd421 100644 --- a/src/main/java/dev/openfeature/sdk/AbstractStructure.java +++ b/src/main/java/dev/openfeature/sdk/AbstractStructure.java @@ -3,7 +3,7 @@ import java.util.HashMap; import java.util.Map; -@SuppressWarnings({ "PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType" }) +@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"}) abstract class AbstractStructure implements Structure { protected final Map attributes; diff --git a/src/main/java/dev/openfeature/sdk/BaseEvaluation.java b/src/main/java/dev/openfeature/sdk/BaseEvaluation.java index ed6e93510..d4209d9b2 100644 --- a/src/main/java/dev/openfeature/sdk/BaseEvaluation.java +++ b/src/main/java/dev/openfeature/sdk/BaseEvaluation.java @@ -2,29 +2,34 @@ /** * This is a common interface between the evaluation results that providers return and what is given to the end users. + * * @param The type of flag being evaluated. */ public interface BaseEvaluation { /** * Returns the resolved value of the evaluation. + * * @return {T} the resolve value */ T getValue(); /** * Returns an identifier for this value, if applicable. + * * @return {String} value identifier */ String getVariant(); /** * Describes how we came to the value that we're returning. + * * @return {Reason} */ String getReason(); /** * The error code, if applicable. Should only be set when the Reason is ERROR. + * * @return {ErrorCode} */ ErrorCode getErrorCode(); @@ -32,6 +37,7 @@ public interface BaseEvaluation { /** * The error message (usually from exception.getMessage()), if applicable. * Should only be set when the Reason is ERROR. + * * @return {String} */ String getErrorMessage(); diff --git a/src/main/java/dev/openfeature/sdk/BooleanHook.java b/src/main/java/dev/openfeature/sdk/BooleanHook.java index e9277766e..3c178ca5a 100644 --- a/src/main/java/dev/openfeature/sdk/BooleanHook.java +++ b/src/main/java/dev/openfeature/sdk/BooleanHook.java @@ -3,7 +3,7 @@ /** * An extension point which can run around flag resolution. They are intended to be used as a way to add custom logic * to the lifecycle of flag evaluation. - * + * * @see Hook */ public interface BooleanHook extends Hook { diff --git a/src/main/java/dev/openfeature/sdk/Client.java b/src/main/java/dev/openfeature/sdk/Client.java index 2184cdcbb..75dc443a9 100644 --- a/src/main/java/dev/openfeature/sdk/Client.java +++ b/src/main/java/dev/openfeature/sdk/Client.java @@ -10,12 +10,14 @@ public interface Client extends Features, EventBus { /** * Return an optional client-level evaluation context. + * * @return {@link EvaluationContext} */ EvaluationContext getEvaluationContext(); /** * Set the client-level evaluation context. + * * @param ctx Client level context. */ Client setEvaluationContext(EvaluationContext ctx); @@ -30,6 +32,7 @@ public interface Client extends Features, EventBus { /** * Fetch the hooks associated to this client. + * * @return A list of {@link Hook}s. */ List getHooks(); diff --git a/src/main/java/dev/openfeature/sdk/DoubleHook.java b/src/main/java/dev/openfeature/sdk/DoubleHook.java index 3ccf88b1b..70d17b37a 100644 --- a/src/main/java/dev/openfeature/sdk/DoubleHook.java +++ b/src/main/java/dev/openfeature/sdk/DoubleHook.java @@ -3,7 +3,7 @@ /** * An extension point which can run around flag resolution. They are intended to be used as a way to add custom logic * to the lifecycle of flag evaluation. - * + * * @see Hook */ public interface DoubleHook extends Hook { @@ -12,4 +12,4 @@ public interface DoubleHook extends Hook { default boolean supportsFlagValueType(FlagValueType flagValueType) { return FlagValueType.DOUBLE == flagValueType; } -} \ No newline at end of file +} diff --git a/src/main/java/dev/openfeature/sdk/EventBus.java b/src/main/java/dev/openfeature/sdk/EventBus.java index d635e9bac..16bd83405 100644 --- a/src/main/java/dev/openfeature/sdk/EventBus.java +++ b/src/main/java/dev/openfeature/sdk/EventBus.java @@ -6,38 +6,38 @@ * Interface for attaching event handlers. */ public interface EventBus { - + /** * Add a handler for the {@link ProviderEvent#PROVIDER_READY} event. * Shorthand for {@link #on(ProviderEvent, Consumer)} - * + * * @param handler behavior to add with this event * @return this */ T onProviderReady(Consumer handler); - + /** * Add a handler for the {@link ProviderEvent#PROVIDER_CONFIGURATION_CHANGED} event. * Shorthand for {@link #on(ProviderEvent, Consumer)} - * + * * @param handler behavior to add with this event * @return this */ T onProviderConfigurationChanged(Consumer handler); - + /** * Add a handler for the {@link ProviderEvent#PROVIDER_STALE} event. * Shorthand for {@link #on(ProviderEvent, Consumer)} - * + * * @param handler behavior to add with this event * @return this */ T onProviderError(Consumer handler); - + /** * Add a handler for the {@link ProviderEvent#PROVIDER_ERROR} event. * Shorthand for {@link #on(ProviderEvent, Consumer)} - * + * * @param handler behavior to add with this event * @return this */ @@ -45,18 +45,18 @@ public interface EventBus { /** * Add a handler for the specified {@link ProviderEvent}. - * - * @param event event type + * + * @param event event type * @param handler behavior to add with this event * @return this */ T on(ProviderEvent event, Consumer handler); - + /** * Remove the previously attached handler by reference. * If the handler doesn't exists, no-op. - * - * @param event event type + * + * @param event event type * @param handler to be removed * @return this */ diff --git a/src/main/java/dev/openfeature/sdk/EventProvider.java b/src/main/java/dev/openfeature/sdk/EventProvider.java index 4e8c022b4..89e328091 100644 --- a/src/main/java/dev/openfeature/sdk/EventProvider.java +++ b/src/main/java/dev/openfeature/sdk/EventProvider.java @@ -26,11 +26,10 @@ public abstract class EventProvider implements FeatureProvider { /** * "Attach" this EventProvider to an SDK, which allows events to propagate from this provider. - * No-op if the same onEmit is already attached. + * No-op if the same onEmit is already attached. * * @param onEmit the function to run when a provider emits events. * @throws IllegalStateException if attempted to bind a new emitter for already bound provider - * */ void attach(TriConsumer onEmit) { if (this.onEmit != null && this.onEmit != onEmit) { @@ -50,7 +49,7 @@ void detach() { /** * Emit the specified {@link ProviderEvent}. - * + * * @param event The event type * @param details The details of the event */ @@ -63,7 +62,7 @@ public void emit(ProviderEvent event, ProviderEventDetails details) { /** * Emit a {@link ProviderEvent#PROVIDER_READY} event. * Shorthand for {@link #emit(ProviderEvent, ProviderEventDetails)} - * + * * @param details The details of the event */ public void emitProviderReady(ProviderEventDetails details) { @@ -74,7 +73,7 @@ public void emitProviderReady(ProviderEventDetails details) { * Emit a * {@link ProviderEvent#PROVIDER_CONFIGURATION_CHANGED} * event. Shorthand for {@link #emit(ProviderEvent, ProviderEventDetails)} - * + * * @param details The details of the event */ public void emitProviderConfigurationChanged(ProviderEventDetails details) { @@ -84,7 +83,7 @@ public void emitProviderConfigurationChanged(ProviderEventDetails details) { /** * Emit a {@link ProviderEvent#PROVIDER_STALE} event. * Shorthand for {@link #emit(ProviderEvent, ProviderEventDetails)} - * + * * @param details The details of the event */ public void emitProviderStale(ProviderEventDetails details) { @@ -94,7 +93,7 @@ public void emitProviderStale(ProviderEventDetails details) { /** * Emit a {@link ProviderEvent#PROVIDER_ERROR} event. * Shorthand for {@link #emit(ProviderEvent, ProviderEventDetails)} - * + * * @param details The details of the event */ public void emitProviderError(ProviderEventDetails details) { diff --git a/src/main/java/dev/openfeature/sdk/EventSupport.java b/src/main/java/dev/openfeature/sdk/EventSupport.java index 085c8eb83..e27702435 100644 --- a/src/main/java/dev/openfeature/sdk/EventSupport.java +++ b/src/main/java/dev/openfeature/sdk/EventSupport.java @@ -35,7 +35,7 @@ class EventSupport { /** * Run all the event handlers associated with this domain. * If the domain is null, handlers attached to unnamed clients will run. - * + * * @param domain the domain to run event handlers for, or null * @param event the event type * @param eventDetails the event details @@ -54,7 +54,7 @@ public void runClientHandlers(String domain, ProviderEvent event, EventDetails e /** * Run all the API (global) event handlers. - * + * * @param event the event type * @param eventDetails the event details */ @@ -67,10 +67,10 @@ public void runGlobalHandlers(ProviderEvent event, EventDetails eventDetails) { /** * Add a handler for the specified domain, or all unnamed clients. - * - * @param domain the domain to add handlers for, or else unnamed - * @param event the event type - * @param handler the handler function to run + * + * @param domain the domain to add handlers for, or else unnamed + * @param event the event type + * @param handler the handler function to run */ public void addClientHandler(String domain, ProviderEvent event, Consumer handler) { final String name = Optional.ofNullable(domain) @@ -88,11 +88,11 @@ public void addClientHandler(String domain, ProviderEvent event, Consumer handler) { domain = Optional.ofNullable(domain) @@ -102,7 +102,7 @@ public void removeClientHandler(String domain, ProviderEvent event, Consumer handler /** * Remove a global event handler for the specified event type. - * + * * @param event the event type * @param handler the handler ref to be removed */ @@ -122,7 +122,7 @@ public void removeGlobalHandler(ProviderEvent event, Consumer hand /** * Get all domain names for which we have event handlers registered. - * + * * @return set of domain names */ public Set getAllDomainNames() { @@ -131,7 +131,7 @@ public Set getAllDomainNames() { /** * Run the passed handler on the taskExecutor. - * + * * @param handler the handler to run * @param eventDetails the event details */ diff --git a/src/main/java/dev/openfeature/sdk/FeatureProvider.java b/src/main/java/dev/openfeature/sdk/FeatureProvider.java index e1e06d0ab..dbcb191ac 100644 --- a/src/main/java/dev/openfeature/sdk/FeatureProvider.java +++ b/src/main/java/dev/openfeature/sdk/FeatureProvider.java @@ -60,9 +60,9 @@ default void shutdown() { * If the provider needs to be initialized, it should return {@link ProviderState#NOT_READY}. * If the provider is in an error state, it should return {@link ProviderState#ERROR}. * If the provider is functioning normally, it should return {@link ProviderState#READY}. - * + * *

Providers which do not implement this method are assumed to be ready immediately.

- * + * * @return ProviderState */ default ProviderState getState() { diff --git a/src/main/java/dev/openfeature/sdk/Features.java b/src/main/java/dev/openfeature/sdk/Features.java index ba25021a9..074b38c9b 100644 --- a/src/main/java/dev/openfeature/sdk/Features.java +++ b/src/main/java/dev/openfeature/sdk/Features.java @@ -16,7 +16,7 @@ public interface Features { FlagEvaluationDetails getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx); FlagEvaluationDetails getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options); + FlagEvaluationOptions options); String getStringValue(String key, String defaultValue); @@ -29,7 +29,7 @@ FlagEvaluationDetails getBooleanDetails(String key, Boolean defaultValu FlagEvaluationDetails getStringDetails(String key, String defaultValue, EvaluationContext ctx); FlagEvaluationDetails getStringDetails(String key, String defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options); + FlagEvaluationOptions options); Integer getIntegerValue(String key, Integer defaultValue); @@ -42,7 +42,7 @@ FlagEvaluationDetails getStringDetails(String key, String defaultValue, FlagEvaluationDetails getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx); FlagEvaluationDetails getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options); + FlagEvaluationOptions options); Double getDoubleValue(String key, Double defaultValue); @@ -55,7 +55,7 @@ FlagEvaluationDetails getIntegerDetails(String key, Integer defaultValu FlagEvaluationDetails getDoubleDetails(String key, Double defaultValue, EvaluationContext ctx); FlagEvaluationDetails getDoubleDetails(String key, Double defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options); + FlagEvaluationOptions options); Value getObjectValue(String key, Value defaultValue); diff --git a/src/main/java/dev/openfeature/sdk/HookContext.java b/src/main/java/dev/openfeature/sdk/HookContext.java index 5c9091b89..ce698534a 100644 --- a/src/main/java/dev/openfeature/sdk/HookContext.java +++ b/src/main/java/dev/openfeature/sdk/HookContext.java @@ -10,28 +10,35 @@ * * @param the type for the flag being evaluated */ -@Value @Builder @With +@Value +@Builder +@With public class HookContext { - @NonNull String flagKey; - @NonNull FlagValueType type; - @NonNull T defaultValue; - @NonNull EvaluationContext ctx; + @NonNull + String flagKey; + @NonNull + FlagValueType type; + @NonNull + T defaultValue; + @NonNull + EvaluationContext ctx; ClientMetadata clientMetadata; Metadata providerMetadata; /** * Builds a {@link HookContext} instances from request data. - * @param key feature flag key - * @param type flag value type - * @param clientMetadata info on which client is calling + * + * @param key feature flag key + * @param type flag value type + * @param clientMetadata info on which client is calling * @param providerMetadata info on the provider - * @param ctx Evaluation Context for the request - * @param defaultValue Fallback value - * @param type that the flag is evaluating against + * @param ctx Evaluation Context for the request + * @param defaultValue Fallback value + * @param type that the flag is evaluating against * @return resulting context for hook */ public static HookContext from(String key, FlagValueType type, ClientMetadata clientMetadata, - Metadata providerMetadata, EvaluationContext ctx, T defaultValue) { + Metadata providerMetadata, EvaluationContext ctx, T defaultValue) { return HookContext.builder() .flagKey(key) .type(type) diff --git a/src/main/java/dev/openfeature/sdk/HookSupport.java b/src/main/java/dev/openfeature/sdk/HookSupport.java index 52c5b9727..c6e7f3a4b 100644 --- a/src/main/java/dev/openfeature/sdk/HookSupport.java +++ b/src/main/java/dev/openfeature/sdk/HookSupport.java @@ -14,7 +14,7 @@ @Slf4j @RequiredArgsConstructor -@SuppressWarnings({ "unchecked", "rawtypes" }) +@SuppressWarnings({"unchecked", "rawtypes"}) class HookSupport { public EvaluationContext beforeHooks(FlagValueType flagValueType, HookContext hookCtx, List hooks, diff --git a/src/main/java/dev/openfeature/sdk/ImmutableContext.java b/src/main/java/dev/openfeature/sdk/ImmutableContext.java index fd2ff2a68..ed820b920 100644 --- a/src/main/java/dev/openfeature/sdk/ImmutableContext.java +++ b/src/main/java/dev/openfeature/sdk/ImmutableContext.java @@ -89,10 +89,10 @@ public EvaluationContext merge(EvaluationContext overridingContext) { @SuppressWarnings("all") private static class DelegateExclusions { @ExcludeFromGeneratedCoverageReport - public Map merge(Function, Structure> newStructure, + public Map merge(Function, Structure> newStructure, Map base, Map overriding) { - + return null; } } diff --git a/src/main/java/dev/openfeature/sdk/ImmutableStructure.java b/src/main/java/dev/openfeature/sdk/ImmutableStructure.java index d70a01637..57128c701 100644 --- a/src/main/java/dev/openfeature/sdk/ImmutableStructure.java +++ b/src/main/java/dev/openfeature/sdk/ImmutableStructure.java @@ -19,7 +19,7 @@ */ @ToString @EqualsAndHashCode -@SuppressWarnings({ "PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType" }) +@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"}) public final class ImmutableStructure extends AbstractStructure { /** @@ -40,8 +40,8 @@ public ImmutableStructure(Map attributes) { .collect(HashMap::new, (accumulated, entry) -> accumulated.put(entry.getKey(), Optional.ofNullable(entry.getValue()) - .map(Value::clone) - .orElse(null)), + .map(Value::clone) + .orElse(null)), HashMap::putAll))); } @@ -70,8 +70,8 @@ public Map asMap() { .collect(HashMap::new, (accumulated, entry) -> accumulated.put(entry.getKey(), Optional.ofNullable(entry.getValue()) - .map(Value::clone) - .orElse(null)), + .map(Value::clone) + .orElse(null)), HashMap::putAll); } } diff --git a/src/main/java/dev/openfeature/sdk/IntegerHook.java b/src/main/java/dev/openfeature/sdk/IntegerHook.java index ada05c78d..971c2b3d6 100644 --- a/src/main/java/dev/openfeature/sdk/IntegerHook.java +++ b/src/main/java/dev/openfeature/sdk/IntegerHook.java @@ -3,7 +3,7 @@ /** * An extension point which can run around flag resolution. They are intended to be used as a way to add custom logic * to the lifecycle of flag evaluation. - * + * * @see Hook */ public interface IntegerHook extends Hook { diff --git a/src/main/java/dev/openfeature/sdk/MutableStructure.java b/src/main/java/dev/openfeature/sdk/MutableStructure.java index fadd68051..cb2a7837c 100644 --- a/src/main/java/dev/openfeature/sdk/MutableStructure.java +++ b/src/main/java/dev/openfeature/sdk/MutableStructure.java @@ -10,9 +10,9 @@ import lombok.ToString; /** - * {@link MutableStructure} represents a potentially nested object type which is used to represent + * {@link MutableStructure} represents a potentially nested object type which is used to represent * structured data. - * The MutableStructure is a Structure implementation which is not threadsafe, and whose attributes can + * The MutableStructure is a Structure implementation which is not threadsafe, and whose attributes can * be modified after instantiation. */ @ToString diff --git a/src/main/java/dev/openfeature/sdk/NoOpProvider.java b/src/main/java/dev/openfeature/sdk/NoOpProvider.java index ef8cf1f83..0d37b277a 100644 --- a/src/main/java/dev/openfeature/sdk/NoOpProvider.java +++ b/src/main/java/dev/openfeature/sdk/NoOpProvider.java @@ -59,7 +59,7 @@ public ProviderEvaluation getDoubleEvaluation(String key, Double default @Override public ProviderEvaluation getObjectEvaluation(String key, Value defaultValue, - EvaluationContext invocationContext) { + EvaluationContext invocationContext) { return ProviderEvaluation.builder() .value(defaultValue) .variant(PASSED_IN_DEFAULT) diff --git a/src/main/java/dev/openfeature/sdk/NoOpTransactionContextPropagator.java b/src/main/java/dev/openfeature/sdk/NoOpTransactionContextPropagator.java index a31b39b4c..99a720f0c 100644 --- a/src/main/java/dev/openfeature/sdk/NoOpTransactionContextPropagator.java +++ b/src/main/java/dev/openfeature/sdk/NoOpTransactionContextPropagator.java @@ -7,6 +7,7 @@ public class NoOpTransactionContextPropagator implements TransactionContextPropa /** * {@inheritDoc} + * * @return empty immutable context */ @Override diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java index f4d20caf2..cb03c32b1 100644 --- a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java +++ b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java @@ -86,7 +86,7 @@ public Client getClient() { * Multiple clients can be used to segment feature flag configuration. * If there is already a provider bound to this domain, this provider will be used. * Otherwise, the default provider is used until a provider is assigned to that domain. - * + * * @param domain an identifier which logically binds clients with providers * @return a new client instance */ @@ -100,8 +100,8 @@ public Client getClient(String domain) { * Multiple clients can be used to segment feature flag configuration. * If there is already a provider bound to this domain, this provider will be used. * Otherwise, the default provider is used until a provider is assigned to that domain. - * - * @param domain a identifier which logically binds clients with providers + * + * @param domain a identifier which logically binds clients with providers * @param version a version identifier * @return a new client instance */ @@ -193,8 +193,8 @@ public void setProvider(FeatureProvider provider) { /** * Add a provider for a domain. * - * @param domain The domain to bind the provider to. - * @param provider The provider to set. + * @param domain The domain to bind the provider to. + * @param provider The provider to set. */ public void setProvider(String domain, FeatureProvider provider) { try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) { @@ -226,8 +226,8 @@ public void setProviderAndWait(FeatureProvider provider) throws OpenFeatureError /** * Add a provider for a domain and wait for initialization to finish. * - * @param domain The domain to bind the provider to. - * @param provider The provider to set. + * @param domain The domain to bind the provider to. + * @param provider The provider to set. */ public void setProviderAndWait(String domain, FeatureProvider provider) throws OpenFeatureError { try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) { @@ -300,6 +300,7 @@ public void addHooks(Hook... hooks) { /** * Fetch the hooks associated to this client. + * * @return A list of {@link Hook}s. */ public List getHooks() { @@ -404,7 +405,7 @@ void addHandler(String domain, ProviderEvent event, Consumer handl /** * Runs the handlers associated with a particular provider. - * + * * @param provider the provider from where this event originated * @param event the event type * @param details the event details diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java b/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java index d8004e5de..b9e636493 100644 --- a/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java +++ b/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java @@ -20,8 +20,8 @@ * OpenFeature Client implementation. * You should not instantiate this or reference this class. * Use the dev.openfeature.sdk.Client interface instead. + * * @see Client - * * @deprecated // TODO: eventually we will make this non-public. See issue #872 */ @Slf4j @@ -48,8 +48,8 @@ public class OpenFeatureClient implements Client { * @param domain An identifier which logically binds clients with providers (used by observability tools). * @param version Version of the client (used by observability tools). * @deprecated Do not use this constructor. It's for internal use only. - * Clients created using it will not run event handlers. - * Use the OpenFeatureAPI's getClient factory method instead. + * Clients created using it will not run event handlers. + * Use the OpenFeatureAPI's getClient factory method instead. */ @Deprecated() // TODO: eventually we will make this non-public. See issue #872 public OpenFeatureClient(OpenFeatureAPI openFeatureAPI, String domain, String version) { diff --git a/src/main/java/dev/openfeature/sdk/ProviderEventDetails.java b/src/main/java/dev/openfeature/sdk/ProviderEventDetails.java index d28da9e50..c12fda4f0 100644 --- a/src/main/java/dev/openfeature/sdk/ProviderEventDetails.java +++ b/src/main/java/dev/openfeature/sdk/ProviderEventDetails.java @@ -8,7 +8,8 @@ /** * The details of a particular event. */ -@Data @SuperBuilder(toBuilder = true) +@Data +@SuperBuilder(toBuilder = true) public class ProviderEventDetails { private List flagsChanged; private String message; diff --git a/src/main/java/dev/openfeature/sdk/ProviderRepository.java b/src/main/java/dev/openfeature/sdk/ProviderRepository.java index 47b9ecf58..ff670cc1b 100644 --- a/src/main/java/dev/openfeature/sdk/ProviderRepository.java +++ b/src/main/java/dev/openfeature/sdk/ProviderRepository.java @@ -47,8 +47,8 @@ public FeatureProvider getProvider(String domain) { public List getDomainsForProvider(FeatureProvider provider) { return providers.entrySet().stream() - .filter(entry -> entry.getValue().equals(provider)) - .map(entry -> entry.getKey()).collect(Collectors.toList()); + .filter(entry -> entry.getValue().equals(provider)) + .map(entry -> entry.getKey()).collect(Collectors.toList()); } public Set getAllBoundDomains() { @@ -99,12 +99,12 @@ public void setProvider(String domain, } private void prepareAndInitializeProvider(String domain, - FeatureProvider newProvider, - Consumer afterSet, - Consumer afterInit, - Consumer afterShutdown, - BiConsumer afterError, - boolean waitForInit) { + FeatureProvider newProvider, + Consumer afterSet, + Consumer afterInit, + Consumer afterShutdown, + BiConsumer afterError, + boolean waitForInit) { if (!isProviderRegistered(newProvider)) { // only run afterSet if new provider is not already attached @@ -155,6 +155,7 @@ private void shutDownOld(FeatureProvider oldProvider, Consumer /** * Helper to check if provider is already known (registered). + * * @param provider provider to check for registration * @return boolean true if already registered, false otherwise */ diff --git a/src/main/java/dev/openfeature/sdk/ProviderState.java b/src/main/java/dev/openfeature/sdk/ProviderState.java index a66d4e944..f2353d57e 100644 --- a/src/main/java/dev/openfeature/sdk/ProviderState.java +++ b/src/main/java/dev/openfeature/sdk/ProviderState.java @@ -8,7 +8,7 @@ public enum ProviderState { /** * Returns true if the passed ProviderEvent maps to this ProviderState. - * + * * @param event event to compare * @return boolean if matches. */ diff --git a/src/main/java/dev/openfeature/sdk/StringHook.java b/src/main/java/dev/openfeature/sdk/StringHook.java index 898174f61..b16f5e9db 100644 --- a/src/main/java/dev/openfeature/sdk/StringHook.java +++ b/src/main/java/dev/openfeature/sdk/StringHook.java @@ -3,7 +3,7 @@ /** * An extension point which can run around flag resolution. They are intended to be used as a way to add custom logic * to the lifecycle of flag evaluation. - * + * * @see Hook */ public interface StringHook extends Hook { diff --git a/src/main/java/dev/openfeature/sdk/Structure.java b/src/main/java/dev/openfeature/sdk/Structure.java index f3768e958..15749cd4c 100644 --- a/src/main/java/dev/openfeature/sdk/Structure.java +++ b/src/main/java/dev/openfeature/sdk/Structure.java @@ -12,12 +12,12 @@ import static dev.openfeature.sdk.Value.objectToValue; /** - * {@link Structure} represents a potentially nested object type which is used to represent + * {@link Structure} represents a potentially nested object type which is used to represent * structured data. */ @SuppressWarnings("PMD.BeanMembersShouldSerialize") public interface Structure { - + /** * Get all keys. * @@ -103,16 +103,16 @@ default Object convertValue(Value value) { /** * Recursively merges the base map with the overriding map. - * - * @param Structure type + * + * @param Structure type * @param newStructure function to create the right structure - * @param base base map to merge - * @param overriding overriding map to merge + * @param base base map to merge + * @param overriding overriding map to merge * @return resulting merged map */ default Map merge(Function, Structure> newStructure, - Map base, - Map overriding) { + Map base, + Map overriding) { final Map merged = new HashMap<>(base); for (Entry overridingEntry : overriding.entrySet()) { @@ -137,9 +137,9 @@ default Map merge(Function map) { return new MutableStructure(map.entrySet().stream() - .collect(HashMap::new, + .collect(HashMap::new, (accumulated, entry) -> accumulated.put(entry.getKey(), - objectToValue(entry.getValue())), + objectToValue(entry.getValue())), HashMap::putAll)); } } diff --git a/src/main/java/dev/openfeature/sdk/Value.java b/src/main/java/dev/openfeature/sdk/Value.java index f0fdc8d45..5ba9f0dcb 100644 --- a/src/main/java/dev/openfeature/sdk/Value.java +++ b/src/main/java/dev/openfeature/sdk/Value.java @@ -37,33 +37,34 @@ public Value() { /** * Construct a new Value with an Object. + * * @param value to be wrapped. * @throws InstantiationException if value is not a valid type - * (boolean, string, int, double, list, structure, instant) + * (boolean, string, int, double, list, structure, instant) */ public Value(Object value) throws InstantiationException { this.innerObject = value; if (!this.isNull() - && !this.isBoolean() - && !this.isString() - && !this.isNumber() - && !this.isStructure() - && !this.isList() - && !this.isInstant()) { + && !this.isBoolean() + && !this.isString() + && !this.isNumber() + && !this.isStructure() + && !this.isList() + && !this.isInstant()) { throw new InstantiationException("Invalid value type: " + value.getClass()); } } public Value(Value value) { - this.innerObject = value.innerObject; + this.innerObject = value.innerObject; } public Value(Boolean value) { - this.innerObject = value; + this.innerObject = value; } public Value(String value) { - this.innerObject = value; + this.innerObject = value; } public Value(Integer value) { @@ -71,69 +72,69 @@ public Value(Integer value) { } public Value(Double value) { - this.innerObject = value; + this.innerObject = value; } public Value(Structure value) { - this.innerObject = value; + this.innerObject = value; } public Value(List value) { - this.innerObject = value; + this.innerObject = value; } public Value(Instant value) { this.innerObject = value; } - /** + /** * Check if this Value represents null. - * + * * @return boolean */ public boolean isNull() { return this.innerObject == null; } - /** + /** * Check if this Value represents a Boolean. - * + * * @return boolean */ public boolean isBoolean() { return this.innerObject instanceof Boolean; } - /** + /** * Check if this Value represents a String. - * + * * @return boolean */ public boolean isString() { return this.innerObject instanceof String; } - /** + /** * Check if this Value represents a numeric value. - * + * * @return boolean */ public boolean isNumber() { return this.innerObject instanceof Number; } - /** + /** * Check if this Value represents a Structure. - * + * * @return boolean */ public boolean isStructure() { return this.innerObject instanceof Structure; } - - /** + + /** * Check if this Value represents a List of Values. - * + * * @return boolean */ public boolean isList() { @@ -155,87 +156,87 @@ public boolean isList() { return true; } - /** + /** * Check if this Value represents an Instant. - * + * * @return boolean */ public boolean isInstant() { return this.innerObject instanceof Instant; } - - /** + + /** * Retrieve the underlying Boolean value, or null. - * + * * @return Boolean */ @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "NP_BOOLEAN_RETURN_NULL", - justification = "This is not a plain true/false method. It's understood it can return null.") + justification = "This is not a plain true/false method. It's understood it can return null.") public Boolean asBoolean() { if (this.isBoolean()) { - return (Boolean)this.innerObject; + return (Boolean) this.innerObject; } return null; } - - /** + + /** * Retrieve the underlying object. - * + * * @return Object */ public Object asObject() { return this.innerObject; } - /** + /** * Retrieve the underlying String value, or null. - * + * * @return String */ public String asString() { if (this.isString()) { - return (String)this.innerObject; + return (String) this.innerObject; } return null; } - /** + /** * Retrieve the underlying numeric value as an Integer, or null. * If the value is not an integer, it will be rounded using Math.round(). - * + * * @return Integer */ public Integer asInteger() { if (this.isNumber() && !this.isNull()) { - return ((Number)this.innerObject).intValue(); + return ((Number) this.innerObject).intValue(); } return null; } - - /** + + /** * Retrieve the underlying numeric value as a Double, or null. - * + * * @return Double */ public Double asDouble() { if (this.isNumber() && !isNull()) { - return ((Number)this.innerObject).doubleValue(); + return ((Number) this.innerObject).doubleValue(); } return null; } - /** + /** * Retrieve the underlying Structure value, or null. - * + * * @return Structure */ public Structure asStructure() { if (this.isStructure()) { - return (Structure)this.innerObject; + return (Structure) this.innerObject; } return null; } - + /** * Retrieve the underlying List value, or null. * @@ -249,14 +250,14 @@ public List asList() { return null; } - /** + /** * Retrieve the underlying Instant value, or null. - * + * * @return Instant */ public Instant asInstant() { if (this.isInstant()) { - return (Instant)this.innerObject; + return (Instant) this.innerObject; } return null; } @@ -306,8 +307,8 @@ public static Value objectToValue(Object object) { return new Value((Structure) object); } else if (object instanceof List) { return new Value(((List) object).stream() - .map(o -> objectToValue(o)) - .collect(Collectors.toList())); + .map(o -> objectToValue(o)) + .collect(Collectors.toList())); } else if (object instanceof Instant) { return new Value((Instant) object); } else if (object instanceof Map) { diff --git a/src/main/java/dev/openfeature/sdk/exceptions/ExceptionUtils.java b/src/main/java/dev/openfeature/sdk/exceptions/ExceptionUtils.java index 28c7cd716..f44dcea24 100644 --- a/src/main/java/dev/openfeature/sdk/exceptions/ExceptionUtils.java +++ b/src/main/java/dev/openfeature/sdk/exceptions/ExceptionUtils.java @@ -9,7 +9,8 @@ public class ExceptionUtils { /** * Creates an Error for the specific error code. - * @param errorCode the ErrorCode to use + * + * @param errorCode the ErrorCode to use * @param errorMessage the error message to include in the returned error * @return the specific OpenFeatureError for the errorCode */ diff --git a/src/main/java/dev/openfeature/sdk/exceptions/FlagNotFoundError.java b/src/main/java/dev/openfeature/sdk/exceptions/FlagNotFoundError.java index 6685f96d5..a30adc09f 100644 --- a/src/main/java/dev/openfeature/sdk/exceptions/FlagNotFoundError.java +++ b/src/main/java/dev/openfeature/sdk/exceptions/FlagNotFoundError.java @@ -8,7 +8,8 @@ @StandardException public class FlagNotFoundError extends OpenFeatureError { private static final long serialVersionUID = 1L; - @Getter private final ErrorCode errorCode = ErrorCode.FLAG_NOT_FOUND; + @Getter + private final ErrorCode errorCode = ErrorCode.FLAG_NOT_FOUND; @Override public synchronized Throwable fillInStackTrace() { diff --git a/src/main/java/dev/openfeature/sdk/exceptions/InvalidContextError.java b/src/main/java/dev/openfeature/sdk/exceptions/InvalidContextError.java index e70c3efe2..7f604ac69 100644 --- a/src/main/java/dev/openfeature/sdk/exceptions/InvalidContextError.java +++ b/src/main/java/dev/openfeature/sdk/exceptions/InvalidContextError.java @@ -11,6 +11,7 @@ public class InvalidContextError extends OpenFeatureError { private static final long serialVersionUID = 1L; - @Getter private final ErrorCode errorCode = ErrorCode.INVALID_CONTEXT; + @Getter + private final ErrorCode errorCode = ErrorCode.INVALID_CONTEXT; } diff --git a/src/main/java/dev/openfeature/sdk/exceptions/ParseError.java b/src/main/java/dev/openfeature/sdk/exceptions/ParseError.java index ac8fca877..29f65018a 100644 --- a/src/main/java/dev/openfeature/sdk/exceptions/ParseError.java +++ b/src/main/java/dev/openfeature/sdk/exceptions/ParseError.java @@ -11,6 +11,7 @@ public class ParseError extends OpenFeatureError { private static final long serialVersionUID = 1L; - @Getter private final ErrorCode errorCode = ErrorCode.PARSE_ERROR; + @Getter + private final ErrorCode errorCode = ErrorCode.PARSE_ERROR; } diff --git a/src/main/java/dev/openfeature/sdk/exceptions/ProviderNotReadyError.java b/src/main/java/dev/openfeature/sdk/exceptions/ProviderNotReadyError.java index 218073441..53e4a0f70 100644 --- a/src/main/java/dev/openfeature/sdk/exceptions/ProviderNotReadyError.java +++ b/src/main/java/dev/openfeature/sdk/exceptions/ProviderNotReadyError.java @@ -8,5 +8,6 @@ @StandardException public class ProviderNotReadyError extends OpenFeatureError { private static final long serialVersionUID = 1L; - @Getter private final ErrorCode errorCode = ErrorCode.PROVIDER_NOT_READY; + @Getter + private final ErrorCode errorCode = ErrorCode.PROVIDER_NOT_READY; } diff --git a/src/main/java/dev/openfeature/sdk/exceptions/TargetingKeyMissingError.java b/src/main/java/dev/openfeature/sdk/exceptions/TargetingKeyMissingError.java index 12437dc7e..23cc9bea8 100644 --- a/src/main/java/dev/openfeature/sdk/exceptions/TargetingKeyMissingError.java +++ b/src/main/java/dev/openfeature/sdk/exceptions/TargetingKeyMissingError.java @@ -11,6 +11,7 @@ public class TargetingKeyMissingError extends OpenFeatureError { private static final long serialVersionUID = 1L; - @Getter private final ErrorCode errorCode = ErrorCode.TARGETING_KEY_MISSING; + @Getter + private final ErrorCode errorCode = ErrorCode.TARGETING_KEY_MISSING; } diff --git a/src/main/java/dev/openfeature/sdk/exceptions/TypeMismatchError.java b/src/main/java/dev/openfeature/sdk/exceptions/TypeMismatchError.java index d27c6209f..57d4e16ce 100644 --- a/src/main/java/dev/openfeature/sdk/exceptions/TypeMismatchError.java +++ b/src/main/java/dev/openfeature/sdk/exceptions/TypeMismatchError.java @@ -11,6 +11,7 @@ public class TypeMismatchError extends OpenFeatureError { private static final long serialVersionUID = 1L; - @Getter private final ErrorCode errorCode = ErrorCode.TYPE_MISMATCH; + @Getter + private final ErrorCode errorCode = ErrorCode.TYPE_MISMATCH; } diff --git a/src/main/java/dev/openfeature/sdk/hooks/logging/LoggingHook.java b/src/main/java/dev/openfeature/sdk/hooks/logging/LoggingHook.java index 716168f06..a396ca0b8 100644 --- a/src/main/java/dev/openfeature/sdk/hooks/logging/LoggingHook.java +++ b/src/main/java/dev/openfeature/sdk/hooks/logging/LoggingHook.java @@ -18,7 +18,7 @@ */ @Slf4j @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "RV_RETURN_VALUE_IGNORED", - justification = "we can ignore return values of chainables (builders) here") + justification = "we can ignore return values of chainables (builders) here") public class LoggingHook implements Hook { static final String DOMAIN_KEY = "domain"; @@ -32,7 +32,7 @@ public class LoggingHook implements Hook { static final String VARIANT_KEY = "variant"; static final String VALUE_KEY = "value"; - private boolean includeEvaluationContext; + private final boolean includeEvaluationContext; /** * Construct a new LoggingHook. @@ -43,7 +43,9 @@ public LoggingHook() { /** * Construct a new LoggingHook. - * @param includeEvaluationContext include a serialized evaluation context in the log message (defaults to false) + * + * @param includeEvaluationContext include a serialized evaluation context in the log message (defaults to + * false) */ public LoggingHook(boolean includeEvaluationContext) { this.includeEvaluationContext = includeEvaluationContext; diff --git a/src/main/java/dev/openfeature/sdk/internal/AutoCloseableLock.java b/src/main/java/dev/openfeature/sdk/internal/AutoCloseableLock.java index bf2f30426..2569aaf30 100644 --- a/src/main/java/dev/openfeature/sdk/internal/AutoCloseableLock.java +++ b/src/main/java/dev/openfeature/sdk/internal/AutoCloseableLock.java @@ -2,7 +2,7 @@ @SuppressWarnings("checkstyle:MissingJavadocType") public interface AutoCloseableLock extends AutoCloseable { - + /** * Override the exception in AutoClosable. */ diff --git a/src/main/java/dev/openfeature/sdk/internal/AutoCloseableReentrantReadWriteLock.java b/src/main/java/dev/openfeature/sdk/internal/AutoCloseableReentrantReadWriteLock.java index 92827ef68..1e94e3aed 100644 --- a/src/main/java/dev/openfeature/sdk/internal/AutoCloseableReentrantReadWriteLock.java +++ b/src/main/java/dev/openfeature/sdk/internal/AutoCloseableReentrantReadWriteLock.java @@ -10,6 +10,7 @@ public class AutoCloseableReentrantReadWriteLock extends ReentrantReadWriteLock /** * Get the single write lock as an AutoCloseableLock. + * * @return unlock method ref */ public AutoCloseableLock writeLockAutoCloseable() { @@ -19,10 +20,11 @@ public AutoCloseableLock writeLockAutoCloseable() { /** * Get the multi read lock as an AutoCloseableLock. + * * @return unlock method ref */ public AutoCloseableLock readLockAutoCloseable() { this.readLock().lock(); return this.readLock()::unlock; } -} \ No newline at end of file +} diff --git a/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java b/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java index 34caadaea..67f8367c1 100644 --- a/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java +++ b/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java @@ -15,9 +15,10 @@ public class ObjectUtils { /** * If the source param is null, return the default value. - * @param source maybe null object + * + * @param source maybe null object * @param defaultValue thing to use if source is null - * @param list type + * @param list type * @return resulting object */ public static List defaultIfNull(List source, Supplier> defaultValue) { @@ -29,10 +30,11 @@ public static List defaultIfNull(List source, Supplier> defaul /** * If the source param is null, return the default value. - * @param source maybe null object + * + * @param source maybe null object * @param defaultValue thing to use if source is null - * @param map key type - * @param map value type + * @param map key type + * @param map value type * @return resulting map */ public static Map defaultIfNull(Map source, Supplier> defaultValue) { @@ -44,9 +46,10 @@ public static Map defaultIfNull(Map source, Supplier type + * @param type * @return resulting object */ public static T defaultIfNull(T source, Supplier defaultValue) { @@ -58,15 +61,16 @@ public static T defaultIfNull(T source, Supplier defaultValue) { /** * Concatenate a bunch of lists. + * * @param sources bunch of lists. - * @param list type + * @param list type * @return resulting object */ @SafeVarargs public static List merge(List... sources) { return Arrays - .stream(sources) - .flatMap(Collection::stream) - .collect(Collectors.toList()); + .stream(sources) + .flatMap(Collection::stream) + .collect(Collectors.toList()); } } diff --git a/src/main/java/dev/openfeature/sdk/internal/TriConsumer.java b/src/main/java/dev/openfeature/sdk/internal/TriConsumer.java index 723f4aeb4..831307800 100644 --- a/src/main/java/dev/openfeature/sdk/internal/TriConsumer.java +++ b/src/main/java/dev/openfeature/sdk/internal/TriConsumer.java @@ -4,7 +4,7 @@ /** * Like {@link java.util.function.BiConsumer} but with 3 params. - * + * * @see java.util.function.BiConsumer */ @FunctionalInterface @@ -35,4 +35,4 @@ default TriConsumer andThen(TriConsumer after) { after.accept(t, u, v); }; } -} \ No newline at end of file +} diff --git a/src/main/java/dev/openfeature/sdk/providers/memory/ContextEvaluator.java b/src/main/java/dev/openfeature/sdk/providers/memory/ContextEvaluator.java index 02fa323c2..715868be6 100644 --- a/src/main/java/dev/openfeature/sdk/providers/memory/ContextEvaluator.java +++ b/src/main/java/dev/openfeature/sdk/providers/memory/ContextEvaluator.java @@ -4,6 +4,7 @@ /** * Context evaluator - use for resolving flag according to evaluation context, for handling targeting. + * * @param expected value type */ public interface ContextEvaluator { diff --git a/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java b/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java index 5b6d28702..e3df24528 100644 --- a/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java +++ b/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java @@ -49,6 +49,7 @@ public InMemoryProvider(Map> flags) { /** * Initializes the provider. + * * @param evaluationContext evaluation context * @throws Exception on error */ @@ -63,6 +64,7 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { * Updates the provider flags configuration. * For existing flags, the new configurations replace the old one. * For new flags, they are added to the configuration. + * * @param newFlags the new flag configurations */ public void updateFlags(Map> newFlags) { @@ -70,9 +72,9 @@ public void updateFlags(Map> newFlags) { this.flags.putAll(newFlags); ProviderEventDetails details = ProviderEventDetails.builder() - .flagsChanged(new ArrayList<>(flagsChanged)) - .message("flags changed") - .build(); + .flagsChanged(new ArrayList<>(flagsChanged)) + .message("flags changed") + .build(); emitProviderConfigurationChanged(details); } @@ -80,14 +82,15 @@ public void updateFlags(Map> newFlags) { * Updates a single provider flag configuration. * For existing flag, the new configuration replaces the old one. * For new flag, they are added to the configuration. + * * @param newFlag the flag to update */ public void updateFlag(String flagKey, Flag newFlag) { this.flags.put(flagKey, newFlag); ProviderEventDetails details = ProviderEventDetails.builder() - .flagsChanged(Collections.singletonList(flagKey)) - .message("flag added/updated") - .build(); + .flagsChanged(Collections.singletonList(flagKey)) + .message("flag added/updated") + .build(); emitProviderConfigurationChanged(details); } @@ -144,10 +147,10 @@ private ProviderEvaluation getEvaluation( value = (T) flag.getVariants().get(flag.getDefaultVariant()); } return ProviderEvaluation.builder() - .value(value) - .variant(flag.getDefaultVariant()) - .reason(Reason.STATIC.toString()) - .build(); + .value(value) + .variant(flag.getDefaultVariant()) + .reason(Reason.STATIC.toString()) + .build(); } } diff --git a/src/test/java/dev/openfeature/sdk/DeveloperExperienceTest.java b/src/test/java/dev/openfeature/sdk/DeveloperExperienceTest.java index b5e5bedf3..3eaeda8e6 100644 --- a/src/test/java/dev/openfeature/sdk/DeveloperExperienceTest.java +++ b/src/test/java/dev/openfeature/sdk/DeveloperExperienceTest.java @@ -20,7 +20,8 @@ class DeveloperExperienceTest implements HookFixtures { transient String flagKey = "mykey"; - @Test void simpleBooleanFlag() { + @Test + void simpleBooleanFlag() { OpenFeatureAPI api = OpenFeatureAPI.getInstance(); api.setProvider(new NoOpProvider()); Client client = api.getClient(); @@ -28,7 +29,8 @@ class DeveloperExperienceTest implements HookFixtures { assertFalse(retval); } - @Test void clientHooks() { + @Test + void clientHooks() { Hook exampleHook = mockBooleanHook(); OpenFeatureAPI api = OpenFeatureAPI.getInstance(); @@ -40,7 +42,8 @@ class DeveloperExperienceTest implements HookFixtures { assertFalse(retval); } - @Test void evalHooks() { + @Test + void evalHooks() { Hook clientHook = mockBooleanHook(); Hook evalHook = mockBooleanHook(); @@ -59,7 +62,8 @@ class DeveloperExperienceTest implements HookFixtures { * As an application author, you probably know special things about your users. You can communicate these to the * provider via {@link MutableContext} */ - @Test void providingContext() { + @Test + void providingContext() { OpenFeatureAPI api = OpenFeatureAPI.getInstance(); api.setProvider(new NoOpProvider()); @@ -76,7 +80,8 @@ class DeveloperExperienceTest implements HookFixtures { assertFalse(retval); } - @Test void brokenProvider() { + @Test + void brokenProvider() { OpenFeatureAPI api = OpenFeatureAPI.getInstance(); FeatureProviderTestUtils.setFeatureProvider(new AlwaysBrokenProvider()); Client client = api.getClient(); @@ -99,7 +104,7 @@ public Optional before(HookContext ctx, Map hints) { return Optional.empty(); } } - + final String defaultValue = "string-value"; final OpenFeatureAPI api = OpenFeatureAPI.getInstance(); final Client client = api.getClient(); @@ -111,7 +116,7 @@ public Optional before(HookContext ctx, Map hints) { assertEquals(new StringBuilder(defaultValue).reverse().toString(), doSomethingValue); api.clearHooks(); - + // subsequent evaluations should now use new provider set by hook String noOpValue = client.getStringValue("val", defaultValue); assertEquals(noOpValue, defaultValue); diff --git a/src/test/java/dev/openfeature/sdk/DoSomethingProvider.java b/src/test/java/dev/openfeature/sdk/DoSomethingProvider.java index 322934469..cd5be8537 100644 --- a/src/test/java/dev/openfeature/sdk/DoSomethingProvider.java +++ b/src/test/java/dev/openfeature/sdk/DoSomethingProvider.java @@ -5,7 +5,7 @@ class DoSomethingProvider implements FeatureProvider { static final String name = "Something"; // Flag evaluation metadata static final ImmutableMetadata DEFAULT_METADATA = ImmutableMetadata.builder().build(); - private ImmutableMetadata flagMetadata; + private final ImmutableMetadata flagMetadata; public DoSomethingProvider() { this.flagMetadata = DEFAULT_METADATA; @@ -53,7 +53,8 @@ public ProviderEvaluation getDoubleEvaluation(String key, Double default } @Override - public ProviderEvaluation getObjectEvaluation(String key, Value defaultValue, EvaluationContext invocationContext) { + public ProviderEvaluation getObjectEvaluation(String key, Value defaultValue, + EvaluationContext invocationContext) { return ProviderEvaluation.builder() .value(null) .flagMetadata(flagMetadata) diff --git a/src/test/java/dev/openfeature/sdk/EvalContextTest.java b/src/test/java/dev/openfeature/sdk/EvalContextTest.java index c7f3aa44d..d79dc9b9b 100644 --- a/src/test/java/dev/openfeature/sdk/EvalContextTest.java +++ b/src/test/java/dev/openfeature/sdk/EvalContextTest.java @@ -11,20 +11,23 @@ import static dev.openfeature.sdk.EvaluationContext.TARGETING_KEY; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class EvalContextTest { - @Specification(number="3.1.1", - text="The `evaluation context` structure **MUST** define an optional `targeting key` field of " + + @Specification(number = "3.1.1", + text = "The `evaluation context` structure **MUST** define an optional `targeting key` field of " + "type string, identifying the subject of the flag evaluation.") - @Test void requires_targeting_key() { + @Test + void requires_targeting_key() { EvaluationContext ec = new ImmutableContext("targeting-key", new HashMap<>()); assertEquals("targeting-key", ec.getTargetingKey()); } - @Specification(number="3.1.2", text= "The evaluation context MUST support the inclusion of " + + @Specification(number = "3.1.2", text = "The evaluation context MUST support the inclusion of " + "custom fields, having keys of type `string`, and " + "values of type `boolean | string | number | datetime | structure`.") - @Test void eval_context() { + @Test + void eval_context() { Map attributes = new HashMap<>(); Instant dt = Instant.now().truncatedTo(ChronoUnit.MILLIS); attributes.put("str", new Value("test")); @@ -42,13 +45,14 @@ public class EvalContextTest { assertEquals(dt, ec.getValue("dt").asInstant().truncatedTo(ChronoUnit.MILLIS)); } - @Specification(number="3.1.2", text="The evaluation context MUST support the inclusion of " + + @Specification(number = "3.1.2", text = "The evaluation context MUST support the inclusion of " + "custom fields, having keys of type `string`, and " + "values of type `boolean | string | number | datetime | structure`.") - @Test void eval_context_structure_array() { + @Test + void eval_context_structure_array() { Map attributes = new HashMap<>(); attributes.put("obj", new Value(new MutableStructure().add("val1", 1).add("val2", "2"))); - List values = new ArrayList(){{ + List values = new ArrayList() {{ add(new Value("one")); add(new Value("two")); }}; @@ -64,9 +68,10 @@ public class EvalContextTest { assertEquals("two", arr.get(1).asString()); } - @Specification(number="3.1.3", text="The evaluation context MUST support fetching the custom fields by key and also fetching all key value pairs.") - @Test void fetch_all() { - Map attributes = new HashMap<>(); + @Specification(number = "3.1.3", text = "The evaluation context MUST support fetching the custom fields by key and also fetching all key value pairs.") + @Test + void fetch_all() { + Map attributes = new HashMap<>(); Instant dt = Instant.now(); MutableStructure mutableStructure = new MutableStructure().add("val1", 1).add("val2", "2"); attributes.put("str", new Value("test")); @@ -96,28 +101,31 @@ public class EvalContextTest { assertEquals("2", foundObj.getValue("val2").asString()); } - @Specification(number="3.1.4", text="The evaluation context fields MUST have an unique key.") - @Test void unique_key_across_types() { + @Specification(number = "3.1.4", text = "The evaluation context fields MUST have an unique key.") + @Test + void unique_key_across_types() { MutableContext ec = new MutableContext(); ec.add("key", "val"); ec.add("key", "val2"); assertEquals("val2", ec.getValue("key").asString()); ec.add("key", 3); - assertEquals(null, ec.getValue("key").asString()); + assertNull(ec.getValue("key").asString()); assertEquals(3, ec.getValue("key").asInteger()); } - @Test void unique_key_across_types_immutableContext() { - HashMap attributes = new HashMap<>(); + @Test + void unique_key_across_types_immutableContext() { + HashMap attributes = new HashMap<>(); attributes.put("key", new Value("val")); attributes.put("key", new Value("val2")); attributes.put("key", new Value(3)); EvaluationContext ec = new ImmutableContext(attributes); - assertEquals(null, ec.getValue("key").asString()); + assertNull(ec.getValue("key").asString()); assertEquals(3, ec.getValue("key").asInteger()); } - @Test void can_chain_attribute_addition() { + @Test + void can_chain_attribute_addition() { MutableContext ec = new MutableContext(); MutableContext out = ec.add("str", "test") .add("int", 4) @@ -126,24 +134,26 @@ public class EvalContextTest { assertEquals(MutableContext.class, out.getClass()); } - @Test void can_add_key_with_null() { + @Test + void can_add_key_with_null() { MutableContext ec = new MutableContext() - .add("Boolean", (Boolean)null) - .add("String", (String)null) - .add("Double", (Double)null) - .add("Structure", (MutableStructure)null) - .add("List", (List)null) - .add("Instant", (Instant)null); + .add("Boolean", (Boolean) null) + .add("String", (String) null) + .add("Double", (Double) null) + .add("Structure", (MutableStructure) null) + .add("List", (List) null) + .add("Instant", (Instant) null); assertEquals(6, ec.asMap().size()); - assertEquals(null, ec.getValue("Boolean").asBoolean()); - assertEquals(null, ec.getValue("String").asString()); - assertEquals(null, ec.getValue("Double").asDouble()); - assertEquals(null, ec.getValue("Structure").asStructure()); - assertEquals(null, ec.getValue("List").asList()); - assertEquals(null, ec.getValue("Instant").asString()); + assertNull(ec.getValue("Boolean").asBoolean()); + assertNull(ec.getValue("String").asString()); + assertNull(ec.getValue("Double").asDouble()); + assertNull(ec.getValue("Structure").asStructure()); + assertNull(ec.getValue("List").asList()); + assertNull(ec.getValue("Instant").asString()); } - @Test void Immutable_context_merge_targeting_key() { + @Test + void Immutable_context_merge_targeting_key() { String key1 = "key1"; EvaluationContext ctx1 = new ImmutableContext(key1, new HashMap<>()); EvaluationContext ctx2 = new ImmutableContext(new HashMap<>()); @@ -156,19 +166,21 @@ public class EvalContextTest { ctxMerged = ctx1.merge(ctx2); assertEquals(key2, ctxMerged.getTargetingKey()); - ctx2 = new ImmutableContext(" ",new HashMap<>()); + ctx2 = new ImmutableContext(" ", new HashMap<>()); ctxMerged = ctx1.merge(ctx2); assertEquals(key1, ctxMerged.getTargetingKey()); } - @Test void merge_null_returns_value() { + @Test + void merge_null_returns_value() { MutableContext ctx1 = new MutableContext("key"); ctx1.add("mything", "value"); EvaluationContext result = ctx1.merge(null); assertEquals(ctx1, result); } - @Test void merge_targeting_key() { + @Test + void merge_targeting_key() { String key1 = "key1"; MutableContext ctx1 = new MutableContext(key1); MutableContext ctx2 = new MutableContext(); @@ -186,14 +198,15 @@ public class EvalContextTest { assertEquals(key2, ctxMerged.getTargetingKey()); } - @Test void asObjectMap() { + @Test + void asObjectMap() { String key1 = "key1"; MutableContext ctx = new MutableContext(key1); ctx.add("stringItem", "stringValue"); ctx.add("boolItem", false); ctx.add("integerItem", 1); ctx.add("doubleItem", 1.2); - ctx.add("instantItem", Instant.ofEpochSecond(1663331342)); + ctx.add("instantItem", Instant.ofEpochSecond(1663331342)); List listItem = new ArrayList<>(); listItem.add(new Value("item1")); listItem.add(new Value("item2")); @@ -207,18 +220,17 @@ public class EvalContextTest { structureValue.put("structBoolItem", new Value(false)); structureValue.put("structIntegerItem", new Value(1)); structureValue.put("structDoubleItem", new Value(1.2)); - structureValue.put("structInstantItem", new Value(Instant.ofEpochSecond(1663331342))); + structureValue.put("structInstantItem", new Value(Instant.ofEpochSecond(1663331342))); Structure structure = new MutableStructure(structureValue); ctx.add("structureItem", structure); - Map want = new HashMap<>(); want.put(TARGETING_KEY, key1); want.put("stringItem", "stringValue"); want.put("boolItem", false); want.put("integerItem", 1); want.put("doubleItem", 1.2); - want.put("instantItem", Instant.ofEpochSecond(1663331342)); + want.put("instantItem", Instant.ofEpochSecond(1663331342)); List wantListItem = new ArrayList<>(); wantListItem.add("item1"); wantListItem.add("item2"); @@ -232,9 +244,9 @@ public class EvalContextTest { wantStructureValue.put("structBoolItem", false); wantStructureValue.put("structIntegerItem", 1); wantStructureValue.put("structDoubleItem", 1.2); - wantStructureValue.put("structInstantItem", Instant.ofEpochSecond(1663331342)); - want.put("structureItem",wantStructureValue); + wantStructureValue.put("structInstantItem", Instant.ofEpochSecond(1663331342)); + want.put("structureItem", wantStructureValue); - assertEquals(want,ctx.asObjectMap()); + assertEquals(want, ctx.asObjectMap()); } } diff --git a/src/test/java/dev/openfeature/sdk/EventProviderTest.java b/src/test/java/dev/openfeature/sdk/EventProviderTest.java index a5be8589c..3ce1efc9f 100644 --- a/src/test/java/dev/openfeature/sdk/EventProviderTest.java +++ b/src/test/java/dev/openfeature/sdk/EventProviderTest.java @@ -127,6 +127,6 @@ public ProviderState getState() { @SuppressWarnings("unchecked") private TriConsumer mockOnEmit() { - return (TriConsumer)mock(TriConsumer.class); + return (TriConsumer) mock(TriConsumer.class); } -} \ No newline at end of file +} diff --git a/src/test/java/dev/openfeature/sdk/EventsTest.java b/src/test/java/dev/openfeature/sdk/EventsTest.java index 6b70617f6..de53069f6 100644 --- a/src/test/java/dev/openfeature/sdk/EventsTest.java +++ b/src/test/java/dev/openfeature/sdk/EventsTest.java @@ -11,6 +11,7 @@ import static org.mockito.Mockito.verify; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; @@ -99,12 +100,14 @@ void apiShouldPropagateEvents() { @Test @DisplayName("should support all event types") - @Specification(number = "5.1.1", text = "The provider MAY define a mechanism for signaling the occurrence " - + "of one of a set of events, including PROVIDER_READY, PROVIDER_ERROR, " - + "PROVIDER_CONFIGURATION_CHANGED and PROVIDER_STALE, with a provider event details payload.") - @Specification(number = "5.2.2", text = "The API MUST provide a function for associating handler functions" - + - " with a particular provider event type.") + @Specification(number = "5.1.1", text = + "The provider MAY define a mechanism for signaling the occurrence " + + "of one of a set of events, including PROVIDER_READY, PROVIDER_ERROR, " + + "PROVIDER_CONFIGURATION_CHANGED and PROVIDER_STALE, with a provider event details payload.") + @Specification(number = "5.2.2", text = + "The API MUST provide a function for associating handler functions" + + + " with a particular provider event type.") void apiShouldSupportAllEventTypes() { final String name = "apiShouldSupportAllEventTypes"; final Consumer handler1 = mockHandler(); @@ -303,9 +306,10 @@ void shouldPropagateAfter() { @Specification(number = "5.1.1", text = "The provider MAY define a mechanism for signaling the occurrence " + "of one of a set of events, including PROVIDER_READY, PROVIDER_ERROR, " + "PROVIDER_CONFIGURATION_CHANGED and PROVIDER_STALE, with a provider event details payload.") - @Specification(number = "5.2.1", text = "The client MUST provide a function for associating handler functions" - + - " with a particular provider event type.") + @Specification(number = "5.2.1", text = + "The client MUST provide a function for associating handler functions" + + + " with a particular provider event type.") void shouldSupportAllEventTypes() { final String name = "shouldSupportAllEventTypes"; final Consumer handler1 = mockHandler(); @@ -337,7 +341,7 @@ void shouldSupportAllEventTypes() { @Test @DisplayName("shutdown provider should not run handlers") - void shouldNotRunHandlers() { + void shouldNotRunHandlers() { final Consumer handler1 = mockHandler(); final Consumer handler2 = mockHandler(); final String name = "shouldNotRunHandlers"; @@ -484,7 +488,7 @@ void shouldHaveAllProperties() { OpenFeatureAPI.getInstance().onProviderConfigurationChanged(handler1); client.onProviderConfigurationChanged(handler2); - List flagsChanged = Arrays.asList("flag"); + List flagsChanged = Collections.singletonList("flag"); ImmutableMetadata metadata = ImmutableMetadata.builder().addInteger("int", 1).build(); String message = "a message"; ProviderEventDetails details = ProviderEventDetails.builder() @@ -594,7 +598,7 @@ void mustPersistAcrossChanges() { @Nested class HandlerRemoval { - @Specification(number="5.2.7", text="The API and client MUST provide a function allowing the removal of event handlers.") + @Specification(number = "5.2.7", text = "The API and client MUST provide a function allowing the removal of event handlers.") @Test @DisplayName("should not run removed events") void removedEventsShouldNotRun() { diff --git a/src/test/java/dev/openfeature/sdk/FlagEvaluationDetailsTest.java b/src/test/java/dev/openfeature/sdk/FlagEvaluationDetailsTest.java index dfa77274e..a4897d25b 100644 --- a/src/test/java/dev/openfeature/sdk/FlagEvaluationDetailsTest.java +++ b/src/test/java/dev/openfeature/sdk/FlagEvaluationDetailsTest.java @@ -29,13 +29,13 @@ public void sevenArgConstructor() { ImmutableMetadata metadata = ImmutableMetadata.builder().build(); FlagEvaluationDetails details = new FlagEvaluationDetails<>( - flagKey, - value, - variant, - reason.toString(), - errorCode, - errorMessage, - metadata); + flagKey, + value, + variant, + reason.toString(), + errorCode, + errorMessage, + metadata); assertEquals(flagKey, details.getFlagKey()); assertEquals(value, details.getValue()); @@ -48,13 +48,13 @@ public void sevenArgConstructor() { @Test @DisplayName("should be able to compare 2 FlagEvaluationDetails") - public void compareFlagEvaluationDetails(){ + public void compareFlagEvaluationDetails() { FlagEvaluationDetails fed1 = FlagEvaluationDetails.builder() .reason(Reason.ERROR.toString()) .value(false) .errorCode(ErrorCode.GENERAL) .errorMessage("error XXX") - .flagMetadata(ImmutableMetadata.builder().addString("metadata","1").build()) + .flagMetadata(ImmutableMetadata.builder().addString("metadata", "1").build()) .build(); FlagEvaluationDetails fed2 = FlagEvaluationDetails.builder() @@ -62,9 +62,9 @@ public void compareFlagEvaluationDetails(){ .value(false) .errorCode(ErrorCode.GENERAL) .errorMessage("error XXX") - .flagMetadata(ImmutableMetadata.builder().addString("metadata","1").build()) + .flagMetadata(ImmutableMetadata.builder().addString("metadata", "1").build()) .build(); - assertEquals(fed1,fed2); + assertEquals(fed1, fed2); } } diff --git a/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java b/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java index b4978cb4b..0241cc3e7 100644 --- a/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java +++ b/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java @@ -52,34 +52,40 @@ void getApiInstance() { api = OpenFeatureAPI.getInstance(); } - @AfterEach void reset_ctx() { + @AfterEach + void reset_ctx() { api.setEvaluationContext(null); } - @BeforeEach void set_logger() { + @BeforeEach + void set_logger() { logger = Mockito.mock(Logger.class); LoggerMock.setMock(OpenFeatureClient.class, logger); } - @AfterEach void reset_logs() { + @AfterEach + void reset_logs() { LoggerMock.setMock(OpenFeatureClient.class, logger); } - @Specification(number="1.1.1", text="The API, and any state it maintains SHOULD exist as a global singleton, even in cases wherein multiple versions of the API are present at runtime.") - @Test void global_singleton() { + @Specification(number = "1.1.1", text = "The API, and any state it maintains SHOULD exist as a global singleton, even in cases wherein multiple versions of the API are present at runtime.") + @Test + void global_singleton() { assertSame(OpenFeatureAPI.getInstance(), OpenFeatureAPI.getInstance()); } - @Specification(number="1.1.2.1", text="The API MUST define a provider mutator, a function to set the default provider, which accepts an API-conformant provider implementation.") - @Test void provider() { + @Specification(number = "1.1.2.1", text = "The API MUST define a provider mutator, a function to set the default provider, which accepts an API-conformant provider implementation.") + @Test + void provider() { FeatureProvider mockProvider = mock(FeatureProvider.class); FeatureProviderTestUtils.setFeatureProvider(mockProvider); assertThat(api.getProvider()).isEqualTo(mockProvider); } @SneakyThrows - @Specification(number="1.1.8", text="The API SHOULD provide functions to set a provider and wait for the initialize function to return or throw.") - @Test void providerAndWait() { + @Specification(number = "1.1.8", text = "The API SHOULD provide functions to set a provider and wait for the initialize function to return or throw.") + @Test + void providerAndWait() { FeatureProvider provider = new TestEventsProvider(500); OpenFeatureAPI.getInstance().setProviderAndWait(provider); assertThat(api.getProvider().getState()).isEqualTo(ProviderState.READY); @@ -91,8 +97,9 @@ void getApiInstance() { } @SneakyThrows - @Specification(number="1.1.8", text="The API SHOULD provide functions to set a provider and wait for the initialize function to return or throw.") - @Test void providerAndWaitError() { + @Specification(number = "1.1.8", text = "The API SHOULD provide functions to set a provider and wait for the initialize function to return or throw.") + @Test + void providerAndWaitError() { FeatureProvider provider1 = new TestEventsProvider(500, true, "fake error"); assertThrows(GeneralError.class, () -> api.setProviderAndWait(provider1)); @@ -101,8 +108,9 @@ void getApiInstance() { assertThrows(GeneralError.class, () -> api.setProviderAndWait(providerName, provider2)); } - @Specification(number="2.4.5", text="The provider SHOULD indicate an error if flag resolution is attempted before the provider is ready.") - @Test void shouldReturnNotReadyIfNotInitialized() { + @Specification(number = "2.4.5", text = "The provider SHOULD indicate an error if flag resolution is attempted before the provider is ready.") + @Test + void shouldReturnNotReadyIfNotInitialized() { FeatureProvider provider = new InMemoryProvider(new HashMap<>()) { @Override public void initialize(EvaluationContext evaluationContext) throws Exception { @@ -113,17 +121,20 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { OpenFeatureAPI.getInstance().setProvider(providerName, provider); assertThat(api.getProvider(providerName).getState()).isEqualTo(ProviderState.NOT_READY); Client client = OpenFeatureAPI.getInstance().getClient(providerName); - assertEquals(ErrorCode.PROVIDER_NOT_READY, client.getBooleanDetails("return_error_when_not_initialized", false).getErrorCode()); + assertEquals(ErrorCode.PROVIDER_NOT_READY, + client.getBooleanDetails("return_error_when_not_initialized", false).getErrorCode()); } - @Specification(number="1.1.5", text="The API MUST provide a function for retrieving the metadata field of the configured provider.") - @Test void provider_metadata() { + @Specification(number = "1.1.5", text = "The API MUST provide a function for retrieving the metadata field of the configured provider.") + @Test + void provider_metadata() { FeatureProviderTestUtils.setFeatureProvider(new DoSomethingProvider()); assertThat(api.getProviderMetadata().getName()).isEqualTo(DoSomethingProvider.name); } - @Specification(number="1.1.4", text="The API MUST provide a function to add hooks which accepts one or more API-conformant hooks, and appends them to the collection of any previously added hooks. When new hooks are added, previously added hooks are not removed.") - @Test void hook_addition() { + @Specification(number = "1.1.4", text = "The API MUST provide a function to add hooks which accepts one or more API-conformant hooks, and appends them to the collection of any previously added hooks. When new hooks are added, previously added hooks are not removed.") + @Test + void hook_addition() { Hook h1 = mock(Hook.class); Hook h2 = mock(Hook.class); api.addHooks(h1); @@ -136,8 +147,9 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { assertEquals(h2, api.getHooks().get(1)); } - @Specification(number="1.1.6", text="The API MUST provide a function for creating a client which accepts the following options: - domain (optional): A logical string identifier for binding clients to provider.") - @Test void domainName() { + @Specification(number = "1.1.6", text = "The API MUST provide a function for creating a client which accepts the following options: - domain (optional): A logical string identifier for binding clients to provider.") + @Test + void domainName() { assertNull(api.getClient().getMetadata().getDomain()); String domain = "Sir Calls-a-lot"; @@ -145,8 +157,9 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { assertEquals(domain, clientForDomain.getMetadata().getDomain()); } - @Specification(number="1.2.1", text="The client MUST provide a method to add hooks which accepts one or more API-conformant hooks, and appends them to the collection of any previously added hooks. When new hooks are added, previously added hooks are not removed.") - @Test void hookRegistration() { + @Specification(number = "1.2.1", text = "The client MUST provide a method to add hooks which accepts one or more API-conformant hooks, and appends them to the collection of any previously added hooks. When new hooks are added, previously added hooks are not removed.") + @Test + void hookRegistration() { Client c = _client(); Hook m1 = mock(Hook.class); Hook m2 = mock(Hook.class); @@ -158,9 +171,10 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { assertTrue(hooks.contains(m2)); } - @Specification(number="1.3.1.1", text="The client MUST provide methods for typed flag evaluation, including boolean, numeric, string, and structure, with parameters flag key (string, required), default value (boolean | number | string | structure, required), evaluation context (optional), and evaluation options (optional), which returns the flag value.") - @Specification(number="1.3.3.1", text="The client SHOULD provide functions for floating-point numbers and integers, consistent with language idioms.") - @Test void value_flags() { + @Specification(number = "1.3.1.1", text = "The client MUST provide methods for typed flag evaluation, including boolean, numeric, string, and structure, with parameters flag key (string, required), default value (boolean | number | string | structure, required), evaluation context (optional), and evaluation options (optional), which returns the flag value.") + @Specification(number = "1.3.3.1", text = "The client SHOULD provide functions for floating-point numbers and integers, consistent with language idioms.") + @Test + void value_flags() { FeatureProviderTestUtils.setFeatureProvider(new DoSomethingProvider()); Client c = api.getClient(); @@ -168,11 +182,13 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { assertEquals(true, c.getBooleanValue(key, false)); assertEquals(true, c.getBooleanValue(key, false, new ImmutableContext())); - assertEquals(true, c.getBooleanValue(key, false, new ImmutableContext(), FlagEvaluationOptions.builder().build())); + assertEquals(true, + c.getBooleanValue(key, false, new ImmutableContext(), FlagEvaluationOptions.builder().build())); assertEquals("gnirts-ym", c.getStringValue(key, "my-string")); assertEquals("gnirts-ym", c.getStringValue(key, "my-string", new ImmutableContext())); - assertEquals("gnirts-ym", c.getStringValue(key, "my-string", new ImmutableContext(), FlagEvaluationOptions.builder().build())); + assertEquals("gnirts-ym", + c.getStringValue(key, "my-string", new ImmutableContext(), FlagEvaluationOptions.builder().build())); assertEquals(400, c.getIntegerValue(key, 4)); assertEquals(400, c.getIntegerValue(key, 4, new ImmutableContext())); @@ -182,18 +198,19 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { assertEquals(40.0, c.getDoubleValue(key, .4, new ImmutableContext())); assertEquals(40.0, c.getDoubleValue(key, .4, new ImmutableContext(), FlagEvaluationOptions.builder().build())); - assertEquals(null, c.getObjectValue(key, new Value())); - assertEquals(null, c.getObjectValue(key, new Value(), new ImmutableContext())); - assertEquals(null, c.getObjectValue(key, new Value(), new ImmutableContext(), FlagEvaluationOptions.builder().build())); + assertNull(c.getObjectValue(key, new Value())); + assertNull(c.getObjectValue(key, new Value(), new ImmutableContext())); + assertNull(c.getObjectValue(key, new Value(), new ImmutableContext(), FlagEvaluationOptions.builder().build())); } - @Specification(number="1.4.1.1", text="The client MUST provide methods for detailed flag value evaluation with parameters flag key (string, required), default value (boolean | number | string | structure, required), evaluation context (optional), and evaluation options (optional), which returns an evaluation details structure.") - @Specification(number="1.4.3", text="The evaluation details structure's value field MUST contain the evaluated flag value.") - @Specification(number="1.4.4.1", text="The evaluation details structure SHOULD accept a generic argument (or use an equivalent language feature) which indicates the type of the wrapped value field.") - @Specification(number="1.4.5", text="The evaluation details structure's flag key field MUST contain the flag key argument passed to the detailed flag evaluation method.") - @Specification(number="1.4.6", text="In cases of normal execution, the evaluation details structure's variant field MUST contain the value of the variant field in the flag resolution structure returned by the configured provider, if the field is set.") - @Specification(number="1.4.7", text="In cases of normal execution, the `evaluation details` structure's `reason` field MUST contain the value of the `reason` field in the `flag resolution` structure returned by the configured `provider`, if the field is set.") - @Test void detail_flags() { + @Specification(number = "1.4.1.1", text = "The client MUST provide methods for detailed flag value evaluation with parameters flag key (string, required), default value (boolean | number | string | structure, required), evaluation context (optional), and evaluation options (optional), which returns an evaluation details structure.") + @Specification(number = "1.4.3", text = "The evaluation details structure's value field MUST contain the evaluated flag value.") + @Specification(number = "1.4.4.1", text = "The evaluation details structure SHOULD accept a generic argument (or use an equivalent language feature) which indicates the type of the wrapped value field.") + @Specification(number = "1.4.5", text = "The evaluation details structure's flag key field MUST contain the flag key argument passed to the detailed flag evaluation method.") + @Specification(number = "1.4.6", text = "In cases of normal execution, the evaluation details structure's variant field MUST contain the value of the variant field in the flag resolution structure returned by the configured provider, if the field is set.") + @Specification(number = "1.4.7", text = "In cases of normal execution, the `evaluation details` structure's `reason` field MUST contain the value of the `reason` field in the `flag resolution` structure returned by the configured `provider`, if the field is set.") + @Test + void detail_flags() { FeatureProviderTestUtils.setFeatureProvider(new DoSomethingProvider()); Client c = api.getClient(); String key = "key"; @@ -206,7 +223,8 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { .build(); assertEquals(bd, c.getBooleanDetails(key, true)); assertEquals(bd, c.getBooleanDetails(key, true, new ImmutableContext())); - assertEquals(bd, c.getBooleanDetails(key, true, new ImmutableContext(), FlagEvaluationOptions.builder().build())); + assertEquals(bd, + c.getBooleanDetails(key, true, new ImmutableContext(), FlagEvaluationOptions.builder().build())); FlagEvaluationDetails sd = FlagEvaluationDetails.builder() .flagKey(key) @@ -216,7 +234,8 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { .build(); assertEquals(sd, c.getStringDetails(key, "test")); assertEquals(sd, c.getStringDetails(key, "test", new ImmutableContext())); - assertEquals(sd, c.getStringDetails(key, "test", new ImmutableContext(), FlagEvaluationOptions.builder().build())); + assertEquals(sd, + c.getStringDetails(key, "test", new ImmutableContext(), FlagEvaluationOptions.builder().build())); FlagEvaluationDetails id = FlagEvaluationDetails.builder() .flagKey(key) @@ -239,24 +258,26 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { // TODO: Structure detail tests. } - @Specification(number="1.5.1", text="The evaluation options structure's hooks field denotes an ordered collection of hooks that the client MUST execute for the respective flag evaluation, in addition to those already configured.") - @Test void hooks() { + @Specification(number = "1.5.1", text = "The evaluation options structure's hooks field denotes an ordered collection of hooks that the client MUST execute for the respective flag evaluation, in addition to those already configured.") + @Test + void hooks() { Client c = _client(); Hook clientHook = mockBooleanHook(); Hook invocationHook = mockBooleanHook(); c.addHooks(clientHook); c.getBooleanValue("key", false, null, FlagEvaluationOptions.builder() - .hook(invocationHook) - .build()); + .hook(invocationHook) + .build()); verify(clientHook, times(1)).before(any(), any()); verify(invocationHook, times(1)).before(any(), any()); } - @Specification(number="1.4.8", text="In cases of abnormal execution, the `evaluation details` structure's `error code` field **MUST** contain an `error code`.") - @Specification(number="1.4.9", text="In cases of abnormal execution (network failure, unhandled error, etc) the `reason` field in the `evaluation details` SHOULD indicate an error.") - @Specification(number="1.4.10", text="Methods, functions, or operations on the client MUST NOT throw exceptions, or otherwise abnormally terminate. Flag evaluation calls must always return the `default value` in the event of abnormal execution. Exceptions include functions or methods for the purposes for configuration or setup.") - @Specification(number="1.4.13", text="In cases of abnormal execution, the `evaluation details` structure's `error message` field **MAY** contain a string containing additional details about the nature of the error.") - @Test void broken_provider() { + @Specification(number = "1.4.8", text = "In cases of abnormal execution, the `evaluation details` structure's `error code` field **MUST** contain an `error code`.") + @Specification(number = "1.4.9", text = "In cases of abnormal execution (network failure, unhandled error, etc) the `reason` field in the `evaluation details` SHOULD indicate an error.") + @Specification(number = "1.4.10", text = "Methods, functions, or operations on the client MUST NOT throw exceptions, or otherwise abnormally terminate. Flag evaluation calls must always return the `default value` in the event of abnormal execution. Exceptions include functions or methods for the purposes for configuration or setup.") + @Specification(number = "1.4.13", text = "In cases of abnormal execution, the `evaluation details` structure's `error message` field **MAY** contain a string containing additional details about the nature of the error.") + @Test + void broken_provider() { FeatureProviderTestUtils.setFeatureProvider(new AlwaysBrokenProvider()); Client c = api.getClient(); assertFalse(c.getBooleanValue("key", false)); @@ -265,8 +286,9 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { assertEquals(TestConstants.BROKEN_MESSAGE, details.getErrorMessage()); } - @Specification(number="1.4.11", text="Methods, functions, or operations on the client SHOULD NOT write log messages.") - @Test void log_on_error() throws NotImplementedException { + @Specification(number = "1.4.11", text = "Methods, functions, or operations on the client SHOULD NOT write log messages.") + @Test + void log_on_error() throws NotImplementedException { FeatureProviderTestUtils.setFeatureProvider(new AlwaysBrokenProvider()); Client c = api.getClient(); FlagEvaluationDetails result = c.getBooleanDetails("test", false); @@ -278,8 +300,9 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { any()); } - @Specification(number="1.2.2", text="The client interface MUST define a metadata member or accessor, containing an immutable domain field or accessor of type string, which corresponds to the domain value supplied during client creation. In previous drafts, this property was called name. For backwards compatibility, implementations should consider name an alias to domain.") - @Test void clientMetadata() { + @Specification(number = "1.2.2", text = "The client interface MUST define a metadata member or accessor, containing an immutable domain field or accessor of type string, which corresponds to the domain value supplied during client creation. In previous drafts, this property was called name. For backwards compatibility, implementations should consider name an alias to domain.") + @Test + void clientMetadata() { Client c = _client(); assertNull(c.getMetadata().getName()); assertNull(c.getMetadata().getDomain()); @@ -292,27 +315,30 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { assertEquals(domainName, c2.getMetadata().getDomain()); } - @Specification(number="1.4.9", text="In cases of abnormal execution (network failure, unhandled error, etc) the reason field in the evaluation details SHOULD indicate an error.") - @Test void reason_is_error_when_there_are_errors() { + @Specification(number = "1.4.9", text = "In cases of abnormal execution (network failure, unhandled error, etc) the reason field in the evaluation details SHOULD indicate an error.") + @Test + void reason_is_error_when_there_are_errors() { FeatureProviderTestUtils.setFeatureProvider(new AlwaysBrokenProvider()); Client c = api.getClient(); FlagEvaluationDetails result = c.getBooleanDetails("test", false); assertEquals(Reason.ERROR.toString(), result.getReason()); } - @Specification(number="1.4.14", text="If the flag metadata field in the flag resolution structure returned by the configured provider is set, the evaluation details structure's flag metadata field MUST contain that value. Otherwise, it MUST contain an empty record.") - @Test void flag_metadata_passed() { + @Specification(number = "1.4.14", text = "If the flag metadata field in the flag resolution structure returned by the configured provider is set, the evaluation details structure's flag metadata field MUST contain that value. Otherwise, it MUST contain an empty record.") + @Test + void flag_metadata_passed() { FeatureProviderTestUtils.setFeatureProvider(new DoSomethingProvider(null)); Client c = api.getClient(); FlagEvaluationDetails result = c.getBooleanDetails("test", false); assertNotNull(result.getFlagMetadata()); } - @Specification(number="3.2.2.1", text="The API MUST have a method for setting the global evaluation context.") - @Test void api_context() { + @Specification(number = "3.2.2.1", text = "The API MUST have a method for setting the global evaluation context.") + @Test + void api_context() { String contextKey = "some-key"; String contextValue = "some-value"; - DoSomethingProvider provider = spy( new DoSomethingProvider()); + DoSomethingProvider provider = spy(new DoSomethingProvider()); FeatureProviderTestUtils.setFeatureProvider(provider); Map attributes = new HashMap<>(); @@ -325,12 +351,14 @@ public void initialize(EvaluationContext evaluationContext) throws Exception { client.getBooleanValue("any-flag", false); // assert that the value from the global context was passed to the provider - verify(provider).getBooleanEvaluation(any(), any(), argThat((arg) -> arg.getValue(contextKey).asString().equals(contextValue))); + verify(provider).getBooleanEvaluation(any(), any(), + argThat((arg) -> arg.getValue(contextKey).asString().equals(contextValue))); } - @Specification(number="3.2.1.1", text="The API, Client and invocation MUST have a method for supplying evaluation context.") - @Specification(number="3.2.3", text="Evaluation context MUST be merged in the order: API (global; lowest precedence) -> transaction -> client -> invocation -> before hooks (highest precedence), with duplicate values being overwritten.") - @Test void multi_layer_context_merges_correctly() { + @Specification(number = "3.2.1.1", text = "The API, Client and invocation MUST have a method for supplying evaluation context.") + @Specification(number = "3.2.3", text = "Evaluation context MUST be merged in the order: API (global; lowest precedence) -> transaction -> client -> invocation -> before hooks (highest precedence), with duplicate values being overwritten.") + @Test + void multi_layer_context_merges_correctly() { DoSomethingProvider provider = spy(new DoSomethingProvider()); FeatureProviderTestUtils.setFeatureProvider(provider); TransactionContextPropagator transactionContextPropagator = new ThreadLocalTransactionContextPropagator(); @@ -343,8 +371,10 @@ public Optional before(HookContext ctx, Map ctx, FlagEvaluationDetails details, Map hints) { + public void after(HookContext ctx, FlagEvaluationDetails details, + Map hints) { Hook.super.after(ctx, details, hints); } }); @@ -441,8 +471,9 @@ public void after(HookContext ctx, FlagEvaluationDetails detai }), any(), any()); } - @Specification(number="3.3.1.1", text="The API SHOULD have a method for setting a transaction context propagator.") - @Test void setting_transaction_context_propagator() { + @Specification(number = "3.3.1.1", text = "The API SHOULD have a method for setting a transaction context propagator.") + @Test + void setting_transaction_context_propagator() { DoSomethingProvider provider = new DoSomethingProvider(); FeatureProviderTestUtils.setFeatureProvider(provider); @@ -451,8 +482,9 @@ public void after(HookContext ctx, FlagEvaluationDetails detai assertEquals(transactionContextPropagator, api.getTransactionContextPropagator()); } - @Specification(number="3.3.1.2.1", text="The API MUST have a method for setting the evaluation context of the transaction context propagator for the current transaction.") - @Test void setting_transaction_context() { + @Specification(number = "3.3.1.2.1", text = "The API MUST have a method for setting the evaluation context of the transaction context propagator for the current transaction.") + @Test + void setting_transaction_context() { DoSomethingProvider provider = new DoSomethingProvider(); FeatureProviderTestUtils.setFeatureProvider(provider); @@ -467,9 +499,10 @@ public void after(HookContext ctx, FlagEvaluationDetails detai assertEquals(transactionContext, transactionContextPropagator.getTransactionContext()); } - @Specification(number="3.3.1.2.2", text="A transaction context propagator MUST have a method for setting the evaluation context of the current transaction.") - @Specification(number="3.3.1.2.3", text="A transaction context propagator MUST have a method for getting the evaluation context of the current transaction.") - @Test void transaction_context_propagator_setting_context() { + @Specification(number = "3.3.1.2.2", text = "A transaction context propagator MUST have a method for setting the evaluation context of the current transaction.") + @Specification(number = "3.3.1.2.3", text = "A transaction context propagator MUST have a method for getting the evaluation context of the current transaction.") + @Test + void transaction_context_propagator_setting_context() { TransactionContextPropagator transactionContextPropagator = new ThreadLocalTransactionContextPropagator(); Map attributes = new HashMap<>(); @@ -480,23 +513,33 @@ public void after(HookContext ctx, FlagEvaluationDetails detai assertEquals(transactionContext, transactionContextPropagator.getTransactionContext()); } - @Specification(number="1.3.4", text="The client SHOULD guarantee the returned value of any typed flag evaluation method is of the expected type. If the value returned by the underlying provider implementation does not match the expected type, it's to be considered abnormal execution, and the supplied default value should be returned.") - @Test void type_system_prevents_this() {} + @Specification(number = "1.3.4", text = "The client SHOULD guarantee the returned value of any typed flag evaluation method is of the expected type. If the value returned by the underlying provider implementation does not match the expected type, it's to be considered abnormal execution, and the supplied default value should be returned.") + @Test + void type_system_prevents_this() { + } - @Specification(number="1.1.7", text="The client creation function MUST NOT throw, or otherwise abnormally terminate.") - @Test void constructor_does_not_throw() {} + @Specification(number = "1.1.7", text = "The client creation function MUST NOT throw, or otherwise abnormally terminate.") + @Test + void constructor_does_not_throw() { + } - @Specification(number="1.4.12", text="The client SHOULD provide asynchronous or non-blocking mechanisms for flag evaluation.") - @Test void one_thread_per_request_model() {} + @Specification(number = "1.4.12", text = "The client SHOULD provide asynchronous or non-blocking mechanisms for flag evaluation.") + @Test + void one_thread_per_request_model() { + } - @Specification(number="1.4.14.1", text="Condition: Flag metadata MUST be immutable.") - @Test void compiler_enforced() {} + @Specification(number = "1.4.14.1", text = "Condition: Flag metadata MUST be immutable.") + @Test + void compiler_enforced() { + } - @Specification(number="1.4.2.1", text="The client MUST provide methods for detailed flag value evaluation with parameters flag key (string, required), default value (boolean | number | string | structure, required), and evaluation options (optional), which returns an evaluation details structure.") - @Specification(number="1.3.2.1", text="The client MUST provide methods for typed flag evaluation, including boolean, numeric, string, and structure, with parameters flag key (string, required), default value (boolean | number | string | structure, required), and evaluation options (optional), which returns the flag value.") - @Specification(number="3.2.2.2", text="The Client and invocation MUST NOT have a method for supplying evaluation context.") - @Specification(number="3.2.4.1", text="When the global evaluation context is set, the on context changed handler MUST run.") - @Specification(number="3.3.2.1", text="The API MUST NOT have a method for setting a transaction context propagator.") - @Test void not_applicable_for_dynamic_context() {} + @Specification(number = "1.4.2.1", text = "The client MUST provide methods for detailed flag value evaluation with parameters flag key (string, required), default value (boolean | number | string | structure, required), and evaluation options (optional), which returns an evaluation details structure.") + @Specification(number = "1.3.2.1", text = "The client MUST provide methods for typed flag evaluation, including boolean, numeric, string, and structure, with parameters flag key (string, required), default value (boolean | number | string | structure, required), and evaluation options (optional), which returns the flag value.") + @Specification(number = "3.2.2.2", text = "The Client and invocation MUST NOT have a method for supplying evaluation context.") + @Specification(number = "3.2.4.1", text = "When the global evaluation context is set, the on context changed handler MUST run.") + @Specification(number = "3.3.2.1", text = "The API MUST NOT have a method for setting a transaction context propagator.") + @Test + void not_applicable_for_dynamic_context() { + } } diff --git a/src/test/java/dev/openfeature/sdk/HookContextTest.java b/src/test/java/dev/openfeature/sdk/HookContextTest.java index 50cc66177..bcc6e8665 100644 --- a/src/test/java/dev/openfeature/sdk/HookContextTest.java +++ b/src/test/java/dev/openfeature/sdk/HookContextTest.java @@ -6,9 +6,10 @@ import static org.mockito.Mockito.mock; class HookContextTest { - @Specification(number="4.2.2.2", text="Condition: The client metadata field in the hook context MUST be immutable.") - @Specification(number="4.2.2.3", text="Condition: The provider metadata field in the hook context MUST be immutable.") - @Test void metadata_field_is_type_metadata() { + @Specification(number = "4.2.2.2", text = "Condition: The client metadata field in the hook context MUST be immutable.") + @Specification(number = "4.2.2.3", text = "Condition: The provider metadata field in the hook context MUST be immutable.") + @Test + void metadata_field_is_type_metadata() { ClientMetadata clientMetadata = mock(ClientMetadata.class); Metadata meta = mock(Metadata.class); HookContext hc = HookContext.from( @@ -24,7 +25,8 @@ class HookContextTest { assertTrue(Metadata.class.isAssignableFrom(hc.getProviderMetadata().getClass())); } - @Specification(number="4.3.3.1", text="The before stage MUST run before flag resolution occurs. It accepts a hook context (required) and hook hints (optional) as parameters. It has no return value.") - @Test void not_applicable_for_dynamic_context() {} + @Specification(number = "4.3.3.1", text = "The before stage MUST run before flag resolution occurs. It accepts a hook context (required) and hook hints (optional) as parameters. It has no return value.") + @Test + void not_applicable_for_dynamic_context() {} -} \ No newline at end of file +} diff --git a/src/test/java/dev/openfeature/sdk/HookSpecTest.java b/src/test/java/dev/openfeature/sdk/HookSpecTest.java index 2554457ab..33f1af7df 100644 --- a/src/test/java/dev/openfeature/sdk/HookSpecTest.java +++ b/src/test/java/dev/openfeature/sdk/HookSpecTest.java @@ -39,8 +39,9 @@ void emptyApiHooks() { OpenFeatureAPI.getInstance().clearHooks(); } - @Specification(number="4.1.3", text="The flag key, flag type, and default value properties MUST be immutable. If the language does not support immutability, the hook MUST NOT modify these properties.") - @Test void immutableValues() { + @Specification(number = "4.1.3", text = "The flag key, flag type, and default value properties MUST be immutable. If the language does not support immutability, the hook MUST NOT modify these properties.") + @Test + void immutableValues() { try { HookContext.class.getMethod("setFlagKey"); fail("Shouldn't be able to find this method"); @@ -63,8 +64,9 @@ void emptyApiHooks() { } } - @Specification(number="4.1.1", text="Hook context MUST provide: the flag key, flag value type, evaluation context, and the default value.") - @Test void nullish_properties_on_hookcontext() { + @Specification(number = "4.1.1", text = "Hook context MUST provide: the flag key, flag value type, evaluation context, and the default value.") + @Test + void nullish_properties_on_hookcontext() { // missing ctx try { HookContext.builder() @@ -127,8 +129,9 @@ void emptyApiHooks() { } - @Specification(number="4.1.2", text="The hook context SHOULD provide: access to the client metadata and the provider metadata fields.") - @Test void optional_properties() { + @Specification(number = "4.1.2", text = "The hook context SHOULD provide: access to the client metadata and the provider metadata fields.") + @Test + void optional_properties() { // don't specify HookContext.builder() .flagKey("key") @@ -156,8 +159,9 @@ void emptyApiHooks() { .build(); } - @Specification(number="4.3.2.1", text="The before stage MUST run before flag resolution occurs. It accepts a hook context (required) and hook hints (optional) as parameters and returns either an evaluation context or nothing.") - @Test void before_runs_ahead_of_evaluation() { + @Specification(number = "4.3.2.1", text = "The before stage MUST run before flag resolution occurs. It accepts a hook context (required) and hook hints (optional) as parameters and returns either an evaluation context or nothing.") + @Test + void before_runs_ahead_of_evaluation() { OpenFeatureAPI api = OpenFeatureAPI.getInstance(); api.setProvider(new AlwaysBrokenProvider()); Client client = api.getClient(); @@ -169,13 +173,15 @@ void emptyApiHooks() { verify(evalHook, times(1)).before(any(), any()); } - @Test void feo_has_hook_list() { + @Test + void feo_has_hook_list() { FlagEvaluationOptions feo = FlagEvaluationOptions.builder() .build(); assertNotNull(feo.getHooks()); } - @Test void error_hook_run_during_non_finally_stage() { + @Test + void error_hook_run_during_non_finally_stage() { final boolean[] error_called = {false}; Hook h = mockBooleanHook(); doThrow(RuntimeException.class).when(h).finallyAfter(any(), any()); @@ -184,7 +190,8 @@ void emptyApiHooks() { } - @Test void error_hook_must_run_if_resolution_details_returns_an_error_code() { + @Test + void error_hook_must_run_if_resolution_details_returns_an_error_code() { String errorMessage = "not found..."; @@ -209,7 +216,7 @@ void emptyApiHooks() { verify(hook, times(1)).before(any(), any()); verify(hook, times(1)).error(any(), captor.capture(), any()); verify(hook, times(1)).finallyAfter(any(), any()); - verify(hook, never()).after(any(),any(), any()); + verify(hook, never()).after(any(), any(), any()); Exception exception = captor.getValue(); assertEquals(errorMessage, exception.getMessage()); @@ -217,12 +224,13 @@ void emptyApiHooks() { } - @Specification(number="4.3.6", text="The after stage MUST run after flag resolution occurs. It accepts a hook context (required), flag evaluation details (required) and hook hints (optional). It has no return value.") - @Specification(number="4.3.7", text="The error hook MUST run when errors are encountered in the before stage, the after stage or during flag resolution. It accepts hook context (required), exception representing what went wrong (required), and hook hints (optional). It has no return value.") - @Specification(number="4.3.8", text="The finally hook MUST run after the before, after, and error stages. It accepts a hook context (required) and hook hints (optional). There is no return value.") - @Specification(number="4.4.1", text="The API, Client, Provider, and invocation MUST have a method for registering hooks.") - @Specification(number="4.4.2", text="Hooks MUST be evaluated in the following order: - before: API, Client, Invocation, Provider - after: Provider, Invocation, Client, API - error (if applicable): Provider, Invocation, Client, API - finally: Provider, Invocation, Client, API") - @Test void hook_eval_order() { + @Specification(number = "4.3.6", text = "The after stage MUST run after flag resolution occurs. It accepts a hook context (required), flag evaluation details (required) and hook hints (optional). It has no return value.") + @Specification(number = "4.3.7", text = "The error hook MUST run when errors are encountered in the before stage, the after stage or during flag resolution. It accepts hook context (required), exception representing what went wrong (required), and hook hints (optional). It has no return value.") + @Specification(number = "4.3.8", text = "The finally hook MUST run after the before, after, and error stages. It accepts a hook context (required) and hook hints (optional). There is no return value.") + @Specification(number = "4.4.1", text = "The API, Client, Provider, and invocation MUST have a method for registering hooks.") + @Specification(number = "4.4.2", text = "Hooks MUST be evaluated in the following order: - before: API, Client, Invocation, Provider - after: Provider, Invocation, Client, API - error (if applicable): Provider, Invocation, Client, API - finally: Provider, Invocation, Client, API") + @Test + void hook_eval_order() { List evalOrder = new ArrayList<>(); OpenFeatureAPI api = OpenFeatureAPI.getInstance(); api.setProvider(new NoOpProvider() { @@ -261,7 +269,8 @@ public Optional before(HookContext ctx, Map ctx, FlagEvaluationDetails details, Map hints) { + public void after(HookContext ctx, FlagEvaluationDetails details, + Map hints) { evalOrder.add("api after"); throw new RuntimeException(); // trigger error flows. } @@ -286,7 +295,8 @@ public Optional before(HookContext ctx, Map ctx, FlagEvaluationDetails details, Map hints) { + public void after(HookContext ctx, FlagEvaluationDetails details, + Map hints) { evalOrder.add("client after"); } @@ -302,41 +312,43 @@ public void finallyAfter(HookContext ctx, Map hints) { }); c.getBooleanValue("key", false, null, FlagEvaluationOptions - .builder() - .hook(new BooleanHook() { - @Override - public Optional before(HookContext ctx, Map hints) { - evalOrder.add("invocation before"); - return null; - } - - @Override - public void after(HookContext ctx, FlagEvaluationDetails details, Map hints) { - evalOrder.add("invocation after"); - } - - @Override - public void error(HookContext ctx, Exception error, Map hints) { - evalOrder.add("invocation error"); - } - - @Override - public void finallyAfter(HookContext ctx, Map hints) { - evalOrder.add("invocation finally"); - } - }) - .build()); + .builder() + .hook(new BooleanHook() { + @Override + public Optional before(HookContext ctx, Map hints) { + evalOrder.add("invocation before"); + return null; + } + + @Override + public void after(HookContext ctx, FlagEvaluationDetails details, + Map hints) { + evalOrder.add("invocation after"); + } + + @Override + public void error(HookContext ctx, Exception error, Map hints) { + evalOrder.add("invocation error"); + } + + @Override + public void finallyAfter(HookContext ctx, Map hints) { + evalOrder.add("invocation finally"); + } + }) + .build()); List expectedOrder = Arrays.asList( - "api before", "client before", "invocation before", "provider before", - "provider after", "invocation after", "client after", "api after", - "provider error", "invocation error", "client error", "api error", - "provider finally", "invocation finally", "client finally", "api finally"); + "api before", "client before", "invocation before", "provider before", + "provider after", "invocation after", "client after", "api after", + "provider error", "invocation error", "client error", "api error", + "provider finally", "invocation finally", "client finally", "api finally"); assertEquals(expectedOrder, evalOrder); } - @Specification(number="4.4.6", text="If an error occurs during the evaluation of before or after hooks, any remaining hooks in the before or after stages MUST NOT be invoked.") - @Test void error_stops_before() { + @Specification(number = "4.4.6", text = "If an error occurs during the evaluation of before or after hooks, any remaining hooks in the before or after stages MUST NOT be invoked.") + @Test + void error_stops_before() { Hook h = mockBooleanHook(); doThrow(RuntimeException.class).when(h).before(any(), any()); Hook h2 = mockBooleanHook(); @@ -353,8 +365,9 @@ public void finallyAfter(HookContext ctx, Map hints) { verify(h2, times(0)).before(any(), any()); } - @Specification(number="4.4.6", text="If an error occurs during the evaluation of before or after hooks, any remaining hooks in the before or after stages MUST NOT be invoked.") - @Test void error_stops_after() { + @Specification(number = "4.4.6", text = "If an error occurs during the evaluation of before or after hooks, any remaining hooks in the before or after stages MUST NOT be invoked.") + @Test + void error_stops_after() { Hook h = mockBooleanHook(); doThrow(RuntimeException.class).when(h).after(any(), any(), any()); Hook h2 = mockBooleanHook(); @@ -369,33 +382,39 @@ public void finallyAfter(HookContext ctx, Map hints) { verify(h2, times(0)).after(any(), any(), any()); } - @Specification(number="4.2.1", text="hook hints MUST be a structure supports definition of arbitrary properties, with keys of type string, and values of type boolean | string | number | datetime | structure..") - @Specification(number="4.5.2", text="hook hints MUST be passed to each hook.") - @Specification(number="4.2.2.1", text="Condition: Hook hints MUST be immutable.") - @Specification(number="4.5.3", text="The hook MUST NOT alter the hook hints structure.") - @Test void hook_hints() { + @Specification(number = "4.2.1", text = "hook hints MUST be a structure supports definition of arbitrary properties, with keys of type string, and values of type boolean | string | number | datetime | structure..") + @Specification(number = "4.5.2", text = "hook hints MUST be passed to each hook.") + @Specification(number = "4.2.2.1", text = "Condition: Hook hints MUST be immutable.") + @Specification(number = "4.5.3", text = "The hook MUST NOT alter the hook hints structure.") + @Test + void hook_hints() { String hintKey = "My hint key"; Client client = getClient(null); Hook mutatingHook = new BooleanHook() { @Override public Optional before(HookContext ctx, Map hints) { - assertThatCode(() -> hints.put(hintKey, "changed value")).isInstanceOf(UnsupportedOperationException.class); + assertThatCode(() -> hints.put(hintKey, "changed value")).isInstanceOf( + UnsupportedOperationException.class); return Optional.empty(); } @Override - public void after(HookContext ctx, FlagEvaluationDetails details, Map hints) { - assertThatCode(() -> hints.put(hintKey, "changed value")).isInstanceOf(UnsupportedOperationException.class); + public void after(HookContext ctx, FlagEvaluationDetails details, + Map hints) { + assertThatCode(() -> hints.put(hintKey, "changed value")).isInstanceOf( + UnsupportedOperationException.class); } @Override public void error(HookContext ctx, Exception error, Map hints) { - assertThatCode(() -> hints.put(hintKey, "changed value")).isInstanceOf(UnsupportedOperationException.class); + assertThatCode(() -> hints.put(hintKey, "changed value")).isInstanceOf( + UnsupportedOperationException.class); } @Override public void finallyAfter(HookContext ctx, Map hints) { - assertThatCode(() -> hints.put(hintKey, "changed value")).isInstanceOf(UnsupportedOperationException.class); + assertThatCode(() -> hints.put(hintKey, "changed value")).isInstanceOf( + UnsupportedOperationException.class); } }; @@ -409,14 +428,16 @@ public void finallyAfter(HookContext ctx, Map hints) { .build()); } - @Specification(number="4.5.1", text="Flag evaluation options MAY contain hook hints, a map of data to be provided to hook invocations.") - @Test void missing_hook_hints() { + @Specification(number = "4.5.1", text = "Flag evaluation options MAY contain hook hints, a map of data to be provided to hook invocations.") + @Test + void missing_hook_hints() { FlagEvaluationOptions feo = FlagEvaluationOptions.builder().build(); assertNotNull(feo.getHookHints()); assertTrue(feo.getHookHints().isEmpty()); } - @Test void flag_eval_hook_order() { + @Test + void flag_eval_hook_order() { Hook hook = mockBooleanHook(); FeatureProvider provider = mock(FeatureProvider.class); when(provider.getBooleanEvaluation(any(), any(), any())) @@ -437,9 +458,10 @@ public void finallyAfter(HookContext ctx, Map hints) { order.verify(hook).finallyAfter(any(), any()); } - @Specification(number="4.4.5", text="If an error occurs in the before or after hooks, the error hooks MUST be invoked.") - @Specification(number="4.4.7", text="If an error occurs in the before hooks, the default value MUST be returned.") - @Test void error_hooks__before() { + @Specification(number = "4.4.5", text = "If an error occurs in the before or after hooks, the error hooks MUST be invoked.") + @Specification(number = "4.4.7", text = "If an error occurs in the before hooks, the default value MUST be returned.") + @Test + void error_hooks__before() { Hook hook = mockBooleanHook(); doThrow(RuntimeException.class).when(hook).before(any(), any()); Client client = getClient(null); @@ -450,8 +472,9 @@ public void finallyAfter(HookContext ctx, Map hints) { assertEquals(false, value, "Falls through to the default."); } - @Specification(number="4.4.5", text="If an error occurs in the before or after hooks, the error hooks MUST be invoked.") - @Test void error_hooks__after() { + @Specification(number = "4.4.5", text = "If an error occurs in the before or after hooks, the error hooks MUST be invoked.") + @Test + void error_hooks__after() { Hook hook = mockBooleanHook(); doThrow(RuntimeException.class).when(hook).after(any(), any(), any()); Client client = getClient(null); @@ -461,7 +484,8 @@ public void finallyAfter(HookContext ctx, Map hints) { verify(hook, times(1)).error(any(), any(), any()); } - @Test void multi_hooks_early_out__before() { + @Test + void multi_hooks_early_out__before() { Hook hook = mockBooleanHook(); Hook hook2 = mockBooleanHook(); doThrow(RuntimeException.class).when(hook).before(any(), any()); @@ -483,7 +507,8 @@ public void finallyAfter(HookContext ctx, Map hints) { @Specification(number = "4.1.4", text = "The evaluation context MUST be mutable only within the before hook.") @Specification(number = "4.3.4", text = "Any `evaluation context` returned from a `before` hook MUST be passed to subsequent `before` hooks (via `HookContext`).") - @Test void beforeContextUpdated() { + @Test + void beforeContextUpdated() { String targetingKey = "test-key"; EvaluationContext ctx = new ImmutableContext(targetingKey); Hook hook = mockBooleanHook(); @@ -508,15 +533,15 @@ public void finallyAfter(HookContext ctx, Map hints) { } - @Specification(number="4.3.5", text="When before hooks have finished executing, any resulting evaluation context MUST be merged with the existing evaluation context.") - @Test void mergeHappensCorrectly() { - Map attributes= new HashMap<>(); + @Specification(number = "4.3.5", text = "When before hooks have finished executing, any resulting evaluation context MUST be merged with the existing evaluation context.") + @Test + void mergeHappensCorrectly() { + Map attributes = new HashMap<>(); attributes.put("test", new Value("works")); attributes.put("another", new Value("exists")); EvaluationContext hookCtx = new ImmutableContext(attributes); - - Map attributes1= new HashMap<>(); + Map attributes1 = new HashMap<>(); attributes1.put("something", new Value("here")); attributes1.put("test", new Value("broken")); EvaluationContext invocationCtx = new ImmutableContext(attributes1); @@ -545,8 +570,9 @@ public void finallyAfter(HookContext ctx, Map hints) { assertEquals("here", ec.getValue("something").asString()); } - @Specification(number="4.4.3", text="If a finally hook abnormally terminates, evaluation MUST proceed, including the execution of any remaining finally hooks.") - @Test void first_finally_broken() { + @Specification(number = "4.4.3", text = "If a finally hook abnormally terminates, evaluation MUST proceed, including the execution of any remaining finally hooks.") + @Test + void first_finally_broken() { Hook hook = mockBooleanHook(); doThrow(RuntimeException.class).when(hook).before(any(), any()); doThrow(RuntimeException.class).when(hook).finallyAfter(any(), any()); @@ -565,8 +591,9 @@ public void finallyAfter(HookContext ctx, Map hints) { order.verify(hook).finallyAfter(any(), any()); } - @Specification(number="4.4.4", text="If an error hook abnormally terminates, evaluation MUST proceed, including the execution of any remaining error hooks.") - @Test void first_error_broken() { + @Specification(number = "4.4.4", text = "If an error hook abnormally terminates, evaluation MUST proceed, including the execution of any remaining error hooks.") + @Test + void first_error_broken() { Hook hook = mockBooleanHook(); doThrow(RuntimeException.class).when(hook).before(any(), any()); doThrow(RuntimeException.class).when(hook).error(any(), any(), any()); @@ -595,18 +622,20 @@ private Client getClient(FeatureProvider provider) { return api.getClient(); } - @Specification(number="4.3.1", text="Hooks MUST specify at least one stage.") - @Test void default_methods_so_impossible() {} + @Specification(number = "4.3.1", text = "Hooks MUST specify at least one stage.") + @Test + void default_methods_so_impossible() {} - @Specification(number="4.3.9.1", text="Instead of finally, finallyAfter SHOULD be used.") + @Specification(number = "4.3.9.1", text = "Instead of finally, finallyAfter SHOULD be used.") @SneakyThrows - @Test void doesnt_use_finally() { + @Test + void doesnt_use_finally() { assertThatCode(() -> Hook.class.getMethod("finally", HookContext.class, Map.class)) - .as("Not possible. Finally is a reserved word.") - .isInstanceOf(NoSuchMethodException.class); + .as("Not possible. Finally is a reserved word.") + .isInstanceOf(NoSuchMethodException.class); assertThatCode(() -> Hook.class.getMethod("finallyAfter", HookContext.class, Map.class)) - .doesNotThrowAnyException(); + .doesNotThrowAnyException(); } } diff --git a/src/test/java/dev/openfeature/sdk/HookSupportTest.java b/src/test/java/dev/openfeature/sdk/HookSupportTest.java index bf6501dd5..431f90db6 100644 --- a/src/test/java/dev/openfeature/sdk/HookSupportTest.java +++ b/src/test/java/dev/openfeature/sdk/HookSupportTest.java @@ -25,14 +25,16 @@ void shouldMergeEvaluationContextsOnBeforeHooksCorrectly() { Map attributes = new HashMap<>(); attributes.put("baseKey", new Value("baseValue")); EvaluationContext baseContext = new ImmutableContext(attributes); - HookContext hookContext = new HookContext<>("flagKey", FlagValueType.STRING, "defaultValue", baseContext, () -> "client", () -> "provider"); + HookContext hookContext = new HookContext<>("flagKey", FlagValueType.STRING, "defaultValue", + baseContext, () -> "client", () -> "provider"); Hook hook1 = mockStringHook(); Hook hook2 = mockStringHook(); when(hook1.before(any(), any())).thenReturn(Optional.of(evaluationContextWithValue("bla", "blubber"))); when(hook2.before(any(), any())).thenReturn(Optional.of(evaluationContextWithValue("foo", "bar"))); HookSupport hookSupport = new HookSupport(); - EvaluationContext result = hookSupport.beforeHooks(FlagValueType.STRING, hookContext, Arrays.asList(hook1, hook2), Collections.emptyMap()); + EvaluationContext result = hookSupport.beforeHooks(FlagValueType.STRING, hookContext, + Arrays.asList(hook1, hook2), Collections.emptyMap()); assertThat(result.getValue("bla").asString()).isEqualTo("blubber"); assertThat(result.getValue("foo").asString()).isEqualTo("bar"); @@ -47,12 +49,17 @@ void shouldAlwaysCallGenericHook(FlagValueType flagValueType) { HookSupport hookSupport = new HookSupport(); EvaluationContext baseContext = new ImmutableContext(); IllegalStateException expectedException = new IllegalStateException("All fine, just a test"); - HookContext hookContext = new HookContext<>("flagKey", flagValueType, createDefaultValue(flagValueType), baseContext, () -> "client", () -> "provider"); + HookContext hookContext = new HookContext<>("flagKey", flagValueType, createDefaultValue(flagValueType), + baseContext, () -> "client", () -> "provider"); - hookSupport.beforeHooks(flagValueType, hookContext, Collections.singletonList(genericHook), Collections.emptyMap()); - hookSupport.afterHooks(flagValueType, hookContext, FlagEvaluationDetails.builder().build(), Collections.singletonList(genericHook), Collections.emptyMap()); - hookSupport.afterAllHooks(flagValueType, hookContext, Collections.singletonList(genericHook), Collections.emptyMap()); - hookSupport.errorHooks(flagValueType, hookContext, expectedException, Collections.singletonList(genericHook), Collections.emptyMap()); + hookSupport.beforeHooks(flagValueType, hookContext, Collections.singletonList(genericHook), + Collections.emptyMap()); + hookSupport.afterHooks(flagValueType, hookContext, FlagEvaluationDetails.builder().build(), + Collections.singletonList(genericHook), Collections.emptyMap()); + hookSupport.afterAllHooks(flagValueType, hookContext, Collections.singletonList(genericHook), + Collections.emptyMap()); + hookSupport.errorHooks(flagValueType, hookContext, expectedException, Collections.singletonList(genericHook), + Collections.emptyMap()); verify(genericHook).before(any(), any()); verify(genericHook).after(any(), any(), any()); diff --git a/src/test/java/dev/openfeature/sdk/ImmutableContextTest.java b/src/test/java/dev/openfeature/sdk/ImmutableContextTest.java index 44a6f4790..5770dc765 100644 --- a/src/test/java/dev/openfeature/sdk/ImmutableContextTest.java +++ b/src/test/java/dev/openfeature/sdk/ImmutableContextTest.java @@ -10,6 +10,7 @@ import static dev.openfeature.sdk.EvaluationContext.TARGETING_KEY; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -23,7 +24,7 @@ void shouldNotAttemptToModifyAttributesForImmutableContext() { // should check the usage of Map.of() which is a more likely use case, but that API isn't available in Java 8 EvaluationContext ctx = new ImmutableContext("targeting key", Collections.unmodifiableMap(attributes)); attributes.put("key3", new Value("val3")); - assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, ctx.keySet().toArray()); + assertArrayEquals(new Object[] {"key1", "key2", TARGETING_KEY}, ctx.keySet().toArray()); } @DisplayName("attributes mutation should not affect the immutable context") @@ -34,7 +35,7 @@ void shouldCreateCopyOfAttributesForImmutableContext() { attributes.put("key2", new Value("val2")); EvaluationContext ctx = new ImmutableContext("targeting key", attributes); attributes.put("key3", new Value("val3")); - assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, ctx.keySet().toArray()); + assertArrayEquals(new Object[] {"key1", "key2", TARGETING_KEY}, ctx.keySet().toArray()); } @DisplayName("targeting key should be changed from the overriding context") @@ -60,11 +61,12 @@ void shouldRetainTargetingKeyWhenOverridingContextTargetingKeyValueIsEmpty() { EvaluationContext merge = ctx.merge(overriding); assertEquals("targeting_key", merge.getTargetingKey()); } + @DisplayName("missing targeting key should return null") @Test void missingTargetingKeyShould() { EvaluationContext ctx = new ImmutableContext(); - assertEquals(null, ctx.getTargetingKey()); + assertNull(ctx.getTargetingKey()); } @DisplayName("Merge should retain all the attributes from the existing context when overriding context is null") @@ -76,7 +78,7 @@ void mergeShouldReturnAllTheValuesFromTheContextWhenOverridingContextIsNull() { EvaluationContext ctx = new ImmutableContext("targeting_key", attributes); EvaluationContext merge = ctx.merge(null); assertEquals("targeting_key", merge.getTargetingKey()); - assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); + assertArrayEquals(new Object[] {"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); } @DisplayName("Merge should retain subkeys from the existing context when the overriding context has the same targeting key") @@ -92,20 +94,20 @@ void mergeShouldRetainItsSubkeysWhenOverridingContextHasTheSameKey() { attributes.put("key2", new Value("val2")); ovKey1Attributes.put("overriding_key1_1", new Value("overriding_val_1_1")); overridingAttributes.put("key1", new Value(new ImmutableStructure(ovKey1Attributes))); - + EvaluationContext ctx = new ImmutableContext("targeting_key", attributes); EvaluationContext overriding = new ImmutableContext("targeting_key", overridingAttributes); EvaluationContext merge = ctx.merge(overriding); assertEquals("targeting_key", merge.getTargetingKey()); - assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); - + assertArrayEquals(new Object[] {"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); + Value key1 = merge.getValue("key1"); assertTrue(key1.isStructure()); - + Structure value = key1.asStructure(); - assertArrayEquals(new Object[]{"key1_1","overriding_key1_1"}, value.keySet().toArray()); + assertArrayEquals(new Object[] {"key1_1", "overriding_key1_1"}, value.keySet().toArray()); } - + @DisplayName("Merge should retain subkeys from the existing context when the overriding context doesn't have targeting key") @Test void mergeShouldRetainItsSubkeysWhenOverridingContextHasNoTargetingKey() { @@ -115,16 +117,16 @@ void mergeShouldRetainItsSubkeysWhenOverridingContextHasNoTargetingKey() { key1Attributes.put("key1_1", new Value("val1_1")); attributes.put("key1", new Value(new ImmutableStructure(key1Attributes))); attributes.put("key2", new Value("val2")); - + EvaluationContext ctx = new ImmutableContext(attributes); EvaluationContext overriding = new ImmutableContext(); EvaluationContext merge = ctx.merge(overriding); - assertArrayEquals(new Object[]{"key1", "key2"}, merge.keySet().toArray()); - + assertArrayEquals(new Object[] {"key1", "key2"}, merge.keySet().toArray()); + Value key1 = merge.getValue("key1"); assertTrue(key1.isStructure()); - + Structure value = key1.asStructure(); - assertArrayEquals(new Object[]{"key1_1"}, value.keySet().toArray()); + assertArrayEquals(new Object[] {"key1_1"}, value.keySet().toArray()); } } diff --git a/src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java b/src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java index 491b5069f..42be146ef 100644 --- a/src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java +++ b/src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java @@ -13,12 +13,14 @@ import static org.junit.jupiter.api.Assertions.*; class ImmutableStructureTest { - @Test void noArgShouldContainEmptyAttributes() { + @Test + void noArgShouldContainEmptyAttributes() { ImmutableStructure structure = new ImmutableStructure(); assertEquals(0, structure.asMap().keySet().size()); } - @Test void mapArgShouldContainNewMap() { + @Test + void mapArgShouldContainNewMap() { String KEY = "key"; Map map = new HashMap() { { @@ -30,7 +32,8 @@ class ImmutableStructureTest { assertNotSame(structure.asMap(), map); // should be a copy } - @Test void MutatingGetValueShouldNotChangeOriginalValue() { + @Test + void MutatingGetValueShouldNotChangeOriginalValue() { String KEY = "key"; List lists = new ArrayList<>(); lists.add(new Value(KEY)); @@ -47,7 +50,8 @@ class ImmutableStructureTest { assertNotSame(structure.asMap(), map); // should be a copy } - @Test void MutatingGetInstantValueShouldNotChangeOriginalValue() { + @Test + void MutatingGetInstantValueShouldNotChangeOriginalValue() { String KEY = "key"; Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS); Map map = new HashMap() { @@ -65,11 +69,12 @@ class ImmutableStructureTest { assertEquals(now, structure.getValue(KEY).asInstant()); } - @Test void MutatingGetStructureValueShouldNotChangeOriginalValue() { + @Test + void MutatingGetStructureValueShouldNotChangeOriginalValue() { String KEY = "key"; List lists = new ArrayList<>(); lists.add(new Value("dummy_list_1")); - MutableStructure mutableStructure = new MutableStructure().add("key1","val1").add("list", lists); + MutableStructure mutableStructure = new MutableStructure().add("key1", "val1").add("list", lists); Map map = new HashMap() { { put(KEY, new Value(mutableStructure)); @@ -81,14 +86,15 @@ class ImmutableStructureTest { //mutate the return value structure.getValue(KEY).asStructure().asMap().put("key3", new Value("val3")); assertEquals(2, structure.getValue(KEY).asStructure().asMap().size()); - assertArrayEquals(new Object[]{"key1", "list"}, structure.getValue(KEY).asStructure().keySet().toArray()); - assertTrue(structure.getValue(KEY).asStructure() instanceof ImmutableStructure); + assertArrayEquals(new Object[] {"key1", "list"}, structure.getValue(KEY).asStructure().keySet().toArray()); + assertInstanceOf(ImmutableStructure.class, structure.getValue(KEY).asStructure()); //mutate list value lists.add(new Value("dummy_list_2")); //mutate the return list value structure.getValue(KEY).asStructure().asMap().get("list").asList().add(new Value("dummy_list_3")); assertEquals(1, structure.getValue(KEY).asStructure().asMap().get("list").asList().size()); - assertEquals("dummy_list_1", structure.getValue(KEY).asStructure().asMap().get("list").asList().get(0).asString()); + assertEquals("dummy_list_1", + structure.getValue(KEY).asStructure().asMap().get("list").asList().get(0).asString()); } @Test @@ -112,7 +118,8 @@ void GettingAMissingValueShouldReturnNull() { assertNull(value); } - @Test void objectMapTest() { + @Test + void objectMapTest() { Map attrs = new HashMap<>(); attrs.put("test", new Value(45)); ImmutableStructure structure = new ImmutableStructure(attrs); diff --git a/src/test/java/dev/openfeature/sdk/InitializeBehaviorSpecTest.java b/src/test/java/dev/openfeature/sdk/InitializeBehaviorSpecTest.java index 4d0599a7a..bfee2cecd 100644 --- a/src/test/java/dev/openfeature/sdk/InitializeBehaviorSpecTest.java +++ b/src/test/java/dev/openfeature/sdk/InitializeBehaviorSpecTest.java @@ -19,10 +19,10 @@ void setupTest() { class DefaultProvider { @Specification(number = "1.1.2.2", text = "The `provider mutator` function MUST invoke the `initialize` " - + "function on the newly registered provider before using it to resolve flag values.") + + "function on the newly registered provider before using it to resolve flag values.") @Test @DisplayName("must call initialize function of the newly registered provider before using it for " - + "flag evaluation") + + "flag evaluation") void mustCallInitializeFunctionOfTheNewlyRegisteredProviderBeforeUsingItForFlagEvaluation() throws Exception { FeatureProvider featureProvider = mock(FeatureProvider.class); doReturn(ProviderState.NOT_READY).when(featureProvider).getState(); @@ -33,9 +33,9 @@ void mustCallInitializeFunctionOfTheNewlyRegisteredProviderBeforeUsingItForFlagE } @Specification(number = "1.4.10", text = "Methods, functions, or operations on the client MUST NOT throw " - + "exceptions, or otherwise abnormally terminate. Flag evaluation calls must always return the " - + "`default value` in the event of abnormal execution. Exceptions include functions or methods for " - + "the purposes for configuration or setup.") + + "exceptions, or otherwise abnormally terminate. Flag evaluation calls must always return the " + + "`default value` in the event of abnormal execution. Exceptions include functions or methods for " + + "the purposes for configuration or setup.") @Test @DisplayName("should catch exception thrown by the provider on initialization") void shouldCatchExceptionThrownByTheProviderOnInitialization() throws Exception { @@ -44,7 +44,7 @@ void shouldCatchExceptionThrownByTheProviderOnInitialization() throws Exception doThrow(TestException.class).when(featureProvider).initialize(any()); assertThatCode(() -> OpenFeatureAPI.getInstance().setProvider(featureProvider)) - .doesNotThrowAnyException(); + .doesNotThrowAnyException(); verify(featureProvider, timeout(1000)).initialize(any()); } @@ -54,11 +54,12 @@ void shouldCatchExceptionThrownByTheProviderOnInitialization() throws Exception class ProviderForNamedClient { @Specification(number = "1.1.2.2", text = "The `provider mutator` function MUST invoke the `initialize`" - + " function on the newly registered provider before using it to resolve flag values.") + + " function on the newly registered provider before using it to resolve flag values.") @Test @DisplayName("must call initialize function of the newly registered named provider before using it " - + "for flag evaluation") - void mustCallInitializeFunctionOfTheNewlyRegisteredNamedProviderBeforeUsingItForFlagEvaluation() throws Exception { + + "for flag evaluation") + void mustCallInitializeFunctionOfTheNewlyRegisteredNamedProviderBeforeUsingItForFlagEvaluation() + throws Exception { FeatureProvider featureProvider = mock(FeatureProvider.class); doReturn(ProviderState.NOT_READY).when(featureProvider).getState(); @@ -68,9 +69,9 @@ void mustCallInitializeFunctionOfTheNewlyRegisteredNamedProviderBeforeUsingItFor } @Specification(number = "1.4.10", text = "Methods, functions, or operations on the client MUST NOT throw " - + "exceptions, or otherwise abnormally terminate. Flag evaluation calls must always return the " - + "`default value` in the event of abnormal execution. Exceptions include functions or methods for " - + "the purposes for configuration or setup.") + + "exceptions, or otherwise abnormally terminate. Flag evaluation calls must always return the " + + "`default value` in the event of abnormal execution. Exceptions include functions or methods for " + + "the purposes for configuration or setup.") @Test @DisplayName("should catch exception thrown by the named client provider on initialization") void shouldCatchExceptionThrownByTheNamedClientProviderOnInitialization() throws Exception { @@ -79,7 +80,7 @@ void shouldCatchExceptionThrownByTheNamedClientProviderOnInitialization() throws doThrow(TestException.class).when(featureProvider).initialize(any()); assertThatCode(() -> OpenFeatureAPI.getInstance().setProvider(DOMAIN_NAME, featureProvider)) - .doesNotThrowAnyException(); + .doesNotThrowAnyException(); verify(featureProvider, timeout(1000)).initialize(any()); } diff --git a/src/test/java/dev/openfeature/sdk/LockingTest.java b/src/test/java/dev/openfeature/sdk/LockingTest.java index ddfa9c079..f7ef22966 100644 --- a/src/test/java/dev/openfeature/sdk/LockingTest.java +++ b/src/test/java/dev/openfeature/sdk/LockingTest.java @@ -18,13 +18,13 @@ @Isolated() class LockingTest { - + private static OpenFeatureAPI api; private OpenFeatureClient client; private AutoCloseableReentrantReadWriteLock apiLock; private AutoCloseableReentrantReadWriteLock clientContextLock; private AutoCloseableReentrantReadWriteLock clientHooksLock; - + @BeforeAll static void beforeAll() { api = OpenFeatureAPI.getInstance(); @@ -34,7 +34,7 @@ static void beforeAll() { @BeforeEach void beforeEach() { client = (OpenFeatureClient) api.getClient("LockingTest"); - + apiLock = setupLock(apiLock, mockInnerReadLock(), mockInnerWriteLock()); OpenFeatureAPI.lock = apiLock; @@ -93,7 +93,7 @@ void onProviderErrorShouldWriteLockAndUnlock() { @Nested class Client { - + // Note that the API lock is used for adding client handlers, they are all added (indirectly) on the API object. @Test @@ -231,4 +231,4 @@ private AutoCloseableReentrantReadWriteLock setupLock(AutoCloseableReentrantRead when(lock.writeLock()).thenReturn(writeLock); return lock; } -} \ No newline at end of file +} diff --git a/src/test/java/dev/openfeature/sdk/MetadataTest.java b/src/test/java/dev/openfeature/sdk/MetadataTest.java index 944f45e36..3d3340e12 100644 --- a/src/test/java/dev/openfeature/sdk/MetadataTest.java +++ b/src/test/java/dev/openfeature/sdk/MetadataTest.java @@ -5,8 +5,8 @@ import static org.junit.jupiter.api.Assertions.fail; class MetadataTest { - @Specification(number="4.2.2.2", text="Condition: The client metadata field in the hook context MUST be immutable.") - @Specification(number="4.2.2.3", text="Condition: The provider metadata field in the hook context MUST be immutable.") + @Specification(number = "4.2.2.2", text = "Condition: The client metadata field in the hook context MUST be immutable.") + @Specification(number = "4.2.2.3", text = "Condition: The provider metadata field in the hook context MUST be immutable.") @Test void metadata_is_immutable() { try { @@ -16,4 +16,4 @@ void metadata_is_immutable() { // Pass } } -} \ No newline at end of file +} diff --git a/src/test/java/dev/openfeature/sdk/MutableContextTest.java b/src/test/java/dev/openfeature/sdk/MutableContextTest.java index df21e6eca..4bfd63eea 100644 --- a/src/test/java/dev/openfeature/sdk/MutableContextTest.java +++ b/src/test/java/dev/openfeature/sdk/MutableContextTest.java @@ -10,6 +10,7 @@ import static dev.openfeature.sdk.EvaluationContext.TARGETING_KEY; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; class MutableContextTest { @@ -23,7 +24,7 @@ void shouldNotAttemptToModifyAttributesForMutableContext() { // should check the usage of Map.of() which is a more likely use case, but that API isn't available in Java 8 EvaluationContext ctx = new MutableContext("targeting key", Collections.unmodifiableMap(attributes)); attributes.put("key3", new Value("val3")); - assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, ctx.keySet().toArray()); + assertArrayEquals(new Object[] {"key1", "key2", TARGETING_KEY}, ctx.keySet().toArray()); } @DisplayName("targeting key should be changed from the overriding context") @@ -49,11 +50,12 @@ void shouldRetainTargetingKeyWhenOverridingContextTargetingKeyValueIsEmpty() { EvaluationContext merge = ctx.merge(overriding); assertEquals("targeting_key", merge.getTargetingKey()); } + @DisplayName("missing targeting key should return null") @Test void missingTargetingKeyShould() { EvaluationContext ctx = new MutableContext(); - assertEquals(null, ctx.getTargetingKey()); + assertNull(ctx.getTargetingKey()); } @DisplayName("Merge should retain all the attributes from the existing context when overriding context is null") @@ -65,7 +67,7 @@ void mergeShouldReturnAllTheValuesFromTheContextWhenOverridingContextIsNull() { EvaluationContext ctx = new MutableContext("targeting_key", attributes); EvaluationContext merge = ctx.merge(null); assertEquals("targeting_key", merge.getTargetingKey()); - assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); + assertArrayEquals(new Object[] {"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); } @DisplayName("Merge should retain subkeys from the existing context when the overriding context has the same targeting key") @@ -81,20 +83,20 @@ void mergeShouldRetainItsSubkeysWhenOverridingContextHasTheSameKey() { attributes.put("key2", new Value("val2")); ovKey1Attributes.put("overriding_key1_1", new Value("overriding_val_1_1")); overridingAttributes.put("key1", new Value(new ImmutableStructure(ovKey1Attributes))); - + EvaluationContext ctx = new MutableContext("targeting_key", attributes); EvaluationContext overriding = new MutableContext("targeting_key", overridingAttributes); EvaluationContext merge = ctx.merge(overriding); assertEquals("targeting_key", merge.getTargetingKey()); - assertArrayEquals(new Object[]{"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); - + assertArrayEquals(new Object[] {"key1", "key2", TARGETING_KEY}, merge.keySet().toArray()); + Value key1 = merge.getValue("key1"); assertTrue(key1.isStructure()); - + Structure value = key1.asStructure(); - assertArrayEquals(new Object[]{"key1_1","overriding_key1_1"}, value.keySet().toArray()); + assertArrayEquals(new Object[] {"key1_1", "overriding_key1_1"}, value.keySet().toArray()); } - + @DisplayName("Merge should retain subkeys from the existing context when the overriding context doesn't have targeting key") @Test void mergeShouldRetainItsSubkeysWhenOverridingContextHasNoTargetingKey() { @@ -104,17 +106,17 @@ void mergeShouldRetainItsSubkeysWhenOverridingContextHasNoTargetingKey() { key1Attributes.put("key1_1", new Value("val1_1")); attributes.put("key1", new Value(new ImmutableStructure(key1Attributes))); attributes.put("key2", new Value("val2")); - + EvaluationContext ctx = new MutableContext(attributes); EvaluationContext overriding = new MutableContext(); EvaluationContext merge = ctx.merge(overriding); - assertArrayEquals(new Object[]{"key1", "key2"}, merge.keySet().toArray()); - + assertArrayEquals(new Object[] {"key1", "key2"}, merge.keySet().toArray()); + Value key1 = merge.getValue("key1"); assertTrue(key1.isStructure()); - + Structure value = key1.asStructure(); - assertArrayEquals(new Object[]{"key1_1"}, value.keySet().toArray()); + assertArrayEquals(new Object[] {"key1_1"}, value.keySet().toArray()); } @DisplayName("Ensure mutations are chainable") @@ -129,6 +131,6 @@ void shouldAllowChainingOfMutations() { assertEquals("TARGETING_KEY", context.getTargetingKey()); assertEquals("val1", context.getValue("key1").asString()); assertEquals(2, context.getValue("key2").asInteger()); - assertEquals(3.0, context.getValue("key3").asDouble()); + assertEquals(3.0, context.getValue("key3").asDouble()); } } diff --git a/src/test/java/dev/openfeature/sdk/NoOpProviderTest.java b/src/test/java/dev/openfeature/sdk/NoOpProviderTest.java index 2f34cd7d4..d0c7c6014 100644 --- a/src/test/java/dev/openfeature/sdk/NoOpProviderTest.java +++ b/src/test/java/dev/openfeature/sdk/NoOpProviderTest.java @@ -5,32 +5,37 @@ import org.junit.jupiter.api.Test; public class NoOpProviderTest { - @Test void bool() { + @Test + void bool() { NoOpProvider p = new NoOpProvider(); ProviderEvaluation eval = p.getBooleanEvaluation("key", true, null); assertEquals(true, eval.getValue()); } - @Test void str() { + @Test + void str() { NoOpProvider p = new NoOpProvider(); ProviderEvaluation eval = p.getStringEvaluation("key", "works", null); assertEquals("works", eval.getValue()); } - @Test void integer() { + @Test + void integer() { NoOpProvider p = new NoOpProvider(); ProviderEvaluation eval = p.getIntegerEvaluation("key", 4, null); assertEquals(4, eval.getValue()); } - @Test void noOpdouble() { + @Test + void noOpdouble() { NoOpProvider p = new NoOpProvider(); ProviderEvaluation eval = p.getDoubleEvaluation("key", 0.4, null); assertEquals(0.4, eval.getValue()); } - @Test void value() { + @Test + void value() { NoOpProvider p = new NoOpProvider(); Value s = new Value(); ProviderEvaluation eval = p.getObjectEvaluation("key", s, null); diff --git a/src/test/java/dev/openfeature/sdk/NotImplementedException.java b/src/test/java/dev/openfeature/sdk/NotImplementedException.java index 09d7bcbbb..780c167b6 100644 --- a/src/test/java/dev/openfeature/sdk/NotImplementedException.java +++ b/src/test/java/dev/openfeature/sdk/NotImplementedException.java @@ -4,7 +4,7 @@ public class NotImplementedException extends RuntimeException { private static final long serialVersionUID = 1L; - public NotImplementedException(String message){ + public NotImplementedException(String message) { super(message); } } diff --git a/src/test/java/dev/openfeature/sdk/OpenFeatureAPITest.java b/src/test/java/dev/openfeature/sdk/OpenFeatureAPITest.java index 74298f72f..9bc29a52a 100644 --- a/src/test/java/dev/openfeature/sdk/OpenFeatureAPITest.java +++ b/src/test/java/dev/openfeature/sdk/OpenFeatureAPITest.java @@ -33,7 +33,7 @@ void namedProviderTest() { .isEqualTo(api.getProviderMetadata("namedProviderTest").getName()); } - @Specification(number="1.1.3", text="The API MUST provide a function to bind a given provider to one or more clients using a domain. If the domain already has a bound provider, it is overwritten with the new mapping.") + @Specification(number = "1.1.3", text = "The API MUST provide a function to bind a given provider to one or more clients using a domain. If the domain already has a bound provider, it is overwritten with the new mapping.") @Test void namedProviderOverwrittenTest() { String domain = "namedProviderOverwrittenTest"; diff --git a/src/test/java/dev/openfeature/sdk/OpenFeatureClientTest.java b/src/test/java/dev/openfeature/sdk/OpenFeatureClientTest.java index d6340a844..582153666 100644 --- a/src/test/java/dev/openfeature/sdk/OpenFeatureClientTest.java +++ b/src/test/java/dev/openfeature/sdk/OpenFeatureClientTest.java @@ -21,14 +21,17 @@ class OpenFeatureClientTest implements HookFixtures { private Logger logger; - @BeforeEach void set_logger() { + @BeforeEach + void set_logger() { logger = Mockito.mock(Logger.class); LoggerMock.setMock(OpenFeatureClient.class, logger); } - @AfterEach void reset_logs() { + @AfterEach + void reset_logs() { LoggerMock.setMock(OpenFeatureClient.class, logger); } + @Test @DisplayName("should not throw exception if hook has different type argument than hookContext") void shouldNotThrowExceptionIfHookHasDifferentTypeArgumentThanHookContext() { @@ -59,13 +62,13 @@ void mergeContextTest() { FeatureProvider mockProvider = mock(FeatureProvider.class); // this makes it so that true is returned only if the targeting key set at the client level is honored when(mockProvider.getBooleanEvaluation( - eq(flag), eq(defaultValue), argThat( - context -> context.getTargetingKey().equals(targetingKey)))).thenReturn(ProviderEvaluation.builder() - .value(true).build()); + eq(flag), eq(defaultValue), argThat( + context -> context.getTargetingKey().equals(targetingKey)))).thenReturn( + ProviderEvaluation.builder() + .value(true).build()); when(api.getProvider()).thenReturn(mockProvider); when(api.getProvider(any())).thenReturn(mockProvider); - OpenFeatureClient client = new OpenFeatureClient(api, "name", "version"); client.setEvaluationContext(ctx); @@ -83,7 +86,7 @@ void addHooksShouldAllowChaining() { Hook hook2 = Mockito.mock(Hook.class); OpenFeatureClient result = client.addHooks(hook1, hook2); - assertEquals(client, result); + assertEquals(client, result); } @Test @@ -96,5 +99,5 @@ void setEvaluationContextShouldAllowChaining() { OpenFeatureClient result = client.setEvaluationContext(ctx); assertEquals(client, result); } - + } diff --git a/src/test/java/dev/openfeature/sdk/ProviderEvaluationTest.java b/src/test/java/dev/openfeature/sdk/ProviderEvaluationTest.java index 16215dc1c..402581313 100644 --- a/src/test/java/dev/openfeature/sdk/ProviderEvaluationTest.java +++ b/src/test/java/dev/openfeature/sdk/ProviderEvaluationTest.java @@ -28,12 +28,12 @@ public void sixArgConstructor() { ImmutableMetadata metadata = ImmutableMetadata.builder().build(); ProviderEvaluation details = new ProviderEvaluation<>( - value, - variant, - reason.toString(), - errorCode, - errorMessage, - metadata); + value, + variant, + reason.toString(), + errorCode, + errorMessage, + metadata); assertEquals(value, details.getValue()); assertEquals(variant, details.getVariant()); diff --git a/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java b/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java index c827c91fb..913220a63 100644 --- a/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java +++ b/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java @@ -90,7 +90,7 @@ void shouldImmediatelyReturnWhenCallingTheProviderMutator() throws Exception { void shouldAvoidAdditionalInitializationCallIfProviderHasBeenInitializedAlready() throws Exception { FeatureProvider provider = createMockedReadyProvider(); setFeatureProvider(provider); - + verify(provider, never()).initialize(any()); } } @@ -254,11 +254,11 @@ void shouldRunLambdasOnSuccessful() { Consumer afterInit = mock(Consumer.class); Consumer afterShutdown = mock(Consumer.class); BiConsumer afterError = mock(BiConsumer.class); - + FeatureProvider oldProvider = providerRepository.getProvider(); FeatureProvider featureProvider1 = createMockedProvider(); FeatureProvider featureProvider2 = createMockedProvider(); - + setFeatureProvider(featureProvider1, afterSet, afterInit, afterShutdown, afterError); setFeatureProvider(featureProvider2); verify(afterSet, timeout(TIMEOUT)).accept(featureProvider1); @@ -275,12 +275,12 @@ void shouldRunLambdasOnError() throws Exception { Consumer afterInit = mock(Consumer.class); Consumer afterShutdown = mock(Consumer.class); BiConsumer afterError = mock(BiConsumer.class); - + FeatureProvider errorFeatureProvider = createMockedErrorProvider(); - + setFeatureProvider(errorFeatureProvider, afterSet, afterInit, afterShutdown, afterError); verify(afterSet, timeout(TIMEOUT)).accept(errorFeatureProvider); - verify(afterInit, never()).accept(any());; + verify(afterInit, never()).accept(any()); verify(afterError, timeout(TIMEOUT)).accept(eq(errorFeatureProvider), any()); } } diff --git a/src/test/java/dev/openfeature/sdk/Specification.java b/src/test/java/dev/openfeature/sdk/Specification.java index 061e45ec5..c75e179c1 100644 --- a/src/test/java/dev/openfeature/sdk/Specification.java +++ b/src/test/java/dev/openfeature/sdk/Specification.java @@ -5,5 +5,6 @@ @Repeatable(Specifications.class) public @interface Specification { String number(); + String text(); } diff --git a/src/test/java/dev/openfeature/sdk/StructureTest.java b/src/test/java/dev/openfeature/sdk/StructureTest.java index 16747ee06..1a208051e 100644 --- a/src/test/java/dev/openfeature/sdk/StructureTest.java +++ b/src/test/java/dev/openfeature/sdk/StructureTest.java @@ -17,12 +17,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class StructureTest { - @Test public void noArgShouldContainEmptyAttributes() { + @Test + public void noArgShouldContainEmptyAttributes() { MutableStructure structure = new MutableStructure(); assertEquals(0, structure.asMap().keySet().size()); } - @Test public void mapArgShouldContainNewMap() { + @Test + public void mapArgShouldContainNewMap() { String KEY = "key"; Map map = new HashMap() { { @@ -34,7 +36,8 @@ public class StructureTest { assertNotSame(structure.asMap(), map); // should be a copy } - @Test public void addAndGetAddAndReturnValues() { + @Test + public void addAndGetAddAndReturnValues() { String BOOL_KEY = "bool"; String STRING_KEY = "string"; String INT_KEY = "int"; @@ -104,7 +107,7 @@ void mapToStructureTest() { @Test void asObjectHandlesNullValue() { Map map = new HashMap<>(); - map.put("null", new Value((String)null)); + map.put("null", new Value((String) null)); ImmutableStructure structure = new ImmutableStructure(map); assertNull(structure.asObjectMap().get("null")); } @@ -112,6 +115,6 @@ void asObjectHandlesNullValue() { @Test void convertValueHandlesNullValue() { ImmutableStructure structure = new ImmutableStructure(); - assertNull(structure.convertValue(new Value((String)null))); + assertNull(structure.convertValue(new Value((String) null))); } } diff --git a/src/test/java/dev/openfeature/sdk/ValueTest.java b/src/test/java/dev/openfeature/sdk/ValueTest.java index 816190ab8..ed29c0357 100644 --- a/src/test/java/dev/openfeature/sdk/ValueTest.java +++ b/src/test/java/dev/openfeature/sdk/ValueTest.java @@ -13,12 +13,14 @@ import org.junit.jupiter.api.Test; public class ValueTest { - @Test public void noArgShouldContainNull() { + @Test + public void noArgShouldContainNull() { Value value = new Value(); assertTrue(value.isNull()); } - @Test public void objectArgShouldContainObject() { + @Test + public void objectArgShouldContainObject() { try { // int is a special case, see intObjectArgShouldConvertToInt() List list = new ArrayList<>(); @@ -30,7 +32,7 @@ public class ValueTest { list.add(Instant.now()); int i = 0; - for (Object l: list) { + for (Object l : list) { Value value = new Value(l); assertEquals(list.get(i), value.asObject()); i++; @@ -40,7 +42,8 @@ public class ValueTest { } } - @Test public void intObjectArgShouldConvertToInt() { + @Test + public void intObjectArgShouldConvertToInt() { try { Object innerValue = 1; Value value = new Value(innerValue); @@ -50,7 +53,8 @@ public class ValueTest { } } - @Test public void invalidObjectArgShouldThrow() { + @Test + public void invalidObjectArgShouldThrow() { class Something {} @@ -59,18 +63,21 @@ class Something {} }); } - @Test public void boolArgShouldContainBool() { + @Test + public void boolArgShouldContainBool() { boolean innerValue = true; Value value = new Value(innerValue); assertTrue(value.isBoolean()); assertEquals(innerValue, value.asBoolean()); } - @Test public void numericArgShouldReturnDoubleOrInt() { + @Test + public void numericArgShouldReturnDoubleOrInt() { double innerDoubleValue = 1.75; Value doubleValue = new Value(innerDoubleValue); assertTrue(doubleValue.isNumber()); - assertEquals(1, doubleValue.asInteger()); // the double value represented by this object converted to type int + assertEquals(1, + doubleValue.asInteger()); // the double value represented by this object converted to type int assertEquals(1.75, doubleValue.asDouble()); int innerIntValue = 100; @@ -80,21 +87,24 @@ class Something {} assertEquals(innerIntValue, intValue.asDouble()); } - @Test public void stringArgShouldContainString() { + @Test + public void stringArgShouldContainString() { String innerValue = "hi!"; Value value = new Value(innerValue); assertTrue(value.isString()); assertEquals(innerValue, value.asString()); } - @Test public void dateShouldContainDate() { + @Test + public void dateShouldContainDate() { Instant innerValue = Instant.now(); Value value = new Value(innerValue); assertTrue(value.isInstant()); assertEquals(innerValue, value.asInstant()); } - @Test public void structureShouldContainStructure() { + @Test + public void structureShouldContainStructure() { String INNER_KEY = "key"; String INNER_VALUE = "val"; MutableStructure innerValue = new MutableStructure().add(INNER_KEY, INNER_VALUE); @@ -103,7 +113,8 @@ class Something {} assertEquals(INNER_VALUE, value.asStructure().getValue(INNER_KEY).asString()); } - @Test public void listArgShouldContainList() { + @Test + public void listArgShouldContainList() { String ITEM_VALUE = "val"; List innerValue = new ArrayList(); innerValue.add(new Value(ITEM_VALUE)); @@ -112,22 +123,24 @@ class Something {} assertEquals(ITEM_VALUE, value.asList().get(0).asString()); } - @Test public void listMustBeOfValues() { + @Test + public void listMustBeOfValues() { String item = "item"; List list = new ArrayList<>(); list.add(item); try { - new Value((Object) list); + new Value(list); fail("Should fail due to creation of list of non-values."); } catch (InstantiationException e) { assertEquals("Invalid value type: class java.util.ArrayList", e.getMessage()); } } - @Test public void emptyListAllowed() { + @Test + public void emptyListAllowed() { List list = new ArrayList<>(); try { - Value value = new Value((Object) list); + Value value = new Value(list); assertTrue(value.isList()); List values = value.asList(); assertTrue(values.isEmpty()); @@ -136,15 +149,17 @@ class Something {} } } - @Test public void valueConstructorValidateListInternals() { + @Test + public void valueConstructorValidateListInternals() { List list = new ArrayList<>(); list.add(new Value("item")); list.add("item"); - assertThrows(InstantiationException.class, ()-> new Value(list)); + assertThrows(InstantiationException.class, () -> new Value(list)); } - @Test public void noOpFinalize() { + @Test + public void noOpFinalize() { Value val = new Value(); assertDoesNotThrow(val::finalize); // does nothing, but we want to defined in and make it final. } diff --git a/src/test/java/dev/openfeature/sdk/e2e/RunCucumberTest.java b/src/test/java/dev/openfeature/sdk/e2e/RunCucumberTest.java index 2c652338d..27d7dedd5 100644 --- a/src/test/java/dev/openfeature/sdk/e2e/RunCucumberTest.java +++ b/src/test/java/dev/openfeature/sdk/e2e/RunCucumberTest.java @@ -12,5 +12,5 @@ @SelectClasspathResource("features") @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty") public class RunCucumberTest { - + } diff --git a/src/test/java/dev/openfeature/sdk/hooks/logging/LoggingHookTest.java b/src/test/java/dev/openfeature/sdk/hooks/logging/LoggingHookTest.java index fad24caf7..ec82255df 100644 --- a/src/test/java/dev/openfeature/sdk/hooks/logging/LoggingHookTest.java +++ b/src/test/java/dev/openfeature/sdk/hooks/logging/LoggingHookTest.java @@ -95,7 +95,8 @@ void beforeLogsAllPropsAndEvaluationContext() { @Test void afterLogsAllPropsExceptEvaluationContext() { LoggingHook hook = new LoggingHook(); - FlagEvaluationDetails details = FlagEvaluationDetails.builder().reason(REASON).variant(VARIANT).value(VALUE).build(); + FlagEvaluationDetails details = FlagEvaluationDetails.builder().reason(REASON).variant(VARIANT) + .value(VALUE).build(); hook.after(hookContext, details, null); verify(logger).atDebug(); @@ -109,7 +110,8 @@ void afterLogsAllPropsExceptEvaluationContext() { @Test void afterLogsAllPropsAndEvaluationContext() { LoggingHook hook = new LoggingHook(true); - FlagEvaluationDetails details = FlagEvaluationDetails.builder().reason(REASON).variant(VARIANT).value(VALUE).build(); + FlagEvaluationDetails details = FlagEvaluationDetails.builder().reason(REASON).variant(VARIANT) + .value(VALUE).build(); hook.after(hookContext, details, null); verify(logger).atDebug(); @@ -164,4 +166,4 @@ private void verifyErrorProps(LoggingEventBuilder mockBuilder) { verify(mockBuilder).addKeyValue(LoggingHook.ERROR_CODE_KEY, ERROR_CODE); verify(mockBuilder).addKeyValue(LoggingHook.ERROR_MESSAGE_KEY, ERROR_MESSAGE); } -} \ No newline at end of file +} diff --git a/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java b/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java index cb7770d48..1217b81c6 100644 --- a/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java +++ b/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java @@ -46,10 +46,10 @@ void beforeEach() { client = OpenFeatureAPI.getInstance().getClient(); provider.updateFlags(flags); provider.updateFlag("addedFlag", Flag.builder() - .variant("on", true) - .variant("off", false) - .defaultVariant("on") - .build()); + .variant("on", true) + .variant("off", false) + .defaultVariant("on") + .build()); } @SneakyThrows @@ -81,9 +81,9 @@ void getDoubleEvaluation() { @Test void getObjectEvaluation() { Value expectedObject = new Value(mapToStructure(ImmutableMap.of( - "showImages", new Value(true), - "title", new Value("Check out these pics!"), - "imagesPerPage", new Value(100) + "showImages", new Value(true), + "title", new Value("Check out these pics!"), + "imagesPerPage", new Value(100) ))); assertEquals(expectedObject, client.getObjectValue("object-flag", new Value(true))); } @@ -108,7 +108,8 @@ void shouldThrowIfNotInitialized() { InMemoryProvider inMemoryProvider = new InMemoryProvider(new HashMap<>()); // ErrorCode.PROVIDER_NOT_READY should be returned when evaluated via the client - assertThrows(ProviderNotReadyError.class, ()-> inMemoryProvider.getBooleanEvaluation("fail_not_initialized", false, new ImmutableContext())); + assertThrows(ProviderNotReadyError.class, + () -> inMemoryProvider.getBooleanEvaluation("fail_not_initialized", false, new ImmutableContext())); } @SuppressWarnings("unchecked") @@ -125,4 +126,4 @@ void emitChangedFlagsOnlyIfThereAreChangedFlags() { await().untilAsserted(() -> verify(handler, times(1)) .accept(argThat(details -> details.getFlagsChanged().size() == buildFlags().size()))); } -} \ No newline at end of file +} diff --git a/src/test/java/dev/openfeature/sdk/testutils/FeatureProviderTestUtils.java b/src/test/java/dev/openfeature/sdk/testutils/FeatureProviderTestUtils.java index 41ffbe18f..d571a7b86 100644 --- a/src/test/java/dev/openfeature/sdk/testutils/FeatureProviderTestUtils.java +++ b/src/test/java/dev/openfeature/sdk/testutils/FeatureProviderTestUtils.java @@ -17,11 +17,12 @@ public static void setFeatureProvider(FeatureProvider provider) { waitForProviderInitializationComplete(OpenFeatureAPI::getProvider, provider); } - private static void waitForProviderInitializationComplete(Function extractor, FeatureProvider provider) { + private static void waitForProviderInitializationComplete(Function extractor, + FeatureProvider provider) { await() - .pollDelay(Duration.ofMillis(1)) - .atMost(Duration.ofSeconds(1)) - .until(() -> extractor.apply(OpenFeatureAPI.getInstance()) == provider); + .pollDelay(Duration.ofMillis(1)) + .atMost(Duration.ofSeconds(1)) + .until(() -> extractor.apply(OpenFeatureAPI.getInstance()) == provider); } public static void setFeatureProvider(String domain, FeatureProvider provider) { diff --git a/src/test/java/dev/openfeature/sdk/testutils/TestFlagsUtils.java b/src/test/java/dev/openfeature/sdk/testutils/TestFlagsUtils.java index d90359294..f4cf4b824 100644 --- a/src/test/java/dev/openfeature/sdk/testutils/TestFlagsUtils.java +++ b/src/test/java/dev/openfeature/sdk/testutils/TestFlagsUtils.java @@ -18,56 +18,57 @@ public class TestFlagsUtils { /** * Building flags for testing purposes. + * * @return map of flags */ public static Map> buildFlags() { Map> flags = new HashMap<>(); flags.put("boolean-flag", Flag.builder() - .variant("on", true) - .variant("off", false) - .defaultVariant("on") - .build()); + .variant("on", true) + .variant("off", false) + .defaultVariant("on") + .build()); flags.put("string-flag", Flag.builder() - .variant("greeting", "hi") - .variant("parting", "bye") - .defaultVariant("greeting") - .build()); + .variant("greeting", "hi") + .variant("parting", "bye") + .defaultVariant("greeting") + .build()); flags.put("integer-flag", Flag.builder() - .variant("one", 1) - .variant("ten", 10) - .defaultVariant("ten") - .build()); + .variant("one", 1) + .variant("ten", 10) + .defaultVariant("ten") + .build()); flags.put("float-flag", Flag.builder() - .variant("tenth", 0.1) - .variant("half", 0.5) - .defaultVariant("half") - .build()); + .variant("tenth", 0.1) + .variant("half", 0.5) + .defaultVariant("half") + .build()); flags.put("object-flag", Flag.builder() - .variant("empty", new HashMap<>()) - .variant("template", new Value(mapToStructure(ImmutableMap.of( - "showImages", new Value(true), - "title", new Value("Check out these pics!"), - "imagesPerPage", new Value(100) - )))) - .defaultVariant("template") - .build()); + .variant("empty", new HashMap<>()) + .variant("template", new Value(mapToStructure(ImmutableMap.of( + "showImages", new Value(true), + "title", new Value("Check out these pics!"), + "imagesPerPage", new Value(100) + )))) + .defaultVariant("template") + .build()); flags.put("context-aware", Flag.builder() - .variant("internal", "INTERNAL") - .variant("external", "EXTERNAL") - .defaultVariant("external") - .contextEvaluator((flag, evaluationContext) -> { - if (new Value(false).equals(evaluationContext.getValue("customer"))) { - return (String) flag.getVariants().get("internal"); - } else { - return (String) flag.getVariants().get(flag.getDefaultVariant()); - } - }) - .build()); + .variant("internal", "INTERNAL") + .variant("external", "EXTERNAL") + .defaultVariant("external") + .contextEvaluator((flag, evaluationContext) -> { + if (new Value(false).equals(evaluationContext.getValue("customer"))) { + return (String) flag.getVariants().get("internal"); + } else { + return (String) flag.getVariants().get(flag.getDefaultVariant()); + } + }) + .build()); flags.put("wrong-flag", Flag.builder() - .variant("one", "uno") - .variant("two", "dos") - .defaultVariant("one") - .build()); + .variant("one", "uno") + .variant("two", "dos") + .defaultVariant("one") + .build()); return flags; } } From 4bc8e862e0132cc6b3aecf2c3e06cba8515a17d2 Mon Sep 17 00:00:00 2001 From: Simon Schrottner Date: Mon, 7 Oct 2024 10:47:44 +0200 Subject: [PATCH 2/3] fixup: update Signed-off-by: Simon Schrottner --- src/main/java/dev/openfeature/sdk/EventSupport.java | 3 +-- .../dev/openfeature/sdk/FlagEvaluationDetails.java | 1 - .../dev/openfeature/sdk/FlagEvaluationOptions.java | 1 - src/main/java/dev/openfeature/sdk/Hook.java | 2 +- src/main/java/dev/openfeature/sdk/HookSupport.java | 1 - .../java/dev/openfeature/sdk/ImmutableContext.java | 2 +- .../java/dev/openfeature/sdk/ImmutableMetadata.java | 5 ++--- .../dev/openfeature/sdk/ImmutableStructure.java | 1 - .../java/dev/openfeature/sdk/MutableContext.java | 2 +- .../java/dev/openfeature/sdk/MutableStructure.java | 1 - .../java/dev/openfeature/sdk/OpenFeatureAPI.java | 3 +-- .../java/dev/openfeature/sdk/OpenFeatureClient.java | 13 ++++++------- .../dev/openfeature/sdk/ProviderEventDetails.java | 1 - .../dev/openfeature/sdk/ProviderRepository.java | 5 ++--- src/main/java/dev/openfeature/sdk/Structure.java | 7 +++---- src/main/java/dev/openfeature/sdk/Value.java | 9 ++++----- .../ExcludeFromGeneratedCoverageReport.java | 6 +++--- .../dev/openfeature/sdk/internal/ObjectUtils.java | 1 - .../dev/openfeature/sdk/providers/memory/Flag.java | 3 +-- .../sdk/providers/memory/InMemoryProvider.java | 7 +++---- test-harness | 2 +- 21 files changed, 30 insertions(+), 46 deletions(-) diff --git a/src/main/java/dev/openfeature/sdk/EventSupport.java b/src/main/java/dev/openfeature/sdk/EventSupport.java index e27702435..eee7bb8e0 100644 --- a/src/main/java/dev/openfeature/sdk/EventSupport.java +++ b/src/main/java/dev/openfeature/sdk/EventSupport.java @@ -1,7 +1,5 @@ package dev.openfeature.sdk; -import lombok.extern.slf4j.Slf4j; - import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -13,6 +11,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import lombok.extern.slf4j.Slf4j; /** * Util class for storing and running handlers. diff --git a/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java b/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java index 4562ea1e5..f8388ed33 100644 --- a/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java +++ b/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java @@ -1,7 +1,6 @@ package dev.openfeature.sdk; import java.util.Optional; - import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java b/src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java index 5fa1a93f1..411b59199 100644 --- a/src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java +++ b/src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java @@ -3,7 +3,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - import lombok.Builder; import lombok.Singular; diff --git a/src/main/java/dev/openfeature/sdk/Hook.java b/src/main/java/dev/openfeature/sdk/Hook.java index 3856af266..96bbab7a2 100644 --- a/src/main/java/dev/openfeature/sdk/Hook.java +++ b/src/main/java/dev/openfeature/sdk/Hook.java @@ -16,7 +16,7 @@ public interface Hook { * @param ctx Information about the particular flag evaluation * @param hints An immutable mapping of data for users to communicate to the hooks. * @return An optional {@link EvaluationContext}. If returned, it will be merged with the EvaluationContext - * instances from other hooks, the client and API. + * instances from other hooks, the client and API. */ default Optional before(HookContext ctx, Map hints) { return Optional.empty(); diff --git a/src/main/java/dev/openfeature/sdk/HookSupport.java b/src/main/java/dev/openfeature/sdk/HookSupport.java index c6e7f3a4b..1ac649b51 100644 --- a/src/main/java/dev/openfeature/sdk/HookSupport.java +++ b/src/main/java/dev/openfeature/sdk/HookSupport.java @@ -8,7 +8,6 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; - import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/dev/openfeature/sdk/ImmutableContext.java b/src/main/java/dev/openfeature/sdk/ImmutableContext.java index ed820b920..eec50e51a 100644 --- a/src/main/java/dev/openfeature/sdk/ImmutableContext.java +++ b/src/main/java/dev/openfeature/sdk/ImmutableContext.java @@ -1,9 +1,9 @@ package dev.openfeature.sdk; +import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport; import java.util.HashMap; import java.util.Map; import java.util.function.Function; -import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport; import lombok.ToString; import lombok.experimental.Delegate; diff --git a/src/main/java/dev/openfeature/sdk/ImmutableMetadata.java b/src/main/java/dev/openfeature/sdk/ImmutableMetadata.java index 75f898470..0ae9e1a94 100644 --- a/src/main/java/dev/openfeature/sdk/ImmutableMetadata.java +++ b/src/main/java/dev/openfeature/sdk/ImmutableMetadata.java @@ -1,10 +1,9 @@ package dev.openfeature.sdk; -import lombok.EqualsAndHashCode; -import lombok.extern.slf4j.Slf4j; - import java.util.HashMap; import java.util.Map; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; /** * Immutable Flag Metadata representation. Implementation is backed by a {@link Map} and immutability is provided diff --git a/src/main/java/dev/openfeature/sdk/ImmutableStructure.java b/src/main/java/dev/openfeature/sdk/ImmutableStructure.java index 57128c701..311380f29 100644 --- a/src/main/java/dev/openfeature/sdk/ImmutableStructure.java +++ b/src/main/java/dev/openfeature/sdk/ImmutableStructure.java @@ -5,7 +5,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; - import lombok.EqualsAndHashCode; import lombok.ToString; diff --git a/src/main/java/dev/openfeature/sdk/MutableContext.java b/src/main/java/dev/openfeature/sdk/MutableContext.java index 653441d31..5bd7707c2 100644 --- a/src/main/java/dev/openfeature/sdk/MutableContext.java +++ b/src/main/java/dev/openfeature/sdk/MutableContext.java @@ -1,11 +1,11 @@ package dev.openfeature.sdk; +import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport; import java.time.Instant; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; -import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport; import lombok.EqualsAndHashCode; import lombok.ToString; import lombok.experimental.Delegate; diff --git a/src/main/java/dev/openfeature/sdk/MutableStructure.java b/src/main/java/dev/openfeature/sdk/MutableStructure.java index cb2a7837c..07e9f421b 100644 --- a/src/main/java/dev/openfeature/sdk/MutableStructure.java +++ b/src/main/java/dev/openfeature/sdk/MutableStructure.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.Map; import java.util.Set; - import lombok.EqualsAndHashCode; import lombok.ToString; diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java index cb03c32b1..721ca0f55 100644 --- a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java +++ b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java @@ -3,14 +3,13 @@ import dev.openfeature.sdk.exceptions.OpenFeatureError; import dev.openfeature.sdk.internal.AutoCloseableLock; import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock; -import lombok.extern.slf4j.Slf4j; - import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; +import lombok.extern.slf4j.Slf4j; /** * A global singleton which holds base configuration for the OpenFeature diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java b/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java index b9e636493..e37f4026e 100644 --- a/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java +++ b/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java @@ -1,18 +1,17 @@ package dev.openfeature.sdk; +import dev.openfeature.sdk.exceptions.ExceptionUtils; +import dev.openfeature.sdk.exceptions.GeneralError; +import dev.openfeature.sdk.exceptions.OpenFeatureError; +import dev.openfeature.sdk.internal.AutoCloseableLock; +import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock; +import dev.openfeature.sdk.internal.ObjectUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Consumer; - -import dev.openfeature.sdk.exceptions.GeneralError; -import dev.openfeature.sdk.exceptions.OpenFeatureError; -import dev.openfeature.sdk.internal.AutoCloseableLock; -import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock; -import dev.openfeature.sdk.exceptions.ExceptionUtils; -import dev.openfeature.sdk.internal.ObjectUtils; import lombok.Getter; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/dev/openfeature/sdk/ProviderEventDetails.java b/src/main/java/dev/openfeature/sdk/ProviderEventDetails.java index c12fda4f0..97f0229c1 100644 --- a/src/main/java/dev/openfeature/sdk/ProviderEventDetails.java +++ b/src/main/java/dev/openfeature/sdk/ProviderEventDetails.java @@ -1,7 +1,6 @@ package dev.openfeature.sdk; import java.util.List; - import lombok.Data; import lombok.experimental.SuperBuilder; diff --git a/src/main/java/dev/openfeature/sdk/ProviderRepository.java b/src/main/java/dev/openfeature/sdk/ProviderRepository.java index ff670cc1b..9b245006c 100644 --- a/src/main/java/dev/openfeature/sdk/ProviderRepository.java +++ b/src/main/java/dev/openfeature/sdk/ProviderRepository.java @@ -1,5 +1,7 @@ package dev.openfeature.sdk; +import dev.openfeature.sdk.exceptions.GeneralError; +import dev.openfeature.sdk.exceptions.OpenFeatureError; import java.util.List; import java.util.Map; import java.util.Optional; @@ -12,9 +14,6 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; - -import dev.openfeature.sdk.exceptions.GeneralError; -import dev.openfeature.sdk.exceptions.OpenFeatureError; import lombok.extern.slf4j.Slf4j; @Slf4j diff --git a/src/main/java/dev/openfeature/sdk/Structure.java b/src/main/java/dev/openfeature/sdk/Structure.java index 15749cd4c..55f34bc15 100644 --- a/src/main/java/dev/openfeature/sdk/Structure.java +++ b/src/main/java/dev/openfeature/sdk/Structure.java @@ -1,16 +1,15 @@ package dev.openfeature.sdk; -import dev.openfeature.sdk.exceptions.ValueNotConvertableError; +import static dev.openfeature.sdk.Value.objectToValue; +import dev.openfeature.sdk.exceptions.ValueNotConvertableError; import java.util.HashMap; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; -import static dev.openfeature.sdk.Value.objectToValue; - /** * {@link Structure} represents a potentially nested object type which is used to represent * structured data. diff --git a/src/main/java/dev/openfeature/sdk/Value.java b/src/main/java/dev/openfeature/sdk/Value.java index 5ba9f0dcb..681aa00b0 100644 --- a/src/main/java/dev/openfeature/sdk/Value.java +++ b/src/main/java/dev/openfeature/sdk/Value.java @@ -1,17 +1,16 @@ package dev.openfeature.sdk; +import static dev.openfeature.sdk.Structure.mapToStructure; + +import dev.openfeature.sdk.exceptions.TypeMismatchError; import java.time.Instant; import java.util.List; import java.util.Map; import java.util.stream.Collectors; - -import dev.openfeature.sdk.exceptions.TypeMismatchError; import lombok.EqualsAndHashCode; import lombok.SneakyThrows; import lombok.ToString; -import static dev.openfeature.sdk.Structure.mapToStructure; - /** * Values serve as a generic return type for structure data from providers. * Providers may deal in JSON, protobuf, XML or some other data-interchange format. @@ -40,7 +39,7 @@ public Value() { * * @param value to be wrapped. * @throws InstantiationException if value is not a valid type - * (boolean, string, int, double, list, structure, instant) + * (boolean, string, int, double, list, structure, instant) */ public Value(Object value) throws InstantiationException { this.innerObject = value; diff --git a/src/main/java/dev/openfeature/sdk/internal/ExcludeFromGeneratedCoverageReport.java b/src/main/java/dev/openfeature/sdk/internal/ExcludeFromGeneratedCoverageReport.java index e25f12607..6ee3dd369 100644 --- a/src/main/java/dev/openfeature/sdk/internal/ExcludeFromGeneratedCoverageReport.java +++ b/src/main/java/dev/openfeature/sdk/internal/ExcludeFromGeneratedCoverageReport.java @@ -1,9 +1,9 @@ package dev.openfeature.sdk.internal; +import java.lang.annotation.ElementType; import java.lang.annotation.Retention; -import java.lang.annotation.Target; import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.ElementType; +import java.lang.annotation.Target; /** * JaCoCo ignores coverage of methods annotated with any annotation with "generated" in the name. @@ -11,4 +11,4 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ExcludeFromGeneratedCoverageReport { -} \ No newline at end of file +} diff --git a/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java b/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java index 67f8367c1..23f7513a8 100644 --- a/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java +++ b/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java @@ -6,7 +6,6 @@ import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; - import lombok.experimental.UtilityClass; @SuppressWarnings("checkstyle:MissingJavadocType") diff --git a/src/main/java/dev/openfeature/sdk/providers/memory/Flag.java b/src/main/java/dev/openfeature/sdk/providers/memory/Flag.java index 8cfe85c93..d6889695d 100644 --- a/src/main/java/dev/openfeature/sdk/providers/memory/Flag.java +++ b/src/main/java/dev/openfeature/sdk/providers/memory/Flag.java @@ -1,12 +1,11 @@ package dev.openfeature.sdk.providers.memory; +import java.util.Map; import lombok.Builder; import lombok.Getter; import lombok.Singular; import lombok.ToString; -import java.util.Map; - /** * Flag representation for the in-memory provider. */ diff --git a/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java b/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java index e3df24528..372d2b08f 100644 --- a/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java +++ b/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java @@ -13,16 +13,15 @@ import dev.openfeature.sdk.exceptions.OpenFeatureError; import dev.openfeature.sdk.exceptions.ProviderNotReadyError; import dev.openfeature.sdk.exceptions.TypeMismatchError; -import lombok.Getter; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; - import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; /** * In-memory provider. diff --git a/test-harness b/test-harness index 2d4c63c80..ed7e0ba66 160000 --- a/test-harness +++ b/test-harness @@ -1 +1 @@ -Subproject commit 2d4c63c800aa3af172cf09176325d93124153cde +Subproject commit ed7e0ba660b01e1a22849e1b28ec37453921552e From 891b5aeb5f3e2b4f3c885281ec02de7f6118e860 Mon Sep 17 00:00:00 2001 From: Simon Schrottner Date: Mon, 7 Oct 2024 13:42:27 +0200 Subject: [PATCH 3/3] fixup: update Signed-off-by: Simon Schrottner --- src/main/java/dev/openfeature/sdk/Client.java | 1 + .../sdk/FeatureProviderStateManager.java | 3 +- .../dev/openfeature/sdk/FlagValueType.java | 2 +- .../dev/openfeature/sdk/NoOpProvider.java | 2 +- .../dev/openfeature/sdk/OpenFeatureAPI.java | 9 ++-- .../openfeature/sdk/OpenFeatureClient.java | 43 ++++++++------- .../dev/openfeature/sdk/ProviderEvent.java | 2 +- .../openfeature/sdk/ProviderRepository.java | 45 ++++++++-------- .../openfeature/sdk/internal/ObjectUtils.java | 2 +- .../providers/memory/InMemoryProvider.java | 54 +++++++++++-------- 10 files changed, 92 insertions(+), 71 deletions(-) diff --git a/src/main/java/dev/openfeature/sdk/Client.java b/src/main/java/dev/openfeature/sdk/Client.java index e740c9f5d..85e023e75 100644 --- a/src/main/java/dev/openfeature/sdk/Client.java +++ b/src/main/java/dev/openfeature/sdk/Client.java @@ -39,6 +39,7 @@ public interface Client extends Features, EventBus { /** * Returns the current state of the associated provider. + * * @return the provider state */ ProviderState getProviderState(); diff --git a/src/main/java/dev/openfeature/sdk/FeatureProviderStateManager.java b/src/main/java/dev/openfeature/sdk/FeatureProviderStateManager.java index 973d46997..e5ca30aa3 100644 --- a/src/main/java/dev/openfeature/sdk/FeatureProviderStateManager.java +++ b/src/main/java/dev/openfeature/sdk/FeatureProviderStateManager.java @@ -1,9 +1,8 @@ package dev.openfeature.sdk; import dev.openfeature.sdk.exceptions.OpenFeatureError; -import lombok.Getter; - import java.util.concurrent.atomic.AtomicBoolean; +import lombok.Getter; class FeatureProviderStateManager implements EventProviderListener { private final FeatureProvider delegate; diff --git a/src/main/java/dev/openfeature/sdk/FlagValueType.java b/src/main/java/dev/openfeature/sdk/FlagValueType.java index 11d43afb3..8c7207058 100644 --- a/src/main/java/dev/openfeature/sdk/FlagValueType.java +++ b/src/main/java/dev/openfeature/sdk/FlagValueType.java @@ -2,5 +2,5 @@ @SuppressWarnings("checkstyle:MissingJavadocType") public enum FlagValueType { - STRING, INTEGER, DOUBLE, OBJECT, BOOLEAN; + STRING, INTEGER, DOUBLE, OBJECT, BOOLEAN } diff --git a/src/main/java/dev/openfeature/sdk/NoOpProvider.java b/src/main/java/dev/openfeature/sdk/NoOpProvider.java index 2ad59c8bf..0d37b277a 100644 --- a/src/main/java/dev/openfeature/sdk/NoOpProvider.java +++ b/src/main/java/dev/openfeature/sdk/NoOpProvider.java @@ -59,7 +59,7 @@ public ProviderEvaluation getDoubleEvaluation(String key, Double default @Override public ProviderEvaluation getObjectEvaluation(String key, Value defaultValue, - EvaluationContext invocationContext) { + EvaluationContext invocationContext) { return ProviderEvaluation.builder() .value(defaultValue) .variant(PASSED_IN_DEFAULT) diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java index ad528568a..645030951 100644 --- a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java +++ b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java @@ -3,10 +3,13 @@ import dev.openfeature.sdk.exceptions.OpenFeatureError; import dev.openfeature.sdk.internal.AutoCloseableLock; import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock; -import lombok.extern.slf4j.Slf4j; - -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.Set; import java.util.function.Consumer; +import lombok.extern.slf4j.Slf4j; /** * A global singleton which holds base configuration for the OpenFeature diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java b/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java index 2162f4130..374bd0489 100644 --- a/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java +++ b/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java @@ -1,15 +1,22 @@ package dev.openfeature.sdk; -import dev.openfeature.sdk.exceptions.*; +import dev.openfeature.sdk.exceptions.ExceptionUtils; +import dev.openfeature.sdk.exceptions.FatalError; +import dev.openfeature.sdk.exceptions.GeneralError; +import dev.openfeature.sdk.exceptions.OpenFeatureError; +import dev.openfeature.sdk.exceptions.ProviderNotReadyError; import dev.openfeature.sdk.internal.AutoCloseableLock; import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock; import dev.openfeature.sdk.internal.ObjectUtils; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import java.util.*; -import java.util.function.Consumer; - /** * OpenFeature Client implementation. * You should not instantiate this or reference this class. @@ -42,8 +49,8 @@ public class OpenFeatureClient implements Client { * @param domain An identifier which logically binds clients with providers (used by observability tools). * @param version Version of the client (used by observability tools). * @deprecated Do not use this constructor. It's for internal use only. - * Clients created using it will not run event handlers. - * Use the OpenFeatureAPI's getClient factory method instead. + * Clients created using it will not run event handlers. + * Use the OpenFeatureAPI's getClient factory method instead. */ @Deprecated() // TODO: eventually we will make this non-public. See issue #872 public OpenFeatureClient( @@ -106,7 +113,7 @@ public EvaluationContext getEvaluationContext() { } private FlagEvaluationDetails evaluateFlag(FlagValueType type, String key, T defaultValue, - EvaluationContext ctx, FlagEvaluationOptions options) { + EvaluationContext ctx, FlagEvaluationOptions options) { FlagEvaluationOptions flagOptions = ObjectUtils.defaultIfNull(options, () -> FlagEvaluationOptions.builder().build()); Map hints = Collections.unmodifiableMap(flagOptions.getHookHints()); @@ -230,7 +237,7 @@ public Boolean getBooleanValue(String key, Boolean defaultValue, EvaluationConte @Override public Boolean getBooleanValue(String key, Boolean defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return getBooleanDetails(key, defaultValue, ctx, options).getValue(); } @@ -246,7 +253,7 @@ public FlagEvaluationDetails getBooleanDetails(String key, Boolean defa @Override public FlagEvaluationDetails getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return this.evaluateFlag(FlagValueType.BOOLEAN, key, defaultValue, ctx, options); } @@ -262,7 +269,7 @@ public String getStringValue(String key, String defaultValue, EvaluationContext @Override public String getStringValue(String key, String defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return getStringDetails(key, defaultValue, ctx, options).getValue(); } @@ -278,7 +285,7 @@ public FlagEvaluationDetails getStringDetails(String key, String default @Override public FlagEvaluationDetails getStringDetails(String key, String defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return this.evaluateFlag(FlagValueType.STRING, key, defaultValue, ctx, options); } @@ -294,7 +301,7 @@ public Integer getIntegerValue(String key, Integer defaultValue, EvaluationConte @Override public Integer getIntegerValue(String key, Integer defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return getIntegerDetails(key, defaultValue, ctx, options).getValue(); } @@ -310,7 +317,7 @@ public FlagEvaluationDetails getIntegerDetails(String key, Integer defa @Override public FlagEvaluationDetails getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return this.evaluateFlag(FlagValueType.INTEGER, key, defaultValue, ctx, options); } @@ -326,7 +333,7 @@ public Double getDoubleValue(String key, Double defaultValue, EvaluationContext @Override public Double getDoubleValue(String key, Double defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return this.evaluateFlag(FlagValueType.DOUBLE, key, defaultValue, ctx, options).getValue(); } @@ -342,7 +349,7 @@ public FlagEvaluationDetails getDoubleDetails(String key, Double default @Override public FlagEvaluationDetails getDoubleDetails(String key, Double defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return this.evaluateFlag(FlagValueType.DOUBLE, key, defaultValue, ctx, options); } @@ -358,7 +365,7 @@ public Value getObjectValue(String key, Value defaultValue, EvaluationContext ct @Override public Value getObjectValue(String key, Value defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return getObjectDetails(key, defaultValue, ctx, options).getValue(); } @@ -369,13 +376,13 @@ public FlagEvaluationDetails getObjectDetails(String key, Value defaultVa @Override public FlagEvaluationDetails getObjectDetails(String key, Value defaultValue, - EvaluationContext ctx) { + EvaluationContext ctx) { return getObjectDetails(key, defaultValue, ctx, FlagEvaluationOptions.builder().build()); } @Override public FlagEvaluationDetails getObjectDetails(String key, Value defaultValue, EvaluationContext ctx, - FlagEvaluationOptions options) { + FlagEvaluationOptions options) { return this.evaluateFlag(FlagValueType.OBJECT, key, defaultValue, ctx, options); } diff --git a/src/main/java/dev/openfeature/sdk/ProviderEvent.java b/src/main/java/dev/openfeature/sdk/ProviderEvent.java index dcefd606a..cba19b00e 100644 --- a/src/main/java/dev/openfeature/sdk/ProviderEvent.java +++ b/src/main/java/dev/openfeature/sdk/ProviderEvent.java @@ -4,5 +4,5 @@ * Provider event types. */ public enum ProviderEvent { - PROVIDER_READY, PROVIDER_CONFIGURATION_CHANGED, PROVIDER_ERROR, PROVIDER_STALE; + PROVIDER_READY, PROVIDER_CONFIGURATION_CHANGED, PROVIDER_ERROR, PROVIDER_STALE } diff --git a/src/main/java/dev/openfeature/sdk/ProviderRepository.java b/src/main/java/dev/openfeature/sdk/ProviderRepository.java index d3a5c1acc..7a022ef35 100644 --- a/src/main/java/dev/openfeature/sdk/ProviderRepository.java +++ b/src/main/java/dev/openfeature/sdk/ProviderRepository.java @@ -2,8 +2,6 @@ import dev.openfeature.sdk.exceptions.GeneralError; import dev.openfeature.sdk.exceptions.OpenFeatureError; -import lombok.extern.slf4j.Slf4j; - import java.util.List; import java.util.Map; import java.util.Optional; @@ -16,6 +14,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; +import lombok.extern.slf4j.Slf4j; @Slf4j class ProviderRepository { @@ -111,11 +110,11 @@ public boolean isDefaultProvider(FeatureProvider provider) { * Set the default provider. */ public void setProvider(FeatureProvider provider, - Consumer afterSet, - Consumer afterInit, - Consumer afterShutdown, - BiConsumer afterError, - boolean waitForInit) { + Consumer afterSet, + Consumer afterInit, + Consumer afterShutdown, + BiConsumer afterError, + boolean waitForInit) { if (provider == null) { throw new IllegalArgumentException("Provider cannot be null"); } @@ -131,12 +130,12 @@ public void setProvider(FeatureProvider provider, * Otherwise, initialization happens in the background. */ public void setProvider(String domain, - FeatureProvider provider, - Consumer afterSet, - Consumer afterInit, - Consumer afterShutdown, - BiConsumer afterError, - boolean waitForInit) { + FeatureProvider provider, + Consumer afterSet, + Consumer afterInit, + Consumer afterShutdown, + BiConsumer afterError, + boolean waitForInit) { if (provider == null) { throw new IllegalArgumentException("Provider cannot be null"); } @@ -147,12 +146,12 @@ public void setProvider(String domain, } private void prepareAndInitializeProvider(String domain, - FeatureProvider newProvider, - Consumer afterSet, - Consumer afterInit, - Consumer afterShutdown, - BiConsumer afterError, - boolean waitForInit) { + FeatureProvider newProvider, + Consumer afterSet, + Consumer afterInit, + Consumer afterShutdown, + BiConsumer afterError, + boolean waitForInit) { final FeatureProviderStateManager newStateManager; final FeatureProviderStateManager oldStateManager; @@ -196,10 +195,10 @@ private FeatureProviderStateManager getExistingStateManagerForProvider(FeaturePr } private void initializeProvider(FeatureProviderStateManager newManager, - Consumer afterInit, - Consumer afterShutdown, - BiConsumer afterError, - FeatureProviderStateManager oldManager) { + Consumer afterInit, + Consumer afterShutdown, + BiConsumer afterError, + FeatureProviderStateManager oldManager) { try { if (ProviderState.NOT_READY.equals(newManager.getState())) { newManager.initialize(OpenFeatureAPI.getInstance().getEvaluationContext()); diff --git a/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java b/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java index 23f7513a8..6aea955ab 100644 --- a/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java +++ b/src/main/java/dev/openfeature/sdk/internal/ObjectUtils.java @@ -1,12 +1,12 @@ package dev.openfeature.sdk.internal; +import lombok.experimental.UtilityClass; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.function.Supplier; import java.util.stream.Collectors; -import lombok.experimental.UtilityClass; @SuppressWarnings("checkstyle:MissingJavadocType") @UtilityClass diff --git a/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java b/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java index 2bea3e4ef..2181c5b01 100644 --- a/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java +++ b/src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java @@ -1,17 +1,28 @@ package dev.openfeature.sdk.providers.memory; -import dev.openfeature.sdk.*; -import dev.openfeature.sdk.exceptions.*; -import lombok.Getter; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; - +import dev.openfeature.sdk.EvaluationContext; +import dev.openfeature.sdk.EventProvider; +import dev.openfeature.sdk.Metadata; +import dev.openfeature.sdk.ProviderEvaluation; +import dev.openfeature.sdk.ProviderEventDetails; +import dev.openfeature.sdk.ProviderState; +import dev.openfeature.sdk.Reason; +import dev.openfeature.sdk.Value; +import dev.openfeature.sdk.exceptions.FatalError; +import dev.openfeature.sdk.exceptions.FlagNotFoundError; +import dev.openfeature.sdk.exceptions.GeneralError; +import dev.openfeature.sdk.exceptions.OpenFeatureError; +import dev.openfeature.sdk.exceptions.ProviderNotReadyError; +import dev.openfeature.sdk.exceptions.TypeMismatchError; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; /** * In-memory provider. @@ -38,6 +49,7 @@ public InMemoryProvider(Map> flags) { /** * Initializes the provider. + * * @param evaluationContext evaluation context * @throws Exception on error */ @@ -60,9 +72,9 @@ public void updateFlags(Map> newFlags) { this.flags.putAll(newFlags); ProviderEventDetails details = ProviderEventDetails.builder() - .flagsChanged(new ArrayList<>(flagsChanged)) - .message("flags changed") - .build(); + .flagsChanged(new ArrayList<>(flagsChanged)) + .message("flags changed") + .build(); emitProviderConfigurationChanged(details); } @@ -76,40 +88,40 @@ public void updateFlags(Map> newFlags) { public void updateFlag(String flagKey, Flag newFlag) { this.flags.put(flagKey, newFlag); ProviderEventDetails details = ProviderEventDetails.builder() - .flagsChanged(Collections.singletonList(flagKey)) - .message("flag added/updated") - .build(); + .flagsChanged(Collections.singletonList(flagKey)) + .message("flag added/updated") + .build(); emitProviderConfigurationChanged(details); } @Override public ProviderEvaluation getBooleanEvaluation(String key, Boolean defaultValue, - EvaluationContext evaluationContext) { + EvaluationContext evaluationContext) { return getEvaluation(key, evaluationContext, Boolean.class); } @Override public ProviderEvaluation getStringEvaluation(String key, String defaultValue, - EvaluationContext evaluationContext) { + EvaluationContext evaluationContext) { return getEvaluation(key, evaluationContext, String.class); } @Override public ProviderEvaluation getIntegerEvaluation(String key, Integer defaultValue, - EvaluationContext evaluationContext) { + EvaluationContext evaluationContext) { return getEvaluation(key, evaluationContext, Integer.class); } @Override public ProviderEvaluation getDoubleEvaluation(String key, Double defaultValue, - EvaluationContext evaluationContext) { + EvaluationContext evaluationContext) { return getEvaluation(key, evaluationContext, Double.class); } @SneakyThrows @Override public ProviderEvaluation getObjectEvaluation(String key, Value defaultValue, - EvaluationContext evaluationContext) { + EvaluationContext evaluationContext) { return getEvaluation(key, evaluationContext, Value.class); } @@ -138,9 +150,9 @@ private ProviderEvaluation getEvaluation( value = (T) flag.getVariants().get(flag.getDefaultVariant()); } return ProviderEvaluation.builder() - .value(value) - .variant(flag.getDefaultVariant()) - .reason(Reason.STATIC.toString()) - .build(); + .value(value) + .variant(flag.getDefaultVariant()) + .reason(Reason.STATIC.toString()) + .build(); } }