Skip to content

Commit

Permalink
Completes integration tests
Browse files Browse the repository at this point in the history
  - Completes integration tests for the codebase
  - Makes the execaCMDRunner catch the invalid commands
  - Removes get-stream dependency from execaCMDRunner
  - Uploads codecoverage to codecov
  - Adds new yarn command to watch the tests
  - Adds emojis to README
  • Loading branch information
prasadtalasila committed Sep 16, 2023
1 parent f28f400 commit d31da4a
Show file tree
Hide file tree
Showing 12 changed files with 192 additions and 44 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,9 @@ jobs:
cd servers/execution/runner
yarn install
yarn test
- name: Upload test coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: servers/execution/runner/coverage/clover.xml
flags: dt-runner
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ site/
*.sublime-workspace

# IDE - VSCode
.vscode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
Expand Down
33 changes: 26 additions & 7 deletions servers/execution/runner/README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
# Overview
# :runner: Digital Twin Runner

A commandline utility to run a digital twin. It will provide REST interface to execute lifecycle scripts of a digital twin. It is possible to run multiple instances of this utility within one computer.
A commandline utility to run a digital twin. It will provide REST interface
to execute lifecycle scripts of a digital twin. It is possible to run
multiple instances of this utility within one computer.

## Developer Commands
## :hammer_and_wrench: Developer Commands

```bash
yarn install # Install dependencies for the microservice
yarn syntax # analyzes source code for potential errors, style violations, and other issues,
yarn build # compile ES6 files into ES5 javascript files and copy all JS files into build/ directory
yarn test # run tests
yarn test:watchAll #Watch changes in test/ and run the tests
yarn start # start the application
yarn clean # deletes directories "build", "coverage", and "dist"
```

## Publish Package
## :package: :ship: Publish Package

### Setup private npm registry

This package need to be published to an npm registry. There after, the package can be installed as a system command. Since publishing to npmjs.org is irrevocable and public, developers are encouraged to setup their own private npm registry for local development. We recommend using [verdaccio](https://verdaccio.org) for this task. The following commands help you create a working private npm registry for development.
This package need to be published to an npm registry. There after, the package
can be installed as a system command. Since publishing to npmjs.org is
irrevocable and public, developers are encouraged to setup their own private
npm registry for local development. We recommend using
[verdaccio](https://verdaccio.org) for this task. The following commands
help you create a working private npm registry for development.

```bash
docker run -d --name verdaccio -p 4873:4873 verdaccio/verdaccio
Expand All @@ -26,7 +34,8 @@ npm set registry http://localhost:4873/
yarn config set registry "http://localhost:4873"
```

You can open `http://localhost:4873` in your browser, login with the user credentials to see the packages published.
You can open `http://localhost:4873` in your browser, login with
the user credentials to see the packages published.

### Publish to private registry

Expand All @@ -39,7 +48,11 @@ yarn publish --no-git-tag-version #increments version in package.json, publishes
yarn publish #increments version in package.json, publishes to registry and adds a git tag
```

The package version in package.json gets updated as well. You can open `http://localhost:4873` in your browser, login with the user credentials to see the packages published. Please see [verdaccio docs](https://verdaccio.org/docs/installation/#basic-usage) for more information.
The package version in package.json gets updated as well. You can
open `http://localhost:4873` in your browser, login with the user credentials
to see the packages published. Please see
[verdaccio docs](https://verdaccio.org/docs/installation/#basic-usage)
for more information.

If there is a need to unpublish a package, ex: `@dtaas/[email protected]`, do:

Expand All @@ -54,3 +67,9 @@ sudo npm install --registry http://localhost:4873 -g @dtaas/runner
sudo npm list -g # should list @dtaas/runner in the packages
sudo npm remove --global @dtaas/runner
```

## :balance_scale: License

This software is owned by
[The INTO-CPS Association](https://into-cps.org/)
and is available under [the INTO-CPS License](./LICENSE.md).
4 changes: 2 additions & 2 deletions servers/execution/runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"format": "prettier --ignore-path ../.gitignore --write \"**/*.{ts,tsx,css,scss}\"",
"start": "script/start.bash",
"syntax": "script/syntax.bash",
"test": "script/test.bash"
"test": "script/test.bash",
"test:watchAll": "script/test.bash --watchAll"
},
"bin": {
"runner": "./dist/src/runner.js"
Expand Down Expand Up @@ -59,7 +60,6 @@
"@nestjs/platform-express": "^10.2.4",
"cross-env": "^7.0.3",
"execa": "^7.2.0",
"get-stream": "^7.0.1",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
}
Expand Down
2 changes: 1 addition & 1 deletion servers/execution/runner/script/test.bash
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ export PATH="$new_path"

npx cross-env NODE_OPTIONS=--experimental-vm-modules \
NODE_NO_WARNINGS=1 \
jest --coverage
jest --coverage "$1"
3 changes: 1 addition & 2 deletions servers/execution/runner/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Module } from '@nestjs/common';
import AppController from './app.controller';
import AppService from './app.service';
import LifeCycleManager from './lifecycleManager.service';
import Queue from './queue.service';

@Module({
imports: [],
controllers: [AppController],
providers: [AppService, LifeCycleManager, Queue],
providers: [LifeCycleManager, Queue],
})
export default class AppModule {}
10 changes: 0 additions & 10 deletions servers/execution/runner/src/app.service.ts

This file was deleted.

26 changes: 11 additions & 15 deletions servers/execution/runner/src/execaCMDRunner.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { execa } from 'execa';
import getStream from 'get-stream';
import CMDRunner from './interfaces/CMDRunner.interface';

export default class ExecaCMDRunner implements CMDRunner {
Expand All @@ -18,29 +17,26 @@ export default class ExecaCMDRunner implements CMDRunner {
async run(): Promise<boolean> {
let status: boolean = false;

const childProcess = execa(this.command);
if (childProcess != null) {
this.stdout = await getStream(childProcess.stdout!);
this.stderr = await getStream(childProcess.stderr!);
try {
const { stdout, stderr } = await execa(this.command);
this.stderr = stderr;
this.stdout = stdout;
status = true;
} catch (ENOENT) {
status = false;
}

return status;
}

checkLogs(): Map<string, string> {
const logs: Map<string, string> = new Map<string, string>();

if (this.stdout !== undefined) {
logs.set('stdout', this.stdout);
} else {
logs.set('stdout', '');
}
let stackString: string = this.stdout !== undefined ? this.stdout : '';
logs.set('stdout', stackString);

if (this.stderr !== undefined) {
logs.set('stderr', this.stderr);
} else {
logs.set('stderr', '');
}
stackString = this.stderr !== undefined ? this.stderr : '';
logs.set('stderr', stackString);

return logs;
}
Expand Down
27 changes: 25 additions & 2 deletions servers/execution/runner/test/integration/execaCMDRunner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,33 @@ import { describe, it, expect } from '@jest/globals';
import CMDRunner from 'src/interfaces/CMDRunner.interface';
import ExecaCMDRunner from 'src/execaCMDRunner';

describe('check Execa CMD Runner instantiation', () => {
it('should be defined', async () => {
describe('check Execa CMD Runner', () => {
it('should execute a valid operating system command', async () => {
const cmdrunner: CMDRunner = new ExecaCMDRunner('date');

expect(await cmdrunner.run()).toBe(true);
});

it('should attempt execution of an invalid command', async () => {
const cmdrunner: CMDRunner = new ExecaCMDRunner('asdfghjkl');
await cmdrunner.run();
});

it('should not succeed in execution of an invalid command too', async () => {
const cmdrunner: CMDRunner = new ExecaCMDRunner('asdfghjkl');
const status: boolean = await cmdrunner.run();

expect(status).toBe(false);
});

it('should capture single line output log', async () => {
const cmdrunner: CMDRunner = new ExecaCMDRunner('date');

const status: boolean = await cmdrunner.run();
const logs: Map<string, string> = cmdrunner.checkLogs();

expect(status).toBe(true);
expect(logs.get('stdout')).toEqual(expect.any(String));
expect(logs.get('stderr')).toEqual('');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe, expect, it } from '@jest/globals';
import LifeCycleManager from 'src/lifecycleManager.service';
import { DTLifeCycle, Phase } from 'src/interfaces/lifecycle.interface';
import ExecaCMDRunner from 'src/execaCMDRunner';

describe('Check LifecycleManager', () => {
it('Should create object', async () => {
try {
const dt: DTLifeCycle = new LifeCycleManager();
expect(dt).toBeInstanceOf(LifeCycleManager);
} catch (error) {
expect(fail);
}
});

it('Should change to valid phase', async () => {
const dt: DTLifeCycle = new LifeCycleManager();
let status: boolean = false;
let logs: Map<string, string> = new Map<string, string>();

[status, logs] = await dt.changePhase('whoami');

expect(status).toBe(true);
expect(logs.get('stdout')).toEqual(expect.any(String));
expect(logs.get('stderr')).toEqual('');
});

it('Should not change to invalid phase', async () => {
const dt: DTLifeCycle = new LifeCycleManager();
let status: boolean = true;

[status] = await dt.changePhase('asdfghjkl');

expect(status).toBe(false);
});

it('Should return undefined if there has been no changePhase calls', async () => {
const dt: DTLifeCycle = new LifeCycleManager();
let phase: Phase | undefined = {
name: 'hello',
status: 'valid',
task: new ExecaCMDRunner(''),
};

phase = dt.checkPhase();

expect(phase).toBe(undefined);
});

it('Should hold correct phase history', async () => {
const dt: DTLifeCycle = new LifeCycleManager();
const status: boolean[] = [];
const pastPhases: Array<string> = ['date', 'whoami'];

dt.changePhase(pastPhases[0]).then(([value]) => {
status.push(value);
});
dt.changePhase(pastPhases[1]).then(([value]) => {
status.push(value);
});

const pastPhasesActual = dt.checkHistory();

expect(pastPhasesActual).toStrictEqual(pastPhases);
});
});
53 changes: 53 additions & 0 deletions servers/execution/runner/test/integration/queue.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { describe, it, expect } from '@jest/globals';
import Queue from 'src/queue.service';
import { Phase } from 'src/interfaces/lifecycle.interface';
import ExecaCMDRunner from 'src/execaCMDRunner';

const phases: Phase[] = [
{
name: 'hello',
status: 'valid',
task: new ExecaCMDRunner(''),
},
{
name: 'world',
status: 'valid',
task: new ExecaCMDRunner(''),
},
{
name: 'terminate',
status: 'invalid',
task: new ExecaCMDRunner(''),
},
];

describe('check Queue service', () => {
it('should store a phase', async () => {
const queue: Queue = new Queue();

expect(queue.enqueue(phases[0])).toBe(true);
});

it('should return active phase as undefined when queue is empty', async () => {
const queue: Queue = new Queue();

expect(queue.activePhase()).toBe(undefined);
});

it('should return active phase when queue is non-empty', async () => {
const queue: Queue = new Queue();

queue.enqueue(phases[0]);

expect(queue.activePhase()).toBe(phases[0]);
});

it('should return correct active phase when queue has more than one phase', async () => {
const queue: Queue = new Queue();

queue.enqueue(phases[0]);
queue.enqueue(phases[1]);

expect(queue.activePhase()).toBe(phases[1]);
});
});
5 changes: 0 additions & 5 deletions servers/execution/runner/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3196,11 +3196,6 @@ get-stream@^6.0.0, get-stream@^6.0.1:
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==

get-stream@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-7.0.1.tgz#1664dfe7d1678540ea6a4da3ae7cd59bf4e4a91e"
integrity sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==

get-symbol-description@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
Expand Down

0 comments on commit d31da4a

Please sign in to comment.