Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions src/main/java/com/launchdarkly/client/TestFeatureStore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.launchdarkly.client;

import java.util.concurrent.atomic.AtomicInteger;

/**
* A decorated {@link InMemoryFeatureStore} which provides functionality to create (or override) "on" or "off" feature flags for all users.
*
* Using this store is useful for testing purposes when you want to have runtime support for turning specific features "on" or "off".
*
*/
public class TestFeatureStore extends InMemoryFeatureStore {

private AtomicInteger version = new AtomicInteger(0);

/**
* Turns a feature, identified by key, "on" for every user. If the feature rules already exist in the store then it will override it to be "on" for every {@link LDUser}.
* If the feature rule is not currently in the store, it will create one that is "on" for every {@link LDUser}.
*
* @param key the key of the feature flag to be "on".
*/
public void turnFeatureOn(String key) {
writeFeatureRep(key, new Variation.Builder<>(true, 100).build());
}

/**
* Turns a feature, identified by key, "off" for every user. If the feature rules already exists in the store then it will override it to be "off" for every {@link LDUser}.
* If the feature rule is not currently in the store, it will create one that is "off" for every {@link LDUser}.
*
* @param key the key of the feature flag to be "off".
*/
public void turnFeatureOff(String key) {
writeFeatureRep(key, new Variation.Builder<>(false, 100).build());
}

private void writeFeatureRep(final String key, final Variation<Boolean> variation) {
FeatureRep<Boolean> newFeature = new FeatureRep.Builder<Boolean>(String.format("test-%s", key), key)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of hardcoded to Boolean based flags only at the moment...

.variation(variation).version(version.incrementAndGet()).build();
upsert(key, newFeature);
}
}
73 changes: 73 additions & 0 deletions src/test/java/com/launchdarkly/client/LDClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
import org.junit.Test;

import java.io.IOException;
import java.io.ObjectInput;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class LDClientTest extends EasyMockSupport {
Expand Down Expand Up @@ -45,6 +48,76 @@ public void testOffline() throws IOException {
verifyAll();
}

@Test
public void testTestFeatureStoreFlagOn() throws IOException, InterruptedException, ExecutionException, TimeoutException {
TestFeatureStore testFeatureStore = new TestFeatureStore();
LDConfig config = new LDConfig.Builder()
.startWaitMillis(10L)
.stream(false)
.featureStore(testFeatureStore)
.build();

expect(initFuture.get(10L, TimeUnit.MILLISECONDS)).andReturn(new Object());
expect(pollingProcessor.start()).andReturn(initFuture);
expect(pollingProcessor.initialized()).andReturn(true).times(1);
expect(eventProcessor.sendEvent(anyObject(Event.class))).andReturn(true);
replayAll();

client = createMockClient(config);
testFeatureStore.turnFeatureOn("key");
assertTrue("Test flag should be on, but was not.", client.toggle("key", new LDUser("user"), false));

verifyAll();
}

@Test
public void testTestFeatureStoreFlagOff() throws IOException, InterruptedException, ExecutionException, TimeoutException {
TestFeatureStore testFeatureStore = new TestFeatureStore();
LDConfig config = new LDConfig.Builder()
.startWaitMillis(10L)
.stream(false)
.featureStore(testFeatureStore)
.build();

expect(initFuture.get(10L, TimeUnit.MILLISECONDS)).andReturn(new Object());
expect(pollingProcessor.start()).andReturn(initFuture);
expect(pollingProcessor.initialized()).andReturn(true).times(1);
expect(eventProcessor.sendEvent(anyObject(Event.class))).andReturn(true);
replayAll();

client = createMockClient(config);
testFeatureStore.turnFeatureOff("key");
assertFalse("Test flag should be off, but was on (the default).", client.toggle("key", new LDUser("user"), true));

verifyAll();
}

@Test
public void testTestFeatureStoreFlagOnThenOff() throws IOException, InterruptedException, ExecutionException, TimeoutException {
TestFeatureStore testFeatureStore = new TestFeatureStore();
LDConfig config = new LDConfig.Builder()
.startWaitMillis(10L)
.stream(false)
.featureStore(testFeatureStore)
.build();

expect(initFuture.get(10L, TimeUnit.MILLISECONDS)).andReturn(new Object());
expect(pollingProcessor.start()).andReturn(initFuture);
expect(pollingProcessor.initialized()).andReturn(true).times(2);
expect(eventProcessor.sendEvent(anyObject(Event.class))).andReturn(true).times(2);
replayAll();

client = createMockClient(config);

testFeatureStore.turnFeatureOn("key");
assertTrue("Test flag should be on, but was not.", client.toggle("key", new LDUser("user"), false));

testFeatureStore.turnFeatureOff("key");
assertFalse("Test flag should be off, but was on (the default).", client.toggle("key", new LDUser("user"), true));

verifyAll();
}

@Test
public void testUseLdd() throws IOException {
LDConfig config = new LDConfig.Builder()
Expand Down