Skip to content

[DPE-10203] test(async-replication): cover the ticket's full dead-DC teardown sequence - #1914

Draft
marceloneppel wants to merge 13 commits into
dpe-10203-async-replication-recoveryfrom
dpe-10203-dead-dc-recovery-test
Draft

[DPE-10203] test(async-replication): cover the ticket's full dead-DC teardown sequence#1914
marceloneppel wants to merge 13 commits into
dpe-10203-async-replication-recoveryfrom
dpe-10203-dead-dc-recovery-test

Conversation

@marceloneppel

@marceloneppel marceloneppel commented Aug 21, 2026

Copy link
Copy Markdown
Member

Issue

DPE-10203: the fix set in #1913 has no CI coverage — the dead-DC recovery scenario needs three models, which the spread-based integration matrix doesn't run. The reported sequence also has steps a naive test would skip: the whole datacenter dies (the watcher's machine together with the cluster's units — "all Rome units"), and the dead relation is first attacked with remove-relation --force — the ticket's Issue 1, for which Juju delivers no events — before the remove-saas --force workaround clears the offer.

Solution

A three-model jubilant integration test replicating the ticket's teardown sequence end to end: dead datacenter (2xPG + Raft-witness watcher per DC), force-promotion, remove-relation --force then remove-saas --force (neither delivering relation-broken), and create-replication to a fresh cluster — which must succeed rather than deadlock. Asserts the labelless-secret contract of #1913: the owner owns the shared secret with no label, and no side registers a consumer-side label alias under either legacy name. The remove-saas workaround tolerates "not found", so the test stays valid if Juju ever honors remove-relation --force.

Alongside the new test, the existing upgrade integration test additionally asserts the shared secret id is stable across the refresh (an id switch would wedge any consumer still running label-attaching code mid-upgrade).

Stacked on #1913; merge after it.

Checklist

  • I have added or updated any relevant documentation.
  • I have cleaned any remaining cloud resources from my accounts.

@marceloneppel marceloneppel added the not bug or enhancement PR is not 'bug' or 'enhancement'. For release notes label Aug 21, 2026
@github-actions github-actions Bot added the Libraries: Out of sync The charm libs used are out-of-sync label Aug 21, 2026
@marceloneppel marceloneppel reopened this Aug 26, 2026
marceloneppel added a commit that referenced this pull request Aug 26, 2026
Carry the scoped _relation test refactor so #1914's diff stays
test-file-only.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
@marceloneppel
marceloneppel force-pushed the dpe-10203-async-replication-recovery branch from 9700e8e to 336a4d6 Compare September 1, 2026 18:00
@marceloneppel
marceloneppel force-pushed the dpe-10203-dead-dc-recovery-test branch 4 times, most recently from f03e521 to ece19b7 Compare September 1, 2026 20:16
…uence

Three-model regression test for DPE-10203 replicating the reported
scenario end to end: the whole datacenter dies (the cluster's units and
its Raft-witness watcher alike), the standby is force-promoted, the dead
relation is attacked with remove-relation --force (the ticket's Issue 1,
for which Juju delivers no events) and the consumed offer is cleared
with remove-saas --force — neither delivering relation-broken — then
create-replication re-establishes replication to a fresh cluster.

Asserts the labelless-secret contract of the fix: the owner owns the
shared secret with no label (nothing for a stale alias to collide with)
and no side registers a consumer-side label alias under either legacy
name. The remove-saas workaround tolerates 'not found' so the test stays
valid if Juju ever honors remove-relation --force.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
…h model

The dead-DC teardown regression only asserted secret-label hygiene; the
client data itself was never exercised. Relate postgresql-test-app to
every cluster, start continuous writes on the primary before the DC
dies, and assert the pre-death data survives the force-promotion and
re-appears on the fresh re-replication target — mirroring the original
async replication tests, which relate the test app to each cluster.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
…down

The three-model fixtures switch the shared JujuFixture to each extra
model; jubilant's destroy_model then nulls the fixture's model when the
destroyed model matches, so the temp-model teardown assert (juju.model
is not None) failed after the last extra model was destroyed — reported
as an ERROR that masked the passing assertions. Switching back to the
previous model after each destroy keeps the fixture consistent.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
create-replication and promote-to-primary read _get_primary_cluster,
which counts an orphaned promoted-cluster-counter left in peer data by
a dead-DC teardown whose relation-broken never fired. With the only
reconciler in update-status, the action fails with "There is already a
replication set up." (or promote-to-primary wrongly sees a primary)
until an update-status cycle happens to run — which the dead-DC
recovery window cannot rely on. Both actions now clear the stale
counter before their guard; the mirror check inside
clear_stale_promotion keeps live replications untouched. The update-
status reconciler stays (idempotent, cheap, and covers paths that don't
go through the actions). The dead-DC integration test drops its
10-minute retry loop, whose only purpose was absorbing that update-
status latency.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
…n types

Condense the multi-paragraph dead-DC comments to the repo's short
single-purpose comments, trim the regression test module docstring to
the same shape, and narrow two of the teardown exception handlers to
their concrete failure types (DeployedWithoutTrustError, RetryError,
ModelError). The get_standby_leader handler keeps Exception: it probes
across three layers whose failure modes cannot be enumerated here, and
a crash would defeat the counter-clear reconciliation.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
@marceloneppel
marceloneppel force-pushed the dpe-10203-dead-dc-recovery-test branch from f994689 to 6b2957e Compare September 1, 2026 20:32
…he forbidden list

The labelless-ownership fix landed without any secret labels; only the
legacy consumer alias can go stale. Trim the constant to that one label
and rename it accordingly.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
…rade

The refresh deploys Charmhub 16/stable (whose charm owns the shared
secret under the legacy label) and then upgrades to the labelless
design. The adoption path must re-use the same secret id — a switch
would wedge any consumer still running label-attaching code during the
cross-version window. Assert the published secret id is unchanged
across the refresh; nothing in the upgrade test asserted secret
identity before.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
…id helper

jubilant's Juju.cli() returns the command output as a string, not a
subprocess result; the helper read .stdout on it and crashed with
AttributeError on both architectures during the upgrade run.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
… test

The dead-DC recovery test was missing its spread task, so the
spread-based integration matrix never ran it.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
…g switch API

jubilant has no Juju.switch; the teardown must restore the fixture's
model by plain attribute assignment (the same mechanism destroy_model
uses to null it). Also trim the module docstring and two inline comments
to the repo's comment style.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
The helper collected the values but never returned them, so
test_data_replication crashed with len(None) as soon as the spread
matrix started running it.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
… file

Move the helpers introduced with the dead-DC recovery test into
high_availability_helpers_new so the other async-replication tests can
reuse them, matching the existing convention:

- get_async_secret_labels (was _async_secret_labels)
- consumer_alias_exists (was _consumer_alias_exists)
- wait_resilient (was _wait_resilient)
- start_continuous_writes (was _start_continuous_writes)
- get_published_secret_id (was _published_secret_id, from the upgrade test)

The multi-model pytest fixtures stay in the dead-DC test module: they are
fixtures bound to that scenario's model suffixes, not shared helpers.

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
… move

Signed-off-by: Marcelo Henrique Neppel <marcelo.neppel@canonical.com>
@marceloneppel
marceloneppel force-pushed the dpe-10203-dead-dc-recovery-test branch from cb975d1 to d5096c3 Compare September 5, 2026 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Libraries: Out of sync The charm libs used are out-of-sync not bug or enhancement PR is not 'bug' or 'enhancement'. For release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant