Example – Submitting a build and automated test results using the REST API

The following example can help you understand what is required to submit a build and automated test results using the Perforce ALM REST API, and how the submitted data is displayed in the ALM web client.

Step 1: Add an automation suite

An automation suite named Alpha Tests is added using the web client.

The suite is configured to automatically associate test results with test cases by script ID. The Test Cases area shows the automated test script IDs for the two test cases related to the tests that will run for this suite. During the test, these IDs are written out to the name attribute in the <testcase> element in the JUnit report files, as you can see in report file examples.

Step 2: Generate JUnit XML results report files

For this example, three JUnit XML results report files are generated after a build.

Step 3: Submit the build to ALM using the REST API

The following example is the REST API JSON translated from the JUnit report files. The JSON is submitted to ALM via the REST API using the POST /{projectID}/automationSuites/{automationSuiteID}/submitBuild endpoint.

Copy
{
  "number": "1234",
  "startDate": "2022-09-14T12:56:44",
  "duration": 1019,
  "results": [
    {
      "name": "appProvidesHelp()",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.AppTest:com.perforce.halm.reportingtool.AppTest:appProvidesHelp()",
      "status": {
        "id": 1
      },
      "duration": 146
    },
    {
      "name": "appProvidesVersion()",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.AppTest:com.perforce.halm.reportingtool.AppTest:appProvidesVersion()",
      "status": {
        "id": 1
      },
      "duration": 4
    },
    {
      "name": "appHandlesException() ALPHA-6",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.AppTest:com.perforce.halm.reportingtool.AppTest:appHandlesException()",
      "status": {
        "id": 1
      },
      "duration": 28
    },
    {
      "name": "processSuiteNoTests()",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:processSuiteNoTests()",
      "status": {
        "id": 1
      },
      "duration": 2
    },
    {
      "name": "processSuiteNoMetadata()",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:processSuiteNoMetadata()",
      "status": {
        "id": 1
      },
      "duration": 1
    },
    {
      "name": "processSuiteWithMetadata()",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:processSuiteWithMetadata()",
      "status": {
        "id": 1
      },
      "duration": 4
    },
    {
      "name": "processWrapperTwoSuitesNoTests()",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:processWrapperTwoSuitesNoTests()",
      "status": {
        "id": 1
      },
      "duration": 2
    },
    {
      "name": "processSuiteAndWrapperNoTests()",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:processSuiteAndWrapperNoTests()",
      "status": {
        "id": 1
      },
      "duration": 3
    },
    {
      "name": "processInvalidFile() ALPHA-30",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:com.perforce.halm.reportingtool.format.junit.JUnitMetaBuildTest:processInvalidFile()",
      "status": {
        "id": 1
      },
      "duration": 6
    },
    {
      "name": "processCaseInvalid()",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.format.junit.JUnitMetaResultTest:com.perforce.halm.reportingtool.format.junit.JUnitMetaResultTest:processCaseInvalid()",
      "status": {
        "id": 3
      },
      "duration": 0
    },
    {
      "name": "processCaseWithMetadata() ALPHA-30",
      "uniqueName": "CAFFEINE2:com.perforce.halm.reportingtool.format.junit.JUnitMetaResultTest:com.perforce.halm.reportingtool.format.junit.JUnitMetaResultTest:processCaseWithMetadata()",
      "status": {
        "id": 2
      },
      "duration": 157,
      "errorMessage": "org.opentest4j.AssertionFailedError: Operating system was not the expected value. ==> expected: <Linux> but was: <Windows>",
      "properties": [
        {
          "name": "failureType",
          "value": "org.opentest4j.AssertionFailedError"
        },
        {
          "name": "failureValue",
          "value": "org.opentest4j.AssertionFailedError: Operating system was not the expected value. ==> expected: <Linux> but was: <Windows>\n\tat app//org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)\n\tat app//org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)\n\tat app//org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)\n\tat app//org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1135)\n\tat app//com.perforce.halm.reportingtool.format.junit.JUnitMetaResultTest.processCaseWithMetadata(JUnitMetaResultTest.java:86)\n\tat java.base@11.0.16/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat java.base@11.0.16/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat java.base@11.0.16/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.base@11.0.16/java.lang.reflect.Method.invoke(Method.java:566)\n\tat app//org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688)\n\tat app//org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)\n\tat app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)\n\tat app//org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)\n\tat app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)\n\tat app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)\n\tat app//org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)\n\tat app//org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)\n\tat app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)\n\tat app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)\n\tat app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)\n\tat app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)\n\tat app//org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)\n\tat app//org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)\n\tat app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)\n\tat app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\n\tat app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)\n\tat app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)\n\tat app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)\n\tat app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)\n\tat app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)\n\tat app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)\n\tat java.base@11.0.16/java.util.ArrayList.forEach(ArrayList.java:1541)\n\tat app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)\n\tat app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)\n\tat app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)\n\tat app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)\n\tat java.base@11.0.16/java.util.ArrayList.forEach(ArrayList.java:1541)\n\tat app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)\n\tat app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)\n\tat app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)\n\tat app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)\n\tat app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)\n\tat app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)\n\tat app//org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)\n\tat app//org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)\n\tat org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)\n\tat org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)\n\tat org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)\n\tat org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)\n\tat org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)\n\tat org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)\n\tat org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)\n\tat org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)\n\tat org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)\n\tat org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)\n\tat org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)\n\tat java.base@11.0.16/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat java.base@11.0.16/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat java.base@11.0.16/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.base@11.0.16/java.lang.reflect.Method.invoke(Method.java:566)\n\tat org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)\n\tat org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)\n\tat org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)\n\tat org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)\n\tat com.sun.proxy.$Proxy2.stop(Unknown Source)\n\tat org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)\n\tat org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)\n\tat org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)\n\tat org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)\n\tat org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)\n\tat org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)\n\tat org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)\n\tat app//worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)\n\tat app//worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)\n"
        }
      ]
    }
  ]
}

Step 4: View the results in the web client

The following screenshots show the data in the web client after it is submitted via the REST API.

Automated test results status

When viewing the results in the automation suite, the Automated Test Result Status tab shows the 11 total tests from the submitted build. The passed and failed test results are indicated. Test results are correctly associated with the two test cases in the automation suite. The other eight test results in the build are not associated with test cases.

All results in the build

When viewing the results in the build, the All Results tab shows all tests that were included in the submitted build. The test result status, associated test cases, and duration are displayed.