Skip to content
Draft
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
21 changes: 14 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ SUPPRESSION_FILE_FDV2=testharness-suppressions-fdv2.txt
TEST_HARNESS_PARAMS_V2= -status-timeout 60
TEST_HARNESS_PARAMS_V3= -status-timeout 60

# The downloader script is version-agnostic -- VERSION selects which harness binary it fetches --
# so both suites use the copy from the v2 branch, which retries the release download.
TEST_HARNESS_DOWNLOADER_URL=https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v2/downloader/run.sh
TEST_HARNESS_DOWNLOADER=build/sdk-test-harness-downloader.sh

build-contract-tests:
@cd contract-tests && ../gradlew --no-daemon -s assembleDebug -PdisablePreDex

Expand All @@ -13,16 +18,18 @@ start-emulator:
start-contract-test-service:
@scripts/start-test-service.sh

$(TEST_HARNESS_DOWNLOADER):
@mkdir -p $(dir $@)
@curl $${GITHUB_TOKEN:+ -H "Authorization: Token $${GITHUB_TOKEN}"} \
--fail -sS -L --retry 5 --retry-delay 2 \
-o $@ $(TEST_HARNESS_DOWNLOADER_URL)

# Note that only the last version of the tests have the stop-service-at-end flag set, so the contract test service will be stopped after the tests are run.
run-contract-tests:
run-contract-tests: $(TEST_HARNESS_DOWNLOADER)
@echo "Running SDK contract test v2..."
@curl $${GITHUB_TOKEN:+ -H "Authorization: Token $${GITHUB_TOKEN}"} \
-s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v2/downloader/run.sh \
| VERSION=v2 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -skip-from $(SUPPRESSION_FILE) $(TEST_HARNESS_PARAMS_V2)" sh
@VERSION=v2 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -skip-from $(SUPPRESSION_FILE) $(TEST_HARNESS_PARAMS_V2)" sh $(TEST_HARNESS_DOWNLOADER)
@echo "Running SDK contract test v3..."
@curl $${GITHUB_TOKEN:+ -H "Authorization: Token $${GITHUB_TOKEN}"} \
-s https://raw.githubusercontent.com/launchdarkly/sdk-test-harness/v3.1.0-alpha.6/downloader/run.sh \
| VERSION=v3.1.0-alpha.6 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -stop-service-at-end -skip-from $(SUPPRESSION_FILE_FDV2) $(TEST_HARNESS_PARAMS_V3)" sh
@VERSION=v3.1.0-alpha.6 PARAMS="-url http://localhost:8001 -host 10.0.2.2 -debug -stop-service-at-end -skip-from $(SUPPRESSION_FILE_FDV2) $(TEST_HARNESS_PARAMS_V3)" sh $(TEST_HARNESS_DOWNLOADER)

contract-tests: build-contract-tests start-emulator start-contract-test-service run-contract-tests

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,21 @@ public void closePreventsFutureCallbacks() throws InterruptedException {
}

@Test
public void closeCancelsPendingTimer() throws InterruptedException {
public void closeCancelsPendingTimer() {
// Uses a manually-driven executor instead of Thread.sleep so the test is deterministic:
// sleeping for a fraction of the debounce window and expecting close() to win the race
// is flaky on loaded CI runners, where the short sleep can overshoot the window and let
// the timer fire first.
AtomicInteger callCount = new AtomicInteger(0);
StateDebounceManager mgr = createManager(true, true, callCount::incrementAndGet);
ManualTaskExecutor manualExecutor = new ManualTaskExecutor();
StateDebounceManager mgr = new StateDebounceManager(
true, true, manualExecutor, TEST_DEBOUNCE_MS, callCount::incrementAndGet);

mgr.setNetworkAvailable(false);
Thread.sleep(TEST_DEBOUNCE_MS / 3);
mgr.close();

Thread.sleep(TEST_DEBOUNCE_MS * 3);
assertEquals("close should cancel the scheduled timer", 1, manualExecutor.cancelledCount());
manualExecutor.runPendingTasks();
assertEquals("pending timer should be cancelled on close", 0, callCount.get());
}

Expand Down Expand Up @@ -341,15 +347,19 @@ public void dedupAllowsGenuineChangeAfterSuppression() throws InterruptedExcepti
// ==== reset() (CONNMODE 3.5.6 — identify bypasses debounce) ====

@Test
public void resetCancelsPendingTimer() throws InterruptedException {
public void resetCancelsPendingTimer() {
// Manually-driven executor for the same reason as closeCancelsPendingTimer: reset() must
// win against the pending timer, which a wall-clock sleep cannot guarantee.
AtomicInteger callCount = new AtomicInteger(0);
StateDebounceManager mgr = createManager(true, true, callCount::incrementAndGet);
ManualTaskExecutor manualExecutor = new ManualTaskExecutor();
StateDebounceManager mgr = new StateDebounceManager(
true, true, manualExecutor, TEST_DEBOUNCE_MS, callCount::incrementAndGet);

mgr.setNetworkAvailable(false);
Thread.sleep(TEST_DEBOUNCE_MS / 3);
mgr.reset(true, true);

Thread.sleep(TEST_DEBOUNCE_MS * 3);
assertEquals("reset should cancel the scheduled timer", 1, manualExecutor.cancelledCount());
manualExecutor.runPendingTasks();
assertEquals("reset should cancel the pending timer", 0, callCount.get());

mgr.close();
Expand Down
Loading