diff --git a/integration-tests/ci-visibility.spec.js b/integration-tests/ci-visibility.spec.js index cdf21678085..de46a825481 100644 --- a/integration-tests/ci-visibility.spec.js +++ b/integration-tests/ci-visibility.spec.js @@ -17,6 +17,8 @@ const { FakeCiVisIntake } = require('./ci-visibility-intake') const { TEST_SESSION_CODE_COVERAGE_ENABLED, TEST_SESSION_ITR_SKIPPING_ENABLED, + TEST_MODULE_CODE_COVERAGE_ENABLED, + TEST_MODULE_ITR_SKIPPING_ENABLED, TEST_ITR_TESTS_SKIPPED } = require('../packages/dd-trace/src/plugins/util/test') @@ -227,7 +229,7 @@ testFrameworks.forEach(({ assert.propertyVal(packfileRequest.headers, 'dd-api-key', '1') const eventTypes = eventsRequest.payload.events.map(event => event.type) - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -276,7 +278,7 @@ testFrameworks.forEach(({ assert.exists(coveragePayload.content.coverages[0].test_suite_id) const eventTypes = eventsRequest.payload.events.map(event => event.type) - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -307,11 +309,15 @@ testFrameworks.forEach(({ receiver.assertPayloadReceived(({ headers, payload }) => { assert.propertyVal(headers, 'dd-api-key', '1') const eventTypes = payload.events.map(event => event.type) - assert.includeMembers(eventTypes, ['test', 'test_session_end', 'test_suite_end']) + assert.includeMembers(eventTypes, ['test', 'test_session_end', 'test_module_end', 'test_suite_end']) const testSession = payload.events.find(event => event.type === 'test_session_end').content assert.propertyVal(testSession.meta, TEST_ITR_TESTS_SKIPPED, 'false') assert.propertyVal(testSession.meta, TEST_SESSION_CODE_COVERAGE_ENABLED, 'false') assert.propertyVal(testSession.meta, TEST_SESSION_ITR_SKIPPING_ENABLED, 'false') + const testModule = payload.events.find(event => event.type === 'test_module_end').content + assert.propertyVal(testModule.meta, TEST_ITR_TESTS_SKIPPED, 'false') + assert.propertyVal(testModule.meta, TEST_MODULE_CODE_COVERAGE_ENABLED, 'false') + assert.propertyVal(testModule.meta, TEST_MODULE_ITR_SKIPPING_ENABLED, 'false') }, ({ url }) => url === '/api/v2/citestcycle').then(() => done()).catch(done) childProcess = exec( @@ -354,7 +360,7 @@ testFrameworks.forEach(({ event.content.resource === 'ci-visibility/test/ci-visibility-test.js.ci visibility can report tests' ) assert.notExists(skippedTest) - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -363,6 +369,10 @@ testFrameworks.forEach(({ assert.propertyVal(testSession.meta, TEST_ITR_TESTS_SKIPPED, 'true') assert.propertyVal(testSession.meta, TEST_SESSION_CODE_COVERAGE_ENABLED, 'true') assert.propertyVal(testSession.meta, TEST_SESSION_ITR_SKIPPING_ENABLED, 'true') + const testModule = eventsRequest.payload.events.find(event => event.type === 'test_module_end').content + assert.propertyVal(testModule.meta, TEST_ITR_TESTS_SKIPPED, 'true') + assert.propertyVal(testModule.meta, TEST_MODULE_CODE_COVERAGE_ENABLED, 'true') + assert.propertyVal(testModule.meta, TEST_MODULE_ITR_SKIPPING_ENABLED, 'true') done() }).catch(done) @@ -394,7 +404,7 @@ testFrameworks.forEach(({ assert.propertyVal(headers, 'dd-api-key', '1') const eventTypes = payload.events.map(event => event.type) // because they are not skipped - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -403,6 +413,10 @@ testFrameworks.forEach(({ assert.propertyVal(testSession.meta, TEST_ITR_TESTS_SKIPPED, 'false') assert.propertyVal(testSession.meta, TEST_SESSION_CODE_COVERAGE_ENABLED, 'true') assert.propertyVal(testSession.meta, TEST_SESSION_ITR_SKIPPING_ENABLED, 'true') + const testModule = payload.events.find(event => event.type === 'test_module_end').content + assert.propertyVal(testModule.meta, TEST_ITR_TESTS_SKIPPED, 'false') + assert.propertyVal(testModule.meta, TEST_MODULE_CODE_COVERAGE_ENABLED, 'true') + assert.propertyVal(testModule.meta, TEST_MODULE_ITR_SKIPPING_ENABLED, 'true') }, ({ url }) => url === '/api/v2/citestcycle').then(() => done()).catch(done) childProcess = exec( @@ -436,7 +450,7 @@ testFrameworks.forEach(({ assert.propertyVal(headers, 'dd-api-key', '1') const eventTypes = payload.events.map(event => event.type) // because they are not skipped - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -520,7 +534,7 @@ testFrameworks.forEach(({ assert.propertyVal(packfileRequest.headers, 'x-datadog-evp-subdomain', 'api') const eventTypes = eventsRequest.payload.events.map(event => event.type) - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -570,7 +584,7 @@ testFrameworks.forEach(({ assert.exists(coveragePayload.content.coverages[0].test_suite_id) const eventTypes = eventsRequest.payload.events.map(event => event.type) - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -602,7 +616,7 @@ testFrameworks.forEach(({ assert.notProperty(headers, 'dd-api-key') assert.propertyVal(headers, 'x-datadog-evp-subdomain', 'citestcycle-intake') const eventTypes = payload.events.map(event => event.type) - assert.includeMembers(eventTypes, ['test', 'test_session_end', 'test_suite_end']) + assert.includeMembers(eventTypes, ['test', 'test_session_end', 'test_module_end', 'test_suite_end']) }, ({ url }) => url === '/evp_proxy/v2/api/v2/citestcycle').then(() => done()).catch(done) childProcess = exec( @@ -651,7 +665,7 @@ testFrameworks.forEach(({ event.content.resource === 'ci-visibility/test/ci-visibility-test.js.ci visibility can report tests' ) assert.notExists(skippedTest) - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -679,7 +693,7 @@ testFrameworks.forEach(({ assert.propertyVal(headers, 'x-datadog-evp-subdomain', 'citestcycle-intake') const eventTypes = payload.events.map(event => event.type) // because they are not skipped - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) @@ -715,7 +729,7 @@ testFrameworks.forEach(({ assert.propertyVal(headers, 'x-datadog-evp-subdomain', 'citestcycle-intake') const eventTypes = payload.events.map(event => event.type) // because they are not skipped - assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_session_end']) + assert.includeMembers(eventTypes, ['test', 'test_suite_end', 'test_module_end', 'test_session_end']) const numSuites = eventTypes.reduce( (acc, type) => type === 'test_suite_end' ? acc + 1 : acc, 0 ) diff --git a/packages/datadog-plugin-jest/src/index.js b/packages/datadog-plugin-jest/src/index.js index b43149c5b11..331623ab27f 100644 --- a/packages/datadog-plugin-jest/src/index.js +++ b/packages/datadog-plugin-jest/src/index.js @@ -10,16 +10,13 @@ const { getTestSessionCommonTags, getTestModuleCommonTags, getTestSuiteCommonTags, + addIntelligentTestRunnerSpanTags, TEST_PARAMETERS, getCodeOwnersFileEntries, TEST_SESSION_ID, TEST_MODULE_ID, TEST_SUITE_ID, TEST_COMMAND, - TEST_ITR_TESTS_SKIPPED, - TEST_SESSION_CODE_COVERAGE_ENABLED, - TEST_SESSION_ITR_SKIPPING_ENABLED, - TEST_CODE_COVERAGE_LINES_TOTAL, TEST_BUNDLE } = require('../../dd-trace/src/plugins/util/test') const { COMPONENT } = require('../../dd-trace/src/constants') @@ -83,14 +80,14 @@ class JestPlugin extends CiPlugin { testCodeCoverageLinesTotal }) => { this.testSessionSpan.setTag(TEST_STATUS, status) - this.testSessionSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false') - this.testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false') - this.testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false') - - if (testCodeCoverageLinesTotal !== undefined) { - this.testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal) - } this.testModuleSpan.setTag(TEST_STATUS, status) + + addIntelligentTestRunnerSpanTags( + this.testSessionSpan, + this.testModuleSpan, + { isSuitesSkipped, isSuitesSkippingEnabled, isCodeCoverageEnabled, testCodeCoverageLinesTotal } + ) + this.testModuleSpan.finish() this.testSessionSpan.finish() finishAllTraceSpans(this.testSessionSpan) diff --git a/packages/datadog-plugin-jest/test/circus.spec.js b/packages/datadog-plugin-jest/test/circus.spec.js index cf67a13c236..e19cd1dc5af 100644 --- a/packages/datadog-plugin-jest/test/circus.spec.js +++ b/packages/datadog-plugin-jest/test/circus.spec.js @@ -23,7 +23,8 @@ const { TEST_COMMAND, TEST_SUITE_ID, TEST_SESSION_ID, - TEST_MODULE_ID + TEST_MODULE_ID, + TEST_BUNDLE } = require('../../dd-trace/src/plugins/util/test') const { version: ddTraceVersion } = require('../../../package.json') @@ -324,11 +325,6 @@ describe('Plugin', function () { status: 'pass', spanResourceMatch: /^test_session/ }, - { - type: 'test_module_end', - status: 'pass', - spanResourceMatch: /^test_module/ - }, { type: 'test_suite_end', status: 'pass', @@ -356,21 +352,21 @@ describe('Plugin', function () { const span = events.find(event => event.type === type).content expect(span.meta[TEST_STATUS]).to.equal(status) expect(span.meta[COMPONENT]).to.equal('jest') - if (type === 'test_session_end') { + if (type === 'test_session_end') { // session and module come in the same payload expect(span.meta[TEST_COMMAND]).not.to.equal(undefined) expect(span[TEST_SUITE_ID]).to.equal(undefined) expect(span[TEST_MODULE_ID]).to.equal(undefined) expect(span[TEST_SESSION_ID]).not.to.equal(undefined) - } - if (type === 'test_module_id') { - expect(span.meta[TEST_COMMAND]).not.to.equal(undefined) - expect(span[TEST_SUITE_ID]).to.equal(undefined) - expect(span[TEST_SESSION_ID]).not.to.equal(undefined) - expect(span[TEST_MODULE_ID]).not.to.equal(undefined) + const testModuleSpan = events.find(event => event.type === 'test_module_end').content + expect(testModuleSpan[TEST_SUITE_ID]).to.equal(undefined) + expect(testModuleSpan[TEST_MODULE_ID]).not.to.equal(undefined) + expect(testModuleSpan[TEST_SESSION_ID]).not.to.equal(undefined) + expect(testModuleSpan.meta[TEST_BUNDLE]).not.to.equal(undefined) } if (type === 'test_suite_end') { expect(span.meta[TEST_SUITE]).to.equal(suite) expect(span.meta[TEST_COMMAND]).not.to.equal(undefined) + expect(span.meta[TEST_BUNDLE]).not.to.equal(undefined) expect(span[TEST_SUITE_ID]).not.to.equal(undefined) expect(span[TEST_SESSION_ID]).not.to.equal(undefined) expect(span[TEST_MODULE_ID]).not.to.equal(undefined) @@ -379,6 +375,7 @@ describe('Plugin', function () { expect(span.meta[TEST_SUITE]).to.equal(suite) expect(span.meta[TEST_NAME]).to.equal(name) expect(span.meta[TEST_COMMAND]).not.to.equal(undefined) + expect(span.meta[TEST_BUNDLE]).not.to.equal(undefined) expect(span[TEST_SUITE_ID]).not.to.equal(undefined) expect(span[TEST_SESSION_ID]).not.to.equal(undefined) expect(span[TEST_MODULE_ID]).not.to.equal(undefined) diff --git a/packages/datadog-plugin-mocha/src/index.js b/packages/datadog-plugin-mocha/src/index.js index c07249d27ac..e69a7eeea10 100644 --- a/packages/datadog-plugin-mocha/src/index.js +++ b/packages/datadog-plugin-mocha/src/index.js @@ -13,14 +13,12 @@ const { getTestSessionCommonTags, getTestModuleCommonTags, getTestSuiteCommonTags, + addIntelligentTestRunnerSpanTags, TEST_SUITE_ID, TEST_SESSION_ID, TEST_MODULE_ID, TEST_BUNDLE, - TEST_COMMAND, - TEST_ITR_TESTS_SKIPPED, - TEST_SESSION_CODE_COVERAGE_ENABLED, - TEST_SESSION_ITR_SKIPPING_ENABLED + TEST_COMMAND } = require('../../dd-trace/src/plugins/util/test') const { COMPONENT } = require('../../dd-trace/src/constants') @@ -156,11 +154,14 @@ class MochaPlugin extends CiPlugin { if (this.testSessionSpan) { const { isSuitesSkippingEnabled, isCodeCoverageEnabled } = this.itrConfig || {} this.testSessionSpan.setTag(TEST_STATUS, status) - this.testSessionSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false') - this.testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false') - this.testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false') - this.testModuleSpan.setTag(TEST_STATUS, status) + + addIntelligentTestRunnerSpanTags( + this.testSessionSpan, + this.testModuleSpan, + { isSuitesSkipped, isSuitesSkippingEnabled, isCodeCoverageEnabled } + ) + this.testModuleSpan.finish() this.testSessionSpan.finish() finishAllTraceSpans(this.testSessionSpan) diff --git a/packages/dd-trace/src/plugins/util/test.js b/packages/dd-trace/src/plugins/util/test.js index 2e6af0ba56d..45ee493dfb1 100644 --- a/packages/dd-trace/src/plugins/util/test.js +++ b/packages/dd-trace/src/plugins/util/test.js @@ -50,6 +50,8 @@ const JEST_TEST_RUNNER = 'test.jest.test_runner' const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped' const TEST_SESSION_ITR_SKIPPING_ENABLED = 'test_session.itr.tests_skipping.enabled' const TEST_SESSION_CODE_COVERAGE_ENABLED = 'test_session.code_coverage.enabled' +const TEST_MODULE_ITR_SKIPPING_ENABLED = 'test_module.itr.tests_skipping.enabled' +const TEST_MODULE_CODE_COVERAGE_ENABLED = 'test_module.code_coverage.enabled' const TEST_CODE_COVERAGE_LINES_TOTAL = 'test.codecov_lines_total' @@ -84,9 +86,13 @@ module.exports = { TEST_MODULE_ID, TEST_SUITE_ID, TEST_ITR_TESTS_SKIPPED, + TEST_BUNDLE, TEST_SESSION_ITR_SKIPPING_ENABLED, TEST_SESSION_CODE_COVERAGE_ENABLED, + TEST_MODULE_ITR_SKIPPING_ENABLED, + TEST_MODULE_CODE_COVERAGE_ENABLED, TEST_CODE_COVERAGE_LINES_TOTAL, + addIntelligentTestRunnerSpanTags, getCoveredFilenamesFromCoverage, resetCoverage, mergeCoverage, @@ -282,6 +288,26 @@ function getTestSuiteCommonTags (command, testFrameworkVersion, testSuite) { } } +function addIntelligentTestRunnerSpanTags ( + testSessionSpan, + testModuleSpan, + { isSuitesSkipped, isSuitesSkippingEnabled, isCodeCoverageEnabled, testCodeCoverageLinesTotal } +) { + testSessionSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false') + testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false') + testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false') + + testModuleSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false') + testModuleSpan.setTag(TEST_MODULE_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false') + testModuleSpan.setTag(TEST_MODULE_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false') + + // If suites have been skipped we don't want to report the total coverage, as it will be wrong + if (testCodeCoverageLinesTotal !== undefined && !isSuitesSkipped) { + testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal) + testModuleSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal) + } +} + function getCoveredFilenamesFromCoverage (coverage) { const coverageMap = istanbul.createCoverageMap(coverage)