pepr 0.38.0-rc → 0.38.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.
Files changed (87) hide show
  1. package/dist/cli.js +13 -13
  2. package/dist/controller.js +1 -1
  3. package/dist/fixtures/loader.d.ts +1 -1
  4. package/dist/fixtures/loader.d.ts.map +1 -1
  5. package/dist/lib/controller/index.d.ts +2 -1
  6. package/dist/lib/controller/index.d.ts.map +1 -1
  7. package/dist/lib/k8s.d.ts +1 -77
  8. package/dist/lib/k8s.d.ts.map +1 -1
  9. package/dist/lib.js.map +2 -2
  10. package/package.json +8 -6
  11. package/src/fixtures/loader.ts +1 -1
  12. package/src/lib/assets/pods.ts +6 -6
  13. package/src/lib/assets/yaml.ts +6 -6
  14. package/src/lib/controller/index.ts +2 -2
  15. package/src/lib/k8s.ts +1 -102
  16. package/dist/cli/init/utils.test.d.ts +0 -2
  17. package/dist/cli/init/utils.test.d.ts.map +0 -1
  18. package/dist/cli/init/walkthrough.test.d.ts +0 -2
  19. package/dist/cli/init/walkthrough.test.d.ts.map +0 -1
  20. package/dist/lib/adjudicators.test.d.ts +0 -2
  21. package/dist/lib/adjudicators.test.d.ts.map +0 -1
  22. package/dist/lib/assets/helm.test.d.ts +0 -2
  23. package/dist/lib/assets/helm.test.d.ts.map +0 -1
  24. package/dist/lib/assets/pods.test.d.ts +0 -2
  25. package/dist/lib/assets/pods.test.d.ts.map +0 -1
  26. package/dist/lib/capability.test.d.ts +0 -2
  27. package/dist/lib/capability.test.d.ts.map +0 -1
  28. package/dist/lib/controller/store.test.d.ts +0 -2
  29. package/dist/lib/controller/store.test.d.ts.map +0 -1
  30. package/dist/lib/errors.test.d.ts +0 -2
  31. package/dist/lib/errors.test.d.ts.map +0 -1
  32. package/dist/lib/filter.test.d.ts +0 -3
  33. package/dist/lib/filter.test.d.ts.map +0 -1
  34. package/dist/lib/finalizer.test.d.ts +0 -2
  35. package/dist/lib/finalizer.test.d.ts.map +0 -1
  36. package/dist/lib/helpers.test.d.ts +0 -2
  37. package/dist/lib/helpers.test.d.ts.map +0 -1
  38. package/dist/lib/included-files.test.d.ts +0 -2
  39. package/dist/lib/included-files.test.d.ts.map +0 -1
  40. package/dist/lib/logger.test.d.ts +0 -2
  41. package/dist/lib/logger.test.d.ts.map +0 -1
  42. package/dist/lib/metrics.test.d.ts +0 -2
  43. package/dist/lib/metrics.test.d.ts.map +0 -1
  44. package/dist/lib/module.test.d.ts +0 -2
  45. package/dist/lib/module.test.d.ts.map +0 -1
  46. package/dist/lib/mutate-request.test.d.ts +0 -2
  47. package/dist/lib/mutate-request.test.d.ts.map +0 -1
  48. package/dist/lib/queue.test.d.ts +0 -2
  49. package/dist/lib/queue.test.d.ts.map +0 -1
  50. package/dist/lib/schedule.test.d.ts +0 -15
  51. package/dist/lib/schedule.test.d.ts.map +0 -1
  52. package/dist/lib/storage.test.d.ts +0 -2
  53. package/dist/lib/storage.test.d.ts.map +0 -1
  54. package/dist/lib/tls.test.d.ts +0 -2
  55. package/dist/lib/tls.test.d.ts.map +0 -1
  56. package/dist/lib/utils.test.d.ts +0 -2
  57. package/dist/lib/utils.test.d.ts.map +0 -1
  58. package/dist/lib/validate-request.test.d.ts +0 -2
  59. package/dist/lib/validate-request.test.d.ts.map +0 -1
  60. package/dist/lib/watch-processor.test.d.ts +0 -2
  61. package/dist/lib/watch-processor.test.d.ts.map +0 -1
  62. package/dist/sdk/sdk.test.d.ts +0 -2
  63. package/dist/sdk/sdk.test.d.ts.map +0 -1
  64. package/src/cli/init/utils.test.ts +0 -19
  65. package/src/cli/init/walkthrough.test.ts +0 -102
  66. package/src/lib/adjudicators.test.ts +0 -1236
  67. package/src/lib/assets/helm.test.ts +0 -64
  68. package/src/lib/assets/pods.test.ts +0 -553
  69. package/src/lib/capability.test.ts +0 -655
  70. package/src/lib/controller/store.test.ts +0 -131
  71. package/src/lib/errors.test.ts +0 -85
  72. package/src/lib/filter.test.ts +0 -691
  73. package/src/lib/finalizer.test.ts +0 -236
  74. package/src/lib/helpers.test.ts +0 -1486
  75. package/src/lib/included-files.test.ts +0 -22
  76. package/src/lib/logger.test.ts +0 -18
  77. package/src/lib/metrics.test.ts +0 -132
  78. package/src/lib/module.test.ts +0 -126
  79. package/src/lib/mutate-request.test.ts +0 -187
  80. package/src/lib/queue.test.ts +0 -152
  81. package/src/lib/schedule.test.ts +0 -217
  82. package/src/lib/storage.test.ts +0 -216
  83. package/src/lib/tls.test.ts +0 -18
  84. package/src/lib/utils.test.ts +0 -69
  85. package/src/lib/validate-request.test.ts +0 -121
  86. package/src/lib/watch-processor.test.ts +0 -418
  87. package/src/sdk/sdk.test.ts +0 -276
@@ -1,655 +0,0 @@
1
- import { Capability } from "./capability";
2
- import Log from "./logger";
3
- import { CapabilityCfg, FinalizeAction, MutateAction, ValidateAction, WatchLogAction } from "./types";
4
- import { a } from "../lib";
5
- import { V1Pod } from "@kubernetes/client-node";
6
- import { expect, describe, jest, beforeEach, it } from "@jest/globals";
7
- import { PeprMutateRequest } from "./mutate-request";
8
- import { PeprValidateRequest } from "./validate-request";
9
- import { Operation, AdmissionRequest } from "./k8s";
10
- import { WatchPhase } from "kubernetes-fluent-client/dist/fluent/types";
11
- import { Event } from "./types";
12
- import { GenericClass } from "kubernetes-fluent-client";
13
- import { Schedule } from "./schedule";
14
- import { OnSchedule } from "./schedule";
15
-
16
- // Mocking isBuildMode, isWatchMode, and isDevMode globally
17
- jest.mock("./module", () => ({
18
- isBuildMode: jest.fn(() => true),
19
- isWatchMode: jest.fn(() => true),
20
- isDevMode: jest.fn(() => true),
21
- }));
22
-
23
- // Mock logger globally
24
- jest.mock("./logger", () => ({
25
- __esModule: true,
26
- default: {
27
- info: jest.fn(),
28
- debug: jest.fn(),
29
- child: jest.fn().mockReturnThis(),
30
- },
31
- }));
32
-
33
- // Mock Storage and OnSchedule
34
- jest.mock("./storage", () => ({
35
- Storage: jest.fn(() => ({
36
- onReady: jest.fn(),
37
- })),
38
- }));
39
-
40
- // Mock OnSchedule and ensure it has a mock setStore method
41
- jest.mock("./schedule", () => ({
42
- OnSchedule: jest.fn().mockImplementation(() => ({
43
- setStore: jest.fn(), // Ensure setStore is a mocked function
44
- })),
45
- }));
46
-
47
- const mockLog = Log as jest.Mocked<typeof Log>;
48
-
49
- describe("Capability", () => {
50
- let mockRequest: AdmissionRequest<V1Pod>;
51
-
52
- beforeEach(() => {
53
- jest.resetModules();
54
- jest.clearAllMocks();
55
-
56
- mockRequest = {
57
- operation: Operation.CREATE,
58
- object: {
59
- apiVersion: "v1",
60
- kind: "Pod",
61
- metadata: {
62
- name: "test-pod",
63
- namespace: "default",
64
- labels: {
65
- "existing-label": "true",
66
- },
67
- annotations: {
68
- "existing-annotation": "true",
69
- },
70
- },
71
- spec: {
72
- containers: [],
73
- },
74
- },
75
- dryRun: false,
76
- uid: "test-uid",
77
- name: "test-pod",
78
- kind: { group: "", version: "v1", kind: "Pod" },
79
- resource: { group: "", version: "v1", resource: "pods" },
80
- userInfo: { username: "test-user" },
81
- oldObject: undefined,
82
- };
83
- });
84
-
85
- const capabilityConfig: CapabilityCfg = {
86
- name: "test-capability",
87
- description: "Test capability description",
88
- namespaces: ["default"],
89
- };
90
-
91
- it("should initialize with given configuration", () => {
92
- const capability = new Capability(capabilityConfig);
93
- expect(capability.name).toBe(capabilityConfig.name);
94
- expect(capability.description).toBe(capabilityConfig.description);
95
- expect(capability.namespaces).toEqual(capabilityConfig.namespaces);
96
- expect(mockLog.info).toHaveBeenCalledWith(`Capability ${capabilityConfig.name} registered`);
97
- });
98
-
99
- it("should register store and schedule store", () => {
100
- const capability = new Capability(capabilityConfig);
101
-
102
- const storeResult = capability.registerStore();
103
- expect(storeResult).toHaveProperty("store");
104
- expect(mockLog.info).toHaveBeenCalledWith(`Registering store for ${capabilityConfig.name}`);
105
-
106
- const scheduleStoreResult = capability.registerScheduleStore();
107
- expect(scheduleStoreResult).toHaveProperty("scheduleStore");
108
- expect(mockLog.info).toHaveBeenCalledWith(`Registering schedule store for ${capabilityConfig.name}`);
109
- });
110
-
111
- it("should throw an error if store is registered twice", () => {
112
- const capability = new Capability(capabilityConfig);
113
-
114
- capability.registerStore();
115
- expect(() => capability.registerStore()).toThrowError("Store already registered for test-capability");
116
- });
117
-
118
- it("should throw an error if schedule store is registered twice", () => {
119
- const capability = new Capability(capabilityConfig);
120
-
121
- capability.registerScheduleStore();
122
- expect(() => capability.registerScheduleStore()).toThrowError(
123
- "Schedule store already registered for test-capability",
124
- );
125
- });
126
-
127
- it("should correctly chain When, InNamespace, WithLabel, and Mutate methods", async () => {
128
- const capability = new Capability(capabilityConfig);
129
-
130
- const mockMutateCallback: MutateAction<typeof V1Pod, V1Pod> = jest.fn(
131
- async (req: PeprMutateRequest<V1Pod>, logger: typeof Log = mockLog) => {
132
- logger.info("Executing mutation action");
133
- },
134
- );
135
-
136
- capability
137
- .When(a.Pod)
138
- .IsCreatedOrUpdated()
139
- .InNamespace("default")
140
- .WithLabel("test-label", "value")
141
- .Alias("test-alias")
142
- .Mutate(mockMutateCallback);
143
-
144
- expect(capability.bindings).toHaveLength(1);
145
- const binding = capability.bindings[0];
146
- expect(binding.filters.namespaces).toContain("default");
147
- expect(binding.filters.labels).toHaveProperty("test-label", "value");
148
- expect(binding.alias).toBe("test-alias");
149
-
150
- // Simulate the mutation action
151
- const peprRequest = new PeprMutateRequest<V1Pod>(mockRequest);
152
-
153
- if (binding.mutateCallback) {
154
- await binding.mutateCallback(peprRequest);
155
- }
156
-
157
- expect(mockMutateCallback).toHaveBeenCalledWith(peprRequest, expect.anything());
158
- expect(mockLog.child).toHaveBeenCalledWith({ alias: "test-alias" });
159
- expect(mockLog.info).toHaveBeenCalledWith("Executing mutation action with alias: test-alias");
160
- });
161
-
162
- it("should use child logger for mutate callback", async () => {
163
- const capability = new Capability(capabilityConfig);
164
-
165
- const mockMutateCallback: MutateAction<typeof V1Pod, V1Pod> = jest.fn(
166
- (req: PeprMutateRequest<V1Pod>, logger: typeof Log = mockLog) => {
167
- logger.info("Mutate action log");
168
- },
169
- );
170
-
171
- capability
172
- .When(a.Pod)
173
- .IsCreatedOrUpdated()
174
- .InNamespace("default")
175
- .WithLabel("test-label", "value")
176
- .Alias("test-alias")
177
- .Mutate(mockMutateCallback);
178
-
179
- expect(capability.bindings).toHaveLength(1);
180
- const binding = capability.bindings[0];
181
-
182
- // Simulate the mutation action
183
- const peprRequest = new PeprMutateRequest<V1Pod>(mockRequest);
184
-
185
- if (binding.mutateCallback) {
186
- await binding.mutateCallback(peprRequest);
187
- }
188
-
189
- expect(mockMutateCallback).toHaveBeenCalledWith(peprRequest, expect.anything());
190
- expect(mockLog.child).toHaveBeenCalledWith({ alias: "test-alias" });
191
- expect(mockLog.info).toHaveBeenCalledWith("Executing mutation action with alias: test-alias");
192
- expect(mockLog.info).toHaveBeenCalledWith("Mutate action log");
193
- });
194
-
195
- it("should handle complex alias and logging correctly", async () => {
196
- const complexCapabilityConfig: CapabilityCfg = {
197
- name: "complex-capability",
198
- description: "Test complex capability description",
199
- namespaces: ["pepr-demo", "pepr-demo-2"],
200
- };
201
-
202
- const capability = new Capability(complexCapabilityConfig);
203
-
204
- const mockMutateCallback: MutateAction<typeof V1Pod, V1Pod> = jest.fn(
205
- async (po: PeprMutateRequest<V1Pod>, logger: typeof Log = mockLog) => {
206
- logger.info(`SNAKES ON A PLANE! ${po.Raw.metadata?.name}`);
207
- },
208
- );
209
-
210
- capability
211
- .When(a.Pod)
212
- .IsCreatedOrUpdated()
213
- .InNamespace("pepr-demo")
214
- .WithLabel("white")
215
- .Alias("reject:pods:runAsRoot:privileged:runAsGroup<10:allowPrivilegeEscalation")
216
- .Mutate(mockMutateCallback);
217
-
218
- expect(capability.bindings).toHaveLength(1);
219
- const binding = capability.bindings[0];
220
- expect(binding.filters.namespaces).toContain("pepr-demo");
221
- expect(binding.filters.labels).toHaveProperty("white", "");
222
- expect(binding.alias).toBe("reject:pods:runAsRoot:privileged:runAsGroup<10:allowPrivilegeEscalation");
223
-
224
- // Simulate the mutation action
225
- const peprRequest = new PeprMutateRequest<V1Pod>(mockRequest);
226
-
227
- if (binding.mutateCallback) {
228
- await binding.mutateCallback(peprRequest);
229
- }
230
-
231
- expect(mockMutateCallback).toHaveBeenCalledWith(peprRequest, expect.anything());
232
- expect(mockLog.child).toHaveBeenCalledWith({
233
- alias: "reject:pods:runAsRoot:privileged:runAsGroup<10:allowPrivilegeEscalation",
234
- });
235
- expect(mockLog.info).toHaveBeenCalledWith(
236
- "Executing mutation action with alias: reject:pods:runAsRoot:privileged:runAsGroup<10:allowPrivilegeEscalation",
237
- );
238
- expect(mockLog.info).toHaveBeenCalledWith(`SNAKES ON A PLANE! ${mockRequest.object.metadata?.name}`);
239
- });
240
-
241
- it("should reset the alias before each mutation", async () => {
242
- const capability = new Capability(capabilityConfig);
243
-
244
- const firstMutateCallback: MutateAction<typeof V1Pod, V1Pod> = jest.fn(
245
- async (req: PeprMutateRequest<V1Pod>, logger: typeof Log = mockLog) => {
246
- logger.info("First mutation action");
247
- },
248
- );
249
-
250
- const secondMutateCallback: MutateAction<typeof V1Pod, V1Pod> = jest.fn(
251
- async (req: PeprMutateRequest<V1Pod>, logger: typeof Log = mockLog) => {
252
- logger.info("Second mutation action");
253
- },
254
- );
255
-
256
- // First mutation with an alias
257
- capability.When(a.Pod).IsCreatedOrUpdated().InNamespace("default").Alias("first-alias").Mutate(firstMutateCallback);
258
-
259
- // Second mutation without an alias (should use "no alias provided")
260
- capability.When(a.Pod).IsCreatedOrUpdated().InNamespace("default").Mutate(secondMutateCallback);
261
-
262
- expect(capability.bindings).toHaveLength(2);
263
-
264
- // Simulate the first mutation action
265
- const peprRequest1 = new PeprMutateRequest<V1Pod>(mockRequest);
266
- if (capability.bindings[0].mutateCallback) {
267
- await capability.bindings[0].mutateCallback(peprRequest1);
268
- }
269
-
270
- expect(firstMutateCallback).toHaveBeenCalledWith(peprRequest1, expect.anything());
271
- expect(mockLog.child).toHaveBeenCalledWith({ alias: "first-alias" });
272
- expect(mockLog.info).toHaveBeenCalledWith("Executing mutation action with alias: first-alias");
273
-
274
- // Simulate the second mutation action
275
- const peprRequest2 = new PeprMutateRequest<V1Pod>(mockRequest);
276
- if (capability.bindings[1].mutateCallback) {
277
- await capability.bindings[1].mutateCallback(peprRequest2);
278
- }
279
-
280
- expect(secondMutateCallback).toHaveBeenCalledWith(peprRequest2, expect.anything());
281
- expect(mockLog.child).toHaveBeenCalledWith({ alias: "no alias provided" });
282
- expect(mockLog.info).toHaveBeenCalledWith("Executing mutation action with alias: no alias provided");
283
- });
284
-
285
- it("should use child logger for validate callback", async () => {
286
- const capability = new Capability(capabilityConfig);
287
-
288
- const mockValidateCallback: ValidateAction<typeof V1Pod, V1Pod> = jest.fn(
289
- async (req: PeprValidateRequest<V1Pod>, logger: typeof Log = mockLog) => {
290
- logger.info("Validate action log");
291
- return { allowed: true };
292
- },
293
- );
294
-
295
- capability
296
- .When(a.Pod)
297
- .IsCreatedOrUpdated()
298
- .InNamespace("default")
299
- .Alias("test-alias")
300
- .Validate(mockValidateCallback);
301
-
302
- expect(capability.bindings).toHaveLength(1);
303
- const binding = capability.bindings[0];
304
-
305
- // Simulate the validation action
306
- const mockPeprRequest = new PeprValidateRequest<V1Pod>(mockRequest);
307
-
308
- if (binding.validateCallback) {
309
- await binding.validateCallback(mockPeprRequest);
310
- }
311
-
312
- expect(mockValidateCallback).toHaveBeenCalledWith(mockPeprRequest, expect.anything());
313
- expect(mockLog.child).toHaveBeenCalledWith({ alias: "test-alias" });
314
- expect(mockLog.info).toHaveBeenCalledWith("Executing validate action with alias: test-alias");
315
- expect(mockLog.info).toHaveBeenCalledWith("Validate action log");
316
- });
317
-
318
- it("should log 'no alias provided' if alias is not set in validate callback", async () => {
319
- const capability = new Capability(capabilityConfig);
320
-
321
- // Mock the validate callback
322
- const mockValidateCallback: ValidateAction<typeof V1Pod, V1Pod> = jest.fn(
323
- async (req: PeprValidateRequest<V1Pod>, logger: typeof Log = mockLog) => {
324
- logger.info("Validate action log");
325
- return { allowed: true };
326
- },
327
- );
328
-
329
- // Do not set alias, to trigger "no alias provided"
330
- capability.When(a.Pod).IsCreatedOrUpdated().Validate(mockValidateCallback);
331
-
332
- expect(capability.bindings).toHaveLength(1);
333
- const binding = capability.bindings[0];
334
-
335
- // Simulate the validation action
336
- const mockPeprRequest = new PeprValidateRequest<V1Pod>(mockRequest);
337
-
338
- if (binding.validateCallback) {
339
- await binding.validateCallback(mockPeprRequest);
340
- }
341
-
342
- // Expect the log to contain "no alias provided"
343
- expect(mockLog.info).toHaveBeenCalledWith("Executing validate action with alias: no alias provided");
344
- expect(mockLog.info).toHaveBeenCalledWith("Validate action log");
345
- });
346
-
347
- it("should register a Watch action and execute it with the logger", async () => {
348
- const capability = new Capability(capabilityConfig);
349
-
350
- // Mock Watch callback function
351
- const mockWatchCallback: WatchLogAction<typeof V1Pod> = jest.fn(
352
- async (update, phase, logger: typeof Log = mockLog) => {
353
- logger.info("Watch action executed");
354
- },
355
- );
356
-
357
- // Chain the When and Watch methods
358
- capability.When(a.Pod).IsCreated().Watch(mockWatchCallback);
359
-
360
- // Log the bindings to ensure they are being added
361
- console.log("Bindings after watch registration: ", capability.bindings);
362
-
363
- // Retrieve the registered binding
364
- const binding = capability.bindings.find(b => b.isWatch === true);
365
-
366
- // Check that the watch callback was registered
367
- expect(binding).toBeDefined();
368
- expect(binding?.isWatch).toBe(true);
369
-
370
- // Simulate calling the watch callback with test data
371
- const testPod = new V1Pod();
372
- await binding?.watchCallback?.(testPod, WatchPhase.Added, mockLog);
373
-
374
- // Ensure that the logger's `info` method was called
375
- expect(mockLog.info).toHaveBeenCalledWith("Watch action executed");
376
- expect(mockWatchCallback).toHaveBeenCalledWith(testPod, WatchPhase.Added, mockLog);
377
- });
378
-
379
- it("should pass the correct parameters to the Watch action", async () => {
380
- const capability = new Capability(capabilityConfig);
381
-
382
- const mockWatchCallback: WatchLogAction<typeof V1Pod> = jest.fn(
383
- async (update, phase, logger: typeof Log = mockLog) => {
384
- logger.info("Watch action executed");
385
- },
386
- );
387
-
388
- capability.When(a.Pod).IsCreated().Watch(mockWatchCallback);
389
-
390
- const binding = capability.bindings.find(b => b.isWatch);
391
- expect(binding).toBeDefined();
392
-
393
- const testPod = new V1Pod();
394
- const testPhase = WatchPhase.Modified;
395
-
396
- // Call the watch callback with custom data
397
- await binding?.watchCallback?.(testPod, testPhase, mockLog);
398
-
399
- expect(mockWatchCallback).toHaveBeenCalledWith(testPod, testPhase, mockLog);
400
- expect(mockLog.info).toHaveBeenCalledWith("Watch action executed");
401
- });
402
-
403
- it("should use child logger for reconcile callback", async () => {
404
- const capability = new Capability(capabilityConfig);
405
-
406
- const mockReconcileCallback: WatchLogAction<typeof V1Pod> = jest.fn(
407
- async (update, phase, logger: typeof Log = mockLog) => {
408
- logger.info("Reconcile action log");
409
- },
410
- );
411
-
412
- capability.When(a.Pod).IsCreatedOrUpdated().Reconcile(mockReconcileCallback);
413
-
414
- expect(capability.bindings).toHaveLength(1);
415
- const binding = capability.bindings[0];
416
-
417
- // Simulate calling the reconcile action
418
- const testPod = new V1Pod();
419
- const testPhase = WatchPhase.Modified;
420
-
421
- if (binding.watchCallback) {
422
- await binding.watchCallback(testPod, testPhase);
423
- }
424
-
425
- expect(mockReconcileCallback).toHaveBeenCalledWith(testPod, testPhase, expect.anything());
426
- expect(mockLog.child).toHaveBeenCalledWith({ alias: "no alias provided" });
427
- expect(mockLog.info).toHaveBeenCalledWith("Executing reconcile action with alias: no alias provided");
428
- expect(mockLog.info).toHaveBeenCalledWith("Reconcile action log");
429
- });
430
-
431
- it("should use child logger for finalize callback", async () => {
432
- const capability = new Capability(capabilityConfig);
433
-
434
- const mockFinalizeCallback: FinalizeAction<typeof V1Pod> = jest.fn(async (update, logger: typeof Log = mockLog) => {
435
- logger.info("Finalize action log");
436
- });
437
-
438
- // Create a mock WatchLogAction function that matches the expected signature
439
- const mockWatchCallback: WatchLogAction<typeof V1Pod> = jest.fn(
440
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
441
- async (update: V1Pod, phase: WatchPhase, logger?: typeof Log) => {},
442
- );
443
-
444
- // Chain .Watch() with the correct function signature before .Finalize()
445
- capability.When(a.Pod).IsCreatedOrUpdated().Watch(mockWatchCallback).Finalize(mockFinalizeCallback);
446
-
447
- // Find the finalize binding
448
- const finalizeBinding = capability.bindings.find(binding => binding.finalizeCallback);
449
-
450
- expect(finalizeBinding).toBeDefined(); // Ensure the finalize binding exists
451
-
452
- // Simulate calling the finalize action
453
- const testPod = new V1Pod();
454
-
455
- if (finalizeBinding?.finalizeCallback) {
456
- await finalizeBinding.finalizeCallback(testPod);
457
- }
458
-
459
- expect(mockFinalizeCallback).toHaveBeenCalledWith(testPod, expect.anything());
460
- expect(mockLog.child).toHaveBeenCalledWith({ alias: "no alias provided" });
461
- expect(mockLog.info).toHaveBeenCalledWith("Executing finalize action with alias: no alias provided");
462
- expect(mockLog.info).toHaveBeenCalledWith("Finalize action log");
463
- });
464
-
465
- it("should add deletionTimestamp filter", () => {
466
- const capability = new Capability(capabilityConfig);
467
-
468
- const mockValidateCallback: ValidateAction<typeof V1Pod, V1Pod> = jest.fn(
469
- async (req: PeprValidateRequest<V1Pod>, logger: typeof Log = mockLog) => {
470
- logger.info("Validate action log");
471
- return { allowed: true };
472
- },
473
- );
474
-
475
- capability.When(a.Pod).IsCreatedOrUpdated().WithDeletionTimestamp().Validate(mockValidateCallback);
476
-
477
- expect(capability.bindings).toHaveLength(1); // Ensure binding is created
478
- expect(capability.bindings[0].filters.deletionTimestamp).toBe(true);
479
- });
480
-
481
- it("should add name filter", () => {
482
- const capability = new Capability(capabilityConfig);
483
-
484
- const mockValidateCallback: ValidateAction<typeof V1Pod, V1Pod> = jest.fn(
485
- async (req: PeprValidateRequest<V1Pod>, logger: typeof Log = mockLog) => {
486
- logger.info("Validate action log");
487
- return { allowed: true };
488
- },
489
- );
490
-
491
- capability.When(a.Pod).IsCreatedOrUpdated().WithName("test-name").Validate(mockValidateCallback);
492
-
493
- expect(capability.bindings).toHaveLength(1); // Ensure binding is created
494
- expect(capability.bindings[0].filters.name).toBe("test-name");
495
- });
496
-
497
- it("should add annotation filter", () => {
498
- const capability = new Capability(capabilityConfig);
499
-
500
- const mockValidateCallback: ValidateAction<typeof V1Pod, V1Pod> = jest.fn(
501
- async (req: PeprValidateRequest<V1Pod>, logger: typeof Log = mockLog) => {
502
- logger.info("Validate action log");
503
- return { allowed: true };
504
- },
505
- );
506
-
507
- capability.When(a.Pod).IsCreatedOrUpdated().WithAnnotation("test-key", "test-value").Validate(mockValidateCallback);
508
-
509
- expect(capability.bindings).toHaveLength(1); // Ensure binding is created
510
- expect(capability.bindings[0].filters.annotations["test-key"]).toBe("test-value");
511
- });
512
-
513
- it("should bind an update event", () => {
514
- const capability = new Capability(capabilityConfig);
515
-
516
- const mockValidateCallback: ValidateAction<typeof V1Pod, V1Pod> = jest.fn(
517
- async (req: PeprValidateRequest<V1Pod>, logger: typeof Log = mockLog) => {
518
- logger.info("Validate action log");
519
- return { allowed: true };
520
- },
521
- );
522
-
523
- capability.When(a.Pod).IsUpdated().InNamespace("default").Validate(mockValidateCallback);
524
-
525
- expect(capability.bindings).toHaveLength(1); // Ensure binding is created
526
- expect(capability.bindings[0].event).toBe(Event.Update);
527
- });
528
-
529
- it("should bind a delete event", async () => {
530
- const capability = new Capability(capabilityConfig);
531
-
532
- const mockValidateCallback: ValidateAction<typeof V1Pod, V1Pod> = jest.fn(
533
- async (req: PeprValidateRequest<V1Pod>, logger: typeof Log = mockLog) => {
534
- logger.info("Validate action log");
535
- return { allowed: true };
536
- },
537
- );
538
-
539
- capability.When(a.Pod).IsDeleted().InNamespace("default").Validate(mockValidateCallback);
540
-
541
- expect(capability.bindings).toHaveLength(1);
542
-
543
- expect(capability.bindings).toHaveLength(1); // Ensure binding is created
544
- expect(capability.bindings[0].event).toBe(Event.Delete);
545
- });
546
-
547
- it("should throw an error if neither matchedKind nor kind is provided", () => {
548
- const capability = new Capability(capabilityConfig);
549
-
550
- // Mock a model with just a name, missing the kind
551
- const mockModel: { name: string } = {
552
- name: "InvalidModel",
553
- };
554
-
555
- // Expect an error when neither matchedKind nor kind is provided
556
- expect(() => {
557
- capability.When(mockModel as unknown as GenericClass); // Cast to the expected type without using 'any'
558
- }).toThrowError(`Kind not specified for ${mockModel.name}`);
559
- });
560
-
561
- it("should create a new schedule and watch the schedule store when PEPR_WATCH_MODE is 'true'", () => {
562
- // Set the environment variable
563
- process.env.PEPR_WATCH_MODE = "true";
564
-
565
- const capability = new Capability(capabilityConfig);
566
-
567
- const mockSchedule: Schedule = {
568
- name: "test-schedule",
569
- every: 5,
570
- unit: "minutes",
571
- run: jest.fn(),
572
- startTime: new Date(),
573
- completions: 1,
574
- };
575
-
576
- // Call OnSchedule with a mock schedule
577
- capability.OnSchedule(mockSchedule);
578
-
579
- // Ensure that the schedule store's `onReady` method is called with the correct callback
580
- const scheduleStoreInstance = capability.getScheduleStore();
581
- expect(scheduleStoreInstance.onReady).toHaveBeenCalledWith(expect.any(Function));
582
-
583
- // Simulate the `onReady` callback being invoked
584
- const onReadyCallback = (scheduleStoreInstance.onReady as jest.Mock).mock.calls[0][0] as () => void;
585
- onReadyCallback(); // The callback function is now invoked as a type of `() => void`
586
-
587
- // Ensure the new OnSchedule instance is created with the correct schedule data
588
- expect(OnSchedule).toHaveBeenCalledWith(mockSchedule);
589
-
590
- // Clean up environment variables after the test
591
- delete process.env.PEPR_WATCH_MODE;
592
- });
593
-
594
- it("should not create a new schedule or watch the schedule store when PEPR_WATCH_MODE is not set", () => {
595
- // Ensure environment variables are not set
596
- delete process.env.PEPR_WATCH_MODE;
597
- delete process.env.PEPR_MODE;
598
-
599
- const capability = new Capability(capabilityConfig);
600
-
601
- const mockSchedule: Schedule = {
602
- name: "test-schedule",
603
- every: 5,
604
- unit: "minutes",
605
- run: jest.fn(),
606
- startTime: new Date(),
607
- completions: 1,
608
- };
609
-
610
- // Call OnSchedule with a mock schedule
611
- capability.OnSchedule(mockSchedule);
612
-
613
- // Ensure that the schedule store's `onReady` method is not called
614
- const scheduleStoreInstance = capability.getScheduleStore();
615
- expect(scheduleStoreInstance.onReady).not.toHaveBeenCalled();
616
-
617
- // Ensure that OnSchedule was not called
618
- expect(OnSchedule).not.toHaveBeenCalled();
619
- });
620
-
621
- it("should use aliasLogger if no logger is provided in watch callback", async () => {
622
- const capability = new Capability(capabilityConfig);
623
-
624
- // Mock the watch callback
625
- const mockWatchCallback: WatchLogAction<typeof V1Pod> = jest.fn(
626
- async (update: V1Pod, phase: WatchPhase, logger?: typeof Log) => {
627
- logger?.info("Watch action log");
628
- },
629
- );
630
-
631
- // Chain Watch without providing an explicit logger
632
- capability.When(a.Pod).IsCreatedOrUpdated().Watch(mockWatchCallback);
633
-
634
- expect(capability.bindings).toHaveLength(1);
635
- const binding = capability.bindings[0];
636
-
637
- // Simulate the watch action without passing a logger, so aliasLogger is used
638
- const testPod = new V1Pod();
639
- await binding.watchCallback?.(testPod, WatchPhase.Added); // No logger passed
640
-
641
- // Assert that aliasLogger was used
642
- expect(mockLog.child).toHaveBeenCalledWith({ alias: "no alias provided" });
643
- expect(mockLog.info).toHaveBeenCalledWith("Executing watch action with alias: no alias provided");
644
- expect(mockLog.info).toHaveBeenCalledWith("Watch action log");
645
- });
646
-
647
- it("should add annotation with an empty value when no value is provided in WithAnnotation", () => {
648
- const capability = new Capability(capabilityConfig);
649
-
650
- // Chain WithAnnotation without providing a value (default to empty string)
651
- capability.When(a.Pod).IsCreatedOrUpdated().WithAnnotation("test-annotation");
652
-
653
- expect(capability.bindings).toHaveLength(0);
654
- });
655
- });