Skip to content

Commit 4524b9e

Browse files
committed
integration tests: daemon
Add basic tests to check whether the daemon starts/stops correctly with the git-bundle-server web-server start and stop commands. Signed-off-by: Lessley Dennington <[email protected]>
1 parent b58aa0b commit 4524b9e

File tree

9 files changed

+392
-0
lines changed

9 files changed

+392
-0
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as child_process from 'child_process'
2+
import { CommandRunner } from './commandRunner';
3+
4+
export abstract class DaemonState {
5+
protected commandRunner: CommandRunner
6+
7+
status: string | null = null
8+
9+
constructor () {
10+
this.commandRunner = new CommandRunner()
11+
this.get()
12+
}
13+
14+
abstract get(): void
15+
16+
parseOutput(stdout: string, regex: RegExp): void {
17+
var potentialMatchParts = stdout.match(regex)
18+
if (potentialMatchParts) {
19+
this.status = potentialMatchParts[1]
20+
}
21+
else {
22+
throw new Error(`No match found for ${regex}`)
23+
}
24+
}
25+
}
26+
27+
export class LaunchdDaemonState extends DaemonState {
28+
get(): void {
29+
var regex = new RegExp(/^\s*state = (.*)$/, "m")
30+
31+
var user = child_process.spawnSync('id', ['-u']).stdout.toString()
32+
var cmdResult = this.commandRunner.run('launchctl',
33+
['print', `user/${user}/com.github.gitbundleserver`])
34+
35+
this.parseOutput(cmdResult.stdout.toString(), regex)
36+
}
37+
}
38+
39+
export class SystemdDaemonState extends DaemonState {
40+
get(): void {
41+
var regex = new RegExp(/^\s*Active: (.*)(?= \()/, "m")
42+
43+
var user = child_process.spawnSync('id', ['-u']).stdout.toString()
44+
var cmdResult = this.commandRunner.run('systemctl',
45+
['status', '--user', user, 'com.github.gitbundleserver'])
46+
47+
this.parseOutput(cmdResult.stdout.toString(), regex)
48+
}
49+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Feature: Bundle server commands
2+
Scenario:
3+
Given the daemon has not been started
4+
When I run the 'git-bundle-server web-server start' command
5+
Then the daemon is running
6+
7+
Scenario:
8+
Given the daemon was started
9+
When I run the 'git-bundle-server web-server stop' command
10+
Then the daemon is not running
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { When } from "@cucumber/cucumber"
2+
import { BundleServerWorld } from "../support/world"
3+
4+
When('I run the {string} command', async function (this: BundleServerWorld, command: string) {
5+
this.run_command(command.split(' '))
6+
})
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { After, Given, Then } from "@cucumber/cucumber"
2+
import { BundleServerWorld } from "../support/world"
3+
import * as daemonHelpers from "../support/daemonHelpers"
4+
5+
Given('the daemon has not been started', async function (this: BundleServerWorld) {
6+
var daemonState = this.getDaemonState()
7+
if (daemonHelpers.isDaemonRunning(daemonState.status)) {
8+
this.run_command(['git-bundle-server', 'web-server', 'stop'])
9+
}
10+
})
11+
12+
Given('the daemon was started', async function (this: BundleServerWorld) {
13+
var daemonState = this.getDaemonState()
14+
if (daemonHelpers.isDaemonRunning(daemonState.status)) {
15+
this.run_command(['git-bundle-server', 'web-server', 'start'])
16+
}
17+
})
18+
19+
Then('the daemon is running', async function (this: BundleServerWorld) {
20+
var daemonStatus = this.getDaemonState()
21+
daemonHelpers.assertDaemonStatus(daemonHelpers.DaemonStatusType.Running, daemonStatus.status)
22+
})
23+
24+
Then('the daemon is not running', async function (this: BundleServerWorld) {
25+
var daemonStatus = this.getDaemonState()
26+
daemonHelpers.assertDaemonStatus(daemonHelpers.DaemonStatusType.NotRunning, daemonStatus.status)
27+
})
28+
29+
After(function (this: BundleServerWorld) {
30+
var daemonState = this.getDaemonState()
31+
if (daemonHelpers.isDaemonRunning(daemonState.status)) {
32+
this.run_command(['git-bundle-server', 'web-server', 'stop'])
33+
}
34+
});
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import * as assert from 'assert'
2+
import * as path from 'path'
3+
4+
// launchd/launchctl
5+
const launchctlDaemonRunningStatus = 'running'
6+
const launchctlDaemonNotRunningStatus = 'not running'
7+
8+
// systemd/systemctl
9+
const systemctlDaemonRunningStatus = 'active'
10+
const systemctlDaemonNotRunningStatus = 'inactive'
11+
12+
export function absPath(pathParam: string): string {
13+
// Convert a given path (either relative to 'test/integration/' or absolute) to an
14+
// absolute path
15+
if (!path.isAbsolute(pathParam)) {
16+
return path.resolve(__dirname, "../..", pathParam)
17+
} else {
18+
return pathParam
19+
}
20+
}
21+
22+
export enum DaemonStatusType {
23+
Running = 1,
24+
NotRunning = 2
25+
}
26+
27+
export function isDaemonRunning(status: string | null) {
28+
switch(process.platform) {
29+
case "darwin":
30+
if (status === launchctlDaemonRunningStatus) {
31+
return true
32+
}
33+
else {
34+
return false
35+
}
36+
case "linux":
37+
if (status === systemctlDaemonRunningStatus) {
38+
return true
39+
}
40+
else {
41+
return false
42+
}
43+
}
44+
}
45+
46+
export function assertDaemonStatus(
47+
statusType: DaemonStatusType,
48+
actual: string | null): void {
49+
var expected = ''
50+
51+
switch(process.platform) {
52+
case "darwin":
53+
if (statusType === DaemonStatusType.Running) {
54+
expected = launchctlDaemonRunningStatus
55+
}
56+
else {
57+
expected = launchctlDaemonNotRunningStatus
58+
}
59+
break
60+
case "linux":
61+
if (statusType === DaemonStatusType.Running) {
62+
expected = systemctlDaemonRunningStatus
63+
}
64+
else {
65+
expected = systemctlDaemonNotRunningStatus
66+
}
67+
break
68+
default:
69+
throw new Error("Unrecognized platform")
70+
}
71+
72+
assert.strictEqual(actual, expected)
73+
}

test/integration/features/support/utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as path from 'path'
2+
import * as assert from 'assert'
23

34
export function absPath(pathParam: string): string {
45
// Convert a given path (either relative to 'test/integration/' or absolute) to an

test/integration/features/support/world.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { setWorldConstructor, World, IWorldOptions } from '@cucumber/cucumber'
22
import { BundleServer } from '../classes/bundleServer'
3+
import { DaemonState, LaunchdDaemonState, SystemdDaemonState } from '../classes/DaemonState'
34

45
interface BundleServerParameters {
56
bundleServerCommand: string
@@ -19,6 +20,13 @@ export class BundleServerWorld extends World<BundleServerParameters> {
1920
args.shift()
2021
this.bundleServer.run_command(args)
2122
}
23+
24+
getDaemonState(): DaemonState {
25+
if (process.platform === "darwin") {
26+
return new LaunchdDaemonState()
27+
}
28+
return new SystemdDaemonState()
29+
}
2230
}
2331

2432
setWorldConstructor(BundleServerWorld)

0 commit comments

Comments
 (0)