kubernetes-fluent-client 1.10.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/fluent/index.d.ts +1 -1
- package/dist/fluent/index.d.ts.map +1 -1
- package/dist/fluent/index.js +2 -2
- package/dist/fluent/types.d.ts +11 -9
- package/dist/fluent/types.d.ts.map +1 -1
- package/dist/fluent/types.js +2 -0
- package/dist/fluent/watch.d.ts +78 -35
- package/dist/fluent/watch.d.ts.map +1 -1
- package/dist/fluent/watch.js +289 -107
- package/dist/fluent/watch.spec.d.ts +2 -0
- package/dist/fluent/watch.spec.d.ts.map +1 -0
- package/dist/fluent/watch.spec.js +235 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/package.json +5 -5
- package/src/fluent/index.ts +4 -4
- package/src/fluent/types.ts +13 -11
- package/src/fluent/watch.spec.ts +281 -0
- package/src/fluent/watch.ts +319 -150
- package/src/index.ts +3 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals";
|
|
4
|
+
import nock from "nock";
|
|
5
|
+
import { PassThrough } from "readable-stream";
|
|
6
|
+
|
|
7
|
+
import { K8s } from ".";
|
|
8
|
+
import { WatchEvent, kind } from "..";
|
|
9
|
+
import { WatchPhase } from "./types";
|
|
10
|
+
import { Watcher } from "./watch";
|
|
11
|
+
|
|
12
|
+
describe("Watcher", () => {
|
|
13
|
+
const evtMock = jest.fn<(update: kind.Pod, phase: WatchPhase) => void>();
|
|
14
|
+
const errMock = jest.fn<(err: Error) => void>();
|
|
15
|
+
|
|
16
|
+
const setupAndStartWatcher = (eventType: WatchEvent, handler: (...args: any[]) => void) => {
|
|
17
|
+
watcher.events.on(eventType, handler);
|
|
18
|
+
watcher.start().catch(errMock);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
let watcher: Watcher<typeof kind.Pod>;
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
jest.resetAllMocks();
|
|
25
|
+
watcher = K8s(kind.Pod).Watch(evtMock, {
|
|
26
|
+
retryDelaySec: 1,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
nock("http://jest-test:8080")
|
|
30
|
+
.get("/api/v1/pods")
|
|
31
|
+
.query({ watch: "true", allowWatchBookmarks: "true" })
|
|
32
|
+
.reply(200, () => {
|
|
33
|
+
const stream = new PassThrough();
|
|
34
|
+
|
|
35
|
+
const resources = [
|
|
36
|
+
{ type: "ADDED", object: createMockPod(`pod-0`, `1`) },
|
|
37
|
+
{ type: "BOOKMARK", object: { metadata: { resourceVersion: "1" } } },
|
|
38
|
+
{ type: "MODIFIED", object: createMockPod(`pod-0`, `2`) },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
resources.forEach(resource => {
|
|
42
|
+
stream.write(JSON.stringify(resource) + "\n");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
stream.end();
|
|
46
|
+
|
|
47
|
+
return stream;
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
watcher.close();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("should watch named resources", done => {
|
|
56
|
+
nock.cleanAll();
|
|
57
|
+
nock("http://jest-test:8080")
|
|
58
|
+
.get("/api/v1/namespaces/tester/pods")
|
|
59
|
+
.query({ watch: "true", allowWatchBookmarks: "true", fieldSelector: "metadata.name=demo" })
|
|
60
|
+
.reply(200);
|
|
61
|
+
|
|
62
|
+
watcher = K8s(kind.Pod, { name: "demo" }).InNamespace("tester").Watch(evtMock);
|
|
63
|
+
|
|
64
|
+
setupAndStartWatcher(WatchEvent.CONNECT, () => {
|
|
65
|
+
done();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("should start the watch at the specified resource version", done => {
|
|
70
|
+
nock.cleanAll();
|
|
71
|
+
nock("http://jest-test:8080")
|
|
72
|
+
.get("/api/v1/pods")
|
|
73
|
+
.query({
|
|
74
|
+
watch: "true",
|
|
75
|
+
allowWatchBookmarks: "true",
|
|
76
|
+
resourceVersion: "25",
|
|
77
|
+
})
|
|
78
|
+
.reply(200);
|
|
79
|
+
|
|
80
|
+
watcher = K8s(kind.Pod).Watch(evtMock, {
|
|
81
|
+
resourceVersion: "25",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
setupAndStartWatcher(WatchEvent.CONNECT, () => {
|
|
85
|
+
done();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should handle resource version is too old", done => {
|
|
90
|
+
nock.cleanAll();
|
|
91
|
+
nock("http://jest-test:8080")
|
|
92
|
+
.get("/api/v1/pods")
|
|
93
|
+
.query({ watch: "true", allowWatchBookmarks: "true", resourceVersion: "45" })
|
|
94
|
+
.reply(200, () => {
|
|
95
|
+
const stream = new PassThrough();
|
|
96
|
+
stream.write(
|
|
97
|
+
JSON.stringify({
|
|
98
|
+
type: "ERROR",
|
|
99
|
+
object: {
|
|
100
|
+
kind: "Status",
|
|
101
|
+
apiVersion: "v1",
|
|
102
|
+
metadata: {},
|
|
103
|
+
status: "Failure",
|
|
104
|
+
message: "too old resource version: 123 (391079)",
|
|
105
|
+
reason: "Gone",
|
|
106
|
+
code: 410,
|
|
107
|
+
},
|
|
108
|
+
}) + "\n",
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
stream.end();
|
|
112
|
+
return stream;
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
watcher = K8s(kind.Pod).Watch(evtMock, {
|
|
116
|
+
resourceVersion: "45",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
setupAndStartWatcher(WatchEvent.OLD_RESOURCE_VERSION, res => {
|
|
120
|
+
expect(res).toEqual("45");
|
|
121
|
+
done();
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should call the event handler for each event", done => {
|
|
126
|
+
watcher = K8s(kind.Pod).Watch((evt, phase) => {
|
|
127
|
+
expect(evt.metadata?.name).toEqual(`pod-0`);
|
|
128
|
+
expect(phase).toEqual(WatchPhase.Added);
|
|
129
|
+
done();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
watcher.start().catch(errMock);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should return the cache id", () => {
|
|
136
|
+
expect(watcher.getCacheID()).toEqual("d69b75a611");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should use an updated resourceVersion", done => {
|
|
140
|
+
nock.cleanAll();
|
|
141
|
+
nock("http://jest-test:8080")
|
|
142
|
+
.get("/api/v1/pods")
|
|
143
|
+
.query({
|
|
144
|
+
watch: "true",
|
|
145
|
+
allowWatchBookmarks: "true",
|
|
146
|
+
resourceVersion: "35",
|
|
147
|
+
})
|
|
148
|
+
.reply(200);
|
|
149
|
+
|
|
150
|
+
// Update the resource version, could be combined with getCacheID to store the value
|
|
151
|
+
watcher.resourceVersion = "35";
|
|
152
|
+
|
|
153
|
+
setupAndStartWatcher(WatchEvent.CONNECT, () => {
|
|
154
|
+
done();
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should handle the CONNECT event", done => {
|
|
159
|
+
setupAndStartWatcher(WatchEvent.CONNECT, () => {
|
|
160
|
+
done();
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("should handle the DATA event", done => {
|
|
165
|
+
setupAndStartWatcher(WatchEvent.DATA, (pod, phase) => {
|
|
166
|
+
expect(pod.metadata?.name).toEqual(`pod-0`);
|
|
167
|
+
expect(phase).toEqual(WatchPhase.Added);
|
|
168
|
+
done();
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("should handle the BOOKMARK event", done => {
|
|
173
|
+
setupAndStartWatcher(WatchEvent.BOOKMARK, bookmark => {
|
|
174
|
+
expect(bookmark.metadata?.resourceVersion).toEqual("1");
|
|
175
|
+
done();
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("should handle the NETWORK_ERROR event", done => {
|
|
180
|
+
nock.cleanAll();
|
|
181
|
+
nock("http://jest-test:8080")
|
|
182
|
+
.get("/api/v1/pods")
|
|
183
|
+
.query({ watch: "true", allowWatchBookmarks: "true" })
|
|
184
|
+
.replyWithError("Something bad happened");
|
|
185
|
+
|
|
186
|
+
setupAndStartWatcher(WatchEvent.NETWORK_ERROR, error => {
|
|
187
|
+
expect(error.message).toEqual(
|
|
188
|
+
"request to http://jest-test:8080/api/v1/pods?watch=true&allowWatchBookmarks=true failed, reason: Something bad happened",
|
|
189
|
+
);
|
|
190
|
+
done();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("should handle the RESOURCE_VERSION event", done => {
|
|
195
|
+
setupAndStartWatcher(WatchEvent.RESOURCE_VERSION, resourceVersion => {
|
|
196
|
+
expect(watcher.resourceVersion).toEqual("2");
|
|
197
|
+
expect(resourceVersion).toEqual("2");
|
|
198
|
+
done();
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("should handle the RECONNECT event", done => {
|
|
203
|
+
nock.cleanAll();
|
|
204
|
+
nock("http://jest-test:8080")
|
|
205
|
+
.get("/api/v1/pods")
|
|
206
|
+
.query({ watch: "true", allowWatchBookmarks: "true" })
|
|
207
|
+
.replyWithError("Something bad happened");
|
|
208
|
+
|
|
209
|
+
setupAndStartWatcher(WatchEvent.RECONNECT, error => {
|
|
210
|
+
expect(error.message).toEqual(
|
|
211
|
+
"request to http://jest-test:8080/api/v1/pods?watch=true&allowWatchBookmarks=true failed, reason: Something bad happened",
|
|
212
|
+
);
|
|
213
|
+
done();
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("should perform a resync after the resync interval", done => {
|
|
218
|
+
watcher = K8s(kind.Pod).Watch(evtMock, {
|
|
219
|
+
resyncIntervalSec: 1,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
setupAndStartWatcher(WatchEvent.RESYNC, err => {
|
|
223
|
+
expect(err.name).toEqual("Resync");
|
|
224
|
+
expect(err.message).toEqual("Resync triggered by resyncIntervalSec");
|
|
225
|
+
done();
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("should handle the GIVE_UP event", done => {
|
|
230
|
+
nock.cleanAll();
|
|
231
|
+
nock("http://jest-test:8080");
|
|
232
|
+
|
|
233
|
+
watcher = K8s(kind.Pod).Watch(evtMock, {
|
|
234
|
+
retryMax: 1,
|
|
235
|
+
retryDelaySec: 1,
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
setupAndStartWatcher(WatchEvent.GIVE_UP, error => {
|
|
239
|
+
expect(error.message).toContain(
|
|
240
|
+
"request to http://jest-test:8080/api/v1/pods?watch=true&allowWatchBookmarks=true failed",
|
|
241
|
+
);
|
|
242
|
+
done();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Creates a mock pod object
|
|
249
|
+
*
|
|
250
|
+
* @param name The name of the pod
|
|
251
|
+
* @param resourceVersion The resource version of the pod
|
|
252
|
+
* @returns A mock pod object
|
|
253
|
+
*/
|
|
254
|
+
function createMockPod(name: string, resourceVersion: string): kind.Pod {
|
|
255
|
+
return {
|
|
256
|
+
kind: "Pod",
|
|
257
|
+
apiVersion: "v1",
|
|
258
|
+
metadata: {
|
|
259
|
+
name: name,
|
|
260
|
+
resourceVersion: resourceVersion,
|
|
261
|
+
// ... other metadata fields
|
|
262
|
+
},
|
|
263
|
+
spec: {
|
|
264
|
+
containers: [
|
|
265
|
+
{
|
|
266
|
+
name: "nginx",
|
|
267
|
+
image: "nginx:1.14.2",
|
|
268
|
+
ports: [
|
|
269
|
+
{
|
|
270
|
+
containerPort: 80,
|
|
271
|
+
protocol: "TCP",
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
status: {
|
|
278
|
+
// ... pod status
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
}
|