mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
a4af238c95
* Fix order so hash is set before notify * Always run tests on master branch
233 lines
7.2 KiB
Groovy
233 lines
7.2 KiB
Groovy
import groovy.io.FileType
|
|
|
|
import static groovy.json.JsonOutput.toJson
|
|
|
|
COMMIT_HASH = null
|
|
RUNNING_LOCALLY = false
|
|
AUXILIARY_SLEEP_MS = 10000
|
|
START_TIME_MS = System.currentTimeMillis()
|
|
WORKSPACES_ROOT = 'workspaces'
|
|
TEST_CASES_DIR = 'testCases'
|
|
LIBRARY_VERSION_UNDER_TEST = "git log --format=%H -n 1".execute().text.trim()
|
|
|
|
EXCLUDED_FROM_CONSUMER_TESTING_REGEXES = [
|
|
/^documentation\/.*$/,
|
|
/^.travis.yml$/,
|
|
/^test\/.*$/
|
|
]
|
|
|
|
|
|
newEmptyDir(WORKSPACES_ROOT)
|
|
TestRunnerThread.workspacesRootDir = WORKSPACES_ROOT
|
|
TestRunnerThread.libraryVersionUnderTest = LIBRARY_VERSION_UNDER_TEST
|
|
TestRunnerThread.repositoryUnderTest = System.getenv('TRAVIS_REPO_SLUG') ?: 'SAP/jenkins-library'
|
|
|
|
def testCaseThreads
|
|
def cli = new CliBuilder(
|
|
usage: 'groovy consumerTestController.groovy [<options>]',
|
|
header: 'Options:',
|
|
footer: 'If no options are set, all tests are run centrally, i.e. on travisCI.')
|
|
|
|
cli.with {
|
|
h longOpt: 'help', 'Print this help text and exit.'
|
|
l longOpt: 'run-locally', 'Run consumer tests locally in Docker, i.e. skip reporting of GitHub status.'
|
|
s longOpt: 'single-test', args: 1, argName: 'filePath', 'Run single test.'
|
|
}
|
|
|
|
def options = cli.parse(args)
|
|
|
|
if (options.h) {
|
|
cli.usage()
|
|
return
|
|
}
|
|
|
|
if (options.l) {
|
|
RUNNING_LOCALLY = true
|
|
}
|
|
|
|
if (!RUNNING_LOCALLY) {
|
|
/*
|
|
In case the build is performed for a pull request TRAVIS_COMMIT is a merge
|
|
commit between the base branch and the PR branch HEAD. That commit is actually built.
|
|
But for notifying about a build status we need the commit which is currently
|
|
the HEAD of the PR branch.
|
|
|
|
In case the build is performed for a simple branch (not associated with a PR)
|
|
In this case there is no merge commit between any base branch and HEAD of a PR branch.
|
|
The commit which we need for notifying about a build status is in this case simply
|
|
TRAVIS_COMMIT itself.
|
|
*/
|
|
COMMIT_HASH = System.getenv('TRAVIS_PULL_REQUEST_SHA') ?: System.getenv('TRAVIS_COMMIT')
|
|
|
|
if (changeDoesNotNeedConsumerTesting()) {
|
|
println 'No consumer tests necessary.'
|
|
notifyGithub("success", "No consumer tests necessary.")
|
|
return
|
|
} else {
|
|
notifyGithub("pending", "Consumer tests are in progress.")
|
|
}
|
|
}
|
|
|
|
if (!System.getenv('CX_INFRA_IT_CF_USERNAME') || !System.getenv('CX_INFRA_IT_CF_PASSWORD')) {
|
|
exitPrematurely('Environment variables CX_INFRA_IT_CF_USERNAME and CX_INFRA_IT_CF_PASSWORD need to be set.')
|
|
}
|
|
|
|
if (options.s) {
|
|
def file = new File(options.s)
|
|
if (!file.exists()) {
|
|
exitPrematurely("Test case configuration file '${file}' does not exist. " +
|
|
"Please provide path to a configuration file of structure '/rootDir/areaDir/testCase.yml'.")
|
|
}
|
|
testCaseThreads = [new TestRunnerThread(file)]
|
|
} else {
|
|
testCaseThreads = listTestCaseThreads()
|
|
}
|
|
|
|
testCaseThreads.each { it ->
|
|
it.start()
|
|
}
|
|
|
|
//The thread below will print to console while the test cases are running.
|
|
//Otherwise the job would be canceled after 10 minutes without output.
|
|
def done = false
|
|
Thread.start {
|
|
def outputWasPrintedPrematurely = false
|
|
def singleTestCase = (testCaseThreads.size() == 1)
|
|
if (singleTestCase) {
|
|
AUXILIARY_SLEEP_MS = 1000 //for a single test case we print the running output every second
|
|
}
|
|
for (; ;) {
|
|
if (singleTestCase) {
|
|
testCaseThreads[0].printRunningStdOut()
|
|
} else {
|
|
println "[INFO] Consumer tests are still running."
|
|
}
|
|
|
|
// Build is killed at 50 min, print log to console at minute 45
|
|
int MINUTES_SINCE_START = (System.currentTimeMillis() - START_TIME_MS) / (1000 * 60)
|
|
if (!singleTestCase && MINUTES_SINCE_START > 44 && !outputWasPrintedPrematurely) {
|
|
testCaseThreads.each { thread ->
|
|
thread.printOutput()
|
|
}
|
|
outputWasPrintedPrematurely = true
|
|
}
|
|
|
|
sleep(AUXILIARY_SLEEP_MS)
|
|
if (done) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
testCaseThreads.each { it ->
|
|
it.join()
|
|
}
|
|
done = true
|
|
|
|
def failedThreads = testCaseThreads.findAll { thread ->
|
|
thread.returnCode != 0
|
|
}
|
|
|
|
def status
|
|
def statusMessage
|
|
if (failedThreads.size() == 0) {
|
|
status = "success"
|
|
statusMessage = "All consumer tests finished successfully. Congratulations!"
|
|
} else {
|
|
failedThreads.each { failedThread ->
|
|
println "[ERROR] ${failedThread.uniqueName}: Process execution of command: '${failedThread.lastCommand}' failed. " +
|
|
"Return code: ${failedThread.returnCode}."
|
|
failedThread.printOutput()
|
|
}
|
|
status = "failure"
|
|
statusMessage "The following consumer test(s) failed: ${failedThreads}"
|
|
}
|
|
|
|
if (!RUNNING_LOCALLY) {
|
|
notifyGithub(status, statusMessage)
|
|
}
|
|
|
|
println statusMessage
|
|
|
|
if (status == "failure") {
|
|
System.exit(1)
|
|
}
|
|
|
|
|
|
def listTestCaseThreads() {
|
|
//Each dir that includes a yml file is a test case
|
|
def threads = []
|
|
new File(TEST_CASES_DIR).traverse(type: FileType.FILES, nameFilter: ~/^.+\.yml\u0024/) { file ->
|
|
threads << new TestRunnerThread(file)
|
|
}
|
|
return threads
|
|
}
|
|
|
|
def notifyGithub(state, description) {
|
|
println "[INFO] Notifying about state '${state}' for commit '${COMMIT_HASH}'."
|
|
|
|
URL url = new URL("https://api.github.com/repos/SAP/jenkins-library/statuses/${COMMIT_HASH}")
|
|
HttpURLConnection con = (HttpURLConnection) url.openConnection()
|
|
con.setRequestMethod('POST')
|
|
con.setRequestProperty("Content-Type", "application/json; utf-8");
|
|
con.setRequestProperty('User-Agent', 'groovy-script')
|
|
con.setRequestProperty('Authorization', "token ${System.getenv('INTEGRATION_TEST_VOTING_TOKEN')}")
|
|
|
|
def postBody = [
|
|
state : state,
|
|
target_url : System.getenv('TRAVIS_BUILD_WEB_URL'),
|
|
description: description,
|
|
context : "integration-tests"
|
|
]
|
|
|
|
con.setDoOutput(true)
|
|
con.getOutputStream().withStream { os ->
|
|
os.write(toJson(postBody).getBytes("UTF-8"))
|
|
}
|
|
|
|
int responseCode = con.getResponseCode()
|
|
if (responseCode != HttpURLConnection.HTTP_CREATED) {
|
|
exitPrematurely("[ERROR] Posting status to github failed. Expected response code " +
|
|
"'${HttpURLConnection.HTTP_CREATED}', but got '${responseCode}'. " +
|
|
"Response message: '${con.getResponseMessage()}'",
|
|
34) // Error code taken from curl: CURLE_HTTP_POST_ERROR
|
|
}
|
|
}
|
|
|
|
def changeDoesNotNeedConsumerTesting() {
|
|
if (System.getenv('TRAVIS_BRANCH') == 'master') {
|
|
return false
|
|
}
|
|
|
|
def excludesRegex = '(' + EXCLUDED_FROM_CONSUMER_TESTING_REGEXES.join('|') + ')'
|
|
|
|
"git remote add sap https://github.com/SAP/jenkins-library.git".execute().waitFor()
|
|
"git fetch sap".execute().waitFor()
|
|
def diff = "git diff --name-only sap/master ${LIBRARY_VERSION_UNDER_TEST}".execute().text.trim()
|
|
|
|
for (def line : diff.readLines()) {
|
|
if (!(line ==~ excludesRegex)) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
static def newEmptyDir(String dirName) {
|
|
def dir = new File(dirName)
|
|
if (dir.exists()) {
|
|
if (!dir.deleteDir()) {
|
|
exitPrematurely("Deletion of dir '${dirName}' failed.")
|
|
}
|
|
}
|
|
if (!dir.mkdirs()) {
|
|
exitPrematurely("Creation of dir '${dirName}' failed.")
|
|
}
|
|
}
|
|
|
|
static def exitPrematurely(String message, int returnCode = 1) {
|
|
println message
|
|
System.exit(returnCode)
|
|
}
|