Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Requesting help in using the new Classifications programatically #118

Closed
e2etesterviu opened this issue Feb 14, 2017 · 4 comments
Closed

Comments

@e2etesterviu
Copy link

Hi,
Thanks you for the new support to add Classifications in the jenkins plugin for cucumber-reports.

I have a small question - I use Jenkins file approach to configure my job. In this job, I have a stage to publish cucumber reports as shown below

            stage("Publish Reports") {
                echo "***** Publish Reports *****"
                step([
                    $class: 'CucumberReportPublisher',
                    classifications: getClassifications(),
                    failedFeaturesNumber: 0,
                    failedScenariosNumber: 0,
                    failedStepsNumber: 0,
                    fileExcludePattern: '',
                    fileIncludePattern: '**/*.json',
                    jsonReportDirectory: 'testrun/reports',
                    parallelTesting: true,
                    pendingStepsNumber: 0,
                    skippedStepsNumber: 0,
                    trendsLimit: 0,
                    undefinedStepsNumber: 0
                ])
            }

As shown above, I need to pass the classifications to the report at runtime - by reading a json file. The contents of this file is dynamic - i.e. each test run may have different information populated in this file during the test execution.

The json file format can be tweaked in any way to make it easier for setting the classifications correctly.

I am stuck at how convert the json in the format needed below at runtime -

classifications: [
    <object of type net.masterthought.jenkins.CucumberReportPublisher.Classification>,
    <object of type net.masterthought.jenkins.CucumberReportPublisher.Classification>,
    <object of type net.masterthought.jenkins.CucumberReportPublisher.Classification>]

Example json:

[
    {
        "key":"samsung",
        "value":"api-22"
    },
    {
        "key":"samsung", 
        "value":"api-23"
    }
]

Can you please help? Thanks.

@damianszczepanik
Copy link
Member

I don't have plan for this, you can prepare PR so I will of course merge it

@anandbagmar
Copy link
Contributor

anandbagmar commented Feb 16, 2017

Hi,
I can send a PR based on your thoughts on the preferred solution from the options listed below.

Also, please guide me on how I should test the changes before I send the PR as I have not worked on Jenkins plugins before.

Problem - Classification is throwing a NotSerializableException

I get a net.masterthought.jenkins.CucumberReportPublisher$Classification NotSerializableException error when using the Cucumber-reports plugin via Jenkins file.

Potential Solution

  • I think the Classification object needs to be made Serializable.
  • Another alternate would be to change the signature of the CucumberReportPublisher consturctor to take a List of HashMaps instead of a List of Classification objects as shown below.
    @DataBoundConstructor
    public CucumberReportPublisher(String jsonReportDirectory, String fileIncludePattern, String fileExcludePattern,
                                   int trendsLimit, int failedStepsNumber, int skippedStepsNumber, int pendingStepsNumber,
                                   int undefinedStepsNumber, int failedScenariosNumber, int failedFeaturesNumber,
                                   String buildStatus, boolean parallelTesting, List<HashMap<String, String>> classifications) {

        this.jsonReportDirectory = jsonReportDirectory;
        this.fileIncludePattern = fileIncludePattern;
        this.fileExcludePattern = fileExcludePattern;
        this.trendsLimit = trendsLimit;
        this.failedStepsNumber = failedStepsNumber;
        this.skippedStepsNumber = skippedStepsNumber;
        this.pendingStepsNumber = pendingStepsNumber;
        this.undefinedStepsNumber = undefinedStepsNumber;
        this.failedScenariosNumber = failedScenariosNumber;
        this.failedFeaturesNumber = failedFeaturesNumber;
        this.buildStatus = buildStatus == null ? null : Result.fromString(buildStatus);
        this.parallelTesting = parallelTesting;
        // don't store the classifications if there was no element provided
        if (CollectionUtils.isNotEmpty(classifications)) {
            for (HashMap<String, String> classification: classifications){
               this.classifications.add(new Classification(classification.get("key"), classification.get("value")));
            }
        }
    }

Steps to reproduce the problem are mentioned below.

  • To provide the (dynamic) classifications based on the test run, I generate a myDevices.txt file (json content) during test execution. Sample content of this file shown below:
myDevices.txt contents: 
{
    "classifications": [
        {
            "value": "ID: ZY223V77FK, API: 24, APPIUM PORT: 0",
            "key": "motorola"
        },
        {
            "value": "ID: ZY2224X23M, API: 23, APPIUM PORT: 0",
            "key": "motorola"
        }
    ]
}
  • Configure the Jenkins file to use the cucumber-reports plugin after tests have run
            stage("Publish Reports") {
                echo "***** Publish Reports *****"
                def runClassifications = getClassificationsFromFile()
                println "runClassifications - " + runClassifications.toString()
                step([
                        $class: 'CucumberReportPublisher',
                        classifications: runClassifications,
                        failedFeaturesNumber: 0,
                        failedScenariosNumber: 0,
                        failedStepsNumber: 0,
                        fileExcludePattern: '',
                        fileIncludePattern: '**/*.json',
                        jsonReportDirectory: 'testrun/reports',
                        parallelTesting: true,
                        pendingStepsNumber: 0,
                        skippedStepsNumber: 0,
                        trendsLimit: 0,
                        undefinedStepsNumber: 0
                ])
            }
  • Load the myDevices.txt file with list of classifications and create the list of Classifications as expected by the plugin
import net.masterthought.jenkins.CucumberReportPublisher.Classification
def ArrayList<Classification> getClassificationsFromFile() {
    String fileName = "${WORKSPACE}/testRun/reports/myDevices.txt"
    def catCmd = sh(script: 'cat ${WORKSPACE}/testRun/reports/myDevices.txt', returnStdout: true)
    def slurper = new groovy.json.JsonSlurper()
    def json = slurper.parseText( catCmd )
    ArrayList<Classification> classifications = Collections.emptyList()
    for (int num=0; num < json.classifications.size(); num++) {
        classifications.add(new Classification(json.classifications[num].key, json.classifications[num].value))
    }
    return classifications
}
  • This is what the getClasificationsFromFile method returns:
[net.masterthought.jenkins.CucumberReportPublisher$Classification@51a05f13, net.masterthought.jenkins.CucumberReportPublisher$Classification@65036f5f]
  • When the test job runs, I get a net.masterthought.jenkins.CucumberReportPublisher$Classification NotSerializableException error when the reports are being generated.
java.io.NotSerializableException: net.masterthought.jenkins.CucumberReportPublisher$Classification
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:569)
	at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
	at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
	at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
	at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
	at java.util.HashMap.internalWriteEntries(HashMap.java:1785)
	at java.util.HashMap.writeObject(HashMap.java:1362)
	at sun.reflect.GeneratedMethodAccessor87.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:967)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
	at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
	at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
	at org.jboss.marshalling.MarshallerObjectOutputStream.writeObjectOverride(MarshallerObjectOutputStream.java:50)
	at org.jboss.marshalling.river.RiverObjectOutputStream.writeObjectOverride(RiverObjectOutputStream.java:179)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:344)
	at java.util.TreeMap.writeObject(TreeMap.java:2438)
	at sun.reflect.GeneratedMethodAccessor305.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.jboss.marshalling.reflect.SerializableClass.callWriteObject(SerializableClass.java:271)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:976)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteFields(RiverMarshaller.java:1032)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteSerializableObject(RiverMarshaller.java:988)
	at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:854)
	at org.jboss.marshalling.AbstractObjectOutput.writeObject(AbstractObjectOutput.java:58)
	at org.jboss.marshalling.AbstractMarshaller.writeObject(AbstractMarshaller.java:111)
	at org.jenkinsci.plugins.workflow.support.pickles.serialization.RiverWriter.writeObject(RiverWriter.java:132)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgram(CpsThreadGroup.java:452)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgram(CpsThreadGroup.java:427)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.saveProgramIfPossible(CpsThreadGroup.java:415)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:360)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$100(CpsThreadGroup.java:80)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:240)
	at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:228)
	at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:63)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:112)
	at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: an exception which occurred:
	in field locals
	in field caller
	in field e
	in field program
	in field threads
	in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@5f25597

@damianszczepanik
Copy link
Member

I haven't got problem with serialization. mvn package generates hpi file which you can install via Jenkins update secion (last tab, upload file namually)

@anandbagmar
Copy link
Contributor

Hi, I have just submitted a PR for this issue (#137). Kindly review the same.

Here is what my Jenkins file looks like (to dynamically add classifications to the report via the cucumber-reports-plugin:

            stage("Publish Reports") {
                echo "***** Publish Reports *****"
                 def runClassifications = getClassificationsFromFile()
                 println "runClassifications - " + runClassifications

                step([
                    $class: 'CucumberReportPublisher',
                    failedFeaturesNumber: 0,
                    failedScenariosNumber: 0,
                    failedStepsNumber: 0,
                    fileExcludePattern: '',
                    fileIncludePattern: '**/*.json',
                    jsonReportDirectory: 'testrun/reports',
                    parallelTesting: true,
                    pendingStepsNumber: 0,
                    skippedStepsNumber: 0,
                    trendsLimit: 0,
                    undefinedStepsNumber: 0,
                    classifications: runClassifications
                ])
            }

The implementation for method getClassificationsFromFile is as shown below:

import net.masterthought.jenkins.CucumberReportPublisher.Classification
def List<Classification> getClassificationsFromFile() {
    String fileName = "${WORKSPACE}/testRun/reports/myDevices.txt"
    println "*********** Loading file - $fileName **************"
    def catCmd = sh(script: 'cat ${WORKSPACE}/testRun/reports/myDevices.txt', returnStdout: true)
    println "myDevices.txt contents: \n$catCmd"

    def slurper = new groovy.json.JsonSlurper()
    def json = slurper.parseText( catCmd )
    ArrayList<Classification> classifications = Collections.emptyList()
    for (int num=0; num < json.classifications.size(); num++) {
        classifications.add(new Classification(json.classifications[num].key, json.classifications[num].value))
    }
    return classifications
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants