Skip to content

Commit

Permalink
Merge branch 'master' into watson/eslint-require-await
Browse files Browse the repository at this point in the history
  • Loading branch information
watson authored Feb 18, 2025
2 parents b995d26 + e6ea5fd commit d78565a
Show file tree
Hide file tree
Showing 72 changed files with 2,484 additions and 382 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ services:
ports:
- "127.0.0.1:6379:6379"
mongo:
image: circleci/mongo:3.6
image: circleci/mongo:4.4
platform: linux/amd64
ports:
- "127.0.0.1:27017:27017"
Expand Down
3 changes: 2 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ export default [
'**/versions', // This is effectively a node_modules tree.
'**/acmeair-nodejs', // We don't own this.
'**/vendor', // Generally, we didn't author this code.
'integration-tests/debugger/target-app/source-map-support/minify.min.js', // Generated
'integration-tests/debugger/target-app/source-map-support/typescript.js', // Generated
'integration-tests/esbuild/out.js', // Generated
'integration-tests/esbuild/aws-sdk-out.js', // Generated
'packages/dd-trace/src/appsec/blocked_templates.js', // TODO Why is this ignored?
'packages/dd-trace/src/payload-tagging/jsonpath-plus.js' // Vendored
]
},
Expand Down
47 changes: 44 additions & 3 deletions integration-tests/ci-visibility-intake.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,43 @@ const DEFAULT_SETTINGS = {
code_coverage: true,
tests_skipping: true,
itr_enabled: true,
require_git: false,
early_flake_detection: {
enabled: false,
slow_test_retries: {
'5s': 3
}
},
flaky_test_retries_enabled: false,
di_enabled: false,
known_tests_enabled: false,
test_management: {
enabled: false
}
}

const DEFAULT_SUITES_TO_SKIP = []
const DEFAULT_GIT_UPLOAD_STATUS = 200
const DEFAULT_KNOWN_TESTS_UPLOAD_STATUS = 200
const DEFAULT_KNOWN_TESTS_RESPONSE_STATUS = 200
const DEFAULT_INFO_RESPONSE = {
endpoints: ['/evp_proxy/v2', '/debugger/v1/input']
}
const DEFAULT_CORRELATION_ID = '1234'
const DEFAULT_KNOWN_TESTS = ['test-suite1.js.test-name1', 'test-suite2.js.test-name2']

const DEFAULT_QUARANTINED_TESTS = {}
const DEFAULT_QUARANTINED_TESTS_RESPONSE_STATUS = 200

let settings = DEFAULT_SETTINGS
let suitesToSkip = DEFAULT_SUITES_TO_SKIP
let gitUploadStatus = DEFAULT_GIT_UPLOAD_STATUS
let infoResponse = DEFAULT_INFO_RESPONSE
let correlationId = DEFAULT_CORRELATION_ID
let knownTests = DEFAULT_KNOWN_TESTS
let knownTestsStatusCode = DEFAULT_KNOWN_TESTS_UPLOAD_STATUS
let knownTestsStatusCode = DEFAULT_KNOWN_TESTS_RESPONSE_STATUS
let waitingTime = 0
let quarantineResponse = DEFAULT_QUARANTINED_TESTS
let quarantineResponseStatusCode = DEFAULT_QUARANTINED_TESTS_RESPONSE_STATUS

class FakeCiVisIntake extends FakeAgent {
setKnownTestsResponseCode (statusCode) {
Expand Down Expand Up @@ -71,6 +83,14 @@ class FakeCiVisIntake extends FakeAgent {
waitingTime = newWaitingTime
}

setQuarantinedTests (newQuarantinedTests) {
quarantineResponse = newQuarantinedTests
}

setQuarantinedTestsResponseCode (newStatusCode) {
quarantineResponseStatusCode = newStatusCode
}

async start () {
const app = express()
app.use(bodyParser.raw({ limit: Infinity, type: 'application/msgpack' }))
Expand Down Expand Up @@ -219,6 +239,25 @@ class FakeCiVisIntake extends FakeAgent {
})
})

app.post([
'/api/v2/test/libraries/test-management/tests',
'/evp_proxy/:version/api/v2/test/libraries/test-management/tests'
], (req, res) => {
res.setHeader('content-type', 'application/json')
const data = JSON.stringify({
data: {
attributes: {
modules: quarantineResponse
}
}
})
res.status(quarantineResponseStatusCode).send(data)
this.emit('message', {
headers: req.headers,
url: req.url
})
})

return new Promise((resolve, reject) => {
const timeoutObj = setTimeout(() => {
reject(new Error('Intake timed out starting up'))
Expand All @@ -237,8 +276,10 @@ class FakeCiVisIntake extends FakeAgent {
settings = DEFAULT_SETTINGS
suitesToSkip = DEFAULT_SUITES_TO_SKIP
gitUploadStatus = DEFAULT_GIT_UPLOAD_STATUS
knownTestsStatusCode = DEFAULT_KNOWN_TESTS_UPLOAD_STATUS
knownTestsStatusCode = DEFAULT_KNOWN_TESTS_RESPONSE_STATUS
infoResponse = DEFAULT_INFO_RESPONSE
quarantineResponseStatusCode = DEFAULT_QUARANTINED_TESTS_RESPONSE_STATUS
quarantineResponse = DEFAULT_QUARANTINED_TESTS
this.removeAllListeners()
if (this.waitingTimeoutId) {
clearTimeout(this.waitingTimeoutId)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Feature: Quarantine
Scenario: Say quarantine
When the greeter says quarantine
Then I should have heard "quarantine"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const assert = require('assert')
const { When, Then } = require('@cucumber/cucumber')

Then('I should have heard {string}', function (expectedResponse) {
assert.equal(this.whatIHeard, 'fail')
})

When('the greeter says quarantine', function () {
this.whatIHeard = 'quarantine'
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const { test, expect } = require('@playwright/test')

test.beforeEach(async ({ page }) => {
await page.goto(process.env.PW_BASE_URL)
})

test.describe('quarantine', () => {
test('should quarantine failed test', async ({ page }) => {
await expect(page.locator('.hello-world')).toHaveText([
'Hello Warld'
])
})
})
11 changes: 11 additions & 0 deletions integration-tests/ci-visibility/quarantine/test-quarantine-1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { expect } = require('chai')

describe('quarantine tests', () => {
it('can quarantine a test', () => {
expect(1 + 2).to.equal(4)
})

it('can pass normally', () => {
expect(1 + 2).to.equal(3)
})
})
11 changes: 11 additions & 0 deletions integration-tests/ci-visibility/quarantine/test-quarantine-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { expect } = require('chai')

describe('quarantine tests 2', () => {
it('can quarantine a test', () => {
expect(1 + 2).to.equal(3)
})

it('can pass normally', () => {
expect(1 + 2).to.equal(3)
})
})
6 changes: 5 additions & 1 deletion integration-tests/ci-visibility/run-jest.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@ if (process.env.COLLECT_COVERAGE_FROM) {
jest.runCLI(
options,
options.projects
).then(() => {
).then((results) => {
if (process.send) {
process.send('finished')
}
if (process.env.SHOULD_CHECK_RESULTS) {
const exitCode = results.results.success ? 0 : 1
process.exit(exitCode)
}
})
7 changes: 5 additions & 2 deletions integration-tests/ci-visibility/run-mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ if (process.env.TESTS_TO_RUN) {
mocha.addFile(require.resolve('./test/ci-visibility-test.js'))
mocha.addFile(require.resolve('./test/ci-visibility-test-2.js'))
}
mocha.run(() => {
mocha.run((failures) => {
if (process.send) {
process.send('finished')
}
}).on('end', () => {
if (process.env.SHOULD_CHECK_RESULTS && failures > 0) {
process.exit(1)
}
}).on('end', (res) => {
// eslint-disable-next-line
console.log('end event: can add event listeners to mocha')
})
11 changes: 11 additions & 0 deletions integration-tests/ci-visibility/vitest-tests/test-quarantine.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { describe, test, expect } from 'vitest'

describe('quarantine tests', () => {
test('can quarantine a test', () => {
expect(1 + 2).to.equal(4)
})

test('can pass normally', () => {
expect(1 + 2).to.equal(3)
})
})
115 changes: 100 additions & 15 deletions integration-tests/cucumber/cucumber.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ const {
DI_DEBUG_ERROR_SNAPSHOT_ID_SUFFIX,
DI_DEBUG_ERROR_LINE_SUFFIX,
TEST_RETRY_REASON,
DD_TEST_IS_USER_PROVIDED_SERVICE
DD_TEST_IS_USER_PROVIDED_SERVICE,
TEST_MANAGEMENT_ENABLED,
TEST_MANAGEMENT_IS_QUARANTINED
} = require('../../packages/dd-trace/src/plugins/util/test')
const { DD_HOST_CPU_COUNT } = require('../../packages/dd-trace/src/plugins/util/env')

Expand Down Expand Up @@ -1585,7 +1587,7 @@ versions.forEach(version => {
})
// Dynamic instrumentation only supported from >=8.0.0
context('dynamic instrumentation', () => {
it('does not activate if DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED is not set', (done) => {
it('does not activate if DD_TEST_FAILED_TEST_REPLAY_ENABLED is set to false', (done) => {
receiver.setSettings({
flaky_test_retries_enabled: true,
di_enabled: true
Expand Down Expand Up @@ -1619,7 +1621,10 @@ versions.forEach(version => {
'./node_modules/.bin/cucumber-js ci-visibility/features-di/test-hit-breakpoint.feature --retry 1',
{
cwd,
env: envVars,
env: {
...envVars,
DD_TEST_FAILED_TEST_REPLAY_ENABLED: 'false'
},
stdio: 'pipe'
}
)
Expand Down Expand Up @@ -1664,10 +1669,7 @@ versions.forEach(version => {
'./node_modules/.bin/cucumber-js ci-visibility/features-di/test-hit-breakpoint.feature --retry 1',
{
cwd,
env: {
...envVars,
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
},
env: envVars,
stdio: 'pipe'
}
)
Expand Down Expand Up @@ -1746,10 +1748,7 @@ versions.forEach(version => {
'./node_modules/.bin/cucumber-js ci-visibility/features-di/test-hit-breakpoint.feature --retry 1',
{
cwd,
env: {
...envVars,
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
},
env: envVars,
stdio: 'pipe'
}
)
Expand Down Expand Up @@ -1798,10 +1797,7 @@ versions.forEach(version => {
'./node_modules/.bin/cucumber-js ci-visibility/features-di/test-not-hit-breakpoint.feature --retry 1',
{
cwd,
env: {
...envVars,
DD_TEST_DYNAMIC_INSTRUMENTATION_ENABLED: 'true'
},
env: envVars,
stdio: 'pipe'
}
)
Expand Down Expand Up @@ -2029,5 +2025,94 @@ versions.forEach(version => {
}).catch(done)
})
})

context('quarantine', () => {
beforeEach(() => {
receiver.setQuarantinedTests({
cucumber: {
suites: {
'ci-visibility/features-quarantine/quarantine.feature': {
tests: {
'Say quarantine': {
properties: {
quarantined: true
}
}
}
}
}
}
})
})

const getTestAssertions = (isQuarantining) =>
receiver
.gatherPayloadsMaxTimeout(({ url }) => url.endsWith('/api/v2/citestcycle'), (payloads) => {
const events = payloads.flatMap(({ payload }) => payload.events)
const failedTest = events.find(event => event.type === 'test').content
const testSession = events.find(event => event.type === 'test_session_end').content

if (isQuarantining) {
assert.propertyVal(testSession.meta, TEST_MANAGEMENT_ENABLED, 'true')
} else {
assert.notProperty(testSession.meta, TEST_MANAGEMENT_ENABLED)
}

assert.equal(failedTest.resource, 'ci-visibility/features-quarantine/quarantine.feature.Say quarantine')

assert.equal(failedTest.meta[TEST_STATUS], 'fail')
if (isQuarantining) {
assert.propertyVal(failedTest.meta, TEST_MANAGEMENT_IS_QUARANTINED, 'true')
} else {
assert.notProperty(failedTest.meta, TEST_MANAGEMENT_IS_QUARANTINED)
}
})

const runTest = (done, isQuarantining, extraEnvVars) => {
const testAssertionsPromise = getTestAssertions(isQuarantining)

childProcess = exec(
'./node_modules/.bin/cucumber-js ci-visibility/features-quarantine/*.feature',
{
cwd,
env: {
...getCiVisAgentlessConfig(receiver.port),
...extraEnvVars
},
stdio: 'inherit'
}
)

childProcess.on('exit', exitCode => {
testAssertionsPromise.then(() => {
if (isQuarantining) {
// even though a test fails, the exit code is 1 because the test is quarantined
assert.equal(exitCode, 0)
} else {
assert.equal(exitCode, 1)
}
done()
}).catch(done)
})
}

it('can quarantine tests', (done) => {
receiver.setSettings({ test_management: { enabled: true } })

runTest(done, true)
})

it('fails if quarantine is not enabled', (done) => {
receiver.setSettings({ test_management: { enabled: false } })

runTest(done, false)
})

it('does not enable quarantine tests if DD_TEST_MANAGEMENT_ENABLED is set to false', (done) => {
receiver.setSettings({ test_management: { enabled: true } })

runTest(done, false, { DD_TEST_MANAGEMENT_ENABLED: '0' })
})
})
})
})
5 changes: 4 additions & 1 deletion integration-tests/cypress-esm-config.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import cypress from 'cypress'

async function runCypress () {
await cypress.run({
const results = await cypress.run({
config: {
defaultCommandTimeout: 1000,
e2e: {
Expand Down Expand Up @@ -39,6 +39,9 @@ async function runCypress () {
screenshotOnRunFailure: false
}
})
if (results.totalFailed !== 0) {
process.exit(1)
}
}

runCypress()
Loading

0 comments on commit d78565a

Please sign in to comment.