Skip to content

Commit 88fe9de

Browse files
authored
Merge pull request #39 from github/integration-tests
Add integration tests
2 parents c084f00 + 511ed32 commit 88fe9de

31 files changed

+1832
-123
lines changed

.github/workflows/test.yml

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: End-to-end test
1+
name: Integration and end-to-end tests
22

33
on:
44
pull_request:
@@ -10,7 +10,7 @@ on:
1010
default: false
1111

1212
jobs:
13-
e2e-test:
13+
tests:
1414
runs-on: ubuntu-latest
1515

1616
steps:
@@ -27,11 +27,17 @@ jobs:
2727
with:
2828
node-version: 18
2929

30-
- name: Install system dependencies for end-to-end tests
30+
- name: Install system dependencies for tests
3131
run: build/ci/install-dependencies.sh
3232
shell: bash
3333

34-
- name: Enable perf tests
34+
- name: Run integration tests
35+
run: |
36+
# Ensure only integration tests that are supported in CI are run using
37+
# the --ci flag.
38+
make integration-test INTEGRATION_FLAGS="--ci"
39+
40+
- name: Enable end-to-end perf tests
3541
if: ${{ github.event.inputs.run-all }}
3642
run: echo "E2E_FLAGS='--all'" >> $GITHUB_ENV
3743

.vscode/settings.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040

4141
// Cucumber settings
4242
"cucumber.features": [
43-
"test/e2e/features/**/*.feature",
43+
"test/**/features/**/*.feature",
4444
],
4545
"cucumber.glue": [
46-
"test/e2e/features/**/*.ts"
46+
"test/**/features/**/*.ts",
4747
],
4848
}

Makefile

+16
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ APPLE_APP_IDENTITY =
2828
APPLE_INST_IDENTITY =
2929
APPLE_KEYCHAIN_PROFILE =
3030
E2E_FLAGS=
31+
INTEGRATION_FLAGS=
3132

3233
# Build targets
3334
.PHONY: build
@@ -42,13 +43,28 @@ doc:
4243
--output="$(DOCDIR)"
4344

4445
# Testing targets
46+
.PHONY: test
47+
test: build
48+
@echo "======== Running unit tests ========"
49+
GOOS="$(GOOS)" GOARCH="$(GOARCH)" go test ./...
50+
51+
.PHONY: integration-test
52+
integration-test: build
53+
@echo
54+
@echo "======== Running integration tests ========"
55+
$(RM) -r $(TESTDIR)
56+
@scripts/run-integration-tests.sh $(INTEGRATION_FLAGS)
57+
4558
.PHONY: e2e-test
4659
e2e-test: build
4760
@echo
4861
@echo "======== Running end-to-end tests ========"
4962
$(RM) -r $(TESTDIR)
5063
@scripts/run-e2e-tests.sh $(E2E_FLAGS)
5164

65+
.PHONY: test-all
66+
test-all: test integration-test e2e-test
67+
5268
# Installation targets
5369
.PHONY: install
5470
install: build doc

scripts/run-e2e-tests.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ set -e
3030
cd "$TESTDIR"
3131

3232
npm install
33-
npm run test -- ${ARGS:+${ARGS[*]}}
33+
npm run e2e-test -- ${ARGS:+${ARGS[*]}}

scripts/run-integration-tests.sh

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/bash
2+
3+
THISDIR="$( cd "$(dirname "$0")" ; pwd -P )"
4+
TESTDIR="$THISDIR/../test/integration"
5+
6+
# Defaults
7+
ARGS=()
8+
9+
# Parse script arguments
10+
for i in "$@"
11+
do
12+
case "$i" in
13+
--offline)
14+
ARGS+=("-p" "offline")
15+
shift # past argument
16+
;;
17+
--ci)
18+
ARGS+=("-p" "ci")
19+
shift # past argument
20+
;;
21+
*)
22+
die "unknown option '$i'"
23+
;;
24+
esac
25+
done
26+
27+
# Exit as soon as any line fails
28+
set -e
29+
30+
cd "$TESTDIR"
31+
32+
npm install
33+
npm run integration-test -- ${ARGS:+${ARGS[*]}}

test/e2e/cucumber.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
const common = {
22
requireModule: ['ts-node/register'],
3-
require: ['features/**/*.ts'],
3+
require: [`${__dirname}/features/**/*.ts`, `${__dirname}/../shared/features/**/*.ts`],
44
publishQuiet: true,
55
format: ['progress'],
66
formatOptions: {
77
snippetInterface: 'async-await'
88
},
99
worldParameters: {
10-
bundleServerCommand: '../../bin/git-bundle-server',
11-
bundleWebServerCommand: '../../bin/git-bundle-web-server',
12-
trashDirectoryBase: '../../_test/e2e'
10+
bundleServerCommand: 'bin/git-bundle-server',
11+
bundleWebServerCommand: 'bin/git-bundle-web-server',
12+
trashDirectoryBase: '_test/e2e'
1313
}
1414
}
1515

Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
import * as utils from '../support/utils'
2-
import { BundleServerWorld, } from '../support/world'
1+
import * as utils from '../../../shared/support/utils'
2+
import { EndToEndBundleServerWorld } from '../support/world'
33
import { Given } from '@cucumber/cucumber'
44

5-
Given('the bundle web server was started at port {int}', async function (this: BundleServerWorld, port: number) {
6-
this.bundleServer.startWebServer(port)
7-
})
8-
9-
Given('the bundle server has been initialized with the remote repo', async function (this: BundleServerWorld) {
5+
Given('the bundle server has been initialized with the remote repo', async function (this: EndToEndBundleServerWorld) {
106
if (this.remote === undefined) {
117
throw new Error("Remote repository is not initialized")
128
}
13-
utils.assertStatus(0, this.bundleServer.init(this.remote))
9+
utils.assertStatus(0, this.bundleServer.init(this.remote, 'e2e'))
1410
})
1511

16-
Given('the bundle server was updated for the remote repo', async function (this: BundleServerWorld) {
12+
Given('the bundle server was updated for the remote repo', async function (this: EndToEndBundleServerWorld) {
1713
utils.assertStatus(0, this.bundleServer.update())
1814
})

test/e2e/features/step_definitions/repository.ts

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as assert from 'assert'
2-
import * as utils from '../support/utils'
2+
import * as utils from '../../../shared/support/utils'
33
import { randomBytes } from 'crypto'
4-
import { BundleServerWorld, User } from '../support/world'
4+
import { EndToEndBundleServerWorld, User } from '../support/world'
55
import { Given, When, Then } from '@cucumber/cucumber'
66

77
/**
@@ -10,7 +10,7 @@ import { Given, When, Then } from '@cucumber/cucumber'
1010
* test steps will live here.
1111
*/
1212

13-
Given('another user pushed {int} commits to {string}', async function (this: BundleServerWorld, commitNum: number, branch: string) {
13+
Given('another user pushed {int} commits to {string}', async function (this: EndToEndBundleServerWorld, commitNum: number, branch: string) {
1414
const clonedRepo = this.getRepoAtBranch(User.Another, branch)
1515

1616
for (let i = 0; i < commitNum; i++) {
@@ -22,7 +22,7 @@ Given('another user pushed {int} commits to {string}', async function (this: Bun
2222
})
2323

2424
Given('another user removed {int} commits and added {int} commits to {string}',
25-
async function (this: BundleServerWorld, removeCommits: number, addCommits: number, branch: string) {
25+
async function (this: EndToEndBundleServerWorld, removeCommits: number, addCommits: number, branch: string) {
2626
const clonedRepo = this.getRepoAtBranch(User.Another, branch)
2727

2828
// First, reset
@@ -40,33 +40,33 @@ Given('another user removed {int} commits and added {int} commits to {string}',
4040
}
4141
)
4242

43-
Given('I cloned from the remote repo with a bundle URI', async function (this: BundleServerWorld) {
43+
Given('I cloned from the remote repo with a bundle URI', async function (this: EndToEndBundleServerWorld) {
4444
const user = User.Me
4545
this.cloneRepositoryFor(user, this.bundleServer.bundleUri())
4646
utils.assertStatus(0, this.getRepo(user).cloneResult)
4747
})
4848

49-
When('I clone from the remote repo with a bundle URI', async function (this: BundleServerWorld) {
49+
When('I clone from the remote repo with a bundle URI', async function (this: EndToEndBundleServerWorld) {
5050
this.cloneRepositoryFor(User.Me, this.bundleServer.bundleUri())
5151
})
5252

53-
When('another developer clones from the remote repo without a bundle URI', async function (this: BundleServerWorld) {
53+
When('another developer clones from the remote repo without a bundle URI', async function (this: EndToEndBundleServerWorld) {
5454
this.cloneRepositoryFor(User.Another)
5555
})
5656

57-
When('I fetch from the remote', async function (this: BundleServerWorld) {
57+
When('I fetch from the remote', async function (this: EndToEndBundleServerWorld) {
5858
const clonedRepo = this.getRepo(User.Me)
5959
utils.assertStatus(0, clonedRepo.runGit("fetch", "origin"))
6060
})
6161

62-
Then('bundles are downloaded and used', async function (this: BundleServerWorld) {
62+
Then('bundles are downloaded and used', async function (this: EndToEndBundleServerWorld) {
6363
const clonedRepo = this.getRepo(User.Me)
6464

6565
// Verify the clone executed as-expected
6666
utils.assertStatus(0, clonedRepo.cloneResult, "git clone failed")
6767

6868
// Ensure warning wasn't thrown
69-
clonedRepo.cloneResult.stderr.toString().split("\n").forEach(function (line) {
69+
clonedRepo.cloneResult.stderr.toString().split("\n").forEach(function (line: string) {
7070
if (line.startsWith("warning: failed to download bundle from URI")) {
7171
assert.fail(line)
7272
}
@@ -81,13 +81,13 @@ Then('bundles are downloaded and used', async function (this: BundleServerWorld)
8181
result = clonedRepo.runGit("for-each-ref", "--format=%(refname)", "refs/bundles/*")
8282
utils.assertStatus(0, result, "git for-each-ref failed")
8383

84-
const bundleRefs = result.stdout.toString().split("\n").filter(function(line) {
84+
const bundleRefs = result.stdout.toString().split("\n").filter(function(line: string) {
8585
return line.trim() != ""
8686
})
8787
assert.strict(bundleRefs.length > 0, "No bundle refs found in the repo")
8888
})
8989

90-
Then('I am up-to-date with {string}', async function (this: BundleServerWorld, branch: string) {
90+
Then('I am up-to-date with {string}', async function (this: EndToEndBundleServerWorld, branch: string) {
9191
const clonedRepo = this.getRepo(User.Me)
9292
const result = clonedRepo.runGit("rev-parse", `refs/remotes/origin/${branch}`)
9393
utils.assertStatus(0, result)
@@ -97,7 +97,7 @@ Then('I am up-to-date with {string}', async function (this: BundleServerWorld, b
9797
})
9898

9999
Then('my repo\'s bundles {boolean} up-to-date with {string}',
100-
async function (this: BundleServerWorld, expectedUpToDate: boolean, branch: string) {
100+
async function (this: EndToEndBundleServerWorld, expectedUpToDate: boolean, branch: string) {
101101
const clonedRepo = this.getRepo(User.Me)
102102
const result = clonedRepo.runGit("rev-parse", `refs/bundles/${branch}`)
103103
utils.assertStatus(0, result)
@@ -112,7 +112,7 @@ Then('my repo\'s bundles {boolean} up-to-date with {string}',
112112
}
113113
)
114114

115-
Then('I compare the clone execution times', async function (this: BundleServerWorld) {
115+
Then('I compare the clone execution times', async function (this: EndToEndBundleServerWorld) {
116116
const myClone = this.getRepo(User.Me)
117117
const otherClone = this.getRepo(User.Another)
118118

test/e2e/features/support/utils.ts

-25
This file was deleted.

test/e2e/features/support/world.ts

+6-38
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,21 @@
1-
import { setWorldConstructor, World, IWorldOptions } from '@cucumber/cucumber'
2-
import { randomUUID } from 'crypto'
3-
import { RemoteRepo } from '../classes/remote'
4-
import * as utils from './utils'
5-
import * as fs from 'fs'
6-
import * as path from 'path'
7-
import { ClonedRepository } from '../classes/repository'
8-
import { BundleServer } from '../classes/bundleServer'
1+
import { setWorldConstructor, IWorldOptions } from '@cucumber/cucumber'
2+
import * as utils from '../../../shared/support/utils'
3+
import { ClonedRepository } from '../../../shared/classes/repository'
4+
import { BundleServerWorldBase, BundleServerParameters } from '../../../shared/support/world'
95

106
export enum User {
117
Me = 1,
128
Another,
139
}
1410

15-
interface BundleServerParameters {
16-
bundleServerCommand: string
17-
bundleWebServerCommand: string
18-
trashDirectoryBase: string
19-
}
20-
21-
export class BundleServerWorld extends World<BundleServerParameters> {
22-
// Internal variables
23-
trashDirectory: string
24-
25-
// Bundle server
26-
bundleServer: BundleServer
27-
remote: RemoteRepo | undefined
28-
11+
export class EndToEndBundleServerWorld extends BundleServerWorldBase {
2912
// Users
3013
repoMap: Map<User, ClonedRepository>
3114

3215
constructor(options: IWorldOptions<BundleServerParameters>) {
3316
super(options)
3417

3518
this.repoMap = new Map<User, ClonedRepository>()
36-
37-
// Set up the trash directory
38-
this.trashDirectory = path.join(utils.absPath(this.parameters.trashDirectoryBase), randomUUID())
39-
fs.mkdirSync(this.trashDirectory, { recursive: true });
40-
41-
// Set up the bundle server
42-
this.bundleServer = new BundleServer(utils.absPath(this.parameters.bundleServerCommand),
43-
utils.absPath(this.parameters.bundleWebServerCommand))
4419
}
4520

4621
cloneRepositoryFor(user: User, bundleUri?: string): void {
@@ -84,13 +59,6 @@ export class BundleServerWorld extends World<BundleServerParameters> {
8459

8560
return clonedRepo
8661
}
87-
88-
cleanup(): void {
89-
this.bundleServer.cleanup()
90-
91-
// Delete the trash directory
92-
fs.rmSync(this.trashDirectory, { recursive: true })
93-
}
9462
}
9563

96-
setWorldConstructor(BundleServerWorld)
64+
setWorldConstructor(EndToEndBundleServerWorld)

test/e2e/package-lock.json

+1-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)