How to always write out to a .csv data file in a Jenkins Groovy pipeline even with test failures

Viewed 1275

I have a test to generate new customer data using TestNG:

public class GenerateNewCustomers{

private static ArrayList<String> customers = new ArrayList<>();

@Test(invocationCount = 5)
public void runApplicationGeneration() throws InterruptedException {

    api = new AgreementApiCalls();
    api.createNewCustomer();//more api calls to enrich customer object
    api.customers = api.insertNewcustomer();

    setCustomers(customers);

@AfterClass
public void writeTestData() throws IOException {
    generateTestDataFile();
}

private static void setCustomers(ArrayList<String> customers) {
    GenerateNewCustomers.customers = customers;
}

private void generateTestDataFile() throws IOException {

    FileWriter writer = new FileWriter("src/test/resources/testData.csv");

    List<String> test = new ArrayList<>(customers);

    String collect = test.stream().collect(Collectors.joining(","));

    writer.write(collect);
    writer.close();
}

This works fine locally:- if, for arguments sake, invocation 4 fails then the previous 3 still get written to the file testData.csv.

My question is how do I also reproduce this behaviour from a CI perspective, specifically, Jenkins? When I run from CI, any failures result in the file not being written to. My pipeline script has this:-

env.PASSWORD_TOOL_SECRET = 'password'
env.PASSWORD_TOOL_SESSION = ''

String getOutputFromClientTool( String command ) {
    String output = sh script: command, returnStdout: true
    output.trim()
}

 def setEnvironmentVariables () {
    sh "java -version"
    env.PASSWORD_TOOL_SESSION = getOutputFromClientTool('./configuration/getPasswordToolSession.sh')
    sh "op get item 'run-tests-${env.ENVIRONMENT}' --vault='my-team' --session=${env.PASSWORD_TOOL_SESSION} > run-tests.json"

    env.SYS_USERNAME      = getOutputFromClientTool("cat run-tests.json | jq -r '.details.sections[] | select( .fields != null ) | .fields[] | select( .t == \"sys-username\" ).v'")
    env.SYS_PASSWORD      = getOutputFromClientTool("cat run-tests.json | jq -r '.details.sections[] | select( .fields != null ) | .fields[] | select( .t == \"sys-password\" ).v'")...//more env vars set here


    withCredentials([
            usernamePassword(
                    credentialsId: 'maven-ro',
                    usernameVariable: 'MAVEN_USERNAME',
                    passwordVariable: 'MAVEN_PASSWORD'
            )
    ]) {
        env.MAVEN_USERNAME = MAVEN_USERNAME
        env.MAVEN_PASSWORD = MAVEN_PASSWORD
    }
}
       try {
           sh "./gradlew clean test -Denv=${env.ENV} - 
           PtestNGSuite=${suite} --no-daemon"
                    archiveArtifacts artifacts: 
                     "src/test/resources/testData.csv", fingerprint: true
                } finally {
                    publishHTML(
                          target: [
                                    allowMissing         : false,
                                    alwaysLinkToLastBuild: false,
                                    keepAll              : true,
                                    reportDir            : 'build/reports/tests/test',
                                    reportFiles          : 'index.html',
                                    reportName           : "Customer Generation Report"
                            ]
                    )
                }
            }
        }

    } catch (exception) {
        currentBuild.result = 'FAILURE'
        throw exception
    } finally {
        // configure notification to slack channel
    }
2 Answers

I think you're missing the archiveArtifacts if there's an exception. Try moving it to a proper post clause, like this:

pipeline {
    stages {...}

    post {
        always {
            archiveArtifacts artifacts: "src/test/resources/testData.csv", fingerprint: true
        }
    }
}

try/catch always popular case

try {
  stage('test') {
    // test
  }
}
catch(e) {
    // print stack trace, message ...
    currentBuild.result = 'FAILURE'

}
finally {
  // always run there
}
Related