This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 08e800f359 Report the execution start and end date of a workflow,
fixes #4052 (#7545)
08e800f359 is described below
commit 08e800f359aecf7342a3cb76dbcfde7bb82087c9
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Jul 16 22:12:20 2026 +0200
Report the execution start and end date of a workflow, fixes #4052 (#7545)
---
.../apache/hop/www/GetWorkflowStatusServlet.java | 2 +
.../hop/www/GetWorkflowStatusServletTest.java | 82 ++++++++++++++++++++++
2 files changed, 84 insertions(+)
diff --git
a/engine/src/main/java/org/apache/hop/www/GetWorkflowStatusServlet.java
b/engine/src/main/java/org/apache/hop/www/GetWorkflowStatusServlet.java
index dcc26956c2..283c09aad7 100644
--- a/engine/src/main/java/org/apache/hop/www/GetWorkflowStatusServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/GetWorkflowStatusServlet.java
@@ -130,6 +130,8 @@ public class GetWorkflowStatusServlet extends
BaseHttpServlet implements IHopSer
workflowStatus.setFirstLoggingLineNr(startLineNr);
workflowStatus.setLastLoggingLineNr(lastLineNr);
workflowStatus.setLogDate(workflow.getExecutionStartDate());
+
workflowStatus.setExecutionStartDate(workflow.getExecutionStartDate());
+ workflowStatus.setExecutionEndDate(workflow.getExecutionEndDate());
// Add status of executed actions
for (ActionResult actionResult : workflow.getActionResults()) {
diff --git
a/engine/src/test/java/org/apache/hop/www/GetWorkflowStatusServletTest.java
b/engine/src/test/java/org/apache/hop/www/GetWorkflowStatusServletTest.java
index 4961c2f44a..f70b528fa2 100644
--- a/engine/src/test/java/org/apache/hop/www/GetWorkflowStatusServletTest.java
+++ b/engine/src/test/java/org/apache/hop/www/GetWorkflowStatusServletTest.java
@@ -18,8 +18,10 @@
package org.apache.hop.www;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -32,14 +34,18 @@ import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
import org.apache.hop.core.gui.Point;
import org.apache.hop.core.logging.HopLogStore;
import org.apache.hop.core.logging.ILogChannel;
+import org.apache.hop.core.xml.XmlHandler;
import org.apache.hop.workflow.Workflow;
import org.apache.hop.workflow.WorkflowMeta;
import org.apache.hop.workflow.engine.IWorkflowEngine;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.owasp.encoder.Encode;
@@ -100,6 +106,82 @@ class GetWorkflowStatusServletTest {
assertFalse(out.toString().contains(ServletTestUtils.BAD_STRING_TO_TEST));
}
+ /**
+ * The workflow status has to report when the workflow started and ended,
the way the pipeline
+ * status does. See issue #4052.
+ */
+ @Test
+ void statusReportsExecutionStartAndEndDate() throws ServletException,
IOException {
+ Date startDate = new Date(1700000000000L);
+ Date endDate = new Date(1700000012345L);
+
+ String xml = getStatusOutput(startDate, endDate, "Y", null);
+
+ assertTrue(
+ xml.contains("<execution_start_date>" +
XmlHandler.date2string(startDate)),
+ "The status should report the start date, was: " + xml);
+ assertTrue(
+ xml.contains("<execution_end_date>" + XmlHandler.date2string(endDate)),
+ "The status should report the end date, was: " + xml);
+ }
+
+ /** The same dates are reported in JSON, which is what the REST API of the
server serves. */
+ @Test
+ void jsonStatusReportsExecutionStartAndEndDate() throws ServletException,
IOException {
+ Date startDate = new Date(1700000000000L);
+ Date endDate = new Date(1700000012345L);
+
+ String json = getStatusOutput(startDate, endDate, null, "Y");
+
+ assertTrue(json.contains("\"executionStartDate\""), "The JSON should hold
the start date");
+ assertTrue(json.contains("\"executionEndDate\""), "The JSON should hold
the end date");
+ assertFalse(
+ json.contains("\"executionStartDate\" : null"),
+ "The start date should not be null: " + json);
+ assertFalse(
+ json.contains("\"executionEndDate\" : null"), "The end date should not
be null: " + json);
+ }
+
+ /** Runs the servlet for a finished workflow and returns what it wrote to
the response. */
+ private String getStatusOutput(Date startDate, Date endDate, String useXml,
String useJson)
+ throws ServletException, IOException {
+ HopLogStore.init();
+ HttpServletRequest mockHttpServletRequest = mock(HttpServletRequest.class);
+ HttpServletResponse mockHttpServletResponse =
mock(HttpServletResponse.class);
+ IWorkflowEngine<WorkflowMeta> mockWorkflow = Mockito.mock(Workflow.class);
+ WorkflowMeta mockWorkflowMeta = mock(WorkflowMeta.class);
+ ILogChannel mockLogChannelInterface = mock(ILogChannel.class);
+ ServletOutputStream outMock = mock(ServletOutputStream.class);
+
+ String id = "123";
+
+
when(mockHttpServletRequest.getContextPath()).thenReturn(GetWorkflowStatusServlet.CONTEXT_PATH);
+ when(mockHttpServletRequest.getParameter("id")).thenReturn(id);
+ when(mockHttpServletRequest.getParameter("xml")).thenReturn(useXml);
+ when(mockHttpServletRequest.getParameter("json")).thenReturn(useJson);
+ when(mockHttpServletResponse.getOutputStream()).thenReturn(outMock);
+ when(mockWorkflowMap.findWorkflow(id)).thenReturn(mockWorkflow);
+ Mockito.when(mockWorkflow.getWorkflowName()).thenReturn("a-workflow");
+
Mockito.when(mockWorkflow.getLogChannel()).thenReturn(mockLogChannelInterface);
+ Mockito.when(mockWorkflow.getWorkflowMeta()).thenReturn(mockWorkflowMeta);
+ Mockito.when(mockWorkflow.isFinished()).thenReturn(true);
+ Mockito.when(mockWorkflow.getLogChannelId()).thenReturn("logId");
+ Mockito.when(mockWorkflow.getExecutionStartDate()).thenReturn(startDate);
+ Mockito.when(mockWorkflow.getExecutionEndDate()).thenReturn(endDate);
+ Mockito.when(mockWorkflowMeta.getMaximum()).thenReturn(new Point(10, 10));
+ when(mockWorkflow.getStatusDescription()).thenReturn("Finished");
+
+ getWorkflowStatusServlet.doGet(mockHttpServletRequest,
mockHttpServletResponse);
+
+ ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class);
+ verify(outMock, atLeastOnce()).write(captor.capture());
+ StringBuilder written = new StringBuilder();
+ for (byte[] data : captor.getAllValues()) {
+ written.append(new String(data, StandardCharsets.UTF_8));
+ }
+ return written.toString();
+ }
+
@Test
void testGetJobStatus() throws ServletException, IOException {
HopLogStore.init();