Skip to content

Commit

Permalink
feat(options): user can set the dockerComposeOptions into the oreches…
Browse files Browse the repository at this point in the history
…trato.json config file (#21)

feat(options): user can set the  dockerComposeOptions into the orechestrato.json config file (#21)
  • Loading branch information
0xIslamTaha authored Apr 8, 2022
1 parent 8fa53af commit f759f85
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 38 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@0xislamtaha/orchestrator",
"version": "2.0.3",
"version": "2.1.0",
"description": "Execute cypress specs in parallel across multiple docker containers",
"main": "src/orchestrator.js",
"scripts": {
Expand Down
18 changes: 11 additions & 7 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ Check the following repo as a public use case.
* Generate one HTML report that has all specs execution results.
* Analyse the execution time for each spec.
* Generate the execution time reports per browser under ExecutionTimeReport dir.
* In the next run, The orchestrator It will split the test cases based on this execution time report to reduce the exeuction time.
* In the next run, The orchestrator will split the test cases based on this execution time report to reduce the execution time.


## 🏹 The Splitting mechanism:
The orchestrator can measure and report the execution time for each spec per browser. It will report it as `mochawesome-report/specsExecutionTime-chrome.json` file. If you provided this path as `specsExecutionTimePath` in the next run, The orchestrator will split the specs based on its execution time to minimize the total execution time 🚀.
The orchestrator can measure and report the execution time for each spec per browser. It will report it as `mochawesome-report/specsExecutionTime-chrome.json` file. If you provided this path as `specsExecutionTimePath` in the next run, The orchestrator will split the specs-based on its execution time to minimize the total execution time 🚀.

## ⌨️ Operating Systems:
- Linux: working out of the box.
Expand Down Expand Up @@ -75,7 +75,7 @@ services:
}
```

3- Edit the orchestrator [configuration file](/src/config.json) with your configuration. Here is the description of each configuration option.
3- Edit the orchestrator [configuration file](/src/orchestrator.json) with your configuration. Here is the description of each configuration option.

```
- parallelizm:
Expand Down Expand Up @@ -103,6 +103,11 @@ services:
type: list
example: ["ls -al", "mkdir -p test"],
- dockerComposeOptions:
description: docker-compose options to be passed to the docker-compose commands
type: dict
example: {"-p": "project_name"}
- dockerComposePath:
description: path to the docker compose file.
type: string
Expand Down Expand Up @@ -149,12 +154,12 @@ services:

* With your configuration file
```bash
npx orchestrator --config "/path/to/config.json"
npx orchestrator --config "/path/to/orchestrator.json"
```

* You can **overwrite** any configuration param on the fly, simplly path the new configuration as a prameter.
* You can **overwrite** any configuration param on the fly, simply pass the new configuration as a parameter.
```bash
npx orchestrator --config ./src/config.json --parallelizm 2 --environment '{"DOCKER_TAG":"master_283"}' --browsers "[chrome, firefox]" --specs "[alerts.js, avatar.js]"
npx orchestrator --config ./src/orchestrator.json --parallelizm 2 --environment '{"DOCKER_TAG":"master_283"}' --browsers "[chrome, firefox]" --specs "[alerts.js, avatar.js]"
```

## 📖 Reports:
Expand All @@ -165,6 +170,5 @@ The orchestrator generates two reports by default:


## 🎬 To-Do:
* Export COMPOSE_PROJECT_NAME with random value if it doesn't exist.
* list configuration rather than multiple files for multiple test suites.
* Provide --help option.
2 changes: 1 addition & 1 deletion src/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function banner() {
██ ██ ██████ ██ ███████ █████ ███████ ██ ██████ ███████ ██ ██ ██ ██████
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██████ ██ ██ ██████ ██ ██ ███████ ███████ ██ ██ ██ ██ ██ ██ ██████ ██ ██
v 2.0.3 @0xIslamTaha
v 2.1.0 @0xIslamTaha
`;

console.log(banner);
Expand Down
71 changes: 45 additions & 26 deletions src/orchestrator.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ import {
orderBasedOnBrowserDuration,
} from "./helper.js";
import * as lg from "./logger";
import { checkRequirements } from "./checker";

import { checkRequirements } from "./checker";

const executionTimeReportDir = "executionTimeReport";
const executionTimeReportDirPath = path.resolve(process.cwd(), executionTimeReportDir)
const executiontimeReportJson = "specsExecutionTime.json"
const executiontimeReportJsonPath = path.join(executionTimeReportDirPath, executiontimeReportJson)
const executionTimeReportDirPath = path.resolve(
process.cwd(),
executionTimeReportDir
);
const executiontimeReportJson = "specsExecutionTime.json";
const executiontimeReportJsonPath = path.join(
executionTimeReportDirPath,
executiontimeReportJson
);

function execa(command, flag = true) {
return new Promise((resolve, reject) =>
Expand Down Expand Up @@ -78,8 +83,8 @@ function parseArgumentsIntoConfig(rawArgs) {
}

function overWriteConfig(args) {
lg.step('Overwrite the config file with the arguments if there is any', true);
const configFile = args["--config"] || path.resolve(__dirname, "config.json");
lg.step("Overwrite the config file with the arguments if there is any", true);
const configFile = args["--config"] || path.resolve(__dirname, "orchestrator.json");
const defaultConfig = JSON.parse(fs.readFileSync(configFile, "utf-8"));
const config = { ...defaultConfig, ...args };
return config;
Expand All @@ -102,13 +107,23 @@ function execPreCommands(config) {
});
}

function extractDockerComposeOptions(config) {
let dockerComposeOptions = "";
Object.keys(config.dockerComposeOptions).forEach((option) => {
dockerComposeOptions = `${dockerComposeOptions} ${option} ${config.dockerComposeOptions[option]}`;
});
return dockerComposeOptions;
}

function getListOfSpecs(config, browser) {
let existingSpecs = [];

if (config.specs.length > 0) {
existingSpecs = [...config.specs];
} else {
existingSpecs = sh.ls('-R', config.specsHomePath).filter((val) => val.match(/.*ts|js/));
existingSpecs = sh
.ls("-R", config.specsHomePath)
.filter((val) => val.match(/.*ts|js/));
}

if (checkFileIsExisting(executiontimeReportJsonPath)) {
Expand Down Expand Up @@ -216,13 +231,14 @@ function upConrainters(config) {
let commands = [];
let [container_name, command] = ["", ""];
let bashCommands = _constructCypressCommands(config);
let dockerComposeOptions = extractDockerComposeOptions(config);

bashCommands.forEach((cmd) => {
container_name = `container_${Math.floor(
Math.random() * 100000
)}__${bashCommands.indexOf(cmd)}`;

command = `timeout --preserve-status ${config.timeout} docker-compose -f ${config.dockerComposePath} run --name ${container_name} ${config.cypressContainerName} bash -c '${cmd}'`;
command = `timeout --preserve-status ${config.timeout} docker-compose ${dockerComposeOptions} -f ${config.dockerComposePath} run --name ${container_name} ${config.cypressContainerName} bash -c '${cmd}'`;
commands.push(command);
lg.subStep(`~$ ${command}`);
promises.push(execa(command));
Expand All @@ -232,29 +248,31 @@ function upConrainters(config) {
}

function downContainers(config) {
let dockerComposeOptions = extractDockerComposeOptions(config);
lg.step("Stop the cypress containers", true);
let dockerComposeDown = `docker-compose -f ${config.dockerComposePath} down`;
let dockerComposeDown = `docker-compose ${dockerComposeOptions} -f ${config.dockerComposePath} down`;
sh.exec(dockerComposeDown);
}

function generateReport(config) {
lg.step("Generate the reports", true);
return merge({ files: [config.mochawesomeJSONPath] })
.then((report) =>{
.then((report) => {
lg.subStep(`HTML report: ${config.reportPath}/mochawesome.html`);
marge.create(report, {
reportDir: config.reportPath,
charts: true,
saveJson: true,
})

});
})
.then(() => {
if (config.analyseReport) {
if (!fs.existsSync(executionTimeReportDirPath)){
if (!fs.existsSync(executionTimeReportDirPath)) {
sh.mkdir(executionTimeReportDirPath);
}
lg.subStep(`Execution time report: ${executionTimeReportDir}/${executiontimeReportJson}`);
lg.subStep(
`Execution time report: ${executionTimeReportDir}/${executiontimeReportJson}`
);
_analyseReport(config);
}
});
Expand Down Expand Up @@ -296,15 +314,16 @@ export async function orchestrator(rawArgs) {
setEnvVars(config);
execPreCommands(config);

Promise.allSettled(upConrainters(config))
.then(promises => {
afterPromises(config, orchestratorTime);
const failedPromises = promises.filter(promise => promise.status === 'rejected');
if(failedPromises.length){
setTimeout(() => {
lg.step('Exit code: 1');
sh.exit(1);
}, 5000);
}
});
Promise.allSettled(upConrainters(config)).then((promises) => {
afterPromises(config, orchestratorTime);
const failedPromises = promises.filter(
(promise) => promise.status === "rejected"
);
if (failedPromises.length) {
setTimeout(() => {
lg.step("Exit code: 1");
sh.exit(1);
}, 5000);
}
});
}
11 changes: 8 additions & 3 deletions src/config.json → src/orchestrator.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
{
"parallelizm": 1,
"parallelizm": 2,
"browsers": ["chrome", "firefox"],
"timeout": "20m",
"environment": {
"DOCKER_TAG": "master_283"
},
"preCommands": [
"docker-compose -f /opt/code/github/design-system/cypress.docker-compose.yml up -d cloud_fe_components"
"echo 'START ORCHESTRATOR'",
"rm -rf cypress/report/* #Remove the old reports",
"mkdir -p mochawesome-report"
],
"dockerComposeOptions": {
"-p": "orchestator_public_use_case_project_name"
},
"dockerComposePath": "/opt/code/github/design-system/cypress.docker-compose.yml",
"specsHomePath": "/opt/code/github/design-system/tests/cypress/storybook/",
"specsDockerPath": "tests/cypress/storybook/",
"cypressContainerName": "cypress_container",
"mochawesomeJSONPath": "/opt/code/github/design-system/tests/report/mochawesome-report/*.json",
"reportPath": "mochawesome-report",
"specs": [],
"analyseReport": false,
"analyseReport": true,
"specsExecutionTimePath": "mochawesome-report/specsExecutionTime-chrome.json"
}

0 comments on commit f759f85

Please sign in to comment.