Skip to content

Commit 36290ba

Browse files
committed
Add support for Mocha (no parallel mode)
1 parent d394f54 commit 36290ba

File tree

5 files changed

+283
-44
lines changed

5 files changed

+283
-44
lines changed

integration-tests/mocha/mocha.spec.js

+144-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ const {
4848
TEST_MANAGEMENT_IS_DISABLED,
4949
DD_CAPABILITIES_TEST_IMPACT_ANALYSIS,
5050
DD_CAPABILITIES_EARLY_FLAKE_DETECTION,
51-
DD_CAPABILITIES_AUTO_TEST_RETRIES
51+
DD_CAPABILITIES_AUTO_TEST_RETRIES,
52+
TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX,
53+
TEST_HAS_FAILED_ALL_RETRIES
5254
} = require('../../packages/dd-trace/src/plugins/util/test')
5355
const { DD_HOST_CPU_COUNT } = require('../../packages/dd-trace/src/plugins/util/env')
5456
const { ERROR_MESSAGE } = require('../../packages/dd-trace/src/constants')
@@ -2566,6 +2568,147 @@ describe('mocha CommonJS', function () {
25662568
})
25672569

25682570
context('test management', () => {
2571+
context('attempt to fix', () => {
2572+
beforeEach(() => {
2573+
receiver.setTestManagementTests({
2574+
mocha: {
2575+
suites: {
2576+
'ci-visibility/test-management/test-attempt-to-fix-1.js': {
2577+
tests: {
2578+
'attempt to fix tests can attempt to fix a test': {
2579+
properties: {
2580+
attempt_to_fix: true
2581+
}
2582+
}
2583+
}
2584+
}
2585+
}
2586+
}
2587+
})
2588+
})
2589+
2590+
const getTestAssertions = (isAttemptToFix) =>
2591+
receiver
2592+
.gatherPayloadsMaxTimeout(({ url }) => url.endsWith('/api/v2/citestcycle'), (payloads) => {
2593+
const events = payloads.flatMap(({ payload }) => payload.events)
2594+
const tests = events.filter(event => event.type === 'test').map(event => event.content)
2595+
const testSession = events.find(event => event.type === 'test_session_end').content
2596+
2597+
if (isAttemptToFix) {
2598+
assert.propertyVal(testSession.meta, TEST_MANAGEMENT_ENABLED, 'true')
2599+
} else {
2600+
assert.notProperty(testSession.meta, TEST_MANAGEMENT_ENABLED)
2601+
}
2602+
2603+
const resourceNames = tests.map(span => span.resource)
2604+
2605+
assert.includeMembers(resourceNames,
2606+
[
2607+
'ci-visibility/test-management/test-attempt-to-fix-1.js.attempt to fix tests can attempt to fix a test'
2608+
]
2609+
)
2610+
2611+
const retriedTests = tests.filter(
2612+
test => test.meta[TEST_NAME] === 'attempt to fix tests can attempt to fix a test'
2613+
)
2614+
2615+
for (let i = 0; i < retriedTests.length; i++) {
2616+
const test = retriedTests[i]
2617+
if (isAttemptToFix && i !== 0) {
2618+
assert.propertyVal(test.meta, TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX, 'true')
2619+
assert.propertyVal(test.meta, TEST_IS_RETRY, 'true')
2620+
assert.propertyVal(test.meta, TEST_RETRY_REASON, 'attempt_to_fix')
2621+
} else {
2622+
assert.notProperty(test.meta, TEST_MANAGEMENT_IS_ATTEMPT_TO_FIX)
2623+
assert.notProperty(test.meta, TEST_IS_RETRY)
2624+
assert.notProperty(test.meta, TEST_RETRY_REASON)
2625+
}
2626+
2627+
if (isAttemptToFix && i === retriedTests.length - 1) {
2628+
assert.propertyVal(test.meta, TEST_HAS_FAILED_ALL_RETRIES, 'true')
2629+
}
2630+
}
2631+
})
2632+
2633+
const runAttemptToFixTest = (done, isAttemptToFix, isQuarantined, extraEnvVars = {}) => {
2634+
let stdout = ''
2635+
const testAssertionsPromise = getTestAssertions(isAttemptToFix)
2636+
2637+
childProcess = exec(
2638+
runTestsWithCoverageCommand,
2639+
{
2640+
cwd,
2641+
env: {
2642+
...getCiVisAgentlessConfig(receiver.port),
2643+
TESTS_TO_RUN: JSON.stringify([
2644+
'./test-management/test-attempt-to-fix-1.js'
2645+
]),
2646+
SHOULD_CHECK_RESULTS: '1',
2647+
...extraEnvVars
2648+
},
2649+
stdio: 'inherit'
2650+
}
2651+
)
2652+
2653+
childProcess.stdout.on('data', (data) => {
2654+
stdout += data
2655+
})
2656+
2657+
childProcess.on('exit', exitCode => {
2658+
testAssertionsPromise.then(() => {
2659+
assert.include(stdout, 'I am running when attempt to fix')
2660+
if (isAttemptToFix && isQuarantined) {
2661+
// even though a test fails, the exit code is 0 because the test is quarantined
2662+
assert.equal(exitCode, 0)
2663+
} else {
2664+
assert.equal(exitCode, 1)
2665+
}
2666+
done()
2667+
}).catch(done)
2668+
})
2669+
}
2670+
2671+
it('can attempt to fix tests', (done) => {
2672+
receiver.setSettings({ test_management: { enabled: true, attempt_to_fix_retries: 3 } })
2673+
2674+
runAttemptToFixTest(done, true, false)
2675+
})
2676+
2677+
it('does not attempt to fix tests if test management is not enabled', (done) => {
2678+
receiver.setSettings({ test_management: { enabled: false, attempt_to_fix_retries: 3 } })
2679+
2680+
runAttemptToFixTest(done, false, false)
2681+
})
2682+
2683+
it('does not enable attempt to fix tests if DD_TEST_MANAGEMENT_ENABLED is set to false', (done) => {
2684+
receiver.setSettings({ test_management: { enabled: true, attempt_to_fix_retries: 3 } })
2685+
2686+
runAttemptToFixTest(done, false, false, { DD_TEST_MANAGEMENT_ENABLED: '0' })
2687+
})
2688+
2689+
it('does not fail retry if a test is quarantined', (done) => {
2690+
receiver.setSettings({ test_management: { enabled: true, attempt_to_fix_retries: 3 } })
2691+
receiver.setTestManagementTests({
2692+
mocha: {
2693+
suites: {
2694+
'ci-visibility/test-management/test-attempt-to-fix-1.js': {
2695+
tests: {
2696+
'attempt to fix tests can attempt to fix a test': {
2697+
properties: {
2698+
attempt_to_fix: true,
2699+
quarantined: true
2700+
}
2701+
}
2702+
}
2703+
}
2704+
}
2705+
}
2706+
})
2707+
2708+
runAttemptToFixTest(done, true, true)
2709+
})
2710+
})
2711+
25692712
context('disabled', () => {
25702713
beforeEach(() => {
25712714
receiver.setTestManagementTests({

packages/datadog-instrumentations/src/mocha/main.js

+30-9
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ const {
3030
newTests,
3131
testsQuarantined,
3232
getTestFullName,
33-
getRunTestsWrapper
33+
getRunTestsWrapper,
34+
testsAttemptToFix,
35+
testsStatuses
3436
} = require('./utils')
3537

3638
require('./common')
@@ -138,16 +140,26 @@ function getOnEndHandler (isParallel) {
138140
}
139141
}
140142

143+
// We substract the errors of attempt to fix tests (quarantined or disabled) from the total number of failures
141144
// We subtract the errors from quarantined tests from the total number of failures
142145
if (config.isTestManagementTestsEnabled) {
143146
let numFailedQuarantinedTests = 0
147+
let numFailedRetriedQuarantinedOrDisabledTests = 0
148+
for (const test of testsAttemptToFix) {
149+
const testName = getTestFullName(test, true, false)
150+
const testProperties = getTestProperties(test, config.testManagementTests)
151+
if (isTestFailed(test) && (testProperties.isQuarantined || testProperties.isDisabled)) {
152+
const failedTests = testsStatuses.get(testName).filter(status => status === 'fail')
153+
numFailedRetriedQuarantinedOrDisabledTests += failedTests.length
154+
}
155+
}
144156
for (const test of testsQuarantined) {
145157
if (isTestFailed(test)) {
146158
numFailedQuarantinedTests++
147159
}
148160
}
149-
this.stats.failures -= numFailedQuarantinedTests
150-
this.failures -= numFailedQuarantinedTests
161+
this.stats.failures -= numFailedQuarantinedTests + numFailedRetriedQuarantinedOrDisabledTests
162+
this.failures -= numFailedQuarantinedTests + numFailedRetriedQuarantinedOrDisabledTests
151163
}
152164

153165
if (status === 'fail') {
@@ -193,6 +205,7 @@ function getExecutionConfiguration (runner, isParallel, onFinishRequest) {
193205
if (err) {
194206
config.testManagementTests = {}
195207
config.isTestManagementTestsEnabled = false
208+
config.testManagementAttemptToFixRetries = 0
196209
} else {
197210
config.testManagementTests = receivedTestManagementTests
198211
}
@@ -260,6 +273,7 @@ function getExecutionConfiguration (runner, isParallel, onFinishRequest) {
260273
config.earlyFlakeDetectionFaultyThreshold = libraryConfig.earlyFlakeDetectionFaultyThreshold
261274
config.isKnownTestsEnabled = libraryConfig.isKnownTestsEnabled
262275
config.isTestManagementTestsEnabled = libraryConfig.isTestManagementEnabled
276+
config.testManagementAttemptToFixRetries = libraryConfig.testManagementAttemptToFixRetries
263277
// ITR and auto test retries are not supported in parallel mode yet
264278
config.isSuitesSkippingEnabled = !isParallel && libraryConfig.isSuitesSkippingEnabled
265279
config.isFlakyTestRetriesEnabled = !isParallel && libraryConfig.isFlakyTestRetriesEnabled
@@ -637,6 +651,7 @@ addHook({
637651
if (config.isTestManagementTestsEnabled) {
638652
const testSuiteTestManagementTests = config.testManagementTests?.mocha?.suites?.[testPath] || {}
639653
newWorkerArgs._ddIsTestManagementTestsEnabled = true
654+
newWorkerArgs._ddTestManagementAttemptToFixRetries = config.testManagementAttemptToFixRetries
640655
newWorkerArgs._ddTestManagementTests = {
641656
mocha: {
642657
suites: {
@@ -661,9 +676,19 @@ addHook({
661676
.map(event => event.data)
662677

663678
for (const test of tests) {
679+
const testProperties = getTestProperties(test, config.testManagementTests)
680+
if (config.isTestManagementTestsEnabled) {
681+
// `testsAttemptToFix` is filled in the worker process, so we need to use the test results to fill it here too.
682+
// `testsQuarantined` is filled in the worker process, so we need to use the test results to fill it here too.
683+
if (testProperties.isAttemptToFix) {
684+
testsAttemptToFix.add(test)
685+
} else if (testProperties.isQuarantined) {
686+
testsQuarantined.add(test)
687+
}
688+
}
664689
// `newTests` is filled in the worker process, so we need to use the test results to fill it here too.
665-
if (config.isKnownTestsEnabled && isNewTest(test, config.knownTests)) {
666-
const testFullName = getTestFullName(test)
690+
if (config.isKnownTestsEnabled && isNewTest(test, config.knownTests) && !testProperties.isAttemptToFix) {
691+
const testFullName = getTestFullName(test, false, true)
667692
const tests = newTests[testFullName]
668693

669694
if (!tests) {
@@ -672,10 +697,6 @@ addHook({
672697
tests.push(test)
673698
}
674699
}
675-
// `testsQuarantined` is filled in the worker process, so we need to use the test results to fill it here too.
676-
if (config.isTestManagementTestsEnabled && getTestProperties(test, config.testManagementTests).isQuarantined) {
677-
testsQuarantined.add(test)
678-
}
679700
}
680701
return testFileResult
681702
})

0 commit comments

Comments
 (0)