Skip to content

Commit

Permalink
Add successful and skipped tests to payload. (#3)
Browse files Browse the repository at this point in the history
* Add successful and skipped tests to payload.

This commit adds a BuildCompleteListener that listens on the PostBuildCompletedEvent. The testcases provided in the BuildContext get saved into a Map and can be accessed from the ChainCompletedNotification.
See the comment above the Map cachedTestResults in the class ServerNotificationRecipient for more information.

Updated Bamboo-api-version.

Updated sample payload shown on README.

* Use ConcurrentHashMap.

Multiple build could finish at the same time, therefor we have to make sure it won't cause any unwanted behaviour.

* Ensure backwards-compatibility.
  • Loading branch information
sleiss authored and Stephan Krusche committed May 5, 2019
1 parent e88a072 commit 9504505
Show file tree
Hide file tree
Showing 7 changed files with 288 additions and 96 deletions.
200 changes: 132 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,73 +44,137 @@ Sample request
--------------
```json
{
"build":{
"artifact":false,
"number":35,
"reason":"Code has changed",
"buildCompletedDate":"2018-12-01T12:36:26.078Z[Zulu]",
"testSummary":{
"duration":26,
"ignoredCount":0,
"failedCount":2,
"existingFailedCount":1,
"quarantineCount":0,
"successfulCount":11,
"description":"2 of 13 failed",
"skippedCount":0,
"fixedCount":0,
"totalCount":13,
"newFailedCount":1
},
"vcs":[
{
"commits":[
{
"comment":"Break stuff.",
"id":"13c43a1e26e5c4635a0ac24e775fed615e069b20"
}
],
"id":"13c43a1e26e5c4635a0ac24e775fed615e069b20",
"repositoryName":"Assignment"
},
{
"commits":[

],
"id":"dcf2dba3846620a89f6c3f63cd9dedfa4336f650",
"repositoryName":"tests"
}
],
"failedJobs":[
{
"failedTests":[
{
"name":"testBubbleSort",
"methodName":"Bubble sort",
"className":"ac1.de.BehaviorTest",
"errors":[
"java.lang.AssertionError: Problem: BubbleSort does not sort correctly expected:<[Mon Feb 15 00:00:00 GMT 2016, Sat Apr 15 00:00:00 GMT 2017, Fri Sep 15 00:00:00 GMT 2017, Thu Nov 08 00:00:00 GMT 2018]> but was:<[Mon Feb 15 00:00:00 GMT 2016, Sat Apr 15 00:00:00 GMT 2017, Thu Nov 08 00:00:00 GMT 2018, Fri Sep 15 00:00:00 GMT 2017]>\n\tat org.junit.Assert.fail(Assert.java:88)\n\tat org.junit.Assert.failNotEquals(Assert.java:834)\n\tat org.junit.Assert.assertEquals(Assert.java:118)\n\tat ac1.de.BehaviorTest.testBubbleSort(BehaviorTest.java:40)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)\n\tat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\n\tat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)\n\tat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\n\tat org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)\n\tat org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)\n\tat java.util.concurrent.FutureTask.run(FutureTask.java:266)\n\tat java.lang.Thread.run(Thread.java:748)\n"
]
},
{
"name":"testMergeSort",
"methodName":"Merge sort",
"className":"ac1.de.BehaviorTest",
"errors":[
"java.lang.NullPointerException\n\tat java.util.Date.getMillisOf(Date.java:958)\n\tat java.util.Date.compareTo(Date.java:978)\n\tat ac1.de.MergeSort.merge(MergeSort.java:30)\n\tat ac1.de.MergeSort.mergesort(MergeSort.java:19)\n\tat ac1.de.MergeSort.performSort(MergeSort.java:10)\n\tat ac1.de.BehaviorTest.testMergeSort(BehaviorTest.java:46)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)\n\tat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\n\tat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)\n\tat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\n\tat org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)\n\tat org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)\n\tat java.util.concurrent.FutureTask.run(FutureTask.java:266)\n\tat java.lang.Thread.run(Thread.java:748)\n"
]
}
],
"id":11403400
}
],
"successful":false
},
"secret":"SomeVerySecretToken",
"notificationType":"Completed Plan Notification",
"plan":{
"key":"SC1AC4ASD-BASE"
}
}
"build":{
"artifact":false,
"number":86,
"reason":"Manual build",
"buildCompletedDate":"2019-05-05T09:51:30.960Z[Zulu]",
"testSummary":{
"duration":62,
"ignoredCount":0,
"failedCount":1,
"existingFailedCount":1,
"quarantineCount":0,
"successfulCount":14,
"description":"1 of 15 failed",
"skippedCount":0,
"fixedCount":0,
"totalCount":15,
"newFailedCount":0
},
"vcs":[
{
"commits":[

],
"id":"f4158f583a02dc3b9bda47e64749fdbf7e9bdcef",
"repositoryName":"Assignment"
},
{
"commits":[

],
"id":"9be1bb278e08d03ab2519b746702196cead996be",
"repositoryName":"tests"
}
],
"jobs":[
{
"skippedTests":[

],
"failedTests":[
{
"name":"testBubbleSort",
"methodName":"Bubble sort",
"className":"de.de.SortingExampleBehaviorTest",
"errors":[
"java.lang.AssertionError: Problem: BubbleSort does not sort correctly expected:<[Mon Feb 15 00:00:00 GMT 2016, Sat Apr 15 00:00:00 GMT 2017, Fri Sep 15 00:00:00 GMT 2017, Thu Nov 08 00:00:00 GMT 2018]> but was:<[Thu Nov 08 00:00:00 GMT 2018, Sat Apr 15 00:00:00 GMT 2017, Mon Feb 15 00:00:00 GMT 2016, Fri Sep 15 00:00:00 GMT 2017]>\n\tat org.junit.Assert.fail(Assert.java:88)\n\tat org.junit.Assert.failNotEquals(Assert.java:834)\n\tat org.junit.Assert.assertEquals(Assert.java:118)\n\tat de.de.SortingExampleBehaviorTest.testBubbleSort(SortingExampleBehaviorTest.java:37)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)\n\tat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\n\tat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)\n\tat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\n\tat org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:298)\n\tat org.junit.internal.runners.statements.FailOnTimeout$CallableStatement.call(FailOnTimeout.java:292)\n\tat java.util.concurrent.FutureTask.run(FutureTask.java:266)\n\tat java.lang.Thread.run(Thread.java:748)\n"
]
}
],
"successfulTests":[
{
"name":"testUseBubbleSortForSmallList",
"methodName":"Use bubble sort for small list",
"className":"de.de.SortingExampleBehaviorTest"
},
{
"name":"testConstructors[Policy]",
"methodName":"Constructors[policy]",
"className":"de.de.ConstructorTest"
},
{
"name":"testClass[Policy]",
"methodName":"Class[policy]",
"className":"de.de.ClassTest"
},
{
"name":"testClass[Context]",
"methodName":"Class[context]",
"className":"de.de.ClassTest"
},
{
"name":"testMethods[SortStrategy]",
"methodName":"Methods[sort strategy]",
"className":"de.de.MethodTest"
},
{
"name":"testMethods[Policy]",
"methodName":"Methods[policy]",
"className":"de.de.MethodTest"
},
{
"name":"testClass[BubbleSort]",
"methodName":"Class[bubble sort]",
"className":"de.de.ClassTest"
},
{
"name":"testMergeSort",
"methodName":"Merge sort",
"className":"de.de.SortingExampleBehaviorTest"
},
{
"name":"testAttributes[Context]",
"methodName":"Attributes[context]",
"className":"de.de.AttributeTest"
},
{
"name":"testUseMergeSortForBigList",
"methodName":"Use merge sort for big list",
"className":"de.de.SortingExampleBehaviorTest"
},
{
"name":"testAttributes[Policy]",
"methodName":"Attributes[policy]",
"className":"de.de.AttributeTest"
},
{
"name":"testMethods[Context]",
"methodName":"Methods[context]",
"className":"de.de.MethodTest"
},
{
"name":"testClass[SortStrategy]",
"methodName":"Class[sort strategy]",
"className":"de.de.ClassTest"
},
{
"name":"testClass[MergeSort]",
"methodName":"Class[merge sort]",
"className":"de.de.ClassTest"
}
],
"id":14581874
}
],
"successful":false
},
"secret":"SomeVerySecretToken",
"notificationType":"Completed Plan Notification",
"plan":{
"key":"CO1BRD3-SOLUTION"
}
}

```
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<description>Notify a Server when a build was executed.</description>
<packaging>atlassian-plugin</packaging>
<properties>
<bamboo.version>5.9.10</bamboo.version>
<bamboo.version>6.8.1</bamboo.version>
<bamboo.data.version>${bamboo.version}</bamboo.data.version>
<amps.version>6.3.21</amps.version>
<plugin.testrunner.version>1.2.3</plugin.testrunner.version>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package de.tum.in.www1.bamboo.server;

import com.atlassian.bamboo.v2.build.CurrentBuildResult;
import com.atlassian.bamboo.v2.build.events.PostBuildCompletedEvent;
import com.atlassian.event.api.EventListener;

public class BuildCompleteListener {

@EventListener
public void onPostBuildComplete(final PostBuildCompletedEvent postBuildCompletedEvent) {
CurrentBuildResult currentBuildResult = postBuildCompletedEvent.getContext().getBuildResult();

TestResultsContainer testResultsContainer = new TestResultsContainer(postBuildCompletedEvent.getPlanResultKey(), currentBuildResult.getSuccessfulTestResults(), currentBuildResult.getSkippedTestResults(), currentBuildResult.getFailedTestResults());
ServerNotificationRecipient.getCachedTestResults().put(postBuildCompletedEvent.getPlanResultKey().toString(), testResultsContainer);

// Remove old TestResultsContainer based on their initialization timestamp
ServerNotificationRecipient.clearOldTestResultsContainer();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ServerNotificationRecipient extends AbstractNotificationRecipient implements DeploymentResultAwareNotificationRecipient,
NotificationRecipient.RequiresPlan,
Expand All @@ -36,6 +37,21 @@ public class ServerNotificationRecipient extends AbstractNotificationRecipient i
private DeploymentResult deploymentResult;
private CustomVariableContext customVariableContext;

// Time in seconds before removing TestResultsContainer
private static final int TESTRESULTSCONTAINER_REMOVE_TIME = 60;

/*
* The TestResults of successful tests can not be loaded from the ChainResultSummary (only failing ones can).
* The TestResults need a BuildContext and can therefor only be accessed when using an Event that extends BuildContextEvent.
* The normal BuildCompletedEvent does not extend BuildContextEvent, but the PostBuildCompletedEvent does.
* We listen for the PostBuildCompletedEvent and save the test cases in this Map with the key of the job as String.
* The TestResults are stored inside the TestResultsContainer class and it can be retrieved using this Map in the ServerNotificationTransport class.
* A method clearOldTestResultsContainer() has been added, that removes old TestResultsContainer from the Map, because we add every build to this Map, even those without
* Notifications enabled.
* The time (in seconds) after the TestResultsContainer can be specified in the variable TESTRESULTSCONTAINER_REMOVE_TIME.
*/
private static Map<String, TestResultsContainer> cachedTestResults = new ConcurrentHashMap<>();

@Override
public void populate(@NotNull Map<String, String[]> params)
{
Expand Down Expand Up @@ -140,6 +156,14 @@ public void setResultsSummary(@Nullable final ResultsSummary resultsSummary)
this.resultsSummary = resultsSummary;
}

public static Map<String, TestResultsContainer> getCachedTestResults() {
return cachedTestResults;
}

public static void clearOldTestResultsContainer() {
getCachedTestResults().entrySet().removeIf(entry -> entry.getValue().getInitTimestamp() < (System.currentTimeMillis() - (1000 * TESTRESULTSCONTAINER_REMOVE_TIME)));
}

//-----------------------------------Dependencies
public void setTemplateRenderer(TemplateRenderer templateRenderer)
{
Expand Down
Loading

0 comments on commit 9504505

Please sign in to comment.