Repository: open-feature/java-sdk
Pull request #563 (2023-08-16 16:14:52)

feat: add method to set provider and block during init
The API SHOULD provide functions to set a provider and wait for the initialize function to return or throw

## This PR
implements spec [Requirement 1.1.8](https://github.com/open-feature/spec/blob/ee80ce2c0dd4d2e2172638f5f3ff225989a85362/specification/sections/01-flag-evaluation.md#requirement-118).

following [blocking setProvider PR](https://github.com/open-feature/spec/pull/201).

liran2000: hi @toddbaert,

on the approach to implement it, I thought it can be good in this case to call initialize on the same caller thread as it needs to wait.

@thomaspoignant for your recent spec addition.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) Report
> Merging [#563](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) (229c4b1) into [main](https://app.codecov.io/gh/open-feature/java-sdk/commit/6c52ee464fdb5d5733cb5a31e9cfea1644840177?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) (6c52ee4) will **decrease** coverage by `0.97%`.
> Report is 2 commits behind head on main.
> The diff coverage is `89.92%`.

```diff
@@             Coverage Diff              @@
##               main     #563      +/-   ##
============================================
- Coverage     95.11%   94.15%   -0.97%     
- Complexity      329      369      +40     
============================================
  Files            31       32       +1     
  Lines           758      873     +115     
  Branches         37       51      +14     
============================================
+ Hits            721      822     +101     
- Misses           20       31      +11     
- Partials         17       20       +3     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `94.15% <89.92%> (-0.97%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Files Changed](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) | Coverage Δ | |
|---|---|---|
| [src/main/java/dev/openfeature/sdk/Value.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL1ZhbHVlLmphdmE=) | `90.09% <82.60%> (-1.96%)` | :arrow_down: |
| [...feature/sdk/providers/memory/InMemoryProvider.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL3Byb3ZpZGVycy9tZW1vcnkvSW5NZW1vcnlQcm92aWRlci5qYXZh) | `84.84% <84.84%> (ø)` | |
| [...ava/dev/openfeature/sdk/FlagEvaluationDetails.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL0ZsYWdFdmFsdWF0aW9uRGV0YWlscy5qYXZh) | `100.00% <100.00%> (ø)` | |
| [.../main/java/dev/openfeature/sdk/OpenFeatureAPI.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL09wZW5GZWF0dXJlQVBJLmphdmE=) | `100.00% <100.00%> (ø)` | |
| [...n/java/dev/openfeature/sdk/ProviderRepository.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL1Byb3ZpZGVyUmVwb3NpdG9yeS5qYXZh) | `98.63% <100.00%> (+0.26%)` | :arrow_up: |
| [src/main/java/dev/openfeature/sdk/Structure.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/563?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL1N0cnVjdHVyZS5qYXZh) | `88.37% <100.00%> (+0.87%)` | :arrow_up: |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature)

toddbaert: > hi @toddbaert,
> 
> on the approach to implement it, I thought it can be good in this case to call initialize on the same caller thread as it needs to wait.
> 
> @thomaspoignant for your recent spec addition.

I'm fine with this approach.
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=563)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [2 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list)


toddbaert: @liran2000 I've updated the PR title to be more "friendly" since it goes into our release notes.
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=563)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [2 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=563)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [2 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=563)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [2 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=563)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [2 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list)


toddbaert: @thomaspoignant since you came up with this spec proposal, I'm interested in your opinion of this implementation.
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=563)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [2 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=563)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL) [2 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=563&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=563&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
index 94047b8..47c0938 100644
--- a/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
+++ b/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
@@ -100,11 +100,12 @@ public class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
     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 class OpenFeatureAPI implements EventBus<OpenFeatureAPI> {
     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 0ff3b70..b7d5704 100644
--- a/src/main/java/dev/openfeature/sdk/ProviderRepository.java
+++ b/src/main/java/dev/openfeature/sdk/ProviderRepository.java
@@ -43,8 +43,8 @@ class ProviderRepository {
 
     public List<String> 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<String> getAllBoundClientNames() {
@@ -62,58 +62,76 @@ class ProviderRepository {
             Consumer<FeatureProvider> afterSet,
             Consumer<FeatureProvider> afterInit,
             Consumer<FeatureProvider> afterShutdown,
-            BiConsumer<FeatureProvider, String> afterError) {
+            BiConsumer<FeatureProvider, String> 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<FeatureProvider> afterSet,
-            Consumer<FeatureProvider> afterInit,
-            Consumer<FeatureProvider> afterShutdown,
-            BiConsumer<FeatureProvider, String> afterError) {
+             FeatureProvider provider,
+             Consumer<FeatureProvider> afterSet,
+             Consumer<FeatureProvider> afterInit,
+             Consumer<FeatureProvider> afterShutdown,
+             BiConsumer<FeatureProvider, String> 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<FeatureProvider> afterSet,
-            Consumer<FeatureProvider> afterInit,
-            Consumer<FeatureProvider> afterShutdown,
-            BiConsumer<FeatureProvider, String> afterError) {
+    private void prepareAndInitializeProvider(@Nullable String clientName,
+              FeatureProvider newProvider,
+              Consumer<FeatureProvider> afterSet,
+              Consumer<FeatureProvider> afterInit,
+              Consumer<FeatureProvider> afterShutdown,
+              BiConsumer<FeatureProvider, String> 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<FeatureProvider> afterInit,
+            Consumer<FeatureProvider> afterShutdown,
+            BiConsumer<FeatureProvider, String> 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<FeatureProvider> afterShutdown) {
@@ -157,7 +175,7 @@ class ProviderRepository {
                 },
                 (FeatureProvider fp,
                         String message) -> {
-                });
+                }, false);
         this.providers.clear();
         taskExecutor.shutdown();
     }


Test patch:
diff --git a/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java b/src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java
index eb41fd9..35eb076 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.HashMap;
 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 @@ class FlagEvaluationSpecTest implements HookFixtures {
         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 @@ class FlagEvaluationSpecTest implements HookFixtures {
 
     @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 5b6dac1..0d4ae5d 100644
--- a/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java
+++ b/src/test/java/dev/openfeature/sdk/ProviderRepositoryTest.java
@@ -55,7 +55,7 @@ class ProviderRepositoryTest {
             @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 @@ class ProviderRepositoryTest {
                         .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 ProviderRepositoryTest {
             @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 @@ class ProviderRepositoryTest {
             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 @@ class ProviderRepositoryTest {
                         .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 @@ class ProviderRepositoryTest {
                         .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 @@ class ProviderRepositoryTest {
 
                 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 @@ class ProviderRepositoryTest {
 
     private void setFeatureProvider(FeatureProvider provider) {
         providerRepository.setProvider(provider, mockAfterSet(), mockAfterInit(), mockAfterShutdown(),
-                mockAfterError());
+                mockAfterError(), false);
         waitForSettingProviderHasBeenCompleted(ProviderRepository::getProvider, provider);
     }
 
@@ -320,13 +320,13 @@ class ProviderRepositoryTest {
             Consumer<FeatureProvider> afterInit, Consumer<FeatureProvider> afterShutdown,
             BiConsumer<FeatureProvider, String> 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 903f0bf..459fcef 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<String, Flag<?>> 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 4cfbb81..ffdc318 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.ImmutableContext;
 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 @@ class InMemoryProviderTest {
         Map<String, Flag<?>> 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 @@ class InMemoryProviderTest {
             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 3fcb588..25650bf 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 class TestEventsProvider extends EventProvider {
     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);