Skip to content

Commit 7ddf528

Browse files
committed
test: wire FDv1 fallback directive into contract test service
Declare the fdv1-fallback capability and accept the new top-level dataSystem.fdv1Fallback config object (baseUri, pollIntervalMs) sent by sdk-test-harness. Wire it directly to the SDK's FDv1 fallback synchronizer instead of inferring it from the last entry of the FDv2 synchronizer list, which misrepresented the SDK's architecture: the FDv1 Fallback Synchronizer is distinct from the FDv2 Primary/Fallback chain. Bumps the test harness pin to v3.0.0-alpha.6 to pull in the new directive test suite that exercises this configuration.
1 parent b81e1a7 commit 7ddf528

4 files changed

Lines changed: 26 additions & 61 deletions

File tree

lib/sdk/server/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ run-contract-tests:
3333
@curl -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v2/downloader/run.sh \
3434
| VERSION=v2 PARAMS="-url http://localhost:$(TEST_SERVICE_PORT) -debug -skip-from=$(SUPPRESSION_FILE) $(TEST_HARNESS_PARAMS_V2)" sh
3535
@echo "Running SDK contract test v3..."
36-
@curl -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v3.0.0-alpha.3/downloader/run.sh \
37-
| VERSION=v3.0.0-alpha.3 PARAMS="-url http://localhost:$(TEST_SERVICE_PORT) -debug -stop-service-at-end -skip-from=$(SUPPRESSION_FILE_FDV2) $(TEST_HARNESS_PARAMS_V3)" sh
36+
@curl -s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v3.0.0-alpha.6/downloader/run.sh \
37+
| VERSION=v3.0.0-alpha.6 PARAMS="-url http://localhost:$(TEST_SERVICE_PORT) -debug -stop-service-at-end -skip-from=$(SUPPRESSION_FILE_FDV2) $(TEST_HARNESS_PARAMS_V3)" sh
3838

3939
contract-tests: build-contract-tests start-contract-test-service-bg run-contract-tests
4040

lib/sdk/server/contract-tests/service/src/main/java/sdktest/Representations.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ public static class SdkConfigDataSystemParams {
136136
SdkConfigDataInitializerParams[] initializers;
137137
/** List of synchronizers (matches servicedef DataSystem.Synchronizers). */
138138
SdkConfigSynchronizerParams[] synchronizers;
139+
/**
140+
* Configuration for the FDv1 fallback synchronizer engaged in response to a
141+
* server-directed FDv1 Fallback Directive. Distinct from the FDv2 synchronizer chain
142+
* above; matches servicedef DataSystem.FDv1Fallback.
143+
*/
144+
SdkConfigPollingParams fdv1Fallback;
139145
String payloadFilter;
140146
}
141147

lib/sdk/server/contract-tests/service/src/main/java/sdktest/SdkClientEntity.java

Lines changed: 16 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@
3333
import com.launchdarkly.sdk.server.integrations.FDv2PollingSynchronizerBuilder;
3434
import com.launchdarkly.sdk.server.integrations.FDv2StreamingSynchronizerBuilder;
3535
import com.launchdarkly.sdk.server.interfaces.BigSegmentStoreStatusProvider;
36-
import com.launchdarkly.sdk.server.subsystems.ComponentConfigurer;
37-
import com.launchdarkly.sdk.server.subsystems.DataSource;
3836
import com.launchdarkly.sdk.server.subsystems.DataSourceBuilder;
3937
import com.launchdarkly.sdk.server.datasources.Initializer;
4038
import com.launchdarkly.sdk.server.datasources.Synchronizer;
@@ -570,20 +568,23 @@ private LDConfig buildSdkConfig(SdkConfigParams params, String tag) {
570568
}
571569
}
572570

573-
// Configure FDv1 fallback synchronizer (pick first polling, else first synchronizer)
574-
SdkConfigSynchronizerParams fallbackSynchronizer =
575-
selectFallbackSynchronizer(params.dataSystem.synchronizers);
576-
if (fallbackSynchronizer != null) {
577-
// Set global polling endpoints if the fallback synchronizer has polling with custom base URI
578-
if (fallbackSynchronizer.polling != null &&
579-
fallbackSynchronizer.polling.baseUri != null) {
580-
endpoints.polling(fallbackSynchronizer.polling.baseUri);
571+
// Configure the FDv1 fallback synchronizer. This is engaged only when the server returns
572+
// the X-LD-FD-Fallback directive; it lives outside the FDv2 Primary/Fallback synchronizer
573+
// chain configured above. The test harness sends this as a dedicated top-level field --
574+
// do not infer it from the FDv2 synchronizer list.
575+
if (params.dataSystem.fdv1Fallback != null) {
576+
SdkConfigPollingParams fdv1Params = params.dataSystem.fdv1Fallback;
577+
if (fdv1Params.baseUri != null) {
578+
endpoints.polling(fdv1Params.baseUri);
581579
}
582-
583-
// Create and configure FDv1 fallback
584-
ComponentConfigurer<DataSource> fdv1Fallback =
585-
createFDv1FallbackSynchronizer(fallbackSynchronizer);
586-
dataSystemBuilder.fDv1FallbackSynchronizer(fdv1Fallback);
580+
PollingDataSourceBuilder fdv1Polling = Components.pollingDataSource();
581+
if (fdv1Params.pollIntervalMs != null) {
582+
fdv1Polling.pollInterval(Duration.ofMillis(fdv1Params.pollIntervalMs));
583+
}
584+
if (params.dataSystem.payloadFilter != null && !params.dataSystem.payloadFilter.isEmpty()) {
585+
fdv1Polling.payloadFilter(params.dataSystem.payloadFilter);
586+
}
587+
dataSystemBuilder.fDv1FallbackSynchronizer(fdv1Polling);
587588
}
588589

589590
builder.dataSystem(dataSystemBuilder);
@@ -625,47 +626,4 @@ private DataSourceBuilder<Synchronizer> createSynchronizer(
625626
return null;
626627
}
627628

628-
/**
629-
* Selects the best synchronizer configuration to use for FDv1 fallback.
630-
* Prefers the first polling synchronizer in the list, otherwise the first synchronizer.
631-
*/
632-
private static SdkConfigSynchronizerParams selectFallbackSynchronizer(
633-
SdkConfigSynchronizerParams[] synchronizers) {
634-
if (synchronizers == null || synchronizers.length == 0) {
635-
return null;
636-
}
637-
// Prefer first polling synchronizer (FDv1 fallback is polling-based)
638-
for (SdkConfigSynchronizerParams sync : synchronizers) {
639-
if (sync.polling != null) {
640-
return sync;
641-
}
642-
}
643-
// Otherwise use first synchronizer (streaming; FDv1 will use default polling config)
644-
return synchronizers[0];
645-
}
646-
647-
/**
648-
* Creates the FDv1 fallback synchronizer based on the selected synchronizer config.
649-
* FDv1 fallback is always polling-based and uses the global service endpoints configuration.
650-
*/
651-
private static ComponentConfigurer<DataSource> createFDv1FallbackSynchronizer(
652-
SdkConfigSynchronizerParams synchronizer) {
653-
654-
// FDv1 fallback is always polling-based
655-
PollingDataSourceBuilder fdv1Polling = Components.pollingDataSource();
656-
657-
// Configure polling interval if the synchronizer has polling configuration
658-
if (synchronizer.polling != null) {
659-
if (synchronizer.polling.pollIntervalMs != null) {
660-
fdv1Polling.pollInterval(Duration.ofMillis(synchronizer.polling.pollIntervalMs));
661-
}
662-
// Note: FDv1 polling doesn't support per-source service endpoints override,
663-
// so it will use the global service endpoints configuration (which is set
664-
// by the caller before this method is invoked)
665-
}
666-
// If streaming synchronizer, use default polling interval
667-
// (no additional configuration needed)
668-
669-
return fdv1Polling;
670-
}
671629
}

lib/sdk/server/contract-tests/service/src/main/java/sdktest/TestService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public class TestService {
4141
"service-endpoints",
4242
"strongly-typed",
4343
"tags",
44-
"server-side-polling"
44+
"server-side-polling",
45+
"fdv1-fallback"
4546
};
4647

4748
static final Gson gson = new GsonBuilder().serializeNulls().create();

0 commit comments

Comments
 (0)