diff --git a/internal/civisibility/integrations/gotesting/instrumentation.go b/internal/civisibility/integrations/gotesting/instrumentation.go index 5f0abf98ea..f1eb023683 100644 --- a/internal/civisibility/integrations/gotesting/instrumentation.go +++ b/internal/civisibility/integrations/gotesting/instrumentation.go @@ -114,9 +114,13 @@ func createTestMetadata(tb testing.TB) *testExecutionMetadata { // getTestMetadata retrieves the CI visibility test metadata associated with a given *testing.T, *testing.B, *testing.common func getTestMetadata(tb testing.TB) *testExecutionMetadata { + return getTestMetadataFromPointer(reflect.ValueOf(tb).UnsafePointer()) +} + +// getTestMetadataFromPointer retrieves the CI visibility test metadata associated with a given *testing.T, *testing.B, *testing.common using a pointer +func getTestMetadataFromPointer(ptr unsafe.Pointer) *testExecutionMetadata { ciVisibilityTestMetadataMutex.RLock() defer ciVisibilityTestMetadataMutex.RUnlock() - ptr := reflect.ValueOf(tb).UnsafePointer() if v, ok := ciVisibilityTestMetadata[ptr]; ok { return v } @@ -223,6 +227,20 @@ func instrumentTestingTFunc(f func(*testing.T)) func(*testing.T) { defer deleteTestMetadata(t) } + // Because this is a subtest let's propagate some execution metadata from the parent test + testPrivateFields := getTestPrivateFields(t) + if testPrivateFields.parent != nil { + parentExecMeta := getTestMetadataFromPointer(*testPrivateFields.parent) + if parentExecMeta != nil { + if parentExecMeta.isANewTest { + execMeta.isANewTest = true + } + if parentExecMeta.isARetry { + execMeta.isARetry = true + } + } + } + // Set the CI visibility test. execMeta.test = test diff --git a/internal/civisibility/integrations/gotesting/testcontroller_test.go b/internal/civisibility/integrations/gotesting/testcontroller_test.go index bfcf78c003..380507f78a 100644 --- a/internal/civisibility/integrations/gotesting/testcontroller_test.go +++ b/internal/civisibility/integrations/gotesting/testcontroller_test.go @@ -105,6 +105,8 @@ func runFlakyTestRetriesTests(m *testing.M) { // 1 TestNormalPassingAfterRetryAlwaysFail // 1 TestEarlyFlakeDetection // 2 normal spans from testing_test.go + + // check spans by resource name checkSpansByResourceName(finishedSpans, "gopkg.in/DataDog/dd-trace-go.v1/internal/civisibility/integrations/gotesting", 1) checkSpansByResourceName(finishedSpans, "reflections_test.go", 1) checkSpansByResourceName(finishedSpans, "testing_test.go", 1) @@ -126,6 +128,10 @@ func runFlakyTestRetriesTests(m *testing.M) { checkSpansByResourceName(finishedSpans, "testing_test.go.TestNormalPassingAfterRetryAlwaysFail", 1) checkSpansByResourceName(finishedSpans, "testing_test.go.TestEarlyFlakeDetection", 1) + // check spans by tag + checkSpansByTagName(finishedSpans, constants.TestIsRetry, 16) + + // check spans by type checkSpansByType(finishedSpans, 44, 1, @@ -183,6 +189,8 @@ func runEarlyFlakyTestDetectionTests(m *testing.M) { // 11 TestNormalPassingAfterRetryAlwaysFail // 11 TestEarlyFlakeDetection // 22 normal spans from testing_test.go + + // check spans by resource name checkSpansByResourceName(finishedSpans, "gopkg.in/DataDog/dd-trace-go.v1/internal/civisibility/integrations/gotesting", 1) checkSpansByResourceName(finishedSpans, "reflections_test.go", 1) checkSpansByResourceName(finishedSpans, "testing_test.go", 1) @@ -204,6 +212,11 @@ func runEarlyFlakyTestDetectionTests(m *testing.M) { checkSpansByResourceName(finishedSpans, "testing_test.go.TestNormalPassingAfterRetryAlwaysFail", 11) checkSpansByResourceName(finishedSpans, "testing_test.go.TestEarlyFlakeDetection", 11) + // check spans by tag + checkSpansByTagName(finishedSpans, constants.TestIsNew, 187) + checkSpansByTagName(finishedSpans, constants.TestIsRetry, 170) + + // check spans by type checkSpansByType(finishedSpans, 218, 1, @@ -275,6 +288,8 @@ func runFlakyTestRetriesWithEarlyFlakyTestDetectionTests(m *testing.M) { // 1 TestNormalPassingAfterRetryAlwaysFail // 11 TestEarlyFlakeDetection + 10 retries // 2 normal spans from testing_test.go + + // check spans by resource name checkSpansByResourceName(finishedSpans, "gopkg.in/DataDog/dd-trace-go.v1/internal/civisibility/integrations/gotesting", 1) checkSpansByResourceName(finishedSpans, "reflections_test.go", 1) checkSpansByResourceName(finishedSpans, "testing_test.go", 1) @@ -296,6 +311,11 @@ func runFlakyTestRetriesWithEarlyFlakyTestDetectionTests(m *testing.M) { checkSpansByResourceName(finishedSpans, "testing_test.go.TestNormalPassingAfterRetryAlwaysFail", 1) checkSpansByResourceName(finishedSpans, "testing_test.go.TestEarlyFlakeDetection", 21) + // check spans by tag + checkSpansByTagName(finishedSpans, constants.TestIsNew, 21) + checkSpansByTagName(finishedSpans, constants.TestIsRetry, 36) + + // check spans by type checkSpansByType(finishedSpans, 64, 1, @@ -357,11 +377,24 @@ func checkSpansByType(finishedSpans []mocktracer.Span, } } -func checkSpansByResourceName(finishedSpans []mocktracer.Span, resourceName string, count int) { - numOfSpans := len(getSpansWithResourceName(finishedSpans, resourceName)) +func checkSpansByResourceName(finishedSpans []mocktracer.Span, resourceName string, count int) []mocktracer.Span { + spans := getSpansWithResourceName(finishedSpans, resourceName) + numOfSpans := len(spans) if numOfSpans != count { panic(fmt.Sprintf("expected exactly %d spans with resource name: %s, got %d", count, resourceName, numOfSpans)) } + + return spans +} + +func checkSpansByTagName(finishedSpans []mocktracer.Span, tagName string, count int) []mocktracer.Span { + spans := getSpansWithTagName(finishedSpans, tagName) + numOfSpans := len(spans) + if numOfSpans != count { + panic(fmt.Sprintf("expected exactly %d spans with tag name: %s, got %d", count, tagName, numOfSpans)) + } + + return spans } func setUpHttpServer(flakyRetriesEnabled bool, earlyFlakyDetectionEnabled bool, earlyFlakyDetectionData *net.EfdResponseData) *httptest.Server { @@ -444,6 +477,17 @@ func getSpansWithResourceName(spans []mocktracer.Span, resourceName string) []mo return result } +func getSpansWithTagName(spans []mocktracer.Span, tag string) []mocktracer.Span { + var result []mocktracer.Span + for _, span := range spans { + if span.Tag(tag) != nil { + result = append(result, span) + } + } + + return result +} + func showResourcesNameFromSpans(spans []mocktracer.Span) { for i, span := range spans { fmt.Printf(" [%d] = %v\n", i, span.Tag(ext.ResourceName))