@codifycli/plugin-core 1.0.0-beta1
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/.eslintignore +2 -0
- package/.eslintrc.json +30 -0
- package/.github/workflows/release.yaml +19 -0
- package/.github/workflows/unit-test-ci.yaml +18 -0
- package/.prettierrc.json +1 -0
- package/bin/build.js +189 -0
- package/dist/bin/build.d.ts +1 -0
- package/dist/bin/build.js +80 -0
- package/dist/bin/deploy-plugin.d.ts +2 -0
- package/dist/bin/deploy-plugin.js +8 -0
- package/dist/common/errors.d.ts +8 -0
- package/dist/common/errors.js +24 -0
- package/dist/entities/change-set.d.ts +24 -0
- package/dist/entities/change-set.js +152 -0
- package/dist/entities/errors.d.ts +4 -0
- package/dist/entities/errors.js +7 -0
- package/dist/entities/plan-types.d.ts +25 -0
- package/dist/entities/plan-types.js +1 -0
- package/dist/entities/plan.d.ts +15 -0
- package/dist/entities/plan.js +127 -0
- package/dist/entities/plugin.d.ts +16 -0
- package/dist/entities/plugin.js +80 -0
- package/dist/entities/resource-options.d.ts +31 -0
- package/dist/entities/resource-options.js +76 -0
- package/dist/entities/resource-types.d.ts +11 -0
- package/dist/entities/resource-types.js +1 -0
- package/dist/entities/resource.d.ts +42 -0
- package/dist/entities/resource.js +303 -0
- package/dist/entities/stateful-parameter.d.ts +29 -0
- package/dist/entities/stateful-parameter.js +46 -0
- package/dist/entities/transform-parameter.d.ts +4 -0
- package/dist/entities/transform-parameter.js +2 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +7 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +26 -0
- package/dist/messages/handlers.d.ts +14 -0
- package/dist/messages/handlers.js +134 -0
- package/dist/messages/sender.d.ts +11 -0
- package/dist/messages/sender.js +57 -0
- package/dist/plan/change-set.d.ts +53 -0
- package/dist/plan/change-set.js +153 -0
- package/dist/plan/plan-types.d.ts +23 -0
- package/dist/plan/plan-types.js +1 -0
- package/dist/plan/plan.d.ts +66 -0
- package/dist/plan/plan.js +328 -0
- package/dist/plugin/plugin.d.ts +24 -0
- package/dist/plugin/plugin.js +200 -0
- package/dist/pty/background-pty.d.ts +21 -0
- package/dist/pty/background-pty.js +127 -0
- package/dist/pty/index.d.ts +50 -0
- package/dist/pty/index.js +20 -0
- package/dist/pty/promise-queue.d.ts +5 -0
- package/dist/pty/promise-queue.js +26 -0
- package/dist/pty/seqeuntial-pty.d.ts +17 -0
- package/dist/pty/seqeuntial-pty.js +119 -0
- package/dist/pty/vitest.config.d.ts +2 -0
- package/dist/pty/vitest.config.js +11 -0
- package/dist/resource/config-parser.d.ts +11 -0
- package/dist/resource/config-parser.js +21 -0
- package/dist/resource/parsed-resource-settings.d.ts +47 -0
- package/dist/resource/parsed-resource-settings.js +196 -0
- package/dist/resource/resource-controller.d.ts +36 -0
- package/dist/resource/resource-controller.js +402 -0
- package/dist/resource/resource-settings.d.ts +303 -0
- package/dist/resource/resource-settings.js +147 -0
- package/dist/resource/resource.d.ts +144 -0
- package/dist/resource/resource.js +44 -0
- package/dist/resource/stateful-parameter.d.ts +165 -0
- package/dist/resource/stateful-parameter.js +94 -0
- package/dist/scripts/deploy.d.ts +1 -0
- package/dist/scripts/deploy.js +2 -0
- package/dist/stateful-parameter/stateful-parameter-controller.d.ts +21 -0
- package/dist/stateful-parameter/stateful-parameter-controller.js +81 -0
- package/dist/stateful-parameter/stateful-parameter.d.ts +144 -0
- package/dist/stateful-parameter/stateful-parameter.js +43 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +5 -0
- package/dist/utils/codify-spawn.d.ts +29 -0
- package/dist/utils/codify-spawn.js +136 -0
- package/dist/utils/debug.d.ts +2 -0
- package/dist/utils/debug.js +10 -0
- package/dist/utils/file-utils.d.ts +23 -0
- package/dist/utils/file-utils.js +186 -0
- package/dist/utils/functions.d.ts +12 -0
- package/dist/utils/functions.js +74 -0
- package/dist/utils/index.d.ts +46 -0
- package/dist/utils/index.js +271 -0
- package/dist/utils/internal-utils.d.ts +12 -0
- package/dist/utils/internal-utils.js +74 -0
- package/dist/utils/load-resources.d.ts +1 -0
- package/dist/utils/load-resources.js +46 -0
- package/dist/utils/package-json-utils.d.ts +12 -0
- package/dist/utils/package-json-utils.js +34 -0
- package/dist/utils/pty-local-storage.d.ts +2 -0
- package/dist/utils/pty-local-storage.js +2 -0
- package/dist/utils/spawn-2.d.ts +5 -0
- package/dist/utils/spawn-2.js +7 -0
- package/dist/utils/spawn.d.ts +29 -0
- package/dist/utils/spawn.js +124 -0
- package/dist/utils/utils.d.ts +18 -0
- package/dist/utils/utils.js +86 -0
- package/dist/utils/verbosity-level.d.ts +5 -0
- package/dist/utils/verbosity-level.js +9 -0
- package/package.json +59 -0
- package/rollup.config.js +24 -0
- package/src/common/errors.test.ts +43 -0
- package/src/common/errors.ts +31 -0
- package/src/errors.ts +8 -0
- package/src/index.test.ts +6 -0
- package/src/index.ts +30 -0
- package/src/messages/handlers.test.ts +329 -0
- package/src/messages/handlers.ts +181 -0
- package/src/messages/sender.ts +69 -0
- package/src/plan/change-set.test.ts +280 -0
- package/src/plan/change-set.ts +236 -0
- package/src/plan/plan-types.ts +27 -0
- package/src/plan/plan.test.ts +413 -0
- package/src/plan/plan.ts +499 -0
- package/src/plugin/plugin.test.ts +533 -0
- package/src/plugin/plugin.ts +291 -0
- package/src/pty/background-pty.test.ts +69 -0
- package/src/pty/background-pty.ts +154 -0
- package/src/pty/index.test.ts +129 -0
- package/src/pty/index.ts +66 -0
- package/src/pty/promise-queue.ts +33 -0
- package/src/pty/seqeuntial-pty.ts +151 -0
- package/src/pty/sequential-pty.test.ts +194 -0
- package/src/resource/config-parser.ts +42 -0
- package/src/resource/parsed-resource-settings.test.ts +186 -0
- package/src/resource/parsed-resource-settings.ts +307 -0
- package/src/resource/resource-controller-stateful-mode.test.ts +253 -0
- package/src/resource/resource-controller.test.ts +1081 -0
- package/src/resource/resource-controller.ts +563 -0
- package/src/resource/resource-settings.test.ts +1213 -0
- package/src/resource/resource-settings.ts +545 -0
- package/src/resource/resource.ts +157 -0
- package/src/stateful-parameter/stateful-parameter-controller.test.ts +244 -0
- package/src/stateful-parameter/stateful-parameter-controller.ts +111 -0
- package/src/stateful-parameter/stateful-parameter.ts +160 -0
- package/src/utils/debug.ts +11 -0
- package/src/utils/file-utils.test.ts +7 -0
- package/src/utils/file-utils.ts +231 -0
- package/src/utils/functions.ts +103 -0
- package/src/utils/index.ts +340 -0
- package/src/utils/internal-utils.test.ts +52 -0
- package/src/utils/pty-local-storage.ts +3 -0
- package/src/utils/test-utils.test.ts +96 -0
- package/src/utils/verbosity-level.ts +11 -0
- package/tsconfig.json +26 -0
- package/tsconfig.test.json +9 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export const VerbosityLevel = new class {
|
|
4
|
+
level = 0;
|
|
5
|
+
get() {
|
|
6
|
+
return this.level;
|
|
7
|
+
}
|
|
8
|
+
set(level) {
|
|
9
|
+
this.level = level;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
export function isDebug() {
|
|
13
|
+
return process.env.DEBUG != null && process.env.DEBUG.includes('codify'); // TODO: replace with debug library
|
|
14
|
+
}
|
|
15
|
+
export function splitUserConfig(config) {
|
|
16
|
+
const coreParameters = {
|
|
17
|
+
type: config.type,
|
|
18
|
+
...(config.name ? { name: config.name } : {}),
|
|
19
|
+
...(config.dependsOn ? { dependsOn: config.dependsOn } : {}),
|
|
20
|
+
};
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
22
|
+
const { type, name, dependsOn, ...parameters } = config;
|
|
23
|
+
return {
|
|
24
|
+
parameters: parameters,
|
|
25
|
+
coreParameters,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function setsEqual(set1, set2) {
|
|
29
|
+
return set1.size === set2.size && [...set1].every((v) => set2.has(v));
|
|
30
|
+
}
|
|
31
|
+
const homeDirectory = os.homedir();
|
|
32
|
+
export function untildify(pathWithTilde) {
|
|
33
|
+
return homeDirectory ? pathWithTilde.replace(/^~(?=$|\/|\\)/, homeDirectory) : pathWithTilde;
|
|
34
|
+
}
|
|
35
|
+
export function tildify(pathWithTilde) {
|
|
36
|
+
return homeDirectory ? pathWithTilde.replace(homeDirectory, '~') : pathWithTilde;
|
|
37
|
+
}
|
|
38
|
+
export function resolvePathWithVariables(pathWithVariables) {
|
|
39
|
+
// @ts-expect-error Ignore this for now
|
|
40
|
+
return pathWithVariables.replace(/\$([A-Z_]+[A-Z0-9_]*)|\${([A-Z0-9_]*)}/ig, (_, a, b) => process.env[a || b]);
|
|
41
|
+
}
|
|
42
|
+
export function addVariablesToPath(pathWithoutVariables) {
|
|
43
|
+
let result = pathWithoutVariables;
|
|
44
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
45
|
+
if (!value || !path.isAbsolute(value) || value === '/' || key === 'HOME' || key === 'PATH' || key === 'SHELL' || key === 'PWD') {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
result = result.replaceAll(value, `$${key}`);
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
export function unhome(pathWithHome) {
|
|
53
|
+
return pathWithHome.includes('$HOME') ? pathWithHome.replaceAll('$HOME', os.homedir()) : pathWithHome;
|
|
54
|
+
}
|
|
55
|
+
export function areArraysEqual(isElementEqual, desired, current) {
|
|
56
|
+
if (!desired || !current) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (!Array.isArray(desired) || !Array.isArray(current)) {
|
|
60
|
+
throw new Error(`A non-array value:
|
|
61
|
+
|
|
62
|
+
Desired: ${JSON.stringify(desired, null, 2)}
|
|
63
|
+
|
|
64
|
+
Current: ${JSON.stringify(desired, null, 2)}
|
|
65
|
+
|
|
66
|
+
Was provided even though type array was specified.
|
|
67
|
+
`);
|
|
68
|
+
}
|
|
69
|
+
if (desired.length !== current.length) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const desiredCopy = [...desired];
|
|
73
|
+
const currentCopy = [...current];
|
|
74
|
+
// Algorithm for to check equality between two un-ordered; un-hashable arrays using
|
|
75
|
+
// an isElementEqual method. Time: O(n^2)
|
|
76
|
+
for (let counter = desiredCopy.length - 1; counter >= 0; counter--) {
|
|
77
|
+
const idx = currentCopy.findIndex((e2) => (isElementEqual
|
|
78
|
+
?? ((a, b) => a === b))(desiredCopy[counter], e2));
|
|
79
|
+
if (idx === -1) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
desiredCopy.splice(counter, 1);
|
|
83
|
+
currentCopy.splice(idx, 1);
|
|
84
|
+
}
|
|
85
|
+
return currentCopy.length === 0;
|
|
86
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codifycli/plugin-core",
|
|
3
|
+
"version": "1.0.0-beta1",
|
|
4
|
+
"description": "Core library for implementing a plugin for Codify",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"typings": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "vitest",
|
|
10
|
+
"posttest": "tsc",
|
|
11
|
+
"prepublishOnly": "tsc"
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"codify-build": "./bin/build.js"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": "",
|
|
18
|
+
"license": "ISC",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
|
|
21
|
+
"@npmcli/promise-spawn": "^7.0.1",
|
|
22
|
+
"ajv": "^8.12.0",
|
|
23
|
+
"ajv-formats": "^2.1.1",
|
|
24
|
+
"clean-deep": "^3.4.0",
|
|
25
|
+
"codify-schemas": "1.0.86-beta11",
|
|
26
|
+
"lodash.isequal": "^4.5.0",
|
|
27
|
+
"nanoid": "^5.0.9",
|
|
28
|
+
"strip-ansi": "^7.1.0",
|
|
29
|
+
"uuid": "^10.0.0",
|
|
30
|
+
"zod": "4.1.13"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@apidevtools/json-schema-ref-parser": "^11.7.2",
|
|
34
|
+
"@oclif/prettier-config": "^0.2.1",
|
|
35
|
+
"@oclif/test": "^3",
|
|
36
|
+
"@types/lodash.isequal": "^4.5.8",
|
|
37
|
+
"@types/node": "^20",
|
|
38
|
+
"@types/npmcli__promise-spawn": "^6.0.3",
|
|
39
|
+
"@types/semver": "^7.5.4",
|
|
40
|
+
"@types/sinon": "^17.0.3",
|
|
41
|
+
"@types/uuid": "^10.0.0",
|
|
42
|
+
"chai-as-promised": "^7.1.1",
|
|
43
|
+
"eslint": "^8.51.0",
|
|
44
|
+
"eslint-config-oclif": "^5",
|
|
45
|
+
"eslint-config-oclif-typescript": "^3",
|
|
46
|
+
"eslint-config-prettier": "^9.0.0",
|
|
47
|
+
"merge-json-schemas": "^1.0.0",
|
|
48
|
+
"shx": "^0.3.3",
|
|
49
|
+
"sinon": "^17.0.1",
|
|
50
|
+
"ts-node": "^10.9.1",
|
|
51
|
+
"tsc-watch": "^6.0.4",
|
|
52
|
+
"typescript": "^5",
|
|
53
|
+
"vitest": "^3.0.5",
|
|
54
|
+
"vitest-mock-extended": "^1.3.1"
|
|
55
|
+
},
|
|
56
|
+
"engines": {
|
|
57
|
+
"node": ">=18.0.0"
|
|
58
|
+
}
|
|
59
|
+
}
|
package/rollup.config.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
2
|
+
import json from '@rollup/plugin-json';
|
|
3
|
+
import nodeResolve from '@rollup/plugin-node-resolve';
|
|
4
|
+
import terser from '@rollup/plugin-terser';
|
|
5
|
+
import typescript from '@rollup/plugin-typescript';
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
input: 'src/index.ts',
|
|
9
|
+
output: {
|
|
10
|
+
dir: 'dist',
|
|
11
|
+
format: 'cjs',
|
|
12
|
+
inlineDynamicImports: true,
|
|
13
|
+
},
|
|
14
|
+
external: ['@homebridge/node-pty-prebuilt-multiarch'],
|
|
15
|
+
plugins: [
|
|
16
|
+
json(),
|
|
17
|
+
nodeResolve({ exportConditions: ['node'] }),
|
|
18
|
+
typescript({
|
|
19
|
+
exclude: ['**/*.test.ts', '**/*.d.ts', 'test']
|
|
20
|
+
}),
|
|
21
|
+
commonjs(),
|
|
22
|
+
terser()
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { ApplyValidationError } from './errors.js';
|
|
3
|
+
import { testPlan } from '../utils/test-utils.test.js';
|
|
4
|
+
|
|
5
|
+
describe('Test file for errors file', () => {
|
|
6
|
+
it('Can properly format ApplyValidationError', () => {
|
|
7
|
+
const plan = testPlan({
|
|
8
|
+
desired: null,
|
|
9
|
+
current: [{ propZ: ['a', 'b', 'c'] }],
|
|
10
|
+
state: { propZ: ['a', 'b', 'c'] },
|
|
11
|
+
core: {
|
|
12
|
+
type: 'homebrew',
|
|
13
|
+
name: 'first'
|
|
14
|
+
},
|
|
15
|
+
isStateful: true,
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
throw new ApplyValidationError(plan);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
console.error(e);
|
|
22
|
+
expect(e.message).toMatch(
|
|
23
|
+
`Failed to apply changes to resource: "homebrew.first". Additional changes are needed to complete apply.
|
|
24
|
+
Changes remaining:
|
|
25
|
+
{
|
|
26
|
+
"operation": "destroy",
|
|
27
|
+
"parameters": [
|
|
28
|
+
{
|
|
29
|
+
"name": "propZ",
|
|
30
|
+
"operation": "remove",
|
|
31
|
+
"currentValue": [
|
|
32
|
+
"a",
|
|
33
|
+
"b",
|
|
34
|
+
"c"
|
|
35
|
+
],
|
|
36
|
+
"desiredValue": null
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}`
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Plan } from '../plan/plan.js';
|
|
2
|
+
|
|
3
|
+
export class ApplyValidationError extends Error {
|
|
4
|
+
resourceType: string;
|
|
5
|
+
resourceName?: string;
|
|
6
|
+
plan: Plan<any>;
|
|
7
|
+
|
|
8
|
+
constructor(plan: Plan<any>) {
|
|
9
|
+
super(`Failed to apply changes to resource: "${plan.resourceId}". Additional changes are needed to complete apply.\nChanges remaining:\n${ApplyValidationError.prettyPrintPlan(plan)}`);
|
|
10
|
+
|
|
11
|
+
this.resourceType = plan.coreParameters.type;
|
|
12
|
+
this.resourceName = plan.coreParameters.name;
|
|
13
|
+
this.plan = plan;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
private static prettyPrintPlan(plan: Plan<any>): string {
|
|
17
|
+
const { operation, parameters } = plan.toResponse();
|
|
18
|
+
|
|
19
|
+
const prettyParameters = parameters.map(({ name, operation, previousValue, newValue }) => ({
|
|
20
|
+
name,
|
|
21
|
+
operation,
|
|
22
|
+
currentValue: previousValue,
|
|
23
|
+
desiredValue: newValue,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
return JSON.stringify({
|
|
27
|
+
operation,
|
|
28
|
+
parameters: prettyParameters,
|
|
29
|
+
}, null, 2);
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/errors.ts
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { MessageHandler } from './messages/handlers.js';
|
|
2
|
+
import { Plugin } from './plugin/plugin.js';
|
|
3
|
+
|
|
4
|
+
export * from './errors.js'
|
|
5
|
+
export * from './messages/sender.js'
|
|
6
|
+
export * from './plan/change-set.js'
|
|
7
|
+
export * from './plan/plan.js'
|
|
8
|
+
export * from './plan/plan-types.js'
|
|
9
|
+
export * from './plugin/plugin.js'
|
|
10
|
+
export * from './pty/background-pty.js';
|
|
11
|
+
export * from './pty/index.js'
|
|
12
|
+
export * from './pty/seqeuntial-pty.js';
|
|
13
|
+
export * from './resource/parsed-resource-settings.js';
|
|
14
|
+
export * from './resource/resource.js'
|
|
15
|
+
export * from './resource/resource-settings.js'
|
|
16
|
+
export * from './stateful-parameter/stateful-parameter.js'
|
|
17
|
+
export * from './utils/file-utils.js'
|
|
18
|
+
export * from './utils/functions.js'
|
|
19
|
+
export * from './utils/index.js'
|
|
20
|
+
export * from './utils/verbosity-level.js'
|
|
21
|
+
export * from 'zod/v4';
|
|
22
|
+
|
|
23
|
+
export async function runPlugin(plugin: Plugin) {
|
|
24
|
+
const messageHandler = new MessageHandler(plugin);
|
|
25
|
+
process.on('message', (message) => messageHandler.onMessage(message))
|
|
26
|
+
|
|
27
|
+
process.on('beforeExit', () => {
|
|
28
|
+
plugin.kill();
|
|
29
|
+
})
|
|
30
|
+
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { MessageHandler } from './handlers.js';
|
|
2
|
+
import { Plugin } from '../plugin/plugin.js';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import { mock } from 'vitest-mock-extended'
|
|
5
|
+
import { Resource } from '../resource/resource.js';
|
|
6
|
+
import { MessageStatus, ResourceOperation } from 'codify-schemas';
|
|
7
|
+
import { TestResource } from '../utils/test-utils.test.js';
|
|
8
|
+
|
|
9
|
+
describe('Message handler tests', () => {
|
|
10
|
+
it('handles plan requests', async () => {
|
|
11
|
+
const plugin = mock<Plugin>();
|
|
12
|
+
const handler = new MessageHandler(plugin);
|
|
13
|
+
|
|
14
|
+
process.send = (message) => {
|
|
15
|
+
expect(message).toMatchObject({
|
|
16
|
+
cmd: 'plan_Response',
|
|
17
|
+
status: MessageStatus.SUCCESS,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Message handler also validates the response. That part does not need to be tested
|
|
24
|
+
try {
|
|
25
|
+
await handler.onMessage({
|
|
26
|
+
cmd: 'plan',
|
|
27
|
+
data: {
|
|
28
|
+
core: {
|
|
29
|
+
type: 'resourceType',
|
|
30
|
+
name: 'name',
|
|
31
|
+
},
|
|
32
|
+
desired: {
|
|
33
|
+
prop1: 'A',
|
|
34
|
+
prop2: 'B',
|
|
35
|
+
},
|
|
36
|
+
isStateful: false,
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
} catch (e) {}
|
|
40
|
+
|
|
41
|
+
expect(plugin.plan.mock.calls.length).to.eq(1);
|
|
42
|
+
process.send = undefined;
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('rejects bad plan requests', async () => {
|
|
46
|
+
const plugin = mock<Plugin>();
|
|
47
|
+
const handler = new MessageHandler(plugin);
|
|
48
|
+
|
|
49
|
+
process.send = (message) => {
|
|
50
|
+
expect(message).toMatchObject({
|
|
51
|
+
cmd: 'plan_Response',
|
|
52
|
+
status: MessageStatus.ERROR,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Message handler also validates the response. That part does not need to be tested
|
|
59
|
+
try {
|
|
60
|
+
await handler.onMessage({
|
|
61
|
+
cmd: 'plan',
|
|
62
|
+
data: {
|
|
63
|
+
name: '1name',
|
|
64
|
+
prop1: 'A',
|
|
65
|
+
prop2: 'B',
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
} catch (e) {
|
|
69
|
+
console.log(e);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
expect(plugin.plan.mock.calls.length).to.eq(0);
|
|
73
|
+
process.send = undefined;
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('handles apply requests', async () => {
|
|
77
|
+
const plugin = mock<Plugin>();
|
|
78
|
+
const handler = new MessageHandler(plugin);
|
|
79
|
+
|
|
80
|
+
// Message handler also validates the response. That part does not need to be tested
|
|
81
|
+
try {
|
|
82
|
+
await handler.onMessage({
|
|
83
|
+
cmd: 'apply',
|
|
84
|
+
data: {
|
|
85
|
+
planId: '1803fff7-a378-4006-95bb-7c97cba02c82'
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
} catch (e) {}
|
|
89
|
+
|
|
90
|
+
expect(plugin.apply.mock.calls.length).to.be.eq(1);
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('rejects bad apply requests', async () => {
|
|
94
|
+
const plugin = mock<Plugin>();
|
|
95
|
+
const handler = new MessageHandler(plugin);
|
|
96
|
+
|
|
97
|
+
// Message handler also validates the response. That part does not need to be tested
|
|
98
|
+
try {
|
|
99
|
+
await handler.onMessage({
|
|
100
|
+
cmd: 'apply',
|
|
101
|
+
data: {}
|
|
102
|
+
})
|
|
103
|
+
} catch (e) {}
|
|
104
|
+
|
|
105
|
+
expect(plugin.apply.mock.calls.length).to.be.eq(0);
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('handles validate requests', async () => {
|
|
109
|
+
const plugin = mock<Plugin>();
|
|
110
|
+
const handler = new MessageHandler(plugin);
|
|
111
|
+
|
|
112
|
+
// Message handler also validates the response. That part does not need to be tested
|
|
113
|
+
try {
|
|
114
|
+
await handler.onMessage({
|
|
115
|
+
cmd: 'validate',
|
|
116
|
+
data: {
|
|
117
|
+
configs: [
|
|
118
|
+
{
|
|
119
|
+
type: 'type1',
|
|
120
|
+
name: 'name1'
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: 'type2',
|
|
124
|
+
name: 'name2'
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
type: 'type2',
|
|
128
|
+
name: 'name3'
|
|
129
|
+
}
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
} catch (e) {}
|
|
134
|
+
|
|
135
|
+
expect(plugin.validate.mock.calls.length).to.eq(1);
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('rejects bad validate requests', async () => {
|
|
139
|
+
const plugin = mock<Plugin>();
|
|
140
|
+
const handler = new MessageHandler(plugin);
|
|
141
|
+
|
|
142
|
+
process.send = () => true;
|
|
143
|
+
|
|
144
|
+
// Message handler also validates the response. That part does not need to be tested
|
|
145
|
+
// This should not throw
|
|
146
|
+
expect(await handler.onMessage({
|
|
147
|
+
cmd: 'validate',
|
|
148
|
+
data: {}
|
|
149
|
+
})).to.eq(undefined);
|
|
150
|
+
|
|
151
|
+
expect(plugin.apply.mock.calls.length).to.be.eq(0);
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('handles errors for plan', async () => {
|
|
155
|
+
const resource = new TestResource()
|
|
156
|
+
const plugin = testPlugin(resource);
|
|
157
|
+
|
|
158
|
+
const handler = new MessageHandler(plugin);
|
|
159
|
+
|
|
160
|
+
process.send = (message) => {
|
|
161
|
+
expect(message).toMatchObject({
|
|
162
|
+
cmd: 'plan_Response',
|
|
163
|
+
status: MessageStatus.ERROR,
|
|
164
|
+
data: 'Refresh error',
|
|
165
|
+
})
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
expect(async () => await handler.onMessage({
|
|
170
|
+
cmd: 'plan',
|
|
171
|
+
data: {
|
|
172
|
+
core: {
|
|
173
|
+
type: 'resourceA',
|
|
174
|
+
},
|
|
175
|
+
desired: {
|
|
176
|
+
type: 'resourceA'
|
|
177
|
+
},
|
|
178
|
+
isStateful: false,
|
|
179
|
+
}
|
|
180
|
+
})).rejects.to.not.throw;
|
|
181
|
+
|
|
182
|
+
process.send = undefined;
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('handles errors for apply (create)', async () => {
|
|
186
|
+
const resource = new TestResource()
|
|
187
|
+
const plugin = testPlugin(resource);
|
|
188
|
+
|
|
189
|
+
const handler = new MessageHandler(plugin);
|
|
190
|
+
|
|
191
|
+
process.send = (message) => {
|
|
192
|
+
expect(message).toMatchObject({
|
|
193
|
+
cmd: 'apply_Response',
|
|
194
|
+
status: MessageStatus.ERROR,
|
|
195
|
+
})
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
expect(async () => await handler.onMessage({
|
|
200
|
+
cmd: 'apply',
|
|
201
|
+
data: {
|
|
202
|
+
plan: {
|
|
203
|
+
resourceType: 'resourceA',
|
|
204
|
+
operation: ResourceOperation.CREATE,
|
|
205
|
+
parameters: []
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
})).rejects.to.not.throw;
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('handles errors for apply (destroy)', async () => {
|
|
212
|
+
const resource = new TestResource()
|
|
213
|
+
const plugin = testPlugin(resource);
|
|
214
|
+
const handler = new MessageHandler(plugin);
|
|
215
|
+
|
|
216
|
+
process.send = (message) => {
|
|
217
|
+
expect(message).toMatchObject({
|
|
218
|
+
cmd: 'apply_Response',
|
|
219
|
+
status: MessageStatus.ERROR,
|
|
220
|
+
})
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
expect(async () => await handler.onMessage({
|
|
225
|
+
cmd: 'apply',
|
|
226
|
+
data: {
|
|
227
|
+
plan: {
|
|
228
|
+
resourceType: 'resourceA',
|
|
229
|
+
operation: ResourceOperation.DESTROY,
|
|
230
|
+
parameters: []
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
})).rejects.to.not.throw;
|
|
234
|
+
|
|
235
|
+
process.send = undefined;
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it('handles changing the verbosity level', async () => {
|
|
239
|
+
const resource = new TestResource()
|
|
240
|
+
const plugin = testPlugin(resource);
|
|
241
|
+
const handler = new MessageHandler(plugin);
|
|
242
|
+
|
|
243
|
+
process.send = (message) => {
|
|
244
|
+
expect(message).toMatchObject({
|
|
245
|
+
cmd: 'setVerbosityLevel_Response',
|
|
246
|
+
status: MessageStatus.SUCCESS,
|
|
247
|
+
})
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
expect(async () => await handler.onMessage({
|
|
252
|
+
cmd: 'setVerbosityLevel',
|
|
253
|
+
data: {
|
|
254
|
+
verbosityLevel: 2,
|
|
255
|
+
}
|
|
256
|
+
})).rejects.to.not.throw;
|
|
257
|
+
|
|
258
|
+
process.send = undefined;
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
it('Supports ipc message v2 (success)', async () => {
|
|
262
|
+
const resource = new TestResource()
|
|
263
|
+
const plugin = testPlugin(resource);
|
|
264
|
+
const handler = new MessageHandler(plugin);
|
|
265
|
+
|
|
266
|
+
process.send = (message) => {
|
|
267
|
+
console.log(message)
|
|
268
|
+
expect(message).toMatchObject({
|
|
269
|
+
cmd: 'plan_Response',
|
|
270
|
+
requestId: 'abcdef',
|
|
271
|
+
status: MessageStatus.SUCCESS,
|
|
272
|
+
})
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
await expect(handler.onMessage({
|
|
277
|
+
cmd: 'plan',
|
|
278
|
+
requestId: 'abcdef',
|
|
279
|
+
data: {
|
|
280
|
+
core: {
|
|
281
|
+
type: 'type',
|
|
282
|
+
name: 'name',
|
|
283
|
+
},
|
|
284
|
+
desired: {
|
|
285
|
+
prop1: 'A',
|
|
286
|
+
prop2: 'B',
|
|
287
|
+
},
|
|
288
|
+
isStateful: false,
|
|
289
|
+
}
|
|
290
|
+
})).resolves.to.eq(undefined);
|
|
291
|
+
|
|
292
|
+
process.send = undefined;
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
it('Supports ipc message v2 (error)', async () => {
|
|
296
|
+
const resource = new TestResource()
|
|
297
|
+
const plugin = testPlugin(resource);
|
|
298
|
+
const handler = new MessageHandler(plugin);
|
|
299
|
+
|
|
300
|
+
process.send = (message) => {
|
|
301
|
+
expect(message).toMatchObject({
|
|
302
|
+
cmd: 'apply_Response',
|
|
303
|
+
requestId: 'abcdef',
|
|
304
|
+
status: MessageStatus.ERROR,
|
|
305
|
+
})
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
await expect(handler.onMessage({
|
|
310
|
+
cmd: 'apply', // Supposed to be a plan so that's why it throws
|
|
311
|
+
requestId: 'abcdef',
|
|
312
|
+
data: {
|
|
313
|
+
desired: {
|
|
314
|
+
type: 'type',
|
|
315
|
+
name: 'name',
|
|
316
|
+
prop1: 'A',
|
|
317
|
+
prop2: 'B',
|
|
318
|
+
},
|
|
319
|
+
isStateful: false,
|
|
320
|
+
}
|
|
321
|
+
})).resolves.to.eq(undefined);
|
|
322
|
+
|
|
323
|
+
process.send = undefined;
|
|
324
|
+
})
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
function testPlugin(resource: Resource<any>) {
|
|
328
|
+
return Plugin.create('plugin', [resource])
|
|
329
|
+
}
|