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" diff --git a/Makefile b/Makefile index afc4c388c3f..db1e210e98b 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 36abd78d1c7..6fad5c817eb 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,6 @@ go 1.22 require ( github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.17.0 - go.opentelemetry.io/contrib v1.30.0 go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.55.0 go.opentelemetry.io/otel v1.30.0 go.opentelemetry.io/otel/sdk v1.30.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 21b6eaa97e9..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 @@ -5,17 +5,16 @@ package test import ( "context" - "os" "testing" "time" "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" - "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 +22,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 +43,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 +52,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{{{Key: "ok", Value: 1}}}, excludeCommand: false, validators: append(commonValidators, func(s sdktrace.ReadOnlySpan) bool { for _, attr := range s.Attributes() { @@ -72,6 +68,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{{{Key: "ok", Value: 1}}}, excludeCommand: true, validators: append(commonValidators, func(s sdktrace.ReadOnlySpan) bool { for _, attr := range s.Attributes() { @@ -84,13 +81,17 @@ 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) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) @@ -106,37 +107,36 @@ func TestDBCrudOperation(t *testing.T) { otelmongo.WithCommandAttributeDisabled(tc.excludeCommand), ) opts.ApplyURI(addr) - client, err := mongo.Connect(ctx, opts) - if err != nil { - t.Fatal(err) - } - _, err = tc.operation(ctx, client.Database("test-database")) + mt.ResetClient(opts) + mt.AddMockResponses(tc.mockResponses...) + + _, 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", "localhost")) - 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)) } }) } @@ -144,15 +144,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{{{Key: "ok", Value: 1}}}, validators: []validator{ func(s sdktrace.ReadOnlySpan) bool { return assert.Equal(t, "test-collection.delete", s.Name()) @@ -173,6 +175,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{ + { + {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()) @@ -187,7 +195,10 @@ 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) { sr := tracetest.NewSpanRecorder() provider := sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) @@ -203,37 +214,36 @@ func TestDBCollectionAttribute(t *testing.T) { otelmongo.WithCommandAttributeDisabled(true), ) opts.ApplyURI(addr) - client, err := mongo.Connect(ctx, opts) - if err != nil { - t.Fatal(err) - } - _, err = tc.operation(ctx, client.Database("test-database")) + mt.ResetClient(opts) + mt.AddMockResponses(tc.mockResponses...) + + _, 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", "localhost")) - 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/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