codify-plugin-test 0.0.14 → 0.0.15
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/.eslintrc.json +10 -3
- package/dist/plugin-tester.d.ts +12 -3
- package/dist/plugin-tester.js +59 -26
- package/dist/plugin-tester.js.map +1 -1
- package/package.json +2 -2
- package/src/plugin-tester.ts +88 -31
- package/test/plugin-tester.test.ts +1 -1
package/.eslintrc.json
CHANGED
|
@@ -9,9 +9,16 @@
|
|
|
9
9
|
"warn",
|
|
10
10
|
"always"
|
|
11
11
|
],
|
|
12
|
-
"perfectionist/sort-classes":
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
"perfectionist/sort-classes": "off",
|
|
13
|
+
"perfectionist/sort-interfaces": "off",
|
|
14
|
+
"perfectionist/sort-enums": "off",
|
|
15
|
+
"perfectionist/sort-objects": "off",
|
|
16
|
+
"perfectionist/sort-object-types": "off",
|
|
17
|
+
"unicorn/no-array-reduce": "off",
|
|
18
|
+
"unicorn/no-array-for-each": "off",
|
|
19
|
+
"unicorn/prefer-object-from-entries": "off",
|
|
20
|
+
"unicorn/prefer-type-error": "off",
|
|
21
|
+
"no-await-in-loop": "off",
|
|
15
22
|
"quotes": [
|
|
16
23
|
"error",
|
|
17
24
|
"single"
|
package/dist/plugin-tester.d.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
import { ApplyRequestData, InitializeResponseData, PlanRequestData, PlanResponseData, ResourceConfig, ValidateRequestData, ValidateResponseData } from 'codify-schemas';
|
|
1
|
+
import { ApplyRequestData, ImportRequestData, ImportResponseData, InitializeResponseData, PlanRequestData, PlanResponseData, ResourceConfig, ValidateRequestData, ValidateResponseData } from 'codify-schemas';
|
|
2
2
|
import { ChildProcess } from 'node:child_process';
|
|
3
3
|
export declare class PluginTester {
|
|
4
4
|
childProcess: ChildProcess;
|
|
5
5
|
constructor(pluginPath: string);
|
|
6
|
-
fullTest(configs: ResourceConfig[],
|
|
7
|
-
|
|
6
|
+
fullTest(configs: ResourceConfig[], { skipUninstall, ...options }: {
|
|
7
|
+
skipUninstall: boolean;
|
|
8
|
+
validatePlan?: (plans: PlanResponseData[]) => Promise<void> | void;
|
|
9
|
+
validateApply?: (plans: PlanResponseData[]) => Promise<void> | void;
|
|
10
|
+
validateDestroy?: (plans: PlanResponseData[]) => Promise<void> | void;
|
|
11
|
+
validateImport?: (importResults: (ImportResponseData['result'][0])[]) => Promise<void> | void;
|
|
12
|
+
}): Promise<void>;
|
|
13
|
+
uninstall(configs: ResourceConfig[], options: {
|
|
14
|
+
validateDestroy?: (plans: PlanResponseData[]) => Promise<void> | void;
|
|
15
|
+
}): Promise<void>;
|
|
8
16
|
initialize(): Promise<InitializeResponseData>;
|
|
9
17
|
validate(data: ValidateRequestData): Promise<ValidateResponseData>;
|
|
10
18
|
plan(data: PlanRequestData): Promise<PlanResponseData>;
|
|
11
19
|
apply(data: ApplyRequestData): Promise<void>;
|
|
20
|
+
import(data: ImportRequestData): Promise<ImportResponseData>;
|
|
12
21
|
kill(): void;
|
|
13
22
|
private handleSudoRequests;
|
|
14
23
|
}
|
package/dist/plugin-tester.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import Ajv from 'ajv';
|
|
2
|
-
import { IpcMessageSchema, MessageCmd,
|
|
2
|
+
import { IpcMessageSchema, MessageCmd, ResourceOperation, SpawnStatus, SudoRequestDataSchema } from 'codify-schemas';
|
|
3
3
|
import { fork, spawn } from 'node:child_process';
|
|
4
|
+
import inspector from 'node:inspector';
|
|
4
5
|
import path from 'node:path';
|
|
5
6
|
import { CodifyTestUtils } from './test-utils.js';
|
|
6
|
-
import inspector from 'node:inspector';
|
|
7
7
|
const ajv = new Ajv.default({
|
|
8
8
|
strict: true
|
|
9
9
|
});
|
|
@@ -15,14 +15,16 @@ export class PluginTester {
|
|
|
15
15
|
if (!path.isAbsolute(pluginPath)) {
|
|
16
16
|
throw new Error('A fully qualified path must be supplied to PluginTester');
|
|
17
17
|
}
|
|
18
|
+
console.log('Node Inspector:');
|
|
19
|
+
console.log(inspector.url());
|
|
18
20
|
this.childProcess = fork(pluginPath, [], {
|
|
19
21
|
detached: true,
|
|
20
22
|
env: { ...process.env },
|
|
21
|
-
execArgv: ['--import', 'tsx/esm',
|
|
23
|
+
execArgv: ['--import', 'tsx/esm', '--inspect=9221'],
|
|
22
24
|
});
|
|
23
25
|
this.handleSudoRequests(this.childProcess);
|
|
24
26
|
}
|
|
25
|
-
async fullTest(configs,
|
|
27
|
+
async fullTest(configs, { skipUninstall = false, ...options }) {
|
|
26
28
|
const initializeResult = await this.initialize();
|
|
27
29
|
const unsupportedConfigs = configs.filter((c) => !initializeResult.resourceDefinitions.some((rd) => rd.type === c.type));
|
|
28
30
|
if (unsupportedConfigs.length > 0) {
|
|
@@ -41,8 +43,8 @@ export class PluginTester {
|
|
|
41
43
|
state: undefined,
|
|
42
44
|
}));
|
|
43
45
|
}
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
+
if (options.validatePlan) {
|
|
47
|
+
await options.validatePlan(plans);
|
|
46
48
|
}
|
|
47
49
|
for (const plan of plans) {
|
|
48
50
|
await this.apply({
|
|
@@ -62,35 +64,63 @@ export class PluginTester {
|
|
|
62
64
|
throw new Error(`The following applies were not successful. Re-running plan shows that the resources did not return no-op but instead returned:
|
|
63
65
|
${JSON.stringify(unsuccessfulPlans, null, 2)}`);
|
|
64
66
|
}
|
|
67
|
+
if (options.validateApply) {
|
|
68
|
+
await options.validateApply(plans);
|
|
69
|
+
}
|
|
70
|
+
const importResults = [];
|
|
71
|
+
const unsuccessfulImports = [];
|
|
72
|
+
for (const config of configs) {
|
|
73
|
+
const importResult = await this.import({ config });
|
|
74
|
+
importResults.push(importResult);
|
|
75
|
+
if (importResult.result.length !== 1 ||
|
|
76
|
+
Object.entries(config).some(([k, v]) => importResult.result[0][k] !== v)) {
|
|
77
|
+
unsuccessfulImports.push(importResult);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (unsuccessfulImports.length > 0) {
|
|
81
|
+
throw new Error(`The following imports were not successful. The imports differed from the original.
|
|
82
|
+
${JSON.stringify(unsuccessfulImports, null, 2)}`);
|
|
83
|
+
}
|
|
84
|
+
if (options.validateImport) {
|
|
85
|
+
await options.validateImport(importResults.map((r) => r.result[0]));
|
|
86
|
+
}
|
|
87
|
+
if (!skipUninstall) {
|
|
88
|
+
await this.uninstall(configs.toReversed(), options);
|
|
89
|
+
}
|
|
65
90
|
}
|
|
66
|
-
async uninstall(configs) {
|
|
91
|
+
async uninstall(configs, options) {
|
|
92
|
+
const plans = [];
|
|
67
93
|
for (const config of configs) {
|
|
68
|
-
|
|
94
|
+
plans.push(await this.plan({
|
|
95
|
+
desired: undefined,
|
|
96
|
+
isStateful: true,
|
|
97
|
+
state: config
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
for (const plan of plans) {
|
|
101
|
+
if (plan.operation !== ResourceOperation.DESTROY) {
|
|
102
|
+
throw new Error(`Expect resource operation to be 'destory' but instead received plan: \n ${JSON.stringify(plan, null, 2)}`);
|
|
103
|
+
}
|
|
69
104
|
await this.apply({
|
|
70
|
-
|
|
71
|
-
operation: ResourceOperation.DESTROY,
|
|
72
|
-
parameters: Object.entries(parameters).map(([key, value]) => ({
|
|
73
|
-
name: key,
|
|
74
|
-
newValue: null,
|
|
75
|
-
operation: ParameterOperation.REMOVE,
|
|
76
|
-
previousValue: value,
|
|
77
|
-
})),
|
|
78
|
-
resourceType: type,
|
|
79
|
-
}
|
|
105
|
+
planId: plan.planId
|
|
80
106
|
});
|
|
107
|
+
}
|
|
108
|
+
for (const config of configs) {
|
|
81
109
|
const validationPlan = await this.plan({
|
|
82
110
|
desired: config,
|
|
83
|
-
|
|
84
|
-
|
|
111
|
+
isStateful: true,
|
|
112
|
+
state: undefined
|
|
85
113
|
});
|
|
86
114
|
if (validationPlan.operation !== ResourceOperation.CREATE) {
|
|
87
|
-
throw new Error(`Resource
|
|
115
|
+
throw new Error(`Resource was not successfully destroyed.
|
|
88
116
|
Validation plan shows:
|
|
89
117
|
${JSON.stringify(validationPlan, null, 2)}
|
|
90
|
-
|
|
91
|
-
${JSON.stringify(config, null, 2)}`);
|
|
118
|
+
`);
|
|
92
119
|
}
|
|
93
120
|
}
|
|
121
|
+
if (options.validateDestroy) {
|
|
122
|
+
await options.validateDestroy(plans);
|
|
123
|
+
}
|
|
94
124
|
}
|
|
95
125
|
async initialize() {
|
|
96
126
|
return CodifyTestUtils.sendMessageAndAwaitResponse(this.childProcess, {
|
|
@@ -116,6 +146,12 @@ ${JSON.stringify(config, null, 2)}`);
|
|
|
116
146
|
data,
|
|
117
147
|
});
|
|
118
148
|
}
|
|
149
|
+
async import(data) {
|
|
150
|
+
return CodifyTestUtils.sendMessageAndAwaitResponse(this.childProcess, {
|
|
151
|
+
cmd: 'import',
|
|
152
|
+
data,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
119
155
|
kill() {
|
|
120
156
|
this.childProcess.kill();
|
|
121
157
|
}
|
|
@@ -168,7 +204,4 @@ async function sudoSpawn(cmd, opts) {
|
|
|
168
204
|
});
|
|
169
205
|
});
|
|
170
206
|
}
|
|
171
|
-
function isInDebugMode() {
|
|
172
|
-
return inspector.url() !== undefined;
|
|
173
|
-
}
|
|
174
207
|
//# sourceMappingURL=plugin-tester.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-tester.js","sourceRoot":"","sources":["../src/plugin-tester.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAGL,gBAAgB,EAChB,UAAU,
|
|
1
|
+
{"version":3,"file":"plugin-tester.js","sourceRoot":"","sources":["../src/plugin-tester.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codify-plugin-test",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"ajv": "^8.12.0",
|
|
17
17
|
"ajv-formats": "^3.0.1",
|
|
18
|
-
"codify-schemas": "1.0.
|
|
18
|
+
"codify-schemas": "1.0.52"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@oclif/prettier-config": "^0.2.1",
|
package/src/plugin-tester.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import Ajv from 'ajv';
|
|
2
2
|
import {
|
|
3
|
-
ApplyRequestData,
|
|
3
|
+
ApplyRequestData, ImportRequestData, ImportRequestDataSchema, ImportResponseData,
|
|
4
4
|
InitializeResponseData,
|
|
5
5
|
IpcMessageSchema,
|
|
6
6
|
MessageCmd,
|
|
7
|
-
ParameterOperation,
|
|
8
7
|
PlanRequestData,
|
|
9
8
|
PlanResponseData,
|
|
10
9
|
ResourceConfig,
|
|
@@ -16,10 +15,10 @@ import {
|
|
|
16
15
|
ValidateResponseData
|
|
17
16
|
} from 'codify-schemas';
|
|
18
17
|
import { ChildProcess, SpawnOptions, fork, spawn } from 'node:child_process';
|
|
18
|
+
import inspector from 'node:inspector'
|
|
19
19
|
import path from 'node:path';
|
|
20
20
|
|
|
21
21
|
import { CodifyTestUtils } from './test-utils.js';
|
|
22
|
-
import inspector from 'node:inspector';
|
|
23
22
|
|
|
24
23
|
const ajv = new Ajv.default({
|
|
25
24
|
strict: true
|
|
@@ -27,6 +26,7 @@ const ajv = new Ajv.default({
|
|
|
27
26
|
const ipcMessageValidator = ajv.compile(IpcMessageSchema);
|
|
28
27
|
const sudoRequestValidator = ajv.compile(SudoRequestDataSchema);
|
|
29
28
|
|
|
29
|
+
|
|
30
30
|
export class PluginTester {
|
|
31
31
|
childProcess: ChildProcess
|
|
32
32
|
|
|
@@ -40,6 +40,9 @@ export class PluginTester {
|
|
|
40
40
|
throw new Error('A fully qualified path must be supplied to PluginTester');
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
console.log('Node Inspector:')
|
|
44
|
+
console.log(inspector.url());
|
|
45
|
+
|
|
43
46
|
this.childProcess = fork(
|
|
44
47
|
pluginPath,
|
|
45
48
|
[],
|
|
@@ -47,14 +50,26 @@ export class PluginTester {
|
|
|
47
50
|
// Use default true to test plugins in secure mode (un-able to request sudo directly)
|
|
48
51
|
detached: true,
|
|
49
52
|
env: { ...process.env },
|
|
50
|
-
execArgv: ['--import', 'tsx/esm',
|
|
53
|
+
execArgv: ['--import', 'tsx/esm', '--inspect=9221'],
|
|
51
54
|
},
|
|
52
55
|
)
|
|
53
56
|
|
|
54
57
|
this.handleSudoRequests(this.childProcess);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
async fullTest(
|
|
60
|
+
async fullTest(
|
|
61
|
+
configs: ResourceConfig[],
|
|
62
|
+
{
|
|
63
|
+
skipUninstall = false,
|
|
64
|
+
...options
|
|
65
|
+
}: {
|
|
66
|
+
skipUninstall: boolean,
|
|
67
|
+
validatePlan?: (plans: PlanResponseData[]) => Promise<void> | void
|
|
68
|
+
validateApply?: (plans: PlanResponseData[]) => Promise<void> | void,
|
|
69
|
+
validateDestroy?: (plans: PlanResponseData[]) => Promise<void> | void,
|
|
70
|
+
validateImport?: (importResults: (ImportResponseData['result'][0])[]) => Promise<void> | void,
|
|
71
|
+
}): Promise<void> {
|
|
72
|
+
|
|
58
73
|
const initializeResult = await this.initialize();
|
|
59
74
|
|
|
60
75
|
const unsupportedConfigs = configs.filter((c) =>
|
|
@@ -80,8 +95,8 @@ export class PluginTester {
|
|
|
80
95
|
}));
|
|
81
96
|
}
|
|
82
97
|
|
|
83
|
-
if (
|
|
84
|
-
|
|
98
|
+
if (options.validatePlan) {
|
|
99
|
+
await options.validatePlan(plans);
|
|
85
100
|
}
|
|
86
101
|
|
|
87
102
|
for (const plan of plans) {
|
|
@@ -106,40 +121,79 @@ export class PluginTester {
|
|
|
106
121
|
${JSON.stringify(unsuccessfulPlans, null, 2)}`
|
|
107
122
|
)
|
|
108
123
|
}
|
|
124
|
+
|
|
125
|
+
if (options.validateApply) {
|
|
126
|
+
await options.validateApply(plans);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const importResults = [];
|
|
130
|
+
const unsuccessfulImports = [];
|
|
131
|
+
for (const config of configs) {
|
|
132
|
+
const importResult = await this.import({ config })
|
|
133
|
+
importResults.push(importResult);
|
|
134
|
+
|
|
135
|
+
if (importResult.result.length !== 1 ||
|
|
136
|
+
Object.entries(config).some(([k, v]) => importResult.result[0][k] !== v)
|
|
137
|
+
) {
|
|
138
|
+
unsuccessfulImports.push(importResult);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (unsuccessfulImports.length > 0) {
|
|
143
|
+
throw new Error(`The following imports were not successful. The imports differed from the original.
|
|
144
|
+
${JSON.stringify(unsuccessfulImports, null, 2)}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (options.validateImport) {
|
|
148
|
+
await options.validateImport(importResults.map((r) => r.result[0]));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!skipUninstall) {
|
|
152
|
+
await this.uninstall(configs.toReversed(), options);
|
|
153
|
+
}
|
|
109
154
|
}
|
|
110
155
|
|
|
111
|
-
async uninstall(configs: ResourceConfig[]
|
|
156
|
+
async uninstall(configs: ResourceConfig[], options: {
|
|
157
|
+
validateDestroy?: (plans: PlanResponseData[]) => Promise<void> | void
|
|
158
|
+
}) {
|
|
159
|
+
const plans = [];
|
|
160
|
+
|
|
112
161
|
for (const config of configs) {
|
|
113
|
-
|
|
162
|
+
plans.push(await this.plan({
|
|
163
|
+
desired: undefined,
|
|
164
|
+
isStateful: true,
|
|
165
|
+
state: config
|
|
166
|
+
}))
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
for (const plan of plans) {
|
|
170
|
+
if (plan.operation !== ResourceOperation.DESTROY) {
|
|
171
|
+
throw new Error(`Expect resource operation to be 'destory' but instead received plan: \n ${JSON.stringify(plan, null, 2)}`)
|
|
172
|
+
}
|
|
114
173
|
|
|
115
174
|
await this.apply({
|
|
116
|
-
|
|
117
|
-
operation: ResourceOperation.DESTROY,
|
|
118
|
-
parameters: Object.entries(parameters).map(([key, value]) => ({
|
|
119
|
-
name: key,
|
|
120
|
-
newValue: null,
|
|
121
|
-
operation: ParameterOperation.REMOVE,
|
|
122
|
-
previousValue: value,
|
|
123
|
-
})),
|
|
124
|
-
resourceType: type,
|
|
125
|
-
}
|
|
175
|
+
planId: plan.planId
|
|
126
176
|
});
|
|
177
|
+
}
|
|
127
178
|
|
|
128
|
-
|
|
179
|
+
// Validate that the destroy was successful
|
|
180
|
+
for (const config of configs) {
|
|
129
181
|
const validationPlan = await this.plan({
|
|
130
182
|
desired: config,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
})
|
|
183
|
+
isStateful: true,
|
|
184
|
+
state: undefined
|
|
185
|
+
})
|
|
134
186
|
if (validationPlan.operation !== ResourceOperation.CREATE) {
|
|
135
|
-
throw new Error(`Resource
|
|
187
|
+
throw new Error(`Resource was not successfully destroyed.
|
|
136
188
|
Validation plan shows:
|
|
137
189
|
${JSON.stringify(validationPlan, null, 2)}
|
|
138
|
-
|
|
139
|
-
${JSON.stringify(config, null, 2)}`
|
|
140
|
-
);
|
|
190
|
+
`);
|
|
141
191
|
}
|
|
142
192
|
}
|
|
193
|
+
|
|
194
|
+
if (options.validateDestroy) {
|
|
195
|
+
await options.validateDestroy(plans);
|
|
196
|
+
}
|
|
143
197
|
}
|
|
144
198
|
|
|
145
199
|
async initialize(): Promise<InitializeResponseData> {
|
|
@@ -170,6 +224,13 @@ ${JSON.stringify(config, null, 2)}`
|
|
|
170
224
|
});
|
|
171
225
|
}
|
|
172
226
|
|
|
227
|
+
async import(data: ImportRequestData): Promise<ImportResponseData> {
|
|
228
|
+
return CodifyTestUtils.sendMessageAndAwaitResponse(this.childProcess, {
|
|
229
|
+
cmd: 'import',
|
|
230
|
+
data,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
173
234
|
kill() {
|
|
174
235
|
this.childProcess.kill();
|
|
175
236
|
}
|
|
@@ -257,7 +318,3 @@ async function sudoSpawn(
|
|
|
257
318
|
})
|
|
258
319
|
})
|
|
259
320
|
}
|
|
260
|
-
|
|
261
|
-
function isInDebugMode() {
|
|
262
|
-
return inspector.url() !== undefined;
|
|
263
|
-
}
|
|
@@ -139,7 +139,7 @@ describe('Plugin tester integration tests', () => {
|
|
|
139
139
|
propA: 'a',
|
|
140
140
|
propB: 10,
|
|
141
141
|
propC: 'c',
|
|
142
|
-
}], (plans) => {
|
|
142
|
+
}], false, (plans) => {
|
|
143
143
|
expect(plans[0]).toMatchObject({
|
|
144
144
|
planId: expect.any(String),
|
|
145
145
|
operation: ResourceOperation.NOOP,
|