Skip to content

Commit 3f13260

Browse files
aepflirenovate[bot]chrfwow
authored
chore(flagd): update testharness and add metadata tests (#1293)
Signed-off-by: Simon Schrottner <[email protected]> Signed-off-by: christian.lutnik <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: christian.lutnik <[email protected]>
1 parent c6b9e89 commit 3f13260

File tree

12 files changed

+125
-22
lines changed

12 files changed

+125
-22
lines changed

Diff for: .gitmodules

+1-1
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 = v2.5.0
7+
branch = v2.7.1
88
[submodule "providers/flagd/spec"]
99
path = providers/flagd/spec
1010
url = https://github.com/open-feature/spec.git

Diff for: providers/flagd/schemas

Diff for: providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/rpc/RpcResolver.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -263,14 +263,14 @@ private <ValT, ReqT extends Message, ResT extends Message> ProviderEvaluation<Va
263263
return result;
264264
}
265265

266-
private <T> Boolean isEvaluationCacheable(ProviderEvaluation<T> evaluation) {
266+
private <T> boolean isEvaluationCacheable(ProviderEvaluation<T> evaluation) {
267267
String reason = evaluation.getReason();
268268

269269
return reason != null && reason.equals(Config.STATIC_REASON) && this.cacheAvailable();
270270
}
271271

272-
private Boolean cacheAvailable() {
273-
return this.cache.getEnabled();
272+
private boolean cacheAvailable() {
273+
return this.cache.isEnabled();
274274
}
275275

276276
private static ImmutableMetadata metadataFromResponse(Message response) {

Diff for: providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/resolver/rpc/cache/Cache.java

+33-2
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ public class Cache {
1616
private Map<String, ProviderEvaluation<?>> store;
1717

1818
@Getter
19-
private final Boolean enabled;
19+
private final boolean enabled;
2020

2121
/**
2222
* Initialize the cache.
2323
*
24-
* @param forType type of the cache.
24+
* @param forType type of the cache.
2525
* @param maxCacheSize max amount of element to keep.
2626
*/
2727
public Cache(final String forType, int maxCacheSize) {
@@ -36,19 +36,50 @@ public Cache(final String forType, int maxCacheSize) {
3636
}
3737
}
3838

39+
/**
40+
* Adds a provider evaluation to the cache.
41+
*
42+
* @param key the key of the flag
43+
* @param value the provider evaluation
44+
*/
3945
public void put(String key, ProviderEvaluation<?> value) {
46+
if (!enabled) {
47+
return;
48+
}
4049
this.store.put(key, value);
4150
}
4251

52+
/**
53+
* Retrieves a provider evaluation from the cache, or null if the key has not been cached before.
54+
*
55+
* @param key the key of the flag
56+
*/
4357
public ProviderEvaluation<?> get(String key) {
58+
if (!enabled) {
59+
return null;
60+
}
4461
return this.store.get(key);
4562
}
4663

64+
/**
65+
* Removes a provider evaluation from the cache.
66+
*
67+
* @param key the key of the flag
68+
*/
4769
public void remove(String key) {
70+
if (!enabled) {
71+
return;
72+
}
4873
this.store.remove(key);
4974
}
5075

76+
/**
77+
* Clears the cache.
78+
*/
5179
public void clear() {
80+
if (!enabled) {
81+
return;
82+
}
5283
this.store.clear();
5384
}
5485
}

Diff for: providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/FlagdProviderSyncResourcesTest.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,14 @@ void interruptingWaitingThread_isIgnored() throws InterruptedException {
7979
@Test
8080
void callingInitialize_wakesUpWaitingThread() throws InterruptedException {
8181
final AtomicBoolean isWaiting = new AtomicBoolean();
82+
final AtomicBoolean successfulTest = new AtomicBoolean();
8283
Thread waitingThread = new Thread(() -> {
8384
long start = System.currentTimeMillis();
8485
isWaiting.set(true);
8586
flagdProviderSyncResources.waitForInitialization(10000);
8687
long end = System.currentTimeMillis();
8788
long duration = end - start;
88-
Assertions.assertTrue(duration < MAX_TIME_TOLERANCE);
89+
successfulTest.set(duration < MAX_TIME_TOLERANCE * 2);
8990
});
9091
waitingThread.start();
9192

@@ -98,12 +99,15 @@ void callingInitialize_wakesUpWaitingThread() throws InterruptedException {
9899
flagdProviderSyncResources.initialize();
99100

100101
waitingThread.join();
102+
103+
Assertions.assertTrue(successfulTest.get());
101104
}
102105

103106
@Timeout(2)
104107
@Test
105108
void callingShutdown_wakesUpWaitingThreadWithException() throws InterruptedException {
106109
final AtomicBoolean isWaiting = new AtomicBoolean();
110+
final AtomicBoolean successfulTest = new AtomicBoolean();
107111
Thread waitingThread = new Thread(() -> {
108112
long start = System.currentTimeMillis();
109113
isWaiting.set(true);
@@ -112,7 +116,7 @@ void callingShutdown_wakesUpWaitingThreadWithException() throws InterruptedExcep
112116

113117
long end = System.currentTimeMillis();
114118
long duration = end - start;
115-
Assertions.assertTrue(duration < MAX_TIME_TOLERANCE);
119+
successfulTest.set(duration < MAX_TIME_TOLERANCE * 2);
116120
});
117121
waitingThread.start();
118122

@@ -125,6 +129,8 @@ void callingShutdown_wakesUpWaitingThreadWithException() throws InterruptedExcep
125129
flagdProviderSyncResources.shutdown();
126130

127131
waitingThread.join();
132+
133+
Assertions.assertTrue(successfulTest.get());
128134
}
129135

130136
@Timeout(2)

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public EventSteps(State state) {
2727
@Given("a {} event handler")
2828
public void a_stale_event_handler(String eventType) {
2929
state.client.on(mapEventType(eventType), eventDetails -> {
30-
log.info("event tracked for {} at {} ms ", eventType, System.currentTimeMillis() % 100_000);
30+
log.info("{} event tracked", eventType);
3131
state.events.add(new Event(eventType, eventDetails));
3232
});
3333
}

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

+53
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,19 @@
44

55
import dev.openfeature.contrib.providers.flagd.e2e.State;
66
import dev.openfeature.sdk.FlagEvaluationDetails;
7+
import dev.openfeature.sdk.ImmutableMetadata;
78
import dev.openfeature.sdk.Value;
89
import io.cucumber.java.en.Given;
910
import io.cucumber.java.en.Then;
1011
import io.cucumber.java.en.When;
12+
import java.io.IOException;
13+
import java.lang.reflect.Field;
14+
import java.util.List;
15+
import java.util.Map;
16+
import lombok.extern.slf4j.Slf4j;
1117
import org.junit.jupiter.api.parallel.Isolated;
1218

19+
@Slf4j
1320
@Isolated()
1421
public class FlagSteps extends AbstractSteps {
1522

@@ -54,6 +61,9 @@ public void the_flag_was_evaluated_with_details() throws InterruptedException {
5461

5562
@Then("the resolved details value should be \"{}\"")
5663
public void the_resolved_details_value_should_be(String value) throws Throwable {
64+
if (state.evaluation.getErrorCode() != null) {
65+
log.warn(state.evaluation.getErrorMessage());
66+
}
5767
assertThat(state.evaluation.getValue()).isEqualTo(Utils.convert(value, state.flag.type));
5868
}
5969

@@ -84,4 +94,47 @@ public Flag(String type, String name, Object defaultValue) {
8494
this.type = type;
8595
}
8696
}
97+
98+
@Then("the resolved metadata is empty")
99+
@SuppressWarnings("unchecked")
100+
public void the_resolved_metadata_is_empty() throws NoSuchFieldException, IllegalAccessException {
101+
ImmutableMetadata flagMetadata = state.evaluation.getFlagMetadata();
102+
103+
Field metadataField = flagMetadata.getClass().getDeclaredField("metadata");
104+
metadataField.setAccessible(true);
105+
Map<String, Object> metadataMap = (Map<String, Object>) metadataField.get(flagMetadata);
106+
assertThat(metadataMap).isEmpty();
107+
}
108+
109+
@Then("the resolved metadata should contain")
110+
@SuppressWarnings("unchecked")
111+
public void the_resolved_metadata_should_contain(io.cucumber.datatable.DataTable dataTable)
112+
throws IOException, ClassNotFoundException {
113+
114+
ImmutableMetadata flagMetadata = state.evaluation.getFlagMetadata();
115+
116+
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
117+
for (Map<String, String> row : rows) {
118+
switch (row.get("metadata_type")) {
119+
case "String":
120+
assertThat(flagMetadata.getString(row.get("key")))
121+
.isEqualTo(Utils.convert(row.get("value"), row.get("metadata_type")));
122+
break;
123+
case "Boolean":
124+
assertThat(flagMetadata.getBoolean(row.get("key")))
125+
.isEqualTo(Utils.convert(row.get("value"), row.get("metadata_type")));
126+
break;
127+
case "Float":
128+
assertThat(flagMetadata.getDouble(row.get("key")))
129+
.isEqualTo(Utils.convert(row.get("value"), row.get("metadata_type")));
130+
break;
131+
case "Integer":
132+
assertThat(flagMetadata.getInteger(row.get("key")))
133+
.isEqualTo(Utils.convert(row.get("value"), row.get("metadata_type")));
134+
break;
135+
default:
136+
throw new AssertionError("type not supported");
137+
}
138+
}
139+
}
87140
}

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

+19-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import static io.restassured.RestAssured.when;
44

55
import dev.openfeature.contrib.providers.flagd.Config;
6+
import dev.openfeature.contrib.providers.flagd.FlagdOptions;
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;
@@ -104,7 +105,21 @@ public void setupProvider(String providerType) throws InterruptedException {
104105
.certPath(absolutePath);
105106
flagdConfig = "ssl";
106107
break;
108+
case "metadata":
109+
flagdConfig = "metadata";
107110

111+
if (State.resolverType == Config.Resolver.FILE) {
112+
FlagdOptions build = state.builder.build();
113+
String selector = build.getSelector();
114+
String replace = selector.replace("rawflags/", "");
115+
116+
state.builder
117+
.port(UNAVAILABLE_PORT)
118+
.offlineFlagSourcePath(new File("test-harness/flags/" + replace).getAbsolutePath());
119+
} else {
120+
state.builder.port(container.getPort(State.resolverType));
121+
}
122+
break;
108123
default:
109124
this.state.providerType = ProviderType.DEFAULT;
110125
if (State.resolverType == Config.Resolver.FILE) {
@@ -124,12 +139,13 @@ public void setupProvider(String providerType) throws InterruptedException {
124139
.then()
125140
.statusCode(200);
126141

127-
// giving flagd a little time to start
128-
Thread.sleep(300);
142+
Thread.sleep(50);
143+
129144
FeatureProvider provider =
130145
new FlagdProvider(state.builder.resolverType(State.resolverType).build());
131146
String providerName = "Provider " + Math.random();
132147
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
148+
133149
if (wait) {
134150
api.setProviderAndWait(providerName, provider);
135151
} else {
@@ -151,10 +167,7 @@ public void the_connection_is_lost_for(int seconds) {
151167
}
152168

153169
@When("the flag was modified")
154-
public void the_flag_was_modded() throws InterruptedException {
170+
public void the_flag_was_modded() {
155171
when().post("http://" + container.getLaunchpadUrl() + "/change").then().statusCode(200);
156-
157-
// we might be too fast in the execution
158-
Thread.sleep(1000);
159172
}
160173
}

Diff for: providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/rpc/RpcResolverTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ public void init() throws Exception {
5050
when(stub.withDeadlineAfter(anyLong(), any())).thenReturn(stub);
5151
doAnswer(new Answer<Void>() {
5252
public Void answer(InvocationOnMock invocation) {
53-
latch.countDown();
5453
Object[] args = invocation.getArguments();
5554
if (args[1] != null) {
5655
observer = (QueueingStreamObserver<EventStreamResponse>) args[1];
5756
}
57+
latch.countDown();
5858
return null;
5959
}
6060
})

Diff for: providers/flagd/src/test/java/dev/openfeature/contrib/providers/flagd/resolver/rpc/cache/CacheTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ void cacheTypeTest() {
2020
final Cache undefined = new Cache("invalid", 10);
2121

2222
// then
23-
assertTrue(lru.getEnabled());
24-
assertFalse(disabled.getEnabled());
25-
assertFalse(undefined.getEnabled());
23+
assertTrue(lru.isEnabled());
24+
assertFalse(disabled.isEnabled());
25+
assertFalse(undefined.isEnabled());
2626
}
2727

2828
@Test

Diff for: providers/flagd/test-harness

0 commit comments

Comments
 (0)