1import * as _ from 'lodash-es' 14// build is possible when the configured builder is usable: 15// - docker/podman: local daemon responds to `info` 16// - kanikojob: builds run in-cluster, so a cluster context suffices (the job surfaces infra failures) 17const isBuildCapable = async () => { 20 return (await do2ExecFile({cmdA: [dockName, 'info']})).isSuccess 23// quick reachability probe so the build test skips gracefully where the registry isn't accessible 24// (200 and 401 both mean the registry answered; 401 just means it wants auth) 25const isRegReachable = async (host: string) => { 27 const resp = await fetch(`https://${host}/v2/`, {signal: AbortSignal.timeout(3000)}) 28 return resp.status === 200 || resp.status === 401 29 } catch { return false } 32// independently derive the registry manifest URL for a repo_name_tag — must match the push target 33// (registryPool[0]), not getDockerPushHost, so the check queries where the image was actually pushed 34const deriveManifestUrl = (repo_name_tag: string) => { 40export const runDockImgCacheSuite: SuiteRunner = async ({ptenv}) => { 41 if (ptenv !== ptenvLocal) return skipSuite('dockimgcache only runs with --ptenv=testlocal') 44 name: 'dockimgcache.pureFns: manifest url parse + format + digest', 47 {input: 'reg.io/repo:tag', expected: {repoPath: 'repo', tag: 'tag'}}, 48 {input: 'reg.io:5000/repo/sub:tag', expected: {repoPath: 'repo/sub', tag: 'tag'}}, 49 {input: 'reg.io/repo@sha256:abc', expected: {repoPath: 'repo', tag: 'sha256:abc'}}, 51 for (const {input, expected} of cases) { 53 if (!_.isEqual(got, expected)) return {passed: false, msg: `${input} -> ${JSON.stringify(got)} (expected ${JSON.stringify(expected)})`} 56 if (mk !== 'https://reg.io/v2/repo/manifests/tag') return {passed: false, msg: `mkManifestUrl mismatch: ${mk}`} 57 return {passed: true, msg: 'parse + format + digest ok'} 62 if (dockreg_host && await isRegReachable(dockreg_host) && await isBuildCapable()) { 63 const suffix = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}` 64 const repo_name_tag = `${dockreg_host}/imgcache-test:${suffix}` 65 // embed suffix in the Dockerfile so df_sha (and thus the kaniko job name) is unique per run; 66 // otherwise kaniko reuses a succeeded job from a prior run that pushed a different tag 67 const dockerfileContent = `# run=${suffix}\nFROM alpine` 70 name: 'dockimgcache.customTagBuildReuse: build+push then reuse at custom tag', 72 const r1 = await dockerBuildPush({repo_name_tag, dockerfileContent, dockreg_host, cluster_name, reqDockPush: true, action: 'apply', name: 'imgcache-test'}) 73 if (r1?.imageReused) return {passed: false, msg: `first build reported imageReused on a fresh tag ${repo_name_tag}`} 75 if (!exists) return {passed: false, msg: `doesDockImg2Exist=false after build (checked wrong tag?) ${repo_name_tag}`} 76 const manifest_url = deriveManifestUrl(repo_name_tag) 78 if (!health.exists) return {passed: false, msg: `image not reachable at tag after push: ${health.reason} ${manifest_url}`} 79 const r2 = await dockerBuildPush({repo_name_tag, dockerfileContent, dockreg_host, cluster_name, reqDockPush: true, action: 'apply', name: 'imgcache-test'}) 80 if (!r2?.imageReused) return {passed: false, msg: `second build did not reuse (cache check queried wrong tag?) ${repo_name_tag}`} 81 const cleanup = await deleteDockImgByTag({manifest_url}).catch((e: unknown) => ({deleted: false, reason: (e as Error).message})) 82 const cleanupMsg = cleanup.deleted ? ' (cleaned up)' : ` (cleanup: ${cleanup.reason})` 83 return {passed: true, msg: `built+pushed then reused ${repo_name_tag}${cleanupMsg}`} 91export const dockImgCacheSuiteConfig: SuiteConfig = {name: 'dockimgcache', runner: runDockImgCacheSuite, deps: [] as const}