Skip to content

Commit 0281223

Browse files
committed
fix: decode error
1 parent ad9c657 commit 0281223

2 files changed

Lines changed: 59 additions & 1 deletion

File tree

store-client/pkg/datastore/providers/mongodb/watcher/watch_store.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,15 @@ func constructMongoClientOptions(
755755
// mirrored the ancestor type and produced bson.M. Change stream events and
756756
// query results are read as bson.M and their nested fields are type-asserted
757757
// as such throughout this package, so keep the v1 shape.
758-
SetBSONOptions(&options.BSONOptions{DefaultDocumentM: true}).
758+
//
759+
// ObjectIDAsHexString likewise restores v1 behaviour: v2 refuses to decode
760+
// an ObjectID into a Go string ("decoding an object ID into a string is not
761+
// supported by default"), which breaks structs that bind `bson:"_id"` to a
762+
// string field.
763+
SetBSONOptions(&options.BSONOptions{
764+
DefaultDocumentM: true,
765+
ObjectIDAsHexString: true,
766+
}).
759767
SetMonitor(otelmongo.NewMonitor(
760768
otelmongo.WithTracerProvider(tracing.GetChildOnlyTracerProvider()),
761769
))

store-client/pkg/datastore/providers/mongodb/watcher/watch_store_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package watcher
1616

1717
import (
18+
"bytes"
1819
"context"
1920
"crypto/rand"
2021
"crypto/rsa"
@@ -369,6 +370,55 @@ func TestConstructMongoClientOptions_NoTLS(t *testing.T) {
369370
}
370371
}
371372

373+
// TestConstructMongoClientOptions_BSONOptions_PreserveV1DecodeShape guards the two
374+
// driver v1 -> v2 decode behaviour changes this package depends on:
375+
//
376+
// - DefaultDocumentM: v2 decodes nested documents into bson.D; callers here
377+
// type-assert bson.M.
378+
// - ObjectIDAsHexString: v2 refuses to decode an ObjectID into a Go string, which
379+
// breaks structs binding `bson:"_id"` to a string field (e.g. the latest-event
380+
// lookup in fault-quarantine's CancelLatestQuarantiningEvents). Losing this
381+
// silently turns manual-uncordon cancellation into a no-op.
382+
func TestConstructMongoClientOptions_BSONOptions_PreserveV1DecodeShape(t *testing.T) {
383+
mongoConfig := MongoDBConfig{
384+
URI: "mongodb://localhost:27017",
385+
Database: "test",
386+
Collection: "test",
387+
TotalPingTimeoutSeconds: 5,
388+
TotalPingIntervalSeconds: 1,
389+
}
390+
391+
opts, err := constructMongoClientOptions(mongoConfig)
392+
require.NoError(t, err)
393+
require.NotNil(t, opts.BSONOptions, "BSON options must be set")
394+
require.True(t, opts.BSONOptions.DefaultDocumentM, "DefaultDocumentM must stay enabled")
395+
require.True(t, opts.BSONOptions.ObjectIDAsHexString, "ObjectIDAsHexString must stay enabled")
396+
}
397+
398+
// TestObjectIDDecodesIntoStringField documents the underlying driver behaviour the
399+
// option above compensates for: without it, decoding _id into a string fails.
400+
func TestObjectIDDecodesIntoStringField(t *testing.T) {
401+
oid := bson.NewObjectID()
402+
403+
raw, err := bson.Marshal(bson.M{"_id": oid})
404+
require.NoError(t, err)
405+
406+
var target struct {
407+
ID string `bson:"_id"`
408+
}
409+
410+
// Default v2 decoder: this is the failure seen in CI.
411+
err = bson.Unmarshal(raw, &target)
412+
require.Error(t, err)
413+
require.Contains(t, err.Error(), "decoding an object ID into a string is not supported by default")
414+
415+
// With ObjectIDAsHexString the same document decodes to the hex string.
416+
dec := bson.NewDecoder(bson.NewDocumentReader(bytes.NewReader(raw)))
417+
dec.ObjectIDAsHexString()
418+
require.NoError(t, dec.Decode(&target))
419+
require.Equal(t, oid.Hex(), target.ID)
420+
}
421+
372422
func TestConstructMongoClientOptions_DynamicClientCertificateUsesX509Auth(t *testing.T) {
373423
caCertPEM, caKeyPEM, err := generateCA()
374424
if err != nil {

0 commit comments

Comments
 (0)