Skip to content

Commit

Permalink
fixup: using toxiproxy
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Schrottner <[email protected]>
  • Loading branch information
aepfli committed Jan 14, 2025
1 parent c33d0ce commit e050132
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 43 deletions.
6 changes: 6 additions & 0 deletions providers/flagd/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@
<version>1.20.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>toxiproxy</artifactId>
<version>1.20.4</version>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import dev.openfeature.sdk.ImmutableStructure;
import dev.openfeature.sdk.Structure;
import lombok.Getter;
import java.util.Collections;
import java.util.List;

Expand All @@ -16,6 +17,7 @@ public class ConnectionEvent {
/**
* The current state of the connection.
*/
@Getter
private final ConnectionState connected;

/**
Expand Down Expand Up @@ -121,4 +123,5 @@ public boolean isConnected() {
public boolean isStale() {
return this.connected == ConnectionState.STALE;
}

}
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package dev.openfeature.contrib.providers.flagd.e2e;

import com.github.dockerjava.api.command.PauseContainerCmd;
import com.github.dockerjava.api.command.SyncDockerCmd;
import com.github.dockerjava.api.command.UnpauseContainerCmd;
import dev.openfeature.contrib.providers.flagd.Config;
import org.apache.logging.log4j.util.Strings;
import org.jetbrains.annotations.NotNull;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.containers.wait.strategy.WaitStrategy;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;

import java.io.File;
import java.nio.file.Files;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

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

@Override
public void start() {
if (!"socket".equals(this.feature))
this.addExposedPorts(8013, 8014, 8015, 8016);
super.start();
waitUntilContainerStarted();
}

public int getPort(Config.Resolver resolver) {
waitUntilContainerStarted();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.junit.platform.suite.api.IncludeEngines;
import org.junit.platform.suite.api.IncludeTags;
import org.junit.platform.suite.api.SelectDirectories;
import org.junit.platform.suite.api.SelectFile;
import org.junit.platform.suite.api.Suite;
import org.testcontainers.junit.jupiter.Testcontainers;

Expand All @@ -22,11 +23,13 @@
@Order(value = Integer.MAX_VALUE)
@Suite
@IncludeEngines("cucumber")
@SelectDirectories("test-harness/gherkin")
//@SelectDirectories("test-harness/gherkin")
@SelectFile("test-harness/gherkin/connection.feature")
@ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "pretty")
@ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "dev.openfeature.contrib.providers.flagd.e2e.steps")
@ConfigurationParameter(key = OBJECT_FACTORY_PROPERTY_NAME, value = "io.cucumber.picocontainer.PicoFactory")
@IncludeTags("rpc")
@IncludeTags({"rpc","reconnect"})
@ExcludeTags({"targetURI", "customCert", "unixsocket"})
@Testcontainers
public class RunRpcTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
import dev.openfeature.sdk.MutableContext;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

public class State {
public ProviderType providerType;
public Client client;
public ArrayList<Event> events = new ArrayList<>();
public List<Event> events = new LinkedList<>();
public Optional<Event> lastEvent;
public FlagSteps.Flag flag;
public MutableContext context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,29 @@
import io.cucumber.java.en.When;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.parallel.Isolated;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.LinkedList;

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

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


public EventSteps(State state) {
super(state);
state.events = new ArrayList<>();
state.events = new LinkedList<>();
}

@Given("a {} event handler")
public void a_stale_event_handler(String eventType) {
state.client.on(mapEventType(eventType), eventDetails -> {
System.out.println(eventType);
LOG.info("event tracked for {} ", eventType);
state.events.add(new Event(eventType, eventDetails));
});
}
Expand All @@ -52,17 +56,15 @@ public void eventWasFired(String eventType) {

@Then("the {} event handler should have been executed")
public void eventHandlerShouldBeExecuted(String eventType) {
eventHandlerShouldBeExecutedWithin(eventType, 10000);
eventHandlerShouldBeExecutedWithin(eventType, 30000);
}

@Then("the {} event handler should have been executed within {int}ms")
public void eventHandlerShouldBeExecutedWithin(String eventType, int ms) {
LOG.info("waiting for eventtype: {}", eventType);
await()
.atMost(ms, MILLISECONDS)
.until(() -> {
state.events.forEach((e) -> System.out.println(e.type));
return state.events.stream().anyMatch(event -> event.type.equals(eventType));
});
.until(() -> state.events.stream().anyMatch(event -> event.type.equals(eventType)));
state.lastEvent = state.events.stream().filter(event -> event.type.equals(eventType)).findFirst();
state.events.removeIf(event -> event.type.equals(eventType));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package dev.openfeature.contrib.providers.flagd.e2e.steps;

import dev.openfeature.contrib.providers.flagd.Config;
import dev.openfeature.contrib.providers.flagd.FlagdProvider;
import dev.openfeature.contrib.providers.flagd.e2e.FlagdContainer;
import dev.openfeature.contrib.providers.flagd.e2e.State;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.FeatureProvider;
import dev.openfeature.sdk.OpenFeatureAPI;
import eu.rekawek.toxiproxy.Proxy;
import eu.rekawek.toxiproxy.ToxiproxyClient;
import eu.rekawek.toxiproxy.model.ToxicDirection;
import eu.rekawek.toxiproxy.model.toxic.Timeout;
import io.cucumber.java.After;
import io.cucumber.java.AfterAll;
import io.cucumber.java.Before;
Expand All @@ -17,6 +21,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.BindMode;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.ToxiproxyContainer;
import org.testcontainers.shaded.org.apache.commons.io.FileUtils;

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

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

static Path sharedTempDir;

Expand All @@ -52,13 +63,32 @@ public ProviderSteps(State state) {
super(state);
}

static String generateProxyName(Config.Resolver resolver, ProviderType providerType) {
return providerType + "-" + resolver;
}

@BeforeAll
public static void beforeAll() throws IOException {
containers.put(ProviderType.DEFAULT, new FlagdContainer());
containers.put(ProviderType.SSL, new FlagdContainer("ssl"));
toxiproxy.start();
toxiproxyClient = new ToxiproxyClient(toxiproxy.getHost(), toxiproxy.getControlPort());
toxiproxyClient.createProxy(
generateProxyName(Config.Resolver.RPC, ProviderType.DEFAULT),
"0.0.0.0:8666", "default:8013");

toxiproxyClient.createProxy(generateProxyName(Config.Resolver.IN_PROCESS, ProviderType.DEFAULT), "0.0.0.0:8667", "default:8015");
toxiproxyClient.createProxy(generateProxyName(Config.Resolver.RPC, ProviderType.SSL), "0.0.0.0:8668", "ssl:8013");
toxiproxyClient.createProxy(generateProxyName(Config.Resolver.IN_PROCESS, ProviderType.SSL), "0.0.0.0:8669", "ssl:8015");

containers.put(ProviderType.DEFAULT,
new FlagdContainer().withNetwork(network).withNetworkAliases("default")
);
containers.put(ProviderType.SSL,
new FlagdContainer("ssl").withNetwork(network).withNetworkAliases("ssl")
);
containers.put(ProviderType.SOCKET, new FlagdContainer("socket")
.withFileSystemBind(sharedTempDir.toAbsolutePath().toString(), "/tmp", BindMode.READ_WRITE));


}

@AfterAll
Expand All @@ -69,16 +99,19 @@ public static void afterAll() throws IOException {
}

@Before
public void before() {
public void before() throws IOException {

containers.values().stream().filter(containers -> !containers.isRunning())
.forEach(FlagdContainer::start);
}

@After
public void tearDown() {
OpenFeatureAPI.getInstance().shutdown();
}



@Given("a {} flagd provider")
public void setupProvider(String providerType) {
state.builder
Expand Down Expand Up @@ -106,14 +139,14 @@ public void setupProvider(String providerType) {
this.state.providerType = ProviderType.SSL;
state
.builder
.port(getContainer().getPort(State.resolverType))
.port(getContainer(state.providerType).getPort(State.resolverType))
.tls(true)
.certPath(absolutePath);
break;

default:
this.state.providerType = ProviderType.DEFAULT;
state.builder.port(getContainer().getPort(State.resolverType));
state.builder.port(toxiproxy.getMappedPort(8666));
break;
}
FeatureProvider provider = new FlagdProvider(state.builder
Expand All @@ -130,30 +163,30 @@ public void setupProvider(String providerType) {
}

@When("the connection is lost for {int}s")
public void the_connection_is_lost_for(int seconds) throws InterruptedException {
FlagdContainer container = getContainer();

/* TimerTask task = new TimerTask() {
public void the_connection_is_lost_for(int seconds) throws InterruptedException, IOException {
LOG.info("Timeout and wait for {} seconds", seconds);
Proxy proxy = toxiproxyClient.getProxy(generateProxyName(State.resolverType, state.providerType));
Timeout restart = proxy
.toxics()
.timeout("restart", ToxicDirection.UPSTREAM, seconds);

TimerTask task = new TimerTask() {
public void run() {
container.start();
int port = container.getPort(State.resolverType);
try {
proxy.toxics().get("restart").remove();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
Timer timer = new Timer("Timer");*/

LOG.info("stopping container for {}", state.providerType);
container.stop();
Timer timer = new Timer("Timer");

//timer.schedule(task, seconds * 1000L);
Thread.sleep(seconds * 1000L);
timer.schedule(task, seconds * 1000L);

LOG.info("starting container for {}", state.providerType);
container.start();
}

private FlagdContainer getContainer() {
LOG.info("getting container for {}", state.providerType);
System.out.println("getting container for " + state.providerType);
return containers.getOrDefault(state.providerType, containers.get(ProviderType.DEFAULT));
static FlagdContainer getContainer(ProviderType providerType) {
LOG.info("getting container for {}", providerType);
return containers.getOrDefault(providerType, containers.get(ProviderType.DEFAULT));
}
}
2 changes: 2 additions & 0 deletions providers/flagd/src/test/resources/simplelogger.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.slf4j.simpleLogger.defaultLogLevel=debug
org.slf4j.simpleLogger.logFile=System.out

0 comments on commit e050132

Please sign in to comment.