From 190e822b34a11a14966c205007365d9e831a31d4 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Sun, 9 Jun 2024 18:16:28 -0600 Subject: [PATCH 01/15] otelmongo#39 Convert to unit tests --- .github/workflows/ci.yml | 44 ---- CHANGELOG.md | 1 + Makefile | 19 +- .../mongo-driver/mongo/otelmongo/test/go.mod | 2 + .../mongo/otelmongo/test/mongo_test.go | 39 ++- .../mongo/otelmongo/test/opmsg_deployment.go | 234 ++++++++++++++++++ internal/util/testutil.go | 20 -- tools/wait.sh | 14 -- 8 files changed, 265 insertions(+), 108 deletions(-) create mode 100644 instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go delete mode 100644 internal/util/testutil.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0783746bd01..b7138957371 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -137,47 +137,3 @@ jobs: echo ${{ needs.compatibility-test.result }} test ${{ needs.compatibility-test.result }} == "success" - integration: - strategy: - matrix: - target: [test-mongo-driver] - runs-on: ubuntu-latest - steps: - - name: Checkout Repo - uses: actions/checkout@v4 - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ${{ env.DEFAULT_GO_VERSION }} - check-latest: true - cache-dependency-path: "**/go.sum" - - name: Run coverage tests ${{ matrix.target }} - env: - INTEGRATION: ${{ matrix.target }} - run: | - make ${{ matrix.target }} - mkdir -p $TEST_RESULTS - find . -name 'coverage.html' > "${TEST_RESULTS}/coverage.lst" - tar -n -cf - -T "${TEST_RESULTS}/coverage.lst" | tar -C "${TEST_RESULTS}" -xvf - - - name: Upload coverage report - uses: codecov/codecov-action@v4.4.1 - if: hashFiles('coverage.out') != '' - with: - file: ./coverage.out - fail_ci_if_error: true - verbose: true - token: ${{ secrets.CODECOV_TOKEN }} - - name: Store coverage test output - uses: actions/upload-artifact@v4 - with: - name: opentelemetry-go-contrib-integration-test-output - path: ${{ env.TEST_RESULTS }} - - test-integration: - runs-on: ubuntu-latest - needs: [integration] - steps: - - name: Test if integration workflow passed - run: | - echo ${{ needs.integration.result }} - test ${{ needs.integration.result }} == "success" diff --git a/CHANGELOG.md b/CHANGELOG.md index 17698373958..4993a368ef4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Improve performance of `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` with the usage of `WithAttributeSet()` instead of `WithAttribute()`. (#5664) - Improve performance of `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` with the usage of `WithAttributeSet()` instead of `WithAttribute()`. (#5664) +- Copy [opmsg_deployment.go](https://github.com/mongodb/mongo-go-driver/blob/d46f29c34e9ff3968a5c00dcdea8fb41a20a2b2f/mongo/integration/mtest/opmsg_deployment.go) from the mongo-go-driver mtest package to create a mock client for testing otelmongo. Remove all helpers specific to running the `test-mongo-driver` integration test. (#39) ## [1.27.0/0.52.0/0.21.0/0.7.0/0.2.0] - 2024-05-21 diff --git a/Makefile b/Makefile index 9404d8203a6..94fd7849922 100644 --- a/Makefile +++ b/Makefile @@ -263,23 +263,6 @@ test-coverage/%: && $$CMD ./... \ && $(GO) tool cover -html=coverage.out -o coverage.html; -.PHONY: test-mongo-driver -test-mongo-driver: - @if ./tools/should_build.sh mongo-driver; then \ - set -e; \ - docker run --name mongo-integ --rm -p 27017:27017 -d mongo; \ - CMD=mongo IMG_NAME=mongo-integ ./tools/wait.sh; \ - (cd instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test && \ - $(GO) test \ - -covermode=$(COVERAGE_MODE) \ - -coverprofile=$(COVERAGE_PROFILE) \ - -coverpkg=go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/... \ - ./... \ - && $(GO) tool cover -html=$(COVERAGE_PROFILE) -o coverage.html); \ - cp ./instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/coverage.out ./; \ - docker stop mongo-integ; \ - fi - # Releasing .PHONY: gorelease @@ -351,4 +334,4 @@ genjsonschema: genjsonschema-cleanup $(GOJSONSCHEMA) .PHONY: codespell codespell: $(CODESPELL) - @$(DOCKERPY) $(CODESPELL) \ No newline at end of file + @$(DOCKERPY) $(CODESPELL) diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod index bc540e9b764..963dda1edde 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod @@ -3,6 +3,8 @@ module go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/m go 1.21 +replace go.mongodb.org/mongo-driver => /Users/prestonvasquez/Developer/mongo-go-driver + require ( github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.15.0 diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go index 8fe95e6ca3e..4ea63fe1ff3 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go @@ -5,7 +5,6 @@ package test import ( "context" - "os" "testing" "time" @@ -15,7 +14,6 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" // nolint:staticcheck // deprecated. - "go.opentelemetry.io/contrib/internal/util" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -23,11 +21,6 @@ import ( "go.opentelemetry.io/otel/trace" ) -func TestMain(m *testing.M) { - util.IntegrationShouldRun("test-mongo-driver") - os.Exit(m.Run()) -} - type validator func(sdktrace.ReadOnlySpan) bool func TestDBCrudOperation(t *testing.T) { @@ -49,6 +42,7 @@ func TestDBCrudOperation(t *testing.T) { tt := []struct { title string operation func(context.Context, *mongo.Database) (interface{}, error) + mockResponses []bson.D excludeCommand bool validators []validator }{ @@ -57,6 +51,7 @@ func TestDBCrudOperation(t *testing.T) { operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").InsertOne(ctx, bson.D{{Key: "test-item", Value: "test-value"}}) }, + mockResponses: []bson.D{{{"ok", 1}}}, excludeCommand: false, validators: append(commonValidators, func(s sdktrace.ReadOnlySpan) bool { for _, attr := range s.Attributes() { @@ -72,6 +67,7 @@ func TestDBCrudOperation(t *testing.T) { operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").InsertOne(ctx, bson.D{{Key: "test-item", Value: "test-value"}}) }, + mockResponses: []bson.D{{{"ok", 1}}}, excludeCommand: true, validators: append(commonValidators, func(s sdktrace.ReadOnlySpan) bool { for _, attr := range s.Attributes() { @@ -105,12 +101,20 @@ func TestDBCrudOperation(t *testing.T) { otelmongo.WithTracerProvider(provider), otelmongo.WithCommandAttributeDisabled(tc.excludeCommand), ) + opts.ApplyURI(addr) + + mock := newMockDeployment() + opts.Deployment = mock + client, err := mongo.Connect(ctx, opts) if err != nil { t.Fatal(err) } + mock.addResponses(tc.mockResponses...) + t.Cleanup(mock.clearResponses) + _, err = tc.operation(ctx, client.Database("test-database")) if err != nil { t.Error(err) @@ -131,7 +135,7 @@ func TestDBCrudOperation(t *testing.T) { assert.Equal(t, trace.SpanKindClient, s.SpanKind()) attrs := s.Attributes() assert.Contains(t, attrs, attribute.String("db.system", "mongodb")) - assert.Contains(t, attrs, attribute.String("net.peer.name", "localhost")) + assert.Contains(t, attrs, attribute.String("net.peer.name", "")) assert.Contains(t, attrs, attribute.Int64("net.peer.port", int64(27017))) assert.Contains(t, attrs, attribute.String("net.transport", "ip_tcp")) assert.Contains(t, attrs, attribute.String("db.name", "test-database")) @@ -144,15 +148,17 @@ func TestDBCrudOperation(t *testing.T) { func TestDBCollectionAttribute(t *testing.T) { tt := []struct { - title string - operation func(context.Context, *mongo.Database) (interface{}, error) - validators []validator + title string + operation func(context.Context, *mongo.Database) (interface{}, error) + mockResponses []bson.D + validators []validator }{ { title: "delete", operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").DeleteOne(ctx, bson.D{{Key: "test-item"}}) }, + mockResponses: []bson.D{{{"ok", 1}}}, validators: []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "test-collection.delete", s.Name()) @@ -173,6 +179,7 @@ func TestDBCollectionAttribute(t *testing.T) { operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.ListCollectionNames(ctx, bson.D{}) }, + mockResponses: []bson.D{{{"ok", 1}, {"cursor", bson.D{{"firstBatch", bson.A{}}}}}}, validators: []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "listCollections", s.Name()) @@ -202,12 +209,20 @@ func TestDBCollectionAttribute(t *testing.T) { otelmongo.WithTracerProvider(provider), otelmongo.WithCommandAttributeDisabled(true), ) + opts.ApplyURI(addr) + + mock := newMockDeployment() + opts.Deployment = mock + client, err := mongo.Connect(ctx, opts) if err != nil { t.Fatal(err) } + mock.addResponses(tc.mockResponses...) + t.Cleanup(mock.clearResponses) + _, err = tc.operation(ctx, client.Database("test-database")) if err != nil { t.Error(err) @@ -228,7 +243,7 @@ func TestDBCollectionAttribute(t *testing.T) { assert.Equal(t, trace.SpanKindClient, s.SpanKind()) attrs := s.Attributes() assert.Contains(t, attrs, attribute.String("db.system", "mongodb")) - assert.Contains(t, attrs, attribute.String("net.peer.name", "localhost")) + assert.Contains(t, attrs, attribute.String("net.peer.name", "")) assert.Contains(t, attrs, attribute.Int64("net.peer.port", int64(27017))) assert.Contains(t, attrs, attribute.String("net.transport", "ip_tcp")) assert.Contains(t, attrs, attribute.String("db.name", "test-database")) diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go new file mode 100644 index 00000000000..eb95f1207ac --- /dev/null +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go @@ -0,0 +1,234 @@ +// Copied from https://github.com/mongodb/mongo-go-driver/blob/d46f29c34e9ff3968a5c00dcdea8fb41a20a2b2f/mongo/integration/mtest/opmsg_deployment.go + +// Copyright (C) MongoDB, Inc. 2017-present. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +package test + +import ( + "context" + "errors" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo/address" + "go.mongodb.org/mongo-driver/mongo/description" + "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" + "go.mongodb.org/mongo-driver/x/mongo/driver" + "go.mongodb.org/mongo-driver/x/mongo/driver/topology" + "go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage" +) + +const ( + serverAddress = address.Address("127.0.0.1:27017") + maxDocumentSize uint32 = 16777216 + maxMessageSize uint32 = 48000000 + maxBatchCount uint32 = 100000 +) + +var ( + sessionTimeoutMinutes uint32 = 30 + sessionTimeoutMinutesInt64 = int64(sessionTimeoutMinutes) + + // MockDescription is the server description used for the mock deployment. Each mocked connection returns this + // value from its Description method. + MockDescription = description.Server{ + CanonicalAddr: serverAddress, + MaxDocumentSize: maxDocumentSize, + MaxMessageSize: maxMessageSize, + MaxBatchCount: maxBatchCount, + // TODO(GODRIVER-2885): This can be removed once legacy + // SessionTimeoutMinutes is removed. + SessionTimeoutMinutes: sessionTimeoutMinutes, + SessionTimeoutMinutesPtr: &sessionTimeoutMinutesInt64, + Kind: description.RSPrimary, + WireVersion: &description.VersionRange{ + Max: topology.SupportedWireVersions.Max, + }, + } +) + +// connection implements the driver.Connection interface and responds to wire messages with pre-configured responses. +type connection struct { + responses []bson.D // responses to send when ReadWireMessage is called +} + +var _ driver.Connection = &connection{} + +// WriteWireMessage is a no-op. +func (c *connection) WriteWireMessage(context.Context, []byte) error { + return nil +} + +// ReadWireMessage returns the next response in the connection's list of responses. +func (c *connection) ReadWireMessage(_ context.Context) ([]byte, error) { + var dst []byte + if len(c.responses) == 0 { + return dst, errors.New("no responses remaining") + } + nextRes := c.responses[0] + c.responses = c.responses[1:] + + var wmindex int32 + wmindex, dst = wiremessage.AppendHeaderStart(dst, wiremessage.NextRequestID(), 0, wiremessage.OpMsg) + dst = wiremessage.AppendMsgFlags(dst, 0) + dst = wiremessage.AppendMsgSectionType(dst, wiremessage.SingleDocument) + resBytes, _ := bson.Marshal(nextRes) + dst = append(dst, resBytes...) + dst = bsoncore.UpdateLength(dst, wmindex, int32(len(dst[wmindex:]))) + return dst, nil +} + +// Description returns a fixed server description for the connection. +func (c *connection) Description() description.Server { + return MockDescription +} + +// Close is a no-op operation. +func (*connection) Close() error { + return nil +} + +// ID returns a fixed identifier for the connection. +func (*connection) ID() string { + return "" +} + +// DriverConnectionID returns a fixed identifier for the driver pool connection. +// TODO(GODRIVER-2824): replace return type with int64. +func (*connection) DriverConnectionID() uint64 { + return 0 +} + +// ServerConnectionID returns a fixed identifier for the server connection. +func (*connection) ServerConnectionID() *int64 { + serverConnectionID := int64(42) + return &serverConnectionID +} + +// Address returns a fixed address for the connection. +func (*connection) Address() address.Address { + return serverAddress +} + +// Stale returns if the connection is stale. +func (*connection) Stale() bool { + return false +} + +// mockDeployment wraps a connection and implements the driver.Deployment interface. +type mockDeployment struct { + conn *connection + updates chan description.Topology +} + +var _ driver.Deployment = &mockDeployment{} +var _ driver.Server = &mockDeployment{} +var _ driver.Connector = &mockDeployment{} +var _ driver.Disconnector = &mockDeployment{} +var _ driver.Subscriber = &mockDeployment{} + +// SelectServer implements the Deployment interface. This method does not use the +// description.SelectedServer provided and instead returns itself. The Connections returned from the +// Connection method have a no-op Close method. +func (md *mockDeployment) SelectServer(context.Context, description.ServerSelector) (driver.Server, error) { + return md, nil +} + +// Kind implements the Deployment interface. It always returns description.Single. +func (md *mockDeployment) Kind() description.TopologyKind { + return description.Single +} + +// Connection implements the driver.Server interface. +func (md *mockDeployment) Connection(context.Context) (driver.Connection, error) { + return md.conn, nil +} + +// ZeroRTTMonitor implements the RTTMonitor interface and is used internally for testing. It returns 0 for all +// RTT calculations and an empty string for RTT statistics. +type ZeroRTTMonitor struct{} + +var _ driver.RTTMonitor = &ZeroRTTMonitor{} + +// EWMA implements the RTT monitor interface. +func (zrm *ZeroRTTMonitor) EWMA() time.Duration { + return 0 +} + +// Min implements the RTT monitor interface. +func (zrm *ZeroRTTMonitor) Min() time.Duration { + return 0 +} + +// P90 implements the RTT monitor interface. +func (zrm *ZeroRTTMonitor) P90() time.Duration { + return 0 +} + +// Stats implements the RTT monitor interface. +func (zrm *ZeroRTTMonitor) Stats() string { + return "" +} + +// RTTMonitor implements the driver.Server interface. +func (md *mockDeployment) RTTMonitor() driver.RTTMonitor { + return &ZeroRTTMonitor{} +} + +// Connect is a no-op method which implements the driver.Connector interface. +func (md *mockDeployment) Connect() error { + return nil +} + +// Disconnect is a no-op method which implements the driver.Disconnector interface { +func (md *mockDeployment) Disconnect(context.Context) error { + close(md.updates) + return nil +} + +// Subscribe returns a subscription from which new topology descriptions can be retrieved. +// Subscribe implements the driver.Subscriber interface. +func (md *mockDeployment) Subscribe() (*driver.Subscription, error) { + if md.updates == nil { + md.updates = make(chan description.Topology, 1) + + md.updates <- description.Topology{ + SessionTimeoutMinutesPtr: &sessionTimeoutMinutesInt64, + + // TODO(GODRIVER-2885): This can be removed once legacy + // SessionTimeoutMinutes is removed. + SessionTimeoutMinutes: sessionTimeoutMinutes, + } + } + + return &driver.Subscription{ + Updates: md.updates, + }, nil +} + +// Unsubscribe is a no-op method which implements the driver.Subscriber interface. +func (md *mockDeployment) Unsubscribe(*driver.Subscription) error { + return nil +} + +// addResponses adds responses to this mock deployment. +func (md *mockDeployment) addResponses(responses ...bson.D) { + md.conn.responses = append(md.conn.responses, responses...) +} + +// clearResponses clears all remaining responses in this mock deployment. +func (md *mockDeployment) clearResponses() { + md.conn.responses = md.conn.responses[:0] +} + +// newMockDeployment returns a mock driver.Deployment that responds with OP_MSG wire messages. +func newMockDeployment(responses ...bson.D) *mockDeployment { + return &mockDeployment{ + conn: &connection{ + responses: responses, + }, + } +} diff --git a/internal/util/testutil.go b/internal/util/testutil.go deleted file mode 100644 index 39e581a7fe4..00000000000 --- a/internal/util/testutil.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package util // import "go.opentelemetry.io/contrib/internal/util" - -import ( - "fmt" - "os" -) - -func IntegrationShouldRun(name string) { - if val, ok := os.LookupEnv("INTEGRATION"); !ok || val != name { - fmt.Println( - "--- SKIP: to enable integration test, set the INTEGRATION environment variable", - "to", - fmt.Sprintf("\"%s\"", name), - ) - os.Exit(0) //nolint revive // Signal test was successfully skipped. - } -} diff --git a/tools/wait.sh b/tools/wait.sh index b485027bdf3..8a4d1a5277e 100755 --- a/tools/wait.sh +++ b/tools/wait.sh @@ -15,18 +15,6 @@ wait_for_cassandra () { exit 1 } -wait_for_mongo () { - for ((i = 0; i < 5; ++i)); do - if docker exec "$1" mongosh; then - exit 0 - fi - echo "Mongo not yet available..." - sleep 10 - done - echo "Timeout waiting for mongo to initialize" - exit 1 -} - wait_for_gomemcache () { for ((i = 0; i < 5; ++i)); do if nc -z localhost 11211; then @@ -49,8 +37,6 @@ fi if [ "$CMD" == "cassandra" ]; then wait_for_cassandra "$IMG_NAME" -elif [ "$CMD" == "mongo" ]; then - wait_for_mongo "$IMG_NAME" elif [ "$CMD" == "gomemcache" ]; then wait_for_gomemcache else From 74daa5714003f22952ec83dc85b332d5d07c57ca Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Sun, 9 Jun 2024 19:03:18 -0600 Subject: [PATCH 02/15] otelmongo#39 Fix linting errors --- Makefile | 2 +- .../mongo-driver/mongo/otelmongo/test/go.mod | 3 --- .../mongo/otelmongo/test/mongo_test.go | 27 ++++++++++++++++--- .../mongo/otelmongo/test/opmsg_deployment.go | 15 ++++++----- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 94fd7849922..def8770acd1 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ TIMEOUT = 60 .DEFAULT_GOAL := precommit .PHONY: precommit ci -precommit: generate license-check misspell go-mod-tidy golangci-lint-fix test-default +precommit: generate license-check misspell go-mod-tidy golangci-lint-fix ci: generate license-check lint vanity-import-check build test-default check-clean-work-tree test-coverage # Tools diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod index 963dda1edde..8989d91a429 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod @@ -3,12 +3,9 @@ module go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/m go 1.21 -replace go.mongodb.org/mongo-driver => /Users/prestonvasquez/Developer/mongo-go-driver - require ( github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.15.0 - go.opentelemetry.io/contrib v1.27.0 go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.52.0 go.opentelemetry.io/otel v1.27.0 go.opentelemetry.io/otel/sdk v1.27.0 diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go index 4ea63fe1ff3..2ad319e9701 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go @@ -51,7 +51,7 @@ func TestDBCrudOperation(t *testing.T) { operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").InsertOne(ctx, bson.D{{Key: "test-item", Value: "test-value"}}) }, - mockResponses: []bson.D{{{"ok", 1}}}, + mockResponses: []bson.D{{{Key: "ok", Value: 1}}}, excludeCommand: false, validators: append(commonValidators, func(s sdktrace.ReadOnlySpan) bool { for _, attr := range s.Attributes() { @@ -67,7 +67,7 @@ func TestDBCrudOperation(t *testing.T) { operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").InsertOne(ctx, bson.D{{Key: "test-item", Value: "test-value"}}) }, - mockResponses: []bson.D{{{"ok", 1}}}, + mockResponses: []bson.D{{{Key: "ok", Value: 1}}}, excludeCommand: true, validators: append(commonValidators, func(s sdktrace.ReadOnlySpan) bool { for _, attr := range s.Attributes() { @@ -105,6 +105,13 @@ func TestDBCrudOperation(t *testing.T) { opts.ApplyURI(addr) mock := newMockDeployment() + + // nolint:staticcheck + // + // Deployment is not part of the stable API guaruntee of the + // mongo-go-driver and is therefore marked as deprecated. + // + // See jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. opts.Deployment = mock client, err := mongo.Connect(ctx, opts) @@ -158,7 +165,7 @@ func TestDBCollectionAttribute(t *testing.T) { operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.Collection("test-collection").DeleteOne(ctx, bson.D{{Key: "test-item"}}) }, - mockResponses: []bson.D{{{"ok", 1}}}, + mockResponses: []bson.D{{{Key: "ok", Value: 1}}}, validators: []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "test-collection.delete", s.Name()) @@ -179,7 +186,12 @@ func TestDBCollectionAttribute(t *testing.T) { operation: func(ctx context.Context, db *mongo.Database) (interface{}, error) { return db.ListCollectionNames(ctx, bson.D{}) }, - mockResponses: []bson.D{{{"ok", 1}, {"cursor", bson.D{{"firstBatch", bson.A{}}}}}}, + mockResponses: []bson.D{ + { + {Key: "ok", Value: 1}, + {Key: "cursor", Value: bson.D{{Key: "firstBatch", Value: bson.A{}}}}, + }, + }, validators: []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "listCollections", s.Name()) @@ -213,6 +225,13 @@ func TestDBCollectionAttribute(t *testing.T) { opts.ApplyURI(addr) mock := newMockDeployment() + + // nolint:staticcheck + // + // Deployment is not part of the stable API guaruntee of the + // mongo-go-driver and is therefore marked as deprecated. + // + // See jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. opts.Deployment = mock client, err := mongo.Connect(ctx, opts) diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go index eb95f1207ac..e2353462c92 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go @@ -5,6 +5,7 @@ // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + package test import ( @@ -124,11 +125,13 @@ type mockDeployment struct { updates chan description.Topology } -var _ driver.Deployment = &mockDeployment{} -var _ driver.Server = &mockDeployment{} -var _ driver.Connector = &mockDeployment{} -var _ driver.Disconnector = &mockDeployment{} -var _ driver.Subscriber = &mockDeployment{} +var ( + _ driver.Deployment = &mockDeployment{} + _ driver.Server = &mockDeployment{} + _ driver.Connector = &mockDeployment{} + _ driver.Disconnector = &mockDeployment{} + _ driver.Subscriber = &mockDeployment{} +) // SelectServer implements the Deployment interface. This method does not use the // description.SelectedServer provided and instead returns itself. The Connections returned from the @@ -183,7 +186,7 @@ func (md *mockDeployment) Connect() error { return nil } -// Disconnect is a no-op method which implements the driver.Disconnector interface { +// Disconnect is a no-op method which implements the driver.Disconnector interface {. func (md *mockDeployment) Disconnect(context.Context) error { close(md.updates) return nil From 5b20239d6125138a90403bef520d43e8b4f49106 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Sun, 9 Jun 2024 19:26:43 -0600 Subject: [PATCH 03/15] otelmongo#39 Add test-default back to precommit --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index def8770acd1..94fd7849922 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ TIMEOUT = 60 .DEFAULT_GOAL := precommit .PHONY: precommit ci -precommit: generate license-check misspell go-mod-tidy golangci-lint-fix +precommit: generate license-check misspell go-mod-tidy golangci-lint-fix test-default ci: generate license-check lint vanity-import-check build test-default check-clean-work-tree test-coverage # Tools From 14448ad95901f26582e78889ed1a653ab24fb39e Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Sun, 9 Jun 2024 19:28:18 -0600 Subject: [PATCH 04/15] otelmongo#39 Add empty line back to Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 94fd7849922..2c081a34e4a 100644 --- a/Makefile +++ b/Makefile @@ -335,3 +335,4 @@ genjsonschema: genjsonschema-cleanup $(GOJSONSCHEMA) .PHONY: codespell codespell: $(CODESPELL) @$(DOCKERPY) $(CODESPELL) + From 1bb795607385c8b24833151b34b38f975d8789ac Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Sun, 9 Jun 2024 19:28:56 -0600 Subject: [PATCH 05/15] otelmongo#39 Remove empty line form Makefile --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index 2c081a34e4a..94fd7849922 100644 --- a/Makefile +++ b/Makefile @@ -335,4 +335,3 @@ genjsonschema: genjsonschema-cleanup $(GOJSONSCHEMA) .PHONY: codespell codespell: $(CODESPELL) @$(DOCKERPY) $(CODESPELL) - From a3297caeb193fc7ecd1920d1a13bd2e19526b774 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Mon, 10 Jun 2024 20:16:54 -0600 Subject: [PATCH 06/15] otelmongo#39 Remove update to CHANGELOG --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f08865d6047..78f99a77d5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,6 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Improve performance of `go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc` with the usage of `WithAttributeSet()` instead of `WithAttribute()`. (#5664) - Improve performance of `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` with the usage of `WithAttributeSet()` instead of `WithAttribute()`. (#5664) -- Copy [opmsg_deployment.go](https://github.com/mongodb/mongo-go-driver/blob/d46f29c34e9ff3968a5c00dcdea8fb41a20a2b2f/mongo/integration/mtest/opmsg_deployment.go) from the mongo-go-driver mtest package to create a mock client for testing otelmongo. Remove all helpers specific to running the `test-mongo-driver` integration test. (#39) ## [1.27.0/0.52.0/0.21.0/0.7.0/0.2.0] - 2024-05-21 From efbef54b398adf230dfc0af42060cd533d88edb6 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Mon, 10 Jun 2024 20:40:42 -0600 Subject: [PATCH 07/15] otelmongo#39 Make CI pass with third-party code --- .github/codecov.yaml | 4 ++++ Makefile | 7 ++++++- .../mongo-driver/mongo/otelmongo/test/mongo_test.go | 6 ++---- .../mongo-driver/mongo/otelmongo/test/opmsg_deployment.go | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/codecov.yaml b/.github/codecov.yaml index d7463d08fb0..57bca0caab0 100644 --- a/.github/codecov.yaml +++ b/.github/codecov.yaml @@ -15,3 +15,7 @@ comment: layout: "reach,diff,flags,tree" behavior: default require_changes: yes + +ignore: + # opmsg_deployment is copied from mongo-go-driver. + - "instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go" diff --git a/Makefile b/Makefile index 94fd7849922..0def5aaf787 100644 --- a/Makefile +++ b/Makefile @@ -186,9 +186,14 @@ vanity-import-check: | $(PORTO) .PHONY: lint lint: go-mod-tidy golangci-lint misspell govulncheck +# The following file is a third-party copy from the mongo-go-driver: +# ./instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go .PHONY: license-check license-check: - @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path './vendor/*' ! -path './exporters/otlp/internal/opentelemetry-proto/*') ; do \ + @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) \ + ! -path './vendor/*' \ + ! -path './exporters/otlp/internal/opentelemetry-proto/*' \ + ! -path './instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go') ; do \ awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \ done); \ if [ -n "$${licRes}" ]; then \ diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go index 2ad319e9701..939f99b942a 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go @@ -101,7 +101,6 @@ func TestDBCrudOperation(t *testing.T) { otelmongo.WithTracerProvider(provider), otelmongo.WithCommandAttributeDisabled(tc.excludeCommand), ) - opts.ApplyURI(addr) mock := newMockDeployment() @@ -111,7 +110,7 @@ func TestDBCrudOperation(t *testing.T) { // Deployment is not part of the stable API guaruntee of the // mongo-go-driver and is therefore marked as deprecated. // - // See jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. + // See https://jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. opts.Deployment = mock client, err := mongo.Connect(ctx, opts) @@ -221,7 +220,6 @@ func TestDBCollectionAttribute(t *testing.T) { otelmongo.WithTracerProvider(provider), otelmongo.WithCommandAttributeDisabled(true), ) - opts.ApplyURI(addr) mock := newMockDeployment() @@ -231,7 +229,7 @@ func TestDBCollectionAttribute(t *testing.T) { // Deployment is not part of the stable API guaruntee of the // mongo-go-driver and is therefore marked as deprecated. // - // See jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. + // See https://jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. opts.Deployment = mock client, err := mongo.Connect(ctx, opts) diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go index e2353462c92..6510f816e4c 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go @@ -6,7 +6,7 @@ // not use this file except in compliance with the License. You may obtain // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 -package test +package test // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test" import ( "context" From e06df49a3dab65938854f42c81e064c94b06c133 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Thu, 13 Jun 2024 10:12:23 -0600 Subject: [PATCH 08/15] Update instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go Co-authored-by: Damien Mathieu <42@dmathieu.com> --- .../mongo-driver/mongo/otelmongo/test/mongo_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go index 939f99b942a..8526bad05b5 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go @@ -107,7 +107,7 @@ func TestDBCrudOperation(t *testing.T) { // nolint:staticcheck // - // Deployment is not part of the stable API guaruntee of the + // Deployment is not part of the stable API guarantee of the // mongo-go-driver and is therefore marked as deprecated. // // See https://jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. From e1537913955a44d55cdad636013b2415daf5f141 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Thu, 13 Jun 2024 10:12:29 -0600 Subject: [PATCH 09/15] Update instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go Co-authored-by: Damien Mathieu <42@dmathieu.com> --- .../mongo-driver/mongo/otelmongo/test/mongo_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go index 8526bad05b5..f1141de9b45 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go @@ -226,7 +226,7 @@ func TestDBCollectionAttribute(t *testing.T) { // nolint:staticcheck // - // Deployment is not part of the stable API guaruntee of the + // Deployment is not part of the stable API guarantee of the // mongo-go-driver and is therefore marked as deprecated. // // See https://jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. From 74892a25e4f02debcc1cec7603f52294e86b1dd4 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Tue, 30 Jul 2024 12:41:20 -0600 Subject: [PATCH 10/15] Use mtest for mocking otelmongo --- .github/codecov.yaml | 4 - Makefile | 8 +- .../mongo-driver/mongo/otelmongo/test/go.mod | 2 + .../mongo/otelmongo/test/mongo_test.go | 118 ++++----- .../mongo/otelmongo/test/opmsg_deployment.go | 237 ------------------ 5 files changed, 55 insertions(+), 314 deletions(-) delete mode 100644 instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go diff --git a/.github/codecov.yaml b/.github/codecov.yaml index 57bca0caab0..d7463d08fb0 100644 --- a/.github/codecov.yaml +++ b/.github/codecov.yaml @@ -15,7 +15,3 @@ comment: layout: "reach,diff,flags,tree" behavior: default require_changes: yes - -ignore: - # opmsg_deployment is copied from mongo-go-driver. - - "instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go" diff --git a/Makefile b/Makefile index 0def5aaf787..72c404a9d2e 100644 --- a/Makefile +++ b/Makefile @@ -186,15 +186,9 @@ vanity-import-check: | $(PORTO) .PHONY: lint lint: go-mod-tidy golangci-lint misspell govulncheck -# The following file is a third-party copy from the mongo-go-driver: -# ./instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go .PHONY: license-check license-check: - @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) \ - ! -path './vendor/*' \ - ! -path './exporters/otlp/internal/opentelemetry-proto/*' \ - ! -path './instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go') ; do \ - awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \ + @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path './vendor/*' ! -path './exporters/otlp/internal/opentelemetry-proto/*') ; do \ done); \ if [ -n "$${licRes}" ]; then \ echo "license header checking failed:"; echo "$${licRes}"; \ diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod index 8989d91a429..769bdb3a9fe 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod @@ -3,6 +3,8 @@ module go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/m go 1.21 +replace go.mongodb.org/mongo-driver => /Users/preston.vasquez/Developer/mongo-go-driver-2 + require ( github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.15.0 diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go index f1141de9b45..10413393a21 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/integration/mtest" "go.mongodb.org/mongo-driver/mongo/options" "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" // nolint:staticcheck // deprecated. @@ -24,6 +25,8 @@ import ( type validator func(sdktrace.ReadOnlySpan) bool func TestDBCrudOperation(t *testing.T) { + t.Parallel() + commonValidators := []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "test-collection.insert", s.Name(), "expected %s", s.Name()) @@ -80,13 +83,19 @@ func TestDBCrudOperation(t *testing.T) { }, } for _, tc := range tt { + tc := tc + title := tc.title if tc.excludeCommand { title = title + "/excludeCommand" } else { title = title + "/includeCommand" } - t.Run(title, func(t *testing.T) { + + mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock)) + mt.Run(title, func(mt *mtest.T) { + mt.Parallel() + sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) @@ -103,56 +112,43 @@ func TestDBCrudOperation(t *testing.T) { ) opts.ApplyURI(addr) - mock := newMockDeployment() - - // nolint:staticcheck - // - // Deployment is not part of the stable API guarantee of the - // mongo-go-driver and is therefore marked as deprecated. - // - // See https://jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. - opts.Deployment = mock - - client, err := mongo.Connect(ctx, opts) - if err != nil { - t.Fatal(err) - } - - mock.addResponses(tc.mockResponses...) - t.Cleanup(mock.clearResponses) + mt.ResetClient(opts) + mt.AddMockResponses(tc.mockResponses...) - _, err = tc.operation(ctx, client.Database("test-database")) + _, err := tc.operation(ctx, mt.Client.Database("test-database")) if err != nil { - t.Error(err) + mt.Error(err) } span.End() spans := sr.Ended() - if !assert.Len(t, spans, 2, "expected 2 spans, received %d", len(spans)) { - t.FailNow() + if !assert.Len(mt, spans, 2, "expected 2 spans, received %d", len(spans)) { + mt.FailNow() } - assert.Len(t, spans, 2) - assert.Equal(t, spans[0].SpanContext().TraceID(), spans[1].SpanContext().TraceID()) - assert.Equal(t, spans[0].Parent().SpanID(), spans[1].SpanContext().SpanID()) - assert.Equal(t, span.SpanContext().SpanID(), spans[1].SpanContext().SpanID()) + assert.Len(mt, spans, 2) + assert.Equal(mt, spans[0].SpanContext().TraceID(), spans[1].SpanContext().TraceID()) + assert.Equal(mt, spans[0].Parent().SpanID(), spans[1].SpanContext().SpanID()) + assert.Equal(mt, span.SpanContext().SpanID(), spans[1].SpanContext().SpanID()) s := spans[0] - assert.Equal(t, trace.SpanKindClient, s.SpanKind()) + assert.Equal(mt, trace.SpanKindClient, s.SpanKind()) attrs := s.Attributes() - assert.Contains(t, attrs, attribute.String("db.system", "mongodb")) - assert.Contains(t, attrs, attribute.String("net.peer.name", "")) - assert.Contains(t, attrs, attribute.Int64("net.peer.port", int64(27017))) - assert.Contains(t, attrs, attribute.String("net.transport", "ip_tcp")) - assert.Contains(t, attrs, attribute.String("db.name", "test-database")) + assert.Contains(mt, attrs, attribute.String("db.system", "mongodb")) + assert.Contains(mt, attrs, attribute.String("net.peer.name", "")) + assert.Contains(mt, attrs, attribute.Int64("net.peer.port", int64(27017))) + assert.Contains(mt, attrs, attribute.String("net.transport", "ip_tcp")) + assert.Contains(mt, attrs, attribute.String("db.name", "test-database")) for _, v := range tc.validators { - assert.True(t, v(s)) + assert.True(mt, v(s)) } }) } } func TestDBCollectionAttribute(t *testing.T) { + t.Parallel() + tt := []struct { title string operation func(context.Context, *mongo.Database) (interface{}, error) @@ -205,7 +201,12 @@ func TestDBCollectionAttribute(t *testing.T) { }, } for _, tc := range tt { - t.Run(tc.title, func(t *testing.T) { + tc := tc + + mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock)) + mt.Run(tc.title, func(mt *mtest.T) { + mt.Parallel() + sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) @@ -222,50 +223,35 @@ func TestDBCollectionAttribute(t *testing.T) { ) opts.ApplyURI(addr) - mock := newMockDeployment() - - // nolint:staticcheck - // - // Deployment is not part of the stable API guarantee of the - // mongo-go-driver and is therefore marked as deprecated. - // - // See https://jira.mongodb.org/browse/GODRIVER-3241 for a long-term solution. - opts.Deployment = mock - - client, err := mongo.Connect(ctx, opts) - if err != nil { - t.Fatal(err) - } - - mock.addResponses(tc.mockResponses...) - t.Cleanup(mock.clearResponses) + mt.ResetClient(opts) + mt.AddMockResponses(tc.mockResponses...) - _, err = tc.operation(ctx, client.Database("test-database")) + _, err := tc.operation(ctx, mt.Client.Database("test-database")) if err != nil { - t.Error(err) + mt.Error(err) } span.End() spans := sr.Ended() - if !assert.Len(t, spans, 2, "expected 2 spans, received %d", len(spans)) { - t.FailNow() + if !assert.Len(mt, spans, 2, "expected 2 spans, received %d", len(spans)) { + mt.FailNow() } - assert.Len(t, spans, 2) - assert.Equal(t, spans[0].SpanContext().TraceID(), spans[1].SpanContext().TraceID()) - assert.Equal(t, spans[0].Parent().SpanID(), spans[1].SpanContext().SpanID()) - assert.Equal(t, span.SpanContext().SpanID(), spans[1].SpanContext().SpanID()) + assert.Len(mt, spans, 2) + assert.Equal(mt, spans[0].SpanContext().TraceID(), spans[1].SpanContext().TraceID()) + assert.Equal(mt, spans[0].Parent().SpanID(), spans[1].SpanContext().SpanID()) + assert.Equal(mt, span.SpanContext().SpanID(), spans[1].SpanContext().SpanID()) s := spans[0] - assert.Equal(t, trace.SpanKindClient, s.SpanKind()) + assert.Equal(mt, trace.SpanKindClient, s.SpanKind()) attrs := s.Attributes() - assert.Contains(t, attrs, attribute.String("db.system", "mongodb")) - assert.Contains(t, attrs, attribute.String("net.peer.name", "")) - assert.Contains(t, attrs, attribute.Int64("net.peer.port", int64(27017))) - assert.Contains(t, attrs, attribute.String("net.transport", "ip_tcp")) - assert.Contains(t, attrs, attribute.String("db.name", "test-database")) + assert.Contains(mt, attrs, attribute.String("db.system", "mongodb")) + assert.Contains(mt, attrs, attribute.String("net.peer.name", "")) + assert.Contains(mt, attrs, attribute.Int64("net.peer.port", int64(27017))) + assert.Contains(mt, attrs, attribute.String("net.transport", "ip_tcp")) + assert.Contains(mt, attrs, attribute.String("db.name", "test-database")) for _, v := range tc.validators { - assert.True(t, v(s)) + assert.True(mt, v(s)) } }) } diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go deleted file mode 100644 index 6510f816e4c..00000000000 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/opmsg_deployment.go +++ /dev/null @@ -1,237 +0,0 @@ -// Copied from https://github.com/mongodb/mongo-go-driver/blob/d46f29c34e9ff3968a5c00dcdea8fb41a20a2b2f/mongo/integration/mtest/opmsg_deployment.go - -// Copyright (C) MongoDB, Inc. 2017-present. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - -package test // import "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test" - -import ( - "context" - "errors" - "time" - - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo/address" - "go.mongodb.org/mongo-driver/mongo/description" - "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" - "go.mongodb.org/mongo-driver/x/mongo/driver" - "go.mongodb.org/mongo-driver/x/mongo/driver/topology" - "go.mongodb.org/mongo-driver/x/mongo/driver/wiremessage" -) - -const ( - serverAddress = address.Address("127.0.0.1:27017") - maxDocumentSize uint32 = 16777216 - maxMessageSize uint32 = 48000000 - maxBatchCount uint32 = 100000 -) - -var ( - sessionTimeoutMinutes uint32 = 30 - sessionTimeoutMinutesInt64 = int64(sessionTimeoutMinutes) - - // MockDescription is the server description used for the mock deployment. Each mocked connection returns this - // value from its Description method. - MockDescription = description.Server{ - CanonicalAddr: serverAddress, - MaxDocumentSize: maxDocumentSize, - MaxMessageSize: maxMessageSize, - MaxBatchCount: maxBatchCount, - // TODO(GODRIVER-2885): This can be removed once legacy - // SessionTimeoutMinutes is removed. - SessionTimeoutMinutes: sessionTimeoutMinutes, - SessionTimeoutMinutesPtr: &sessionTimeoutMinutesInt64, - Kind: description.RSPrimary, - WireVersion: &description.VersionRange{ - Max: topology.SupportedWireVersions.Max, - }, - } -) - -// connection implements the driver.Connection interface and responds to wire messages with pre-configured responses. -type connection struct { - responses []bson.D // responses to send when ReadWireMessage is called -} - -var _ driver.Connection = &connection{} - -// WriteWireMessage is a no-op. -func (c *connection) WriteWireMessage(context.Context, []byte) error { - return nil -} - -// ReadWireMessage returns the next response in the connection's list of responses. -func (c *connection) ReadWireMessage(_ context.Context) ([]byte, error) { - var dst []byte - if len(c.responses) == 0 { - return dst, errors.New("no responses remaining") - } - nextRes := c.responses[0] - c.responses = c.responses[1:] - - var wmindex int32 - wmindex, dst = wiremessage.AppendHeaderStart(dst, wiremessage.NextRequestID(), 0, wiremessage.OpMsg) - dst = wiremessage.AppendMsgFlags(dst, 0) - dst = wiremessage.AppendMsgSectionType(dst, wiremessage.SingleDocument) - resBytes, _ := bson.Marshal(nextRes) - dst = append(dst, resBytes...) - dst = bsoncore.UpdateLength(dst, wmindex, int32(len(dst[wmindex:]))) - return dst, nil -} - -// Description returns a fixed server description for the connection. -func (c *connection) Description() description.Server { - return MockDescription -} - -// Close is a no-op operation. -func (*connection) Close() error { - return nil -} - -// ID returns a fixed identifier for the connection. -func (*connection) ID() string { - return "" -} - -// DriverConnectionID returns a fixed identifier for the driver pool connection. -// TODO(GODRIVER-2824): replace return type with int64. -func (*connection) DriverConnectionID() uint64 { - return 0 -} - -// ServerConnectionID returns a fixed identifier for the server connection. -func (*connection) ServerConnectionID() *int64 { - serverConnectionID := int64(42) - return &serverConnectionID -} - -// Address returns a fixed address for the connection. -func (*connection) Address() address.Address { - return serverAddress -} - -// Stale returns if the connection is stale. -func (*connection) Stale() bool { - return false -} - -// mockDeployment wraps a connection and implements the driver.Deployment interface. -type mockDeployment struct { - conn *connection - updates chan description.Topology -} - -var ( - _ driver.Deployment = &mockDeployment{} - _ driver.Server = &mockDeployment{} - _ driver.Connector = &mockDeployment{} - _ driver.Disconnector = &mockDeployment{} - _ driver.Subscriber = &mockDeployment{} -) - -// SelectServer implements the Deployment interface. This method does not use the -// description.SelectedServer provided and instead returns itself. The Connections returned from the -// Connection method have a no-op Close method. -func (md *mockDeployment) SelectServer(context.Context, description.ServerSelector) (driver.Server, error) { - return md, nil -} - -// Kind implements the Deployment interface. It always returns description.Single. -func (md *mockDeployment) Kind() description.TopologyKind { - return description.Single -} - -// Connection implements the driver.Server interface. -func (md *mockDeployment) Connection(context.Context) (driver.Connection, error) { - return md.conn, nil -} - -// ZeroRTTMonitor implements the RTTMonitor interface and is used internally for testing. It returns 0 for all -// RTT calculations and an empty string for RTT statistics. -type ZeroRTTMonitor struct{} - -var _ driver.RTTMonitor = &ZeroRTTMonitor{} - -// EWMA implements the RTT monitor interface. -func (zrm *ZeroRTTMonitor) EWMA() time.Duration { - return 0 -} - -// Min implements the RTT monitor interface. -func (zrm *ZeroRTTMonitor) Min() time.Duration { - return 0 -} - -// P90 implements the RTT monitor interface. -func (zrm *ZeroRTTMonitor) P90() time.Duration { - return 0 -} - -// Stats implements the RTT monitor interface. -func (zrm *ZeroRTTMonitor) Stats() string { - return "" -} - -// RTTMonitor implements the driver.Server interface. -func (md *mockDeployment) RTTMonitor() driver.RTTMonitor { - return &ZeroRTTMonitor{} -} - -// Connect is a no-op method which implements the driver.Connector interface. -func (md *mockDeployment) Connect() error { - return nil -} - -// Disconnect is a no-op method which implements the driver.Disconnector interface {. -func (md *mockDeployment) Disconnect(context.Context) error { - close(md.updates) - return nil -} - -// Subscribe returns a subscription from which new topology descriptions can be retrieved. -// Subscribe implements the driver.Subscriber interface. -func (md *mockDeployment) Subscribe() (*driver.Subscription, error) { - if md.updates == nil { - md.updates = make(chan description.Topology, 1) - - md.updates <- description.Topology{ - SessionTimeoutMinutesPtr: &sessionTimeoutMinutesInt64, - - // TODO(GODRIVER-2885): This can be removed once legacy - // SessionTimeoutMinutes is removed. - SessionTimeoutMinutes: sessionTimeoutMinutes, - } - } - - return &driver.Subscription{ - Updates: md.updates, - }, nil -} - -// Unsubscribe is a no-op method which implements the driver.Subscriber interface. -func (md *mockDeployment) Unsubscribe(*driver.Subscription) error { - return nil -} - -// addResponses adds responses to this mock deployment. -func (md *mockDeployment) addResponses(responses ...bson.D) { - md.conn.responses = append(md.conn.responses, responses...) -} - -// clearResponses clears all remaining responses in this mock deployment. -func (md *mockDeployment) clearResponses() { - md.conn.responses = md.conn.responses[:0] -} - -// newMockDeployment returns a mock driver.Deployment that responds with OP_MSG wire messages. -func newMockDeployment(responses ...bson.D) *mockDeployment { - return &mockDeployment{ - conn: &connection{ - responses: responses, - }, - } -} From f30710d9a6de55d7ac8c3eea04955afa7df2f3b0 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Tue, 30 Jul 2024 12:42:42 -0600 Subject: [PATCH 11/15] Revert changes to license-check Makefile --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 72c404a9d2e..0155d9f0d2f 100644 --- a/Makefile +++ b/Makefile @@ -188,7 +188,8 @@ lint: go-mod-tidy golangci-lint misspell govulncheck .PHONY: license-check license-check: - @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path './vendor/*' ! -path './exporters/otlp/internal/opentelemetry-proto/*') ; do \ + @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*' ! -path './.git/*' ) ; do \ + awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \ done); \ if [ -n "$${licRes}" ]; then \ echo "license header checking failed:"; echo "$${licRes}"; \ From 167b222cd171b854518ab1d0f2295acbfcd68054 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Tue, 30 Jul 2024 12:49:35 -0600 Subject: [PATCH 12/15] Revert changes to license-check Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1e610e00716..db1e210e98b 100644 --- a/Makefile +++ b/Makefile @@ -188,7 +188,7 @@ lint: go-mod-tidy golangci-lint misspell govulncheck .PHONY: license-check license-check: - @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*' ! -path './.git/*' ) ; do \ + @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path './vendor/*' ! -path './exporters/otlp/internal/opentelemetry-proto/*') ; do \ awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \ done); \ if [ -n "$${licRes}" ]; then \ From 1c01674c04c7dfe91be2ebf9a8a14ba482384dc2 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Tue, 27 Aug 2024 08:47:48 -0600 Subject: [PATCH 13/15] #39 Revert changes to ci --- .github/workflows/ci.yml | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4bcc5f2a83a..9b9a4ac5819 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -138,3 +138,48 @@ jobs: run: | echo ${{ needs.compatibility-test.result }} test ${{ needs.compatibility-test.result }} == "success" + + integration: + strategy: + matrix: + target: [test-mongo-driver] + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.DEFAULT_GO_VERSION }} + check-latest: true + cache-dependency-path: "**/go.sum" + - name: Run coverage tests ${{ matrix.target }} + env: + INTEGRATION: ${{ matrix.target }} + run: | + make ${{ matrix.target }} + mkdir -p $TEST_RESULTS + find . -name 'coverage.html' > "${TEST_RESULTS}/coverage.lst" + tar -n -cf - -T "${TEST_RESULTS}/coverage.lst" | tar -C "${TEST_RESULTS}" -xvf - + - name: Upload coverage report + uses: codecov/codecov-action@v4.5.0 + if: hashFiles('coverage.out') != '' + with: + file: ./coverage.out + fail_ci_if_error: true + verbose: true + token: ${{ secrets.CODECOV_TOKEN }} + - name: Store coverage test output + uses: actions/upload-artifact@v4 + with: + name: opentelemetry-go-contrib-integration-test-output + path: ${{ env.TEST_RESULTS }} + + test-integration: + runs-on: ubuntu-latest + needs: [integration] + steps: + - name: Test if integration workflow passed + run: | + echo ${{ needs.integration.result }} + test ${{ needs.integration.result }} == "success" From 9b43a52b41003d155a9443ad0bd112c142117ada Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Thu, 29 Aug 2024 12:02:45 -0600 Subject: [PATCH 14/15] #39 re-add removing ci integration --- .github/workflows/ci.yml | 44 ---------------------------------------- 1 file changed, 44 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b9a4ac5819..46f990ff15c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,47 +139,3 @@ jobs: echo ${{ needs.compatibility-test.result }} test ${{ needs.compatibility-test.result }} == "success" - integration: - strategy: - matrix: - target: [test-mongo-driver] - runs-on: ubuntu-latest - steps: - - name: Checkout Repo - uses: actions/checkout@v4 - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: ${{ env.DEFAULT_GO_VERSION }} - check-latest: true - cache-dependency-path: "**/go.sum" - - name: Run coverage tests ${{ matrix.target }} - env: - INTEGRATION: ${{ matrix.target }} - run: | - make ${{ matrix.target }} - mkdir -p $TEST_RESULTS - find . -name 'coverage.html' > "${TEST_RESULTS}/coverage.lst" - tar -n -cf - -T "${TEST_RESULTS}/coverage.lst" | tar -C "${TEST_RESULTS}" -xvf - - - name: Upload coverage report - uses: codecov/codecov-action@v4.5.0 - if: hashFiles('coverage.out') != '' - with: - file: ./coverage.out - fail_ci_if_error: true - verbose: true - token: ${{ secrets.CODECOV_TOKEN }} - - name: Store coverage test output - uses: actions/upload-artifact@v4 - with: - name: opentelemetry-go-contrib-integration-test-output - path: ${{ env.TEST_RESULTS }} - - test-integration: - runs-on: ubuntu-latest - needs: [integration] - steps: - - name: Test if integration workflow passed - run: | - echo ${{ needs.integration.result }} - test ${{ needs.integration.result }} == "success" From bafa299213cc2f76929745325503b0b2f03c1d43 Mon Sep 17 00:00:00 2001 From: Preston Vasquez Date: Mon, 9 Sep 2024 09:19:45 -0600 Subject: [PATCH 15/15] otelmongo#39 Reomve parallel tests --- .../mongo-driver/mongo/otelmongo/test/go.mod | 2 +- .../mongo-driver/mongo/otelmongo/test/mongo_test.go | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod index 45735eeba40..b287d8b08de 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/go.mod @@ -5,7 +5,7 @@ go 1.22 require ( github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.16.1 - go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.54.0 + go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.0.0-00010101000000-000000000000 go.opentelemetry.io/otel v1.29.0 go.opentelemetry.io/otel/sdk v1.29.0 go.opentelemetry.io/otel/trace v1.29.0 diff --git a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go index 10413393a21..4b0f62b932b 100644 --- a/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go +++ b/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo/test/mongo_test.go @@ -14,7 +14,7 @@ import ( "go.mongodb.org/mongo-driver/mongo/integration/mtest" "go.mongodb.org/mongo-driver/mongo/options" - "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" // nolint:staticcheck // deprecated. + "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" @@ -25,8 +25,6 @@ import ( type validator func(sdktrace.ReadOnlySpan) bool func TestDBCrudOperation(t *testing.T) { - t.Parallel() - commonValidators := []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "test-collection.insert", s.Name(), "expected %s", s.Name()) @@ -94,8 +92,6 @@ func TestDBCrudOperation(t *testing.T) { mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock)) mt.Run(title, func(mt *mtest.T) { - mt.Parallel() - sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) @@ -147,8 +143,6 @@ func TestDBCrudOperation(t *testing.T) { } func TestDBCollectionAttribute(t *testing.T) { - t.Parallel() - tt := []struct { title string operation func(context.Context, *mongo.Database) (interface{}, error) @@ -205,8 +199,6 @@ func TestDBCollectionAttribute(t *testing.T) { mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock)) mt.Run(tc.title, func(mt *mtest.T) { - mt.Parallel() - sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr))