Skip to content

Commit 38bc1dd

Browse files
committed
improve coverage for top.ts by covering topNodes.
1 parent 45bdb75 commit 38bc1dd

File tree

3 files changed

+95
-12
lines changed

3 files changed

+95
-12
lines changed

eslint.config.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ export default tseslint.config(
2121
'@typescript-eslint/no-empty-object-type': 'off',
2222
'@typescript-eslint/no-explicit-any': 'off',
2323
'@typescript-eslint/no-non-null-assertion': 'off',
24-
'@typescript-eslint/no-unused-vars': ['error', { args: 'none' }],
24+
'@typescript-eslint/no-unused-vars': [
25+
'error',
26+
{
27+
args: 'none',
28+
destructuredArrayIgnorePattern: '^_',
29+
},
30+
],
2531
},
2632
},
2733
);

src/top_test.ts

Lines changed: 85 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { deepEqual, deepStrictEqual, strictEqual } from 'assert';
22
import nock from 'nock';
33
import { KubeConfig } from './config.js';
44
import { Metrics, PodMetricsList } from './metrics.js';
5-
import { CurrentResourceUsage, topPods } from './top.js';
6-
import { CoreV1Api, V1Pod } from './api.js';
5+
import { CurrentResourceUsage, ResourceUsage, topNodes, topPods } from './top.js';
6+
import { CoreV1Api, V1Node, V1Pod } from './api.js';
77

88
const emptyPodMetrics: PodMetricsList = {
99
kind: 'PodMetricsList',
@@ -83,6 +83,10 @@ const podList: V1Pod[] = [
8383
},
8484
},
8585
],
86+
nodeName: 'node1',
87+
},
88+
status: {
89+
phase: 'Running',
8690
},
8791
},
8892
{
@@ -118,6 +122,43 @@ const podList: V1Pod[] = [
118122
},
119123
},
120124
],
125+
nodeName: 'node1',
126+
},
127+
status: {
128+
phase: 'Running',
129+
},
130+
},
131+
];
132+
133+
const nodeList: V1Node[] = [
134+
{
135+
metadata: {
136+
name: 'node1',
137+
},
138+
status: {
139+
capacity: {
140+
cpu: '4',
141+
memory: '16Gi',
142+
},
143+
allocatable: {
144+
cpu: '4',
145+
memory: '16Gi',
146+
},
147+
},
148+
},
149+
{
150+
metadata: {
151+
name: 'node2',
152+
},
153+
status: {
154+
capacity: {
155+
cpu: '8',
156+
memory: '32Gi',
157+
},
158+
allocatable: {
159+
cpu: '8',
160+
memory: '32Gi',
161+
},
121162
},
122163
},
123164
];
@@ -134,22 +175,23 @@ const testConfigOptions: any = {
134175
const systemUnderTest = (
135176
namespace?: string,
136177
options: any = testConfigOptions,
137-
): [() => ReturnType<typeof topPods>, nock.Scope] => {
178+
): [() => ReturnType<typeof topPods>, () => ReturnType<typeof topNodes>, nock.Scope] => {
138179
const kc = new KubeConfig();
139180
kc.loadFromOptions(options);
140181
const metricsClient = new Metrics(kc);
141182
const core = kc.makeApiClient(CoreV1Api);
142183
const topPodsFunc = () => topPods(core, metricsClient, namespace);
184+
const topNodesFunc = () => topNodes(core);
143185

144186
const scope = nock(testConfigOptions.clusters[0].server);
145187

146-
return [topPodsFunc, scope];
188+
return [topPodsFunc, topNodesFunc, scope];
147189
};
148190

149191
describe('Top', () => {
150192
describe('topPods', () => {
151193
it('should return empty when no pods', async () => {
152-
const [topPodsFunc, scope] = systemUnderTest();
194+
const [topPodsFunc, _, scope] = systemUnderTest();
153195
const podMetrics = scope.get('/apis/metrics.k8s.io/v1beta1/pods').reply(200, emptyPodMetrics);
154196
const pods = scope.get('/api/v1/pods').reply(200, {
155197
items: [],
@@ -160,7 +202,7 @@ describe('Top', () => {
160202
pods.done();
161203
});
162204
it('should return use cluster scope when namespace empty string', async () => {
163-
const [topPodsFunc, scope] = systemUnderTest('');
205+
const [topPodsFunc, _, scope] = systemUnderTest('');
164206
const podMetrics = scope.get('/apis/metrics.k8s.io/v1beta1/pods').reply(200, emptyPodMetrics);
165207
const pods = scope.get('/api/v1/pods').reply(200, {
166208
items: [],
@@ -171,7 +213,7 @@ describe('Top', () => {
171213
pods.done();
172214
});
173215
it('should return cluster wide pod metrics', async () => {
174-
const [topPodsFunc, scope] = systemUnderTest();
216+
const [topPodsFunc, _, scope] = systemUnderTest();
175217
const podMetrics = scope.get('/apis/metrics.k8s.io/v1beta1/pods').reply(200, mockedPodMetrics);
176218
const pods = scope.get('/api/v1/pods').reply(200, {
177219
items: podList,
@@ -235,7 +277,7 @@ describe('Top', () => {
235277
pods.done();
236278
});
237279
it('should return best effort pod metrics', async () => {
238-
const [topPodsFunc, scope] = systemUnderTest();
280+
const [topPodsFunc, _, scope] = systemUnderTest();
239281
const podMetrics = scope.get('/apis/metrics.k8s.io/v1beta1/pods').reply(200, mockedPodMetrics);
240282
const pods = scope.get('/api/v1/pods').reply(200, {
241283
items: bestEffortPodList,
@@ -263,7 +305,7 @@ describe('Top', () => {
263305
pods.done();
264306
});
265307
it('should return 0 when pod metrics missing', async () => {
266-
const [topPodsFunc, scope] = systemUnderTest();
308+
const [topPodsFunc, _, scope] = systemUnderTest();
267309
const podMetrics = scope.get('/apis/metrics.k8s.io/v1beta1/pods').reply(200, emptyPodMetrics);
268310
const pods = scope.get('/api/v1/pods').reply(200, {
269311
items: podList,
@@ -286,7 +328,7 @@ describe('Top', () => {
286328
pods.done();
287329
});
288330
it('should return empty array when pods missing', async () => {
289-
const [topPodsFunc, scope] = systemUnderTest();
331+
const [topPodsFunc, _, scope] = systemUnderTest();
290332
const podMetrics = scope.get('/apis/metrics.k8s.io/v1beta1/pods').reply(200, mockedPodMetrics);
291333
const pods = scope.get('/api/v1/pods').reply(200, {
292334
items: [],
@@ -297,7 +339,7 @@ describe('Top', () => {
297339
pods.done();
298340
});
299341
it('should return namespace pod metrics', async () => {
300-
const [topPodsFunc, scope] = systemUnderTest(TEST_NAMESPACE);
342+
const [topPodsFunc, _, scope] = systemUnderTest(TEST_NAMESPACE);
301343
const podMetrics = scope
302344
.get(`/apis/metrics.k8s.io/v1beta1/namespaces/${TEST_NAMESPACE}/pods`)
303345
.reply(200, mockedPodMetrics);
@@ -363,4 +405,36 @@ describe('Top', () => {
363405
pods.done();
364406
});
365407
});
408+
describe('topNodes', () => {
409+
it('should return empty when no nodes', async () => {
410+
const [_, topNodesFunc, scope] = systemUnderTest();
411+
const nodes = scope.get('/api/v1/nodes').reply(200, {
412+
items: [],
413+
});
414+
const result = await topNodesFunc();
415+
deepStrictEqual(result, []);
416+
nodes.done();
417+
});
418+
419+
it('should return cluster wide node metrics', async () => {
420+
const [_, topNodesFunc, scope] = systemUnderTest();
421+
const pods = scope.get('/api/v1/pods').times(2).reply(200, {
422+
items: podList,
423+
});
424+
const nodes = scope.get('/api/v1/nodes').reply(200, {
425+
items: nodeList,
426+
});
427+
const result = await topNodesFunc();
428+
strictEqual(result.length, 2);
429+
deepStrictEqual(result[0].CPU, new ResourceUsage(4, 2.2, 2.2));
430+
deepStrictEqual(
431+
result[0].Memory,
432+
new ResourceUsage(BigInt('17179869184'), BigInt('262144000'), BigInt('314572800')),
433+
);
434+
deepStrictEqual(result[1].CPU, new ResourceUsage(8, 0, 0));
435+
deepStrictEqual(result[1].Memory, new ResourceUsage(BigInt('34359738368'), 0, 0));
436+
pods.done();
437+
nodes.done();
438+
});
439+
});
366440
});

src/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { CoreV1Api, V1Container, V1Pod } from './gen/index.js';
33

44
export async function podsForNode(api: CoreV1Api, nodeName: string): Promise<V1Pod[]> {
55
const allPods = await api.listPodForAllNamespaces();
6+
if (!allPods.items) {
7+
return [];
8+
}
69
return allPods.items.filter((pod: V1Pod) => pod.spec!.nodeName === nodeName);
710
}
811

0 commit comments

Comments
 (0)