Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[test optimization] Fix ATR + DI issues with jest #5136

Merged
merged 3 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
/* eslint-disable */
const sum = require('./dependency')
const isJest = require('./is-jest')
const { expect } = require('chai')

// TODO: instead of retrying through jest, this should be retried with auto test retries
if (isJest()) {
jest.retryTimes(1)
}

let count = 0
describe('dynamic-instrumentation', () => {
it('retries with DI', function () {
if (this.retries) {
this.retries(1)
if (process.env.TEST_SHOULD_PASS_AFTER_RETRY && count++ === 1) {
// Passes after a retry if TEST_SHOULD_PASS_AFTER_RETRY is passed
expect(sum(1, 3)).to.equal(4)
} else {
expect(sum(11, 3)).to.equal(14)
}
expect(sum(11, 3)).to.equal(14)
})

it('is not retried', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
/* eslint-disable */
const sum = require('./dependency')
const isJest = require('./is-jest')
const { expect } = require('chai')

// TODO: instead of retrying through jest, this should be retried with auto test retries
if (isJest()) {
jest.retryTimes(1)
}

let count = 0
describe('dynamic-instrumentation', () => {
it('retries with DI', function () {
if (this.retries) {
this.retries(1)
}
const willFail = count++ === 0
if (willFail) {
expect(sum(11, 3)).to.equal(14) // only throws the first time
Expand Down
53 changes: 48 additions & 5 deletions integration-tests/jest/jest.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ describe('jest CommonJS', () => {
const retriedTests = tests.filter(test => test.meta[TEST_IS_RETRY] === 'true')

assert.equal(retriedTests.length, 2)
const [retriedTest] = retriedTests
const retriedTest = retriedTests.find(test => test.meta[TEST_SUITE].includes('test-hit-breakpoint.js'))

assert.propertyVal(retriedTest.meta, DI_ERROR_DEBUG_INFO_CAPTURED, 'true')

Expand Down Expand Up @@ -560,6 +560,7 @@ describe('jest CommonJS', () => {
...getCiVisAgentlessConfig(receiver.port),
TESTS_TO_RUN: 'dynamic-instrumentation/test-',
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1',
RUN_IN_PARALLEL: true
},
stdio: 'inherit'
Expand Down Expand Up @@ -2518,7 +2519,8 @@ describe('jest CommonJS', () => {
cwd,
env: {
...getCiVisAgentlessConfig(receiver.port),
TESTS_TO_RUN: 'dynamic-instrumentation/test-hit-breakpoint'
TESTS_TO_RUN: 'dynamic-instrumentation/test-hit-breakpoint',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1'
},
stdio: 'inherit'
}
Expand Down Expand Up @@ -2565,7 +2567,8 @@ describe('jest CommonJS', () => {
env: {
...getCiVisAgentlessConfig(receiver.port),
TESTS_TO_RUN: 'dynamic-instrumentation/test-hit-breakpoint',
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1'
},
stdio: 'inherit'
}
Expand Down Expand Up @@ -2649,7 +2652,8 @@ describe('jest CommonJS', () => {
env: {
...getCiVisAgentlessConfig(receiver.port),
TESTS_TO_RUN: 'dynamic-instrumentation/test-hit-breakpoint',
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1'
},
stdio: 'inherit'
}
Expand Down Expand Up @@ -2698,7 +2702,8 @@ describe('jest CommonJS', () => {
env: {
...getCiVisAgentlessConfig(receiver.port),
TESTS_TO_RUN: 'dynamic-instrumentation/test-not-hit-breakpoint',
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1'
},
stdio: 'inherit'
}
Expand All @@ -2711,6 +2716,44 @@ describe('jest CommonJS', () => {
}).catch(done)
})
})

it('does not wait for breakpoint for a passed test', (done) => {
receiver.setSettings({
flaky_test_retries_enabled: true,
di_enabled: true
})

const eventsPromise = receiver
.gatherPayloadsMaxTimeout(({ url }) => url.endsWith('/api/v2/citestcycle'), (payloads) => {
const events = payloads.flatMap(({ payload }) => payload.events)

const tests = events.filter(event => event.type === 'test').map(event => event.content)
const retriedTests = tests.filter(test => test.meta[TEST_IS_RETRY] === 'true')

assert.equal(retriedTests.length, 1)
const [retriedTest] = retriedTests
// Duration is in nanoseconds, so 200 * 1e6 is 200ms
assert.equal(retriedTest.duration < 200 * 1e6, true)
})

childProcess = exec(runTestsWithCoverageCommand,
{
cwd,
env: {
...getCiVisAgentlessConfig(receiver.port),
TESTS_TO_RUN: 'dynamic-instrumentation/test-hit-breakpoint',
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1',
TEST_SHOULD_PASS_AFTER_RETRY: '1'
},
stdio: 'inherit'
}
)

childProcess.on('exit', () => {
eventsPromise.then(() => done()).catch(done)
})
})
})

// This happens when using office-addin-mock
Expand Down
12 changes: 8 additions & 4 deletions integration-tests/mocha/mocha.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2188,7 +2188,8 @@ describe('mocha CommonJS', function () {
...getCiVisAgentlessConfig(receiver.port),
TESTS_TO_RUN: JSON.stringify([
'./dynamic-instrumentation/test-hit-breakpoint'
])
]),
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1'
},
stdio: 'inherit'
}
Expand Down Expand Up @@ -2240,7 +2241,8 @@ describe('mocha CommonJS', function () {
TESTS_TO_RUN: JSON.stringify([
'./dynamic-instrumentation/test-hit-breakpoint'
]),
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1'
},
stdio: 'inherit'
}
Expand Down Expand Up @@ -2329,7 +2331,8 @@ describe('mocha CommonJS', function () {
TESTS_TO_RUN: JSON.stringify([
'./dynamic-instrumentation/test-hit-breakpoint'
]),
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1'
},
stdio: 'inherit'
}
Expand Down Expand Up @@ -2382,7 +2385,8 @@ describe('mocha CommonJS', function () {
TESTS_TO_RUN: JSON.stringify([
'./dynamic-instrumentation/test-not-hit-breakpoint'
]),
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true',
DD_CIVISIBILITY_FLAKY_RETRY_COUNT: '1'
},
stdio: 'inherit'
}
Expand Down
4 changes: 2 additions & 2 deletions packages/datadog-instrumentations/src/jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
const numRetries = this.global[RETRY_TIMES]
const numTestExecutions = event.test?.invocations
const willBeRetried = numRetries > 0 && numTestExecutions - 1 < numRetries
const mightHitBreakpoint = this.isDiEnabled && numTestExecutions >= 1
const mightHitBreakpoint = this.isDiEnabled && numTestExecutions >= 2

const asyncResource = asyncResources.get(event.test)

Expand All @@ -319,7 +319,7 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {

// After finishing it might take a bit for the snapshot to be handled.
// This means that tests retried with DI are BREAKPOINT_HIT_GRACE_PERIOD_MS slower at least.
if (mightHitBreakpoint) {
if (status === 'fail' && mightHitBreakpoint) {
await new Promise(resolve => {
setTimeout(() => {
resolve()
Expand Down
10 changes: 4 additions & 6 deletions packages/dd-trace/src/plugins/util/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -691,14 +691,12 @@ function getFileAndLineNumberFromError (error, repositoryRoot) {
return []
}

// The error.stack property in TestingLibraryElementError includes the message, which results in redundant information
function getFormattedError (error, repositoryRoot) {
if (error.name !== 'TestingLibraryElementError') {
return error
}
const { stack } = error
const newError = new Error(error.message)
newError.stack = stack.split('\n').filter(line => line.includes(repositoryRoot)).join('\n')
if (error.stack) {
newError.stack = error.stack.split('\n').filter(line => line.includes(repositoryRoot)).join('\n')
}
newError.name = error.name

return newError
}
Loading