Conversation
1cd8040 to
4f02169
Compare
4f02169 to
a53abd3
Compare
| @@ -26,10 +28,10 @@ byte[] getContentHash() { | |||
| } | |||
|
|
|||
| ProviderEvaluation<Boolean> evaluate(String slug, Boolean defaultValue, EvaluationContext evaluationContext) { | |||
There was a problem hiding this comment.
This method mostly matches the .NET equivalent logically, though with a different shape. I propose that we align them further prior to the next piece of work in this area.
| if (rolloutPercentage < 100) { | ||
| return ProviderEvaluation.<Boolean>builder() | ||
| .value(false) | ||
| .reason(Reason.TARGETING_MATCH.toString()) |
There was a problem hiding this comment.
There was a problem hiding this comment.
| return null; | ||
| } | ||
| List<FeatureToggleEvaluation> evaluations = OctopusObjectMapper.INSTANCE.readValue(httpResponse.body(), new TypeReference<>(){}); | ||
| var evaluations = OctopusObjectMapper.INSTANCE.readValue(httpResponse.body(), new TypeReference<List<FeatureToggleEvaluation>>(){}); |
There was a problem hiding this comment.
I lied in my last PR. Well, not that I lied, but I did think we were on Java 8 rather than 11.
There was a problem hiding this comment.
Pull request overview
Adds client-side fractional (percentage) rollout evaluation to the Java OpenFeature provider, aligning behavior with the .NET provider and re-enabling the spec fixture suite.
Changes:
- Introduced MurmurHash3-based bucketing (evaluationKey + targetingKey) to support percentage rollouts.
- Updated evaluation flow in
OctopusContextto incorporate rollout checks before segment matching. - Reworked/expanded tests (including re-enabling spec fixture tests) to validate cross-SDK-consistent bucketing and evaluation behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/main/java/com/octopus/openfeature/provider/OctopusContext.java |
Implements normalized bucketing via MurmurHash3 and integrates rollout gating into flag evaluation flow. |
src/test/java/com/octopus/openfeature/provider/OctopusContextTests.java |
Replaces prior tests with extensive rollout + segment evaluation cases and cross-SDK bucketing vectors. |
src/test/java/com/octopus/openfeature/provider/SpecificationTests.java |
Re-enables parameterized specification fixture tests. |
src/test/java/com/octopus/openfeature/provider/FeatureToggleEvaluationDeserializationTests.java |
Tightens TypeReference typing for toggle list deserialization. |
src/main/java/com/octopus/openfeature/provider/OctopusClient.java |
Tightens TypeReference typing when deserializing toggle evaluations. |
pom.xml |
Adds Apache Commons Codec dependency for MurmurHash3. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // MurmurHash3 32-bit, seed 0. hash32x86 processes tail bytes in little-endian order, | ||
| // matching the reference C spec and equivalent to .NET's MurmurHash.Create32() + | ||
| // BinaryPrimitives.ReadUInt32LittleEndian(). | ||
| int hash = MurmurHash3.hash32x86(bytes, 0, bytes.length, 0); |
| ); | ||
| var subject = new OctopusContext(toggles); | ||
| assertThrows(FlagNotFoundError.class, () -> subject.evaluate("This is clearly not a slug!", true, null)); | ||
| } |
There was a problem hiding this comment.
Should we also assert here that it's resolving to the default value?
There was a problem hiding this comment.
This is a side effect of the Java library throwing exceptions instead of returning ProviderEvaluation: it is relying on the OpenFeature SDK to catch the exception and returning the default value.
As these are unit tests for OctopusContext I don't think we can assert the default value.
There is an equivalent specification test disabled when default value is false and slug is not a slug that I think we can lean on instead.
| ); | ||
| var subject = new OctopusContext(toggles); | ||
| assertThrows(FlagNotFoundError.class, () -> subject.evaluate("anotherfeature", true, null)); | ||
| } |
There was a problem hiding this comment.
Same answer too. :)
| var result = subject.evaluate("Enabled-Feature", false, null); | ||
| void whenTargetingKeyFallsWithinRolloutPercentage_AndFeatureIsNotToggledForSegments_ResolvesToTrue() { | ||
| // "evaluation-key:targeting-key" is known to hash to bucket 13 | ||
| // rollout=13 → bucket(13) <= rollout(13) → within → true |
There was a problem hiding this comment.
Maybe we could simplify this comment for the benefit our futures selves... 😜 E.g.
// "evaluation-key:targeting-key" is known to hash to bucket 13.
// Rollout is to 13%. Therefore bucket is <= rollout percentage.
There was a problem hiding this comment.
You could probably say the same for my comments on the .NET version too.
There was a problem hiding this comment.
Yeah, I didn't love these either. Let me see if I can improve.
| // implementations in other Octopus OpenFeature provider libraries (e.g. .NET). The expected values | ||
| // are derived from the reference MurmurHash3 little-endian algorithm and are duplicated verbatim | ||
| // across all libraries. DO NOT modify the input arguments or expected values — doing so would mask | ||
| // a real divergence in evaluation behaviour between libraries and defeat the purpose of this test. |
caitlynstocker
left a comment
There was a problem hiding this comment.
Have picked thought this and it all makes sense to me 😄 Has it been manually tested as well? If so, I've added a few tiny comments but otherwise I'm confident to approve it.
@caitlynstocker, I have done a smoke test against a local instance of OctoToggle. That, combined with the specification tests, gives me reasonable confidence. |
Background
We are implementing client-side percentage rollout evaluation to our three OpenFeature provider libraries.
The .NET provider had this added in OctopusDeploy/openfeature-provider-dotnet#45.
This PR adds this to the Java library.
Resolves https://linear.app/octopus/issue/DEVEX-82/add-fractional-evaluation-support-to-java-client-library
Changes
OctopusContextto have the same logical flow as the .NET equivalent, including implementinggetNormalizeNumberto hash theevaluationKey+targetingKeyfor percentage rollout.OctopusContextTestsreplace existing tests and these now align with the .NET equivalents to ensure consistent evaluation.Notes for review
Reasonoptions chosen. It may be good to talk these through. Or perhaps ignore them until we do reasons properly and across our feature toggles ecosystem.