From b83e1820198a36dfe865be0bb5ca06edada42f7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aslak=20Helles=C3=B8y?=
<1000+aslakhellesoy@users.noreply.github.com>
Date: Mon, 26 Jul 2021 16:34:00 -0500
Subject: [PATCH 1/3] Add Support for Cucumber using @split[feature:treatment]
tags (#247)
* Add CucumberSplit
* Add URL in JavaDoc
* Improve the Cucumber example to be more realistic
* disambiguation
---
testing/pom.xml | 10 ++++
.../testing/cucumber/CucumberSplit.java | 51 +++++++++++++++++
.../testing/cucumber/CoffeeMachine.java | 44 +++++++++++++++
.../testing/cucumber/RunCucumberTest.java | 9 +++
.../io/split/client/testing/cucumber/SKU.java | 37 +++++++++++++
.../testing/cucumber/StepDefinitions.java | 55 +++++++++++++++++++
.../src/test/resources/cucumber.properties | 1 +
.../testing/cucumber/MakeCoffee.feature | 25 +++++++++
8 files changed, 232 insertions(+)
create mode 100644 testing/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java
create mode 100644 testing/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java
create mode 100644 testing/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java
create mode 100644 testing/src/test/java/io/split/client/testing/cucumber/SKU.java
create mode 100644 testing/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java
create mode 100644 testing/src/test/resources/cucumber.properties
create mode 100644 testing/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature
diff --git a/testing/pom.xml b/testing/pom.xml
index bbad31d7f..d690ce04f 100644
--- a/testing/pom.xml
+++ b/testing/pom.xml
@@ -23,5 +23,15 @@
junit
junit
+
+ io.cucumber
+ cucumber-java
+ 6.10.4
+
+
+ io.cucumber
+ cucumber-junit
+ 6.10.4
+
diff --git a/testing/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java b/testing/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java
new file mode 100644
index 000000000..716b51088
--- /dev/null
+++ b/testing/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java
@@ -0,0 +1,51 @@
+package io.split.client.testing.cucumber;
+
+import io.cucumber.java.Scenario;
+import io.split.client.testing.SplitClientForTest;
+
+import java.util.Collection;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * Simple Cucumber plugin for Split.
+ *
+ *
+ * Cucumber scenarios annotated with {@code @split[feature:treatment]} tags can be used to
+ * configure a {@link SplitClientForTest} instance.
+ *
+ *
+ * To use it, define a Before Hook that invokes the {@link CucumberSplit#configureSplit(SplitClientForTest, Scenario)}
+ * method. Example:
+ *
+ *
+ *
+ * import io.cucumber.java.Before;
+ * import io.split.client.testing.SplitClientForTest;
+ *
+ * public class StepDefinitions {
+ * private final SplitClientForTest splitClient = new SplitClientForTest();
+ *
+ * @Before
+ * public void configureSplit(Scenario scenario) {
+ * CucumberSplit.configureSplit(splitClient, scenario);
+ * }
+ * }
+ *
+ */
+public class CucumberSplit {
+ private static final Pattern SPLIT_TAG_PATTERN = Pattern.compile("^@split\\[(.*):(.*)]");
+
+ public static void configureSplit(SplitClientForTest splitClient, Scenario scenario) {
+ Collection tags = scenario.getSourceTagNames();
+ for (String tag : tags) {
+ Matcher matcher = SPLIT_TAG_PATTERN.matcher(tag);
+ if (matcher.matches()) {
+ String feature = matcher.group(1);
+ String treatment = matcher.group(2);
+ splitClient.registerTreatment(feature, treatment);
+ }
+ }
+ }
+}
diff --git a/testing/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java b/testing/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java
new file mode 100644
index 000000000..2cfa2e913
--- /dev/null
+++ b/testing/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java
@@ -0,0 +1,44 @@
+package io.split.client.testing.cucumber;
+
+import io.split.client.SplitClient;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableList;
+
+/**
+ * A simple coffee machine that displays available drinks. It can offer an experimental cappuccino
+ * drink that is toggled on/off with Split.
+ */
+public class CoffeeMachine {
+ private final SplitClient splitClient;
+ private final String splitKey;
+ private double level;
+
+ public CoffeeMachine(SplitClient splitClient, String splitKey) {
+ this.splitClient = splitClient;
+ this.splitKey = splitKey;
+ }
+
+ /**
+ * Indicate how full the machine is
+ *
+ * @param level a number between 0 and 1
+ */
+ public void setLevel(double level) {
+ this.level = level;
+ }
+
+ public List getAvailableDrinks() {
+ if(this.level == 0) return emptyList();
+
+ List availableDrinks = new ArrayList<>();
+ availableDrinks.add(new SKU("filter coffee", 0.80));
+ if ("on".equals(this.splitClient.getTreatment(splitKey, "cappuccino"))) {
+ availableDrinks.add(new SKU("cappuccino", 1.10));
+ }
+ return unmodifiableList(availableDrinks);
+ }
+}
diff --git a/testing/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java b/testing/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java
new file mode 100644
index 000000000..18a325ab7
--- /dev/null
+++ b/testing/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java
@@ -0,0 +1,9 @@
+package io.split.client.testing.cucumber;
+
+import io.cucumber.junit.Cucumber;
+import org.junit.runner.RunWith;
+
+// This is the entry point for Cucumber, which runs all the .feature files in the same package
+@RunWith(Cucumber.class)
+public class RunCucumberTest {
+}
diff --git a/testing/src/test/java/io/split/client/testing/cucumber/SKU.java b/testing/src/test/java/io/split/client/testing/cucumber/SKU.java
new file mode 100644
index 000000000..12e5a8cb1
--- /dev/null
+++ b/testing/src/test/java/io/split/client/testing/cucumber/SKU.java
@@ -0,0 +1,37 @@
+package io.split.client.testing.cucumber;
+
+import java.util.Objects;
+
+/**
+ * A simple Stock Keeping Unit (SKU).
+ */
+public class SKU {
+ private final String name;
+ private final double price;
+
+ public SKU(String name, double price) {
+ this.name = name;
+ this.price = price;
+ }
+
+ @Override
+ public String toString() {
+ return "SKU{" +
+ "name='" + name + '\'' +
+ ", price=" + price +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SKU sku = (SKU) o;
+ return Double.compare(sku.price, price) == 0 && name.equals(sku.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, price);
+ }
+}
diff --git a/testing/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java b/testing/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java
new file mode 100644
index 000000000..59d3eae29
--- /dev/null
+++ b/testing/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java
@@ -0,0 +1,55 @@
+package io.split.client.testing.cucumber;
+
+import io.cucumber.java.Before;
+import io.cucumber.java.DataTableType;
+import io.cucumber.java.Scenario;
+import io.cucumber.java.en.Given;
+import io.cucumber.java.en.Then;
+import io.split.client.testing.SplitClientForTest;
+
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Collections.emptyList;
+import static org.junit.Assert.assertEquals;
+
+public class StepDefinitions {
+ private final SplitClientForTest splitClient = new SplitClientForTest();
+ private final CoffeeMachine coffeeMachine = new CoffeeMachine(splitClient, "arbitraryKey");
+
+ // Called by Cucumber to convert each row in the data table in the .feature file to a SKU object
+ @DataTableType
+ public SKU sku(Map entry) {
+ return new SKU(
+ entry.get("name"),
+ Double.parseDouble(entry.get("price"))
+ );
+ }
+
+ @Given("the machine is not empty")
+ public void the_machine_is_not_empty() {
+ coffeeMachine.setLevel(1.0);
+ }
+
+ @Given("the machine is empty")
+ public void the_machine_is_empty() {
+ coffeeMachine.setLevel(0);
+ }
+
+ @Then("the following drinks should be available:")
+ public void the_following_drinks_should_be_available(List expectedSKUs) {
+ List availableSKUs = coffeeMachine.getAvailableDrinks();
+ assertEquals(expectedSKUs, availableSKUs);
+ }
+
+ @Then("no drinks should be available")
+ public void no_drinks_should_be_available() {
+ List availableSKUs = coffeeMachine.getAvailableDrinks();
+ assertEquals(emptyList(), availableSKUs);
+ }
+
+ @Before
+ public void configureSplit(Scenario scenario) {
+ CucumberSplit.configureSplit(splitClient, scenario);
+ }
+}
diff --git a/testing/src/test/resources/cucumber.properties b/testing/src/test/resources/cucumber.properties
new file mode 100644
index 000000000..b48dd63bf
--- /dev/null
+++ b/testing/src/test/resources/cucumber.properties
@@ -0,0 +1 @@
+cucumber.publish.quiet=true
diff --git a/testing/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature b/testing/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature
new file mode 100644
index 000000000..bb2c98a15
--- /dev/null
+++ b/testing/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature
@@ -0,0 +1,25 @@
+# This tag is inherited by all the scenarios, setting the "cappuccino" split feature to "off" by default.
+@split[cappuccino:off]
+Feature: Make Coffee
+ The scenarios in this feature file describes how the coffee machine works.
+
+ Scenario: Empty machine
+ Given the machine is empty
+ Then no drinks should be available
+
+ Scenario: Display available drinks
+ Given the machine is not empty
+ Then the following drinks should be available:
+ | name | price |
+ | filter coffee | 0.80 |
+
+ # The tags on this scenario will be ["@split[cappuccino:off]", "@split[cappuccino:on]"]
+ # The @split tags are processed sequentially, so the cappuccino split feature will be set to "off"
+ # and then immediately overwritten to "on".
+ @split[cappuccino:on]
+ Scenario: Display available drinks (including the new experimental cappuccino)
+ Given the machine is not empty
+ Then the following drinks should be available:
+ | name | price |
+ | filter coffee | 0.80 |
+ | cappuccino | 1.10 |
From 06d8298b92d5b07ac793c433f021c4beb1a6e4a6 Mon Sep 17 00:00:00 2001
From: Patricio Echague
Date: Mon, 26 Jul 2021 15:06:41 -0700
Subject: [PATCH 2/3] Create a separate module for cucumber
---
testing-cucumber/CHANGES.txt | 5 +++
testing-cucumber/pom.xml | 38 +++++++++++++++++++
.../testing/cucumber/CucumberSplit.java | 0
.../testing/cucumber/CoffeeMachine.java | 0
.../testing/cucumber/RunCucumberTest.java | 0
.../io/split/client/testing/cucumber/SKU.java | 0
.../testing/cucumber/StepDefinitions.java | 0
.../src/test/resources/cucumber.properties | 0
.../testing/cucumber/MakeCoffee.feature | 0
testing/pom.xml | 10 -----
10 files changed, 43 insertions(+), 10 deletions(-)
create mode 100644 testing-cucumber/CHANGES.txt
create mode 100644 testing-cucumber/pom.xml
rename {testing => testing-cucumber}/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java (100%)
rename {testing => testing-cucumber}/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java (100%)
rename {testing => testing-cucumber}/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java (100%)
rename {testing => testing-cucumber}/src/test/java/io/split/client/testing/cucumber/SKU.java (100%)
rename {testing => testing-cucumber}/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java (100%)
rename {testing => testing-cucumber}/src/test/resources/cucumber.properties (100%)
rename {testing => testing-cucumber}/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature (100%)
diff --git a/testing-cucumber/CHANGES.txt b/testing-cucumber/CHANGES.txt
new file mode 100644
index 000000000..8bffaed34
--- /dev/null
+++ b/testing-cucumber/CHANGES.txt
@@ -0,0 +1,5 @@
+CHANGES
+
+1.0.0(July 27, 2021)
+- First release of Cucumber integration for Split testing module
+
diff --git a/testing-cucumber/pom.xml b/testing-cucumber/pom.xml
new file mode 100644
index 000000000..303b6b478
--- /dev/null
+++ b/testing-cucumber/pom.xml
@@ -0,0 +1,38 @@
+
+
+ 4.0.0
+
+
+ io.split.client
+ java-client-parent
+ 4.2.1
+
+
+ java-client-testing-cucumber
+ 1.0.0-rc1
+ jar
+ Split Java Client Cucumber testing module
+ Cucumber integration for the testing module of Split Java Client
+
+
+ io.split.client
+ java-client-testing
+ ${parent.version}
+
+
+ junit
+ junit
+
+
+ io.cucumber
+ cucumber-java
+ 6.10.4
+
+
+ io.cucumber
+ cucumber-junit
+ 6.10.4
+
+
+
diff --git a/testing/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java b/testing-cucumber/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java
similarity index 100%
rename from testing/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java
rename to testing-cucumber/src/main/java/io/split/client/testing/cucumber/CucumberSplit.java
diff --git a/testing/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java b/testing-cucumber/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java
similarity index 100%
rename from testing/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java
rename to testing-cucumber/src/test/java/io/split/client/testing/cucumber/CoffeeMachine.java
diff --git a/testing/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java b/testing-cucumber/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java
similarity index 100%
rename from testing/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java
rename to testing-cucumber/src/test/java/io/split/client/testing/cucumber/RunCucumberTest.java
diff --git a/testing/src/test/java/io/split/client/testing/cucumber/SKU.java b/testing-cucumber/src/test/java/io/split/client/testing/cucumber/SKU.java
similarity index 100%
rename from testing/src/test/java/io/split/client/testing/cucumber/SKU.java
rename to testing-cucumber/src/test/java/io/split/client/testing/cucumber/SKU.java
diff --git a/testing/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java b/testing-cucumber/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java
similarity index 100%
rename from testing/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java
rename to testing-cucumber/src/test/java/io/split/client/testing/cucumber/StepDefinitions.java
diff --git a/testing/src/test/resources/cucumber.properties b/testing-cucumber/src/test/resources/cucumber.properties
similarity index 100%
rename from testing/src/test/resources/cucumber.properties
rename to testing-cucumber/src/test/resources/cucumber.properties
diff --git a/testing/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature b/testing-cucumber/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature
similarity index 100%
rename from testing/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature
rename to testing-cucumber/src/test/resources/io/split/client/testing/cucumber/MakeCoffee.feature
diff --git a/testing/pom.xml b/testing/pom.xml
index d690ce04f..bbad31d7f 100644
--- a/testing/pom.xml
+++ b/testing/pom.xml
@@ -23,15 +23,5 @@
junit
junit
-
- io.cucumber
- cucumber-java
- 6.10.4
-
-
- io.cucumber
- cucumber-junit
- 6.10.4
-
From 5572c03efccd95cadea392548e8a39ecb77b9604 Mon Sep 17 00:00:00 2001
From: Patricio Echague
Date: Mon, 26 Jul 2021 17:40:28 -0700
Subject: [PATCH 3/3] Address feedback
---
pom.xml | 3 ++-
testing-cucumber/pom.xml | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index ee6d16156..c0edf7cf6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -70,8 +70,9 @@
1.8
- testing
client
+ testing
+ testing-cucumber
diff --git a/testing-cucumber/pom.xml b/testing-cucumber/pom.xml
index 303b6b478..e649a3bed 100644
--- a/testing-cucumber/pom.xml
+++ b/testing-cucumber/pom.xml
@@ -28,11 +28,13 @@
io.cucumber
cucumber-java
6.10.4
+ provided
io.cucumber
cucumber-junit
6.10.4
+ provided