kubernetes-fluent-client 3.0.3 → 4.0.0-rc-http2-watch

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 (42) hide show
  1. package/.prettierignore +4 -0
  2. package/README.md +24 -0
  3. package/dist/cli.js +21 -1
  4. package/dist/fileSystem.d.ts +11 -0
  5. package/dist/fileSystem.d.ts.map +1 -0
  6. package/dist/fileSystem.js +42 -0
  7. package/dist/fileSystem.test.d.ts +2 -0
  8. package/dist/fileSystem.test.d.ts.map +1 -0
  9. package/dist/fileSystem.test.js +75 -0
  10. package/dist/fluent/watch.d.ts +2 -0
  11. package/dist/fluent/watch.d.ts.map +1 -1
  12. package/dist/fluent/watch.js +147 -27
  13. package/dist/generate.d.ts +71 -11
  14. package/dist/generate.d.ts.map +1 -1
  15. package/dist/generate.js +130 -117
  16. package/dist/generate.test.js +293 -346
  17. package/dist/postProcessing.d.ts +246 -0
  18. package/dist/postProcessing.d.ts.map +1 -0
  19. package/dist/postProcessing.js +497 -0
  20. package/dist/postProcessing.test.d.ts +2 -0
  21. package/dist/postProcessing.test.d.ts.map +1 -0
  22. package/dist/postProcessing.test.js +550 -0
  23. package/e2e/cli.e2e.test.ts +127 -0
  24. package/e2e/crds/policyreports.default.expected/policyreport-v1alpha1.ts +332 -0
  25. package/e2e/crds/policyreports.default.expected/policyreport-v1alpha2.ts +360 -0
  26. package/e2e/crds/policyreports.default.expected/policyreport-v1beta1.ts +360 -0
  27. package/e2e/crds/policyreports.no.post.expected/policyreport-v1alpha1.ts +331 -0
  28. package/e2e/crds/policyreports.no.post.expected/policyreport-v1alpha2.ts +360 -0
  29. package/e2e/crds/policyreports.no.post.expected/policyreport-v1beta1.ts +360 -0
  30. package/e2e/crds/test.yaml/policyreports.test.yaml +1008 -0
  31. package/e2e/crds/test.yaml/uds-podmonitors.test.yaml +1245 -0
  32. package/e2e/crds/uds-podmonitors.default.expected/podmonitor-v1.ts +1333 -0
  33. package/e2e/crds/uds-podmonitors.no.post.expected/podmonitor-v1.ts +1360 -0
  34. package/package.json +6 -5
  35. package/src/cli.ts +25 -1
  36. package/src/fileSystem.test.ts +67 -0
  37. package/src/fileSystem.ts +25 -0
  38. package/src/fluent/watch.ts +174 -35
  39. package/src/generate.test.ts +368 -358
  40. package/src/generate.ts +173 -154
  41. package/src/postProcessing.test.ts +742 -0
  42. package/src/postProcessing.ts +568 -0
@@ -6,368 +6,315 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const globals_1 = require("@jest/globals");
7
7
  const generate_1 = require("./generate");
8
8
  const fs_1 = __importDefault(require("fs"));
9
- const sampleYaml = `
10
- # non-crd should be ignored
11
- apiVersion: v1
12
- kind: ConfigMap
13
- metadata:
14
- name: test
15
- namespace: default
16
- data:
17
- any: bleh
18
- ---
19
- apiVersion: apiextensions.k8s.io/v1
20
- kind: CustomResourceDefinition
21
- metadata:
22
- name: movies.example.com
23
- spec:
24
- group: example.com
25
- names:
26
- kind: Movie
27
- plural: movies
28
- scope: Namespaced
29
- versions:
30
- - name: v1
31
- schema:
32
- openAPIV3Schema:
33
- type: object
34
- description: Movie nerd
35
- properties:
36
- spec:
37
- properties:
38
- title:
39
- type: string
40
- author:
41
- type: string
42
- type: object
43
- ---
44
- # duplicate entries should not break things
45
- apiVersion: apiextensions.k8s.io/v1
46
- kind: CustomResourceDefinition
47
- metadata:
48
- name: movies.example.com
49
- spec:
50
- group: example.com
51
- names:
52
- kind: Movie
53
- plural: movies
54
- scope: Namespaced
55
- versions:
56
- - name: v1
57
- schema:
58
- openAPIV3Schema:
59
- type: object
60
- description: Movie nerd
61
- properties:
62
- spec:
63
- properties:
64
- title:
65
- type: string
66
- author:
67
- type: string
68
- type: object
69
- ---
70
- # should support multiple versions
71
- apiVersion: apiextensions.k8s.io/v1
72
- kind: CustomResourceDefinition
73
- metadata:
74
- name: books.example.com
75
- spec:
76
- group: example.com
77
- names:
78
- kind: Book
79
- plural: books
80
- scope: Namespaced
81
- versions:
82
- - name: v1
83
- schema:
84
- openAPIV3Schema:
85
- type: object
86
- description: Book nerd
87
- properties:
88
- spec:
89
- properties:
90
- title:
91
- type: string
92
- author:
93
- type: string
94
- type: object
95
- - name: v2
96
- schema:
97
- openAPIV3Schema:
98
- type: object
99
- description: Book nerd
100
- properties:
101
- spec:
102
- properties:
103
- author:
104
- type: string
105
- type: object
106
- served: true
107
- storage: true
108
- `;
109
- globals_1.jest.mock("./fetch", () => ({
110
- fetch: globals_1.jest.fn(),
9
+ const path_1 = __importDefault(require("path"));
10
+ const quicktype_core_1 = require("quicktype-core");
11
+ const fetch_1 = require("./fetch");
12
+ const client_node_1 = require("@kubernetes/client-node");
13
+ const fluent_1 = require("./fluent");
14
+ const upstream_1 = require("./upstream");
15
+ // Mock the file system
16
+ globals_1.jest.mock("fs", () => ({
17
+ ...globals_1.jest.requireActual("fs"), // Preserve the rest of the fs module
18
+ writeFileSync: globals_1.jest.fn(), // Mock only writeFileSync
19
+ existsSync: globals_1.jest.fn(),
20
+ readFileSync: globals_1.jest.fn(),
111
21
  }));
22
+ globals_1.jest.mock("./fetch");
23
+ globals_1.jest.mock("quicktype-core", () => {
24
+ const actualQuicktypeCore = globals_1.jest.requireActual("quicktype-core");
25
+ return {
26
+ quicktype: globals_1.jest.fn(),
27
+ JSONSchemaInput: actualQuicktypeCore.JSONSchemaInput,
28
+ FetchingJSONSchemaStore: actualQuicktypeCore.FetchingJSONSchemaStore,
29
+ InputData: actualQuicktypeCore.InputData,
30
+ };
31
+ });
32
+ globals_1.jest.mock("@kubernetes/client-node", () => {
33
+ const actualModule = globals_1.jest.requireActual("@kubernetes/client-node");
34
+ return {
35
+ ...(typeof actualModule === "object" ? actualModule : {}),
36
+ loadAllYaml: globals_1.jest.fn(), // Mock only the specific method
37
+ };
38
+ });
112
39
  globals_1.jest.mock("./fluent", () => ({
113
40
  K8s: globals_1.jest.fn(),
114
41
  }));
42
+ globals_1.jest.mock("./generate", () => {
43
+ const actualGenerate = globals_1.jest.requireActual("./generate");
44
+ return {
45
+ ...(typeof actualGenerate === "object" ? actualGenerate : {}),
46
+ resolveFilePath: globals_1.jest.fn(), // Mock resolveFilePath globally
47
+ tryParseUrl: globals_1.jest.fn(),
48
+ };
49
+ });
50
+ // Sample CRD content to use in tests
51
+ const sampleCrd = {
52
+ apiVersion: "apiextensions.k8s.io/v1",
53
+ kind: "CustomResourceDefinition",
54
+ metadata: { name: "movies.example.com" },
55
+ spec: {
56
+ group: "example.com",
57
+ names: { kind: "Movie", plural: "movies" },
58
+ scope: "Namespaced",
59
+ versions: [
60
+ {
61
+ name: "v1",
62
+ served: true,
63
+ storage: true,
64
+ schema: {
65
+ openAPIV3Schema: {
66
+ type: "object",
67
+ description: "Movie nerd",
68
+ properties: {
69
+ spec: {
70
+ properties: {
71
+ title: { type: "string" },
72
+ author: { type: "string" },
73
+ },
74
+ },
75
+ },
76
+ },
77
+ },
78
+ },
79
+ ],
80
+ },
81
+ };
82
+ const expectedMovie = [
83
+ "/**",
84
+ " * Movie nerd",
85
+ " */",
86
+ "export interface Movie {",
87
+ " spec?: any[] | boolean | number | number | null | SpecObject | string;",
88
+ " [property: string]: any;",
89
+ "}",
90
+ "",
91
+ "export interface SpecObject {",
92
+ " author?: string;",
93
+ " title?: string;",
94
+ " [property: string]: any;",
95
+ "}",
96
+ "",
97
+ ];
115
98
  (0, globals_1.describe)("CRD Generate", () => {
116
- const originalReadFileSync = fs_1.default.readFileSync;
117
- globals_1.jest.spyOn(fs_1.default, "existsSync").mockReturnValue(true);
118
- globals_1.jest.spyOn(fs_1.default, "readFileSync").mockImplementation((...args) => {
119
- // Super janky hack due ot source-map-support calling readFileSync internally
120
- if (args[0].toString().includes("test-crd.yaml")) {
121
- return sampleYaml;
122
- }
123
- return originalReadFileSync(...args);
99
+ let logFn; // Mock log function
100
+ (0, globals_1.beforeEach)(() => {
101
+ globals_1.jest.clearAllMocks(); // Reset all mocks before each test
102
+ logFn = globals_1.jest.fn(); // Mock the log function with correct typing
124
103
  });
125
- const mkdirSyncSpy = globals_1.jest.spyOn(fs_1.default, "mkdirSync").mockReturnValue(undefined);
126
- const writeFileSyncSpy = globals_1.jest.spyOn(fs_1.default, "writeFileSync").mockReturnValue(undefined);
104
+ (0, globals_1.test)("convertCRDtoTS should generate the expected TypeScript file", async () => {
105
+ // Mock convertCRDtoTS to return a valid result structure
106
+ quicktype_core_1.quicktype.mockResolvedValueOnce({
107
+ lines: expectedMovie,
108
+ annotations: [],
109
+ });
110
+ const options = {
111
+ source: "test-crd.yaml",
112
+ language: "ts",
113
+ logFn,
114
+ directory: "test-dir",
115
+ plain: false,
116
+ npmPackage: "kubernetes-fluent-client",
117
+ };
118
+ // Call convertCRDtoTS with sample CRD
119
+ const result = await (0, generate_1.convertCRDtoTS)(sampleCrd, options);
120
+ // Extract the generated types from the result
121
+ const generatedTypes = result[0].results["movie-v1"];
122
+ // Assert that the generated types match the expected TypeScript code
123
+ (0, globals_1.expect)(generatedTypes).toEqual(expectedMovie);
124
+ // Assert the file writing happens with the expected TypeScript content
125
+ (0, globals_1.expect)(fs_1.default.writeFileSync).toHaveBeenCalledWith(path_1.default.join("test-dir", "movie-v1.ts"), expectedMovie.join("\n"));
126
+ // Assert the logs contain expected log messages
127
+ (0, globals_1.expect)(logFn).toHaveBeenCalledWith("- Generating example.com/v1 types for Movie");
128
+ });
129
+ });
130
+ (0, globals_1.describe)("readOrFetchCrd", () => {
131
+ let mockOpts;
127
132
  (0, globals_1.beforeEach)(() => {
128
133
  globals_1.jest.clearAllMocks();
134
+ mockOpts = {
135
+ source: "mock-file-path",
136
+ logFn: globals_1.jest.fn(),
137
+ };
138
+ // Reapply mock for resolveFilePath inside beforeEach
139
+ const { resolveFilePath } = globals_1.jest.requireMock("./generate");
140
+ resolveFilePath.mockReturnValue("mock-file-path");
141
+ });
142
+ (0, globals_1.test)("should load CRD from a local file", async () => {
143
+ // Inside the test:
144
+ const absoluteFilePath = path_1.default.join(process.cwd(), "mock-file-path");
145
+ // Mock file system functions
146
+ fs_1.default.existsSync.mockReturnValue(true);
147
+ fs_1.default.readFileSync.mockReturnValue("mock file content");
148
+ // Mock loadAllYaml to return parsed CRD
149
+ const mockCrd = [{ kind: "CustomResourceDefinition" }];
150
+ client_node_1.loadAllYaml.mockReturnValue(mockCrd);
151
+ // Call the function
152
+ const result = await (0, generate_1.readOrFetchCrd)(mockOpts);
153
+ // Assert fs and loadAllYaml were called with correct args
154
+ (0, globals_1.expect)(fs_1.default.existsSync).toHaveBeenCalledWith(absoluteFilePath);
155
+ (0, globals_1.expect)(fs_1.default.readFileSync).toHaveBeenCalledWith(absoluteFilePath, "utf8");
156
+ (0, globals_1.expect)(client_node_1.loadAllYaml).toHaveBeenCalledWith("mock file content");
157
+ // Assert the result matches the mocked CRD
158
+ (0, globals_1.expect)(result).toEqual(mockCrd);
159
+ // Assert log function was called with correct message
160
+ (0, globals_1.expect)(mockOpts.logFn).toHaveBeenCalledWith("Attempting to load mock-file-path as a local file");
129
161
  });
130
- (0, globals_1.test)("converts CRD to TypeScript", async () => {
131
- const options = { source: "test-crd.yaml", language: "ts", logFn: globals_1.jest.fn() };
132
- const actual = await (0, generate_1.generate)(options);
133
- const expectedMovie = [
134
- "// This file is auto-generated by kubernetes-fluent-client, do not edit manually\n",
135
- 'import { GenericKind, RegisterKind } from "kubernetes-fluent-client";\n',
136
- "/**",
137
- " * Movie nerd",
138
- " */",
139
- "export class Movie extends GenericKind {",
140
- " spec?: Spec;",
141
- "}",
142
- "",
143
- "export interface Spec {",
144
- " author?: string;",
145
- " title?: string;",
146
- "}",
147
- "",
148
- "RegisterKind(Movie, {",
149
- ' group: "example.com",',
150
- ' version: "v1",',
151
- ' kind: "Movie",',
152
- ' plural: "movies",',
153
- "});",
154
- ];
155
- const expectedBookV1 = [
156
- "// This file is auto-generated by kubernetes-fluent-client, do not edit manually\n",
157
- 'import { GenericKind, RegisterKind } from "kubernetes-fluent-client";\n',
158
- "/**",
159
- " * Book nerd",
160
- " */",
161
- "export class Book extends GenericKind {",
162
- " spec?: Spec;",
163
- "}",
164
- "",
165
- "export interface Spec {",
166
- " author?: string;",
167
- " title?: string;",
168
- "}",
169
- "",
170
- "RegisterKind(Book, {",
171
- ' group: "example.com",',
172
- ' version: "v1",',
173
- ' kind: "Book",',
174
- ' plural: "books",',
175
- "});",
176
- ];
177
- const expectedBookV2 = expectedBookV1
178
- .filter(line => !line.includes("title?"))
179
- .map(line => line.replace("v1", "v2"));
180
- (0, globals_1.expect)(actual["movie-v1"]).toEqual(expectedMovie);
181
- (0, globals_1.expect)(actual["book-v1"]).toEqual(expectedBookV1);
182
- (0, globals_1.expect)(actual["book-v2"]).toEqual(expectedBookV2);
162
+ });
163
+ (0, globals_1.describe)("readOrFetchCrd with URL", () => {
164
+ let mockOpts;
165
+ (0, globals_1.beforeEach)(() => {
166
+ globals_1.jest.clearAllMocks();
167
+ mockOpts = {
168
+ source: "http://example.com/mock-crd",
169
+ logFn: globals_1.jest.fn(),
170
+ };
171
+ // Mock resolveFilePath to simulate URL logic
172
+ const { resolveFilePath } = globals_1.jest.requireMock("./generate");
173
+ resolveFilePath.mockReturnValue("mock-file-path");
174
+ // Ensure fs.existsSync returns false for URL tests to skip file logic
175
+ fs_1.default.existsSync.mockReturnValue(false);
183
176
  });
184
- (0, globals_1.test)("converts CRD to TypeScript with plain option", async () => {
185
- const options = { source: "test-crd.yaml", language: "ts", plain: true, logFn: globals_1.jest.fn() };
186
- const actual = await (0, generate_1.generate)(options);
187
- const expectedMovie = [
188
- "/**",
189
- " * Movie nerd",
190
- " */",
191
- "export interface Movie {",
192
- " spec?: Spec;",
193
- "}",
194
- "",
195
- "export interface Spec {",
196
- " author?: string;",
197
- " title?: string;",
198
- "}",
199
- "",
200
- ];
201
- const expectedBookV1 = [
202
- "/**",
203
- " * Book nerd",
204
- " */",
205
- "export interface Book {",
206
- " spec?: Spec;",
207
- "}",
208
- "",
209
- "export interface Spec {",
210
- " author?: string;",
211
- " title?: string;",
212
- "}",
213
- "",
214
- ];
215
- const expectedBookV2 = expectedBookV1
216
- .filter(line => !line.includes("title?"))
217
- .map(line => line.replace("v1", "v2"));
218
- (0, globals_1.expect)(actual["movie-v1"]).toEqual(expectedMovie);
219
- (0, globals_1.expect)(actual["book-v1"]).toEqual(expectedBookV1);
220
- (0, globals_1.expect)(actual["book-v2"]).toEqual(expectedBookV2);
177
+ (0, globals_1.test)("should fetch CRD from a URL and parse YAML", async () => {
178
+ const { tryParseUrl } = globals_1.jest.requireMock("./generate");
179
+ tryParseUrl.mockReturnValue(new URL("http://example.com/mock-crd"));
180
+ // Mock fetch to return a valid response
181
+ fetch_1.fetch.mockResolvedValue({
182
+ ok: true,
183
+ data: "mock fetched data",
184
+ status: 0,
185
+ statusText: "",
186
+ });
187
+ // Mock loadAllYaml to return parsed CRD
188
+ const mockCrd = [{ kind: "CustomResourceDefinition" }];
189
+ client_node_1.loadAllYaml.mockReturnValue(mockCrd);
190
+ // Call the function
191
+ const result = await (0, generate_1.readOrFetchCrd)(mockOpts);
192
+ // Assert fetch was called with correct URL
193
+ (0, globals_1.expect)(fetch_1.fetch).toHaveBeenCalledWith("http://example.com/mock-crd");
194
+ // Assert loadAllYaml was called with fetched data
195
+ (0, globals_1.expect)(client_node_1.loadAllYaml).toHaveBeenCalledWith("mock fetched data");
196
+ // Assert the result matches the mocked CRD
197
+ (0, globals_1.expect)(result).toEqual(mockCrd);
198
+ // Assert log function was called with correct message
199
+ (0, globals_1.expect)(mockOpts.logFn).toHaveBeenCalledWith("Attempting to load http://example.com/mock-crd as a URL");
221
200
  });
222
- (0, globals_1.test)("converts CRD to TypeScript with other options", async () => {
223
- const options = {
224
- source: "test-crd.yaml",
225
- npmPackage: "test-package",
201
+ });
202
+ (0, globals_1.describe)("readOrFetchCrd from Kubernetes cluster", () => {
203
+ let mockOpts;
204
+ (0, globals_1.beforeEach)(() => {
205
+ globals_1.jest.clearAllMocks();
206
+ mockOpts = {
207
+ source: "my-crd",
226
208
  logFn: globals_1.jest.fn(),
227
209
  };
228
- const actual = await (0, generate_1.generate)(options);
229
- const expectedMovie = [
230
- "// This file is auto-generated by test-package, do not edit manually\n",
231
- 'import { GenericKind, RegisterKind } from "test-package";\n',
232
- "/**",
233
- " * Movie nerd",
234
- " */",
235
- "export class Movie extends GenericKind {",
236
- " spec?: Spec;",
237
- "}",
238
- "",
239
- "export interface Spec {",
240
- " author?: string;",
241
- " title?: string;",
242
- "}",
243
- "",
244
- "RegisterKind(Movie, {",
245
- ' group: "example.com",',
246
- ' version: "v1",',
247
- ' kind: "Movie",',
248
- ' plural: "movies",',
249
- "});",
250
- ];
251
- const expectedBookV1 = [
252
- "// This file is auto-generated by test-package, do not edit manually\n",
253
- 'import { GenericKind, RegisterKind } from "test-package";\n',
254
- "/**",
255
- " * Book nerd",
256
- " */",
257
- "export class Book extends GenericKind {",
258
- " spec?: Spec;",
259
- "}",
260
- "",
261
- "export interface Spec {",
262
- " author?: string;",
263
- " title?: string;",
264
- "}",
265
- "",
266
- "RegisterKind(Book, {",
267
- ' group: "example.com",',
268
- ' version: "v1",',
269
- ' kind: "Book",',
270
- ' plural: "books",',
271
- "});",
272
- ];
273
- const expectedBookV2 = expectedBookV1
274
- .filter(line => !line.includes("title?"))
275
- .map(line => line.replace("v1", "v2"));
276
- (0, globals_1.expect)(actual["movie-v1"]).toEqual(expectedMovie);
277
- (0, globals_1.expect)(actual["book-v1"]).toEqual(expectedBookV1);
278
- (0, globals_1.expect)(actual["book-v2"]).toEqual(expectedBookV2);
210
+ // Mock resolveFilePath and tryParseUrl to return null or invalid results
211
+ const { resolveFilePath, tryParseUrl } = globals_1.jest.requireMock("./generate");
212
+ resolveFilePath.mockReturnValue("mock-file-path");
213
+ tryParseUrl.mockReturnValue(null);
214
+ // Ensure fs.existsSync returns false to force fallback to Kubernetes
215
+ fs_1.default.existsSync.mockReturnValue(false);
279
216
  });
280
- (0, globals_1.test)("converts CRD to TypeScript and writes to the given directory", async () => {
281
- const options = {
282
- source: "test-crd.yaml",
283
- directory: "test",
217
+ (0, globals_1.test)("should load CRD from Kubernetes cluster", async () => {
218
+ // Mock K8s to return a mocked CRD from the Kubernetes cluster
219
+ const mockCrd = { kind: "CustomResourceDefinition" };
220
+ const mockK8sGet = globals_1.jest
221
+ .fn()
222
+ .mockResolvedValue(mockCrd);
223
+ fluent_1.K8s.mockReturnValue({ Get: mockK8sGet });
224
+ // Call the function
225
+ const result = await (0, generate_1.readOrFetchCrd)(mockOpts);
226
+ // Assert K8s.Get was called with the correct source
227
+ (0, globals_1.expect)(fluent_1.K8s).toHaveBeenCalledWith(upstream_1.CustomResourceDefinition);
228
+ (0, globals_1.expect)(mockK8sGet).toHaveBeenCalledWith("my-crd");
229
+ // Assert the result matches the mocked CRD
230
+ (0, globals_1.expect)(result).toEqual([mockCrd]);
231
+ // Assert log function was called with correct message
232
+ (0, globals_1.expect)(mockOpts.logFn).toHaveBeenCalledWith("Attempting to read my-crd from the Kubernetes cluster");
233
+ });
234
+ (0, globals_1.test)("should log an error if Kubernetes cluster read fails", async () => {
235
+ // Mock K8s to throw an error
236
+ const mockError = new Error("Kubernetes API error");
237
+ const mockK8sGet = globals_1.jest.fn().mockRejectedValue(mockError);
238
+ fluent_1.K8s.mockReturnValue({ Get: mockK8sGet });
239
+ // Call the function and assert that it throws an error
240
+ await (0, globals_1.expect)((0, generate_1.readOrFetchCrd)(mockOpts)).rejects.toThrowError(`Failed to read my-crd as a file, URL, or Kubernetes CRD`);
241
+ // Assert log function was called with error message
242
+ (0, globals_1.expect)(mockOpts.logFn).toHaveBeenCalledWith("Error loading CRD: Kubernetes API error");
243
+ // Assert K8s.Get was called with the correct source
244
+ (0, globals_1.expect)(fluent_1.K8s).toHaveBeenCalledWith(upstream_1.CustomResourceDefinition);
245
+ (0, globals_1.expect)(mockK8sGet).toHaveBeenCalledWith("my-crd");
246
+ });
247
+ });
248
+ (0, globals_1.describe)("readOrFetchCrd error handling", () => {
249
+ let mockOpts;
250
+ (0, globals_1.beforeEach)(() => {
251
+ globals_1.jest.clearAllMocks();
252
+ mockOpts = {
253
+ source: "mock-source",
284
254
  logFn: globals_1.jest.fn(),
285
255
  };
286
- await (0, generate_1.generate)(options);
287
- const expectedMovie = [
288
- "// This file is auto-generated by kubernetes-fluent-client, do not edit manually\n",
289
- 'import { GenericKind, RegisterKind } from "kubernetes-fluent-client";\n',
290
- "/**",
291
- " * Movie nerd",
292
- " */",
293
- "export class Movie extends GenericKind {",
294
- " spec?: Spec;",
295
- "}",
296
- "",
297
- "export interface Spec {",
298
- " author?: string;",
299
- " title?: string;",
300
- "}",
301
- "",
302
- "RegisterKind(Movie, {",
303
- ' group: "example.com",',
304
- ' version: "v1",',
305
- ' kind: "Movie",',
306
- ' plural: "movies",',
307
- "});",
308
- ];
309
- const expectedBookV1 = [
310
- "// This file is auto-generated by kubernetes-fluent-client, do not edit manually\n",
311
- 'import { GenericKind, RegisterKind } from "kubernetes-fluent-client";\n',
312
- "/**",
313
- " * Book nerd",
314
- " */",
315
- "export class Book extends GenericKind {",
316
- " spec?: Spec;",
317
- "}",
318
- "",
319
- "export interface Spec {",
320
- " author?: string;",
321
- " title?: string;",
322
- "}",
323
- "",
324
- "RegisterKind(Book, {",
325
- ' group: "example.com",',
326
- ' version: "v1",',
327
- ' kind: "Book",',
328
- ' plural: "books",',
329
- "});",
330
- ];
331
- const expectedBookV2 = expectedBookV1
332
- .filter(line => !line.includes("title?"))
333
- .map(line => line.replace("v1", "v2"));
334
- (0, globals_1.expect)(mkdirSyncSpy).toHaveBeenCalledWith("test", { recursive: true });
335
- (0, globals_1.expect)(writeFileSyncSpy).toHaveBeenCalledWith("test/movie-v1.ts", expectedMovie.join("\n"));
336
- (0, globals_1.expect)(writeFileSyncSpy).toHaveBeenCalledWith("test/book-v1.ts", expectedBookV1.join("\n"));
337
- (0, globals_1.expect)(writeFileSyncSpy).toHaveBeenCalledWith("test/book-v2.ts", expectedBookV2.join("\n"));
338
256
  });
339
- (0, globals_1.test)("converts CRD to Go", async () => {
340
- const options = { source: "test-crd.yaml", language: "go", logFn: globals_1.jest.fn() };
341
- const actual = await (0, generate_1.generate)(options);
342
- const expectedMovie = [
343
- "// Movie nerd",
344
- "type Movie struct {",
345
- '\tSpec *Spec `json:"spec,omitempty"`',
346
- "}",
347
- "",
348
- "type Spec struct {",
349
- '\tAuthor *string `json:"author,omitempty"`',
350
- '\tTitle *string `json:"title,omitempty"`',
351
- "}",
352
- "",
353
- ];
354
- const expectedBookV1 = [
355
- "// Book nerd",
356
- "type Book struct {",
357
- '\tSpec *Spec `json:"spec,omitempty"`',
358
- "}",
359
- "",
360
- "type Spec struct {",
361
- '\tAuthor *string `json:"author,omitempty"`',
362
- '\tTitle *string `json:"title,omitempty"`',
363
- "}",
364
- "",
365
- ];
366
- const expectedBookV2 = expectedBookV1
367
- .filter(line => !line.includes("Title"))
368
- .map(line => line.replace("v1", "v2"));
369
- (0, globals_1.expect)(actual["movie-v1"]).toEqual(expectedMovie);
370
- (0, globals_1.expect)(actual["book-v1"]).toEqual(expectedBookV1);
371
- (0, globals_1.expect)(actual["book-v2"]).toEqual(expectedBookV2);
257
+ (0, globals_1.test)("should throw an error if file reading fails", async () => {
258
+ fs_1.default.existsSync.mockReturnValue(true);
259
+ fs_1.default.readFileSync.mockImplementation(() => {
260
+ throw new Error("File read error");
261
+ });
262
+ await (0, globals_1.expect)((0, generate_1.readOrFetchCrd)(mockOpts)).rejects.toThrowError("Failed to read mock-source as a file, URL, or Kubernetes CRD");
263
+ (0, globals_1.expect)(mockOpts.logFn).toHaveBeenCalledWith("Error loading CRD: File read error");
264
+ });
265
+ });
266
+ (0, globals_1.describe)("convertCRDtoTS with invalid CRD", () => {
267
+ (0, globals_1.test)("should skip CRD with no versions", async () => {
268
+ const invalidCrd = {
269
+ ...sampleCrd,
270
+ spec: {
271
+ ...sampleCrd.spec,
272
+ versions: [], // CRD with no versions
273
+ },
274
+ };
275
+ const options = {
276
+ source: "mock-source",
277
+ language: "ts",
278
+ logFn: globals_1.jest.fn(), // Ensure the mock log function is set
279
+ directory: "test-dir",
280
+ plain: false,
281
+ npmPackage: "kubernetes-fluent-client",
282
+ };
283
+ const result = await (0, generate_1.convertCRDtoTS)(invalidCrd, options);
284
+ // Assert that result is empty due to invalid CRD
285
+ (0, globals_1.expect)(result).toEqual([]);
286
+ // Assert the log function is called with the correct message
287
+ (0, globals_1.expect)(options.logFn).toHaveBeenCalledWith("Skipping movies.example.com, it does not appear to be a CRD");
288
+ });
289
+ (0, globals_1.test)("should handle schema with no OpenAPI schema", async () => {
290
+ // Modify the sampleCrd to simulate the invalid CRD
291
+ const invalidCrd = {
292
+ ...sampleCrd,
293
+ spec: {
294
+ ...sampleCrd.spec,
295
+ versions: [
296
+ {
297
+ name: "v1",
298
+ served: true,
299
+ storage: true,
300
+ schema: undefined, // No OpenAPI schema
301
+ },
302
+ ],
303
+ },
304
+ };
305
+ const options = {
306
+ source: "mock-source",
307
+ language: "ts",
308
+ logFn: globals_1.jest.fn(), // Mock log function
309
+ directory: "test-dir",
310
+ plain: false,
311
+ npmPackage: "kubernetes-fluent-client",
312
+ };
313
+ // Call the convertCRDtoTS function with the invalid CRD
314
+ const result = await (0, generate_1.convertCRDtoTS)(invalidCrd, options);
315
+ // Assert that result is empty due to invalid schema
316
+ (0, globals_1.expect)(result).toEqual([]);
317
+ // Assert that the log function was called with the appropriate message
318
+ (0, globals_1.expect)(options.logFn).toHaveBeenCalledWith("Skipping movies.example.com, it does not appear to have a valid schema");
372
319
  });
373
320
  });