Skip to content

Commit 5b308b5

Browse files
feat: Update contract tests to support multiple synchronizers and initializers (#222)
**Requirements** - [ ] I have added test coverage for new or changed functionality - [ ] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests) - [ ] I have validated my changes against all supported platform versions **Related issues** Related to sdk-test-harness commit: launchdarkly/sdk-test-harness@01a245c **Describe the solution you've provided** Updates the contract test implementation to match the sdk-test-harness changes that add support for multiple synchronizers (more than 2) for testing fallback scenarios. Contract test model changes: - Changed `SdkConfigDataSystemParams.Synchronizers` from `SdkConfigSynchronizersParams` (with `Primary`/`Secondary` properties) to `SdkConfigDataSynchronizerParams[]` (array) - Removed the `SdkConfigSynchronizersParams` class - Renamed `SdkConfigSynchronizerParams` to `SdkConfigDataSynchronizerParams` for consistency - Updated `SdkClientEntity.BuildSdkConfig` to iterate over the synchronizers array CI config change: - Pinned FDv2 contract tests to use the `v3.0.0-alpha.3` tag of sdk-test-harness instead of the `feat/fdv2` branch **Human review checklist** - [ ] Verify `v3.0.0-alpha.3` tag exists in sdk-test-harness and is compatible with the array-based synchronizer format used here - [ ] Verify the FDv1 fallback synchronizer selection logic is correct — it now picks the first polling synchronizer found in the array, or falls back to the first synchronizer if none have polling configured - [ ] Confirm the JSON serialization matches what the test harness sends (property names are auto-camelCased) **Describe alternatives you've considered** Could have kept backward compatibility by supporting both the old Primary/Secondary structure and the new array format, but this would add unnecessary complexity since the test harness has moved to the array-based approach. **Additional context** - Link to Devin run: https://app.devin.ai/sessions/5d71cc37cb45475088773207ef7fd987 - Requested by: rlamb@launchdarkly.com This is a contract test and CI config change only — no changes to the SDK itself. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Moderate risk due to a breaking change in the contract-test config model (`Synchronizers` shape) and updated fallback-selection behavior that could alter FDv2/FDv1 test execution, though it is confined to test/CI code. > > **Overview** > Updates the contract test data-system configuration model to support **multiple** synchronizers by changing `SdkConfigDataSystemParams.Synchronizers` from a `Primary`/`Secondary` object to an array of `SdkConfigDataSynchronizerParams` (and removing/renaming the old types). > > Adjusts `SdkClientEntity.BuildSdkConfig` to build all provided synchronizers, and changes FDv1 fallback selection to pick the *first polling* synchronizer found (otherwise the first synchronizer). CI’s FDv2 contract test action is also updated to run `sdk-test-harness` from the pinned `v3.0.0-alpha.3` tag instead of the `feat/fdv2` branch. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 349d410. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: rlamb@launchdarkly.com <rlamb@launchdarkly.com>
1 parent aa4616d commit 5b308b5

File tree

3 files changed

+24
-42
lines changed

3 files changed

+24
-42
lines changed

.github/actions/contract-tests/action.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ inputs:
1212
required: false
1313
default: ''
1414
run_fdv2_tests:
15-
description: 'Whether to run contract tests from the feat/fdv2 branch'
15+
description: 'Whether to run contract tests from the v3.0.0-alpha.3 tag'
1616
required: false
1717
default: 'false'
1818

@@ -64,15 +64,15 @@ runs:
6464
shell: bash
6565
run: dotnet ${{ inputs.service_dll_file }} > test-service.log 2>&1 & disown
6666

67-
- name: Clone and run contract tests from feat/fdv2 branch
67+
- name: Clone and run contract tests from v3.0.0-alpha.3 tag
6868
if: inputs.run_fdv2_tests == 'true'
6969
shell: bash
7070
run: |
7171
mkdir -p /tmp/sdk-test-harness
7272
git clone https://github.com/launchdarkly/sdk-test-harness.git /tmp/sdk-test-harness
7373
cp $(dirname ./${{ inputs.service_project_file }})/test-supressions-fdv2.txt /tmp/sdk-test-harness/testharness-suppressions-fdv2.txt
7474
cd /tmp/sdk-test-harness
75-
git checkout feat/fdv2
75+
git checkout v3.0.0-alpha.3
7676
go build -o test-harness .
7777
./test-harness -url http://localhost:8000 -debug -status-timeout=360 --skip-from=testharness-suppressions-fdv2.txt --stop-service-at-end
7878
env:

pkgs/sdk/server/contract-tests/Representations.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public class SdkConfigDataSystemParams
152152
public SdkConfigDataStoreParams Store { get; set; }
153153
public int? StoreMode { get; set; }
154154
public SdkConfigDataInitializerParams[] Initializers { get; set; }
155-
public SdkConfigSynchronizersParams Synchronizers { get; set; }
155+
public SdkConfigDataSynchronizerParams[] Synchronizers { get; set; }
156156
public string PayloadFilter { get; set; }
157157
}
158158

@@ -185,13 +185,7 @@ public class SdkConfigDataInitializerParams
185185
public SdkConfigPollingParams Polling { get; set; }
186186
}
187187

188-
public class SdkConfigSynchronizersParams
189-
{
190-
public SdkConfigSynchronizerParams Primary { get; set; }
191-
public SdkConfigSynchronizerParams Secondary { get; set; }
192-
}
193-
194-
public class SdkConfigSynchronizerParams
188+
public class SdkConfigDataSynchronizerParams
195189
{
196190
public SdkConfigStreamingParams Streaming { get; set; }
197191
public SdkConfigPollingParams Polling { get; set; }

pkgs/sdk/server/contract-tests/SdkClientEntity.cs

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -487,27 +487,16 @@ private static Configuration BuildSdkConfig(SdkConfigParams sdkParams, ILogAdapt
487487
}
488488

489489
// Configure synchronizers
490-
if (sdkParams.DataSystem.Synchronizers != null)
490+
if (sdkParams.DataSystem.Synchronizers != null && sdkParams.DataSystem.Synchronizers.Length > 0)
491491
{
492492
var synchronizers = new List<IComponentConfigurer<IDataSource>>();
493493

494-
// Primary synchronizer
495-
if (sdkParams.DataSystem.Synchronizers.Primary != null)
494+
foreach (var synchronizerParams in sdkParams.DataSystem.Synchronizers)
496495
{
497-
var primary = CreateSynchronizer(sdkParams.DataSystem.Synchronizers.Primary, sdkParams.DataSystem.PayloadFilter);
498-
if (primary != null)
496+
var synchronizer = CreateSynchronizer(synchronizerParams, sdkParams.DataSystem.PayloadFilter);
497+
if (synchronizer != null)
499498
{
500-
synchronizers.Add(primary);
501-
}
502-
}
503-
504-
// Secondary synchronizer (optional)
505-
if (sdkParams.DataSystem.Synchronizers.Secondary != null)
506-
{
507-
var secondary = CreateSynchronizer(sdkParams.DataSystem.Synchronizers.Secondary, sdkParams.DataSystem.PayloadFilter);
508-
if (secondary != null)
509-
{
510-
synchronizers.Add(secondary);
499+
synchronizers.Add(synchronizer);
511500
}
512501
}
513502

@@ -517,23 +506,22 @@ private static Configuration BuildSdkConfig(SdkConfigParams sdkParams, ILogAdapt
517506

518507
// Find the best synchronizer to use for FDv1 fallback configuration
519508
// Prefer polling synchronizers since FDv1 fallback is polling-based
520-
SdkConfigSynchronizerParams synchronizerForFallback = null;
509+
SdkConfigDataSynchronizerParams synchronizerForFallback = null;
521510

522-
// First, try to find a polling synchronizer (check secondary first, then primary)
523-
if (sdkParams.DataSystem.Synchronizers.Secondary != null &&
524-
sdkParams.DataSystem.Synchronizers.Secondary.Polling != null)
511+
// First, try to find a polling synchronizer
512+
foreach (var syncParams in sdkParams.DataSystem.Synchronizers)
525513
{
526-
synchronizerForFallback = sdkParams.DataSystem.Synchronizers.Secondary;
527-
}
528-
else if (sdkParams.DataSystem.Synchronizers.Primary != null &&
529-
sdkParams.DataSystem.Synchronizers.Primary.Polling != null)
530-
{
531-
synchronizerForFallback = sdkParams.DataSystem.Synchronizers.Primary;
514+
if (syncParams.Polling != null)
515+
{
516+
synchronizerForFallback = syncParams;
517+
break;
518+
}
532519
}
533-
// If no polling synchronizer found, use primary synchronizer (could be streaming)
534-
else if (sdkParams.DataSystem.Synchronizers.Primary != null)
520+
521+
// If no polling synchronizer found, use the first synchronizer (could be streaming)
522+
if (synchronizerForFallback == null && sdkParams.DataSystem.Synchronizers.Length > 0)
535523
{
536-
synchronizerForFallback = sdkParams.DataSystem.Synchronizers.Primary;
524+
synchronizerForFallback = sdkParams.DataSystem.Synchronizers[0];
537525
}
538526

539527
if (synchronizerForFallback != null)
@@ -563,7 +551,7 @@ private static Configuration BuildSdkConfig(SdkConfigParams sdkParams, ILogAdapt
563551
}
564552

565553
private static IComponentConfigurer<IDataSource> CreateSynchronizer(
566-
SdkConfigSynchronizerParams synchronizer,
554+
SdkConfigDataSynchronizerParams synchronizer,
567555
string payloadFilter)
568556
{
569557
if (synchronizer.Polling != null)
@@ -608,7 +596,7 @@ private static IComponentConfigurer<IDataSource> CreateSynchronizer(
608596
}
609597

610598
private static IComponentConfigurer<IDataSource> CreateFDv1FallbackSynchronizer(
611-
SdkConfigSynchronizerParams synchronizer)
599+
SdkConfigDataSynchronizerParams synchronizer)
612600
{
613601
// FDv1 fallback synchronizer is always polling-based
614602
var fdv1PollingBuilder = DataSystemComponents.FDv1Polling();

0 commit comments

Comments
 (0)