Skip to content

Commit eb47baa

Browse files
authored
Adding more tests and minor changes in code (#21)
* added cleanup job checks, started testing constants file * added getVolumeClaimName test * added write entrypoint tests * added tests around k8s utils * fixed new regexp * added tests around runner instance label * 100% test coverage of constants
1 parent 20c19da commit eb47baa

File tree

5 files changed

+376
-8
lines changed

5 files changed

+376
-8
lines changed

packages/k8s/src/hooks/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ export function getSecretName(): string {
3939
)}-secret-${uuidv4().substring(0, STEP_POD_NAME_SUFFIX_LENGTH)}`
4040
}
4141

42-
const MAX_POD_NAME_LENGTH = 63
43-
const STEP_POD_NAME_SUFFIX_LENGTH = 8
42+
export const MAX_POD_NAME_LENGTH = 63
43+
export const STEP_POD_NAME_SUFFIX_LENGTH = 8
4444
export const JOB_CONTAINER_NAME = 'job'
4545

4646
export class RunnerInstanceLabel {

packages/k8s/src/k8s/utils.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ export function containerVolumes(
2020
}
2121
]
2222

23+
const workspacePath = process.env.GITHUB_WORKSPACE as string
2324
if (containerAction) {
24-
const workspace = process.env.GITHUB_WORKSPACE as string
2525
mounts.push(
2626
{
2727
name: POD_VOLUME_NAME,
2828
mountPath: '/github/workspace',
29-
subPath: workspace.substring(workspace.indexOf('work/') + 1)
29+
subPath: workspacePath.substring(workspacePath.indexOf('work/') + 1)
3030
},
3131
{
3232
name: POD_VOLUME_NAME,
3333
mountPath: '/github/file_commands',
34-
subPath: workspace.substring(workspace.indexOf('work/') + 1)
34+
subPath: workspacePath.substring(workspacePath.indexOf('work/') + 1)
3535
}
3636
)
3737
return mounts
@@ -63,7 +63,6 @@ export function containerVolumes(
6363
return mounts
6464
}
6565

66-
const workspacePath = process.env.GITHUB_WORKSPACE as string
6766
for (const userVolume of userMountVolumes) {
6867
let sourceVolumePath = ''
6968
if (path.isAbsolute(userVolume.sourceVolumePath)) {

packages/k8s/tests/cleanup-job-test.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import * as k8s from '@kubernetes/client-node'
12
import { cleanupJob, prepareJob } from '../src/hooks'
3+
import { RunnerInstanceLabel } from '../src/hooks/constants'
4+
import { namespace } from '../src/k8s'
25
import { TestHelper } from './test-setup'
36

47
let testHelper: TestHelper
@@ -13,10 +16,50 @@ describe('Cleanup Job', () => {
1316
)
1417
await prepareJob(prepareJobData.args, prepareJobOutputFilePath)
1518
})
19+
20+
afterEach(async () => {
21+
await testHelper.cleanup()
22+
})
23+
1624
it('should not throw', async () => {
1725
await expect(cleanupJob()).resolves.not.toThrow()
1826
})
19-
afterEach(async () => {
20-
await testHelper.cleanup()
27+
28+
it('should have no runner linked pods running', async () => {
29+
await cleanupJob()
30+
const kc = new k8s.KubeConfig()
31+
32+
kc.loadFromDefault()
33+
const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
34+
35+
const podList = await k8sApi.listNamespacedPod(
36+
namespace(),
37+
undefined,
38+
undefined,
39+
undefined,
40+
undefined,
41+
new RunnerInstanceLabel().toString()
42+
)
43+
44+
expect(podList.body.items.length).toBe(0)
45+
})
46+
47+
it('should have no runner linked secrets', async () => {
48+
await cleanupJob()
49+
const kc = new k8s.KubeConfig()
50+
51+
kc.loadFromDefault()
52+
const k8sApi = kc.makeApiClient(k8s.CoreV1Api)
53+
54+
const secretList = await k8sApi.listNamespacedSecret(
55+
namespace(),
56+
undefined,
57+
undefined,
58+
undefined,
59+
undefined,
60+
new RunnerInstanceLabel().toString()
61+
)
62+
63+
expect(secretList.body.items.length).toBe(0)
2164
})
2265
})
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import {
2+
getJobPodName,
3+
getRunnerPodName,
4+
getSecretName,
5+
getStepPodName,
6+
getVolumeClaimName,
7+
MAX_POD_NAME_LENGTH,
8+
RunnerInstanceLabel,
9+
STEP_POD_NAME_SUFFIX_LENGTH
10+
} from '../src/hooks/constants'
11+
12+
describe('constants', () => {
13+
describe('runner instance label', () => {
14+
beforeEach(() => {
15+
process.env.ACTIONS_RUNNER_POD_NAME = 'example'
16+
})
17+
it('should throw if ACTIONS_RUNNER_POD_NAME env is not set', () => {
18+
delete process.env.ACTIONS_RUNNER_POD_NAME
19+
expect(() => new RunnerInstanceLabel()).toThrow()
20+
})
21+
22+
it('should have key truthy', () => {
23+
const runnerInstanceLabel = new RunnerInstanceLabel()
24+
expect(typeof runnerInstanceLabel.key).toBe('string')
25+
expect(runnerInstanceLabel.key).toBeTruthy()
26+
expect(runnerInstanceLabel.key.length).toBeGreaterThan(0)
27+
})
28+
29+
it('should have value as runner pod name', () => {
30+
const name = process.env.ACTIONS_RUNNER_POD_NAME as string
31+
const runnerInstanceLabel = new RunnerInstanceLabel()
32+
expect(typeof runnerInstanceLabel.value).toBe('string')
33+
expect(runnerInstanceLabel.value).toBe(name)
34+
})
35+
36+
it('should have toString combination of key and value', () => {
37+
const runnerInstanceLabel = new RunnerInstanceLabel()
38+
expect(runnerInstanceLabel.toString()).toBe(
39+
`${runnerInstanceLabel.key}=${runnerInstanceLabel.value}`
40+
)
41+
})
42+
})
43+
44+
describe('getRunnerPodName', () => {
45+
it('should throw if ACTIONS_RUNNER_POD_NAME env is not set', () => {
46+
delete process.env.ACTIONS_RUNNER_POD_NAME
47+
expect(() => getRunnerPodName()).toThrow()
48+
49+
process.env.ACTIONS_RUNNER_POD_NAME = ''
50+
expect(() => getRunnerPodName()).toThrow()
51+
})
52+
53+
it('should return corrent ACTIONS_RUNNER_POD_NAME name', () => {
54+
const name = 'example'
55+
process.env.ACTIONS_RUNNER_POD_NAME = name
56+
expect(getRunnerPodName()).toBe(name)
57+
})
58+
})
59+
60+
describe('getJobPodName', () => {
61+
it('should throw on getJobPodName if ACTIONS_RUNNER_POD_NAME env is not set', () => {
62+
delete process.env.ACTIONS_RUNNER_POD_NAME
63+
expect(() => getJobPodName()).toThrow()
64+
65+
process.env.ACTIONS_RUNNER_POD_NAME = ''
66+
expect(() => getRunnerPodName()).toThrow()
67+
})
68+
69+
it('should contain suffix -workflow', () => {
70+
const tableTests = [
71+
{
72+
podName: 'test',
73+
expect: 'test-workflow'
74+
},
75+
{
76+
// podName.length == 63
77+
podName:
78+
'abcdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
79+
expect:
80+
'abcdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-workflow'
81+
}
82+
]
83+
84+
for (const tt of tableTests) {
85+
process.env.ACTIONS_RUNNER_POD_NAME = tt.podName
86+
const actual = getJobPodName()
87+
expect(actual).toBe(tt.expect)
88+
}
89+
})
90+
})
91+
92+
describe('getVolumeClaimName', () => {
93+
it('should throw if ACTIONS_RUNNER_POD_NAME env is not set', () => {
94+
delete process.env.ACTIONS_RUNNER_CLAIM_NAME
95+
delete process.env.ACTIONS_RUNNER_POD_NAME
96+
expect(() => getVolumeClaimName()).toThrow()
97+
98+
process.env.ACTIONS_RUNNER_POD_NAME = ''
99+
expect(() => getVolumeClaimName()).toThrow()
100+
})
101+
102+
it('should return ACTIONS_RUNNER_CLAIM_NAME env if set', () => {
103+
const claimName = 'testclaim'
104+
process.env.ACTIONS_RUNNER_CLAIM_NAME = claimName
105+
process.env.ACTIONS_RUNNER_POD_NAME = 'example'
106+
expect(getVolumeClaimName()).toBe(claimName)
107+
})
108+
109+
it('should contain suffix -work if ACTIONS_RUNNER_CLAIM_NAME is not set', () => {
110+
delete process.env.ACTIONS_RUNNER_CLAIM_NAME
111+
process.env.ACTIONS_RUNNER_POD_NAME = 'example'
112+
expect(getVolumeClaimName()).toBe('example-work')
113+
})
114+
})
115+
116+
describe('getSecretName', () => {
117+
it('should throw if ACTIONS_RUNNER_POD_NAME env is not set', () => {
118+
delete process.env.ACTIONS_RUNNER_POD_NAME
119+
expect(() => getSecretName()).toThrow()
120+
121+
process.env.ACTIONS_RUNNER_POD_NAME = ''
122+
expect(() => getSecretName()).toThrow()
123+
})
124+
125+
it('should contain suffix -secret- and name trimmed', () => {
126+
const podNames = [
127+
'test',
128+
'abcdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
129+
]
130+
131+
for (const podName of podNames) {
132+
process.env.ACTIONS_RUNNER_POD_NAME = podName
133+
const actual = getSecretName()
134+
const re = new RegExp(
135+
`${podName.substring(
136+
MAX_POD_NAME_LENGTH -
137+
'-secret-'.length -
138+
STEP_POD_NAME_SUFFIX_LENGTH
139+
)}-secret-[a-z0-9]{8,}`
140+
)
141+
expect(actual).toMatch(re)
142+
}
143+
})
144+
})
145+
146+
describe('getStepPodName', () => {
147+
it('should throw if ACTIONS_RUNNER_POD_NAME env is not set', () => {
148+
delete process.env.ACTIONS_RUNNER_POD_NAME
149+
expect(() => getStepPodName()).toThrow()
150+
151+
process.env.ACTIONS_RUNNER_POD_NAME = ''
152+
expect(() => getStepPodName()).toThrow()
153+
})
154+
155+
it('should contain suffix -step- and name trimmed', () => {
156+
const podNames = [
157+
'test',
158+
'abcdaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
159+
]
160+
161+
for (const podName of podNames) {
162+
process.env.ACTIONS_RUNNER_POD_NAME = podName
163+
const actual = getStepPodName()
164+
const re = new RegExp(
165+
`${podName.substring(
166+
MAX_POD_NAME_LENGTH - '-step-'.length - STEP_POD_NAME_SUFFIX_LENGTH
167+
)}-step-[a-z0-9]{8,}`
168+
)
169+
expect(actual).toMatch(re)
170+
}
171+
})
172+
})
173+
})

0 commit comments

Comments
 (0)