Skip to content

Commit c506fea

Browse files
committed
fixup: using toxiproxy
Signed-off-by: Simon Schrottner <[email protected]>
1 parent 4a37f8e commit c506fea

File tree

8 files changed

+90
-43
lines changed

8 files changed

+90
-43
lines changed

providers/flagd/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@
149149
<version>1.20.4</version>
150150
<scope>test</scope>
151151
</dependency>
152+
<dependency>
153+
<groupId>org.testcontainers</groupId>
154+
<artifactId>toxiproxy</artifactId>
155+
<version>1.20.4</version>
156+
<scope>test</scope>
157+
</dependency>
152158

153159
</dependencies>
154160

providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/common/ConnectionEvent.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import dev.openfeature.sdk.ImmutableStructure;
44
import dev.openfeature.sdk.Structure;
5+
import lombok.Getter;
56
import java.util.Collections;
67
import java.util.List;
78

@@ -16,6 +17,7 @@ public class ConnectionEvent {
1617
/**
1718
* The current state of the connection.
1819
*/
20+
@Getter
1921
private final ConnectionState connected;
2022

2123
/**
@@ -121,4 +123,5 @@ public boolean isConnected() {
121123
public boolean isStale() {
122124
return this.connected == ConnectionState.STALE;
123125
}
126+
124127
}

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

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

3+
import com.github.dockerjava.api.command.PauseContainerCmd;
4+
import com.github.dockerjava.api.command.SyncDockerCmd;
5+
import com.github.dockerjava.api.command.UnpauseContainerCmd;
36
import dev.openfeature.contrib.providers.flagd.Config;
47
import org.apache.logging.log4j.util.Strings;
58
import org.jetbrains.annotations.NotNull;
69
import org.testcontainers.containers.GenericContainer;
710
import org.testcontainers.containers.Network;
8-
import org.testcontainers.containers.wait.strategy.Wait;
9-
import org.testcontainers.containers.wait.strategy.WaitStrategy;
1011
import org.testcontainers.utility.DockerImageName;
1112
import org.testcontainers.utility.MountableFile;
1213

1314
import java.io.File;
1415
import java.nio.file.Files;
1516
import java.util.List;
17+
import java.util.Timer;
18+
import java.util.TimerTask;
1619

1720
public class FlagdContainer extends GenericContainer<FlagdContainer> {
1821
private static final String version;
@@ -43,13 +46,6 @@ public FlagdContainer(String feature) {
4346
this.addExposedPorts(8013, 8014, 8015, 8016);
4447
}
4548

46-
@Override
47-
public void start() {
48-
if (!"socket".equals(this.feature))
49-
this.addExposedPorts(8013, 8014, 8015, 8016);
50-
super.start();
51-
waitUntilContainerStarted();
52-
}
5349

5450
public int getPort(Config.Resolver resolver) {
5551
waitUntilContainerStarted();

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.junit.platform.suite.api.IncludeEngines;
1010
import org.junit.platform.suite.api.IncludeTags;
1111
import org.junit.platform.suite.api.SelectDirectories;
12+
import org.junit.platform.suite.api.SelectFile;
1213
import org.junit.platform.suite.api.Suite;
1314
import org.testcontainers.junit.jupiter.Testcontainers;
1415

@@ -22,11 +23,13 @@
2223
@Order(value = Integer.MAX_VALUE)
2324
@Suite
2425
@IncludeEngines("cucumber")
25-
@SelectDirectories("test-harness/gherkin")
26+
//@SelectDirectories("test-harness/gherkin")
27+
@SelectFile("test-harness/gherkin/connection.feature")
2628
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
2729
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "dev.openfeature.contrib.providers.flagd.e2e.steps")
2830
@ConfigurationParameter(key = OBJECT_FACTORY_PROPERTY_NAME, value = "io.cucumber.picocontainer.PicoFactory")
29-
@IncludeTags("rpc")
31+
@IncludeTags({"rpc","reconnect"})
32+
@ExcludeTags({"targetURI", "customCert", "unixsocket"})
3033
@Testcontainers
3134
public class RunRpcTest {
3235

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
import dev.openfeature.sdk.MutableContext;
1111

1212
import java.util.ArrayList;
13+
import java.util.LinkedList;
14+
import java.util.List;
1315
import java.util.Optional;
1416

1517
public class State {
1618
public ProviderType providerType;
1719
public Client client;
18-
public ArrayList<Event> events = new ArrayList<>();
20+
public List<Event> events = new LinkedList<>();
1921
public Optional<Event> lastEvent;
2022
public FlagSteps.Flag flag;
2123
public MutableContext context

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,29 @@
77
import io.cucumber.java.en.When;
88
import org.jetbrains.annotations.NotNull;
99
import org.junit.jupiter.api.parallel.Isolated;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
1012

1113
import java.util.ArrayList;
14+
import java.util.LinkedList;
1215

1316
import static java.util.concurrent.TimeUnit.MILLISECONDS;
1417
import static org.awaitility.Awaitility.await;
1518

1619
@Isolated()
1720
public class EventSteps extends AbstractSteps {
21+
private static final Logger LOG = LoggerFactory.getLogger(EventSteps.class);
1822

1923

2024
public EventSteps(State state) {
2125
super(state);
22-
state.events = new ArrayList<>();
26+
state.events = new LinkedList<>();
2327
}
2428

2529
@Given("a {} event handler")
2630
public void a_stale_event_handler(String eventType) {
2731
state.client.on(mapEventType(eventType), eventDetails -> {
28-
System.out.println(eventType);
32+
LOG.info("event tracked for {} ", eventType);
2933
state.events.add(new Event(eventType, eventDetails));
3034
});
3135
}
@@ -52,17 +56,15 @@ public void eventWasFired(String eventType) {
5256

5357
@Then("the {} event handler should have been executed")
5458
public void eventHandlerShouldBeExecuted(String eventType) {
55-
eventHandlerShouldBeExecutedWithin(eventType, 10000);
59+
eventHandlerShouldBeExecutedWithin(eventType, 30000);
5660
}
5761

5862
@Then("the {} event handler should have been executed within {int}ms")
5963
public void eventHandlerShouldBeExecutedWithin(String eventType, int ms) {
64+
LOG.info("waiting for eventtype: {}", eventType);
6065
await()
6166
.atMost(ms, MILLISECONDS)
62-
.until(() -> {
63-
state.events.forEach((e) -> System.out.println(e.type));
64-
return state.events.stream().anyMatch(event -> event.type.equals(eventType));
65-
});
67+
.until(() -> state.events.stream().anyMatch(event -> event.type.equals(eventType)));
6668
state.lastEvent = state.events.stream().filter(event -> event.type.equals(eventType)).findFirst();
6769
state.events.removeIf(event -> event.type.equals(eventType));
6870
}

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

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

3+
import dev.openfeature.contrib.providers.flagd.Config;
34
import dev.openfeature.contrib.providers.flagd.FlagdProvider;
45
import dev.openfeature.contrib.providers.flagd.e2e.FlagdContainer;
56
import dev.openfeature.contrib.providers.flagd.e2e.State;
6-
import dev.openfeature.sdk.Client;
77
import dev.openfeature.sdk.FeatureProvider;
88
import dev.openfeature.sdk.OpenFeatureAPI;
9+
import eu.rekawek.toxiproxy.Proxy;
10+
import eu.rekawek.toxiproxy.ToxiproxyClient;
11+
import eu.rekawek.toxiproxy.model.ToxicDirection;
12+
import eu.rekawek.toxiproxy.model.toxic.Timeout;
913
import io.cucumber.java.After;
1014
import io.cucumber.java.AfterAll;
1115
import io.cucumber.java.Before;
@@ -17,6 +21,8 @@
1721
import org.slf4j.Logger;
1822
import org.slf4j.LoggerFactory;
1923
import org.testcontainers.containers.BindMode;
24+
import org.testcontainers.containers.Network;
25+
import org.testcontainers.containers.ToxiproxyContainer;
2026
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
2127

2228
import java.io.File;
@@ -36,6 +42,11 @@ public class ProviderSteps extends AbstractSteps {
3642

3743
public static final int UNAVAILABLE_PORT = 9999;
3844
static Map<ProviderType, FlagdContainer> containers = new HashMap<>();
45+
static Map<ProviderType, Map<Config.Resolver, String>> proxyports = new HashMap<>();
46+
public static Network network = Network.newNetwork();
47+
public static ToxiproxyContainer toxiproxy = new ToxiproxyContainer("ghcr.io/shopify/toxiproxy:2.5.0")
48+
.withNetwork(network).withCreateContainerCmdModifier((cmd -> cmd.withName("toxiproxy")));
49+
public static ToxiproxyClient toxiproxyClient;
3950

4051
static Path sharedTempDir;
4152

@@ -52,13 +63,32 @@ public ProviderSteps(State state) {
5263
super(state);
5364
}
5465

66+
static String generateProxyName(Config.Resolver resolver, ProviderType providerType) {
67+
return providerType + "-" + resolver;
68+
}
69+
5570
@BeforeAll
5671
public static void beforeAll() throws IOException {
57-
containers.put(ProviderType.DEFAULT, new FlagdContainer());
58-
containers.put(ProviderType.SSL, new FlagdContainer("ssl"));
72+
toxiproxy.start();
73+
toxiproxyClient = new ToxiproxyClient(toxiproxy.getHost(), toxiproxy.getControlPort());
74+
toxiproxyClient.createProxy(
75+
generateProxyName(Config.Resolver.RPC, ProviderType.DEFAULT),
76+
"0.0.0.0:8666", "default:8013");
77+
78+
toxiproxyClient.createProxy(generateProxyName(Config.Resolver.IN_PROCESS, ProviderType.DEFAULT), "0.0.0.0:8667", "default:8015");
79+
toxiproxyClient.createProxy(generateProxyName(Config.Resolver.RPC, ProviderType.SSL), "0.0.0.0:8668", "ssl:8013");
80+
toxiproxyClient.createProxy(generateProxyName(Config.Resolver.IN_PROCESS, ProviderType.SSL), "0.0.0.0:8669", "ssl:8015");
81+
82+
containers.put(ProviderType.DEFAULT,
83+
new FlagdContainer().withNetwork(network).withNetworkAliases("default")
84+
);
85+
containers.put(ProviderType.SSL,
86+
new FlagdContainer("ssl").withNetwork(network).withNetworkAliases("ssl")
87+
);
5988
containers.put(ProviderType.SOCKET, new FlagdContainer("socket")
6089
.withFileSystemBind(sharedTempDir.toAbsolutePath().toString(), "/tmp", BindMode.READ_WRITE));
6190

91+
6292
}
6393

6494
@AfterAll
@@ -69,16 +99,19 @@ public static void afterAll() throws IOException {
6999
}
70100

71101
@Before
72-
public void before() {
102+
public void before() throws IOException {
103+
73104
containers.values().stream().filter(containers -> !containers.isRunning())
74105
.forEach(FlagdContainer::start);
75106
}
107+
76108
@After
77109
public void tearDown() {
78110
OpenFeatureAPI.getInstance().shutdown();
79111
}
80112

81113

114+
82115
@Given("a {} flagd provider")
83116
public void setupProvider(String providerType) {
84117
state.builder
@@ -106,14 +139,14 @@ public void setupProvider(String providerType) {
106139
this.state.providerType = ProviderType.SSL;
107140
state
108141
.builder
109-
.port(getContainer().getPort(State.resolverType))
142+
.port(getContainer(state.providerType).getPort(State.resolverType))
110143
.tls(true)
111144
.certPath(absolutePath);
112145
break;
113146

114147
default:
115148
this.state.providerType = ProviderType.DEFAULT;
116-
state.builder.port(getContainer().getPort(State.resolverType));
149+
state.builder.port(toxiproxy.getMappedPort(8666));
117150
break;
118151
}
119152
FeatureProvider provider = new FlagdProvider(state.builder
@@ -130,30 +163,30 @@ public void setupProvider(String providerType) {
130163
}
131164

132165
@When("the connection is lost for {int}s")
133-
public void the_connection_is_lost_for(int seconds) throws InterruptedException {
134-
FlagdContainer container = getContainer();
135-
136-
/* TimerTask task = new TimerTask() {
166+
public void the_connection_is_lost_for(int seconds) throws InterruptedException, IOException {
167+
LOG.info("Timeout and wait for {} seconds", seconds);
168+
Proxy proxy = toxiproxyClient.getProxy(generateProxyName(State.resolverType, state.providerType));
169+
Timeout restart = proxy
170+
.toxics()
171+
.timeout("restart", ToxicDirection.UPSTREAM, seconds);
172+
173+
TimerTask task = new TimerTask() {
137174
public void run() {
138-
container.start();
139-
int port = container.getPort(State.resolverType);
175+
try {
176+
proxy.toxics().get("restart").remove();
177+
} catch (IOException e) {
178+
throw new RuntimeException(e);
179+
}
140180
}
141181
};
142-
Timer timer = new Timer("Timer");*/
143-
144-
LOG.info("stopping container for {}", state.providerType);
145-
container.stop();
182+
Timer timer = new Timer("Timer");
146183

147-
//timer.schedule(task, seconds * 1000L);
148-
Thread.sleep(seconds * 1000L);
184+
timer.schedule(task, seconds * 1000L);
149185

150-
LOG.info("starting container for {}", state.providerType);
151-
container.start();
152186
}
153187

154-
private FlagdContainer getContainer() {
155-
LOG.info("getting container for {}", state.providerType);
156-
System.out.println("getting container for " + state.providerType);
157-
return containers.getOrDefault(state.providerType, containers.get(ProviderType.DEFAULT));
188+
static FlagdContainer getContainer(ProviderType providerType) {
189+
LOG.info("getting container for {}", providerType);
190+
return containers.getOrDefault(providerType, containers.get(ProviderType.DEFAULT));
158191
}
159192
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
org.slf4j.simpleLogger.defaultLogLevel=debug
2+
org.slf4j.simpleLogger.logFile=System.out

0 commit comments

Comments
 (0)