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 d4cea5c834 issue #2267 : show failed and stalled icons in execution
information (#7951)
d4cea5c834 is described below
commit d4cea5c8346c075fa189c7fb7363b023a4c2dd19
Author: Matt Casters <[email protected]>
AuthorDate: Sat Aug 15 10:19:27 2026 +0200
issue #2267 : show failed and stalled icons in execution information (#7951)
Add pipeline/workflow error and stalled SVG icons and use them in the
execution information tree and viewer tabs. Keep the existing row
background colors as a secondary cue.
---
.../hop-gui/perspective-execution-information.adoc | 16 +++++
.../org/apache/hop/ui/core/gui/GuiResource.java | 36 ++++++++++
.../execution/ExecutionPerspective.java | 31 ++++++--
.../perspective/execution/ExecutionStatusIcon.java | 68 ++++++++++++++++++
.../execution/PipelineExecutionViewer.java | 3 +-
.../execution/WorkflowExecutionViewer.java | 3 +-
.../hop/ui/hopgui/shared/BaseExecutionViewer.java | 15 ++++
ui/src/main/resources/ui/images/pipeline-error.svg | 9 +++
.../main/resources/ui/images/pipeline-stalled.svg | 9 +++
ui/src/main/resources/ui/images/workflow-error.svg | 8 +++
.../main/resources/ui/images/workflow-stalled.svg | 8 +++
.../execution/ExecutionStatusIconTest.java | 82 ++++++++++++++++++++++
12 files changed, 279 insertions(+), 9 deletions(-)
diff --git
a/docs/hop-user-manual/modules/ROOT/pages/hop-gui/perspective-execution-information.adoc
b/docs/hop-user-manual/modules/ROOT/pages/hop-gui/perspective-execution-information.adoc
index 89f70207ab..c875a808b6 100644
---
a/docs/hop-user-manual/modules/ROOT/pages/hop-gui/perspective-execution-information.adoc
+++
b/docs/hop-user-manual/modules/ROOT/pages/hop-gui/perspective-execution-information.adoc
@@ -56,6 +56,22 @@ For example:
image::execution-information-perspective-left-panel-example.png[An example
left panel]
+The pipeline and workflow icons also show execution status:
+
+|===
+|Icon |Meaning
+
+|Default pipeline or workflow icon
+|Finished successfully, or still running. Running rows also use a light-blue
background.
+
+|Pipeline or workflow icon with a red exclamation mark
+|The execution failed. Failed rows also use a light-red background.
+
+|Pipeline or workflow icon with an orange question mark
+|The execution is stalled: no state update was received within the location
logging interval. Stalled rows also use a light-gray background.
+
+|===
+
Possible action:
|===
diff --git a/ui/src/main/java/org/apache/hop/ui/core/gui/GuiResource.java
b/ui/src/main/java/org/apache/hop/ui/core/gui/GuiResource.java
index ab6bda3f1c..9a9960c5a6 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/gui/GuiResource.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/gui/GuiResource.java
@@ -149,9 +149,13 @@ public class GuiResource {
private SwtUniversalImage imageHash;
private SwtUniversalImage imagePipeline;
private SwtUniversalImage imagePipelineDisabled;
+ private SwtUniversalImage imagePipelineError;
+ private SwtUniversalImage imagePipelineStalled;
private SwtUniversalImage imagePartitionSchema;
private SwtUniversalImage imageWorkflow;
private SwtUniversalImage imageWorkflowDisabled;
+ private SwtUniversalImage imageWorkflowError;
+ private SwtUniversalImage imageWorkflowStalled;
private SwtUniversalImage imageArrowDefault;
private SwtUniversalImage imageArrowTrue;
private SwtUniversalImage imageArrowFalse;
@@ -459,9 +463,13 @@ public class GuiResource {
imageHash.dispose();
imagePipeline.dispose();
imagePipelineDisabled.dispose();
+ imagePipelineError.dispose();
+ imagePipelineStalled.dispose();
imagePartitionSchema.dispose();
imageWorkflow.dispose();
imageWorkflowDisabled.dispose();
+ imageWorkflowError.dispose();
+ imageWorkflowStalled.dispose();
imageCopyRows.dispose();
imageCopyRowsDisabled.dispose();
imageError.dispose();
@@ -843,9 +851,17 @@ public class GuiResource {
imagePipeline = SwtSvgImageUtil.getImageAsResource(display,
"ui/images/pipeline.svg");
imagePipelineDisabled =
SwtSvgImageUtil.getImageAsResource(display,
"ui/images/pipeline-disabled.svg");
+ imagePipelineError =
+ SwtSvgImageUtil.getImageAsResource(display,
"ui/images/pipeline-error.svg");
+ imagePipelineStalled =
+ SwtSvgImageUtil.getImageAsResource(display,
"ui/images/pipeline-stalled.svg");
imageWorkflow = SwtSvgImageUtil.getImageAsResource(display,
"ui/images/workflow.svg");
imageWorkflowDisabled =
SwtSvgImageUtil.getImageAsResource(display,
"ui/images/workflow-disabled.svg");
+ imageWorkflowError =
+ SwtSvgImageUtil.getImageAsResource(display,
"ui/images/workflow-error.svg");
+ imageWorkflowStalled =
+ SwtSvgImageUtil.getImageAsResource(display,
"ui/images/workflow-stalled.svg");
imageServer = SwtSvgImageUtil.getImageAsResource(display,
"ui/images/server.svg");
imagePreview = SwtSvgImageUtil.getImageAsResource(display,
"ui/images/preview.svg");
imageTrue = SwtSvgImageUtil.getImageAsResource(display,
"ui/images/true.svg");
@@ -1250,6 +1266,16 @@ public class GuiResource {
imagePipelineDisabled, display, ConstUi.SMALL_ICON_SIZE,
ConstUi.SMALL_ICON_SIZE);
}
+ public Image getImagePipelineError() {
+ return getZoomedImaged(
+ imagePipelineError, display, ConstUi.SMALL_ICON_SIZE,
ConstUi.SMALL_ICON_SIZE);
+ }
+
+ public Image getImagePipelineStalled() {
+ return getZoomedImaged(
+ imagePipelineStalled, display, ConstUi.SMALL_ICON_SIZE,
ConstUi.SMALL_ICON_SIZE);
+ }
+
@Deprecated
public Image getImageClosePanel() {
return imageClose;
@@ -1276,6 +1302,16 @@ public class GuiResource {
imageWorkflowDisabled, display, ConstUi.SMALL_ICON_SIZE,
ConstUi.SMALL_ICON_SIZE);
}
+ public Image getImageWorkflowError() {
+ return getZoomedImaged(
+ imageWorkflowError, display, ConstUi.SMALL_ICON_SIZE,
ConstUi.SMALL_ICON_SIZE);
+ }
+
+ public Image getImageWorkflowStalled() {
+ return getZoomedImaged(
+ imageWorkflowStalled, display, ConstUi.SMALL_ICON_SIZE,
ConstUi.SMALL_ICON_SIZE);
+ }
+
/**
* @return the imageArrow
*/
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionPerspective.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionPerspective.java
index c3ff71765c..2be21509b4 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionPerspective.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionPerspective.java
@@ -1139,14 +1139,12 @@ public class ExecutionPerspective implements
IHopPerspective, TabClosable {
Execution execution,
ExecutionState state) {
try {
- executionItem.setImage(GuiResource.getInstance().getImagePipeline());
-
String label = execution.getName();
label += " - " +
START_DATE_FORMAT.format(execution.getExecutionStartDate());
executionItem.setText(label);
executionItem.setData(execution);
- decorateItemWithState(executionItem, location, state);
+ decorateItemWithState(executionItem, location, execution, state);
} catch (Exception e) {
new ErrorDialog(
getShell(), CONST_ERROR1, "Error drawing pipeline execution
information tree item", e);
@@ -1159,8 +1157,6 @@ public class ExecutionPerspective implements
IHopPerspective, TabClosable {
Execution execution,
ExecutionState state) {
try {
- executionItem.setImage(GuiResource.getInstance().getImageWorkflow());
-
String label = execution.getName();
label +=
" - "
@@ -1168,7 +1164,7 @@ public class ExecutionPerspective implements
IHopPerspective, TabClosable {
executionItem.setText(label);
executionItem.setData(execution);
- decorateItemWithState(executionItem, location, state);
+ decorateItemWithState(executionItem, location, execution, state);
} catch (Exception e) {
new ErrorDialog(
getShell(), CONST_ERROR1, "Error drawing workflow execution
information tree item", e);
@@ -1176,9 +1172,17 @@ public class ExecutionPerspective implements
IHopPerspective, TabClosable {
}
private static void decorateItemWithState(
- TreeItem executionItem, ExecutionInfoLocation location, ExecutionState
state) {
+ TreeItem executionItem,
+ ExecutionInfoLocation location,
+ Execution execution,
+ ExecutionState state) {
long loggingInterval = Const.toLong(location.getDataLoggingInterval(),
20000);
+ ExecutionStatusIcon statusIcon = ExecutionStatusIcon.from(state,
loggingInterval);
+ executionItem.setImage(statusIcon.toImage(execution.getExecutionType()));
+ if (state == null) {
+ return;
+ }
if (state.isFailed()) {
executionItem.setBackground(GuiResource.getInstance().getColorLightRed());
} else if (state.isStale(loggingInterval)) {
@@ -1188,6 +1192,19 @@ public class ExecutionPerspective implements
IHopPerspective, TabClosable {
}
}
+ /** Refresh the tab image after a viewer reloads execution state (failed /
stalled / default). */
+ public void updateViewerTabImage(IExecutionViewer viewer) {
+ if (tabFolder == null || tabFolder.isDisposed() || viewer == null) {
+ return;
+ }
+ for (CTabItem item : tabFolder.getItems()) {
+ if (viewer.equals(item.getData()) && !item.isDisposed()) {
+ item.setImage(viewer.getTitleImage());
+ return;
+ }
+ }
+ }
+
@Override
public boolean remove(IHopFileTypeHandler typeHandler) {
if (typeHandler instanceof MetadataEditor<?> editor) {
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionStatusIcon.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionStatusIcon.java
new file mode 100644
index 0000000000..b841e4035f
--- /dev/null
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionStatusIcon.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.perspective.execution;
+
+import org.apache.hop.execution.ExecutionState;
+import org.apache.hop.execution.ExecutionType;
+import org.apache.hop.ui.core.gui.GuiResource;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * Tree and tab icon for a pipeline or workflow execution. Failed wins over
stalled; everything else
+ * uses the default pipeline or workflow image.
+ */
+public enum ExecutionStatusIcon {
+ DEFAULT,
+ ERROR,
+ STALLED;
+
+ public static ExecutionStatusIcon from(ExecutionState state, long
loggingInterval) {
+ if (state == null) {
+ return DEFAULT;
+ }
+ if (state.isFailed()) {
+ return ERROR;
+ }
+ if (state.isStale(loggingInterval)) {
+ return STALLED;
+ }
+ return DEFAULT;
+ }
+
+ public Image toImage(ExecutionType type) {
+ boolean pipeline = type == ExecutionType.Pipeline;
+ return switch (this) {
+ case ERROR ->
+ pipeline
+ ? GuiResource.getInstance().getImagePipelineError()
+ : GuiResource.getInstance().getImageWorkflowError();
+ case STALLED ->
+ pipeline
+ ? GuiResource.getInstance().getImagePipelineStalled()
+ : GuiResource.getInstance().getImageWorkflowStalled();
+ case DEFAULT ->
+ pipeline
+ ? GuiResource.getInstance().getImagePipeline()
+ : GuiResource.getInstance().getImageWorkflow();
+ };
+ }
+
+ public static Image imageFor(ExecutionType type, ExecutionState state, long
loggingInterval) {
+ return from(state, loggingInterval).toImage(type);
+ }
+}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/PipelineExecutionViewer.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/PipelineExecutionViewer.java
index e50060547d..d5e915dd1d 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/PipelineExecutionViewer.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/PipelineExecutionViewer.java
@@ -680,7 +680,7 @@ public class PipelineExecutionViewer extends
BaseExecutionViewer
@Override
public Image getTitleImage() {
- return GuiResource.getInstance().getImagePipeline();
+ return ExecutionStatusIcon.imageFor(ExecutionType.Pipeline,
executionState, loggingInterval());
}
@Override
@@ -822,6 +822,7 @@ public class PipelineExecutionViewer extends
BaseExecutionViewer
refreshStatus();
refreshMetrics();
refreshTransformData();
+ perspective.updateViewerTabImage(this);
redraw();
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/WorkflowExecutionViewer.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/WorkflowExecutionViewer.java
index f65ef47aa1..5e2b41cb79 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/WorkflowExecutionViewer.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/execution/WorkflowExecutionViewer.java
@@ -528,7 +528,7 @@ public class WorkflowExecutionViewer extends
BaseExecutionViewer
@Override
public Image getTitleImage() {
- return GuiResource.getInstance().getImageWorkflow();
+ return ExecutionStatusIcon.imageFor(ExecutionType.Workflow,
executionState, loggingInterval());
}
@Override
@@ -712,6 +712,7 @@ public class WorkflowExecutionViewer extends
BaseExecutionViewer
public void refresh() {
refreshStatus();
refreshActionData();
+ perspective.updateViewerTabImage(this);
redraw();
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/shared/BaseExecutionViewer.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/shared/BaseExecutionViewer.java
index a8a726be21..7d6816afae 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/shared/BaseExecutionViewer.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/shared/BaseExecutionViewer.java
@@ -169,6 +169,21 @@ public abstract class BaseExecutionViewer extends
DragViewZoomBase
return Utils.getDurationHMS(durationMs / 1000.0);
}
+ /**
+ * Logging interval from the execution information location, used to decide
whether state is
+ * stalled. Defaults to 20s when the location is not loaded yet.
+ */
+ protected long loggingInterval() {
+ if (perspective == null || perspective.getLocationMap() == null) {
+ return 20000;
+ }
+ ExecutionInfoLocation location =
perspective.getLocationMap().get(locationName);
+ if (location == null) {
+ return 20000;
+ }
+ return Const.toLong(location.getDataLoggingInterval(), 20000);
+ }
+
public abstract void drillDownOnLocation(Point location);
@Override
diff --git a/ui/src/main/resources/ui/images/pipeline-error.svg
b/ui/src/main/resources/ui/images/pipeline-error.svg
new file mode 100644
index 0000000000..11fad44dbc
--- /dev/null
+++ b/ui/src/main/resources/ui/images/pipeline-error.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
+ <path d="M16.429 4a7.52 7.52 0 0 0-.682.028c-1.782.155-3.29.865-4.273
1.328-1.033.486-2.334 1.25-3.703 1.585s-2.682.284-3.976-.82a1.118 1.29 0 1
0-1.33 2.074c1.886 1.609 4.02 1.697 5.769 1.27s3.242-1.323 4.085-1.72c.969-.456
2.237-1.026 3.597-1.144s2.775.161 4.259 1.507a1.118 1.29 0 1 0
1.382-2.027C19.865 4.545 18.051 4.007 16.429 4zm0 5.159a7.52 7.52 0 0
0-.682.028c-1.782.155-3.29.865-4.273 1.328-1.033.486-2.334 1.25-3.703
1.585s-2.682.284-3.976-.82a1.118 1.29 0 1 0-1.33 2.074c1.886 [...]
+ fill="#53c3c4"/>
+ <circle cx="17.2" cy="17.2" r="6.8" fill="#ffffff"/>
+ <circle cx="17.2" cy="17.2" r="5.8" fill="#EA102A"/>
+ <rect x="16.2" y="13.2" width="2" height="5.2" rx="0.4" fill="#ffffff"/>
+ <circle cx="17.2" cy="20.2" r="1" fill="#ffffff"/>
+</svg>
diff --git a/ui/src/main/resources/ui/images/pipeline-stalled.svg
b/ui/src/main/resources/ui/images/pipeline-stalled.svg
new file mode 100644
index 0000000000..2d97dee418
--- /dev/null
+++ b/ui/src/main/resources/ui/images/pipeline-stalled.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
+ <path d="M16.429 4a7.52 7.52 0 0 0-.682.028c-1.782.155-3.29.865-4.273
1.328-1.033.486-2.334 1.25-3.703 1.585s-2.682.284-3.976-.82a1.118 1.29 0 1
0-1.33 2.074c1.886 1.609 4.02 1.697 5.769 1.27s3.242-1.323 4.085-1.72c.969-.456
2.237-1.026 3.597-1.144s2.775.161 4.259 1.507a1.118 1.29 0 1 0
1.382-2.027C19.865 4.545 18.051 4.007 16.429 4zm0 5.159a7.52 7.52 0 0
0-.682.028c-1.782.155-3.29.865-4.273 1.328-1.033.486-2.334 1.25-3.703
1.585s-2.682.284-3.976-.82a1.118 1.29 0 1 0-1.33 2.074c1.886 [...]
+ fill="#53c3c4"/>
+ <circle cx="17.2" cy="17.2" r="6.8" fill="#ffffff"/>
+ <circle cx="17.2" cy="17.2" r="5.8" fill="#FFA500"/>
+ <path fill="#ffffff" d="M15.35 15.05c0-1.15.95-2.05 2.05-2.05 1.15 0
2.05.85 2.05 1.95 0 .85-.45 1.35-1.2 1.85-.7.45-.95.8-.95
1.45v.25h-1.7v-.3c0-1.05.4-1.6 1.15-2.1.55-.4.85-.7.85-1.15
0-.5-.35-.85-.85-.85-.5 0-.85.3-.95.9h-1.45z"/>
+ <circle cx="17.2" cy="20.25" r="0.95" fill="#ffffff"/>
+</svg>
diff --git a/ui/src/main/resources/ui/images/workflow-error.svg
b/ui/src/main/resources/ui/images/workflow-error.svg
new file mode 100644
index 0000000000..2d93bc29d6
--- /dev/null
+++ b/ui/src/main/resources/ui/images/workflow-error.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
+ <path fill="#033d5d" d="M12.033 2c-.401 0-.802.153-1.109.461L7.726 5.659
8.86 6.792l2.73-2.73c.123-.123.283-.184.443-.184s.321.061.443.184l2.134
2.134-1.154 1.154H16.9V3.906l-1.157 1.157-2.602-2.602C12.835 2.154 12.434 2
12.033 2zM3.905 7.1l1.157 1.157-2.602 2.602c-.307.307-.461.708-.461
1.109s.153.802.461 1.109l3.198 3.198
1.134-1.134-2.73-2.73c-.123-.123-.184-.283-.184-.443s.061-.321.184-.443L6.196
9.39l1.154 1.154V7.1zm14.436.627l-1.134 1.134 2.73
2.73c.123.123.184.283.184.443s-.0 [...]
+ <circle cx="17.2" cy="17.2" r="6.8" fill="#ffffff"/>
+ <circle cx="17.2" cy="17.2" r="5.8" fill="#EA102A"/>
+ <rect x="16.2" y="13.2" width="2" height="5.2" rx="0.4" fill="#ffffff"/>
+ <circle cx="17.2" cy="20.2" r="1" fill="#ffffff"/>
+</svg>
diff --git a/ui/src/main/resources/ui/images/workflow-stalled.svg
b/ui/src/main/resources/ui/images/workflow-stalled.svg
new file mode 100644
index 0000000000..be457c4c8f
--- /dev/null
+++ b/ui/src/main/resources/ui/images/workflow-stalled.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
+ <path fill="#033d5d" d="M12.033 2c-.401 0-.802.153-1.109.461L7.726 5.659
8.86 6.792l2.73-2.73c.123-.123.283-.184.443-.184s.321.061.443.184l2.134
2.134-1.154 1.154H16.9V3.906l-1.157 1.157-2.602-2.602C12.835 2.154 12.434 2
12.033 2zM3.905 7.1l1.157 1.157-2.602 2.602c-.307.307-.461.708-.461
1.109s.153.802.461 1.109l3.198 3.198
1.134-1.134-2.73-2.73c-.123-.123-.184-.283-.184-.443s.061-.321.184-.443L6.196
9.39l1.154 1.154V7.1zm14.436.627l-1.134 1.134 2.73
2.73c.123.123.184.283.184.443s-.0 [...]
+ <circle cx="17.2" cy="17.2" r="6.8" fill="#ffffff"/>
+ <circle cx="17.2" cy="17.2" r="5.8" fill="#FFA500"/>
+ <path fill="#ffffff" d="M15.35 15.05c0-1.15.95-2.05 2.05-2.05 1.15 0
2.05.85 2.05 1.95 0 .85-.45 1.35-1.2 1.85-.7.45-.95.8-.95
1.45v.25h-1.7v-.3c0-1.05.4-1.6 1.15-2.1.55-.4.85-.7.85-1.15
0-.5-.35-.85-.85-.85-.5 0-.85.3-.95.9h-1.45z"/>
+ <circle cx="17.2" cy="20.25" r="0.95" fill="#ffffff"/>
+</svg>
diff --git
a/ui/src/test/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionStatusIconTest.java
b/ui/src/test/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionStatusIconTest.java
new file mode 100644
index 0000000000..449d3ebb1c
--- /dev/null
+++
b/ui/src/test/java/org/apache/hop/ui/hopgui/perspective/execution/ExecutionStatusIconTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.perspective.execution;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Date;
+import org.apache.hop.execution.ExecutionState;
+import org.junit.jupiter.api.Test;
+
+class ExecutionStatusIconTest {
+
+ private static final long LOGGING_INTERVAL = 20_000L;
+
+ @Test
+ void nullStateIsDefault() {
+ assertEquals(ExecutionStatusIcon.DEFAULT, ExecutionStatusIcon.from(null,
LOGGING_INTERVAL));
+ }
+
+ @Test
+ void failedWinsOverStale() {
+ ExecutionState state = new ExecutionState();
+ state.setFailed(true);
+ state.setUpdateTime(new Date(System.currentTimeMillis() - 60_000L));
+
+ assertEquals(ExecutionStatusIcon.ERROR, ExecutionStatusIcon.from(state,
LOGGING_INTERVAL));
+ }
+
+ @Test
+ void unfinishedWithoutRecentUpdateIsStalled() {
+ ExecutionState state = new ExecutionState();
+ state.setFailed(false);
+ state.setExecutionEndDate(null);
+ state.setUpdateTime(new Date(System.currentTimeMillis() - 60_000L));
+
+ assertEquals(ExecutionStatusIcon.STALLED, ExecutionStatusIcon.from(state,
LOGGING_INTERVAL));
+ }
+
+ @Test
+ void finishedIsNeverStalled() {
+ ExecutionState state = new ExecutionState();
+ state.setFailed(false);
+ state.setExecutionEndDate(new Date(System.currentTimeMillis() - 60_000L));
+ state.setUpdateTime(new Date(System.currentTimeMillis() - 60_000L));
+
+ assertEquals(ExecutionStatusIcon.DEFAULT, ExecutionStatusIcon.from(state,
LOGGING_INTERVAL));
+ }
+
+ @Test
+ void freshRunningIsDefault() {
+ ExecutionState state = new ExecutionState();
+ state.setFailed(false);
+ state.setStatusDescription("Running");
+ state.setUpdateTime(new Date());
+
+ assertEquals(ExecutionStatusIcon.DEFAULT, ExecutionStatusIcon.from(state,
LOGGING_INTERVAL));
+ }
+
+ @Test
+ void missingUpdateTimeIsNotStalled() {
+ ExecutionState state = new ExecutionState();
+ state.setFailed(false);
+ state.setUpdateTime(null);
+
+ assertEquals(ExecutionStatusIcon.DEFAULT, ExecutionStatusIcon.from(state,
LOGGING_INTERVAL));
+ }
+}