Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
c343038
[test optimization] Add filesystem cache for known tests requests
juan-fernandez Apr 2, 2026
ed4d57b
Merge master and resolve conflict with cursor-based pagination
juan-fernandez Apr 2, 2026
9ed42cf
fix: clean up stale lock in waitForCache and fix 5xx test retries
juan-fernandez Apr 2, 2026
9fd4b99
fix: add lock heartbeat to prevent false stale detection during slow …
juan-fernandez Apr 2, 2026
f803109
fix: disable known tests cache in integration tests
juan-fernandez Apr 6, 2026
a03acc5
refactor: make known tests cache opt-in via DD_EXPERIMENTAL_TEST_OPT_…
juan-fernandez Apr 6, 2026
e671856
refactor: extract shared fs-cache module, add caching to all test req…
juan-fernandez Apr 6, 2026
23774b5
fix: move DD_EXPERIMENTAL_TEST_REQUESTS_FS_CACHE to correct alphabeti…
juan-fernandez Apr 6, 2026
7b4a706
fix: use isTrue() to parse DD_EXPERIMENTAL_TEST_REQUESTS_FS_CACHE
juan-fernandez Apr 6, 2026
9eaf2a2
fix: validate data field in cache before returning hit
juan-fernandez Apr 6, 2026
66fc101
fix: use JSON.stringify for cache key to prevent collisions
juan-fernandez Apr 6, 2026
a1cf7d3
test: add cache tests for skippable suites and test management
juan-fernandez Apr 6, 2026
3c76fbf
fix: remove hard deadline from waitForCache, rely solely on lock stal…
juan-fernandez Apr 6, 2026
6af3852
fix: make touchLock atomic to prevent false stale detection
juan-fernandez Apr 6, 2026
7a9ac74
chore: remove unused mergeKnownTests export and revert helper changes
juan-fernandez Apr 6, 2026
f2c09cc
fix implementation
juan-fernandez Apr 6, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,17 @@ const {
} = require('../../ci-visibility/telemetry')

const { getNumFromKnownTests } = require('../../plugins/util/test')
const { buildCacheKey, writeToCache, withCache } = require('../requests/fs-cache')

const MAX_KNOWN_TESTS_PAGES = 10_000

/**
* Deep-merges page tests into aggregate.
* Structure: { module: { suite: [testName, ...] } }
*
* @param {object | null} aggregate
* @param {object | null} page
* @returns {object | null}
*/
function mergeKnownTests (aggregate, page) {
if (!page) return aggregate
Expand Down Expand Up @@ -62,6 +67,71 @@ function getKnownTests ({
runtimeName,
runtimeVersion,
custom,
}, done) {
const cacheKey = buildCacheKey('known-tests', [
sha, service, env, repositoryUrl, osPlatform, osVersion, osArchitecture,
runtimeName, runtimeVersion, custom,
])

withCache(cacheKey, (activeCacheKey, cb) => {
fetchFromApi({
url,
isEvpProxy,
evpProxyPrefix,
isGzipCompatible,
env,
service,
repositoryUrl,
sha,
osVersion,
osPlatform,
osArchitecture,
runtimeName,
runtimeVersion,
custom,
cacheKey: activeCacheKey,
}, cb)
}, done)
}

/**
* Fetches known tests from the API with cursor-based pagination and writes the
* result to cache on success.
*
* @param {object} params
* @param {string} params.url
* @param {boolean} params.isEvpProxy
* @param {string} params.evpProxyPrefix
* @param {boolean} params.isGzipCompatible
* @param {string} params.env
* @param {string} params.service
* @param {string} params.repositoryUrl
* @param {string} params.sha
* @param {string} params.osVersion
* @param {string} params.osPlatform
* @param {string} params.osArchitecture
* @param {string} params.runtimeName
* @param {string} params.runtimeVersion
* @param {object} [params.custom]
* @param {string | null} params.cacheKey
* @param {Function} done
*/
function fetchFromApi ({
url,
isEvpProxy,
evpProxyPrefix,
isGzipCompatible,
env,
service,
repositoryUrl,
sha,
osVersion,
osPlatform,
osArchitecture,
runtimeName,
runtimeVersion,
custom,
cacheKey,
}, done) {
const options = {
path: '/api/v2/ci/libraries/tests',
Expand Down Expand Up @@ -166,7 +236,9 @@ function getKnownTests ({
distributionMetric(TELEMETRY_KNOWN_TESTS_RESPONSE_TESTS, {}, numTests)
distributionMetric(TELEMETRY_KNOWN_TESTS_RESPONSE_BYTES, {}, totalResponseBytes)

log.debug('Number of received known tests:', numTests)
log.debug('Number of received known tests: %d', numTests)

writeToCache(cacheKey, aggregateTests)

done(null, aggregateTests)
} catch (err) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS,
TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES,
} = require('../../ci-visibility/telemetry')
const { buildCacheKey, writeToCache, withCache } = require('../requests/fs-cache')

function getSkippableSuites ({
url,
Expand All @@ -30,6 +31,76 @@ function getSkippableSuites ({
runtimeVersion,
custom,
testLevel = 'suite',
}, done) {
const cacheKey = buildCacheKey('skippable', [
sha, service, env, repositoryUrl, osPlatform, osVersion, osArchitecture,
runtimeName, runtimeVersion, testLevel, custom,
])

withCache(cacheKey, (activeCacheKey, cb) => {
fetchFromApi({
url,
isEvpProxy,
evpProxyPrefix,
isGzipCompatible,
env,
service,
repositoryUrl,
sha,
osVersion,
osPlatform,
osArchitecture,
runtimeName,
runtimeVersion,
custom,
testLevel,
cacheKey: activeCacheKey,
}, cb)
}, (err, data) => {
if (err) return done(err)
done(null, data.skippableSuites, data.correlationId)
})
}

/**
* Fetches skippable suites from the API and writes the result to cache on success.
*
* @param {object} params
* @param {string} params.url
* @param {boolean} params.isEvpProxy
* @param {string} params.evpProxyPrefix
* @param {boolean} params.isGzipCompatible
* @param {string} params.env
* @param {string} params.service
* @param {string} params.repositoryUrl
* @param {string} params.sha
* @param {string} params.osVersion
* @param {string} params.osPlatform
* @param {string} params.osArchitecture
* @param {string} params.runtimeName
* @param {string} params.runtimeVersion
* @param {object} [params.custom]
* @param {string} [params.testLevel]
* @param {string | null} params.cacheKey
* @param {Function} done
*/
function fetchFromApi ({
url,
isEvpProxy,
evpProxyPrefix,
isGzipCompatible,
env,
service,
repositoryUrl,
sha,
osVersion,
osPlatform,
osArchitecture,
runtimeName,
runtimeVersion,
custom,
testLevel,
cacheKey,
}, done) {
const options = {
path: '/api/v2/ci/tests/skippable',
Expand Down Expand Up @@ -109,7 +180,11 @@ function getSkippableSuites ({
)
distributionMetric(TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES, {}, res.length)
log.debug('Number of received skippable %ss:', testLevel, skippableSuites.length)
done(null, skippableSuites, correlationId)

const result = { skippableSuites, correlationId }
writeToCache(cacheKey, result)

done(null, result)
} catch (err) {
done(err)
}
Expand Down
Loading
Loading