Skip to content

Commit

Permalink
Merge branch 'master' into dependabot/go_modules/golang.org/x/sync-0.9.0
Browse files Browse the repository at this point in the history
  • Loading branch information
prestonvasquez authored Nov 19, 2024
2 parents 12e1b4f + e56a50f commit d83018f
Show file tree
Hide file tree
Showing 44 changed files with 523 additions and 6,238 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Dockerfile for Go Driver local development.

# Build libmongocrypt in a separate build stage.
FROM ubuntu:20.04 as libmongocrypt
FROM artifactory.corp.mongodb.com/dockerhub/ubuntu:20.04 as libmongocrypt

RUN apt-get -qq update && \
apt-get -qqy install --no-install-recommends \
Expand All @@ -17,7 +17,7 @@ RUN cd /root && bash ./install-libmongocrypt.sh


# Copy in the files from the libmongocrypt build stage.
FROM ubuntu:20.04
FROM artifactory.corp.mongodb.com/dockerhub/ubuntu:20.04

# Install common deps.
RUN export DEBIAN_FRONTEND=noninteractive && \
Expand Down
16 changes: 14 additions & 2 deletions docs/migration-2.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -1183,8 +1183,20 @@ A new `RawArray` type has been added to the `bson` package as a primitive type t

### ValueMarshaler

The `MarshalBSONValue` method of the `ValueMarshaler` interface is only required to return a byte type value representing the BSON type to avoid importing the `bsontype` package.
The `MarshalBSONValue` method of the [ValueMarshaler](https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueMarshaler) interface now returns a `byte` value representing the [BSON type](https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#Type). That allows external packages to implement the `ValueMarshaler` interface without having to import the `bson` package. Convert a returned `byte` value to [bson.Type](https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#Type) to compare with the BSON type constants. For example:

```go
btype, _, _ := m.MarshalBSONValue()
fmt.Println("type of data: %s: ", bson.Type(btype))
fmt.Println("type of data is an array: %v", bson.Type(btype) == bson.TypeArray)
```

### ValueUnmarshaler

The `UnmarshalBSONValue` method of the `ValueUnmarshaler` interface is only required to take a byte type argument representing the BSON type to avoid importing the Go driver package.
The `UnmarshalBSONValue` method of the [ValueUnmarshaler](https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#ValueUnmarshaler) interface now accepts a `byte` value representing the [BSON type](https://pkg.go.dev/go.mongodb.org/mongo-driver/v2/bson#Type) for the first argument. That allows packages to implement `ValueUnmarshaler` without having to import the `bson` package. For example:

```go
if err := m.UnmarshalBSONValue(bson.TypeEmbeddedDocument, bytes); err != nil {
log.Fatalf("failed to decode embedded document: %v", err)
}
```
10 changes: 6 additions & 4 deletions internal/integration/client_side_encryption_prose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1381,8 +1381,9 @@ func TestClientSideEncryptionProse(t *testing.T) {
}
})

// These tests only run when 3 KMS HTTP servers and 1 KMS KMIP server are running. See specification for port numbers and necessary arguments:
// https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#kms-tls-options-tests
// These tests only run when 3 KMS HTTP servers and 1 KMS KMIP server are
// running. See specification for port numbers and necessary arguments:
// https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#10-kms-tls-tests
mt.RunOpts("10. kms tls tests", noClientOpts, func(mt *mtest.T) {
kmsTlsTestcase := os.Getenv("KMS_TLS_TESTCASE")
if kmsTlsTestcase == "" {
Expand Down Expand Up @@ -1436,8 +1437,9 @@ func TestClientSideEncryptionProse(t *testing.T) {
}
})

// These tests only run when 3 KMS HTTP servers and 1 KMS KMIP server are running. See specification for port numbers and necessary arguments:
// https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#kms-tls-options-tests
// These tests only run when 3 KMS HTTP servers and 1 KMS KMIP server are
// running. See specification for port numbers and necessary arguments:
// https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.md#11-kms-tls-options-tests
mt.RunOpts("11. kms tls options tests", noClientOpts, func(mt *mtest.T) {
if os.Getenv("KMS_MOCK_SERVERS_RUNNING") == "" {
mt.Skipf("Skipping test as KMS_MOCK_SERVERS_RUNNING is not set")
Expand Down
61 changes: 49 additions & 12 deletions internal/integration/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"go.mongodb.org/mongo-driver/v2/internal/handshake"
"go.mongodb.org/mongo-driver/v2/internal/integration/mtest"
"go.mongodb.org/mongo-driver/v2/internal/require"
"go.mongodb.org/mongo-driver/v2/mongo/options"
"go.mongodb.org/mongo-driver/v2/version"
"go.mongodb.org/mongo-driver/v2/x/bsonx/bsoncore"
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/wiremessage"
Expand All @@ -34,19 +35,31 @@ func TestHandshakeProse(t *testing.T) {
CreateCollection(false).
ClientType(mtest.Proxy)

clientMetadata := func(env bson.D) bson.D {
clientMetadata := func(env bson.D, info *options.DriverInfo) bson.D {
var (
driverName = "mongo-go-driver"
driverVersion = version.Driver
platform = runtime.Version()
)

if info != nil {
driverName = driverName + "|" + info.Name
driverVersion = driverVersion + "|" + info.Version
platform = platform + "|" + info.Platform
}

elems := bson.D{
{Key: "driver", Value: bson.D{
{Key: "name", Value: "mongo-go-driver"},
{Key: "version", Value: version.Driver},
{Key: "name", Value: driverName},
{Key: "version", Value: driverVersion},
}},
{Key: "os", Value: bson.D{
{Key: "type", Value: runtime.GOOS},
{Key: "architecture", Value: runtime.GOARCH},
}},
}

elems = append(elems, bson.E{Key: "platform", Value: runtime.Version()})
elems = append(elems, bson.E{Key: "platform", Value: platform})

// If env is empty, don't include it in the metadata.
if env != nil && !reflect.DeepEqual(env, bson.D{}) {
Expand All @@ -56,6 +69,12 @@ func TestHandshakeProse(t *testing.T) {
return elems
}

driverInfo := &options.DriverInfo{
Name: "outer-library-name",
Version: "outer-library-version",
Platform: "outer-library-platform",
}

// Reset the environment variables to avoid environment namespace
// collision.
t.Setenv("AWS_EXECUTION_ENV", "")
Expand All @@ -72,6 +91,7 @@ func TestHandshakeProse(t *testing.T) {
for _, test := range []struct {
name string
env map[string]string
opts *options.ClientOptionsBuilder
want bson.D
}{
{
Expand All @@ -81,20 +101,22 @@ func TestHandshakeProse(t *testing.T) {
"AWS_REGION": "us-east-2",
"AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024",
},
opts: nil,
want: clientMetadata(bson.D{
{Key: "name", Value: "aws.lambda"},
{Key: "memory_mb", Value: 1024},
{Key: "region", Value: "us-east-2"},
}),
}, nil),
},
{
name: "2. valid Azure",
env: map[string]string{
"FUNCTIONS_WORKER_RUNTIME": "node",
},
opts: nil,
want: clientMetadata(bson.D{
{Key: "name", Value: "azure.func"},
}),
}, nil),
},
{
name: "3. valid GCP",
Expand All @@ -104,31 +126,34 @@ func TestHandshakeProse(t *testing.T) {
"FUNCTION_TIMEOUT_SEC": "60",
"FUNCTION_REGION": "us-central1",
},
opts: nil,
want: clientMetadata(bson.D{
{Key: "name", Value: "gcp.func"},
{Key: "memory_mb", Value: 1024},
{Key: "region", Value: "us-central1"},
{Key: "timeout_sec", Value: 60},
}),
}, nil),
},
{
name: "4. valid Vercel",
env: map[string]string{
"VERCEL": "1",
"VERCEL_REGION": "cdg1",
},
opts: nil,
want: clientMetadata(bson.D{
{Key: "name", Value: "vercel"},
{Key: "region", Value: "cdg1"},
}),
}, nil),
},
{
name: "5. invalid multiple providers",
env: map[string]string{
"AWS_EXECUTION_ENV": "AWS_Lambda_java8",
"FUNCTIONS_WORKER_RUNTIME": "node",
},
want: clientMetadata(nil),
opts: nil,
want: clientMetadata(nil, nil),
},
{
name: "6. invalid long string",
Expand All @@ -142,26 +167,34 @@ func TestHandshakeProse(t *testing.T) {
return s
}(),
},
opts: nil,
want: clientMetadata(bson.D{
{Key: "name", Value: "aws.lambda"},
}),
}, nil),
},
{
name: "7. invalid wrong types",
env: map[string]string{
"AWS_EXECUTION_ENV": "AWS_Lambda_java8",
"AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "big",
},
opts: nil,
want: clientMetadata(bson.D{
{Key: "name", Value: "aws.lambda"},
}),
}, nil),
},
{
name: "8. Invalid - AWS_EXECUTION_ENV does not start with \"AWS_Lambda_\"",
env: map[string]string{
"AWS_EXECUTION_ENV": "EC2",
},
want: clientMetadata(nil),
opts: nil,
want: clientMetadata(nil, nil),
},
{
name: "driver info included",
opts: options.Client().SetDriverInfo(driverInfo),
want: clientMetadata(nil, driverInfo),
},
} {
test := test
Expand All @@ -171,6 +204,10 @@ func TestHandshakeProse(t *testing.T) {
mt.Setenv(k, v)
}

if test.opts != nil {
mt.ResetClient(test.opts)
}

// Ping the server to ensure the handshake has completed.
err := mt.Client.Ping(context.Background(), nil)
require.NoError(mt, err, "Ping error: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion internal/integration/server_selection_prose_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func runsServerSelection(mt *mtest.T, monitor *eventtest.TestPoolMonitor,
}

// TestServerSelectionProse implements the Server Selection prose tests:
// https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection-tests.rst
// https://github.com/mongodb/specifications/blob/master/source/server-selection/server-selection-tests.md
func TestServerSelectionProse(t *testing.T) {
const maxPoolSize = 10
const localThreshold = 30 * time.Second
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ func executeDistinct(ctx context.Context, operation *operation) (*operationResul
val := elem.Value()

switch key {
case "hint":
opts.SetHint(val)
case "collation":
collation, err := createCollation(val.Document())
if err != nil {
Expand Down
10 changes: 10 additions & 0 deletions mongo/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,16 @@ func (coll *Collection) Distinct(
}
op.Comment(comment)
}
if args.Hint != nil {
if isUnorderedMap(args.Hint) {
return &DistinctResult{err: ErrMapForOrderedArgument{"hint"}}
}
hint, err := marshalValue(args.Hint, coll.bsonOpts, coll.registry)
if err != nil {
return &DistinctResult{err: err}
}
op.Hint(hint)
}
retry := driver.RetryNone
if coll.client.retryReads {
retry = driver.RetryOncePerCommand
Expand Down
25 changes: 25 additions & 0 deletions mongo/options/clientoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,17 @@ type BSONOptions struct {
ZeroStructs bool
}

// DriverInfo appends the client metadata generated by the driver when
// handshaking the server. These options do not replace the values used
// during the handshake, rather they are deliminated with a | with the
// driver-generated data. This should be used by libraries wrapping the driver,
// e.g. ODMs.
type DriverInfo struct {
Name string // Name of the library wrapping the driver.
Version string // Version of the library wrapping the driver.
Platform string // Platform information for the wrapping driver.
}

// ClientOptions contains arguments to configure a Client instance. Arguments
// can be set through the ClientOptions setter functions. See each function for
// documentation.
Expand All @@ -235,6 +246,7 @@ type ClientOptions struct {
Dialer ContextDialer
Direct *bool
DisableOCSPEndpointCheck *bool
DriverInfo *DriverInfo
HeartbeatInterval *time.Duration
Hosts []string
HTTPClient *http.Client
Expand Down Expand Up @@ -1249,6 +1261,19 @@ func (c *ClientOptionsBuilder) SetSRVServiceName(srvName string) *ClientOptionsB
return c
}

// SetDriverInfo configures optional data to include in the handshake's client
// metadata, delimited by "|" with the driver-generated data. This should be
// used by libraries wrapping the driver, e.g. ODMs.
func (c *ClientOptionsBuilder) SetDriverInfo(info *DriverInfo) *ClientOptionsBuilder {
c.Opts = append(c.Opts, func(opts *ClientOptions) error {
opts.DriverInfo = info

return nil
})

return c
}

// addCACertFromFile adds a root CA certificate to the configuration given a path
// to the containing file.
func addCACertFromFile(cfg *tls.Config, file string) error {
Expand Down
19 changes: 19 additions & 0 deletions mongo/options/distinctoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package options
type DistinctOptions struct {
Collation *Collation
Comment interface{}
Hint interface{}
}

// DistinctOptionsBuilder contains options to configure distinct operations. Each
Expand Down Expand Up @@ -60,3 +61,21 @@ func (do *DistinctOptionsBuilder) SetComment(comment interface{}) *DistinctOptio

return do
}

// SetHint specifies the index to use for the operation. This should either be
// the index name as a string or the index specification as a document. This
// option is only valid for MongoDB versions >= 7.1. Previous server versions
// will return an error if an index hint is specified. Distinct returns an error
// if the hint parameter is a multi-key map. The default value is nil, which
// means that no index hint will be sent.
//
// SetHint sets the Hint field.
func (do *DistinctOptionsBuilder) SetHint(hint interface{}) *DistinctOptionsBuilder {
do.Opts = append(do.Opts, func(opts *DistinctOptions) error {
opts.Hint = hint

return nil
})

return do
}
Loading

0 comments on commit d83018f

Please sign in to comment.