systemview 1.6.2 → 1.7.3

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.
@@ -13,11 +13,10 @@ module.exports = async function appIsRunning(appUrls) {
13
13
  responses.forEach((res, index) => {
14
14
  if (res.statusCode !== 200) {
15
15
  allAppsRunning = false;
16
- console.log(`App ${index + 1} is not running`);
16
+ console.log(`App ${appUrls[index]} is not running`);
17
17
  }
18
18
  });
19
19
  } catch (err) {
20
- console.error("Error pinging apps:", err.message);
21
20
  allAppsRunning = false;
22
21
  }
23
22
 
package/cli/index.js CHANGED
@@ -6,28 +6,73 @@
6
6
  *
7
7
  * @author Odion Edwards <none>
8
8
  */
9
-
9
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
10
10
  const init = require("./utils/init");
11
11
  const cli = require("./utils/cli");
12
12
  const log = require("./utils/log");
13
13
 
14
14
  const launchApp = require("./launchApp");
15
- const startLineReader = require("./startLineReader");
16
15
  const runTests = require("./runTests");
16
+ const appIsRunning = require("./appIsRunning");
17
+ const { HttpClient } = require("systemlynx");
17
18
 
18
19
  const input = cli.input;
19
20
  const flags = cli.flags;
20
21
  const { clear, debug } = flags;
21
-
22
+ const DEFAULT_PORT = 3000;
23
+ async function launch(_port) {
24
+ const port = isNaN(_port) ? DEFAULT_PORT : _port;
25
+ try {
26
+ await launchApp(port);
27
+ } catch (error) {
28
+ log("Launch failed:" + error.message, "error");
29
+ }
30
+ }
22
31
  (async () => {
23
32
  init({ clear });
24
33
  if (input.includes(`help`)) {
25
34
  cli.showHelp(0);
26
35
  } else if (input.includes("test")) {
27
- if (await launchApp()) await runTests(input[1]);
36
+ const api = `http://localhost:${DEFAULT_PORT}/systemview/api`;
37
+ try {
38
+ input.shift();
39
+ if (await appIsRunning([api])) {
40
+ await runTests(api, ...input);
41
+ process.exit();
42
+ } else {
43
+ await launch();
44
+ await runTests(api, ...input);
45
+ process.exit();
46
+ }
47
+ } catch (error) {
48
+ console.error("Error executing tests:", error.message);
49
+ }
50
+ } else if (["exit", "q", "shutdown"].includes(input[0])) {
51
+ const port = isNaN(input[1]) ? DEFAULT_PORT : input[1];
52
+ const api = `http://localhost:${port}/systemview/api`;
53
+ if (await appIsRunning([api])) {
54
+ const url = `${api}/SystemView/shutdown`;
55
+ const method = "put";
56
+ log("SystemView is running from another terminal", "info", "info");
57
+ log("Attempting remote shutdown...", "info", "info");
58
+ HttpClient.request({ url, method })
59
+ .then(() => console.log("SystemView shutdown successful!"))
60
+ .catch(async (error) => {
61
+ if (await appIsRunning([api])) {
62
+ log("Remote shutdown failed!", "error", "error");
63
+ } else {
64
+ console.log("SystemView shutdown successful!");
65
+ }
66
+ });
67
+ } else {
68
+ log(`SystemView instance not found @${api}`, "warning", "warning");
69
+ console.log("Please include the port if default port is not being used:");
70
+ log("systemview shutdown 4000", "info", "example");
71
+ }
72
+ } else if (input[0] === "start") {
73
+ launch(input[1]);
28
74
  } else {
29
- const shutdown = await launchApp();
30
- if (typeof shutdown === "function") startLineReader(shutdown);
75
+ launch();
31
76
  }
32
77
 
33
78
  cli.input = [];
package/cli/launchApp.js CHANGED
@@ -1,48 +1,22 @@
1
1
  const log = require("./utils/log");
2
- const { spawn } = require("child_process");
3
- const path = require("path");
4
2
  const appIsRunning = require("./appIsRunning");
5
- const parentDirectory = path.resolve(__dirname, "..");
6
- const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
3
+ const launchSystemView = require("../api");
4
+ const startLineReader = require("./startLineReader");
7
5
 
8
- function logConnection(api, app) {
6
+ function logConnection(api) {
9
7
  log("connected!", "success");
10
- console.log(`SystemView API running @${api}`);
11
- console.log(`SystemView UI running @${app}`);
8
+ console.log(`SystemView UI running @${api}`);
9
+ console.log(`SystemView API running @${api}/systemview/api`);
12
10
  }
13
- module.exports = async function launchApp(_port) {
14
- const port = isNaN(_port) ? 3000 : _port;
15
- const env = Object.create(process.env);
16
- const api = `http://localhost:${3300}/systemview/api`;
17
- const app = `http://localhost:${port}/`;
18
- env.PORT = port;
19
-
20
- if (await appIsRunning([api, app])) {
11
+ module.exports = async function launchApp(port) {
12
+ const api = `http://localhost:${port}/systemview/api`;
13
+ if (await appIsRunning([api])) {
21
14
  log("SystemView is running from another terminal", "info", "info");
22
- logConnection(api, app);
23
- return true;
15
+ logConnection(api);
24
16
  } else {
25
17
  log("Launching...");
26
-
27
- const appProcess = spawn("node", ["api & node server"], {
28
- stdio: ["inherit"],
29
- shell: true,
30
- env,
31
- cwd: parentDirectory,
32
- });
33
-
34
- appProcess.on("close", (code) => {
35
- console.log(`SystemView APP exited with code ${code}`);
36
- });
37
- const shutdown = () => {
38
- if (appProcess) appProcess.kill();
39
- };
40
-
41
- await delay(2000);
42
- const isRunning = await appIsRunning([api, app]);
43
- if (isRunning) {
44
- logConnection(api, app);
45
- return shutdown;
46
- }
18
+ await launchSystemView(port);
19
+ logConnection(api);
20
+ startLineReader(api);
47
21
  }
48
22
  };
package/cli/runTests.js CHANGED
@@ -3,60 +3,115 @@ const { initializeSavedTests } = require("../testing-utilities/transformTests");
3
3
  const FullTestController = require("../testing-utilities/FullTestController");
4
4
  const log = require("./utils/log");
5
5
  const validationMessages = require("../testing-utilities/validtionMessages");
6
- module.exports = async function runTests(project_code) {
6
+ const PARTITION =
7
+ "-------------------------------------------------------------------------";
8
+
9
+ module.exports = async function runTests(
10
+ api,
11
+ project_code,
12
+ namespace,
13
+ printAll,
14
+ trackTime
15
+ ) {
7
16
  if (!project_code) {
8
17
  return log("project_code or service_url are required", "warning", "warning");
9
18
  }
10
19
  // get connected services from the systemview api
11
- const connectedServices = await getConnectedServices(project_code);
20
+ const connectedServices = await getConnectedServices(api, project_code);
12
21
  //get all the test for each service or the targeted services
13
22
  if (!connectedServices.length) {
14
- return log("No connected services found!", "warning");
23
+ log("No connected services found!", "warning");
24
+ console.log(
25
+ "You may have to refresh your systemlynx apps for project_code: " + project_code
26
+ );
27
+ return;
15
28
  } else {
16
29
  connectedServices.forEach(({ serviceId, system }) => {
17
- log(`connected @${system.connectionData.serviceUrl}`, "success", serviceId);
30
+ log(`connected! @${system.connectionData.serviceUrl}`, "success", serviceId);
18
31
  });
19
32
  }
20
33
 
21
- const Tests = await getTests(connectedServices);
22
- //transform the test from the saved format to the testing format
34
+ const testsReceived = await getTests(connectedServices);
35
+
36
+ const testToRun = !namespace
37
+ ? testsReceived
38
+ : testsReceived
39
+ .map((testList) => {
40
+ return testList.filter(({ namespace: n }) => {
41
+ return `${n.serviceId}.${n.moduleName}.${n.methodName}`.includes(namespace);
42
+ });
43
+ })
44
+ .filter((testList) => testList.length);
45
+
46
+ if (testToRun.length) {
47
+ const executeTest = async (savedTests) => {
48
+ const tests = initializeSavedTests(savedTests, connectedServices);
49
+ await runAllTests(tests, trackTime);
50
+ };
23
51
 
24
- const executeTest = async (savedTests) => {
25
- const tests = initializeSavedTests(savedTests, connectedServices);
26
- await runAllTests(tests);
27
- };
28
- (
29
52
  await new Promise((resolve) => {
30
53
  async function recursiveExecuteTest(i = 0) {
31
- const { serviceId } = connectedServices[i];
32
- log(`Initializing Tests...`, "info", serviceId);
33
- if (i === Tests.length) resolve();
34
- else executeTest(Tests[0]).then(() => recursiveExecuteTest(i + 1));
54
+ if (i === testToRun.length) resolve();
55
+ else {
56
+ const { serviceId } = testToRun[i][0].namespace;
57
+ log(`Initializing Tests...`, "info", serviceId);
58
+ executeTest(testToRun[i]).then(() => recursiveExecuteTest(i + 1));
59
+ }
35
60
  }
36
61
  recursiveExecuteTest();
37
- })
38
- )();
62
+ });
63
+ } else {
64
+ log(`No tests found matching ${project_code} ${namespace}`, "warning", "warning");
65
+ }
39
66
  };
67
+
40
68
  const Logger = function (trackTime) {
41
69
  this.start = (test) => {
42
- if (trackTime) {
43
- }
70
+ // if (trackTime) {
71
+ // console.log
72
+ // }
44
73
  };
45
74
 
46
- this.end = ({ errors }) => {
47
- errors.forEach((err) => {
48
- const msg = validationMessages(err);
49
- log(msg, "error", err.namespace);
50
- });
75
+ this.end = ({ errors, results, namespace, title }) => {
76
+ // const { moduleName, methodName, serviceId } = namespace;
77
+ // if (errors.length) {
78
+ // log(title, "error", "failed");
79
+ // console.error(results);
80
+ // errors.forEach((err) => console.log(validationMessages(err)));
81
+ // } else {
82
+ // log(title, "success", "passed");
83
+ // console.log(`${serviceId}.${moduleName}.${methodName}(...)`);
84
+ // }
51
85
  };
52
86
  };
87
+ const sections = ["Before", "Main", "Events", "After"];
53
88
  const { runFullTest } = new FullTestController();
54
- const runAllTests = async (savedTest) => {
89
+ const runAllTests = async (savedTest, trackTime) => {
55
90
  const runTest = async ({ Before, Main, Events, After }) => {
56
91
  const fullTest = [Before, Main, Events, After];
57
- const [B, M, E, A] = await runFullTest(fullTest, new Logger());
92
+ const results = await runFullTest(fullTest, new Logger(trackTime));
58
93
  const { title, namespace } = Main[0];
59
- return { Before: B, Main: M, Events: E, After: A, title, namespace };
94
+ const { serviceId, moduleName, methodName } = namespace;
95
+ const totalError = results.reduce((sum, testSection) => {
96
+ return sum + testSection.reduce((sum, test) => (sum += test.errors.length), 0);
97
+ }, 0);
98
+ //console.log(PARTITION);
99
+ // console.log(PARTITION);
100
+ if (totalError) {
101
+ log(title + ` (${totalError} errors)`, "error", namespace.serviceId);
102
+ results.forEach((testSection) => {
103
+ testSection.forEach(({ errors, results, namespace, title }, i) => {
104
+ const { serviceId, moduleName, methodName } = namespace;
105
+ log(title, "error", sections[i]);
106
+ console.log(`${serviceId}${moduleName}.${methodName}(..)`);
107
+ console.log(results);
108
+ errors.forEach((err) => console.log(validationMessages(err)));
109
+ });
110
+ });
111
+ } else {
112
+ log(title, "success", namespace.serviceId);
113
+ console.log(`---> ${serviceId}.${moduleName}.${methodName}(..)`);
114
+ }
60
115
  };
61
116
 
62
117
  await new Promise((resolve) => {
@@ -73,7 +128,7 @@ async function getTests(connectedServices) {
73
128
 
74
129
  return (async function recursiveGetTests(i = 0) {
75
130
  if (i < connectedServices.length) {
76
- const { connectionData } = connectedServices[1].system;
131
+ const { connectionData } = connectedServices[i].system;
77
132
  try {
78
133
  results.push(await Client.createService(connectionData).Plugin.getTests());
79
134
  } catch (error) {
@@ -85,13 +140,11 @@ async function getTests(connectedServices) {
85
140
  })();
86
141
  });
87
142
  }
88
- async function getConnectedServices(project_code) {
143
+ async function getConnectedServices(api, project_code) {
89
144
  try {
90
- const { SystemView } = await Client.loadService(
91
- "http://localhost:3300/systemview/api"
92
- );
145
+ const { SystemView } = await Client.loadService(api);
93
146
  try {
94
- return SystemView.getServices(project_code);
147
+ return await SystemView.getServices(project_code);
95
148
  } catch (error) {}
96
149
  } catch (error) {
97
150
  console.log("Failed to connect to systemview");
@@ -3,18 +3,22 @@ const cli = require("./utils/cli");
3
3
 
4
4
  const readline = require("readline");
5
5
 
6
- module.exports = function startLineReader(shutdown) {
6
+ module.exports = function startLineReader(api) {
7
7
  const lineReader = readline.createInterface({
8
8
  input: process.stdin,
9
9
  output: process.stdout,
10
10
  });
11
11
  const handleInput = (input = "") => {
12
- const [command, argument] = input.split(" ").map((s) => s.trim());
13
- if (["exit", "q"].includes(command)) {
14
- shutdown();
15
- lineReader.close();
12
+ const args = input.split(" ").map((s) => s.trim());
13
+ const command = args.shift();
14
+ if (["exit", "q", "shutdown"].includes(command)) {
15
+ process.exit(0);
16
16
  } else if (command === "test") {
17
- runTests(argument);
17
+ try {
18
+ runTests(api, ...args);
19
+ } catch (error) {
20
+ console.error("Error executing tests:", error.message);
21
+ }
18
22
  } else if (command === "help") {
19
23
  cli.showHelp(0);
20
24
  }
@@ -23,5 +27,6 @@ module.exports = function startLineReader(shutdown) {
23
27
 
24
28
  lineReader.prompt();
25
29
  lineReader.on("line", handleInput);
26
- lineReader.on("close", shutdown);
30
+ lineReader.on("close", () => process.exit(0));
31
+ return lineReader;
27
32
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "systemview",
3
3
  "description": "A documentation and testing suite for SystemLynx",
4
- "version": "1.6.2",
4
+ "version": "1.7.3",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
7
7
  "systemview": "cli/index.js"
@@ -83,6 +83,7 @@
83
83
  "cli/",
84
84
  "api/",
85
85
  "build/",
86
+ "testing-utilities",
86
87
  "server.js"
87
88
  ]
88
89
  }
@@ -0,0 +1,90 @@
1
+ const {
2
+ isTargetValueFn,
3
+ isTargetNamespace,
4
+ targetValueFnRegex,
5
+ obj,
6
+ isEqualArrays,
7
+ isFunction,
8
+ strFn,
9
+ } = require("./test-helpers");
10
+
11
+ function TargetValue(target_namespace, source_map = [], source_index = 0) {
12
+ this.target_namespace = target_namespace;
13
+ this.source_map = source_map;
14
+ this.source_index = source_index;
15
+ }
16
+ function Argument(name, FullTest, input_type = "undefined", input, targetValues = []) {
17
+ this.name = name;
18
+ this.input = input;
19
+ this.input_type = input_type;
20
+ this.data_type = "";
21
+ this.targetValues = targetValues;
22
+
23
+ this.value = () => {
24
+ return this.targetValues.reduce((arg, { source_map, target_namespace: nsp }) => {
25
+ const [value, placeholder, key] = obj(arg).parse(source_map);
26
+
27
+ if (isTargetValueFn(nsp)) {
28
+ placeholder[key] = value
29
+ .trim()
30
+ .replace(nsp, getTargetValue(nsp.substring(3, nsp.length - 1)));
31
+ } else if (isTargetNamespace(nsp)) {
32
+ placeholder[key] = getTargetValue(nsp);
33
+ } else {
34
+ placeholder[key] = strFn(nsp);
35
+ }
36
+
37
+ return arg;
38
+ //creating a deep copy in order to lose refs to original
39
+ }, obj(this).clone()).input;
40
+ };
41
+
42
+ this.parseTargetValues = (input, source_map) => {
43
+ //extract one or more target replacer text from string (i.e. "tv(beforeTest.Action1.error)")
44
+ Array.from(input.matchAll(targetValueFnRegex)).forEach((match) => {
45
+ this.addTargetValue(match[0], source_map, match.index);
46
+ });
47
+ if (isTargetNamespace(input) || isFunction(input))
48
+ this.addTargetValue(input, source_map, 0);
49
+
50
+ return this;
51
+ };
52
+
53
+ this.checkTargetNamespaces = () => {
54
+ // check target namespaces against current input for deletion
55
+ //keep if the target value string still exist on this.input...
56
+ this.targetValues = this.targetValues.filter(
57
+ ({ target_namespace, source_map, source_index }) => {
58
+ const value = obj(this).valueAt(source_map);
59
+ return (
60
+ typeof value === "string" &&
61
+ value.indexOf(target_namespace, source_index) === source_index
62
+ );
63
+ }
64
+ );
65
+ return this;
66
+ };
67
+
68
+ this.addTargetValue = (target_namespace, source_map = [], source_index) => {
69
+ //check to see if target value already exists first
70
+ this.targetValues.findIndex(
71
+ (tv) =>
72
+ tv.target_namespace === target_namespace &&
73
+ isEqualArrays(tv.source_map, source_map) &&
74
+ tv.source_index === source_index
75
+ ) === -1 &&
76
+ this.targetValues.push(new TargetValue(target_namespace, source_map, source_index));
77
+ return this;
78
+ };
79
+
80
+ const getTargetValue = (input) => {
81
+ const [test, action] = input.split(".");
82
+ const nsp = input
83
+ .replace(test, { beforeTest: 0, mainTest: 1, Events: 2, afterTest: 3 }[test])
84
+ .replace(action, parseInt(action.replace("Action", "")) - 1)
85
+ .replace("error", "results");
86
+ return obj(FullTest).valueAtNsp(nsp);
87
+ };
88
+ }
89
+
90
+ module.exports = { Argument, TargetValue, default: Argument };
@@ -0,0 +1,78 @@
1
+ const Test = require("./Test.class");
2
+
3
+ const sections = ["Before", "Main", "Events", "After"];
4
+
5
+ module.exports = function FullTestController({ FullTest, connectedServices } = {}) {
6
+ this.runFullTest = async ([Before, Main, Events, After] = FullTest || [], Logger) => {
7
+ Events.forEach((test) => test.runTest(Logger));
8
+
9
+ await new Promise((resolve) => {
10
+ function recursiveRunTest(tests, i = 0) {
11
+ if (i === tests.length) resolve();
12
+ else tests[i].runTest(Logger).then(() => recursiveRunTest(tests, i + 1));
13
+ }
14
+ recursiveRunTest([...Before, ...Main, ...After]);
15
+ });
16
+
17
+ return [Before, Main, Events, After];
18
+ };
19
+
20
+ function validateTest({ title, evaluations, shouldValidate }, section, index) {
21
+ if (!title)
22
+ return {
23
+ message: `${sections[section]}: Action ${index + 1} description is required`,
24
+ error: true,
25
+ };
26
+ if (shouldValidate && !evaluations.filter((e) => e.save).length)
27
+ return {
28
+ message: `${sections[section]}: Action ${index + 1} validations required`,
29
+ error: true,
30
+ };
31
+
32
+ return { error: false };
33
+ }
34
+ this.saveTests = async (Tests = FullTest) => {
35
+ const { title, getConnection, namespace, index } = Tests[1][0];
36
+
37
+ for (let i = 0; i < Tests.length; i++) {
38
+ for (let x = 0; x < Tests.length; x++) {
39
+ const res = Tests[i][x] ? validateTest(Tests[i][x], i, x) : {};
40
+ if (res.error) return res;
41
+ }
42
+ }
43
+
44
+ const { connection } = getConnection(connectedServices);
45
+
46
+ const { Plugin } = connection[namespace.serviceId];
47
+
48
+ if (Plugin) {
49
+ const [Before, Main, Events, After] = Tests.map((testSection) =>
50
+ testSection.map((test) => {
51
+ const { args, evaluations, namespace, title } = test;
52
+ //resetting scope of test
53
+ Object.assign(test, new Test(test));
54
+ return {
55
+ args,
56
+ namespace,
57
+ title,
58
+ savedEvaluations: evaluations
59
+ .filter((e) => e.save)
60
+ .map(({ namespace, expected_type, validations, save, indexed }) => ({
61
+ namespace,
62
+ expected_type,
63
+ validations,
64
+ save,
65
+ indexed,
66
+ })),
67
+ };
68
+ })
69
+ );
70
+
71
+ const testIndex = await Plugin.saveTest(
72
+ { Before, Main, Events, After, title, namespace },
73
+ index
74
+ );
75
+ return { message: "Test Saved!", error: false, testIndex };
76
+ } else return { message: "Plugin Plugin not connected!", error: true };
77
+ };
78
+ };