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.
@@ -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
+ }