Skip to content

Commit

Permalink
GEODE-9156: Replace docker-compose-rule with testcontainers in geode-…
Browse files Browse the repository at this point in the history
…assembly (apache#6385)

Something to note when doing SSL testing: testcontainers does not let
you set the container name (using `container_name` in your compose.yml).
This ultimately means that reverse IP lookups produce hostnames that
look something like `project_service_index`. The problem is that these
names are not RFC compliant as they contain underscores. This can break
some aspects of SSL validation. I've had to work around this by renaming
containers in various test classes.
  • Loading branch information
jdeppe-pivotal authored Apr 30, 2021
1 parent d15601d commit 473af50
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 322 deletions.
10 changes: 0 additions & 10 deletions boms/geode-all-bom/src/test/resources/expected-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -492,16 +492,6 @@
<artifactId>json-path</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.palantir.docker.compose</groupId>
<artifactId>docker-compose-rule-core</artifactId>
<version>0.31.1</version>
</dependency>
<dependency>
<groupId>com.palantir.docker.compose</groupId>
<artifactId>docker-compose-rule-junit4</artifactId>
<version>0.31.1</version>
</dependency>
<dependency>
<groupId>com.pholser</groupId>
<artifactId>junit-quickcheck-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,6 @@ class DependencyConstraints implements Plugin<Project> {
entry('json-path')
}

dependencySet(group: 'com.palantir.docker.compose', version: '0.31.1') {
entry('docker-compose-rule-core')
entry('docker-compose-rule-junit4')
}

dependencySet(group: 'com.pholser', version: '1.0') {
entry('junit-quickcheck-core')
entry('junit-quickcheck-generators')
Expand Down
7 changes: 1 addition & 6 deletions geode-assembly/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,6 @@ repositories {
maven {
url 'https://repo.gradle.org/gradle/libs-releases'
}
// docker-compose-rule is published on bintray
maven {
url 'https://dl.bintray.com/palantir/releases'
}
}

def webServersDir = "$buildDir/generated-resources/webservers"
Expand Down Expand Up @@ -269,8 +265,7 @@ dependencies {
// don't have it be the same version as the outer gradle version.
acceptanceTestImplementation('org.gradle:gradle-tooling-api:5.1.1')

acceptanceTestImplementation('com.palantir.docker.compose:docker-compose-rule-core')
acceptanceTestImplementation('com.palantir.docker.compose:docker-compose-rule-junit4')
acceptanceTestImplementation('org.testcontainers:testcontainers')

uiTestImplementation(project(':geode-core'))
uiTestImplementation(project(':geode-dunit')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
*/
package org.apache.geode.cache.wan;

import static com.palantir.docker.compose.execution.DockerComposeExecArgument.arguments;
import static com.palantir.docker.compose.execution.DockerComposeExecOption.options;
import static org.apache.geode.cache.Region.SEPARATOR;
import static org.apache.geode.distributed.ConfigurationProperties.DISTRIBUTED_SYSTEM_ID;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
Expand All @@ -26,15 +24,13 @@
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import com.palantir.docker.compose.DockerComposeRule;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
Expand All @@ -48,12 +44,12 @@
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.persistence.PartitionOfflineException;
import org.apache.geode.client.sni.NotOnWindowsDockerRule;
import org.apache.geode.distributed.Locator;
import org.apache.geode.internal.cache.ForceReattemptException;
import org.apache.geode.internal.cache.PoolStats;
import org.apache.geode.internal.cache.wan.AbstractGatewaySender;
import org.apache.geode.internal.cache.wan.InternalGatewaySenderFactory;
import org.apache.geode.rules.DockerComposeRule;
import org.apache.geode.test.dunit.IgnoredException;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.rules.DistributedRule;
Expand All @@ -63,20 +59,17 @@
/**
* These tests use two Geode sites:
*
* - One site (the remote one) consisting of a 2-server, 1-locator Geode cluster.
* The servers host a partition region (region-wan) and have gateway senders to receive events
* from the other site with the same value for hostname-for-senders and listening on the
* same port (2324).
* The servers and locator run each inside a Docker container and are not route-able
* from the host (where this JUnit test is running).
* Another Docker container is running the HAProxy image and it's set up as a TCP load balancer.
* The other site connects to the locator and to the gateway receivers via the
* TCP load balancer that forwards traffic directed to the 20334 port to the locator and
* traffic directed to the 2324 port to the receivers in a round robin fashion.
* - One site (the remote one) consisting of a 2-server, 1-locator Geode cluster. The servers host a
* partition region (region-wan) and have gateway senders to receive events from the other site with
* the same value for hostname-for-senders and listening on the same port (2324). The servers and
* locator run each inside a Docker container and are not route-able from the host (where this JUnit
* test is running). Another Docker container is running the HAProxy image and it's set up as a TCP
* load balancer. The other site connects to the locator and to the gateway receivers via the TCP
* load balancer that forwards traffic directed to the 20334 port to the locator and traffic
* directed to the 2324 port to the receivers in a round robin fashion.
*
* - Another site consisting of a 1-server, 1-locator Geode cluster.
* The server hosts a partition region (region-wan) and has a gateway receiver
* to send events to the remote site.
* - Another site consisting of a 1-server, 1-locator Geode cluster. The server hosts a partition
* region (region-wan) and has a gateway receiver to send events to the remote site.
*/
@Category({WanTest.class})
public class SeveralGatewayReceiversWithSamePortAndHostnameForSendersTest {
Expand All @@ -89,12 +82,12 @@ public class SeveralGatewayReceiversWithSamePortAndHostnameForSendersTest {
SeveralGatewayReceiversWithSamePortAndHostnameForSendersTest.class
.getResource("docker-compose.yml");

// Docker compose does not work on windows in CI. Ignore this test on windows
// Using a RuleChain to make sure we ignore the test before the rule comes into play
@ClassRule
public static NotOnWindowsDockerRule docker =
new NotOnWindowsDockerRule(() -> DockerComposeRule.builder()
.file(DOCKER_COMPOSE_PATH.getPath()).build());
public static DockerComposeRule docker = new DockerComposeRule.Builder()
.file(DOCKER_COMPOSE_PATH.getPath())
.service("haproxy", 20334)
.service("haproxy", 2324)
.build();

@Rule
public DistributedRule distributedRule =
Expand All @@ -103,36 +96,35 @@ public class SeveralGatewayReceiversWithSamePortAndHostnameForSendersTest {
@BeforeClass
public static void beforeClass() throws Exception {
// Start locator
docker.get().exec(options("-T"), "locator",
arguments("gfsh", "run", "--file=/geode/scripts/geode-starter-locator.gfsh"));
docker.execForService("locator", "gfsh", "run",
"--file=/geode/scripts/geode-starter-locator.gfsh");
// Start server1
docker.get().exec(options("-T"), "server1",
arguments("gfsh", "run", "--file=/geode/scripts/geode-starter-server1.gfsh"));
docker.execForService("server1", "gfsh", "run",
"--file=/geode/scripts/geode-starter-server1.gfsh");
// Start server2
docker.get().exec(options("-T"), "server2",
arguments("gfsh", "run", "--file=/geode/scripts/geode-starter-server2.gfsh"));
docker.execForService("server2", "gfsh", "run",
"--file=/geode/scripts/geode-starter-server2.gfsh");
// Create partition region and gateway receiver
docker.get().exec(options("-T"), "locator",
arguments("gfsh", "run", "--file=/geode/scripts/geode-starter-create.gfsh"));
docker.execForService("locator", "gfsh", "run",
"--file=/geode/scripts/geode-starter-create.gfsh");
}

public SeveralGatewayReceiversWithSamePortAndHostnameForSendersTest() {
super();
}

/**
* The aim of this test is verify that when several gateway receivers in a remote site
* share the same port and hostname-for-senders, the pings sent from the gateway senders
* reach the right gateway receiver and not just any of the receivers. Failure to do this
* may result in the closing of connections by a gateway receiver for not having
* received the ping in time.
* The aim of this test is verify that when several gateway receivers in a remote site share the
* same port and hostname-for-senders, the pings sent from the gateway senders reach the right
* gateway receiver and not just any of the receivers. Failure to do this may result in the
* closing of connections by a gateway receiver for not having received the ping in time.
*/
@Test
public void testPingsToReceiversWithSamePortAndHostnameForSendersReachTheRightReceivers()
throws InterruptedException {
String senderId = "ln";
String regionName = "region-wan";
final int remoteLocPort = 20334;
final int remoteLocPort = docker.getExternalPortForService("haproxy", 20334);

int locPort = createLocator(VM.getVM(0), 1, remoteLocPort);

Expand Down Expand Up @@ -168,7 +160,7 @@ public void testPingsToReceiversWithSamePortAndHostnameForSendersReachTheRightRe
public void testSerialGatewaySenderThreadsConnectToSameReceiver() {
String senderId = "ln";
String regionName = "region-wan";
final int remoteLocPort = 20334;
final int remoteLocPort = docker.getExternalPortForService("haproxy", 20334);

int locPort = createLocator(VM.getVM(0), 1, remoteLocPort);

Expand All @@ -188,7 +180,7 @@ public void testSerialGatewaySenderThreadsConnectToSameReceiver() {
@Test
public void testTwoSendersWithSameIdShouldUseSameValueForEnforceThreadsConnectToSameServer() {
String senderId = "ln";
final int remoteLocPort = 20334;
final int remoteLocPort = docker.getExternalPortForService("haproxy", 20334);

int locPort = createLocator(VM.getVM(0), 1, remoteLocPort);

Expand Down Expand Up @@ -225,20 +217,9 @@ private boolean allDispatchersConnectedToSameReceiver(int server) {
return true;
}


private String runListGatewayReceiversCommandInServer(int serverN) {
String result = "";
try {
result = docker.get().exec(options("-T"), "locator",
arguments("gfsh", "run",
"--file=/geode/scripts/geode-list-gateway-receivers-server" + serverN + ".gfsh"));
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
return result;
}
return docker.execForService("locator", "gfsh", "run",
"--file=/geode/scripts/geode-list-gateway-receivers-server" + serverN + ".gfsh");
}

private Vector<String> parseSendersConnectedFromGfshOutput(String gfshOutput) {
Expand Down Expand Up @@ -293,7 +274,8 @@ public static void createGatewaySender(VM vm, String dsName, int remoteDsId,
public static void createGatewaySender(VM vm, String dsName, int remoteDsId,
boolean isParallel, Integer batchSize,
int numDispatchers,
GatewaySender.OrderPolicy orderPolicy, boolean enforceThreadsConnectToSameReceiver) {
GatewaySender.OrderPolicy orderPolicy,
boolean enforceThreadsConnectToSameReceiver) {
vm.invoke(() -> {
final IgnoredException exln = IgnoredException.addIgnoredException("Could not connect");
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
*/
package org.apache.geode.client.sni;

import static com.palantir.docker.compose.execution.DockerComposeExecArgument.arguments;
import static com.palantir.docker.compose.execution.DockerComposeExecOption.options;
import static org.apache.geode.cache.Region.SEPARATOR;
import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS;
import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENDPOINT_IDENTIFICATION_ENABLED;
Expand All @@ -27,19 +25,16 @@
import static org.apache.geode.test.util.ResourceUtils.createTempFileFromResource;
import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;
import java.net.URL;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

import com.palantir.docker.compose.DockerComposeRule;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TestRule;

import org.apache.geode.cache.Operation;
import org.apache.geode.cache.Region;
Expand All @@ -57,38 +52,32 @@
import org.apache.geode.cache.query.CqQuery;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.RegionNotFoundException;
import org.apache.geode.test.junit.rules.IgnoreOnWindowsRule;
import org.apache.geode.rules.DockerComposeRule;

public class ClientSNICQAcceptanceTest {

private static final URL DOCKER_COMPOSE_PATH =
ClientSNICQAcceptanceTest.class.getResource("docker-compose.yml");

// Docker compose does not work on windows in CI. Ignore this test on windows
// Using a RuleChain to make sure we ignore the test before the rule comes into play
@ClassRule
public static TestRule ignoreOnWindowsRule = new IgnoreOnWindowsRule();

@ClassRule
public static NotOnWindowsDockerRule docker =
new NotOnWindowsDockerRule(() -> DockerComposeRule.builder()
.file(DOCKER_COMPOSE_PATH.getPath()).build());
public static DockerComposeRule docker = new DockerComposeRule.Builder()
.file(DOCKER_COMPOSE_PATH.getPath())
.service("haproxy", 15443)
.build();

private CqQuery cqTracker;

AtomicInteger eventCreateCounter = new AtomicInteger(0);
AtomicInteger eventUpdateCounter = new AtomicInteger(0);
private ClientCache cache;
private Region<String, Integer> region;
private static String trustStorePath;

class SNICQListener implements CqListener {


@Override
public void onEvent(CqEvent cqEvent) {
Operation queryOperation = cqEvent.getQueryOperation();


if (queryOperation.isUpdate()) {
eventUpdateCounter.incrementAndGet();
} else if (queryOperation.isCreate()) {
Expand All @@ -102,17 +91,14 @@ public void onError(CqEvent aCqEvent) {
}
}

private static String trustStorePath;

@BeforeClass
public static void beforeClass() throws IOException, InterruptedException {
public static void beforeClass() {
trustStorePath =
createTempFileFromResource(ClientSNICQAcceptanceTest.class,
"geode-config/truststore.jks")
.getAbsolutePath();
docker.get().exec(options("-T"), "geode",
arguments("gfsh", "run", "--file=/geode/scripts/geode-starter.gfsh"));

docker.loggingExecForService("geode",
"gfsh", "run", "--file=/geode/scripts/geode-starter.gfsh");
}

@AfterClass
Expand All @@ -122,13 +108,8 @@ public static void afterClass() {
}

private static void printlog(String name) {
try {
String output =
docker.get().exec(options("-T"), "geode",
arguments("cat", name + "/" + name + ".log"));
System.out.println(name + " log file--------------------------------\n" + output);
} catch (Throwable ignore) {
}
String output = docker.execForService("geode", "cat", name + "/" + name + ".log");
System.out.println(name + " log file--------------------------------\n" + output);
}

@Before
Expand All @@ -142,10 +123,7 @@ public void before() throws Exception {
gemFireProps.setProperty(SSL_TRUSTSTORE_PASSWORD, "geode");
gemFireProps.setProperty(SSL_ENDPOINT_IDENTIFICATION_ENABLED, "true");

int proxyPort = docker.get().containers()
.container("haproxy")
.port(15443)
.getExternalPort();
int proxyPort = docker.getExternalPortForService("haproxy", 15443);
cache = new ClientCacheFactory(gemFireProps)
.addPoolLocator("locator-maeve", 10334)
.setPoolSocketFactory(ProxySocketFactories.sni("localhost",
Expand Down Expand Up @@ -188,10 +166,10 @@ public void performSimpleCQOverSNIProxy() throws Exception {
// the CQ has been closed. StatArchiveReader has a main() that we can use to get a printout
// of stat values
await().untilAsserted(() -> {
String stats = docker.get().exec(options("-T"), "geode",
arguments("java", "-cp", "/geode/lib/geode-dependencies.jar",
"org.apache.geode.internal.statistics.StatArchiveReader",
"stat", "server-dolores/statArchive.gfs", "CqServiceStats.numCqsClosed"));
String stats = docker.execForService("geode",
"java", "-cp", "/geode/lib/geode-dependencies.jar",
"org.apache.geode.internal.statistics.StatArchiveReader",
"stat", "server-dolores/statArchive.gfs", "CqServiceStats.numCqsClosed");
// the stat should transition from zero to one at some point
assertThat(stats).contains("0.0 1.0");
});
Expand Down
Loading

0 comments on commit 473af50

Please sign in to comment.