diff --git a/.github/workflows/merge.yml b/.github/workflows/merge.yml
index 153fd0a5..de88ba99 100644
--- a/.github/workflows/merge.yml
+++ b/.github/workflows/merge.yml
@@ -20,9 +20,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@96f53100ba2a5449eb71d2e6604bbcd94b9449b5
+ - uses: actions/checkout@8b5e8b768746b50394015010d25e690bfab9dfbc
- name: Set up JDK 8
- uses: actions/setup-java@5b86b67f5bb794ee4de9464f70b700b9445b03a8
+ uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
with:
java-version: '8'
distribution: 'temurin'
@@ -49,7 +49,7 @@ jobs:
run: mvn --batch-mode --update-snapshots verify
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@e1dd05cde2ed37d100f658b34ea423728ba1812e
+ uses: codecov/codecov-action@04adcebd9b38cae0bb0fd4a05e3497ce0bce41a0
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
flags: unittests # optional
diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml
index dd5d05b2..3173d904 100644
--- a/.github/workflows/pullrequest.yml
+++ b/.github/workflows/pullrequest.yml
@@ -10,17 +10,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out the code
- uses: actions/checkout@96f53100ba2a5449eb71d2e6604bbcd94b9449b5
+ uses: actions/checkout@8b5e8b768746b50394015010d25e690bfab9dfbc
- name: Set up JDK 8
- uses: actions/setup-java@5b86b67f5bb794ee4de9464f70b700b9445b03a8
+ uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
with:
java-version: '8'
distribution: 'temurin'
cache: maven
- name: Initialize CodeQL
- uses: github/codeql-action/init@e683046da183a09174d531cc43713853e27debb3
+ uses: github/codeql-action/init@07d42ec34e55d7e17f411bffdf54e254effd68ae
with:
languages: java
@@ -36,7 +36,7 @@ jobs:
run: mvn --batch-mode --update-snapshots --activate-profiles e2e verify
- name: Upload coverage to Codecov
- uses: codecov/codecov-action@e1dd05cde2ed37d100f658b34ea423728ba1812e
+ uses: codecov/codecov-action@04adcebd9b38cae0bb0fd4a05e3497ce0bce41a0
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
flags: unittests # optional
@@ -45,4 +45,4 @@ jobs:
verbose: true # optional (default = false)
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@e683046da183a09174d531cc43713853e27debb3
+ uses: github/codeql-action/analyze@07d42ec34e55d7e17f411bffdf54e254effd68ae
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6a77578c..d433b047 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -19,7 +19,7 @@ jobs:
# Release-please creates a PR that tracks all changes
steps:
- - uses: google-github-actions/release-please-action@ca6063f4ed81b55db15b8c42d1b6f7925866342d
+ - uses: google-github-actions/release-please-action@01b3219546e6e7c4cfdaece8cd06efa464f49e2a
id: release
with:
command: manifest
@@ -29,10 +29,10 @@ jobs:
# These steps are only run if this was a merged release-please PR
- name: checkout
if: ${{ steps.release.outputs.releases_created }}
- uses: actions/checkout@96f53100ba2a5449eb71d2e6604bbcd94b9449b5
+ uses: actions/checkout@8b5e8b768746b50394015010d25e690bfab9dfbc
- name: Set up JDK 8
if: ${{ steps.release.outputs.releases_created }}
- uses: actions/setup-java@5b86b67f5bb794ee4de9464f70b700b9445b03a8
+ uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
with:
java-version: '8'
distribution: 'temurin'
diff --git a/.github/workflows/static-code-scanning.yaml b/.github/workflows/static-code-scanning.yaml
index e4a66ac5..f5558e99 100644
--- a/.github/workflows/static-code-scanning.yaml
+++ b/.github/workflows/static-code-scanning.yaml
@@ -29,16 +29,16 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@96f53100ba2a5449eb71d2e6604bbcd94b9449b5
+ uses: actions/checkout@8b5e8b768746b50394015010d25e690bfab9dfbc
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@e683046da183a09174d531cc43713853e27debb3
+ uses: github/codeql-action/init@07d42ec34e55d7e17f411bffdf54e254effd68ae
with:
languages: java
- name: Autobuild
- uses: github/codeql-action/autobuild@e683046da183a09174d531cc43713853e27debb3
+ uses: github/codeql-action/autobuild@07d42ec34e55d7e17f411bffdf54e254effd68ae
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@e683046da183a09174d531cc43713853e27debb3
+ uses: github/codeql-action/analyze@07d42ec34e55d7e17f411bffdf54e254effd68ae
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 287b4c71..4a8b7113 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1 +1 @@
-{".":"1.5.0"}
\ No newline at end of file
+{".":"1.6.0"}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 51917159..bb5e01d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,41 @@
# Changelog
+## [1.6.0](https://github.com/open-feature/java-sdk/compare/v1.5.0...v1.6.0) (2023-09-03)
+
+
+### ๐ Bug Fixes
+
+* **deps:** update dependency org.slf4j:slf4j-api to v2.0.9 ([#586](https://github.com/open-feature/java-sdk/issues/586)) ([84f72ac](https://github.com/open-feature/java-sdk/commit/84f72ac70d3b64975ee22ec73cf863db8c8a06af))
+
+
+### โจ New Features
+
+* add method to set provider and block during init ([#563](https://github.com/open-feature/java-sdk/issues/563)) ([506e89f](https://github.com/open-feature/java-sdk/commit/506e89fd348f107df0065c5e0b218abdded0efec))
+
+
+### ๐งน Chore
+
+* **deps:** update actions/checkout digest to 7739b9b ([#564](https://github.com/open-feature/java-sdk/issues/564)) ([adfb587](https://github.com/open-feature/java-sdk/commit/adfb58764a2073e6ac381d0c60199f27ba01d398))
+* **deps:** update actions/checkout digest to 8b5e8b7 ([#585](https://github.com/open-feature/java-sdk/issues/585)) ([9ae4407](https://github.com/open-feature/java-sdk/commit/9ae440786f6f56f73e85f163d71b75641950fc30))
+* **deps:** update actions/checkout digest to 97a652b ([#580](https://github.com/open-feature/java-sdk/issues/580)) ([816950a](https://github.com/open-feature/java-sdk/commit/816950a89589b6cbc2a702305681082075e90b1b))
+* **deps:** update actions/checkout digest to f43a0e5 ([#572](https://github.com/open-feature/java-sdk/issues/572)) ([46bbdcc](https://github.com/open-feature/java-sdk/commit/46bbdccf0f05a08eb31011cb26818ef2179f4c62))
+* **deps:** update actions/setup-java digest to 4075bfc ([#583](https://github.com/open-feature/java-sdk/issues/583)) ([8a38d12](https://github.com/open-feature/java-sdk/commit/8a38d12360ff7c7190113bfed9c01d8841af2cfe))
+* **deps:** update codecov/codecov-action digest to 04adceb ([#581](https://github.com/open-feature/java-sdk/issues/581)) ([30942af](https://github.com/open-feature/java-sdk/commit/30942afe842c5a868eace9653428469ee79791cf))
+* **deps:** update codecov/codecov-action digest to 6991c70 ([#575](https://github.com/open-feature/java-sdk/issues/575)) ([300c505](https://github.com/open-feature/java-sdk/commit/300c5054b93e8c0540e67450b707ac93880d0524))
+* **deps:** update codecov/codecov-action digest to 8ccb892 ([#570](https://github.com/open-feature/java-sdk/issues/570)) ([5d4230f](https://github.com/open-feature/java-sdk/commit/5d4230f0fd61570dfec5777343d0278a66a3cf0a))
+* **deps:** update codecov/codecov-action digest to c17956f ([#568](https://github.com/open-feature/java-sdk/issues/568)) ([666f784](https://github.com/open-feature/java-sdk/commit/666f784c2ea1ad2a027b1e4f7c011b7ff3011599))
+* **deps:** update codecov/codecov-action digest to de1b515 ([#573](https://github.com/open-feature/java-sdk/issues/573)) ([49e49cc](https://github.com/open-feature/java-sdk/commit/49e49cc9e4d4eacbc826b9893519e23758147f44))
+* **deps:** update github/codeql-action digest to 07d42ec ([#584](https://github.com/open-feature/java-sdk/issues/584)) ([91f7552](https://github.com/open-feature/java-sdk/commit/91f75527459695ff44126e0fec87c8848255208e))
+* **deps:** update github/codeql-action digest to 1009124 ([#576](https://github.com/open-feature/java-sdk/issues/576)) ([7b1eb1c](https://github.com/open-feature/java-sdk/commit/7b1eb1c035f35421a6527a4382e4dc837eb4b9b6))
+* **deps:** update github/codeql-action digest to 14877a1 ([#567](https://github.com/open-feature/java-sdk/issues/567)) ([9e14633](https://github.com/open-feature/java-sdk/commit/9e146330dfe6e25b6697a31c533a3f902bd32adb))
+* **deps:** update github/codeql-action digest to 8ecc33d ([#579](https://github.com/open-feature/java-sdk/issues/579)) ([2a0da51](https://github.com/open-feature/java-sdk/commit/2a0da511a75bc06ba4fb0b6761ddc2d121c024ca))
+* **deps:** update github/codeql-action digest to 9a53fd0 ([#569](https://github.com/open-feature/java-sdk/issues/569)) ([e423726](https://github.com/open-feature/java-sdk/commit/e4237262548e1af14273ac35b3609b9b684465ac))
+* **deps:** update github/codeql-action digest to b88b550 ([#578](https://github.com/open-feature/java-sdk/issues/578)) ([3142c43](https://github.com/open-feature/java-sdk/commit/3142c43c0565c1d86e46dab7215c9bbefb4fb59e))
+* **deps:** update github/codeql-action digest to c5acfe3 ([#582](https://github.com/open-feature/java-sdk/issues/582)) ([a4113c6](https://github.com/open-feature/java-sdk/commit/a4113c6308c557055e967e66f41f0a0e6ba62d56))
+* **deps:** update github/codeql-action digest to e426271 ([#566](https://github.com/open-feature/java-sdk/issues/566)) ([04adc3e](https://github.com/open-feature/java-sdk/commit/04adc3eb4d03417233a109e5d653925fbc01319a))
+* **deps:** update github/codeql-action digest to ff9cb43 ([#574](https://github.com/open-feature/java-sdk/issues/574)) ([dffa593](https://github.com/open-feature/java-sdk/commit/dffa59344089847628e8e5b22defbaa5b69c6d5e))
+* **deps:** update google-github-actions/release-please-action digest to 01b3219 ([#571](https://github.com/open-feature/java-sdk/issues/571)) ([e260022](https://github.com/open-feature/java-sdk/commit/e260022cf5a320239228ad9d793c830a845bc51e))
+
## [1.5.0](https://github.com/open-feature/java-sdk/compare/v1.4.3...v1.5.0) (2023-08-16)
diff --git a/README.md b/README.md
index 34f5ee44..6f3afdfd 100644
--- a/README.md
+++ b/README.md
@@ -18,8 +18,8 @@
-
-
+
+
@@ -59,7 +59,7 @@ Note that this library is intended to be used in server-side contexts and has no
dev.openfeature
sdk
- 1.5.0
+ 1.6.0
```
@@ -84,7 +84,7 @@ If you would like snapshot builds, this is the relevant repository information:
```groovy
dependencies {
- implementation 'dev.openfeature:sdk:1.5.0'
+ implementation 'dev.openfeature:sdk:1.6.0'
}
```
diff --git a/pom.xml b/pom.xml
index f0133467..56375a74 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
dev.openfeature
sdk
- 1.5.0
+ 1.6.0
UTF-8
@@ -60,7 +60,7 @@
org.slf4j
slf4j-api
- 2.0.7
+ 2.0.9
diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
index 94047b8c..47c09388 100644
--- a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
+++ b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
@@ -100,11 +100,12 @@ public EvaluationContext getEvaluationContext() {
public void setProvider(FeatureProvider provider) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
providerRepository.setProvider(
- provider,
- (p) -> attachEventProvider(p),
- (p) -> emitReady(p),
- (p) -> detachEventProvider(p),
- (p, message) -> emitError(p, message));
+ provider,
+ this::attachEventProvider,
+ this::emitReady,
+ this::detachEventProvider,
+ this::emitError,
+ false);
}
}
@@ -117,11 +118,45 @@ public void setProvider(FeatureProvider provider) {
public void setProvider(String clientName, FeatureProvider provider) {
try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
providerRepository.setProvider(clientName,
- provider,
- this::attachEventProvider,
- this::emitReady,
- this::detachEventProvider,
- this::emitError);
+ provider,
+ this::attachEventProvider,
+ this::emitReady,
+ this::detachEventProvider,
+ this::emitError,
+ false);
+ }
+ }
+
+ /**
+ * Set the default provider and wait for initialization to finish.
+ */
+ public void setProviderAndWait(FeatureProvider provider) {
+ try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
+ providerRepository.setProvider(
+ provider,
+ this::attachEventProvider,
+ this::emitReady,
+ this::detachEventProvider,
+ this::emitError,
+ true);
+ }
+ }
+
+ /**
+ * Add a provider for a named client and wait for initialization to finish.
+ *
+ * @param clientName The name of the client.
+ * @param provider The provider to set.
+ */
+ public void setProviderAndWait(String clientName, FeatureProvider provider) {
+ try (AutoCloseableLock __ = lock.writeLockAutoCloseable()) {
+ providerRepository.setProvider(clientName,
+ provider,
+ this::attachEventProvider,
+ this::emitReady,
+ this::detachEventProvider,
+ this::emitError,
+ true);
}
}
diff --git a/src/main/java/dev/openfeature/sdk/ProviderRepository.java b/src/main/java/dev/openfeature/sdk/ProviderRepository.java
index 0ff3b70b..b7d57049 100644
--- a/src/main/java/dev/openfeature/sdk/ProviderRepository.java
+++ b/src/main/java/dev/openfeature/sdk/ProviderRepository.java
@@ -43,8 +43,8 @@ public FeatureProvider getProvider(String name) {
public List getClientNamesForProvider(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 getAllBoundClientNames() {
@@ -62,58 +62,76 @@ public void setProvider(FeatureProvider provider,
Consumer afterSet,
Consumer afterInit,
Consumer afterShutdown,
- BiConsumer afterError) {
+ BiConsumer afterError,
+ boolean waitForInit) {
if (provider == null) {
throw new IllegalArgumentException("Provider cannot be null");
}
- initializeProvider(null, provider, afterSet, afterInit, afterShutdown, afterError);
+ prepareAndInitializeProvider(null, provider, afterSet, afterInit, afterShutdown, afterError, waitForInit);
}
/**
* Add a provider for a named client.
*
- * @param clientName The name of the client.
- * @param provider The provider to set.
+ * @param clientName The name of the client.
+ * @param provider The provider to set.
+ * @param waitForInit When true, wait for initialization to finish, then returns.
+ * Otherwise, initialization happens in the background.
*/
public void setProvider(String clientName,
- FeatureProvider provider,
- Consumer afterSet,
- Consumer afterInit,
- Consumer afterShutdown,
- BiConsumer afterError) {
+ FeatureProvider provider,
+ Consumer afterSet,
+ Consumer afterInit,
+ Consumer afterShutdown,
+ BiConsumer afterError,
+ boolean waitForInit) {
if (provider == null) {
throw new IllegalArgumentException("Provider cannot be null");
}
if (clientName == null) {
throw new IllegalArgumentException("clientName cannot be null");
}
- initializeProvider(clientName, provider, afterSet, afterInit, afterShutdown, afterError);
+ prepareAndInitializeProvider(clientName, provider, afterSet, afterInit, afterShutdown, afterError, waitForInit);
}
- private void initializeProvider(@Nullable String clientName,
- FeatureProvider newProvider,
- Consumer afterSet,
- Consumer afterInit,
- Consumer afterShutdown,
- BiConsumer afterError) {
+ private void prepareAndInitializeProvider(@Nullable String clientName,
+ FeatureProvider newProvider,
+ Consumer afterSet,
+ Consumer afterInit,
+ Consumer afterShutdown,
+ BiConsumer afterError,
+ boolean waitForInit) {
+
// provider is set immediately, on this thread
FeatureProvider oldProvider = clientName != null
- ? this.providers.put(clientName, newProvider)
- : this.defaultProvider.getAndSet(newProvider);
+ ? this.providers.put(clientName, newProvider)
+ : this.defaultProvider.getAndSet(newProvider);
afterSet.accept(newProvider);
- taskExecutor.submit(() -> {
- // initialization happens in a different thread
- try {
- if (ProviderState.NOT_READY.equals(newProvider.getState())) {
- newProvider.initialize(OpenFeatureAPI.getInstance().getEvaluationContext());
- afterInit.accept(newProvider);
- }
- shutDownOld(oldProvider, afterShutdown);
- } catch (Exception e) {
- log.error("Exception when initializing feature provider {}", newProvider.getClass().getName(), e);
- afterError.accept(newProvider, e.getMessage());
+ if (waitForInit) {
+ initializeProvider(newProvider, afterInit, afterShutdown, afterError, oldProvider);
+ } else {
+ taskExecutor.submit(() -> {
+ // initialization happens in a different thread if we're not waiting it
+ initializeProvider(newProvider, afterInit, afterShutdown, afterError, oldProvider);
+ });
+ }
+ }
+
+ private void initializeProvider(FeatureProvider newProvider,
+ Consumer afterInit,
+ Consumer afterShutdown,
+ BiConsumer afterError,
+ FeatureProvider oldProvider) {
+ try {
+ if (ProviderState.NOT_READY.equals(newProvider.getState())) {
+ newProvider.initialize(OpenFeatureAPI.getInstance().getEvaluationContext());
+ afterInit.accept(newProvider);
}
- });
+ shutDownOld(oldProvider, afterShutdown);
+ } catch (Exception e) {
+ log.error("Exception when initializing feature provider {}", newProvider.getClass().getName(), e);
+ afterError.accept(newProvider, e.getMessage());
+ }
}
private void shutDownOld(FeatureProvider oldProvider,Consumer afterShutdown) {
@@ -157,7 +175,7 @@ public void shutdown() {
},
(FeatureProvider fp,
String message) -> {
- });
+ }, false);
this.providers.clear();
taskExecutor.shutdown();
}
diff --git a/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java b/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java
index eb41fd95..35eb0769 100644
--- a/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java
+++ b/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java
@@ -17,6 +17,10 @@
import java.util.List;
import java.util.Map;
+import dev.openfeature.sdk.providers.memory.InMemoryProvider;
+import dev.openfeature.sdk.testutils.TestEventsProvider;
+import lombok.SneakyThrows;
+import org.awaitility.Awaitility;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -69,6 +73,34 @@ void getApiInstance() {
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() {
+ FeatureProvider provider = new TestEventsProvider(500);
+ OpenFeatureAPI.getInstance().setProviderAndWait(provider);
+ assertThat(api.getProvider().getState()).isEqualTo(ProviderState.READY);
+
+ provider = new TestEventsProvider(500);
+ String providerName = "providerAndWait";
+ OpenFeatureAPI.getInstance().setProviderAndWait(providerName, provider);
+ assertThat(api.getProvider(providerName).getState()).isEqualTo(ProviderState.READY);
+ }
+
+ @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 {
+ Awaitility.await().wait(3000);
+ }
+ };
+ String providerName = "shouldReturnNotReadyIfNotInitialized";
+ 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());
+ }
+
@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());
@@ -291,4 +323,5 @@ void getApiInstance() {
@Specification(number="1.4.11", text="The client SHOULD provide asynchronous or non-blocking mechanisms for flag evaluation.")
@Test void one_thread_per_request_model() {}
+
}
diff --git a/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java b/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java
index 5b6dac1b..0d4ae5d6 100644
--- a/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java
+++ b/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java
@@ -55,7 +55,7 @@ class DefaultProvider {
@DisplayName("should reject null as default provider")
void shouldRejectNullAsDefaultProvider() {
assertThatCode(() -> providerRepository.setProvider(null, mockAfterSet(), mockAfterInit(),
- mockAfterShutdown(), mockAfterError())).isInstanceOf(IllegalArgumentException.class);
+ mockAfterShutdown(), mockAfterError(), false)).isInstanceOf(IllegalArgumentException.class);
}
@Test
@@ -76,7 +76,7 @@ void shouldImmediatelyReturnWhenCallingTheProviderMutator() throws Exception {
.atMost(Duration.ofSeconds(1))
.until(() -> {
providerRepository.setProvider(featureProvider, mockAfterSet(), mockAfterInit(),
- mockAfterShutdown(), mockAfterError());
+ mockAfterShutdown(), mockAfterError(), false);
verify(featureProvider, timeout(TIMEOUT)).initialize(any());
return true;
});
@@ -101,7 +101,7 @@ class NamedProvider {
@DisplayName("should reject null as named provider")
void shouldRejectNullAsNamedProvider() {
assertThatCode(() -> providerRepository.setProvider(CLIENT_NAME, null, mockAfterSet(), mockAfterInit(),
- mockAfterShutdown(), mockAfterError()))
+ mockAfterShutdown(), mockAfterError(), false))
.isInstanceOf(IllegalArgumentException.class);
}
@@ -110,7 +110,7 @@ void shouldRejectNullAsNamedProvider() {
void shouldRejectNullAsDefaultProvider() {
NoOpProvider provider = new NoOpProvider();
assertThatCode(() -> providerRepository.setProvider(null, provider, mockAfterSet(), mockAfterInit(),
- mockAfterShutdown(), mockAfterError()))
+ mockAfterShutdown(), mockAfterError(), false))
.isInstanceOf(IllegalArgumentException.class);
}
@@ -126,7 +126,7 @@ void shouldImmediatelyReturnWhenCallingTheNamedClientProviderMutator() throws Ex
.atMost(Duration.ofSeconds(1))
.until(() -> {
providerRepository.setProvider("named client", featureProvider, mockAfterSet(),
- mockAfterInit(), mockAfterShutdown(), mockAfterError());
+ mockAfterInit(), mockAfterShutdown(), mockAfterError(), false);
verify(featureProvider, timeout(TIMEOUT)).initialize(any());
return true;
});
@@ -161,7 +161,7 @@ void shouldImmediatelyReturnWhenCallingTheProviderMutator() throws Exception {
.atMost(Duration.ofSeconds(1))
.until(() -> {
providerRepository.setProvider(newProvider, mockAfterSet(), mockAfterInit(),
- mockAfterShutdown(), mockAfterError());
+ mockAfterShutdown(), mockAfterError(), false);
verify(newProvider, timeout(TIMEOUT)).initialize(any());
return true;
});
@@ -194,7 +194,7 @@ void shouldImmediatelyReturnWhenCallingTheProviderMutator() throws Exception {
Future> providerMutation = executorService
.submit(() -> providerRepository.setProvider(CLIENT_NAME, newProvider, mockAfterSet(),
- mockAfterInit(), mockAfterShutdown(), mockAfterError()));
+ mockAfterInit(), mockAfterShutdown(), mockAfterError(), false));
await()
.alias("wait for provider mutator to return")
@@ -311,7 +311,7 @@ void shouldShutdownAllFeatureProvidersOnShutdown() {
private void setFeatureProvider(FeatureProvider provider) {
providerRepository.setProvider(provider, mockAfterSet(), mockAfterInit(), mockAfterShutdown(),
- mockAfterError());
+ mockAfterError(), false);
waitForSettingProviderHasBeenCompleted(ProviderRepository::getProvider, provider);
}
@@ -320,13 +320,13 @@ private void setFeatureProvider(FeatureProvider provider, Consumer afterInit, Consumer afterShutdown,
BiConsumer afterError) {
providerRepository.setProvider(provider, afterSet, afterInit, afterShutdown,
- afterError);
+ afterError, false);
waitForSettingProviderHasBeenCompleted(ProviderRepository::getProvider, provider);
}
private void setFeatureProvider(String namedProvider, FeatureProvider provider) {
providerRepository.setProvider(namedProvider, provider, mockAfterSet(), mockAfterInit(), mockAfterShutdown(),
- mockAfterError());
+ mockAfterError(), false);
waitForSettingProviderHasBeenCompleted(repository -> repository.getProvider(namedProvider), provider);
}
diff --git a/src/test/java/dev/openfeature/sdk/e2e/StepDefinitions.java b/src/test/java/dev/openfeature/sdk/e2e/StepDefinitions.java
index 903f0bf8..459fcefe 100644
--- a/src/test/java/dev/openfeature/sdk/e2e/StepDefinitions.java
+++ b/src/test/java/dev/openfeature/sdk/e2e/StepDefinitions.java
@@ -56,11 +56,7 @@ public class StepDefinitions {
public static void setup() {
Map> flags = buildFlags();
InMemoryProvider provider = new InMemoryProvider(flags);
- OpenFeatureAPI.getInstance().setProvider(provider);
-
- // TODO: setProvider with wait for init, pending https://github.com/open-feature/ofep/pull/80
- Thread.sleep(500);
-
+ OpenFeatureAPI.getInstance().setProviderAndWait(provider);
client = OpenFeatureAPI.getInstance().getClient();
}
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 4cfbb812..ffdc3182 100644
--- a/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java
+++ b/src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java
@@ -6,12 +6,13 @@
import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Value;
import dev.openfeature.sdk.exceptions.FlagNotFoundError;
+import dev.openfeature.sdk.exceptions.ProviderNotReadyError;
import dev.openfeature.sdk.exceptions.TypeMismatchError;
import lombok.SneakyThrows;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
-import org.omg.CORBA.DynAnyPackage.TypeMismatch;
+import java.util.HashMap;
import java.util.Map;
import static dev.openfeature.sdk.Structure.mapToStructure;
@@ -36,11 +37,7 @@ static void beforeAll() {
Map> flags = buildFlags();
provider = spy(new InMemoryProvider(flags));
OpenFeatureAPI.getInstance().onProviderConfigurationChanged(eventDetails -> {});
- OpenFeatureAPI.getInstance().setProvider(provider);
-
- // TODO: setProvider with wait for init, pending https://github.com/open-feature/ofep/pull/80
- Thread.sleep(500);
-
+ OpenFeatureAPI.getInstance().setProviderAndWait(provider);
client = OpenFeatureAPI.getInstance().getClient();
provider.updateFlags(flags);
provider.updateFlag("addedFlag", Flag.builder()
@@ -99,4 +96,13 @@ void typeMismatch() {
provider.getBooleanEvaluation("string-flag", false, new ImmutableContext());
});
}
+
+ @SneakyThrows
+ @Test
+ 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()));
+ }
}
\ No newline at end of file
diff --git a/src/test/java/dev/openfeature/sdk/testutils/TestEventsProvider.java b/src/test/java/dev/openfeature/sdk/testutils/TestEventsProvider.java
index 3fcb5888..25650bf6 100644
--- a/src/test/java/dev/openfeature/sdk/testutils/TestEventsProvider.java
+++ b/src/test/java/dev/openfeature/sdk/testutils/TestEventsProvider.java
@@ -15,19 +15,19 @@ public class TestEventsProvider extends EventProvider {
private String initErrorMessage;
private ProviderState state = ProviderState.NOT_READY;
private boolean shutDown = false;
- private int initTimeout = 0;
+ private int initTimeoutMs = 0;
@Override
public ProviderState getState() {
return this.state;
}
- public TestEventsProvider(int initTimeout) {
- this.initTimeout = initTimeout;
+ public TestEventsProvider(int initTimeoutMs) {
+ this.initTimeoutMs = initTimeoutMs;
}
- public TestEventsProvider(int initTimeout, boolean initError, String initErrorMessage) {
- this.initTimeout = initTimeout;
+ public TestEventsProvider(int initTimeoutMs, boolean initError, String initErrorMessage) {
+ this.initTimeoutMs = initTimeoutMs;
this.initError = initError;
this.initErrorMessage = initErrorMessage;
}
@@ -53,7 +53,7 @@ public void shutdown() {
public void initialize(EvaluationContext evaluationContext) throws Exception {
if (ProviderState.NOT_READY.equals(state)) {
// wait half the TIMEOUT, otherwise some init/errors can be fired before we add handlers
- Thread.sleep(initTimeout);
+ Thread.sleep(initTimeoutMs);
if (this.initError) {
this.state = ProviderState.ERROR;
throw new Exception(initErrorMessage);
diff --git a/version.txt b/version.txt
index bc80560f..dc1e644a 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.5.0
+1.6.0