@@ -1607,10 +1607,6 @@ func TestDeleteNonMigratedDbUnblocksBootstrapMigration(t *testing.T) {
16071607// this node's status doc reads complete but its local "migration complete" cache (IsMigrationComplete) is updated too.
16081608// RecheckPendingBucketMetadataMigrations should converge that cache so the node stops falling back
16091609// to _default._default and stops re-doing the recheck work for that bucket every poll.
1610- //
1611- // bug: maybeCompleteBucketMetadataMigration returns early when it sees status.Bootstrap.State == complete,
1612- // *before* it reaches SetMigrationComplete. So the recheck sees the completed doc but never flips the local cache,
1613- // and IsMigrationComplete stays false indefinitely.
16141610func TestRecheckConvergesLocalCacheOnPeerCompletedMigration (t * testing.T ) {
16151611 base .TestRequiresCollections (t )
16161612
@@ -1675,3 +1671,79 @@ func TestRecheckConvergesLocalCacheOnPeerCompletedMigration(t *testing.T) {
16751671
16761672 require .True (t , conn .IsMigrationComplete (tb .GetName ()), "finding 2: recheck observing a peer-completed status doc should converge the local migration-complete cache" )
16771673}
1674+
1675+ // TestDeleteAllDbsCompletesPendingBootstrapMigration is similar to TestDeleteNonMigratedDbUnblocksBootstrapMigration
1676+ // except that it deletes *every* db (both the migrated db1 and the un-migrated db2) and asserts the same thing
1677+ func TestDeleteAllDbsCompletesPendingBootstrapMigration (t * testing.T ) {
1678+ base .TestRequiresCollections (t )
1679+
1680+ ctx := base .TestCtx (t )
1681+ tb := base .GetTestBucket (t )
1682+ defer tb .Close (ctx )
1683+
1684+ rt := rest .NewRestTester (t , & rest.RestTesterConfig {
1685+ CustomTestBucket : tb .NoCloseClone (),
1686+ PersistentConfig : true ,
1687+ })
1688+ defer rt .Close ()
1689+
1690+ dataStore1 , err := tb .GetNamedDataStore (0 )
1691+ require .NoError (t , err )
1692+ db1Cfg := rt .NewDbConfig ()
1693+ db1Cfg .UseSystemMobileMetadataCollection = base .Ptr (false )
1694+ db1Cfg .Scopes = rest.ScopesConfig {
1695+ dataStore1 .ScopeName (): rest.ScopeConfig {
1696+ Collections : rest.CollectionsConfig {dataStore1 .CollectionName (): {}},
1697+ },
1698+ }
1699+ rest .RequireStatus (t , rt .CreateDatabase ("db1" , db1Cfg ), http .StatusCreated )
1700+
1701+ dataStore2 , err := tb .GetNamedDataStore (1 )
1702+ require .NoError (t , err )
1703+ db2Cfg := rt .NewDbConfig ()
1704+ db2Cfg .UseSystemMobileMetadataCollection = base .Ptr (false )
1705+ db2Cfg .Scopes = rest.ScopesConfig {
1706+ dataStore2 .ScopeName (): rest.ScopeConfig {
1707+ Collections : rest.CollectionsConfig {dataStore2 .CollectionName (): {}},
1708+ },
1709+ }
1710+ rest .RequireStatus (t , rt .CreateDatabase ("db2" , db2Cfg ), http .StatusCreated )
1711+
1712+ // Opt in for db1 and start its migration. This stamps the bucket-level status doc with
1713+ // Bootstrap.State == pending. The bucket cannot complete yet because db2 has not opted in.
1714+ db1Cfg .UseSystemMobileMetadataCollection = base .Ptr (true )
1715+ rest .RequireStatus (t , rt .UpsertDbConfig ("db1" , db1Cfg ), http .StatusCreated )
1716+ rt .ServerContext ().ForceClusterCompatRefresh (t , rt .Context ())
1717+ resp := rt .SendAdminRequest (http .MethodPost , "/db1/_metadata_migration?action=start" , "" )
1718+ rest .RequireStatus (t , resp , http .StatusOK )
1719+
1720+ rt .WaitForMetadataMigrationStatusForDB (db .BackgroundProcessStateCompleted , "db1" )
1721+
1722+ conn := rt .ServerContext ().BootstrapContext .Connection
1723+
1724+ // Sanity check: with db2 still present and un-migrated, the bucket bootstrap migration is pending.
1725+ status , _ , err := conn .GetMetadataMigrationStatus (ctx , tb .GetName ())
1726+ require .NoError (t , err )
1727+ require .NotNil (t , status )
1728+ require .Equal (t , base .MigrationStatePending , status .Bootstrap .State , "precondition: bucket migration should be pending while db2 is un-migrated" )
1729+
1730+ // Delete every database in the bucket — both the migrated db1 and the un-migrated db2 — so the
1731+ // registry has no live entries left.
1732+ rest .RequireStatus (t , rt .SendAdminRequest (http .MethodDelete , "/db2/" , "" ), http .StatusOK )
1733+ rest .RequireStatus (t , rt .SendAdminRequest (http .MethodDelete , "/db1/" , "" ), http .StatusOK )
1734+
1735+ // Re-run the recheck on every tick (mirroring the config-polling cadence) and expect the bucket
1736+ // migration to converge to complete now that nothing blocks it. It never does — this assertion
1737+ // fails on the current code because maybeComplete bails at its len(expected) == 0 guard.
1738+ require .EventuallyWithT (rt .TB (), func (c * assert.CollectT ) {
1739+ rt .ServerContext ().RecheckPendingBucketMetadataMigrations (ctx )
1740+ status , _ , err := conn .GetMetadataMigrationStatus (ctx , tb .GetName ())
1741+ if ! assert .NoError (c , err ) {
1742+ return
1743+ }
1744+ if ! assert .NotNil (c , status ) {
1745+ return
1746+ }
1747+ assert .Equal (c , base .MigrationStateComplete , status .Bootstrap .State , "deleting all dbs should let the pending bucket migration complete" )
1748+ }, 5 * time .Second , 100 * time .Millisecond )
1749+ }
0 commit comments