Basic get/put test
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/75521268 Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/75521268 Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/75521268 Branch: refs/heads/feature/e2e-testing Commit: 75521268a535c1cc9fff3b0245e5cd1af84665cc Parents: 2cec7a6 Author: Jens Deppe <jde...@pivotal.io> Authored: Tue Oct 4 10:02:50 2016 -0700 Committer: Jens Deppe <jde...@pivotal.io> Committed: Tue Oct 4 10:02:50 2016 -0700 ---------------------------------------------------------------------- .../java/org/apache/geode/e2e/DockerTest.java | 8 +- .../test/java/org/apache/geode/e2e/GetPut.java | 32 +++++++ .../java/org/apache/geode/e2e/GetPutSteps.java | 71 ++++++++++++++ .../java/org/apache/geode/e2e/StoryRunner.java | 47 ++++++++++ .../geode/e2e/container/DockerCluster.java | 97 ++++++++++++++++---- .../geode/e2e/container/ResultCallback.java | 6 ++ .../org/apache/geode/e2e/get_put.story | 5 + gradle/test.gradle | 1 + 8 files changed, 245 insertions(+), 22 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/75521268/geode-core/src/test/java/org/apache/geode/e2e/DockerTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/e2e/DockerTest.java b/geode-core/src/test/java/org/apache/geode/e2e/DockerTest.java index e8e04f0..d8581f4 100644 --- a/geode-core/src/test/java/org/apache/geode/e2e/DockerTest.java +++ b/geode-core/src/test/java/org/apache/geode/e2e/DockerTest.java @@ -14,7 +14,9 @@ public class DockerTest { @Before public void setup() throws Exception { - cluster = new DockerCluster("testy", 1); + cluster = new DockerCluster("testy"); + cluster.setLocatorCount(1); + cluster.setServerCount(2); } @After @@ -25,11 +27,11 @@ public class DockerTest { @Test public void sanity() throws Exception { cluster.start(); - assertNotNull("Locator address is null", cluster.getLocatorAddress()); + assertNotNull("Locator host is null", cluster.getLocatorHost()); } @Test - public void testInvalidGfshCommand() throws Exception { + public void testInvalidGfshCommandReturnsNonZero() throws Exception { String id = cluster.startContainer(0); int r = cluster.execCommand(id, false, null, new String[] { "/tmp/work/bin/gfsh", "startx" }); assertEquals(1, r); http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/75521268/geode-core/src/test/java/org/apache/geode/e2e/GetPut.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/e2e/GetPut.java b/geode-core/src/test/java/org/apache/geode/e2e/GetPut.java new file mode 100644 index 0000000..e62194b --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/e2e/GetPut.java @@ -0,0 +1,32 @@ +package org.apache.geode.e2e; + +import org.jbehave.core.configuration.Configuration; +import org.jbehave.core.configuration.MostUsefulConfiguration; +import org.jbehave.core.io.LoadFromClasspath; +import org.jbehave.core.junit.JUnitStory; +import org.jbehave.core.reporters.Format; +import org.jbehave.core.reporters.StoryReporterBuilder; +import org.jbehave.core.steps.InjectableStepsFactory; +import org.jbehave.core.steps.InstanceStepsFactory; + +public class GetPut extends JUnitStory { + + // Here we specify the configuration, starting from default MostUsefulConfiguration, and changing only what is need ed + @Override + public Configuration configuration() { + return new MostUsefulConfiguration() + // where to find the stories + .useStoryLoader(new LoadFromClasspath(this.getClass())) + // CONSOLE and TXT reporting + .useStoryReporterBuilder(new StoryReporterBuilder().withDefaultFormats() + .withFormats(Format.ANSI_CONSOLE, Format.TXT)); + } + + // Here we specify the steps classes + @Override + public InjectableStepsFactory stepsFactory() { + // varargs, can have more that one steps classes + return new InstanceStepsFactory(configuration(), new GetPutSteps()); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/75521268/geode-core/src/test/java/org/apache/geode/e2e/GetPutSteps.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/e2e/GetPutSteps.java b/geode-core/src/test/java/org/apache/geode/e2e/GetPutSteps.java new file mode 100644 index 0000000..bb4db31 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/e2e/GetPutSteps.java @@ -0,0 +1,71 @@ +package org.apache.geode.e2e; + +import static org.junit.Assert.assertEquals; + +import com.spotify.docker.client.exceptions.DockerException; +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ClientCache; +import org.apache.geode.cache.client.ClientCacheFactory; +import org.apache.geode.cache.client.ClientRegionShortcut; +import org.apache.geode.e2e.container.DockerCluster; +import org.jbehave.core.annotations.AfterScenario; +import org.jbehave.core.annotations.BeforeScenario; +import org.jbehave.core.annotations.BeforeStories; +import org.jbehave.core.annotations.Given; +import org.jbehave.core.annotations.Then; +import org.jbehave.core.annotations.When; + +public class GetPutSteps { + + private DockerCluster cluster; + + @BeforeStories + public void teardownContainers() throws DockerException, InterruptedException { + DockerCluster.scorch(); + } + + @BeforeScenario + public void beforeScenario() { + cluster = new DockerCluster("test-cluster"); + } + + @AfterScenario + public void afterScenario() throws Exception { + cluster.stop(); + } + + @Given("cluster is started with $locators locators and $servers servers") + public void startCluster(int locatorCount, int serverCount) throws Exception { + cluster.setLocatorCount(locatorCount); + cluster.setServerCount(serverCount); + cluster.start(); + } + + @Given("region $name is created as $type") + public void createRegion(String name, String type) throws Exception { + cluster.gfshCommand(String.format("create region --name=%s --type=%s", name, type)); + } + + @When("I put $count entries into region $name") + public void when(int count, String name) throws Exception { + ClientCache cache = new ClientCacheFactory(). + set("log-level", "warn"). + addPoolLocator("localhost", cluster.getLocatorPort()). + create(); + Region region = cache.createClientRegionFactory(ClientRegionShortcut.PROXY).create(name); + for (int i = 0; i < count; i++) { + region.put("key_" + i, "value_" + i); + } + } + + @Then("I can get $count entries from region $name") + public void then(int count, String name) throws Exception { + Region region = CacheFactory.getAnyInstance().getRegion(name); + + for (int i = 0; i < count; i++) { + assertEquals("value_" + i, region.get("key_" + i)); + } + } +} + http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/75521268/geode-core/src/test/java/org/apache/geode/e2e/StoryRunner.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/e2e/StoryRunner.java b/geode-core/src/test/java/org/apache/geode/e2e/StoryRunner.java new file mode 100644 index 0000000..21921cb --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/e2e/StoryRunner.java @@ -0,0 +1,47 @@ +package org.apache.geode.e2e; + +import static org.jbehave.core.io.CodeLocations.codeLocationFromClass; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.jbehave.core.configuration.Configuration; +import org.jbehave.core.configuration.MostUsefulConfiguration; +import org.jbehave.core.io.LoadFromClasspath; +import org.jbehave.core.io.StoryFinder; +import org.jbehave.core.junit.JUnitStories; +import org.jbehave.core.junit.JUnitStory; +import org.jbehave.core.reporters.Format; +import org.jbehave.core.reporters.StoryReporterBuilder; +import org.jbehave.core.steps.InjectableStepsFactory; +import org.jbehave.core.steps.InstanceStepsFactory; + +public class StoryRunner extends JUnitStories { + + // Here we specify the configuration, starting from default MostUsefulConfiguration, and changing only what is need ed + @Override + public Configuration configuration() { + return new MostUsefulConfiguration() + // where to find the stories + .useStoryLoader(new LoadFromClasspath(this.getClass())) + // CONSOLE and TXT reporting + .useStoryReporterBuilder(new StoryReporterBuilder().withDefaultFormats() + .withFormats(Format.ANSI_CONSOLE, Format.TXT)); + } + + // Here we specify the steps classes + @Override + public InjectableStepsFactory stepsFactory() { + // varargs, can have more that one steps classes + return new InstanceStepsFactory(configuration(), new GetPutSteps()); + } + + @Override + protected List<String> storyPaths() { + String codeLocation = codeLocationFromClass(this.getClass()).getFile() + "../../resources/test"; + List<String> stories = new ArrayList<>(); + stories.add("**/*.story"); + return new StoryFinder().findPaths(codeLocation, stories, Collections.EMPTY_LIST); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/75521268/geode-core/src/test/java/org/apache/geode/e2e/container/DockerCluster.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/e2e/container/DockerCluster.java b/geode-core/src/test/java/org/apache/geode/e2e/container/DockerCluster.java index 3be2feb..c9a4478 100644 --- a/geode-core/src/test/java/org/apache/geode/e2e/container/DockerCluster.java +++ b/geode-core/src/test/java/org/apache/geode/e2e/container/DockerCluster.java @@ -4,15 +4,20 @@ import static com.google.common.base.Charsets.*; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import com.spotify.docker.client.DefaultDockerClient; import com.spotify.docker.client.DockerClient; import com.spotify.docker.client.LogStream; import com.spotify.docker.client.exceptions.DockerException; +import com.spotify.docker.client.messages.Container; import com.spotify.docker.client.messages.ContainerConfig; import com.spotify.docker.client.messages.ContainerCreation; import com.spotify.docker.client.messages.HostConfig; +import com.spotify.docker.client.messages.NetworkSettings; +import com.spotify.docker.client.messages.PortBinding; public class DockerCluster { @@ -21,39 +26,52 @@ public class DockerCluster { private int serverCount; private String name; private List<String> nodeIds; - private String locatorAddress; + private String locatorHost; + private int locatorPort; - public DockerCluster(String name, int serverCount) { - this(name, 1, serverCount); - } - - public DockerCluster(String name, int locatorCount, int serverCount) { + public DockerCluster(String name) { docker = DefaultDockerClient.builder(). uri("unix:///var/run/docker.sock").build(); this.name = name; - this.locatorCount = locatorCount; - this.serverCount = serverCount; this.nodeIds = new ArrayList<>(); } + public void setServerCount(int count) { + this.serverCount = count; + } + + public void setLocatorCount(int count) { + this.locatorCount = count; + } + public void start() throws Exception { startLocators(); startServers(); } public String startContainer(int index) throws DockerException, InterruptedException { + return startContainer(index, new HashMap<>()); + } + + public String startContainer(int index, Map<String, List<PortBinding>> portBindings) throws DockerException, InterruptedException { String geodeHome = System.getenv("GEODE_HOME"); + if (geodeHome == null) { + throw new IllegalStateException("GEODE_HOME environment variable is not set"); + } + String vol = String.format("%s:/tmp/work", geodeHome); HostConfig hostConfig = HostConfig. builder(). + portBindings(portBindings). appendBinds(vol). build(); ContainerConfig config = ContainerConfig.builder(). image("gemfire/ubuntu-gradle"). openStdin(true). + exposedPorts(portBindings.keySet()). hostname(String.format("%s-%d", name, index)). hostConfig(hostConfig). workingDir("/tmp"). @@ -77,7 +95,12 @@ public class DockerCluster { String.format("--name=%s-locator-%d", name, i) }; - String id = startContainer(i); + Map<String, List<PortBinding>> ports = new HashMap<>(); + List<PortBinding> binding = new ArrayList<>(); + binding.add(PortBinding.of("HostPort", (10334 + i) + "")); + ports.put((10334 + i) + "/tcp", binding); + + String id = startContainer(i, ports); execCommand(id, true, null, command); while (gfshCommand(null, null) != 0) { @@ -85,19 +108,28 @@ public class DockerCluster { } } - locatorAddress = String.format("%s[10334]", docker.inspectContainer(nodeIds.get(0)).networkSettings().ipAddress()); + // Let's get the host port which is mapped to the container 10334 port + NetworkSettings networks = docker.inspectContainer(nodeIds.get(0)).networkSettings(); + locatorPort = Integer.parseInt(networks.ports().get("10334/tcp").get(0).hostPort()); } public void startServers() throws DockerException, InterruptedException { - for (int i = 0; i < serverCount+1; i++) { + String locatorAddress = String.format("%s[10334]", docker.inspectContainer(nodeIds.get(0)).networkSettings().ipAddress()); + for (int i = 0; i < serverCount; i++) { String[] command = { "/tmp/work/bin/gfsh", "start server", String.format("--name=%s-server-%d", name, i), - String.format("--locators=%s", locatorAddress) + String.format("--locators=%s", locatorAddress), + "--hostname-for-clients=localhost" }; - String id = startContainer(i); + Map<String, List<PortBinding>> ports = new HashMap<>(); + List<PortBinding> binding = new ArrayList<>(); + binding.add(PortBinding.of("HostPort", (40404 + i) + "")); + ports.put((40404 + i) + "/tcp", binding); + + String id = startContainer(i, ports); execCommand(id, true, null, command); } @@ -122,6 +154,10 @@ public class DockerCluster { } } + public int gfshCommand(String command) throws DockerException, InterruptedException { + return gfshCommand(command, null); + } + public int gfshCommand(String command, ResultCallback callback) throws DockerException, InterruptedException { String locatorId = nodeIds.get(0); List<String> gfshCmd = new ArrayList<>(); @@ -137,14 +173,20 @@ public class DockerCluster { public int execCommand(String id, boolean startDetached, ResultCallback callback, String... command) throws DockerException, InterruptedException { List<DockerClient.ExecCreateParam> execParams = new ArrayList<>(); - execParams.add(DockerClient.ExecCreateParam.attachStdout()); - execParams.add(DockerClient.ExecCreateParam.attachStderr()); - execParams.add(DockerClient.ExecCreateParam.detach(startDetached)); + + if (startDetached) { + execParams.add(DockerClient.ExecCreateParam.detach(startDetached)); + } else { + execParams.add(DockerClient.ExecCreateParam.attachStdout()); + execParams.add(DockerClient.ExecCreateParam.attachStderr()); + } String execId = docker.execCreate(id, command, execParams.toArray(new DockerClient.ExecCreateParam[]{})); + LogStream output = docker.execStart(execId); if (startDetached) { + output.close(); return 0; } @@ -155,7 +197,7 @@ public class DockerCluster { if (buffer.indexOf("\n") >= 0) { int n; - while ((n = buffer.indexOf("\n")) >=0 ) { + while ((n = buffer.indexOf("\n")) >= 0) { System.out.println("[gfsh]: " + buffer.substring(0, n)); if (callback != null) { callback.call(buffer.substring(0, n)); @@ -165,6 +207,8 @@ public class DockerCluster { } } + output.close(); + return docker.execInspect(execId).exitCode(); } @@ -176,7 +220,22 @@ public class DockerCluster { docker.close(); } - public String getLocatorAddress() { - return locatorAddress; + public String getLocatorHost() { + return locatorHost; + } + + public int getLocatorPort() { + return locatorPort; + } + + public static void scorch() throws DockerException, InterruptedException { + DockerClient docker = DefaultDockerClient.builder(). + uri("unix:///var/run/docker.sock").build(); + + List<Container> containers = docker.listContainers(); + for (Container c : containers) { + docker.stopContainer(c.id(), 0); + docker.removeContainer(c.id()); + } } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/75521268/geode-core/src/test/java/org/apache/geode/e2e/container/ResultCallback.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/e2e/container/ResultCallback.java b/geode-core/src/test/java/org/apache/geode/e2e/container/ResultCallback.java new file mode 100644 index 0000000..03eefbf --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/e2e/container/ResultCallback.java @@ -0,0 +1,6 @@ +package org.apache.geode.e2e.container; + +public interface ResultCallback { + + void call(String output); +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/75521268/geode-core/src/test/resources/org/apache/geode/e2e/get_put.story ---------------------------------------------------------------------- diff --git a/geode-core/src/test/resources/org/apache/geode/e2e/get_put.story b/geode-core/src/test/resources/org/apache/geode/e2e/get_put.story new file mode 100644 index 0000000..b981023 --- /dev/null +++ b/geode-core/src/test/resources/org/apache/geode/e2e/get_put.story @@ -0,0 +1,5 @@ +Scenario: gfsh can start and manage a cluster +Given cluster is started with 1 locators and 2 servers +Given region FOO is created as REPLICATE +When I put 100 entries into region FOO +Then I can get 100 entries from region FOO http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/75521268/gradle/test.gradle ---------------------------------------------------------------------- diff --git a/gradle/test.gradle b/gradle/test.gradle index 5b35db4..4b4e00d 100644 --- a/gradle/test.gradle +++ b/gradle/test.gradle @@ -72,6 +72,7 @@ subprojects { testCompile 'org.jmock:jmock-legacy:' + project.'jmock.version' testCompile 'pl.pragmatists:JUnitParams:' + project.'JUnitParams.version' testCompile 'com.spotify:docker-client:5.0.2' + testCompile 'org.jbehave:jbehave-core:4.0.5' testRuntime 'cglib:cglib:' + project.'cglib.version' testRuntime 'org.ow2.asm:asm:' + project.'asm.version'