Skip to content

Commit f1b77ac

Browse files
authored
Merge pull request #2272 from brendandburns/coverage
Improve coverage by adding unit tests for log.ts
2 parents 1d63ebf + 45bdb75 commit f1b77ac

File tree

3 files changed

+180
-4
lines changed

3 files changed

+180
-4
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"src/**/*.ts"
3434
],
3535
"exclude": [
36-
"src/gen/*/**.ts",
36+
"src/gen/**/*.ts",
3737
"src/index.ts",
3838
"src/*_test.ts",
3939
"src/test"

src/log.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export class Log {
142142
// TODO: the follow search param still has the stream close prematurely based on my testing
143143
response.body!.pipe(stream);
144144
} else if (status === 500) {
145-
const v1status = response.body as V1Status;
145+
const v1status = (await response.json()) as V1Status;
146146
const v1code = v1status.code;
147147
const v1message = v1status.message;
148148
if (v1code !== undefined && v1message !== undefined) {
@@ -152,6 +152,13 @@ export class Log {
152152
v1status,
153153
normalizeResponseHeaders(response),
154154
);
155+
} else {
156+
throw new ApiException<undefined>(
157+
status,
158+
'Error occurred in log request',
159+
undefined,
160+
normalizeResponseHeaders(response),
161+
);
155162
}
156163
} else {
157164
throw new ApiException<undefined>(

src/log_test.ts

Lines changed: 171 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,177 @@
1-
import { strictEqual, throws } from 'node:assert';
2-
import { AddOptionsToSearchParams, LogOptions } from './log.js';
1+
import { strictEqual, rejects, throws } from 'node:assert';
2+
import nock from 'nock';
3+
import { AddOptionsToSearchParams, Log, LogOptions } from './log.js';
4+
import { KubeConfig } from './config.js';
5+
import { Writable } from 'node:stream';
36

47
describe('Log', () => {
8+
describe('Constructor', () => {
9+
it('should work', () => {
10+
const config = new KubeConfig();
11+
config.addCluster({
12+
name: 'foo',
13+
server: 'https://example.com',
14+
caData: 'certificate-authority-data',
15+
skipTLSVerify: false,
16+
});
17+
const log = new Log(config);
18+
strictEqual(log.config, config);
19+
});
20+
});
21+
describe('log', () => {
22+
const config = new KubeConfig();
23+
config.addCluster({
24+
name: 'foo',
25+
server: 'https://example.com',
26+
caData: 'certificate-authority-data',
27+
skipTLSVerify: false,
28+
});
29+
config.addContext({
30+
name: 'foo',
31+
cluster: 'foo',
32+
user: 'foo',
33+
});
34+
config.setCurrentContext('foo');
35+
const log = new Log(config);
36+
37+
afterEach(() => {
38+
nock.cleanAll();
39+
});
40+
41+
it('should make a request with correct parameters', async () => {
42+
const namespace = 'default';
43+
const podName = 'mypod';
44+
const containerName = 'mycontainer';
45+
const stream = new Writable({
46+
write(chunk, encoding, callback) {
47+
callback();
48+
},
49+
});
50+
const options: LogOptions = {
51+
follow: true,
52+
limitBytes: 100,
53+
pretty: true,
54+
previous: true,
55+
sinceSeconds: 1,
56+
tailLines: 1,
57+
timestamps: true,
58+
};
59+
60+
nock('https://example.com')
61+
.get('/api/v1/namespaces/default/pods/mypod/log')
62+
.query({
63+
container: 'mycontainer',
64+
follow: 'true',
65+
limitBytes: '100',
66+
pretty: 'true',
67+
previous: 'true',
68+
sinceSeconds: '1',
69+
tailLines: '1',
70+
timestamps: 'true',
71+
})
72+
.reply(200, 'log data');
73+
74+
const controller = await log.log(namespace, podName, containerName, stream, options);
75+
strictEqual(controller instanceof AbortController, true);
76+
});
77+
78+
it('should throw an error if no active cluster', async () => {
79+
const configWithoutCluster = new KubeConfig();
80+
const logWithoutCluster = new Log(configWithoutCluster);
81+
const namespace = 'default';
82+
const podName = 'mypod';
83+
const containerName = 'mycontainer';
84+
const stream = new Writable({
85+
write(chunk, encoding, callback) {
86+
callback();
87+
},
88+
});
89+
90+
await rejects(async () => {
91+
await logWithoutCluster.log(namespace, podName, containerName, stream);
92+
}, /No currently active cluster/);
93+
});
94+
95+
it('should handle API exceptions on non-500', async () => {
96+
const namespace = 'default';
97+
const podName = 'mypod';
98+
const containerName = 'mycontainer';
99+
const stream = new Writable({
100+
write(chunk, encoding, callback) {
101+
callback();
102+
},
103+
});
104+
105+
nock('https://example.com')
106+
.get('/api/v1/namespaces/default/pods/mypod/log')
107+
.query({ container: 'mycontainer' })
108+
.reply(501, { message: 'Error occurred in log request' });
109+
110+
await rejects(async () => {
111+
await log.log(namespace, podName, containerName, stream);
112+
}, /Error occurred in log request/);
113+
});
114+
115+
it('should handle API exceptions on 500', async () => {
116+
const namespace = 'default';
117+
const podName = 'mypod';
118+
const containerName = 'mycontainer';
119+
const stream = new Writable({
120+
write(chunk, encoding, callback) {
121+
callback();
122+
},
123+
});
124+
125+
nock('https://example.com')
126+
.get('/api/v1/namespaces/default/pods/mypod/log')
127+
.query({ container: 'mycontainer' })
128+
.reply(500, { message: 'Error occurred in log request' });
129+
130+
await rejects(async () => {
131+
await log.log(namespace, podName, containerName, stream);
132+
}, /Error occurred in log request/);
133+
});
134+
135+
it('should handle V1Status with code and message', async () => {
136+
const namespace = 'default';
137+
const podName = 'mypod';
138+
const containerName = 'mycontainer';
139+
const stream = new Writable({
140+
write(chunk, encoding, callback) {
141+
callback();
142+
},
143+
});
144+
145+
const v1Status = {
146+
kind: 'Status',
147+
apiVersion: 'v1',
148+
metadata: {},
149+
status: 'Failure',
150+
message: 'Pod not found',
151+
reason: 'NotFound',
152+
details: {
153+
name: podName,
154+
kind: 'pods',
155+
},
156+
code: 404,
157+
};
158+
159+
nock('https://example.com')
160+
.get('/api/v1/namespaces/default/pods/mypod/log')
161+
.query({ container: 'mycontainer' })
162+
.reply(500, v1Status);
163+
164+
await rejects(async () => {
165+
await log.log(namespace, podName, containerName, stream);
166+
}, /Pod not found/);
167+
});
168+
});
5169
describe('AddOptionsToSearchParams', () => {
170+
it('should handle no log options', () => {
171+
const searchParams = new URLSearchParams();
172+
AddOptionsToSearchParams(undefined, searchParams);
173+
// verify that it doesn't throw.
174+
});
6175
it('should add options to search params', () => {
7176
let searchParams = new URLSearchParams();
8177
let options: LogOptions = {

0 commit comments

Comments
 (0)