@@ -1602,3 +1602,76 @@ func TestDeleteNonMigratedDbUnblocksBootstrapMigration(t *testing.T) {
16021602 assert .Equal (c , base .MigrationStateComplete , status .Bootstrap .State , "bucket bootstrap migration should be complete" )
16031603 }, 10 * time .Second , 100 * time .Millisecond )
16041604}
1605+
1606+ // TestRecheckConvergesLocalCacheOnPeerCompletedMigration ensures when a node completes the bucket bootstrap migration,
1607+ // this node's status doc reads complete but its local "migration complete" cache (IsMigrationComplete) is updated too.
1608+ // RecheckPendingBucketMetadataMigrations should converge that cache so the node stops falling back
1609+ // 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.
1614+ func TestRecheckConvergesLocalCacheOnPeerCompletedMigration (t * testing.T ) {
1615+ base .TestRequiresCollections (t )
1616+
1617+ ctx := base .TestCtx (t )
1618+ tb := base .GetTestBucket (t )
1619+ defer tb .Close (ctx )
1620+
1621+ dataStore1 , err := tb .GetNamedDataStore (0 )
1622+ require .NoError (t , err )
1623+ rt := rest .NewRestTester (t , & rest.RestTesterConfig {
1624+ CustomTestBucket : tb .NoCloseClone (),
1625+ PersistentConfig : true ,
1626+ })
1627+ defer rt .Close ()
1628+
1629+ db1Cfg := rt .NewDbConfig ()
1630+ db1Cfg .UseSystemMobileMetadataCollection = base .Ptr (false )
1631+ db1Cfg .Scopes = rest.ScopesConfig {
1632+ dataStore1 .ScopeName (): rest.ScopeConfig {
1633+ Collections : rest.CollectionsConfig {dataStore1 .CollectionName (): {}},
1634+ },
1635+ }
1636+ rest .RequireStatus (t , rt .CreateDatabase ("db1" , db1Cfg ), http .StatusCreated )
1637+
1638+ dataStore2 , err := tb .GetNamedDataStore (1 )
1639+ require .NoError (t , err )
1640+ db2Cfg := rt .NewDbConfig ()
1641+ db2Cfg .UseSystemMobileMetadataCollection = base .Ptr (false )
1642+ db2Cfg .Scopes = rest.ScopesConfig {
1643+ dataStore2 .ScopeName (): rest.ScopeConfig {
1644+ Collections : rest.CollectionsConfig {dataStore2 .CollectionName (): {}},
1645+ },
1646+ }
1647+ rest .RequireStatus (t , rt .CreateDatabase ("db2" , db2Cfg ), http .StatusCreated )
1648+
1649+ // Opt in for db1 and run its migration. db2 stays un-migrated, so this node never completes the
1650+ // bucket migration on its own — its local IsMigrationComplete cache stays false. (db2 also
1651+ // guarantees the recheck can't complete the bucket itself, isolating the test to the cache
1652+ // convergence path.)
1653+ db1Cfg .UseSystemMobileMetadataCollection = base .Ptr (true )
1654+ rest .RequireStatus (t , rt .UpsertDbConfig ("db1" , db1Cfg ), http .StatusCreated )
1655+ rt .ServerContext ().ForceClusterCompatRefresh (t , rt .Context ())
1656+ resp := rt .SendAdminRequest (http .MethodPost , "/db1/_metadata_migration?action=start" , "" )
1657+ rest .RequireStatus (t , resp , http .StatusOK )
1658+ rt .WaitForMetadataMigrationStatusForDB (db .BackgroundProcessStateCompleted , "db1" )
1659+
1660+ conn := rt .ServerContext ().BootstrapContext .Connection
1661+
1662+ // Simulate a peer node winning the completion: stamp the bucket status doc to complete directly.
1663+ // UpdateMetadataMigrationStatus only writes the doc — it does not touch this node's local cache,
1664+ // so IsMigrationComplete is still false afterwards, exactly as it would be on a peer that didn't
1665+ // run the completion itself.
1666+ _ , err = conn .UpdateMetadataMigrationStatus (ctx , tb .GetName (), func (s * base.MetadataMigrationStatus ) error {
1667+ s .Bootstrap .State = base .MigrationStateComplete
1668+ return nil
1669+ })
1670+ require .NoError (t , err )
1671+ require .False (t , conn .IsMigrationComplete (tb .GetName ()), "precondition: local node should not have marked migration complete yet" )
1672+
1673+ // The recheck observes the completed status doc; it should converge the local cache.
1674+ rt .ServerContext ().RecheckPendingBucketMetadataMigrations (ctx )
1675+
1676+ require .True (t , conn .IsMigrationComplete (tb .GetName ()), "finding 2: recheck observing a peer-completed status doc should converge the local migration-complete cache" )
1677+ }
0 commit comments