Skip to content

Commit

Permalink
Merge pull request #4 from Informatievlaanderen/chore/add-cancellation
Browse files Browse the repository at this point in the history
chore: add cancellation
  • Loading branch information
rorlic authored Apr 3, 2024
2 parents 40ce567 + c06486d commit 642aea6
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 35 deletions.
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,25 +135,26 @@ curl "http://localhost:9000/test/c47a3487-2f9f-433c-ab5a-82b196fff7e1/results"
curl "http://localhost:9000/test/c47a3487-2f9f-433c-ab5a-82b196fff7e1/jmeter.log"
```

### `DELETE /test/<test-run-id>` -- Remove Test Run
Removes the test run with the given ID and its related data including resuls, so use with caution.
```bash
curl -X DELETE http://localhost:9000/test/c47a3487-2f9f-433c-ab5a-82b196fff7e1
```
> **Note** that if the test is still running, you need to confirm the deletion by adding `?confirm=true`, e.g.
### `DELETE /test/<test-run-id>[?confirm=true]` -- Cancel Test Run or Remove Test And Results
If confirmed (`?confirm=true`), removes the test run with the given ID and its related data including results, so use with caution. If a test is running it is first cancelled. E.g.:
```bash
curl -X DELETE http://localhost:9000/test/c47a3487-2f9f-433c-ab5a-82b196fff7e1?confirm=true
```

### `DELETE /` -- Remove All Test Runs
Removes all tests and their related data including resuls, so use with extreme caution.
If not confirmed, a running test is simply cancelled. E.g.:
```bash
curl -X DELETE http://localhost:9000/test
curl -X DELETE http://localhost:9000/test/c47a3487-2f9f-433c-ab5a-82b196fff7e1
```
> **Note** that if a test is still running, you need to confirm the deletion by adding `?confirm=true`, e.g.
### `DELETE /test[?confirm=true]` -- Cancel All Test Runs or Delete All Tests
If confirmed (`?confirm=true`), removes all tests and their related data including results, so use with extreme caution. All running tests are cancelled before deletion. E.g.:
```bash
curl -X DELETE http://localhost:9000/test?confirm=true
```

If not confirmed, all running tests are simply cancelled. E.g.
```bash
curl -X DELETE http://localhost:9000/test
```

### `GET /prometheus` -- Get Metrics
Exposes the metrics using [Prometheus](https://prometheus.io/) format.
37 changes: 25 additions & 12 deletions src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,19 @@ export class Controller {
}
}

private _exportRun(id: string) {
const run = this._getTest(id)!.run;
this._writeMetadata({ ...run, status: TestRunStatus.cancelled });
this._moveToResults(id);
private _exportTestRun(run: TestRun) {
this._writeMetadata(run);
this._moveToResults(run.id);
}

private _cancelTest(id: string) {
const test = this._getTest(id)!;
private _cancelTest(test: Test) {
const id = test.run.id;
console.warn(`[WARN] Test ${id} is running...`);
const process = test.process;
console.warn(`[WARN] Killing pid ${process?.pid}...`);
const killed = process?.kill;
console.warn(killed ? `[WARN] Test ${id} was cancelled.` : `Failed to kill test ${id} (pid: ${process?.pid}).`);
return this._upsertTest({run: {...test.run, status: TestRunStatus.cancelled} as TestRun, process: undefined} as Test);
}

private _writeMetadata(run: TestRun) {
Expand Down Expand Up @@ -149,10 +149,7 @@ export class Controller {

public async exportTestRuns() {
const runs = await this._getSubDirectories(this._config.tempFolder);
runs.forEach(id => {
this._cancelTest(id);
this._exportRun(id);
});
runs.forEach(id => this.cancelTest(id));
}

public testExists(id: string): boolean {
Expand All @@ -164,14 +161,22 @@ export class Controller {
return !!test && test.run.status === TestRunStatus.running;
}

public cancelTest(id: string) {
const test = this._getTest(id);
if (test) {
this._exportTestRun(this._cancelTest(test).run);
}
}

public deleteTest(id: string) {
const testData = path.join(this._config.testFolder, id);
const runData = path.join(this._config.tempFolder, id);

const exists = this.testExists(id);
if (exists) {
if (this.testRunning(id)) {
this._cancelTest(id);
const test = this._getTest(id)!;
this._cancelTest(test);
}
delete this._testsById[id];
} else {
Expand All @@ -195,10 +200,18 @@ export class Controller {
return exists || testDataExists || runDataExists;
}

public deleteAllTestRuns() {
public deleteAllTests() {
this._tests.map(x => this.deleteTest(x.run.id));
}

public cancelAllRunningTests() {
this._tests.map(x => {
if (x.process && !x.process.exitCode) {
this.cancelTest(x.run.id)
}
});
}

public async getTestRunStatus(id: string, limit: number = 1000) {
const test = this._getTest(id);
if (!test) throw new Error(`Test ${id} does not exist.`);
Expand Down
38 changes: 25 additions & 13 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,23 @@ server.delete('/test', { schema: { querystring: { confirm: { type: 'boolean' } }
}

const parameters = request.query as { confirm?: boolean };
const cancelOnly = !parameters.confirm;

try {
if (controller.runningCount > 0 && !parameters.confirm) {
return reply.status(405).send("Cannot delete all tests as some are still running.\nHint:pass query parameter '?confirm=true'.\n");
} else {
controller.deleteAllTestRuns();
const anyTestRunning = controller.runningCount > 0;
if (anyTestRunning) {
controller.cancelAllRunningTests();
}

if (!cancelOnly) {
controller.deleteAllTests();
return reply.send('All tests deleted\n');
}

return anyTestRunning
? reply.send('All running tests cancelled\n')
: reply.status(405).send("No tests cancelled nor deleted.\nHint:pass query parameter '?confirm=true' to actually delete all tests.\n");

} catch (error) {
return reply.send({ msg: 'Cannot delete all tests\n', error: error });
}
Expand All @@ -177,18 +186,21 @@ server.delete('/test/:id', { schema: { querystring: { confirm: { type: 'boolean'

const { id } = request.params as { id: string };
const parameters = request.query as { confirm?: boolean };
const cancelOnly = !parameters.confirm;

try {
if (controller.testRunning(id) && !parameters.confirm) {
return reply.status(405).send(`Test ${id} is still running.\nHint:pass query parameter '?confirm=true'.\n`);
} else {
const deleted = controller.deleteTest(id);
if (deleted) {
return reply.send(`Test ${id} deleted\n`);
} else {
return reply.status(404).send(`Test ${id} not found\n`);
}
if (controller.testRunning(id)) {
controller.cancelTest(id);
}

if (cancelOnly) {
return reply.send(`Test ${id} cancelled\n`);
}

return controller.deleteTest(id)
? reply.send(`Test ${id} deleted\n`)
: reply.status(404).send(`Test ${id} not found\n`);

} catch (error) {
return reply.send({ msg: `Cannot delete test ${id}\n`, error: error });
}
Expand Down

0 comments on commit 642aea6

Please sign in to comment.