diff --git a/src/main/java/com/uber/cadence/internal/common/WorkflowExecutionUtils.java b/src/main/java/com/uber/cadence/internal/common/WorkflowExecutionUtils.java index e9f50ea7..067c3e0b 100644 --- a/src/main/java/com/uber/cadence/internal/common/WorkflowExecutionUtils.java +++ b/src/main/java/com/uber/cadence/internal/common/WorkflowExecutionUtils.java @@ -57,13 +57,8 @@ import java.nio.ByteBuffer; import java.nio.file.Files; import java.time.Duration; -import java.util.Collection; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Optional; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -506,24 +501,6 @@ public static String prettyPrintHistory( return result.toString(); } - public static String prettyPrintDecisions(Iterable decisions) { - StringBuilder result = new StringBuilder(); - result.append("{"); - boolean first = true; - for (Decision decision : decisions) { - if (first) { - first = false; - } else { - result.append(","); - } - result.append("\n"); - result.append(INDENTATION); - result.append(prettyPrintDecision(decision)); - } - result.append("\n}"); - return result.toString(); - } - /** * Returns single event in a human readable format * @@ -561,6 +538,29 @@ private static Object getEventAttributes(HistoryEvent event) { } } + /** + * Returns decisions in a human readable format + * + * @param decisions decisions to pretty print + */ + public static String prettyPrintDecisions(Iterable decisions) { + StringBuilder result = new StringBuilder(); + result.append("{"); + boolean first = true; + for (Decision decision : decisions) { + if (first) { + first = false; + } else { + result.append(","); + } + result.append("\n"); + result.append(INDENTATION); + result.append(prettyPrintDecision(decision)); + } + result.append("\n}"); + return result.toString(); + } + /** * Returns single decision in a human readable format * @@ -638,7 +638,8 @@ private static String prettyPrintObject( result.append("{ "); String prefix = ""; - for (Object entry : ((Map) object).entrySet()) { + Map sortedMap = new TreeMap<>((Map) object); // Automatically sorts by keys + for (Map.Entry entry : sortedMap.entrySet()) { result.append(prefix); prefix = ", "; result.append( @@ -652,6 +653,7 @@ private static String prettyPrintObject( if (Collection.class.isAssignableFrom(clz)) { return String.valueOf(object); } + if (!skipLevel) { if (printTypeName) { result.append(object.getClass().getSimpleName()); @@ -659,7 +661,13 @@ private static String prettyPrintObject( } result.append("{"); } + + // walk through getter methods without params and dump them as + // key (method-name) = value (getter-result) + Method[] eventMethods = object.getClass().getDeclaredMethods(); + Arrays.sort(eventMethods, Comparator.comparing(Method::getName)); + boolean first = true; for (Method method : eventMethods) { String name = method.getName(); diff --git a/src/test/java/com/uber/cadence/internal/common/WorkflowExecutionUtilsTest.java b/src/test/java/com/uber/cadence/internal/common/WorkflowExecutionUtilsTest.java index 35a10f28..8d0e5096 100644 --- a/src/test/java/com/uber/cadence/internal/common/WorkflowExecutionUtilsTest.java +++ b/src/test/java/com/uber/cadence/internal/common/WorkflowExecutionUtilsTest.java @@ -17,20 +17,13 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import com.uber.cadence.EventType; -import com.uber.cadence.GetWorkflowExecutionHistoryResponse; -import com.uber.cadence.History; -import com.uber.cadence.HistoryEvent; -import com.uber.cadence.StartChildWorkflowExecutionFailedEventAttributes; -import com.uber.cadence.WorkflowExecution; -import com.uber.cadence.WorkflowExecutionCloseStatus; +import com.google.common.collect.ImmutableMap; +import com.uber.cadence.*; import com.uber.cadence.client.WorkflowTerminatedException; import com.uber.cadence.client.WorkflowTimedOutException; +import com.uber.cadence.internal.compatibility.ThriftObjects; import com.uber.cadence.serviceclient.IWorkflowService; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.Optional; +import java.util.*; import java.util.concurrent.CancellationException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -42,6 +35,33 @@ public class WorkflowExecutionUtilsTest { private IWorkflowService mockService; private WorkflowExecution workflowExecution; + private final String DECISIONS_PRETTY_PRINT = + "{\n" + + " ScheduleActivityTaskDecisionAttributes {\n" + + " ActivityId = activityId;\n" + + " ActivityType = activityName;\n" + + " Domain = domain;\n" + + " Header = {\n" + + " Fields = { key1=value1, key2=value2 };\n" + + " FieldsSize = 2\n" + + " };\n" + + " HeartbeatTimeoutSeconds = 4;\n" + + " Input = input;\n" + + " ScheduleToCloseTimeoutSeconds = 1;\n" + + " ScheduleToStartTimeoutSeconds = 2;\n" + + " StartToCloseTimeoutSeconds = 3;\n" + + " TaskList = taskList\n" + + " },\n" + + " FailWorkflowExecutionDecisionAttributes {\n" + + " Details = {\n" + + " \"error\": \"panic\",\n" + + " \"stackTrace\": \"fn()\n" + + " main()\"\n" + + " };\n" + + " Reason = failure reason\n" + + " },\n" + + " null\n" + + "}"; @Before public void setUp() { @@ -400,4 +420,53 @@ public void testGetHistoryPage_ExceptionWhileRetrievingExecutionHistory() throws assertTrue(exception.getMessage().contains(errMessage)); } + + @Test + public void testPrettyPrintDecisions() throws Exception { + final TaskList taskList = + new com.uber.cadence.TaskList() + .setName("taskList") + .setKind(com.uber.cadence.TaskListKind.NORMAL); + + final ActivityType activityType = new ActivityType().setName("activityName"); + final Header activityHeader = + new Header() + .setFields( + ImmutableMap.of( + "key1", ThriftObjects.utf8("value1"), + "key2", ThriftObjects.utf8("value2"))); + + final Decision decisionScheduleActivity = + new Decision() + .setDecisionType(DecisionType.ScheduleActivityTask) + .setScheduleActivityTaskDecisionAttributes( + new ScheduleActivityTaskDecisionAttributes() + .setActivityId("activityId") + .setActivityType(activityType) + .setTaskList(taskList) + .setInput(ThriftObjects.utf8("input")) + .setScheduleToCloseTimeoutSeconds(1) + .setScheduleToStartTimeoutSeconds(2) + .setStartToCloseTimeoutSeconds(3) + .setHeartbeatTimeoutSeconds(4) + .setHeader(activityHeader) + .setRequestLocalDispatch(true) + .setDomain("domain")); + + final Decision decisionFailWorkflow = + new Decision() + .setDecisionType(DecisionType.FailWorkflowExecution) + .setFailWorkflowExecutionDecisionAttributes( + new FailWorkflowExecutionDecisionAttributes() + .setReason("failure reason") + .setDetails( + ThriftObjects.utf8( + "{\"error\":\"panic\", \"stackTrace\":\"fn()\\nmain()\"}"))); + + ArrayList decisions = + new ArrayList<>(Arrays.asList(decisionScheduleActivity, decisionFailWorkflow, null)); + + String result = WorkflowExecutionUtils.prettyPrintDecisions(decisions); + assertEquals(DECISIONS_PRETTY_PRINT, result); + } }