Skip to content

Commit 23a1b7d

Browse files
authored
Fix CDC read error (#96)
CDCEvent reads the _id field into a string. By default, the Mongo client v2 will not convert the ObjectID to a string, so we get an error at read time. To fix this, we now set BSONOptions on the collection to allow this deserialization. This wasn't caught in the previous tests because the test code explicitly set the _id field to a string when creating test events, so the test events deserialized without error. I've also updated the TestWriteSuccess test to use a Mongo generated _id which reproduces the error. Alternatively I considered changing CDCEvent.ID to a bson.ObjectID type, but since this struct is used in the REST client library I do not want to leak that Mongo type and dependency into the client. I also considered creating an internal cdcEvent struct identical to CDCEvent but with the bson.ObjectID type, then have the server deserialize into that struct and copy to the CDCEvent struct, but that seemed heavy and unnecessary.
1 parent 4d8eb11 commit 23a1b7d

File tree

3 files changed

+25
-3
lines changed

3 files changed

+25
-3
lines changed

cdc/store_test.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,10 @@ func TestRead(t *testing.T) {
113113
func TestWriteSuccess(t *testing.T) {
114114
cdcs := setup(t, "", cdc.NoRetryPolicy)
115115

116+
// Note we don't explicitly set ID here, so that MongoDB will generate an _id for us.
117+
// This is the same behavior as the actual store implementation, which does not set the _id and
118+
// allows MongoDB to generate it.
116119
event := etre.CDCEvent{
117-
Id: "abc",
118120
Ts: 54,
119121
Op: "i",
120122
Caller: "mike",
@@ -140,6 +142,19 @@ func TestWriteSuccess(t *testing.T) {
140142
actualEvents, err := cdcs.Read(filter)
141143
require.NoError(t, err)
142144
assert.Len(t, actualEvents, 1)
145+
146+
// MongoDB auto-generates the _id column since we didn't provide one in `event` above.
147+
// This is the same behavior as the actual store implementation, which does not set the _id and
148+
// allows MongoDB to generate it.
149+
//
150+
// Since we don't know what the generated _id will be, we can't compare the entire event directly.
151+
// Instead, verify that the _id is a valid ObjectID and then clear it so we can compare the rest
152+
// of the event we read (in actualEvents[0]) with the original `event` above.
153+
_, err = bson.ObjectIDFromHex(actualEvents[0].Id)
154+
require.NoError(t, err)
155+
actualEvents[0].Id = ""
156+
157+
// Compare the rest of the event
143158
assert.Equal(t, event, actualEvents[0])
144159
}
145160

server/server.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010

1111
"go.mongodb.org/mongo-driver/v2/mongo"
12+
"go.mongodb.org/mongo-driver/v2/mongo/options"
1213

1314
"github.com/square/etre"
1415
"github.com/square/etre/api"
@@ -64,7 +65,8 @@ func (s *Server) Boot(configFile string) error {
6465
return fmt.Errorf("cannot connect to CDC datasource: %s", err)
6566
}
6667
s.cdcDbClient = cdcClient
67-
cdcColl := cdcClient.Database(cfg.Datasource.Database).Collection(config.CDC_COLLECTION)
68+
cdcOpts := options.Collection().SetBSONOptions(&options.BSONOptions{ObjectIDAsHexString: true}) // Because etre.CDCEvent has string _id, not bson.ObjectID
69+
cdcColl := cdcClient.Database(cfg.Datasource.Database).Collection(config.CDC_COLLECTION, cdcOpts)
6870

6971
// Store
7072
wrp := cdc.RetryPolicy{

test/db.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ func DbCollections(entityTypes []string) (*mongo.Client, map[string]*mongo.Colle
2424
}
2525
coll := map[string]*mongo.Collection{}
2626
for _, t := range entityTypes {
27-
coll[t] = client.Database(database).Collection(t)
27+
if t == "cdc" {
28+
cdcOpts := options.Collection().SetBSONOptions(&options.BSONOptions{ObjectIDAsHexString: true}) // Because etre.CDCEvent has string _id, not bson.ObjectID
29+
coll[t] = client.Database(database).Collection(t, cdcOpts)
30+
} else {
31+
coll[t] = client.Database(database).Collection(t)
32+
}
2833
}
2934
return client, coll, nil
3035
}

0 commit comments

Comments
 (0)