testilo 5.0.0 → 6.1.0

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/README.md CHANGED
@@ -25,9 +25,40 @@ The reason for Testilo being an independent package, rather than part of Testaro
25
25
 
26
26
  ## Utilities
27
27
 
28
+ ### `aim`
29
+
30
+ The `aim` function allows you to _aim_ a script at a host. That means modifying the script so that it performs its operations on the specified host. The modifications are:
31
+ - Modify the value of the `id` property of the script by:
32
+ - Prefixing the value with a time stamp.
33
+ - Suffixing the value with the value of the `id` property of the host.
34
+ - Modify each `url` command of the script by changing the values of its `which`, `what`, and `id` properties to the values of those properties of the host.
35
+ - Add a `source` property to the script, identifying the script, the host, and the requester.
36
+
37
+ Execution by a module:
38
+
39
+ ```javaScript
40
+ const host = {
41
+ which: https://w3c.org/,
42
+ what: 'World Wide Web Consortium',
43
+ id: w3c
44
+ };
45
+ const fs = require('fs/promises');
46
+ const {aim} = require('testilo/aim');
47
+ const aimedScript = aim('tp25', host, 'developer@w3c.org');
48
+ fs.writeFile(process.env.JOBDIR, JSON.stringify(aimedScript, null, 2));
49
+ ```
50
+
51
+ Execution by a user:
52
+
53
+ ```bash
54
+ node call aim tp25 https://w3.org/ 'World Wide Web Consortium' w3c developer@w3c.org
55
+ ```
56
+
57
+ In these examples, a copy of the script file named `tp25.json` in the `SCRIPTDIR` directory is aimed at the World Wide Web Consortium and then saved in the `JOBDIR` directory.
58
+
28
59
  ### `merge`
29
60
 
30
- The `merge` utility is useful when you want Testaro to perform the same set of operations on multiple hosts. For example, you may want the same tests run on multiple web pages. You would have a single script, and you would want multiple jobs created from it. Each job would target one host, and, for that purpose, any `url` command in the script would be modified so that its properties are those of that host. The `merge` utility (similar to mail merge in office applications) does this. It creates Testaro jobs out of a script and a _batch_.
61
+ The `merge` function is similar to the `aim` function, but it aims a script at multiple hosts, not only one. The hosts are identified in a _batch_, a file in the `BATCHDIR` directory. The output of `merge` is multiple script files, one per host, saved in the `JOBDIR` directory.
31
62
 
32
63
  A batch is a JSON-format file representing a `batch` object, which contains an array of _hosts_.
33
64
 
@@ -52,84 +83,92 @@ Here is an example of a batch:
52
83
  }
53
84
  ```
54
85
 
55
- The `merge` utility finds all the `url` commands in a script (telling the browser what to visit), replaces them with one of the hosts in the batch, and outputs the modified script as a job. It then does the same with each of the other hosts in the batch.
86
+ Execution by a module:
56
87
 
57
- To execute `merge`, you need to have three environment variables defined to tell `merge` where files are located. You can define the environment variables in the `.env` file. Here is an example:
58
-
59
- ```
60
- SCRIPTDIR=../testing/scripts
61
- BATCHDIR=../testing/batches
62
- JOBDIR=../testing/jobs
88
+ ```javaScript
89
+ const {merge} = require('testilo/merge');
90
+ merge('tp25', 'weborgs')
91
+ .then(() => {
92
+ console.log('Merger complete');
93
+ });
63
94
  ```
64
95
 
65
- In this example, the script, batch, and job files are located in directories named `scripts`, `batches`, and `jobs` within `testing`, which is a sibling directory of the Testilo project directory.
66
-
67
- The syntax of the `merge` statement is documented in `merge.js`.
96
+ Execution by a user:
68
97
 
69
- Suppose that:
70
- - The environment variables are defined as in the above example.
71
- - There is a script file named `testall.json`.
72
- - The above batch example is in a file named `usFedExec1.json`.
73
-
74
- The statement `node merge testall usFedExec1 allFedExec` would tell Testilo to merge the batch `../testing/batches/usFedExec1.json` and the script `../testing/scripts/testall.json` into two job files and save those files in the directory `../testing/jobs/allFedExec`. Testilo will create any directories necessary to save the files there.
98
+ ```bash
99
+ node call merge tp25 weborgs
100
+ ```
75
101
 
76
102
  ### `score`
77
103
 
78
104
  Testaro performs tests and produces reports of test results. Testilo can add scores to those reports. In this way, each report can not only detail successes and failures of individual tests but also assign scores to those results and combine the partial scores into total scores.
79
105
 
80
- The `score` utility performs scoring. It depends on score procs to define the scoring rules. Some score procs are in the Testilo package (in the `procs/score` directory), and you can create more score procs to implement different rules.
106
+ The `score` function performs scoring. It depends on _score procs_ to define the scoring rules. Some score procs are in the Testilo package (in the `procs/score` directory), and you can create more score procs to implement different rules.
81
107
 
82
- You can score multiple reports with a single invocation of `score`.
108
+ Execution by a module:
83
109
 
84
- To execute `score`, you need to have two environment variables defined to tell `score` where files are located. You can define the environment variables in the `.env` file. Here is an example:
85
-
86
- ```
87
- REPORTDIR_RAW=../testing/reports/raw
88
- REPORTDIR_SCORED=../testing/reports/scored
110
+ ```javaScript
111
+ const {score} = require('testilo/score');
112
+ score('sp25a', '756mr')
113
+ .then(hostCount => {
114
+ console.log(`Scoring complete. Count of reports scored: ${hostCount}`);
115
+ });
89
116
  ```
90
117
 
91
- The named directories must already exist.
118
+ Execution by a user:
92
119
 
93
- The syntax of the `score` statement is documented in `score.js`.
120
+ ```bash
121
+ node call score sp25a 756mr
122
+ ```
94
123
 
95
- A scored report file is identical to the file it was created from, except that the scored report has new properties named `score` and `scoreProcID`. The `score` property contains the scores.
124
+ The first argument to `score` names the score proc to be used. The second argument is optional. If it is present, then only reports whose names begin with the value of that argument will be scored. Otherwise all reports in the `REPORTDIR_RAW` directory will be scored. The scored reports will be written in the `REPORTDIR_SCORED` directory.
96
125
 
97
126
  ### `digest`
98
127
 
99
- Testaro reports, both originally and after they are scored, are JSON files. That format is basically designed for machine tractability.
128
+ Testaro reports, both originally and after they are scored, are JSON files. That format is human-readable, but it is basically designed for machine tractability.
100
129
 
101
- The `digest` utility converts scored reports into HTML documents with explanatory content. Thus, it converts machine-oriented reports into human-oriented reports, called _digests_. It depends on digest procs to define the digesting rules. Some digest procs are in the Testilo package (in the `procs/digest` directory), and you can create more digest procs to implement different rules.
130
+ The `digest` function converts scored reports into HTML documents with explanatory content. Thus, it converts machine-oriented reports into human-oriented reports, called _digests_. It depends on _digest procs_ to define the digesting rules. Some digest procs are in the Testilo package (in the `procs/digest` directory), and you can create more digest procs to implement different rules.
102
131
 
103
- You can digest multiple scored reports with a single invocation of `digest`.
132
+ Execution by a module:
104
133
 
105
- To execute `digest`, you need to have two environment variables defined to tell `digest` where files are located. You can define the environment variables in the `.env` file. Here is an example:
106
-
107
- ```
108
- REPORTDIR_SCORED=../testing/reports/scored
109
- REPORTDIR_DIGESTED=../testing/reports/digested
134
+ ```javaScript
135
+ const {digest} = require('testilo/digest');
136
+ digest('dp25a', '756mr')
137
+ .then(hostCount => {
138
+ console.log(`Digesting complete. Count of reports digested: ${hostCount}.`);
139
+ });
110
140
  ```
111
141
 
112
- The named directories must already exist.
142
+ Execution by a user:
113
143
 
114
- The syntax of the `digest` statement is documented in `digest.js`.
144
+ ```bash
145
+ node call digest sp25a 756mr
146
+ ```
115
147
 
116
- The digests created by `digest` are HTML files, and they expect a `style.css` file to exist in their directory. The `reports/digested/style.css` file in Testilo is an appropriate stylesheet to be copied into `process.env.REPORTDIR_DIGESTED`.
148
+ The first argument to `digest` names the digest proc to be used. The second argument is optional. If it is present, then only reports whose names begin with the value of that argument will be digested. Otherwise all reports in the `REPORTDIR_SCORED` directory will be digested. The digested reports will be written in the `REPORTDIR_DIGESTED` directory.
117
149
 
118
- ### `compare`
150
+ The digests created by `digest` are HTML files, and they expect a `style.css` file to exist in their directory. The `reports/digested/style.css` file in Testilo is an appropriate stylesheet to be copied into the `REPORTDIR_DIGESTED` directory.
119
151
 
120
- You can summarize the results of a multi-host job by producing a document comparing the scores received by the hosts. The `compare` utility does this.
152
+ ### `compare`
121
153
 
122
- The `compare` utility gathers scores from a set of scored reports and produces an HTML document comparing the scores. It depends on compare procs to define the rules for making and showing the comparative scores. Some compare procs are in the Testilo package (in the `procs/compare` directory), and you can create more compare procs to implement different rules.
154
+ You can summarize the results of a multi-host job by producing a document comparing the scores received by the hosts. The `compare` function does this. It gathers scores from a set of scored reports and produces an HTML document comparing the scores. It depends on _comparison procs_ to define the rules for making and showing the comparative scores. Some compare procs are in the Testilo package (in the `procs/compare` directory), and you can create more compare procs to implement different rules.
123
155
 
124
- To execute `compare`, you need to have two environment variables defined to tell `digest` where files are located. You can define the environment variables in the `.env` file. Here is an example:
156
+ Execution by a module:
125
157
 
126
- ```
127
- REPORTDIR_SCORED=../testing/reports/scored
128
- COMPARISONDIR=../testing/reports/compared
158
+ ```javaScript
159
+ const {compare} = require('testilo/compare');
160
+ compare('cp25a', 'legislators')
161
+ .then(() => {
162
+ console.log(`Comparison complete`);
163
+ });
129
164
  ```
130
165
 
131
- The named directories must already exist.
166
+ Execution by a user:
167
+
168
+ ```bash
169
+ node call compare cp25a legislators
170
+ ```
132
171
 
133
- The syntax of the `compare` statement is documented in `compare.js`.
172
+ The first argument to `compare` names the comparison proc to be used. The second argument specifies a base of the name of the comparative report that will be produced. The scores in all reports in the `REPORTDIR_SCORED` directory will be compared. The comparative report will be written in the `COMPARISONDIR` directory.
134
173
 
135
- The comparisons created by `compare` are HTML files, and they expect a `style.css` file to exist in their directory. The `reports/comparative/style.css` file in Testilo is an appropriate stylesheet to be copied into `process.env.COMPARISONDIR`.
174
+ The digests created by `compare` are HTML files, and they expect a `style.css` file to exist in their directory. The `reports/comparative/style.css` file in Testilo is an appropriate stylesheet to be copied into the `COMPARISONDIR` directory.
package/aim.js CHANGED
@@ -1,14 +1,6 @@
1
1
  /*
2
2
  aim.js
3
- Returns a script aimed at a host.
4
- Arguments:
5
- 0. base of name of script located in process.env.SCRIPTDIR.
6
- 1. ID of the host.
7
- 2. URL of the host.
8
- 3. Name of the host.
9
- 4. ID of the requester.
10
- Usage example:
11
- node aim tp18 w3c https://www.w3.org/ 'World Wide Web Consortium'
3
+ Module for aiming a script at a host.
12
4
  */
13
5
 
14
6
  // ########## IMPORTS
package/call.js ADDED
@@ -0,0 +1,119 @@
1
+ /*
2
+ do.js
3
+ Invokes Testilo modules with arguments.
4
+ This is the universal module for use of Testilo from a command line.
5
+ Arguments:
6
+ 0. function to execute.
7
+ 1+. arguments to pass to the function.
8
+ Usage examples:
9
+ node call aim script454 https://www.w3c.org/ 'World Wide Web Consortium' w3c
10
+ node call merge script454 webOrgs
11
+ node call score sp25a (to score all reports in REPORTDIR_RAW)
12
+ node call score sp25a 8ep9f- (same, but only if names start with 8ep9f-)
13
+ node call digest dp25a (to digest all reports in REPORTDIR_SCORED)
14
+ node call digest dp25a 8ep9f- (same, but only if names start with 8ep9f-)
15
+ node call compare cp25a weborgs (to write weborgs.html, comparing all reports in REPORTDIR_SCORED)
16
+ */
17
+
18
+ // ########## IMPORTS
19
+
20
+ // Module to keep secrets.
21
+ require('dotenv').config();
22
+ // Function to process a script aiming.
23
+ const {aim} = require('./aim');
24
+ // Function to process a script-batch merger.
25
+ const {merge} = require('./merge');
26
+ // Function to score reports.
27
+ const {score} = require('./score');
28
+ // Function to digest reports.
29
+ const {digest} = require('./digest');
30
+ // Function to compare scores.
31
+ const {compare} = require('./compare');
32
+
33
+ // ########## CONSTANTS
34
+
35
+ const jobDir = process.env.JOBDIR;
36
+ const scoredDir = process.env.REPORTDIR_SCORED;
37
+ const digestedDir = process.env.REPORTDIR_DIGESTED;
38
+ const comparisonDir = process.env.COMPARISONDIR;
39
+ const fn = process.argv[2];
40
+ const fnArgs = process.argv.slice(3);
41
+
42
+ // ########## FUNCTIONS
43
+
44
+ // Fulfills an aiming request.
45
+ const callAim = async (scriptName, hostURL, hostName, hostID, notifyee) => {
46
+ await aim(
47
+ scriptName,
48
+ {
49
+ id: hostID,
50
+ which: hostURL,
51
+ what: hostName
52
+ },
53
+ notifyee
54
+ );
55
+ console.log(`Script ${scriptID}.json has been aimed at ${hostName}`);
56
+ };
57
+ // Fulfills a merger request.
58
+ const callMerge = async (scriptName, batchName) => {
59
+ await merge(scriptName, batchName);
60
+ console.log(`Batch ${batchName}.json merged into script ${scriptName} in ${jobDir}`);
61
+ };
62
+ // Fulfills a scoring request.
63
+ const callScore = async (scoreProcID, reportIDStart) => {
64
+ const reportCount = await score(scoreProcID, reportIDStart);
65
+ console.log(
66
+ `Scoring completed. Score proc: ${scoreProcID}. Report count: ${reportCount}. Directory: ${scoredDir}`
67
+ );
68
+ };
69
+ // Fulfills a digesting request.
70
+ const callDigest = async (digestProcID, reportIDStart) => {
71
+ const reportCount = await digest(digestProcID, reportIDStart);
72
+ console.log(
73
+ `Digesting completed. Digest proc: ${digestProcID}. Report count: ${reportCount}. Directory: ${digestedDir}`
74
+ );
75
+ };
76
+ // Fulfills a comparison request.
77
+ const callCompare = async (compareProcID, comparisonNameBase) => {
78
+ await compare(compareProcID, comparisonNameBase);
79
+ console.log(
80
+ `Comparison completed. Comparison proc: ${compareProcID}. Directory: ${comparisonDir}`
81
+ );
82
+ };
83
+
84
+ // ########## OPERATION
85
+
86
+ // Execute the requested function.
87
+ if (fn === 'aim' && fnArgs.length === 5) {
88
+ callAim(... fnArgs)
89
+ .then(() => {
90
+ console.log('Execution completed');
91
+ });
92
+ }
93
+ else if (fn === 'merge' && fnArgs.length === 2) {
94
+ callMerge(... fnArgs)
95
+ .then(() => {
96
+ console.log('Execution completed');
97
+ });
98
+ }
99
+ else if (fn === 'score' && fnArgs.length > 0 && fnArgs.length < 3) {
100
+ callScore(... fnArgs)
101
+ .then(() => {
102
+ console.log('Execution completed');
103
+ });
104
+ }
105
+ else if (fn === 'digest' && fnArgs.length > 0 && fnArgs.length < 3) {
106
+ callDigest(... fnArgs)
107
+ .then(() => {
108
+ console.log('Execution completed');
109
+ });
110
+ }
111
+ else if (fn === 'compare' && fnArgs.length === 2) {
112
+ callCompare(... fnArgs)
113
+ .then(() => {
114
+ console.log('Execution completed');
115
+ });
116
+ }
117
+ else {
118
+ console.log('ERROR: Invalid statement');
119
+ }
package/compare.js CHANGED
@@ -19,8 +19,6 @@ const fs = require('fs/promises');
19
19
  // ########## CONSTANTS
20
20
 
21
21
  const comparisonDir = process.env.COMPARISONDIR || 'reports/comparative';
22
- const compareProcID = process.argv[2];
23
- const comparisonNameBase = process.argv[3];
24
22
 
25
23
  // ########## FUNCTIONS
26
24
 
@@ -28,7 +26,7 @@ const comparisonNameBase = process.argv[3];
28
26
  const replaceHolders = (content, query) => content
29
27
  .replace(/__([a-zA-Z]+)__/g, (ph, qp) => query[qp]);
30
28
  // Creates and saves a web page containing a comparative table.
31
- const compare = async () => {
29
+ exports.compare = async (compareProcID, comparisonNameBase) => {
32
30
  const comparisonDirAbs = `${__dirname}/${comparisonDir}`;
33
31
  const {getQuery} = require(`./procs/compare/${compareProcID}/index`);
34
32
  const query = await getQuery();
@@ -37,7 +35,3 @@ const compare = async () => {
37
35
  await fs.writeFile(`${comparisonDirAbs}/${comparisonNameBase}.html`, page);
38
36
  console.log(`Page ${comparisonNameBase}.html created and saved`);
39
37
  };
40
-
41
- // ########## OPERATION
42
-
43
- compare();
package/digest.js CHANGED
@@ -21,8 +21,6 @@ const fs = require('fs/promises');
21
21
 
22
22
  const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
23
23
  const reportDirDigested = process.env.REPORTDIR_DIGESTED || 'reports/digested';
24
- const digesterID = process.argv[2];
25
- const reportIDStart = process.argv[3];
26
24
 
27
25
  // ########## FUNCTIONS
28
26
 
@@ -30,7 +28,7 @@ const reportIDStart = process.argv[3];
30
28
  const replaceHolders = (content, query) => content
31
29
  .replace(/__([a-zA-Z]+)__/g, (ph, qp) => query[qp]);
32
30
  // Creates digests.
33
- const digest = async () => {
31
+ exports.digest = async (digesterID, reportIDStart) => {
34
32
  const reportDirScoredAbs = `${__dirname}/${reportDirScored}`;
35
33
  let reportFileNames = await fs.readdir(reportDirScoredAbs);
36
34
  reportFileNames = reportFileNames.filter(fileName => fileName.endsWith('.json'));
@@ -51,8 +49,5 @@ const digest = async () => {
51
49
  await fs.writeFile(`${__dirname}/${reportDirDigested}/${fileNameBase}.html`, digest);
52
50
  console.log(`Report ${fileNameBase} digested and saved`);
53
51
  };
52
+ return reportFileNames.length;
54
53
  };
55
-
56
- // ########## OPERATION
57
-
58
- digest();
package/merge.js CHANGED
@@ -20,18 +20,20 @@ const fs = require('fs/promises');
20
20
 
21
21
  const scriptDir = process.env.SCRIPTDIR || 'scripts';
22
22
  const batchDir = process.env.BATCHDIR || 'batches';
23
- const watchDir = process.env.WATCHDIR || 'watch';
24
- const scriptName = process.argv[2];
25
- const batchName = process.argv[3];
23
+ const jobDir = process.env.JOBDIR || 'watch';
26
24
 
27
25
  // ########## FUNCTIONS
28
26
 
29
27
  // Returns a string representing the date and time.
30
28
  const nowString = () => (new Date()).toISOString().slice(0, 19);
31
29
  // Merges a batch into a script and writes host-specific scripts.
32
- const merge = async (script, batch) => {
30
+ exports.merge = async (scriptName, batchName) => {
31
+ const scriptJSON = await fs.readFile(`${scriptDir}/${scriptName}.json`, 'utf8');
32
+ const batchJSON = await fs.readFile(`${batchDir}/${batchName}.json`, 'utf8');
33
+ const script = JSON.parse(scriptJSON);
34
+ const batch = JSON.parse(batchJSON);
33
35
  // Create the watch directory if it does not exist.
34
- await fs.mkdir(watchDir, {recursive: true});
36
+ await fs.mkdir(jobDir, {recursive: true});
35
37
  // Create a job-creation time stamp.
36
38
  const timeStamp = Math.floor((Date.now() - Date.UTC(2022, 1)) / 2000).toString(36);
37
39
  // For each host in the batch:
@@ -52,8 +54,6 @@ const merge = async (script, batch) => {
52
54
  script: script.id,
53
55
  batch: batch.id
54
56
  }
55
- // Add a job-creation time stamp to the script.
56
- newScript.timeStamp = timeStamp;
57
57
  // Add the job-creation time to the script.
58
58
  newScript.jobCreationTime = nowString();
59
59
  // Change the script id property to include the time stamp and the host ID.
@@ -63,19 +63,7 @@ const merge = async (script, batch) => {
63
63
  });
64
64
  // Write the host-specific scripts.
65
65
  for (const newScript of newScripts) {
66
- await fs.writeFile(`${watchDir}/${newScript.id}.json`, JSON.stringify(newScript, null, 2));
66
+ await fs.writeFile(`${jobDir}/${newScript.id}.json`, JSON.stringify(newScript, null, 2));
67
67
  };
68
68
  console.log(`Merger completed. Script count: ${hosts.length}. Time stamp: ${timeStamp}`);
69
69
  };
70
-
71
- // ########## OPERATION
72
-
73
- fs.readFile(`${scriptDir}/${scriptName}.json`, 'utf8')
74
- .then(scriptFile => {
75
- fs.readFile(`${batchDir}/${batchName}.json`, 'utf8')
76
- .then(async batchFile => {
77
- const script = JSON.parse(scriptFile);
78
- const batch = JSON.parse(batchFile);
79
- await merge(script, batch);
80
- });
81
- });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "5.0.0",
3
+ "version": "6.1.0",
4
4
  "description": "Client that scores and digests Testaro reports",
5
5
  "main": "aim.js",
6
6
  "scripts": {
@@ -19,7 +19,7 @@ const query = {};
19
19
 
20
20
  // ########## FUNCTIONS
21
21
 
22
- // Returns data on the hosts in the report directory.
22
+ // Returns data on the hosts in the scored-report directory.
23
23
  const getData = async () => {
24
24
  const reportDirAbs = `${__dirname}/../../../${reportDirScored}`;
25
25
  const reportFileNamesAll = await fs.readdir(reportDirAbs);
package/score.js CHANGED
@@ -21,13 +21,11 @@ const fs = require('fs/promises');
21
21
 
22
22
  const reportDirRaw = process.env.REPORTDIR_RAW || 'reports/raw';
23
23
  const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
24
- const scoreProcID = process.argv[2];
25
- const reportIDStart = process.argv[3];
26
24
 
27
25
  // ########## FUNCTIONS
28
26
 
29
- // Score the specified reports.
30
- const score = async () => {
27
+ // Score the specified reports and return their count.
28
+ exports.score = async (scoreProcID, reportIDStart) => {
31
29
  // Identify the reports to be scored.
32
30
  const reportDirRawAbs = `${__dirname}/${reportDirRaw}`;
33
31
  let reportFileNames = await fs.readdir(reportDirRawAbs);
@@ -48,8 +46,5 @@ const score = async () => {
48
46
  await fs.writeFile(`${__dirname}/${reportDirScored}/${fileName}`, `${scoredReportJSON}\n`);
49
47
  console.log(`Report ${fileName.slice(0, -5)} scored and saved`);
50
48
  };
49
+ return reportFileNames.length;
51
50
  };
52
-
53
- // ########## OPERATION
54
-
55
- score();