Skip to content

Commit 5c06cff

Browse files
committed
test(flagd): use newest testbed launchpad
Signed-off-by: Simon Schrottner <[email protected]>
1 parent b4fe2f4 commit 5c06cff

File tree

7 files changed

+55
-136
lines changed

7 files changed

+55
-136
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[submodule "providers/flagd/test-harness"]
55
path = providers/flagd/test-harness
66
url = https://github.com/open-feature/test-harness.git
7-
branch = v1.1.1
7+
branch = v1.3.1
88
[submodule "providers/flagd/spec"]
99
path = providers/flagd/spec
1010
url = https://github.com/open-feature/spec.git

providers/flagd/pom.xml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,13 +150,12 @@
150150
<scope>test</scope>
151151
</dependency>
152152
<dependency>
153-
<groupId>org.testcontainers</groupId>
154-
<artifactId>toxiproxy</artifactId>
155-
<version>1.20.4</version>
153+
<groupId>io.rest-assured</groupId>
154+
<artifactId>rest-assured</artifactId>
155+
<version>5.5.0</version>
156156
<scope>test</scope>
157157
</dependency>
158158
<!-- uncomment for logoutput during test runs -->
159-
160159
<dependency>
161160
<groupId>org.slf4j</groupId>
162161
<artifactId>slf4j-simple</artifactId>

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/e2e/FlagdContainer.java

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package dev.openfeature.contrib.providers.flagd.e2e;
22

3+
import dev.openfeature.contrib.providers.flagd.Config;
34
import java.io.File;
45
import java.nio.file.Files;
56
import java.util.List;
6-
import org.apache.logging.log4j.util.Strings;
77
import org.jetbrains.annotations.NotNull;
88
import org.testcontainers.containers.GenericContainer;
99
import org.testcontainers.containers.Network;
@@ -28,16 +28,25 @@ public class FlagdContainer extends GenericContainer<FlagdContainer> {
2828
private String feature;
2929

3030
public FlagdContainer() {
31-
this("");
31+
super(generateContainerName());
32+
this.feature = feature;
33+
this.addExposedPorts(8013, 8014, 8015, 8080);
3234
}
3335

34-
public FlagdContainer(String feature) {
35-
super(generateContainerName(feature));
36-
this.withReuse(true);
37-
this.feature = feature;
38-
if (!"socket".equals(this.feature)) this.addExposedPorts(8013, 8014, 8015, 8016);
36+
public int getPort(Config.Resolver resolver) {
37+
switch (resolver) {
38+
case RPC:
39+
return getMappedPort(8013);
40+
case IN_PROCESS:
41+
return getMappedPort(8015);
42+
default:
43+
return 0;
44+
}
3945
}
4046

47+
public String launchpad() {
48+
return this.getHost() + ":" + this.getMappedPort(8080);
49+
}
4150
/**
4251
* @return a {@link org.testcontainers.containers.GenericContainer} instance of envoy container using
4352
* flagd sync service as backend expose on port 9211
@@ -52,11 +61,8 @@ public static GenericContainer envoy() {
5261
.withNetworkAliases("envoy");
5362
}
5463

55-
public static @NotNull String generateContainerName(String feature) {
64+
public static @NotNull String generateContainerName() {
5665
String container = "ghcr.io/open-feature/flagd-testbed";
57-
if (!Strings.isBlank(feature)) {
58-
container += "-" + feature;
59-
}
6066
container += ":v" + version;
6167
return container;
6268
}

providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/e2e/steps/FlagSteps.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package dev.openfeature.contrib.providers.flagd.e2e.steps;
22

3-
import static java.util.concurrent.TimeUnit.MILLISECONDS;
43
import static org.assertj.core.api.Assertions.assertThat;
5-
import static org.awaitility.Awaitility.await;
64

75
import dev.openfeature.contrib.providers.flagd.e2e.State;
86
import dev.openfeature.sdk.FlagEvaluationDetails;
@@ -70,15 +68,9 @@ public void the_variant_should_be(String variant) {
7068
}
7169

7270
@Then("the flag should be part of the event payload")
73-
@Then("the flag was modified")
7471
public void the_flag_was_modified() {
75-
await().atMost(5000, MILLISECONDS).until(() -> state.events.stream()
76-
.anyMatch(event -> event.type.equals("change")
77-
&& event.details.getFlagsChanged().contains(state.flag.name)));
78-
state.lastEvent = state.events.stream()
79-
.filter(event -> event.type.equals("change")
80-
&& event.details.getFlagsChanged().contains(state.flag.name))
81-
.findFirst();
72+
Event event = state.lastEvent.orElseThrow(AssertionError::new);
73+
assertThat(event.details.getFlagsChanged()).contains(state.flag.name);
8274
}
8375

8476
public class Flag {
Lines changed: 30 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
package dev.openfeature.contrib.providers.flagd.e2e.steps;
22

3+
import static io.restassured.RestAssured.when;
4+
35
import com.fasterxml.jackson.databind.ObjectMapper;
46
import com.fasterxml.jackson.databind.ObjectReader;
5-
import dev.openfeature.contrib.providers.flagd.Config;
67
import dev.openfeature.contrib.providers.flagd.FlagdProvider;
78
import dev.openfeature.contrib.providers.flagd.e2e.FlagdContainer;
89
import dev.openfeature.contrib.providers.flagd.e2e.State;
910
import dev.openfeature.sdk.FeatureProvider;
1011
import dev.openfeature.sdk.OpenFeatureAPI;
11-
import eu.rekawek.toxiproxy.Proxy;
12-
import eu.rekawek.toxiproxy.ToxiproxyClient;
13-
import eu.rekawek.toxiproxy.model.ToxicDirection;
1412
import io.cucumber.java.After;
1513
import io.cucumber.java.AfterAll;
1614
import io.cucumber.java.Before;
@@ -22,126 +20,58 @@
2220
import java.nio.file.Files;
2321
import java.nio.file.Path;
2422
import java.nio.file.Paths;
25-
import java.util.HashMap;
26-
import java.util.Map;
2723
import java.util.Objects;
28-
import java.util.Timer;
29-
import java.util.TimerTask;
3024
import lombok.extern.slf4j.Slf4j;
3125
import org.apache.commons.lang3.RandomStringUtils;
3226
import org.junit.jupiter.api.parallel.Isolated;
3327
import org.testcontainers.containers.BindMode;
34-
import org.testcontainers.containers.Network;
35-
import org.testcontainers.containers.ToxiproxyContainer;
3628
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
3729

3830
@Isolated()
3931
@Slf4j
4032
public class ProviderSteps extends AbstractSteps {
4133

4234
public static final int UNAVAILABLE_PORT = 9999;
43-
static Map<ProviderType, FlagdContainer> containers = new HashMap<>();
44-
public static Network network = Network.newNetwork();
45-
public static ToxiproxyContainer toxiproxy =
46-
new ToxiproxyContainer("ghcr.io/shopify/toxiproxy:2.5.0").withNetwork(network);
47-
public static ToxiproxyClient toxiproxyClient;
35+
static FlagdContainer container;
4836

4937
static Path sharedTempDir;
5038

5139
public ProviderSteps(State state) {
5240
super(state);
5341
}
5442

55-
static String generateProxyName(Config.Resolver resolver, ProviderType providerType) {
56-
return providerType + "-" + resolver;
57-
}
58-
5943
@BeforeAll
6044
public static void beforeAll() throws IOException {
61-
toxiproxy.start();
62-
toxiproxyClient = new ToxiproxyClient(toxiproxy.getHost(), toxiproxy.getControlPort());
63-
toxiproxyClient.createProxy(
64-
generateProxyName(Config.Resolver.RPC, ProviderType.DEFAULT), "0.0.0.0:8666", "default:8013");
65-
66-
toxiproxyClient.createProxy(
67-
generateProxyName(Config.Resolver.IN_PROCESS, ProviderType.DEFAULT), "0.0.0.0:8667", "default:8015");
68-
toxiproxyClient.createProxy(
69-
generateProxyName(Config.Resolver.RPC, ProviderType.SSL), "0.0.0.0:8668", "ssl:8013");
70-
toxiproxyClient.createProxy(
71-
generateProxyName(Config.Resolver.IN_PROCESS, ProviderType.SSL), "0.0.0.0:8669", "ssl:8015");
72-
73-
containers.put(
74-
ProviderType.DEFAULT, new FlagdContainer().withNetwork(network).withNetworkAliases("default"));
75-
containers.put(
76-
ProviderType.SSL, new FlagdContainer("ssl").withNetwork(network).withNetworkAliases("ssl"));
45+
7746
sharedTempDir = Files.createDirectories(
7847
Paths.get("tmp/" + RandomStringUtils.randomAlphanumeric(8).toLowerCase() + "/"));
79-
containers.put(
80-
ProviderType.SOCKET,
81-
new FlagdContainer("socket")
82-
.withFileSystemBind(sharedTempDir.toAbsolutePath().toString(), "/tmp", BindMode.READ_WRITE));
48+
container = new FlagdContainer()
49+
.withFileSystemBind(sharedTempDir.toAbsolutePath().toString(), "/tmp", BindMode.READ_WRITE);
50+
;
8351
}
8452

8553
@AfterAll
8654
public static void afterAll() throws IOException {
87-
88-
containers.forEach((name, container) -> container.stop());
55+
container.stop();
8956
FileUtils.deleteDirectory(sharedTempDir.toFile());
90-
toxiproxyClient.reset();
91-
toxiproxy.stop();
9257
}
9358

9459
@Before
9560
public void before() throws IOException {
96-
97-
toxiproxyClient.getProxies().forEach(proxy -> {
98-
try {
99-
proxy.toxics().getAll().forEach(toxic -> {
100-
try {
101-
toxic.remove();
102-
} catch (IOException e) {
103-
log.debug("Failed to remove timout", e);
104-
}
105-
});
106-
} catch (IOException e) {
107-
log.debug("Failed to remove timout", e);
108-
}
109-
});
110-
111-
containers.values().stream()
112-
.filter(containers -> !containers.isRunning())
113-
.forEach(FlagdContainer::start);
61+
if (!container.isRunning()) {
62+
container.start();
63+
}
11464
}
11565

11666
@After
11767
public void tearDown() {
11868
OpenFeatureAPI.getInstance().shutdown();
11969
}
12070

121-
public int getPort(Config.Resolver resolver, ProviderType providerType) {
122-
switch (resolver) {
123-
case RPC:
124-
switch (providerType) {
125-
case DEFAULT:
126-
return toxiproxy.getMappedPort(8666);
127-
case SSL:
128-
return toxiproxy.getMappedPort(8668);
129-
}
130-
case IN_PROCESS:
131-
switch (providerType) {
132-
case DEFAULT:
133-
return toxiproxy.getMappedPort(8667);
134-
case SSL:
135-
return toxiproxy.getMappedPort(8669);
136-
}
137-
default:
138-
throw new IllegalArgumentException("Unsupported resolver: " + resolver);
139-
}
140-
}
141-
14271
@Given("a {} flagd provider")
143-
public void setupProvider(String providerType) throws IOException {
144-
state.builder.deadline(500).keepAlive(0).retryGracePeriod(3);
72+
public void setupProvider(String providerType) throws IOException, InterruptedException {
73+
String flagdConfig = "default";
74+
state.builder.deadline(1000).keepAlive(0).retryGracePeriod(3);
14575
boolean wait = true;
14676
switch (providerType) {
14777
case "unavailable":
@@ -163,9 +93,10 @@ public void setupProvider(String providerType) throws IOException {
16393
String absolutePath = file.getAbsolutePath();
16494
this.state.providerType = ProviderType.SSL;
16595
state.builder
166-
.port(getPort(State.resolverType, state.providerType))
96+
.port(container.getPort(State.resolverType))
16797
.tls(true)
16898
.certPath(absolutePath);
99+
flagdConfig = "ssl";
169100
break;
170101
case "offline":
171102
File flags = new File("test-harness/flags");
@@ -185,9 +116,15 @@ public void setupProvider(String providerType) throws IOException {
185116

186117
default:
187118
this.state.providerType = ProviderType.DEFAULT;
188-
state.builder.port(getPort(State.resolverType, state.providerType));
119+
state.builder.port(container.getPort(State.resolverType));
189120
break;
190121
}
122+
when().post("http://" + container.launchpad() + "/start?config={config}", flagdConfig)
123+
.then()
124+
.statusCode(200);
125+
126+
// giving flagd a little time to start
127+
Thread.sleep(100);
191128
FeatureProvider provider =
192129
new FlagdProvider(state.builder.resolverType(State.resolverType).build());
193130

@@ -203,30 +140,15 @@ public void setupProvider(String providerType) throws IOException {
203140
@When("the connection is lost for {int}s")
204141
public void the_connection_is_lost_for(int seconds) throws InterruptedException, IOException {
205142
log.info("Timeout and wait for {} seconds", seconds);
206-
String randomizer = RandomStringUtils.randomAlphanumeric(5);
207-
String timeoutUpName = "restart-up-" + randomizer;
208-
String timeoutDownName = "restart-down-" + randomizer;
209-
Proxy proxy = toxiproxyClient.getProxy(generateProxyName(State.resolverType, state.providerType));
210-
proxy.toxics().timeout(timeoutDownName, ToxicDirection.DOWNSTREAM, seconds);
211-
proxy.toxics().timeout(timeoutUpName, ToxicDirection.UPSTREAM, seconds);
212-
213-
TimerTask task = new TimerTask() {
214-
public void run() {
215-
try {
216-
proxy.toxics().get(timeoutUpName).remove();
217-
proxy.toxics().get(timeoutDownName).remove();
218-
} catch (IOException e) {
219-
log.debug("Failed to remove timeout", e);
220-
}
221-
}
222-
};
223-
Timer restartTimer = new Timer("Timer" + randomizer);
224143

225-
restartTimer.schedule(task, seconds * 1000L);
144+
when().post("http://" + container.launchpad() + "/restart?seconds={seconds}", seconds)
145+
.then()
146+
.statusCode(200);
226147
}
227148

228-
static FlagdContainer getContainer(ProviderType providerType) {
229-
log.info("getting container for {}", providerType);
230-
return containers.getOrDefault(providerType, containers.get(ProviderType.DEFAULT));
149+
@When("the flag was modified")
150+
public void the_flag_was_modded() {
151+
152+
when().post("http://" + container.launchpad() + "/change").then().statusCode(200);
231153
}
232154
}

providers/flagd/test-harness

0 commit comments

Comments
 (0)