diff --git a/client/src/main/java/io/split/client/dtos/BetweenStringMatcherData.java b/client/src/main/java/io/split/client/dtos/BetweenStringMatcherData.java new file mode 100644 index 00000000..3af1cc0c --- /dev/null +++ b/client/src/main/java/io/split/client/dtos/BetweenStringMatcherData.java @@ -0,0 +1,11 @@ +package io.split.client.dtos; + +/** + * Metadata to support the between matcher. + * + * @author adil + */ +public class BetweenStringMatcherData { + public String start; + public String end; +} diff --git a/client/src/main/java/io/split/client/dtos/Matcher.java b/client/src/main/java/io/split/client/dtos/Matcher.java index 12c824d2..fc2c6515 100644 --- a/client/src/main/java/io/split/client/dtos/Matcher.java +++ b/client/src/main/java/io/split/client/dtos/Matcher.java @@ -13,6 +13,7 @@ public class Matcher { public WhitelistMatcherData whitelistMatcherData; public UnaryNumericMatcherData unaryNumericMatcherData; public BetweenMatcherData betweenMatcherData; + public BetweenStringMatcherData betweenStringMatcherData; public DependencyMatcherData dependencyMatcherData; public Boolean booleanMatcherData; public String stringMatcherData; diff --git a/client/src/main/java/io/split/client/dtos/MatcherType.java b/client/src/main/java/io/split/client/dtos/MatcherType.java index 81a15756..b8c78a7b 100644 --- a/client/src/main/java/io/split/client/dtos/MatcherType.java +++ b/client/src/main/java/io/split/client/dtos/MatcherType.java @@ -36,5 +36,6 @@ public enum MatcherType { EQUAL_TO_SEMVER, GREATER_THAN_OR_EQUAL_TO_SEMVER, LESS_THAN_OR_EQUAL_TO_SEMVER, - IN_LIST_SEMVER + IN_LIST_SEMVER, + BETWEEN_SEMVER } diff --git a/client/src/main/java/io/split/engine/evaluator/Labels.java b/client/src/main/java/io/split/engine/evaluator/Labels.java index 59cfceef..ac5a465a 100644 --- a/client/src/main/java/io/split/engine/evaluator/Labels.java +++ b/client/src/main/java/io/split/engine/evaluator/Labels.java @@ -6,5 +6,5 @@ public class Labels { public static final String KILLED = "killed"; public static final String DEFINITION_NOT_FOUND = "definition not found"; public static final String EXCEPTION = "exception"; - public static final String UNSUPPORTED_MATCHER = "unsupported matcher type"; + public static final String UNSUPPORTED_MATCHER = "targeting rule type unsupported by sdk"; } \ No newline at end of file diff --git a/client/src/main/java/io/split/engine/experiments/SplitParser.java b/client/src/main/java/io/split/engine/experiments/SplitParser.java index 477d9db8..b320dff6 100644 --- a/client/src/main/java/io/split/engine/experiments/SplitParser.java +++ b/client/src/main/java/io/split/engine/experiments/SplitParser.java @@ -32,6 +32,7 @@ import io.split.engine.matchers.GreaterThanOrEqualToSemverMatcher; import io.split.engine.matchers.LessThanOrEqualToSemverMatcher; import io.split.engine.matchers.InListSemverMatcher; +import io.split.engine.matchers.BetweenSemverMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -214,6 +215,10 @@ private AttributeMatcher toMatcher(Matcher matcher) { checkNotNull(matcher.whitelistMatcherData, "whitelistMatcherData is required for IN_LIST_SEMVER matcher type"); delegate = new InListSemverMatcher(matcher.whitelistMatcherData.whitelist); break; + case BETWEEN_SEMVER: + checkNotNull(matcher.betweenStringMatcherData, "betweenStringMatcherData is required for BETWEEN_SEMVER matcher type"); + delegate = new BetweenSemverMatcher(matcher.betweenStringMatcherData.start, matcher.betweenStringMatcherData.end); + break; default: throw new IllegalArgumentException("Unknown matcher type: " + matcher.matcherType); } diff --git a/client/src/main/java/io/split/engine/matchers/BetweenSemverMatcher.java b/client/src/main/java/io/split/engine/matchers/BetweenSemverMatcher.java new file mode 100644 index 00000000..a36d9c6d --- /dev/null +++ b/client/src/main/java/io/split/engine/matchers/BetweenSemverMatcher.java @@ -0,0 +1,58 @@ +package io.split.engine.matchers; + +import io.split.engine.evaluator.EvaluationContext; + +import java.util.Map; + +public class BetweenSemverMatcher implements Matcher { + + private final Semver _semverStart; + private final Semver _semverEnd; + + public BetweenSemverMatcher(String semverStart, String semverEnd) { + _semverStart = Semver.build(semverStart); + _semverEnd = Semver.build(semverEnd); + } + + @Override + public boolean match(Object matchValue, String bucketingKey, Map attributes, EvaluationContext evaluationContext) { + if (matchValue == null || _semverStart == null || _semverEnd == null) { + return false; + } + Semver matchSemver = Semver.build(matchValue.toString()); + if (matchSemver == null) { + return false; + } + + return matchSemver.Compare(_semverStart) >= 0 && matchSemver.Compare(_semverEnd) <= 0; + } + + @Override + public String toString() { + StringBuilder bldr = new StringBuilder(); + bldr.append("between semver "); + bldr.append(_semverStart.Version()); + bldr.append(" and "); + bldr.append(_semverEnd.Version()); + return bldr.toString(); + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + _semverStart.hashCode() + _semverEnd.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (this == obj) return true; + if (!(obj instanceof BetweenSemverMatcher)) return false; + + BetweenSemverMatcher other = (BetweenSemverMatcher) obj; + + return _semverStart == other._semverStart && _semverEnd == other._semverEnd; + } + +} diff --git a/client/src/test/java/io/split/engine/matchers/BetweenSemverMatcherTest.java b/client/src/test/java/io/split/engine/matchers/BetweenSemverMatcherTest.java new file mode 100644 index 00000000..cb979b8e --- /dev/null +++ b/client/src/test/java/io/split/engine/matchers/BetweenSemverMatcherTest.java @@ -0,0 +1,25 @@ +package io.split.engine.matchers; + +import org.junit.Test; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +/** + * Tests for EqualToSemverMatcher + */ + +public class BetweenSemverMatcherTest { + + @Test + public void works() { + BetweenSemverMatcher betweenSemverMatcher = new BetweenSemverMatcher("2.1.8", "3.0.0"); + + assertTrue( betweenSemverMatcher.match("2.1.8", null, null, null)); + assertTrue( betweenSemverMatcher.match("2.1.9", null, null, null)); + assertFalse( betweenSemverMatcher.match("2.1.8-rc", null, null, null)); + assertTrue( betweenSemverMatcher.match("3.0.0+build", null, null, null)); + assertFalse( betweenSemverMatcher.match("4.5.8", null, null, null)); + assertFalse( betweenSemverMatcher.match("1.0.4", null, null, null)); + } +}