diff --git a/source/server-discovery-and-monitoring/tests/rs/disaggregated_storage_setversion.json b/source/server-discovery-and-monitoring/tests/rs/disaggregated_storage_setversion.json new file mode 100644 index 0000000000..c8b41d30ca --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/rs/disaggregated_storage_setversion.json @@ -0,0 +1,167 @@ +{ + "description": "Static setVersion (DSC) is compatible with both pre and post DRIVERS-2412", + "uri": "mongodb://a/?replicaSet=rs", + "phases": [ + { + "responses": [ + [ + "a:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000005" + }, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ], + [ + "b:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": false, + "secondary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 1, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ] + ], + "outcome": { + "servers": { + "a:27017": { + "type": "RSPrimary", + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000005" + } + }, + "b:27017": { + "type": "RSSecondary", + "setName": "rs", + "setVersion": 1, + "electionId": null + } + }, + "topologyType": "ReplicaSetWithPrimary", + "logicalSessionTimeoutMinutes": null, + "setName": "rs", + "maxSetVersion": 1, + "maxElectionId": { + "$oid": "000000000000000000000005" + } + } + }, + { + "responses": [ + [ + "b:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000006" + }, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ] + ], + "outcome": { + "servers": { + "a:27017": { + "type": "Unknown", + "setName": null, + "setVersion": null, + "electionId": null + }, + "b:27017": { + "type": "RSPrimary", + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000006" + } + } + }, + "topologyType": "ReplicaSetWithPrimary", + "logicalSessionTimeoutMinutes": null, + "setName": "rs", + "maxSetVersion": 1, + "maxElectionId": { + "$oid": "000000000000000000000006" + } + } + }, + { + "responses": [ + [ + "a:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000005" + }, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ] + ], + "outcome": { + "servers": { + "a:27017": { + "type": "Unknown", + "setName": null, + "setVersion": null, + "electionId": null + }, + "b:27017": { + "type": "RSPrimary", + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000006" + } + } + }, + "topologyType": "ReplicaSetWithPrimary", + "logicalSessionTimeoutMinutes": null, + "setName": "rs", + "maxSetVersion": 1, + "maxElectionId": { + "$oid": "000000000000000000000006" + } + } + } + ] +} diff --git a/source/server-discovery-and-monitoring/tests/rs/disaggregated_storage_setversion.yml b/source/server-discovery-and-monitoring/tests/rs/disaggregated_storage_setversion.yml new file mode 100644 index 0000000000..c20b0027ab --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/rs/disaggregated_storage_setversion.yml @@ -0,0 +1,118 @@ +# Disaggregated storage clusters use a constant setVersion (typically 1) instead of +# incrementing it on each reconfig. This test validates that primary staleness detection +# works correctly using electionId when setVersion doesn't change. +description: Static setVersion (DSC) is compatible with both pre and post DRIVERS-2412 +uri: "mongodb://a/?replicaSet=rs" +phases: + # Phase 1: Initial state - A is primary with electionId=5, setVersion=1 + - responses: + - + - "a:27017" + - ok: 1 + helloOk: true + isWritablePrimary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000005"} + minWireVersion: 0 + maxWireVersion: 17 + - + - "b:27017" + - ok: 1 + helloOk: true + isWritablePrimary: false + secondary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 1 + minWireVersion: 0 + maxWireVersion: 17 + outcome: + servers: + a:27017: + type: RSPrimary + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000005"} + b:27017: + type: RSSecondary + setName: rs + setVersion: 1 + electionId: null + topologyType: ReplicaSetWithPrimary + logicalSessionTimeoutMinutes: null + setName: rs + maxSetVersion: 1 + maxElectionId: {"$oid": "000000000000000000000005"} + # Phase 2: B becomes primary with newer electionId=6, but setVersion stays at 1 + # The driver should accept B as the new primary and mark A as Unknown + - responses: + - + - "b:27017" + - ok: 1 + helloOk: true + isWritablePrimary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000006"} + minWireVersion: 0 + maxWireVersion: 17 + outcome: + servers: + a:27017: + type: Unknown + setName: null + setVersion: null + electionId: null + b:27017: + type: RSPrimary + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000006"} + topologyType: ReplicaSetWithPrimary + logicalSessionTimeoutMinutes: null + setName: rs + maxSetVersion: 1 + maxElectionId: {"$oid": "000000000000000000000006"} + # Phase 3: Old primary A tries to come back with stale electionId=5 + # Even though setVersion is still 1 (unchanged), the driver should reject A + # because its electionId is older than the current maxElectionId=6 + - responses: + - + - "a:27017" + - ok: 1 + helloOk: true + isWritablePrimary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000005"} + minWireVersion: 0 + maxWireVersion: 17 + outcome: + servers: + a:27017: + type: Unknown + setName: null + setVersion: null + electionId: null + b:27017: + type: RSPrimary + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000006"} + topologyType: ReplicaSetWithPrimary + logicalSessionTimeoutMinutes: null + setName: rs + maxSetVersion: 1 + maxElectionId: {"$oid": "000000000000000000000006"} diff --git a/source/server-discovery-and-monitoring/tests/rs/migration_from_disaggregated_storage.json b/source/server-discovery-and-monitoring/tests/rs/migration_from_disaggregated_storage.json new file mode 100644 index 0000000000..c5109026bc --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/rs/migration_from_disaggregated_storage.json @@ -0,0 +1,167 @@ +{ + "description": "DSC to ASC reverse migration - ASC primary with higher setVersion is accepted", + "uri": "mongodb://a/?replicaSet=rs", + "phases": [ + { + "responses": [ + [ + "a:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000005" + }, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ], + [ + "b:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": false, + "secondary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 1, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ] + ], + "outcome": { + "servers": { + "a:27017": { + "type": "RSPrimary", + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000005" + } + }, + "b:27017": { + "type": "RSSecondary", + "setName": "rs", + "setVersion": 1, + "electionId": null + } + }, + "topologyType": "ReplicaSetWithPrimary", + "logicalSessionTimeoutMinutes": null, + "setName": "rs", + "maxSetVersion": 1, + "maxElectionId": { + "$oid": "000000000000000000000005" + } + } + }, + { + "responses": [ + [ + "b:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 1000, + "electionId": { + "$oid": "000000000000000000000006" + }, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ] + ], + "outcome": { + "servers": { + "a:27017": { + "type": "Unknown", + "setName": null, + "setVersion": null, + "electionId": null + }, + "b:27017": { + "type": "RSPrimary", + "setName": "rs", + "setVersion": 1000, + "electionId": { + "$oid": "000000000000000000000006" + } + } + }, + "topologyType": "ReplicaSetWithPrimary", + "logicalSessionTimeoutMinutes": null, + "setName": "rs", + "maxSetVersion": 1000, + "maxElectionId": { + "$oid": "000000000000000000000006" + } + } + }, + { + "responses": [ + [ + "a:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 1, + "electionId": { + "$oid": "000000000000000000000005" + }, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ] + ], + "outcome": { + "servers": { + "a:27017": { + "type": "Unknown", + "setName": null, + "setVersion": null, + "electionId": null + }, + "b:27017": { + "type": "RSPrimary", + "setName": "rs", + "setVersion": 1000, + "electionId": { + "$oid": "000000000000000000000006" + } + } + }, + "topologyType": "ReplicaSetWithPrimary", + "logicalSessionTimeoutMinutes": null, + "setName": "rs", + "maxSetVersion": 1000, + "maxElectionId": { + "$oid": "000000000000000000000006" + } + } + } + ] +} diff --git a/source/server-discovery-and-monitoring/tests/rs/migration_from_disaggregated_storage.yml b/source/server-discovery-and-monitoring/tests/rs/migration_from_disaggregated_storage.yml new file mode 100644 index 0000000000..6bb88f0fc1 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/rs/migration_from_disaggregated_storage.yml @@ -0,0 +1,119 @@ +# When migrating from disaggregated storage (constant setVersion) back to a +# traditional replica set (incrementing setVersion), a force reconfig is used +# with a high setVersion value to ensure the driver accepts the new primary. +description: DSC to ASC reverse migration - ASC primary with higher setVersion is accepted +uri: "mongodb://a/?replicaSet=rs" +phases: + # Phase 1: Disaggregated storage cluster with constant setVersion=1 + - responses: + - + - "a:27017" + - ok: 1 + helloOk: true + isWritablePrimary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000005"} + minWireVersion: 0 + maxWireVersion: 17 + - + - "b:27017" + - ok: 1 + helloOk: true + isWritablePrimary: false + secondary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 1 + minWireVersion: 0 + maxWireVersion: 17 + outcome: + servers: + a:27017: + type: RSPrimary + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000005"} + b:27017: + type: RSSecondary + setName: rs + setVersion: 1 + electionId: null + topologyType: ReplicaSetWithPrimary + logicalSessionTimeoutMinutes: null + setName: rs + maxSetVersion: 1 + maxElectionId: {"$oid": "000000000000000000000005"} + # Phase 2: After migration to traditional replica set, B becomes primary with + # setVersion=1000 (force reconfig with high value) and newer electionId=6 + # The driver should accept B as the new primary due to higher setVersion + - responses: + - + - "b:27017" + - ok: 1 + helloOk: true + isWritablePrimary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 1000 + electionId: {"$oid": "000000000000000000000006"} + minWireVersion: 0 + maxWireVersion: 17 + outcome: + servers: + a:27017: + type: Unknown + setName: null + setVersion: null + electionId: null + b:27017: + type: RSPrimary + setName: rs + setVersion: 1000 + electionId: {"$oid": "000000000000000000000006"} + topologyType: ReplicaSetWithPrimary + logicalSessionTimeoutMinutes: null + setName: rs + maxSetVersion: 1000 + maxElectionId: {"$oid": "000000000000000000000006"} + # Phase 3: Old disaggregated storage primary A tries to come back + # The driver should reject it because both setVersion (1 < 1000) and + # electionId (5 < 6) are stale + - responses: + - + - "a:27017" + - ok: 1 + helloOk: true + isWritablePrimary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 1 + electionId: {"$oid": "000000000000000000000005"} + minWireVersion: 0 + maxWireVersion: 17 + outcome: + servers: + a:27017: + type: Unknown + setName: null + setVersion: null + electionId: null + b:27017: + type: RSPrimary + setName: rs + setVersion: 1000 + electionId: {"$oid": "000000000000000000000006"} + topologyType: ReplicaSetWithPrimary + logicalSessionTimeoutMinutes: null + setName: rs + maxSetVersion: 1000 + maxElectionId: {"$oid": "000000000000000000000006"} diff --git a/source/server-discovery-and-monitoring/tests/rs/migration_to_disaggregated_storage.json b/source/server-discovery-and-monitoring/tests/rs/migration_to_disaggregated_storage.json new file mode 100644 index 0000000000..57f39c93b2 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/rs/migration_to_disaggregated_storage.json @@ -0,0 +1,119 @@ +{ + "description": "ASC to DSC forward migration - DSC uses setVersionASC + 1 to prevent false stale detection", + "uri": "mongodb://a/?replicaSet=rs", + "phases": [ + { + "responses": [ + [ + "a:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 10, + "electionId": { + "$oid": "000000000000000000000005" + }, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ], + [ + "b:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": false, + "secondary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 10, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ] + ], + "outcome": { + "servers": { + "a:27017": { + "type": "RSPrimary", + "setName": "rs", + "setVersion": 10, + "electionId": { + "$oid": "000000000000000000000005" + } + }, + "b:27017": { + "type": "RSSecondary", + "setName": "rs", + "setVersion": 10, + "electionId": null + } + }, + "topologyType": "ReplicaSetWithPrimary", + "logicalSessionTimeoutMinutes": null, + "setName": "rs", + "maxSetVersion": 10, + "maxElectionId": { + "$oid": "000000000000000000000005" + } + } + }, + { + "responses": [ + [ + "a:27017", + { + "ok": 1, + "helloOk": true, + "isWritablePrimary": true, + "hosts": [ + "a:27017", + "b:27017" + ], + "setName": "rs", + "setVersion": 11, + "electionId": { + "$oid": "000000000000000000000006" + }, + "minWireVersion": 0, + "maxWireVersion": 17 + } + ] + ], + "outcome": { + "servers": { + "a:27017": { + "type": "RSPrimary", + "setName": "rs", + "setVersion": 11, + "electionId": { + "$oid": "000000000000000000000006" + } + }, + "b:27017": { + "type": "RSSecondary", + "setName": "rs", + "setVersion": 10, + "electionId": null + } + }, + "topologyType": "ReplicaSetWithPrimary", + "logicalSessionTimeoutMinutes": null, + "setName": "rs", + "maxSetVersion": 11, + "maxElectionId": { + "$oid": "000000000000000000000006" + } + } + } + ] +} diff --git a/source/server-discovery-and-monitoring/tests/rs/migration_to_disaggregated_storage.yml b/source/server-discovery-and-monitoring/tests/rs/migration_to_disaggregated_storage.yml new file mode 100644 index 0000000000..a798392dc9 --- /dev/null +++ b/source/server-discovery-and-monitoring/tests/rs/migration_to_disaggregated_storage.yml @@ -0,0 +1,85 @@ +# When migrating from a traditional replica set (incrementing setVersion) to +# disaggregated storage (constant setVersion), the migration uses setVersionASC + 1 +# to prevent the driver from incorrectly marking the new primary as stale. +description: ASC to DSC forward migration - DSC uses setVersionASC + 1 to prevent false stale detection +uri: "mongodb://a/?replicaSet=rs" +phases: + # Phase 1: Traditional replica set with incrementing setVersion=10 + - responses: + - + - "a:27017" + - ok: 1 + helloOk: true + isWritablePrimary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 10 + electionId: {"$oid": "000000000000000000000005"} + minWireVersion: 0 + maxWireVersion: 17 + - + - "b:27017" + - ok: 1 + helloOk: true + isWritablePrimary: false + secondary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 10 + minWireVersion: 0 + maxWireVersion: 17 + outcome: + servers: + a:27017: + type: RSPrimary + setName: rs + setVersion: 10 + electionId: {"$oid": "000000000000000000000005"} + b:27017: + type: RSSecondary + setName: rs + setVersion: 10 + electionId: null + topologyType: ReplicaSetWithPrimary + logicalSessionTimeoutMinutes: null + setName: rs + maxSetVersion: 10 + maxElectionId: {"$oid": "000000000000000000000005"} + # Phase 2: After migration to disaggregated storage, setVersion becomes 11 (10 + 1) + # This ensures the driver sees a newer setVersion and accepts the new primary, + # even though future reconfigs will keep setVersion constant at 11 + - responses: + - + - "a:27017" + - ok: 1 + helloOk: true + isWritablePrimary: true + hosts: + - "a:27017" + - "b:27017" + setName: rs + setVersion: 11 + electionId: {"$oid": "000000000000000000000006"} + minWireVersion: 0 + maxWireVersion: 17 + outcome: + servers: + a:27017: + type: RSPrimary + setName: rs + setVersion: 11 + electionId: {"$oid": "000000000000000000000006"} + b:27017: + type: RSSecondary + setName: rs + setVersion: 10 + electionId: null + topologyType: ReplicaSetWithPrimary + logicalSessionTimeoutMinutes: null + setName: rs + maxSetVersion: 11 + maxElectionId: {"$oid": "000000000000000000000006"}