testeranto 0.47.11 → 0.47.13
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/dist/common/Features.js +85 -0
- package/dist/common/Node.js +82 -0
- package/dist/common/NodeWriter.js +56 -0
- package/dist/common/Project.js +648 -0
- package/dist/common/Types.js +2 -0
- package/dist/common/Web.js +70 -0
- package/dist/common/core.js +392 -0
- package/dist/common/electron.js +40 -0
- package/dist/common/preload.js +8 -0
- package/dist/common/subPackages/react/component.js +2 -0
- package/dist/common/subPackages/react/node.js +57 -0
- package/dist/common/subPackages/react/web.js +57 -0
- package/dist/common/subPackages/react-test-render/component.js +2 -0
- package/dist/common/subPackages/react-test-render/node.js +46 -0
- package/dist/common/subPackages/react-test-render/web.js +46 -0
- package/dist/common/tsconfig.common.tsbuildinfo +1 -0
- package/dist/module/Features.js +74 -0
- package/dist/module/Node.js +77 -0
- package/dist/module/NodeWriter.js +50 -0
- package/dist/module/Project.js +618 -0
- package/dist/module/Report.js +186 -0
- package/dist/module/Types.js +1 -0
- package/dist/module/Web.js +65 -0
- package/dist/module/core.js +383 -0
- package/dist/module/electron.js +35 -0
- package/dist/module/preload.js +6 -0
- package/dist/module/subPackages/react/component.js +1 -0
- package/dist/module/subPackages/react/node.js +52 -0
- package/dist/module/subPackages/react/web.js +52 -0
- package/dist/module/subPackages/react-test-render/component.js +1 -0
- package/dist/module/subPackages/react-test-render/node.js +16 -0
- package/dist/module/subPackages/react-test-render/web.js +16 -0
- package/dist/module/tsconfig.module.tsbuildinfo +1 -0
- package/dist/types/Features.d.ts +68 -0
- package/dist/types/Node.d.ts +12 -0
- package/dist/types/NodeWriter.d.ts +2 -0
- package/dist/types/Project.d.ts +32 -0
- package/dist/types/Types.d.ts +17 -0
- package/dist/types/Web.d.ts +12 -0
- package/dist/types/core.d.ts +219 -0
- package/dist/types/electron.d.ts +1 -0
- package/dist/types/preload.d.ts +1 -0
- package/dist/types/subPackages/react/component.d.ts +17 -0
- package/dist/types/subPackages/react/node.d.ts +4 -0
- package/dist/types/subPackages/react/web.d.ts +4 -0
- package/dist/types/subPackages/react-test-render/component.d.ts +17 -0
- package/dist/types/subPackages/react-test-render/node.d.ts +4 -0
- package/dist/types/subPackages/react-test-render/web.d.ts +4 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -0
- package/package.json +9 -5
- package/src/subPackages/react/component.ts +1 -0
- package/src/subPackages/react-test-render/component.ts +21 -0
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.ITProject = void 0;
|
|
30
|
+
const ws_1 = require("ws");
|
|
31
|
+
const esbuild_1 = __importDefault(require("esbuild"));
|
|
32
|
+
const fs_1 = __importDefault(require("fs"));
|
|
33
|
+
const path_1 = __importDefault(require("path"));
|
|
34
|
+
const fs_promises_exists_1 = __importDefault(require("fs.promises.exists"));
|
|
35
|
+
const pm2_1 = __importDefault(require("pm2"));
|
|
36
|
+
const readline_1 = __importDefault(require("readline"));
|
|
37
|
+
readline_1.default.emitKeypressEvents(process.stdin);
|
|
38
|
+
if (process.stdin.isTTY)
|
|
39
|
+
process.stdin.setRawMode(true);
|
|
40
|
+
const TIMEOUT = 2000;
|
|
41
|
+
const OPEN_PORT = "";
|
|
42
|
+
let webSocketServer;
|
|
43
|
+
const getRunnables = (tests, payload = [new Set(), new Set()]) => {
|
|
44
|
+
return tests.reduce((pt, cv, cndx, cry) => {
|
|
45
|
+
if (cv[1] === "node") {
|
|
46
|
+
pt[0].add(cv[0]);
|
|
47
|
+
}
|
|
48
|
+
else if (cv[1] === "web") {
|
|
49
|
+
pt[1].add(cv[0]);
|
|
50
|
+
}
|
|
51
|
+
if (cv[2].length) {
|
|
52
|
+
getRunnables(cv[2], payload);
|
|
53
|
+
}
|
|
54
|
+
return pt;
|
|
55
|
+
}, payload);
|
|
56
|
+
};
|
|
57
|
+
class ITProject {
|
|
58
|
+
constructor(config) {
|
|
59
|
+
this.exitCodes = {};
|
|
60
|
+
this.mode = `up`;
|
|
61
|
+
this.ports = {};
|
|
62
|
+
this.websockets = {};
|
|
63
|
+
this.resourceQueue = [];
|
|
64
|
+
this.spinCycle = 0;
|
|
65
|
+
this.spinAnimation = "←↖↑↗→↘↓↙";
|
|
66
|
+
this.mainLoop = async () => {
|
|
67
|
+
if (this.clearScreen) {
|
|
68
|
+
console.clear();
|
|
69
|
+
}
|
|
70
|
+
const procsTable = [];
|
|
71
|
+
pm2_1.default.list((err, procs) => {
|
|
72
|
+
procs.forEach((proc) => {
|
|
73
|
+
var _a, _b;
|
|
74
|
+
procsTable.push({
|
|
75
|
+
name: proc.name,
|
|
76
|
+
pid: proc.pid,
|
|
77
|
+
pm_id: proc.pm_id,
|
|
78
|
+
mem: (_a = proc.monit) === null || _a === void 0 ? void 0 : _a.memory,
|
|
79
|
+
cpu: (_b = proc.monit) === null || _b === void 0 ? void 0 : _b.cpu,
|
|
80
|
+
"exit code": this.exitCodes[proc.name]
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
console.table(procsTable);
|
|
84
|
+
console.table(this.resourceQueue);
|
|
85
|
+
// console.log("webSocketServer.clients", webSocketServer.clients.size);
|
|
86
|
+
// console.log("resourceQueue", this.resourceQueue);
|
|
87
|
+
const resourceRequest = this.resourceQueue.pop();
|
|
88
|
+
if (!resourceRequest) {
|
|
89
|
+
if (!this.devMode && this.mode === "up") {
|
|
90
|
+
this.initiateShutdown("resource request queue is empty");
|
|
91
|
+
}
|
|
92
|
+
if (this.mode === "down" && procsTable.every((p) => p.pid === 0 || p.pid === undefined)) {
|
|
93
|
+
this.shutdown();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
console.log("handling", resourceRequest);
|
|
98
|
+
if (resourceRequest.protocol === "ipc") {
|
|
99
|
+
this.allocateViaIpc(resourceRequest);
|
|
100
|
+
}
|
|
101
|
+
else if (resourceRequest.protocol === "ws") {
|
|
102
|
+
this.allocateViaWs(resourceRequest);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (this.devMode) {
|
|
106
|
+
if (this.mode === "up") {
|
|
107
|
+
console.log(this.spinner(), "Running tests while watching for changes. Use 'q' to initiate shutdown");
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
console.log(this.spinner(), "Shutdown is in progress. Please wait.");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
if (this.mode === "up") {
|
|
115
|
+
console.log(this.spinner(), "Running tests without watching for changes. Use 'q' to initiate shutdown");
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.log(this.spinner(), "Shutdown is in progress. Please wait.");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// console.log(this.spinner());
|
|
122
|
+
// console.log(
|
|
123
|
+
// this.spinner(),
|
|
124
|
+
// this.mode === `up`
|
|
125
|
+
// ? `press "q" to initiate graceful shutdown`
|
|
126
|
+
// : `please wait while testeranto shuts down gracefully...`
|
|
127
|
+
// );
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
this.clearScreen = config.clearScreen;
|
|
131
|
+
this.devMode = config.devMode;
|
|
132
|
+
Object.values(config.ports).forEach((port) => {
|
|
133
|
+
this.ports[port] = OPEN_PORT;
|
|
134
|
+
});
|
|
135
|
+
const testPath = `${process.cwd()}/${config.tests}`;
|
|
136
|
+
const featurePath = `${process.cwd()}/${config.features}`;
|
|
137
|
+
process.on('SIGINT', () => this.initiateShutdown("CTRL+C"));
|
|
138
|
+
process.on('SIGQUIT', () => this.initiateShutdown("Keyboard quit"));
|
|
139
|
+
process.on('SIGTERM', () => this.initiateShutdown("'kill' command"));
|
|
140
|
+
process.stdin.on('keypress', (str, key) => {
|
|
141
|
+
if (key.name === 'q') {
|
|
142
|
+
this.initiateShutdown("'q' command");
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
Promise.resolve().then(() => __importStar(require(testPath))).then((tests) => {
|
|
146
|
+
this.tests = tests.default;
|
|
147
|
+
Promise.resolve().then(() => __importStar(require(featurePath))).then((features) => {
|
|
148
|
+
this.features = features.default;
|
|
149
|
+
Promise.resolve(Promise.all([
|
|
150
|
+
...this.getSecondaryEndpointsPoints("web")
|
|
151
|
+
]
|
|
152
|
+
.map(async (sourceFilePath) => {
|
|
153
|
+
const sourceFileSplit = sourceFilePath.split("/");
|
|
154
|
+
const sourceDir = sourceFileSplit.slice(0, -1);
|
|
155
|
+
const sourceFileName = sourceFileSplit[sourceFileSplit.length - 1];
|
|
156
|
+
const sourceFileNameMinusJs = sourceFileName.split(".").slice(0, -1).join(".");
|
|
157
|
+
const htmlFilePath = path_1.default.normalize(`${process.cwd()}/${config.outdir}/${sourceDir.join("/")}/${sourceFileNameMinusJs}.html`);
|
|
158
|
+
const jsfilePath = `./${sourceFileNameMinusJs}.mjs`;
|
|
159
|
+
return fs_1.default.promises.mkdir(path_1.default.dirname(htmlFilePath), { recursive: true }).then(x => fs_1.default.writeFileSync(htmlFilePath, `
|
|
160
|
+
<!DOCTYPE html>
|
|
161
|
+
<html lang="en">
|
|
162
|
+
<head>
|
|
163
|
+
<script type="module" src="${jsfilePath}"></script>
|
|
164
|
+
</head>
|
|
165
|
+
|
|
166
|
+
<body>
|
|
167
|
+
<h1>${htmlFilePath}</h1>
|
|
168
|
+
<div id="root">
|
|
169
|
+
|
|
170
|
+
</div>
|
|
171
|
+
</body>
|
|
172
|
+
|
|
173
|
+
<footer></footer>
|
|
174
|
+
|
|
175
|
+
</html>
|
|
176
|
+
`));
|
|
177
|
+
})));
|
|
178
|
+
const [nodeEntryPoints, webEntryPoints] = getRunnables(this.tests);
|
|
179
|
+
const esbuildConfigNode = {
|
|
180
|
+
define: {
|
|
181
|
+
"process.env.FLUENTFFMPEG_COV": "0"
|
|
182
|
+
},
|
|
183
|
+
absWorkingDir: process.cwd(),
|
|
184
|
+
banner: {
|
|
185
|
+
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
186
|
+
},
|
|
187
|
+
target: "esnext",
|
|
188
|
+
// packages: "external",
|
|
189
|
+
format: "esm",
|
|
190
|
+
splitting: true,
|
|
191
|
+
outExtension: { '.js': '.mjs' },
|
|
192
|
+
platform: "node",
|
|
193
|
+
external: ["tests.test.js", "features.test.js", "react"],
|
|
194
|
+
outbase: config.outbase,
|
|
195
|
+
outdir: config.outdir,
|
|
196
|
+
jsx: 'transform',
|
|
197
|
+
entryPoints: [...nodeEntryPoints],
|
|
198
|
+
bundle: true,
|
|
199
|
+
minify: config.minify === true,
|
|
200
|
+
write: true,
|
|
201
|
+
loader: {
|
|
202
|
+
'.js': 'jsx',
|
|
203
|
+
'.png': 'binary',
|
|
204
|
+
'.jpg': 'binary',
|
|
205
|
+
},
|
|
206
|
+
plugins: [
|
|
207
|
+
...(config.plugins || []),
|
|
208
|
+
{
|
|
209
|
+
name: 'rebuild-notify',
|
|
210
|
+
setup(build) {
|
|
211
|
+
build.onEnd(result => {
|
|
212
|
+
console.log(`node build ended with ${result.errors.length} errors`);
|
|
213
|
+
result.errors.length !== 0 && process.exit(-1);
|
|
214
|
+
// HERE: somehow restart the server from here, e.g., by sending a signal that you trap and react to inside the server.
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
};
|
|
220
|
+
const esbuildConfigWeb = {
|
|
221
|
+
// packages: "external",
|
|
222
|
+
target: "esnext",
|
|
223
|
+
format: "esm",
|
|
224
|
+
splitting: true,
|
|
225
|
+
outExtension: { '.js': '.mjs' },
|
|
226
|
+
alias: {
|
|
227
|
+
react: path_1.default.resolve("./node_modules/react")
|
|
228
|
+
},
|
|
229
|
+
external: [
|
|
230
|
+
// "url",
|
|
231
|
+
"electron",
|
|
232
|
+
"path",
|
|
233
|
+
"fs",
|
|
234
|
+
// "react",
|
|
235
|
+
"stream",
|
|
236
|
+
"tests.test.js", "features.test.js"
|
|
237
|
+
],
|
|
238
|
+
platform: "browser",
|
|
239
|
+
outbase: config.outbase,
|
|
240
|
+
outdir: config.outdir,
|
|
241
|
+
jsx: 'transform',
|
|
242
|
+
entryPoints: [
|
|
243
|
+
...webEntryPoints,
|
|
244
|
+
testPath,
|
|
245
|
+
featurePath,
|
|
246
|
+
],
|
|
247
|
+
bundle: true,
|
|
248
|
+
minify: config.minify === true,
|
|
249
|
+
write: true,
|
|
250
|
+
loader: {
|
|
251
|
+
'.js': 'jsx',
|
|
252
|
+
'.png': 'binary',
|
|
253
|
+
'.jpg': 'binary',
|
|
254
|
+
},
|
|
255
|
+
plugins: [
|
|
256
|
+
...(config.plugins || []),
|
|
257
|
+
{
|
|
258
|
+
name: 'rebuild-notify',
|
|
259
|
+
setup(build) {
|
|
260
|
+
build.onEnd(result => {
|
|
261
|
+
console.log(`web build ended with ${result.errors.length} errors`);
|
|
262
|
+
result.errors.length !== 0 && process.exit(-1);
|
|
263
|
+
// HERE: somehow restart the server from here, e.g., by sending a signal that you trap and react to inside the server.
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
esbuild_1.default.build({
|
|
270
|
+
bundle: true,
|
|
271
|
+
entryPoints: ["./node_modules/testeranto/dist/module/Report.js"],
|
|
272
|
+
minify: config.minify === true,
|
|
273
|
+
outbase: config.outbase,
|
|
274
|
+
write: true,
|
|
275
|
+
outfile: `${config.outdir}/Report.js`,
|
|
276
|
+
external: ["tests.test.js", "features.test.js"]
|
|
277
|
+
});
|
|
278
|
+
fs_1.default.writeFileSync(`${config.outdir}/report.html`, `
|
|
279
|
+
<!DOCTYPE html>
|
|
280
|
+
<html lang="en">
|
|
281
|
+
|
|
282
|
+
<head>
|
|
283
|
+
<meta name="description" content="Webpage description goes here" />
|
|
284
|
+
<meta charset="utf-8" />
|
|
285
|
+
<title>kokomoBay - testeranto</title>
|
|
286
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
287
|
+
<meta name="author" content="" />
|
|
288
|
+
<link rel="stylesheet" href="./Report.css" />
|
|
289
|
+
|
|
290
|
+
<script type="importmap">
|
|
291
|
+
{
|
|
292
|
+
"imports": {
|
|
293
|
+
"tests.test.js": "./tests.test.js",
|
|
294
|
+
"features.test.js": "./features.test.js"
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
</script>
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
<script src="./Report.js"></script>
|
|
301
|
+
</head>
|
|
302
|
+
|
|
303
|
+
<body>
|
|
304
|
+
<div id="root">
|
|
305
|
+
react is loading
|
|
306
|
+
</div>
|
|
307
|
+
</body>
|
|
308
|
+
|
|
309
|
+
</html>
|
|
310
|
+
`);
|
|
311
|
+
Promise.all([
|
|
312
|
+
esbuild_1.default.context(esbuildConfigNode).then(async (nodeContext) => {
|
|
313
|
+
await nodeContext.watch();
|
|
314
|
+
}),
|
|
315
|
+
esbuild_1.default.context(esbuildConfigWeb).then(async (esbuildWeb) => {
|
|
316
|
+
await esbuildWeb.watch();
|
|
317
|
+
})
|
|
318
|
+
]);
|
|
319
|
+
pm2_1.default.connect(async (err) => {
|
|
320
|
+
if (err) {
|
|
321
|
+
console.error(err);
|
|
322
|
+
process.exit(-1);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
console.log(`pm2 is connected`);
|
|
326
|
+
}
|
|
327
|
+
// run a websocket as an alternative to node IPC
|
|
328
|
+
webSocketServer = new ws_1.WebSocketServer({
|
|
329
|
+
port: 8080,
|
|
330
|
+
host: "localhost",
|
|
331
|
+
});
|
|
332
|
+
webSocketServer.on('open', () => {
|
|
333
|
+
console.log('open');
|
|
334
|
+
// process.exit()
|
|
335
|
+
});
|
|
336
|
+
webSocketServer.on('close', (data) => {
|
|
337
|
+
console.log('webSocketServer close: %s', data);
|
|
338
|
+
// process.exit()
|
|
339
|
+
});
|
|
340
|
+
webSocketServer.on('listening', () => {
|
|
341
|
+
console.log("webSocketServer listening", webSocketServer.address());
|
|
342
|
+
// process.exit()
|
|
343
|
+
});
|
|
344
|
+
webSocketServer.on('connection', (webSocket) => {
|
|
345
|
+
console.log('webSocketServer connection');
|
|
346
|
+
webSocket.on('message', (webSocketData) => {
|
|
347
|
+
console.log('webSocket message: %s', webSocketData);
|
|
348
|
+
const payload = webSocketData.valueOf();
|
|
349
|
+
const name = payload.data.name;
|
|
350
|
+
const messageType = payload.type;
|
|
351
|
+
const requestedResources = payload.data;
|
|
352
|
+
this.websockets[name] = webSocket;
|
|
353
|
+
console.log('connected: ' + name + ' in ' + Object.getOwnPropertyNames(this.websockets));
|
|
354
|
+
if (messageType === "testeranto:hola") {
|
|
355
|
+
console.log("hola WS", requestedResources);
|
|
356
|
+
this.requestResource(requestedResources, 'ws');
|
|
357
|
+
}
|
|
358
|
+
else if (messageType === "testeranto:adios") {
|
|
359
|
+
console.log("adios WS", name);
|
|
360
|
+
this.releaseTestResources(payload);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
const makePath = (fPath, rt) => {
|
|
365
|
+
return path_1.default.resolve("./" + config.outdir + "/" + fPath.replace(path_1.default.extname(fPath), "") + ".mjs");
|
|
366
|
+
};
|
|
367
|
+
const bootInterval = setInterval(async () => {
|
|
368
|
+
const filesToLookup = this.tests
|
|
369
|
+
.map(([p, rt]) => {
|
|
370
|
+
const filepath = makePath(p, rt);
|
|
371
|
+
return {
|
|
372
|
+
filepath,
|
|
373
|
+
exists: (0, fs_promises_exists_1.default)(filepath),
|
|
374
|
+
};
|
|
375
|
+
});
|
|
376
|
+
const allFilesExist = (await Promise.all(filesToLookup.map((f) => f.exists))).every((b) => b);
|
|
377
|
+
if (!allFilesExist) {
|
|
378
|
+
console.log(this.spinner(), "waiting for files to build...");
|
|
379
|
+
filesToLookup.forEach((f) => {
|
|
380
|
+
console.log(f.exists, "\t", f.filepath);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
clearInterval(bootInterval);
|
|
385
|
+
pm2_1.default.launchBus((err, pm2_bus) => {
|
|
386
|
+
pm2_bus.on("testeranto:hola", (packet) => {
|
|
387
|
+
console.log("hola IPC", packet);
|
|
388
|
+
this.requestResource(packet.data.requirement, 'ipc');
|
|
389
|
+
});
|
|
390
|
+
pm2_bus.on("testeranto:adios", (payload) => {
|
|
391
|
+
console.log("adios IPC", payload);
|
|
392
|
+
this.releaseTestResources(payload.data);
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
this
|
|
396
|
+
.tests
|
|
397
|
+
.reduce((m, [inputFilePath, runtime]) => {
|
|
398
|
+
const script = makePath(inputFilePath, runtime);
|
|
399
|
+
const partialTestResourceByCommandLineArg = `${script} '${JSON.stringify({
|
|
400
|
+
name: inputFilePath,
|
|
401
|
+
ports: [],
|
|
402
|
+
fs: path_1.default.resolve(process.cwd(), config.outdir, inputFilePath),
|
|
403
|
+
})}'`;
|
|
404
|
+
if (runtime === "web") {
|
|
405
|
+
const fileAsList = inputFilePath.split("/");
|
|
406
|
+
const fileListHead = fileAsList.slice(0, -1);
|
|
407
|
+
const fname = fileAsList[fileAsList.length - 1];
|
|
408
|
+
const fnameOnly = fname.split(".").slice(0, -1).join(".");
|
|
409
|
+
const htmlFile = [config.outdir, ...fileListHead, `${fnameOnly}.html`].join("/");
|
|
410
|
+
const jsFile = htmlFile.split(".html")[0] + ".mjs";
|
|
411
|
+
console.log("watching", jsFile);
|
|
412
|
+
pm2_1.default.start({
|
|
413
|
+
script: `yarn electron node_modules/testeranto/dist/common/electron.js ${htmlFile} '${JSON.stringify({
|
|
414
|
+
name: inputFilePath,
|
|
415
|
+
ports: [],
|
|
416
|
+
fs: path_1.default.resolve(process.cwd(), config.outdir, inputFilePath),
|
|
417
|
+
})}'`,
|
|
418
|
+
name: inputFilePath,
|
|
419
|
+
autorestart: false,
|
|
420
|
+
args: partialTestResourceByCommandLineArg,
|
|
421
|
+
watch: [jsFile],
|
|
422
|
+
}, (err, proc) => {
|
|
423
|
+
if (err) {
|
|
424
|
+
console.error(err);
|
|
425
|
+
return pm2_1.default.disconnect();
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
else if (runtime === "node") {
|
|
430
|
+
pm2_1.default.start({
|
|
431
|
+
name: inputFilePath,
|
|
432
|
+
script: `node ${script} '${JSON.stringify({
|
|
433
|
+
name: inputFilePath,
|
|
434
|
+
ports: [],
|
|
435
|
+
fs: path_1.default.resolve(process.cwd(), config.outdir, inputFilePath),
|
|
436
|
+
})}'`,
|
|
437
|
+
autorestart: false,
|
|
438
|
+
watch: [script],
|
|
439
|
+
args: partialTestResourceByCommandLineArg
|
|
440
|
+
}, (err, proc) => {
|
|
441
|
+
if (err) {
|
|
442
|
+
console.error(err);
|
|
443
|
+
return pm2_1.default.disconnect();
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
this.exitCodes[inputFilePath] = null;
|
|
448
|
+
return [inputFilePath, ...m];
|
|
449
|
+
}, []);
|
|
450
|
+
setInterval(this.mainLoop, TIMEOUT).unref();
|
|
451
|
+
}
|
|
452
|
+
}, TIMEOUT).unref();
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
requestResource(requirement, protocol) {
|
|
458
|
+
this.resourceQueue.push({ requirement, protocol });
|
|
459
|
+
}
|
|
460
|
+
getSecondaryEndpointsPoints(runtime) {
|
|
461
|
+
if (runtime) {
|
|
462
|
+
return this.tests
|
|
463
|
+
.filter((t) => {
|
|
464
|
+
return (t[1] === runtime);
|
|
465
|
+
})
|
|
466
|
+
.map((tc) => tc[0]);
|
|
467
|
+
}
|
|
468
|
+
return this.tests
|
|
469
|
+
.map((tc) => tc[0]);
|
|
470
|
+
}
|
|
471
|
+
initiateShutdown(reason) {
|
|
472
|
+
console.log("Shutdown initiated because", reason);
|
|
473
|
+
this.mode = "down";
|
|
474
|
+
}
|
|
475
|
+
shutdown() {
|
|
476
|
+
console.log("Stopping PM2");
|
|
477
|
+
pm2_1.default.stop("all", (e) => console.error(e));
|
|
478
|
+
pm2_1.default.killDaemon((e) => console.error(e));
|
|
479
|
+
pm2_1.default.disconnect();
|
|
480
|
+
process.exit();
|
|
481
|
+
}
|
|
482
|
+
spinner() {
|
|
483
|
+
this.spinCycle = (this.spinCycle + 1) % this.spinAnimation.length;
|
|
484
|
+
return this.spinAnimation[this.spinCycle];
|
|
485
|
+
}
|
|
486
|
+
async releaseTestResources(payload) {
|
|
487
|
+
const name = payload.testResourceConfiguration.name;
|
|
488
|
+
const failed = payload.failed;
|
|
489
|
+
console.log("releaseTestResources", name, failed);
|
|
490
|
+
// reset ports
|
|
491
|
+
pm2_1.default.list((err, processes) => {
|
|
492
|
+
processes.forEach((proc) => {
|
|
493
|
+
if (proc.name === name) {
|
|
494
|
+
Object.keys(this.ports).forEach((port) => {
|
|
495
|
+
if (this.ports[port] === name) {
|
|
496
|
+
this.ports[port] = OPEN_PORT;
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
this.exitCodes[name] = failed;
|
|
503
|
+
}
|
|
504
|
+
allocateViaWs(resourceRequest) {
|
|
505
|
+
const pName = resourceRequest.requirement.name;
|
|
506
|
+
const testResourceRequirement = resourceRequest.requirement;
|
|
507
|
+
pm2_1.default.list((err, processes) => {
|
|
508
|
+
console.error(err);
|
|
509
|
+
processes.forEach((p) => {
|
|
510
|
+
if (p.name === pName && p.pid) {
|
|
511
|
+
const message = {
|
|
512
|
+
// these fields must be present
|
|
513
|
+
id: p.pid,
|
|
514
|
+
topic: "some topic",
|
|
515
|
+
type: "process:msg",
|
|
516
|
+
// Data to be sent
|
|
517
|
+
data: {
|
|
518
|
+
testResourceConfiguration: {
|
|
519
|
+
ports: [],
|
|
520
|
+
// fs: fPath,
|
|
521
|
+
},
|
|
522
|
+
id: p.pm_id,
|
|
523
|
+
},
|
|
524
|
+
};
|
|
525
|
+
if ((testResourceRequirement === null || testResourceRequirement === void 0 ? void 0 : testResourceRequirement.ports) === 0) {
|
|
526
|
+
pm2_1.default.sendDataToProcessId(p.pid, message, function (err, res) {
|
|
527
|
+
// console.log("sendDataToProcessId", err, res, message);
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
if (((testResourceRequirement === null || testResourceRequirement === void 0 ? void 0 : testResourceRequirement.ports) || 0) > 0) {
|
|
531
|
+
// clear any port-slots associated with this job
|
|
532
|
+
Object.values(this.ports).forEach((jobMaybe, portNumber) => {
|
|
533
|
+
if (jobMaybe && jobMaybe === pName) {
|
|
534
|
+
this.ports[portNumber] = OPEN_PORT;
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
// find a list of open ports
|
|
538
|
+
const foundOpenPorts = Object.keys(this.ports).filter((p) => this.ports[p] === OPEN_PORT);
|
|
539
|
+
// if there are enough open port-slots...
|
|
540
|
+
if (foundOpenPorts.length >= testResourceRequirement.ports) {
|
|
541
|
+
const selectionOfPorts = foundOpenPorts.slice(0, testResourceRequirement.ports);
|
|
542
|
+
const message = {
|
|
543
|
+
// these fields must be present
|
|
544
|
+
id: p.pid,
|
|
545
|
+
topic: "some topic",
|
|
546
|
+
// process:msg will be send as 'message' on target process
|
|
547
|
+
type: "process:msg",
|
|
548
|
+
// Data to be sent
|
|
549
|
+
data: {
|
|
550
|
+
testResourceConfiguration: {
|
|
551
|
+
// fs: fPath,
|
|
552
|
+
ports: selectionOfPorts,
|
|
553
|
+
},
|
|
554
|
+
id: p.pid,
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
pm2_1.default.sendDataToProcessId(p.pid, message, function (err, res) {
|
|
558
|
+
// no-op
|
|
559
|
+
});
|
|
560
|
+
// mark the selected ports as occupied
|
|
561
|
+
for (const foundOpenPort of selectionOfPorts) {
|
|
562
|
+
this.ports[foundOpenPort] = p.pid.toString();
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
console.log(`no port was open so send the ${p.pid} job to the back of the resourceQueue`);
|
|
567
|
+
this.resourceQueue.push(resourceRequest);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
allocateViaIpc(resourceRequest) {
|
|
575
|
+
console.log("allocateViaIpc", resourceRequest);
|
|
576
|
+
const pName = resourceRequest.requirement.name;
|
|
577
|
+
const testResourceRequirement = resourceRequest.requirement;
|
|
578
|
+
pm2_1.default.list((err, processes) => {
|
|
579
|
+
console.error(err);
|
|
580
|
+
processes.forEach((p) => {
|
|
581
|
+
console.log("p.pid, p.name, p.pm_id", p.pid, p.name, p.pm_id);
|
|
582
|
+
if (p.name === pName && p.pid) {
|
|
583
|
+
const message = {
|
|
584
|
+
// these fields must be present
|
|
585
|
+
id: p.pid,
|
|
586
|
+
topic: "some topic",
|
|
587
|
+
type: "process:msg",
|
|
588
|
+
// Data to be sent
|
|
589
|
+
data: {
|
|
590
|
+
testResourceConfiguration: {
|
|
591
|
+
ports: [],
|
|
592
|
+
// fs: fPath,
|
|
593
|
+
},
|
|
594
|
+
id: p.pm_id,
|
|
595
|
+
},
|
|
596
|
+
};
|
|
597
|
+
console.log("message", message);
|
|
598
|
+
if ((testResourceRequirement === null || testResourceRequirement === void 0 ? void 0 : testResourceRequirement.ports) === 0) {
|
|
599
|
+
pm2_1.default.sendDataToProcessId(p.pm_id, message, function (err, res) {
|
|
600
|
+
// console.log("sendDataToProcessId", err, res, message);
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
if (((testResourceRequirement === null || testResourceRequirement === void 0 ? void 0 : testResourceRequirement.ports) || 0) > 0) {
|
|
604
|
+
// clear any port-slots associated with this job
|
|
605
|
+
Object.values(this.ports).forEach((jobMaybe, portNumber) => {
|
|
606
|
+
if (jobMaybe && jobMaybe === pName) {
|
|
607
|
+
this.ports[portNumber] = OPEN_PORT;
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
// find a list of open ports
|
|
611
|
+
const foundOpenPorts = Object.keys(this.ports).filter((p) => this.ports[p] === OPEN_PORT);
|
|
612
|
+
// if there are enough open port-slots...
|
|
613
|
+
if (foundOpenPorts.length >= testResourceRequirement.ports) {
|
|
614
|
+
const selectionOfPorts = foundOpenPorts.slice(0, testResourceRequirement.ports);
|
|
615
|
+
const message = {
|
|
616
|
+
// these fields must be present
|
|
617
|
+
id: p.pid,
|
|
618
|
+
topic: "some topic",
|
|
619
|
+
// process:msg will be send as 'message' on target process
|
|
620
|
+
type: "process:msg",
|
|
621
|
+
// Data to be sent
|
|
622
|
+
data: {
|
|
623
|
+
testResourceConfiguration: {
|
|
624
|
+
// fs: fPath,
|
|
625
|
+
ports: selectionOfPorts,
|
|
626
|
+
},
|
|
627
|
+
id: p.pid,
|
|
628
|
+
},
|
|
629
|
+
};
|
|
630
|
+
pm2_1.default.sendDataToProcessId(p.pm_id, message, function (err, res) {
|
|
631
|
+
// no-op
|
|
632
|
+
});
|
|
633
|
+
// mark the selected ports as occupied
|
|
634
|
+
for (const foundOpenPort of selectionOfPorts) {
|
|
635
|
+
this.ports[foundOpenPort] = p.pid.toString();
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
console.log(`no port was open so send the ${p.pid} job to the back of the resourceQueue`);
|
|
640
|
+
this.resourceQueue.push(resourceRequest);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
exports.ITProject = ITProject;
|