Skip to content

Commit 3cbb24a

Browse files
authored
[3.1.9 backport] CBG-4073: fix panic in CheckpointHash function (#6983)
* CBG-4073: fix panic in CheckpointHash function Backports CBG-4070. * Test fix for walrus
1 parent 5a551e1 commit 3cbb24a

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

db/active_replicator_config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ func (arc ActiveReplicatorConfig) CheckpointHash(collectionIdx *int) (string, er
160160
if _, err := hash.Write([]byte(arc.RunAs)); err != nil {
161161
return "", err
162162
}
163+
if arc.ActiveDB == nil || arc.ActiveDB.Bucket == nil {
164+
return "", fmt.Errorf("error calculating checkpoint hash, cannot fetch bucket UUID")
165+
}
163166
bucketUUID, err := arc.ActiveDB.Bucket.UUID()
164167
if err != nil {
165168
return "", err

rest/replicatortest/replicator_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8227,3 +8227,62 @@ func TestReplicatorWithCollectionsFailWithoutCollectionsEnabled(t *testing.T) {
82278227
}
82288228

82298229
}
8230+
8231+
// TestPanicInCheckpointHash:
8232+
// - Create two rest testers
8233+
// - Add active replicator for rt1 to push to rt2
8234+
// - Remove database context off os rt1
8235+
// - Call start on active replicator, this would normally hit panic in ticket CBG-4070, should now error instead
8236+
func TestPanicInCheckpointHash(t *testing.T) {
8237+
if base.UnitTestUrlIsWalrus() {
8238+
t.Skip("Test requires Couchbase Server bucket - walrus panics on db removal underneath replication")
8239+
}
8240+
// Create two rest testers
8241+
rt1 := rest.NewRestTester(t, nil)
8242+
defer rt1.Close()
8243+
8244+
rt2 := rest.NewRestTester(t, nil)
8245+
defer rt2.Close()
8246+
8247+
username := "alice"
8248+
rt2.CreateUser(username, []string{username})
8249+
8250+
// construct remote URL to have _blipsync connect to
8251+
srv := httptest.NewServer(rt2.TestPublicHandler())
8252+
defer srv.Close()
8253+
passiveDBURL, err := url.Parse(srv.URL + "/db")
8254+
require.NoError(t, err)
8255+
passiveDBURL.User = url.UserPassword(username, rest.RestTesterDefaultUserPassword)
8256+
8257+
stats, err := base.SyncGatewayStats.NewDBStats(t.Name(), false, false, false, nil, nil)
8258+
require.NoError(t, err)
8259+
dbstats, err := stats.DBReplicatorStats(t.Name())
8260+
require.NoError(t, err)
8261+
8262+
ar, err := db.NewActiveReplicator(base.TestCtx(t), &db.ActiveReplicatorConfig{
8263+
ID: t.Name(),
8264+
Direction: db.ActiveReplicatorTypePush,
8265+
ActiveDB: &db.Database{DatabaseContext: rt1.GetDatabase()},
8266+
RemoteDBURL: passiveDBURL,
8267+
ReplicationStatsMap: dbstats,
8268+
Continuous: true,
8269+
CollectionsEnabled: !rt1.GetDatabase().OnlyDefaultCollection(),
8270+
})
8271+
require.NoError(t, err)
8272+
8273+
// remove the db context for rt1 off the server context
8274+
ok := rt1.ServerContext().RemoveDatabase(base.TestCtx(t), "db")
8275+
require.True(t, ok)
8276+
8277+
// assert that the db context has been removed
8278+
require.EventuallyWithT(t, func(c *assert.CollectT) {
8279+
assert.Equal(c, 0, len(rt1.ServerContext().AllDatabases()))
8280+
}, time.Second*10, time.Millisecond*100)
8281+
8282+
// attempt to start active replicator, this will hit panic in CBG-4070 pre this work due to the bucket being nil
8283+
// on the active db context
8284+
replicatorErr := ar.Start(base.TestCtx(t))
8285+
assert.Error(t, replicatorErr)
8286+
assert.ErrorContains(t, replicatorErr, "cannot fetch bucket UUID")
8287+
8288+
}

0 commit comments

Comments
 (0)