From 29032f6bdf33d7dc830cdcc30205a10071167b89 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Thu, 14 Aug 2025 16:50:31 -0300 Subject: [PATCH 01/10] Update dependencies --- CHANGES.txt | 12 +++++-- README.md | 24 +++++++++----- pom.xml | 31 +++++++++---------- .../java/io/split/openfeature/ClientTest.java | 6 ++-- .../split/openfeature/SplitProviderTest.java | 5 ++- 5 files changed, 44 insertions(+), 34 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 0cd9583..5433234 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,10 @@ -1.0.0 -- First release. Up to date with java sdk v0.1.0 +1.2.0 (August XX, 2025) + - Updated `io.split.client` dependency to 4.16.1 + - Updated `dev.openfeature` dependency to 1.16.0 + 1.1.0 -- Up tp date with spec v0.5.0 and java sdk v0.3.1 + - Up tp date with spec v0.5.0 and java sdk v0.3.1 + +1.0.0 + - First release. Up to date with java sdk v0.1.0 + diff --git a/README.md b/README.md index 19beb5e..1114f87 100644 --- a/README.md +++ b/README.md @@ -85,17 +85,25 @@ To learn more about Split, contact hello@split.io, or get started with feature f Split has built and maintains SDKs for: -* Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK) -* Javascript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK) -* Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK) * .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK) -* Ruby [Github](https://github.com/splitio/ruby-client) [Docs](https://help.split.io/hc/en-us/articles/360020673251-Ruby-SDK) -* PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK) -* Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK) -* GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK) * Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK) +* Angular [Github](https://github.com/splitio/angular-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/6495326064397-Angular-utilities) +* Elixir thin-client [Github](https://github.com/splitio/elixir-thin-client) [Docs](https://help.split.io/hc/en-us/articles/26988707417869-Elixir-Thin-Client-SDK) +* Flutter [Github](https://github.com/splitio/flutter-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/8096158017165-Flutter-plugin) +* GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK) * iOS [Github](https://github.com/splitio/ios-client) [Docs](https://help.split.io/hc/en-us/articles/360020401491-iOS-SDK) - +* Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK) +* JavaScript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK) +* JavaScript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK) +* Node.js [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK) +* PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK) +* PHP thin-client [Github](https://github.com/splitio/php-thin-client) [Docs](https://help.split.io/hc/en-us/articles/18305128673933-PHP-Thin-Client-SDK) +* Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK) +* React [Github](https://github.com/splitio/react-client) [Docs](https://help.split.io/hc/en-us/articles/360038825091-React-SDK) +* React Native [Github](https://github.com/splitio/react-native-client) [Docs](https://help.split.io/hc/en-us/articles/4406066357901-React-Native-SDK) +* Redux [Github](https://github.com/splitio/redux-client) [Docs](https://help.split.io/hc/en-us/articles/360038851551-Redux-SDK) +* Ruby [Github](https://github.com/splitio/ruby-client) [Docs](https://help.split.io/hc/en-us/articles/360020673251-Ruby-SDK) + For a comprehensive list of open source projects visit our [Github page](https://github.com/splitio?utf8=%E2%9C%93&query=%20only%3Apublic%20). **Learn more about Split:** diff --git a/pom.xml b/pom.xml index 66c81c7..8c3618b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.split.openfeature split-openfeature-provider - 1.1.0 + 1.2.0 split-openfeature-provider-java Split OpenFeature Java Provider @@ -23,6 +23,10 @@ Robert Grassian robert.grassian@split.io + + Emmanuel Zamora + emmanuel.zamora@harness.io + @@ -34,32 +38,27 @@ UTF-8 - 1.7 - 1.7 + 11 + 5.10.2 + 3.2.5 org.junit.jupiter - junit-jupiter-engine - 5.4.0 - test - - - org.junit.vintage - junit-vintage-engine - 5.4.0 + junit-jupiter + ${junit.jupiter.version} test io.split.client java-client - 4.4.3 + 4.16.1 org.apache.httpcomponents httpclient - 4.5.13 + 4.5.14 io.split.integrations.azure @@ -75,7 +74,7 @@ dev.openfeature sdk - 0.3.1 + 1.16.0 @@ -143,7 +142,7 @@ -Xdoclint:none - 1.8 + 11 @@ -151,7 +150,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.3 + 1.6.13 true true diff --git a/src/test/java/io/split/openfeature/ClientTest.java b/src/test/java/io/split/openfeature/ClientTest.java index 88a0f63..80314f4 100644 --- a/src/test/java/io/split/openfeature/ClientTest.java +++ b/src/test/java/io/split/openfeature/ClientTest.java @@ -42,9 +42,8 @@ public void init() { System.out.println("Unexpected Exception occurred initializing Split Provider."); } client = openFeatureAPI.getClient("Split Client"); - EvaluationContext evaluationContext = new MutableContext(); String targetingKey = "key"; - evaluationContext.setTargetingKey(targetingKey); + EvaluationContext evaluationContext = new MutableContext(targetingKey); client.setEvaluationContext(evaluationContext); } @@ -106,8 +105,7 @@ public void getBooleanSplitWithKeyTest() { // if we override the evaluation context for this check to use a different key, // this should take priority, and therefore we should receive a treatment of off - EvaluationContext evaluationContext = new MutableContext(); - evaluationContext.setTargetingKey("randomKey"); + EvaluationContext evaluationContext = new MutableContext("randomKey"); result = client.getBooleanValue("my_feature", true, evaluationContext); assertFalse(result); } diff --git a/src/test/java/io/split/openfeature/SplitProviderTest.java b/src/test/java/io/split/openfeature/SplitProviderTest.java index 64ff453..65296cd 100644 --- a/src/test/java/io/split/openfeature/SplitProviderTest.java +++ b/src/test/java/io/split/openfeature/SplitProviderTest.java @@ -35,12 +35,11 @@ public class SplitProviderTest { private SplitClient mockSplitClient; @BeforeEach - private void init() { + public void init() { MockitoAnnotations.openMocks(this); key = "key"; - evaluationContext = new MutableContext(); - evaluationContext.setTargetingKey(key); + evaluationContext = new MutableContext(key); } @Test From 6316d664ab1d179bfef93ab504ba15680127670d Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Thu, 28 Aug 2025 13:35:33 -0300 Subject: [PATCH 02/10] Add track and evaluate with details --- pom.xml | 5 +- .../io/split/openfeature/SplitProvider.java | 159 ++++++++++-------- .../java/io/split/openfeature/ClientTest.java | 25 ++- .../split/openfeature/SplitProviderTest.java | 123 ++++++++++---- 4 files changed, 208 insertions(+), 104 deletions(-) diff --git a/pom.xml b/pom.xml index 8c3618b..601ffbd 100644 --- a/pom.xml +++ b/pom.xml @@ -74,7 +74,7 @@ dev.openfeature sdk - 1.16.0 + 1.17.0 @@ -126,6 +126,7 @@ org.apache.maven.plugins maven-compiler-plugin + 3.13.0 11 11 @@ -134,6 +135,7 @@ org.apache.maven.plugins maven-javadoc-plugin + 3.11.3 attach-javadocs @@ -159,6 +161,7 @@ org.apache.maven.plugins maven-source-plugin + 3.3.1 attach-sources diff --git a/src/main/java/io/split/openfeature/SplitProvider.java b/src/main/java/io/split/openfeature/SplitProvider.java index c2d1437..fbed871 100644 --- a/src/main/java/io/split/openfeature/SplitProvider.java +++ b/src/main/java/io/split/openfeature/SplitProvider.java @@ -3,21 +3,26 @@ import dev.openfeature.sdk.ErrorCode; import dev.openfeature.sdk.EvaluationContext; import dev.openfeature.sdk.FeatureProvider; +import dev.openfeature.sdk.ImmutableMetadata; import dev.openfeature.sdk.Metadata; import dev.openfeature.sdk.MutableStructure; import dev.openfeature.sdk.ProviderEvaluation; import dev.openfeature.sdk.Reason; +import dev.openfeature.sdk.TrackingEventDetails; import dev.openfeature.sdk.Value; import dev.openfeature.sdk.exceptions.GeneralError; import dev.openfeature.sdk.exceptions.OpenFeatureError; import dev.openfeature.sdk.exceptions.ParseError; import dev.openfeature.sdk.exceptions.TargetingKeyMissingError; import io.split.client.SplitClient; +import io.split.client.api.SplitResult; import io.split.openfeature.utils.Serialization; import java.time.Instant; import java.time.format.DateTimeParseException; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; public class SplitProvider implements FeatureProvider { @@ -44,126 +49,138 @@ public Metadata getMetadata() { } @Override - public ProviderEvaluation getBooleanEvaluation(String key, Boolean defaultTreatment, EvaluationContext evaluationContext) { - try { - String evaluated = evaluateTreatment(key, evaluationContext); - if (noTreatment(evaluated)) { - return constructProviderEvaluation(defaultTreatment, evaluated, Reason.DEFAULT, ErrorCode.FLAG_NOT_FOUND); - } + public ProviderEvaluation getBooleanEvaluation( + String key, Boolean defaultVal, EvaluationContext ctx) { + return getEvaluation(key, defaultVal, ctx, s -> { // if treatment is "on" or "true" we treat that as true // if it is "off" or "false" we treat it as false // if it is some other value we throw an error (sdk will catch it and throw default treatment) - boolean value; - if (Boolean.parseBoolean(evaluated) || evaluated.equals("on")) { - value = true; - } else if (evaluated.equalsIgnoreCase("false") || evaluated.equals("off")) { - value = false; + if (Boolean.parseBoolean(s) || s.equals("on")) { + return true; + } else if (s.equalsIgnoreCase("false") || s.equals("off")) { + return false; } else { throw new ParseError(); } - return constructProviderEvaluation(value, evaluated); - } catch (OpenFeatureError e) { - throw e; - } catch (Exception e) { - throw new GeneralError("Error getting boolean evaluation", e); - } + }, "Boolean"); + } + @Override + public ProviderEvaluation getStringEvaluation( + String key, String defaultVal, EvaluationContext ctx) { + return getEvaluation(key, defaultVal, ctx, s -> s, "String"); } @Override - public ProviderEvaluation getStringEvaluation(String key, String defaultTreatment, EvaluationContext evaluationContext) { - try { - String evaluated = evaluateTreatment(key, evaluationContext); - if (noTreatment(evaluated)) { - return constructProviderEvaluation(defaultTreatment, evaluated, Reason.DEFAULT, ErrorCode.FLAG_NOT_FOUND); - } - return constructProviderEvaluation(evaluated, evaluated); - } catch (OpenFeatureError e) { - throw e; - } catch (Exception e) { - throw new GeneralError("Error getting String evaluation", e); - } + public ProviderEvaluation getIntegerEvaluation( + String key, Integer defaultVal, EvaluationContext ctx) { + return getEvaluation(key, defaultVal, ctx, Integer::valueOf, "Integer"); } @Override - public ProviderEvaluation getIntegerEvaluation(String key, Integer defaultTreatment, EvaluationContext evaluationContext) { - try { - String evaluated = evaluateTreatment(key, evaluationContext); - if (noTreatment(evaluated)) { - return constructProviderEvaluation(defaultTreatment, evaluated, Reason.DEFAULT, ErrorCode.FLAG_NOT_FOUND); - } - Integer value = Integer.valueOf(evaluated); - return constructProviderEvaluation(value, evaluated); - } catch (OpenFeatureError e) { - throw e; - } catch (NumberFormatException e) { - throw new ParseError(); - } catch (Exception e) { - throw new GeneralError("Error getting Integer evaluation", e); - } + public ProviderEvaluation getDoubleEvaluation( + String key, Double defaultTreatment, EvaluationContext ctx) { + + return getEvaluation(key, defaultTreatment, ctx, s -> { + if (s == null) throw new NumberFormatException("null"); + return Double.valueOf(s.trim()); + }, "Double"); } @Override - public ProviderEvaluation getDoubleEvaluation(String key, Double defaultTreatment, EvaluationContext evaluationContext) { + public ProviderEvaluation getObjectEvaluation( + String key, Value defaultVal, EvaluationContext ctx) { + return getEvaluation(key, defaultVal, ctx, s -> { + Map rawMap = Serialization.stringToMap(s); + return mapToValue(rawMap); + }, "Object"); + } + + @FunctionalInterface + interface Mapper { + T map(String s) throws Exception; + } + + private ProviderEvaluation getEvaluation( + String key, + T defaultValue, + EvaluationContext ctx, + Mapper mapper, + String typeLabel + ) { try { - String evaluated = evaluateTreatment(key, evaluationContext); - if (noTreatment(evaluated)) { - return constructProviderEvaluation(defaultTreatment, evaluated, Reason.DEFAULT, ErrorCode.FLAG_NOT_FOUND); + SplitResult evaluated = evaluateTreatment(key, ctx); + String treatment = evaluated.treatment(); + String config = evaluated.config(); + ImmutableMetadata metadata = ImmutableMetadata.builder().addString("config", config).build(); + System.out.println(metadata.getString("config")); + if (noTreatment(treatment)) { + return constructProviderEvaluation( + defaultValue, treatment, Reason.DEFAULT, ErrorCode.FLAG_NOT_FOUND, metadata); } - Double value = Double.valueOf(evaluated); - return constructProviderEvaluation(value, evaluated); + T mapped = mapper.map(treatment); + return constructProviderEvaluation(mapped, treatment, metadata); + } catch (OpenFeatureError e) { throw e; - } catch (NumberFormatException e) { - throw new ParseError(); } catch (Exception e) { - throw new GeneralError("Error getting Double evaluation", e); + throw new GeneralError("Error getting " + typeLabel + " evaluation", e); } } @Override - public ProviderEvaluation getObjectEvaluation(String key, Value defaultTreatment, EvaluationContext evaluationContext) { - try { - String evaluated = evaluateTreatment(key, evaluationContext); - if (noTreatment(evaluated)) { - return constructProviderEvaluation(defaultTreatment, evaluated, Reason.DEFAULT, ErrorCode.FLAG_NOT_FOUND); - } - Map rawMap = Serialization.stringToMap(evaluated); - Value value = mapToValue(rawMap); - return constructProviderEvaluation(value, evaluated); - } catch (OpenFeatureError e) { - throw e; - } catch (Exception e) { - throw new GeneralError("Error getting Object evaluation", e); + public void track(String eventName, EvaluationContext context, TrackingEventDetails details) { + + // targetingKey is always required + String key = context.getTargetingKey(); + if (key == null || key.isEmpty()) throw new TargetingKeyMissingError(); + + // eventName is always required + if (eventName == null || eventName.isBlank()) throw new GeneralError("Missing eventName, required to track"); + + // trafficType is always required + Value ttVal = context.getValue("trafficType"); + String trafficType = (ttVal != null && !ttVal.isNull() && ttVal.isString()) ? ttVal.asString() : null; + if (trafficType == null || trafficType.isBlank()) throw new GeneralError("Missing trafficType variable, required to track"); + + double value = 0; + Map attributes = new HashMap<>(); + if (details != null) { + Optional optionalValue = details.getValue(); + value = optionalValue.orElse(0).doubleValue(); + attributes = details.asObjectMap(); } + + client.track(key, trafficType, eventName, value, attributes); } public Map transformContext(EvaluationContext context) { return context.asObjectMap(); } - private String evaluateTreatment(String key, EvaluationContext evaluationContext) { + private SplitResult evaluateTreatment(String key, EvaluationContext evaluationContext) { String id = evaluationContext.getTargetingKey(); if (id == null || id.isEmpty()) { // targeting key is always required throw new TargetingKeyMissingError(); } Map attributes = transformContext(evaluationContext); - return client.getTreatment(id, key, attributes); + return client.getTreatmentWithConfig(id, key, attributes); } private boolean noTreatment(String treatment) { return treatment == null || treatment.isEmpty() || treatment.equals("control"); } - private ProviderEvaluation constructProviderEvaluation(T value, String variant) { - return constructProviderEvaluation(value, variant, Reason.TARGETING_MATCH, null); + private ProviderEvaluation constructProviderEvaluation(T value, String variant, ImmutableMetadata metadata) { + return constructProviderEvaluation(value, variant, Reason.TARGETING_MATCH, null, metadata); } - private ProviderEvaluation constructProviderEvaluation(T value, String variant, Reason reason, ErrorCode errorCode) { + private ProviderEvaluation constructProviderEvaluation(T value, String variant, Reason reason, ErrorCode errorCode, ImmutableMetadata metadata) { ProviderEvaluation.ProviderEvaluationBuilder builder = ProviderEvaluation.builder(); return builder .value(value) + .flagMetadata(metadata) .reason(reason.name()) .variant(variant) .errorCode(errorCode) diff --git a/src/test/java/io/split/openfeature/ClientTest.java b/src/test/java/io/split/openfeature/ClientTest.java index 80314f4..8856b89 100644 --- a/src/test/java/io/split/openfeature/ClientTest.java +++ b/src/test/java/io/split/openfeature/ClientTest.java @@ -148,6 +148,7 @@ public void getBooleanDetailsTest() { assertFalse(details.getValue()); // the flag has a treatment of "off", this is returned as a value of false but the variant is still "off" assertEquals("off", details.getVariant()); + assertNull(details.getFlagMetadata().getString("config")); assertNull(details.getErrorCode()); } @@ -159,17 +160,30 @@ public void getIntegerDetailsTest() { assertEquals(32, details.getValue()); // the flag has a treatment of "32", this is resolved to an integer but the variant is still "32" assertEquals("32", details.getVariant()); + assertNull(details.getFlagMetadata().getString("config")); assertNull(details.getErrorCode()); } @Test - public void getStringDetailsTest() { + public void getStringWithDetailsTest() { + FlagEvaluationDetails details = client.getStringDetails("my_feature", "key"); + assertEquals("my_feature", details.getFlagKey()); + assertEquals(Reason.TARGETING_MATCH.name(), details.getReason()); + assertEquals("on", details.getValue()); + assertEquals("on", details.getVariant()); + assertEquals("{\"desc\" : \"this applies only to ON treatment\"}", details.getFlagMetadata().getString("config")); + assertNull(details.getErrorCode()); + } + + @Test + public void getStringWithoutDetailsTest() { FlagEvaluationDetails details = client.getStringDetails("some_other_feature", "blah"); assertEquals("some_other_feature", details.getFlagKey()); assertEquals(Reason.TARGETING_MATCH.name(), details.getReason()); assertEquals("off", details.getValue()); // the flag has a treatment of "off", since this is a string the variant is the same as the value assertEquals("off", details.getVariant()); + assertNull(details.getFlagMetadata().getString("config")); assertNull(details.getErrorCode()); } @@ -181,6 +195,7 @@ public void getObjectDetailsTest() { assertEquals(mapToValue(Map.of("key", new Value("value"))), details.getValue()); // the flag's treatment is stored as a string, and the variant is that raw string assertEquals("{\"key\": \"value\"}", details.getVariant()); + assertNull(details.getFlagMetadata().getString("config")); assertNull(details.getErrorCode()); } @@ -192,6 +207,7 @@ public void getDoubleDetailsTest() { assertEquals(32D, details.getValue()); // the flag has a treatment of "32", this is resolved to a double but the variant is still "32" assertEquals("32", details.getVariant()); + assertNull(details.getFlagMetadata().getString("config")); assertNull(details.getErrorCode()); } @@ -205,6 +221,7 @@ public void getBooleanFailTest() { assertFalse(details.getValue()); assertEquals(ErrorCode.PARSE_ERROR, details.getErrorCode()); assertEquals(Reason.ERROR.name(), details.getReason()); + assertNull(details.getFlagMetadata().getString("config")); assertNull(details.getVariant()); } @@ -216,8 +233,9 @@ public void getIntegerFailTest() { FlagEvaluationDetails details = client.getIntegerDetails("obj_feature", 10); assertEquals(10, details.getValue()); - assertEquals(ErrorCode.PARSE_ERROR, details.getErrorCode()); + assertEquals(ErrorCode.GENERAL, details.getErrorCode()); assertEquals(Reason.ERROR.name(), details.getReason()); + assertNull(details.getFlagMetadata().getString("config")); assertNull(details.getVariant()); } @@ -229,8 +247,9 @@ public void getDoubleFailTest() { FlagEvaluationDetails details = client.getDoubleDetails("obj_feature", 10D); assertEquals(10D, details.getValue()); - assertEquals(ErrorCode.PARSE_ERROR, details.getErrorCode()); + assertEquals(ErrorCode.GENERAL, details.getErrorCode()); assertEquals(Reason.ERROR.name(), details.getReason()); + assertNull(details.getFlagMetadata().getString("config")); assertNull(details.getVariant()); } diff --git a/src/test/java/io/split/openfeature/SplitProviderTest.java b/src/test/java/io/split/openfeature/SplitProviderTest.java index 65296cd..d5c0dc8 100644 --- a/src/test/java/io/split/openfeature/SplitProviderTest.java +++ b/src/test/java/io/split/openfeature/SplitProviderTest.java @@ -3,12 +3,15 @@ import dev.openfeature.sdk.ErrorCode; import dev.openfeature.sdk.EvaluationContext; import dev.openfeature.sdk.MutableContext; +import dev.openfeature.sdk.MutableTrackingEventDetails; import dev.openfeature.sdk.MutableStructure; import dev.openfeature.sdk.ProviderEvaluation; +import dev.openfeature.sdk.TrackingEventDetails; import dev.openfeature.sdk.Value; import dev.openfeature.sdk.exceptions.GeneralError; import dev.openfeature.sdk.exceptions.OpenFeatureError; import io.split.client.SplitClient; +import io.split.client.api.SplitResult; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; @@ -21,10 +24,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; + import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; public class SplitProviderTest { @@ -64,7 +73,7 @@ public void evalBooleanNullEmptyTest() { String flagName = "flagName"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(null); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(null,"")); ProviderEvaluation response = splitProvider.getBooleanEvaluation(flagName, false, evaluationContext); assertFalse(response.getValue()); @@ -72,7 +81,7 @@ public void evalBooleanNullEmptyTest() { response = splitProvider.getBooleanEvaluation(flagName, true, evaluationContext); assertTrue(response.getValue()); - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(""); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("","")); response = splitProvider.getBooleanEvaluation(flagName, false, evaluationContext); assertFalse(response.getValue()); @@ -88,7 +97,7 @@ public void evalBooleanControlTest() { String flagName = "flagName"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("control"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("control","")); ProviderEvaluation response = splitProvider.getBooleanEvaluation(flagName, false, evaluationContext); assertFalse(response.getValue()); @@ -103,7 +112,7 @@ public void evalBooleanTrueTest() { SplitProvider splitProvider = new SplitProvider(mockSplitClient); String flagName = "flagName"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("true"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("true","")); ProviderEvaluation response = splitProvider.getBooleanEvaluation(flagName, false, evaluationContext); assertTrue(response.getValue()); @@ -115,7 +124,7 @@ public void evalBooleanOnTest() { SplitProvider splitProvider = new SplitProvider(mockSplitClient); String flagName = "flagName"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("on"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("on","")); ProviderEvaluation response = splitProvider.getBooleanEvaluation(flagName, false, evaluationContext); assertTrue(response.getValue()); @@ -127,7 +136,7 @@ public void evalBooleanFalseTest() { SplitProvider splitProvider = new SplitProvider(mockSplitClient); String flagName = "flagName"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("false"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("false","")); ProviderEvaluation response = splitProvider.getBooleanEvaluation(flagName, false, evaluationContext); assertFalse(response.getValue()); @@ -139,7 +148,7 @@ public void evalBooleanOffTest() { SplitProvider splitProvider = new SplitProvider(mockSplitClient); String flagName = "flagName"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("off"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("off","")); ProviderEvaluation response = splitProvider.getBooleanEvaluation(flagName, false, evaluationContext); assertFalse(response.getValue()); @@ -151,7 +160,7 @@ public void evalBooleanErrorTest() { SplitProvider splitProvider = new SplitProvider(mockSplitClient); String flagName = "flagName"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("a random string"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("a random string","")); try { splitProvider.getBooleanEvaluation(flagName, false, evaluationContext); fail("Should have thrown an exception casting string to boolean"); @@ -172,12 +181,12 @@ public void evalStringNullEmptyTest() { String flagName = "flagName"; String defaultTreatment = "defaultTreatment"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(null); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(null,"")); ProviderEvaluation response = splitProvider.getStringEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(""); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("","")); response = splitProvider.getStringEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); @@ -191,7 +200,7 @@ public void evalStringControlTest() { String flagName = "flagName"; String defaultTreatment = "defaultTreatment"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("control"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("control","")); ProviderEvaluation response = splitProvider.getStringEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); @@ -205,7 +214,7 @@ public void evalStringRegularTest() { String flagName = "flagName"; String treatment = "treatment"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(treatment); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(treatment,"")); ProviderEvaluation response = splitProvider.getStringEvaluation(flagName, "defaultTreatment", evaluationContext); assertEquals(treatment, response.getValue()); @@ -221,12 +230,12 @@ public void evalIntNullEmptyTest() { String flagName = "flagName"; int defaultTreatment = 10; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(null); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(null,"")); ProviderEvaluation response = splitProvider.getIntegerEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(""); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("","")); response = splitProvider.getIntegerEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); @@ -240,7 +249,7 @@ public void evalIntControlTest() { String flagName = "flagName"; int defaultTreatment = 10; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("control"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("control","")); ProviderEvaluation response = splitProvider.getIntegerEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); @@ -255,7 +264,7 @@ public void evalIntRegularTest() { String numString = "50"; int numInt = 50; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(numString); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(numString,"")); ProviderEvaluation response = splitProvider.getIntegerEvaluation(flagName, 10, evaluationContext); assertEquals(numInt, response.getValue()); @@ -275,7 +284,7 @@ public void evalIntErrorTest() { splitProvider.getIntegerEvaluation(flagName, 10, evaluationContext); fail("Should have thrown an exception casting string to integer"); } catch (OpenFeatureError e) { - assertEquals(ErrorCode.PARSE_ERROR, e.getErrorCode()); + assertEquals(ErrorCode.GENERAL, e.getErrorCode()); } catch (Exception e) { fail("Unexpected exception occurred", e); } @@ -291,12 +300,12 @@ public void evalDoubleNullEmptyTest() { String flagName = "flagName"; double defaultTreatment = 10; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(null); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(null,"")); ProviderEvaluation response = splitProvider.getDoubleEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(""); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("","")); response = splitProvider.getDoubleEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); @@ -310,7 +319,7 @@ public void evalDoubleControlTest() { String flagName = "flagName"; double defaultTreatment = 10; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("control"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("control","")); ProviderEvaluation response = splitProvider.getDoubleEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); @@ -325,7 +334,7 @@ public void evalDoubleRegularTest() { String numString = "50"; double num = 50; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(numString); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(numString,"")); ProviderEvaluation response = splitProvider.getDoubleEvaluation(flagName, 10D, evaluationContext); assertEquals(num, response.getValue()); @@ -339,13 +348,13 @@ public void evalDoubleErrorTest() { String flagName = "flagName"; String numString = "notAnInt"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(numString); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(numString,"")); try { splitProvider.getDoubleEvaluation(flagName, 10D, evaluationContext); fail("Should have thrown an exception casting string to integer"); } catch (OpenFeatureError e) { - assertEquals(ErrorCode.PARSE_ERROR, e.getErrorCode()); + assertEquals(ErrorCode.GENERAL, e.getErrorCode()); } catch (Exception e) { fail("Unexpected exception occurred", e); } @@ -361,12 +370,12 @@ public void evalStructureNullEmptyTest() { String flagName = "flagName"; Value defaultTreatment = mapToValue(Map.of("foo", new Value("bar"))); - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(null); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(null,"")); ProviderEvaluation response = splitProvider.getObjectEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(""); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("","")); response = splitProvider.getObjectEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); @@ -380,7 +389,7 @@ public void evalStructureControlTest() { String flagName = "flagName"; Value defaultTreatment = mapToValue(Map.of("foo", new Value("bar"))); - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn("control"); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult("control","")); ProviderEvaluation response = splitProvider.getObjectEvaluation(flagName, defaultTreatment, evaluationContext); assertEquals(defaultTreatment, response.getValue()); @@ -395,7 +404,7 @@ public void evalStructureRegularTest() { Value treatment = mapToValue(Map.of("abc", new Value("def"))); String treatmentAsString = "{\"abc\":\"def\"}"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(treatmentAsString); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(treatmentAsString,"")); ProviderEvaluation response = splitProvider.getObjectEvaluation(flagName, mapToValue(Map.of("foo", new Value("bar"))), evaluationContext); @@ -433,7 +442,7 @@ public void evalStructureComplexTest() { )); String treatmentAsString = "{\"string\":\"blah\",\"int\":10,\"double\":100.0,\"bool\":true, \"struct\":{\"foo\":\"bar\",\"baz\":10,\"innerMap\":{\"aa\":\"bb\"}},\"list\":[1,true,{\"cc\":\"dd\"},{\"ee\":1}],\"dateTime\":\"2022-10-13T22:05:54.828Z\"}"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(treatmentAsString); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(treatmentAsString,"")); ProviderEvaluation response = splitProvider.getObjectEvaluation(flagName, mapToValue(Map.of("foo", new Value("bar"))), evaluationContext); @@ -448,7 +457,7 @@ public void evalStructureErrorTest() { String flagName = "flagName"; String treatment = "not an object"; - when(mockSplitClient.getTreatment(eq(key), eq(flagName), anyMap())).thenReturn(treatment); + when(mockSplitClient.getTreatmentWithConfig(eq(key), eq(flagName), anyMap())).thenReturn(new SplitResult(treatment,"")); try { splitProvider.getObjectEvaluation(flagName, mapToValue(Map.of("foo", new Value("bar"))), evaluationContext); @@ -460,6 +469,62 @@ public void evalStructureErrorTest() { } } + @Test + public void trackWithDetailsTest() { + SplitProvider provider = new SplitProvider(mockSplitClient); + + + EvaluationContext ctx = new MutableContext(key).add("trafficType", "user"); + TrackingEventDetails details = new MutableTrackingEventDetails(42.5) + .add("plan", new Value("pro")) + .add("beta", new Value(true)); + + when(mockSplitClient.track("key", "user", "purchase", 42.5, details.asObjectMap())) + .thenReturn(true); + + provider.track("purchase", ctx, details); + + verify(mockSplitClient).track( + eq(key), eq("user"), eq("purchase"), eq(42.5), + argThat(m -> "pro".equals(m.get("plan")) && Boolean.TRUE.equals(m.get("beta")))); + verifyNoMoreInteractions(mockSplitClient); + } + + @Test + public void trackTargetingKeyErrorTest() { + // Tracking without targetingKey should throw error + SplitProvider provider = new SplitProvider(mockSplitClient); + EvaluationContext ctx = new MutableContext().add("trafficType", "user"); + + assertThrows(dev.openfeature.sdk.exceptions.TargetingKeyMissingError.class, + () -> provider.track("purchase", ctx, null)); + verifyNoInteractions(mockSplitClient); + } + + @Test + public void trackEventNameErrorTest() { + // Tracking without eventName should throw error + SplitProvider provider = new SplitProvider(mockSplitClient); + EvaluationContext ctx = new MutableContext(key).add("trafficType", "user"); + + GeneralError ex = assertThrows(GeneralError.class, + () -> provider.track(" ", ctx, null)); // blank name + assertTrue(ex.getMessage().toLowerCase().contains("eventname")); + verifyNoInteractions(mockSplitClient); + } + + @Test + public void trackTrafficTypeErrorTest() { + // Tracking without trafficType should throw error + SplitProvider provider = new SplitProvider(mockSplitClient); + EvaluationContext ctx = new MutableContext(key); + + GeneralError ex = assertThrows(GeneralError.class, + () -> provider.track("purchase", ctx, null)); + assertTrue(ex.getMessage().toLowerCase().contains("traffictype")); + verifyNoInteractions(mockSplitClient); + } + private Value mapToValue(Map map) { return new Value(new MutableStructure(map)); } From d0545c19431cf6d2880fadd0af1b2492acbee408 Mon Sep 17 00:00:00 2001 From: ZamoraEmmanuel <87494075+ZamoraEmmanuel@users.noreply.github.com> Date: Thu, 28 Aug 2025 14:49:14 -0300 Subject: [PATCH 03/10] Update src/main/java/io/split/openfeature/SplitProvider.java Co-authored-by: nmayorsplit <104373752+nmayorsplit@users.noreply.github.com> --- src/main/java/io/split/openfeature/SplitProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/split/openfeature/SplitProvider.java b/src/main/java/io/split/openfeature/SplitProvider.java index fbed871..91d0fd7 100644 --- a/src/main/java/io/split/openfeature/SplitProvider.java +++ b/src/main/java/io/split/openfeature/SplitProvider.java @@ -124,7 +124,7 @@ private ProviderEvaluation getEvaluation( } catch (OpenFeatureError e) { throw e; } catch (Exception e) { - throw new GeneralError("Error getting " + typeLabel + " evaluation", e); + throw new GeneralError(String.format("Error getting %s evaluation", typeLabel), e); } } From 3af24558416e42d38b14be73ed40dbe4cc4117a6 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Fri, 29 Aug 2025 11:18:38 -0300 Subject: [PATCH 04/10] Add github tests ci --- .github/CODEOWNERS | 1 + .github/workflows/test.yml | 46 +++++++++++++++++++ .../io/split/openfeature/SplitProvider.java | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/workflows/test.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..ab53a7c --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @splitio/sdk \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..20656d1 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,46 @@ +name: test + +on: + pull_request: + branches: + - '*' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + test: + name: Run tests + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + jdk: + - '8' + - '11' + - '19' + env: + ARTIFACTORY_USER: ${{ secrets.ARTIFACTORY_USER }} + ARTIFACTORY_TOKEN: ${{ secrets.ARTIFACTORY_TOKEN }} + MAVEN_OPTS: "-XX:InitialHeapSize=2G -XX:MaxHeapSize=2G -XX:+PrintCommandLineFlags -XX:ThreadStackSize=65536 -XX:-TieredCompilation -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn" + muteProps: "true" + + steps: + - name: Checkout code + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Setup JDK ${{ matrix.jdk }} + uses: actions/setup-java@v3 + with: + distribution: 'adopt' + java-version: ${{ matrix.jdk }} + + - name: Setup Maven + run: cp .ci.settings.xml ${HOME}/.m2/settings.xml + + - name: Test + if: matrix.jdk == '8' && github.event_name == 'pull_request' && github.ref != 'refs/heads/main' && github.ref != 'refs/heads/development' + run: mvn --batch-mode clean install diff --git a/src/main/java/io/split/openfeature/SplitProvider.java b/src/main/java/io/split/openfeature/SplitProvider.java index 91d0fd7..06982d3 100644 --- a/src/main/java/io/split/openfeature/SplitProvider.java +++ b/src/main/java/io/split/openfeature/SplitProvider.java @@ -113,7 +113,7 @@ private ProviderEvaluation getEvaluation( String treatment = evaluated.treatment(); String config = evaluated.config(); ImmutableMetadata metadata = ImmutableMetadata.builder().addString("config", config).build(); - System.out.println(metadata.getString("config")); + if (noTreatment(treatment)) { return constructProviderEvaluation( defaultValue, treatment, Reason.DEFAULT, ErrorCode.FLAG_NOT_FOUND, metadata); From 8c931dce792ae15606a28d9f708ebccfa432bb53 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Fri, 29 Aug 2025 11:24:58 -0300 Subject: [PATCH 05/10] Add precommit file and fix typo --- .ci.settings.xml | 41 +++++++++++++++++++++++++++++++++++++++++ .github/CODEOWNERS | 2 +- .pre-commit-config.yaml | 9 +++++++++ CHANGES.txt | 2 +- 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 .ci.settings.xml create mode 100644 .pre-commit-config.yaml diff --git a/.ci.settings.xml b/.ci.settings.xml new file mode 100644 index 0000000..cca4cef --- /dev/null +++ b/.ci.settings.xml @@ -0,0 +1,41 @@ + + + + + + maven-dev + ${env.ARTIFACTORY_USER} + ${env.ARTIFACTORY_TOKEN} + + + + maven-all-virtual + ${env.ARTIFACTORY_USER} + ${env.ARTIFACTORY_TOKEN} + + + + org.sonarsource.scanner.maven + + + + sonar + + true + + + java-client + https://sonarqube.split-internal.com + ${env.SONAR_TOKEN} + . + pom.xml,src/main/** + . + src/test/** + .csv + **/matchers/**/*.* + https://travis-ci.com/splitio/java-client + https://github.com/splitio/java-client + + + + \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ab53a7c..9e31981 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @splitio/sdk \ No newline at end of file +* @splitio/sdk diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..49239fa --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: check-added-large-files + - id: check-json + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace diff --git a/CHANGES.txt b/CHANGES.txt index 5433234..05656e5 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,6 @@ 1.2.0 (August XX, 2025) - Updated `io.split.client` dependency to 4.16.1 - - Updated `dev.openfeature` dependency to 1.16.0 + - Updated `dev.openfeature` dependency to 1.17.0 1.1.0 - Up tp date with spec v0.5.0 and java sdk v0.3.1 From 94896ebc86ca8401f43c7206ac5246ee85f32d45 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Fri, 29 Aug 2025 11:27:05 -0300 Subject: [PATCH 06/10] Remove java 8 from tests --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 20656d1..269e20f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,6 @@ jobs: fail-fast: false matrix: jdk: - - '8' - '11' - '19' env: From 79a1fbc7dc3973f345333e7cd9909ddfccd9a338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Daniel=20Fad=C3=B3n?= Date: Fri, 29 Aug 2025 18:04:15 -0300 Subject: [PATCH 07/10] Fix --- .ci.settings.xml | 41 ----- .github/workflows/test.yml | 12 +- .gitignore | 20 +- CHANGES.txt | 1 - LICENSE | 2 +- README.md | 19 +- pom.xml | 368 ++++++++++++++++++------------------- 7 files changed, 212 insertions(+), 251 deletions(-) delete mode 100644 .ci.settings.xml diff --git a/.ci.settings.xml b/.ci.settings.xml deleted file mode 100644 index cca4cef..0000000 --- a/.ci.settings.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - maven-dev - ${env.ARTIFACTORY_USER} - ${env.ARTIFACTORY_TOKEN} - - - - maven-all-virtual - ${env.ARTIFACTORY_USER} - ${env.ARTIFACTORY_TOKEN} - - - - org.sonarsource.scanner.maven - - - - sonar - - true - - - java-client - https://sonarqube.split-internal.com - ${env.SONAR_TOKEN} - . - pom.xml,src/main/** - . - src/test/** - .csv - **/matchers/**/*.* - https://travis-ci.com/splitio/java-client - https://github.com/splitio/java-client - - - - \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 269e20f..03a90df 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,11 +20,7 @@ jobs: - '11' - '19' env: - ARTIFACTORY_USER: ${{ secrets.ARTIFACTORY_USER }} - ARTIFACTORY_TOKEN: ${{ secrets.ARTIFACTORY_TOKEN }} MAVEN_OPTS: "-XX:InitialHeapSize=2G -XX:MaxHeapSize=2G -XX:+PrintCommandLineFlags -XX:ThreadStackSize=65536 -XX:-TieredCompilation -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn" - muteProps: "true" - steps: - name: Checkout code uses: actions/checkout@v5 @@ -32,14 +28,10 @@ jobs: fetch-depth: 0 - name: Setup JDK ${{ matrix.jdk }} - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'adopt' java-version: ${{ matrix.jdk }} - - name: Setup Maven - run: cp .ci.settings.xml ${HOME}/.m2/settings.xml - - name: Test - if: matrix.jdk == '8' && github.event_name == 'pull_request' && github.ref != 'refs/heads/main' && github.ref != 'refs/heads/development' - run: mvn --batch-mode clean install + run: mvn --batch-mode -T 2C -U clean package diff --git a/.gitignore b/.gitignore index ec376bb..df059e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,20 @@ +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://maven.apache.org/wrapper/#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +# Eclipse m2e generated files +# Eclipse Core +.project +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Idea .idea -target \ No newline at end of file diff --git a/CHANGES.txt b/CHANGES.txt index 05656e5..a94da51 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,4 +7,3 @@ 1.0.0 - First release. Up to date with java sdk v0.1.0 - diff --git a/LICENSE b/LICENSE index aebce89..051b5fd 100644 --- a/LICENSE +++ b/LICENSE @@ -10,4 +10,4 @@ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and -limitations under the License. \ No newline at end of file +limitations under the License. diff --git a/README.md b/README.md index 1114f87..ed1dd96 100644 --- a/README.md +++ b/README.md @@ -55,12 +55,12 @@ Client client = api.getClient("CLIENT_NAME"); EvaluationContext context = new MutableContext("TARGETING_KEY"); Boolean boolValue = client.getBooleanValue("boolFlag", false, context); ``` -If the same targeting key is used repeatedly, the evaluation context may be set at the client level +If the same targeting key is used repeatedly, the evaluation context may be set at the client level ```java EvaluationContext context = new MutableContext("TARGETING_KEY"); client.setEvaluationContext(context) ``` -or at the OpenFeatureAPI level +or at the OpenFeatureAPI level ```java EvaluationContext context = new MutableContext("TARGETING_KEY"); OpenFeatureAPI.getInstance().setEvaluationContext(context) @@ -68,7 +68,7 @@ OpenFeatureAPI.getInstance().setEvaluationContext(context) If the context was set at the client or api level, it is not required to provide it during flag evaluation. ## Submitting issues - + The Split team monitors all issues submitted to this [issue tracker](https://github.com/splitio/split-openfeature-provider-java/issues). We encourage you to use this issue tracker to submit any bug reports, feedback, and feature enhancements. We'll do our best to respond in a timely manner. ## Contributing @@ -78,13 +78,13 @@ Please see [Contributors Guide](CONTRIBUTORS-GUIDE.md) to find all you need to s Licensed under the Apache License, Version 2.0. See: [Apache License](http://www.apache.org/licenses/). ## About Split - + Split is the leading Feature Delivery Platform for engineering teams that want to confidently deploy features as fast as they can develop them. Split’s fine-grained management, real-time monitoring, and data-driven experimentation ensure that new features will improve the customer experience without breaking or degrading performance. Companies like Twilio, Salesforce, GoDaddy and WePay trust Split to power their feature delivery. - + To learn more about Split, contact hello@split.io, or get started with feature flags for free at https://www.split.io/signup. - + Split has built and maintains SDKs for: - + * .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK) * Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK) * Angular [Github](https://github.com/splitio/angular-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/6495326064397-Angular-utilities) @@ -105,8 +105,7 @@ Split has built and maintains SDKs for: * Ruby [Github](https://github.com/splitio/ruby-client) [Docs](https://help.split.io/hc/en-us/articles/360020673251-Ruby-SDK) For a comprehensive list of open source projects visit our [Github page](https://github.com/splitio?utf8=%E2%9C%93&query=%20only%3Apublic%20). - + **Learn more about Split:** - -Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](http://help.split.io) for more detailed information. +Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](http://help.split.io) for more detailed information. diff --git a/pom.xml b/pom.xml index 601ffbd..b766653 100644 --- a/pom.xml +++ b/pom.xml @@ -1,190 +1,184 @@ - - - 4.0.0 - - io.split.openfeature - split-openfeature-provider - 1.2.0 - - split-openfeature-provider-java - Split OpenFeature Java Provider - www.split.io - - - scm:git:git@github.com:splitio/split-openfeature-provider-java.git - scm:git@github.com:splitio/split-openfeature-provider-java.git - git@github.com:splitio/split-openfeature-provider-java.git - - - - - Robert Grassian - robert.grassian@split.io - - - Emmanuel Zamora - emmanuel.zamora@harness.io - - - - - - Apache 2.0 - http://www.apache.org/licenses/LICENSE-2.0 - - - - - UTF-8 - 11 - 5.10.2 - 3.2.5 - - - - - org.junit.jupiter - junit-jupiter - ${junit.jupiter.version} - test - - - io.split.client - java-client - 4.16.1 - - - org.apache.httpcomponents - httpclient - 4.5.14 - - - io.split.integrations.azure - impressions-listener - 0.9.1 - - - org.mockito - mockito-core - 3.4.6 - test - - - dev.openfeature - sdk - 1.17.0 - - - - - - - - - maven-clean-plugin - 3.1.0 - - - - maven-resources-plugin - 3.0.2 - - - maven-compiler-plugin - 3.8.0 - - - maven-surefire-plugin - 2.22.1 - - - maven-jar-plugin - 3.0.2 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - - maven-site-plugin - 3.7.1 - - - maven-project-info-reports-plugin - 3.0.0 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.13.0 - - 11 - 11 - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.11.3 - - - attach-javadocs - - jar - - - -Xdoclint:none - 11 - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.13 - true - - true - - - - org.apache.maven.plugins - maven-source-plugin - 3.3.1 - - - attach-sources - - jar - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.5 - - - sign-artifacts - verify - - sign - - - - - - + 4.0.0 + io.split.openfeature + split-openfeature-provider + 1.2.0 + split-openfeature-provider-java + Split OpenFeature Java Provider + www.split.io + + scm:git:git@github.com:splitio/split-openfeature-provider-java.git + scm:git@github.com:splitio/split-openfeature-provider-java.git + git@github.com:splitio/split-openfeature-provider-java.git + + + + Robert Grassian + robert.grassian@split.io + + + Emmanuel Zamora + emmanuel.zamora@harness.io + + + + + Apache 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + + + + UTF-8 + 11 + 5.10.2 + 3.2.5 + + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + io.split.client + java-client + 4.16.1 + + + org.apache.httpcomponents + httpclient + 4.5.14 + + + io.split.integrations.azure + impressions-listener + 0.9.1 + + + org.mockito + mockito-core + 3.4.6 + test + + + dev.openfeature + sdk + 1.17.0 + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + 11 + 11 + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.11.3 + + + attach-javadocs + + jar + + + -Xdoclint:none + 11 + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.13 + true + + true + + + + org.apache.maven.plugins + maven-source-plugin + 3.3.1 + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + From 472b242bd343302ffac07e7df78b2a4a4ae800ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Daniel=20Fad=C3=B3n?= Date: Fri, 29 Aug 2025 18:29:59 -0300 Subject: [PATCH 08/10] Fix maven opts --- .github/workflows/test.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 03a90df..cf0a2a9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,9 +18,10 @@ jobs: matrix: jdk: - '11' - - '19' + - '17' + - '21' env: - MAVEN_OPTS: "-XX:InitialHeapSize=2G -XX:MaxHeapSize=2G -XX:+PrintCommandLineFlags -XX:ThreadStackSize=65536 -XX:-TieredCompilation -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn" + MAVEN_OPTS: "-Xms2g -Xmx2g -XX:+PrintCommandLineFlags -XX:ThreadStackSize=1024 -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn" steps: - name: Checkout code uses: actions/checkout@v5 @@ -32,6 +33,7 @@ jobs: with: distribution: 'adopt' java-version: ${{ matrix.jdk }} + cache: 'maven' - name: Test - run: mvn --batch-mode -T 2C -U clean package + run: mvn --batch-mode -T 2C clean package From 5e60470267512d15b659b597829277d813b811d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Daniel=20Fad=C3=B3n?= Date: Fri, 29 Aug 2025 18:38:54 -0300 Subject: [PATCH 09/10] Fix git checkout --- .github/workflows/test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cf0a2a9..2eeb3fc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,8 +25,6 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v5 - with: - fetch-depth: 0 - name: Setup JDK ${{ matrix.jdk }} uses: actions/setup-java@v5 From e597ecd60d2c24d403c07a34abb83bbae3921d52 Mon Sep 17 00:00:00 2001 From: Emmanuel Zamora Date: Mon, 1 Sep 2025 10:47:36 -0300 Subject: [PATCH 10/10] wait for client readyness in tests --- src/test/java/io/split/openfeature/ClientTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/io/split/openfeature/ClientTest.java b/src/test/java/io/split/openfeature/ClientTest.java index 8856b89..a0ec342 100644 --- a/src/test/java/io/split/openfeature/ClientTest.java +++ b/src/test/java/io/split/openfeature/ClientTest.java @@ -37,7 +37,7 @@ public void init() { try { SplitClientConfig config = SplitClientConfig.builder().splitFile("src/test/resources/split.yaml").build(); SplitClient client = SplitFactoryBuilder.build("localhost", config).client(); - openFeatureAPI.setProvider(new SplitProvider(client)); + openFeatureAPI.setProviderAndWait(new SplitProvider(client)); } catch (URISyntaxException | IOException e) { System.out.println("Unexpected Exception occurred initializing Split Provider."); }