1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-12 10:55:20 +02:00

batsExecuteTests - add step for executing bats-core (#254)

details are available in the documentation contained in this PR
This commit is contained in:
Oliver Nocon 2018-08-15 11:41:01 +02:00 committed by GitHub
parent e49633a7d2
commit 17ee927807
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 320 additions and 0 deletions

View File

@ -0,0 +1,77 @@
# batsExecuteTests
## Description
This step executes tests using the [Bash Automated Testing System - bats-core](https://github.com/bats-core/bats-core)
## Prerequsites
You need to have a Bats test file. By default you would put this into directory `src/test` within your source code repository.
## Parameters
| parameter | mandatory | default | possible values |
|-----------|-----------|---------|-----------------|
| script | no | empty `globalPipelineEnvironment` | |
| dockerImage | no | `node:8-stretch` | |
| dockerWorkspace | no |`/home/node`| |
| envVars | no | `[:]` | |
| failOnError | no | `false` | |
| gitBranch | no | | |
| gitSshKeyCredentialsId | no | | |
| outputFormat | no | `junit` | `tap` |
| repository | no | `https://github.com/bats-core/bats-core.git` | |
| stashContent | no | `['tests']` | |
| testPackage | no | `piper-bats` | |
| testPath | no | `src/test`| |
| testRepository | no | | |
Details:
* `outputFormat` defines the format of the test result output. `junit` would be the standard for automated build environments but you could use also the option `tap`.
* For the transformation of the test result to xUnit format the node module **tap-xunit** is used. `dockerImage` and `dockerWorkspace` define the Docker image used for the transformation and `testPackage` defines the name of the test package used in the xUnit result file.
* `testPath` defines either the directory which contains the test files (`*.bats`) or a single file. You can find further details in the [Bats-core documentation](https://github.com/bats-core/bats-core#usage)
* With `failOnError` you can define the behavior, in case tests fail. For example, in case of `outputFormat: 'junit'` you should set it to `false`. Otherwise test results cannot be recorded using the `testsPublishhResults` step afterwards.
* You can pass environment variables to the test execution by defining parameter `envVars`.
With `envVars` it is possible to pass either fixed values but also templates using [`commonPipelineEnvironment`](commonPipelineEnvironment.md).
Example:
```
batsExecuteTests script: this, envVars = [
FIX_VALUE: 'my fixed value',
CONTAINER_NAME: '${commonPipelineEnvironment.configuration.steps.executeBatsTests.dockerContainerName}',
IMAGE_NAME: '${return commonPipelineEnvironment.getDockerImageNameAndTag()}'
]
```
This means within the test one could refer to environment variables by calling e.g.
`run docker run --rm -i --name $CONTAINER_NAME --entrypoint /bin/bash $IMAGE_NAME echo "Test"`
* Using parameters `testRepository` the tests can be loaded from another reposirory. In case the tests are not located in the master branch the branch can be specified with `gitBranch`. For protected repositories you can also define the access credentials via `gitSshKeyCredentialsId`. **Note: In case of using a protected repository, `testRepository` should include the ssh link to the repository.**
* The parameter `repository` defines the version of **bats-core** to be used. By default we use the version from the master branch.
## Step configuration
The following parameters can also be specified as step/stage/general parameters using the [global configuration](../configuration.md):
* dockerImage
* dockerWorkspace
* envVars
* failOnError
* gitBranch
* gitSshKeyCredentialsId
* outputFormat
* repository
* stashContent
* testPackage
* testPath
* testRepository
## Example
```groovy
batsExecuteTests script:this
testsPublishResults junit: [pattern: '**/Test-*.xml', archive: true]
```

View File

@ -4,6 +4,7 @@ pages:
- Configuration: configuration.md
- 'Library steps':
- artifactSetVersion: steps/artifactSetVersion.md
- batsExecuteTests: steps/batsExecuteTests.md
- checkChangeInDevelopment: steps/checkChangeInDevelopment.md
- cloudFoundryDeploy: steps/cloudFoundryDeploy.md
- commonPipelineEnvironment: steps/commonPipelineEnvironment.md

View File

@ -42,6 +42,17 @@ steps:
sbt:
filePath: 'sbtDescriptor.json'
versioningTemplate: '${version}-${timestamp}${commitId?"+"+commitId:""}'
batsExecuteTests:
dockerImage: 'node:8-stretch'
dockerWorkspace: '/home/node'
envVars: {}
outputFormat: 'junit' # tap, junit
testPath: 'src/test'
failOnError: false
repository: 'https://github.com/bats-core/bats-core.git'
stashContent:
- 'tests'
testPackage: 'piper-bats'
checksPublishResults:
aggregation:
active: true

View File

@ -0,0 +1,143 @@
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.ExpectedException
import org.junit.rules.RuleChain
import util.*
import static org.hamcrest.Matchers.hasItem
import static org.hamcrest.Matchers.is
import static org.junit.Assert.assertThat
class BatsExecuteTestsTest extends BasePiperTest {
private ExpectedException thrown = ExpectedException.none()
private JenkinsStepRule jsr = new JenkinsStepRule(this)
private JenkinsLoggingRule jlr = new JenkinsLoggingRule(this)
private JenkinsShellCallRule jscr = new JenkinsShellCallRule(this)
private JenkinsDockerExecuteRule jder = new JenkinsDockerExecuteRule(this)
@Rule
public RuleChain rules = Rules
.getCommonRules(this)
.around(thrown)
.around(jder)
.around(jscr)
.around(jlr)
.around(jsr)
List withEnvArgs = []
@Before
void init() throws Exception {
helper.registerAllowedMethod("withEnv", [List.class, Closure.class], {arguments, closure ->
arguments.each {arg ->
withEnvArgs.add(arg.toString())
}
return closure()
})
}
@Test
void testDefault() {
nullScript.commonPipelineEnvironment.configuration = [general: [container: 'test-container']]
jsr.step.batsExecuteTests(
script: nullScript,
juStabUtils: utils,
dockerContainerName: 'test-container',
dockerImageNameAndTag: 'test/image',
envVars: [
IMAGE_NAME: 'test/image',
CONTAINER_NAME: '${commonPipelineEnvironment.configuration.general.container}'
],
testPackage: 'testPackage'
)
// asserts
assertThat(withEnvArgs, hasItem('IMAGE_NAME=test/image'))
assertThat(withEnvArgs, hasItem('CONTAINER_NAME=test-container'))
assertThat(jscr.shell, hasItem('git clone https://github.com/bats-core/bats-core.git'))
assertThat(jscr.shell, hasItem('bats-core/bin/bats --recursive --tap src/test > \'TEST-testPackage.tap\''))
assertThat(jscr.shell, hasItem('cat \'TEST-testPackage.tap\''))
assertThat(jder.dockerParams.dockerImage, is('node:8-stretch'))
assertThat(jder.dockerParams.dockerWorkspace, is('/home/node'))
assertThat(jscr.shell, hasItem('npm install tap-xunit -g'))
assertThat(jscr.shell, hasItem('cat \'TEST-testPackage.tap\' | tap-xunit --package=\'testPackage\' > TEST-testPackage.xml'))
assertJobStatusSuccess()
}
@Test
void testTap() {
jsr.step.batsExecuteTests(
script: nullScript,
juStabUtils: utils,
outputFormat: 'tap'
)
assertThat(jder.dockerParams.size(), is(0))
}
@Test
void testFailOnError() {
helper.registerAllowedMethod('sh', [String.class], {s ->
if (s.startsWith('bats-core/bin/bats')) {
throw new Exception('Shell call failed')
} else {
return null
}
})
thrown.expectMessage('Shell call failed')
jsr.step.batsExecuteTests(
script: nullScript,
juStabUtils: utils,
failOnError: true,
)
}
@Test
void testGit() {
def gitRepository
helper.registerAllowedMethod('git', [Map.class], {m ->
gitRepository = m
})
helper.registerAllowedMethod('stash', [String.class], {s ->
assertThat(s, is('batsTests'))
})
jsr.step.batsExecuteTests(
script: nullScript,
juStabUtils: utils,
testRepository: 'testRepo',
)
assertThat(gitRepository.size(), is(1))
assertThat(gitRepository.url, is('testRepo'))
assertThat(jder.dockerParams.stashContent, hasItem('batsTests'))
}
@Test
void testGitBranchAndCredentials() {
def gitRepository
helper.registerAllowedMethod('git', [Map.class], {m ->
gitRepository = m
})
helper.registerAllowedMethod('stash', [String.class], {s ->
assertThat(s, is('batsTests'))
})
jsr.step.batsExecuteTests(
script: nullScript,
juStabUtils: utils,
gitBranch: 'test',
gitSshKeyCredentialsId: 'testCredentials',
testRepository: 'testRepo',
)
assertThat(gitRepository.size(), is(3))
assertThat(gitRepository.credentialsId, is('testCredentials'))
assertThat(gitRepository.branch, is('test'))
}
}

View File

@ -0,0 +1,80 @@
import com.sap.piper.Utils
import com.sap.piper.ConfigurationHelper
import groovy.text.SimpleTemplateEngine
import groovy.transform.Field
@Field String STEP_NAME = 'batsExecuteTests'
@Field Set STEP_CONFIG_KEYS = [
'dockerImage', //
'dockerWorkspace',
'envVars',
'failOnError',
'gitBranch',
'gitSshKeyCredentialsId',
'outputFormat',
'repository',
'stashContent',
'testPackage',
'testPath',
'testRepository'
]
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS
def call(Map parameters = [:]) {
handlePipelineStepErrors (stepName: STEP_NAME, stepParameters: parameters) {
def utils = parameters.juStabUtils ?: new Utils()
def script = parameters.script ?: [commonPipelineEnvironment: commonPipelineEnvironment]
Map config = ConfigurationHelper
.loadStepDefaults(this)
.mixinGeneralConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
.mixinStepConfig(script.commonPipelineEnvironment, STEP_CONFIG_KEYS)
.mixinStageConfig(script.commonPipelineEnvironment, parameters.stageName?:env.STAGE_NAME, STEP_CONFIG_KEYS)
.mixin(parameters, PARAMETER_KEYS)
.use()
// report to SWA
utils.pushToSWA([step: STEP_NAME], config)
script.commonPipelineEnvironment.setInfluxStepData('bats', false)
if (config.testRepository) {
def gitParameters = [url: config.testRepository]
if (config.gitSshKeyCredentialsId?.length()>0) gitParameters.credentialsId = config.gitSshKeyCredentialsId
if (config.gitBranch?.length()>0) gitParameters.branch = config.gitBranch
git gitParameters
stash 'batsTests'
config.stashContent = ['batsTests']
} else {
config.stashContent = utils.unstashAll(config.stashContent)
}
//resolve commonPipelineEnvironment references in envVars
config.envVarList = []
config.envVars.each {e ->
def envValue = SimpleTemplateEngine.newInstance().createTemplate(e.getValue()).make(commonPipelineEnvironment: script.commonPipelineEnvironment).toString()
config.envVarList.add("${e.getKey()}=${envValue}")
}
withEnv(config.envVarList) {
sh "git clone ${config.repository}"
try {
sh "bats-core/bin/bats --recursive --tap ${config.testPath} > 'TEST-${config.testPackage}.tap'"
script.commonPipelineEnvironment.setInfluxStepData('bats', true)
} catch (err) {
echo "[${STEP_NAME}] One or more tests failed"
if (config.failOnError) throw err
} finally {
sh "cat 'TEST-${config.testPackage}.tap'"
if (config.outputFormat == 'junit') {
dockerExecute(dockerImage: config.dockerImage, dockerWorkspace: config.dockerWorkspace, stashContent: config.stashContent) {
sh "npm install tap-xunit -g"
sh "cat 'TEST-${config.testPackage}.tap' | tap-xunit --package='${config.testPackage}' > TEST-${config.testPackage}.xml"
}
}
}
}
}
}

View File

@ -96,6 +96,14 @@ class commonPipelineEnvironment implements Serializable {
return influxCustomDataMap
}
def setInfluxStepData (dataKey, value) {
influxCustomDataMap.step_data[dataKey] = value
}
def getInfluxStepData (dataKey) {
return influxCustomDataMap.step_data[dataKey]
}
def getMtarFilePath() {
return mtarFilePath
}