Skip to content

Commit c0f8732

Browse files
author
Alan Christie
committed
- Refactoring to support Docker pipeline execution
- Better handling of test execution timeout - Extends tests for utils - Adds a Docker-specific gradle task - Better gitignore
1 parent 4265b81 commit c0f8732

File tree

10 files changed

+1014
-754
lines changed

10 files changed

+1014
-754
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ work
1212
.nextflow.log*
1313
/tmp
1414
**/*.egg-info
15+
**/.DS_Store

README.md

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,13 @@ of the number of test files and individual tests that were executed: -
5454
-------
5555
Summary
5656
-------
57-
Test Files : 20
58-
Tests : 30
59-
Tests ignored: 0
60-
Tests failed : 0
57+
Test Files : 20
58+
Tests Found : 30
59+
Tests passed : 30
60+
Tests failed : 0
61+
Tests skipped : 0
62+
Tests ignored : 0
63+
Warnings : 0
6164
-------
6265
Passed: TRUE
6366

@@ -68,8 +71,27 @@ across all the repositories by running the tester from here. Simply
6871
run the following Gradle command from here: -
6972

7073
$ ./gradlew runPipelineTester
74+
75+
### In Docker
76+
You can run the pipeline tests in Docxker using their expected container
77+
image (defined in the service descriptor). Doing this gives you added
78+
confidence that your pipeline will work wen deployed.
79+
80+
To run in Docker you need to add the `-d` or `--indocker` command-line
81+
argument. To pass these variables through Gradle into the pipeline tester
82+
run the tests like this: -
83+
84+
$ ./gradlew runPipelineTester -Pptargs=-d
85+
86+
Or by using the Docker-specific gradle command:
87+
88+
$ ./gradlew runDockerPipelineTester
89+
90+
> When you run _in docker_ only the tests that can run in Docker (those with
91+
a defined image name) will be executed. Tests that cannot be executed in
92+
Docker will be _skipped_.
7193

72-
### Debugging test failures
94+
## Debugging test failures
7395
Ideally your tests will pass. When they don't the test framework prints
7496
the collected log to the screen as it happens but also keeps all the files
7597
generated (by all the tests) in case they are of use for diagnostics.
@@ -102,6 +124,13 @@ in order to create a set of tests for a new pipeline.
102124
> At the moment the tester only permits one test file per pipeline so all
103125
tests for a given pipeline need to be composed in one file.
104126

127+
## Testing the pipeline utilities
128+
The pipeline utilities consist of a number of Python-based modules
129+
that can be tested using `setup.py`. To test these modules run the
130+
following from the `src/python` directory: -
131+
132+
$ python setup.py test
133+
105134
---
106135

107136
[Conda]: https://conda.io/docs/

build.gradle

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,12 @@ task runPipelineTester(type: Exec) {
3434
commandLine 'groovy', 'PipelineTester.groovy', "$args"
3535

3636
}
37+
38+
task runDockerPipelineTester(type: Exec) {
39+
40+
description 'Runs the PipelineTester Docker tests'
41+
42+
workingDir 'src/groovy'
43+
commandLine 'groovy', 'PipelineTester.groovy', '-indocker'
44+
45+
}

pipeline.test.template

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,19 @@
3131
// file. Individual tests can define their own test-specific files
3232
// with their own 'creates' block, discussed later in this file.
3333
//
34+
// pin: This property can be used to over-ride the automatically
35+
// generated data input path (which is typically the repository's
36+
// own data directory. This allows you to use date outside the
37+
// repository - maybe because it's a large file or an experimental
38+
// file.
39+
//
3440
// There can only be one setup_collection section and it must be
3541
// the first section in the file.
3642

3743
setup_collection = [
3844
timeout: 10,
39-
creates: [ 'output.txt' ]
45+
creates: [ 'output.txt' ],
46+
pin: /Users/alan/data
4047
],
4148

4249
// Individual tests.
@@ -60,6 +67,8 @@
6067
//
6168
// If a test is not working an you want to keep it and avoid running it
6269
// then simply prefix the test section name with `ignore_`.
70+
//
71+
// The location of any input data you provide in your test
6372

6473
test_1 = [
6574

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env groovy
2+
3+
/**
4+
* Copyright (c) 2018 Informatics Matters Ltd.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
/**
20+
* The PipelineTester Container Executor class. The class is responsible for
21+
* executing a pipeline command in the supplied Docker container image.
22+
*/
23+
class ContainerExecutor {
24+
25+
/**
26+
* Executes the given command in the supplied container image.
27+
*
28+
* @param imageName The image to run the command in
29+
* @param command The command to run
30+
* @param timeoutSeconds The time to allow for the command to execute
31+
* @return A list containing the STDOUT and STDERR encapsulated in a
32+
* StringBuilder(), an integer command exit code and a timeout
33+
* boolean (set if the program execution timed out)
34+
*/
35+
static execute(String command, String imageName,
36+
String pin, String pout,
37+
int timeoutSeconds) {
38+
39+
StringBuilder sout = new StringBuilder()
40+
StringBuilder serr = new StringBuilder()
41+
42+
String cmd = "docker run -v $pin:/data -v $pout:/output" +
43+
" -w /output -e PIN=/data -e POUT=/output $imageName" +
44+
" sh -c '$command'"
45+
46+
def proc = ['sh', '-c', cmd].execute(null, new File('.'))
47+
proc.consumeProcessOutput(sout, serr)
48+
proc.waitForOrKill((long)timeoutSeconds * 1000)
49+
int exitValue = proc.exitValue()
50+
51+
// Timeout?
52+
//
53+
// Some exit codes have a special meaning.
54+
//
55+
// We can, for example, assume that the process was killed
56+
// if the exit code is 143 as 143, which is 128 + 15, means
57+
// the program died with signal 15 (SIGTERM).
58+
// See http://www.tldp.org/LDP/abs/html/exitcodes.html.
59+
boolean timeout = exitValue == 143 ? true : false
60+
61+
return [sout, serr, exitValue, timeout]
62+
63+
}
64+
65+
}

0 commit comments

Comments
 (0)