• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

temporalio / sdk-java / #333

16 Oct 2024 07:28PM UTC coverage: 78.65% (+0.6%) from 78.085%
#333

push

github

web-flow
Fix code coverage (#2275)

22670 of 28824 relevant lines covered (78.65%)

0.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.22
/temporal-sdk/src/main/java/io/temporal/internal/common/WorkflowExecutionUtils.java
1
/*
2
 * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3
 *
4
 * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
 *
6
 * Modifications copyright (C) 2017 Uber Technologies, Inc.
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this material except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *   http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20

21
package io.temporal.internal.common;
22

23
import com.google.gson.JsonElement;
24
import com.google.gson.JsonPrimitive;
25
import com.google.protobuf.MessageOrBuilder;
26
import com.google.protobuf.TextFormat;
27
import io.temporal.api.command.v1.Command;
28
import io.temporal.api.common.v1.Payloads;
29
import io.temporal.api.common.v1.WorkflowExecution;
30
import io.temporal.api.enums.v1.CommandType;
31
import io.temporal.api.enums.v1.EventType;
32
import io.temporal.api.enums.v1.RetryState;
33
import io.temporal.api.enums.v1.TimeoutType;
34
import io.temporal.api.enums.v1.WorkflowExecutionStatus;
35
import io.temporal.api.history.v1.*;
36
import io.temporal.api.sdk.v1.UserMetadata;
37
import io.temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponseOrBuilder;
38
import io.temporal.client.WorkflowFailedException;
39
import io.temporal.common.converter.DataConverter;
40
import io.temporal.common.converter.EncodedValues;
41
import io.temporal.failure.CanceledFailure;
42
import io.temporal.failure.TerminatedFailure;
43
import io.temporal.failure.TimeoutFailure;
44
import java.util.ArrayList;
45
import java.util.List;
46
import java.util.Map.Entry;
47
import java.util.Optional;
48
import javax.annotation.Nullable;
49

50
/**
51
 * Convenience methods to be used by unit tests and during development. Intended to be a collection
52
 * of relatively small static utility methods.
53
 */
54
public class WorkflowExecutionUtils {
×
55

56
  /**
57
   * Indentation for history and commands pretty printing. Do not change it from 2 spaces. The gson
58
   * pretty printer has it hardcoded and changing it breaks the indentation of exception stack
59
   * traces.
60
   */
61
  private static final String INDENTATION = "  ";
62

63
  public static Optional<Payloads> getResultFromCloseEvent(
64
      WorkflowExecution workflowExecution,
65
      Optional<String> workflowType,
66
      HistoryEvent closeEvent,
67
      DataConverter dataConverter) {
68
    if (closeEvent == null) {
1✔
69
      throw new IllegalStateException("Workflow is still running");
×
70
    }
71
    switch (closeEvent.getEventType()) {
1✔
72
      case EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED:
73
        WorkflowExecutionCompletedEventAttributes completedEventAttributes =
1✔
74
            closeEvent.getWorkflowExecutionCompletedEventAttributes();
1✔
75
        if (completedEventAttributes.hasResult()) {
1✔
76
          return Optional.of(completedEventAttributes.getResult());
1✔
77
        }
78
        return Optional.empty();
×
79
      case EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED:
80
        WorkflowExecutionCanceledEventAttributes canceled =
1✔
81
            closeEvent.getWorkflowExecutionCanceledEventAttributes();
1✔
82
        Optional<Payloads> details =
83
            canceled.hasDetails() ? Optional.of(canceled.getDetails()) : Optional.empty();
1✔
84
        throw new WorkflowFailedException(
1✔
85
            workflowExecution,
86
            workflowType.orElse(null),
1✔
87
            closeEvent.getEventType(),
1✔
88
            -1,
89
            RetryState.RETRY_STATE_NON_RETRYABLE_FAILURE,
90
            new CanceledFailure(
91
                "Workflow canceled", new EncodedValues(details, dataConverter), null));
92
      case EVENT_TYPE_WORKFLOW_EXECUTION_FAILED:
93
        WorkflowExecutionFailedEventAttributes failed =
1✔
94
            closeEvent.getWorkflowExecutionFailedEventAttributes();
1✔
95
        throw new WorkflowFailedException(
1✔
96
            workflowExecution,
97
            workflowType.orElse(null),
1✔
98
            closeEvent.getEventType(),
1✔
99
            failed.getWorkflowTaskCompletedEventId(),
1✔
100
            failed.getRetryState(),
1✔
101
            dataConverter.failureToException(failed.getFailure()));
1✔
102
      case EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED:
103
        WorkflowExecutionTerminatedEventAttributes terminated =
1✔
104
            closeEvent.getWorkflowExecutionTerminatedEventAttributes();
1✔
105
        throw new WorkflowFailedException(
1✔
106
            workflowExecution,
107
            workflowType.orElse(null),
1✔
108
            closeEvent.getEventType(),
1✔
109
            -1,
110
            RetryState.RETRY_STATE_NON_RETRYABLE_FAILURE,
111
            new TerminatedFailure(terminated.getReason(), null));
1✔
112
      case EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT:
113
        WorkflowExecutionTimedOutEventAttributes timedOut =
1✔
114
            closeEvent.getWorkflowExecutionTimedOutEventAttributes();
1✔
115
        throw new WorkflowFailedException(
1✔
116
            workflowExecution,
117
            workflowType.orElse(null),
1✔
118
            closeEvent.getEventType(),
1✔
119
            -1,
120
            timedOut.getRetryState(),
1✔
121
            new TimeoutFailure(null, null, TimeoutType.TIMEOUT_TYPE_START_TO_CLOSE));
122
      default:
123
        throw new RuntimeException(
×
124
            "Workflow end state is not completed: "
125
                + WorkflowExecutionUtils.prettyPrintObject(closeEvent));
×
126
    }
127
  }
128

129
  public static boolean isWorkflowTaskClosedEvent(HistoryEventOrBuilder event) {
130
    return ((event != null)
1✔
131
        && (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_COMPLETED
1✔
132
            || event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_FAILED
1✔
133
            || event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT));
1✔
134
  }
135

136
  public static boolean isWorkflowExecutionClosedEvent(HistoryEventOrBuilder event) {
137
    return ((event != null)
1✔
138
        && (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED
1✔
139
            || event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED
1✔
140
            || event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED
1✔
141
            || event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT
1✔
142
            || event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW
1✔
143
            || event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED));
1✔
144
  }
145

146
  public static boolean isWorkflowExecutionCompleteCommand(Command command) {
147
    return ((command != null)
1✔
148
        && (command.getCommandType() == CommandType.COMMAND_TYPE_COMPLETE_WORKFLOW_EXECUTION
1✔
149
            || command.getCommandType() == CommandType.COMMAND_TYPE_CANCEL_WORKFLOW_EXECUTION
1✔
150
            || command.getCommandType() == CommandType.COMMAND_TYPE_FAIL_WORKFLOW_EXECUTION
1✔
151
            || command.getCommandType()
1✔
152
                == CommandType.COMMAND_TYPE_CONTINUE_AS_NEW_WORKFLOW_EXECUTION));
153
  }
154

155
  public static boolean isActivityTaskClosedEvent(HistoryEvent event) {
156
    return ((event != null)
×
157
        && (event.getEventType() == EventType.EVENT_TYPE_ACTIVITY_TASK_COMPLETED
×
158
            || event.getEventType() == EventType.EVENT_TYPE_ACTIVITY_TASK_CANCELED
×
159
            || event.getEventType() == EventType.EVENT_TYPE_ACTIVITY_TASK_FAILED
×
160
            || event.getEventType() == EventType.EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT));
×
161
  }
162

163
  public static boolean isExternalWorkflowClosedEvent(HistoryEvent event) {
164
    return ((event != null)
×
165
        && (event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED
×
166
            || event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED
×
167
            || event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED
×
168
            || event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED
×
169
            || event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT));
×
170
  }
171

172
  public static WorkflowExecution getWorkflowIdFromExternalWorkflowCompletedEvent(
173
      HistoryEvent event) {
174
    if (event != null) {
×
175
      if (event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED) {
×
176
        return event.getChildWorkflowExecutionCompletedEventAttributes().getWorkflowExecution();
×
177
      } else if (event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED) {
×
178
        return event.getChildWorkflowExecutionCanceledEventAttributes().getWorkflowExecution();
×
179
      } else if (event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED) {
×
180
        return event.getChildWorkflowExecutionFailedEventAttributes().getWorkflowExecution();
×
181
      } else if (event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED) {
×
182
        return event.getChildWorkflowExecutionTerminatedEventAttributes().getWorkflowExecution();
×
183
      } else if (event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT) {
×
184
        return event.getChildWorkflowExecutionTimedOutEventAttributes().getWorkflowExecution();
×
185
      }
186
    }
187

188
    return null;
×
189
  }
190

191
  public static String getId(HistoryEvent historyEvent) {
192
    String id = null;
×
193
    if (historyEvent != null) {
×
194
      if (historyEvent.getEventType()
×
195
          == EventType.EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED) {
196
        id = historyEvent.getStartChildWorkflowExecutionFailedEventAttributes().getWorkflowId();
×
197
      }
198
    }
199

200
    return id;
×
201
  }
202

203
  public static String getFailureCause(HistoryEvent historyEvent) {
204
    String failureCause = null;
×
205
    if (historyEvent != null) {
×
206
      if (historyEvent.getEventType()
×
207
          == EventType.EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED) {
208
        failureCause =
×
209
            historyEvent
210
                .getStartChildWorkflowExecutionFailedEventAttributes()
×
211
                .getCause()
×
212
                .toString();
×
213
        //            } else if (historyEvent.getEventType() ==
214
        // EventType.EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED) {
215
        //                failureCause =
216
        // historyEvent.getSignalExternalWorkflowExecutionFailedEventAttributes().getCause();
217
      } else {
218
        failureCause = "Cannot extract failure cause from " + historyEvent.getEventType();
×
219
      }
220
    }
221

222
    return failureCause;
×
223
  }
224

225
  public static WorkflowExecutionStatus getCloseStatus(HistoryEvent event) {
226
    switch (event.getEventType()) {
1✔
227
      case EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED:
228
        return WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_CANCELED;
×
229
      case EVENT_TYPE_WORKFLOW_EXECUTION_FAILED:
230
        return WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_FAILED;
1✔
231
      case EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT:
232
        return WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_TIMED_OUT;
×
233
      case EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW:
234
        return WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW;
×
235
      case EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED:
236
        return WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_COMPLETED;
1✔
237
      case EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED:
238
        return WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_TERMINATED;
×
239
      default:
240
        throw new IllegalArgumentException("Not a close event: " + event);
×
241
    }
242
  }
243

244
  public static UserMetadata makeUserMetaData(String summary, String details, DataConverter dc) {
245
    if (summary == null && details == null) {
1✔
246
      return null;
1✔
247
    }
248

249
    UserMetadata.Builder builder = UserMetadata.newBuilder();
×
250
    if (summary != null) {
×
251
      builder.setSummary(dc.toPayload(summary).get());
×
252
    }
253
    if (details != null) {
×
254
      builder.setDetails(dc.toPayload(details).get());
×
255
    }
256
    return builder.build();
×
257
  }
258

259
  public static String prettyPrintCommands(Iterable<Command> commands) {
260
    StringBuilder result = new StringBuilder();
×
261
    for (Command command : commands) {
×
262
      result.append(prettyPrintObject(command));
×
263
    }
×
264
    return result.toString();
×
265
  }
266

267
  /** Pretty prints a proto message. */
268
  @SuppressWarnings("deprecation")
269
  public static String prettyPrintObject(MessageOrBuilder object) {
270
    return TextFormat.printToString(object);
×
271
  }
272

273
  public static boolean containsEvent(List<HistoryEvent> history, EventType eventType) {
274
    for (HistoryEvent event : history) {
×
275
      if (event.getEventType() == eventType) {
×
276
        return true;
×
277
      }
278
    }
×
279
    return false;
×
280
  }
281

282
  private static void fixStackTrace(JsonElement json, String stackIndentation) {
283
    if (!json.isJsonObject()) {
×
284
      return;
×
285
    }
286
    for (Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
×
287
      if ("stackTrace".equals(entry.getKey())) {
×
288
        String value = entry.getValue().getAsString();
×
289
        String replacement = "\n" + stackIndentation;
×
290
        String fixed = value.replaceAll("\\n", replacement);
×
291
        entry.setValue(new JsonPrimitive(fixed));
×
292
        continue;
×
293
      }
294
      fixStackTrace(entry.getValue(), stackIndentation + INDENTATION);
×
295
    }
×
296
  }
×
297

298
  /** Command event is an event that is created to mirror a command issued by a workflow task */
299
  public static boolean isCommandEvent(HistoryEvent event) {
300
    EventType eventType = event.getEventType();
1✔
301
    switch (eventType) {
1✔
302
      case EVENT_TYPE_ACTIVITY_TASK_SCHEDULED:
303
      case EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED:
304
      case EVENT_TYPE_TIMER_STARTED:
305
      case EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED:
306
      case EVENT_TYPE_WORKFLOW_EXECUTION_FAILED:
307
      case EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED:
308
      case EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW:
309
      case EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED:
310
      case EVENT_TYPE_TIMER_CANCELED:
311
      case EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED:
312
      case EVENT_TYPE_MARKER_RECORDED:
313
      case EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED:
314
      case EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES:
315
      case EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED:
316
      case EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED:
317
      case EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED:
318
      case EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED:
319
      case EVENT_TYPE_NEXUS_OPERATION_SCHEDULED:
320
      case EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED:
321
        return true;
1✔
322
      default:
323
        return false;
1✔
324
    }
325
  }
326

327
  /** Returns event that corresponds to a command. */
328
  public static EventType getEventTypeForCommand(CommandType commandType) {
329
    switch (commandType) {
1✔
330
      case COMMAND_TYPE_SCHEDULE_ACTIVITY_TASK:
331
        return EventType.EVENT_TYPE_ACTIVITY_TASK_SCHEDULED;
1✔
332
      case COMMAND_TYPE_REQUEST_CANCEL_ACTIVITY_TASK:
333
        return EventType.EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED;
1✔
334
      case COMMAND_TYPE_START_TIMER:
335
        return EventType.EVENT_TYPE_TIMER_STARTED;
1✔
336
      case COMMAND_TYPE_COMPLETE_WORKFLOW_EXECUTION:
337
        return EventType.EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED;
1✔
338
      case COMMAND_TYPE_FAIL_WORKFLOW_EXECUTION:
339
        return EventType.EVENT_TYPE_WORKFLOW_EXECUTION_FAILED;
1✔
340
      case COMMAND_TYPE_CANCEL_TIMER:
341
        return EventType.EVENT_TYPE_TIMER_CANCELED;
1✔
342
      case COMMAND_TYPE_CANCEL_WORKFLOW_EXECUTION:
343
        return EventType.EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED;
×
344
      case COMMAND_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION:
345
        return EventType.EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED;
1✔
346
      case COMMAND_TYPE_RECORD_MARKER:
347
        return EventType.EVENT_TYPE_MARKER_RECORDED;
1✔
348
      case COMMAND_TYPE_CONTINUE_AS_NEW_WORKFLOW_EXECUTION:
349
        return EventType.EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW;
×
350
      case COMMAND_TYPE_START_CHILD_WORKFLOW_EXECUTION:
351
        return EventType.EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED;
1✔
352
      case COMMAND_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION:
353
        return EventType.EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED;
1✔
354
      case COMMAND_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES:
355
        return EventType.EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES;
1✔
356
      case COMMAND_TYPE_MODIFY_WORKFLOW_PROPERTIES:
357
        return EventType.EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED;
1✔
358
      case COMMAND_TYPE_SCHEDULE_NEXUS_OPERATION:
359
        return EventType.EVENT_TYPE_NEXUS_OPERATION_SCHEDULED;
1✔
360
      case COMMAND_TYPE_REQUEST_CANCEL_NEXUS_OPERATION:
361
        return EventType.EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED;
1✔
362
    }
363
    throw new IllegalArgumentException("Unknown commandType");
×
364
  }
365

366
  public static boolean isFullHistory(PollWorkflowTaskQueueResponseOrBuilder workflowTask) {
367
    return workflowTask.getHistory() != null
1✔
368
        && workflowTask.getHistory().getEventsCount() > 0
1✔
369
        && workflowTask.getHistory().getEvents(0).getEventId() == 1;
1✔
370
  }
371

372
  @Nullable
373
  public static HistoryEvent getEventOfType(History history, EventType eventType) {
374
    List<HistoryEvent> events = getEventsOfType(history, eventType);
1✔
375
    if (events.size() > 1) {
1✔
376
      throw new IllegalStateException(
×
377
          "More than one event of type " + eventType + " found in the history");
378
    }
379
    return events.size() > 0 ? events.get(0) : null;
1✔
380
  }
381

382
  public static List<HistoryEvent> getEventsOfType(History history, EventType eventType) {
383
    List<HistoryEvent> result = new ArrayList<>();
1✔
384
    for (HistoryEvent event : history.getEventsList()) {
1✔
385
      if (eventType == event.getEventType()) {
1✔
386
        result.add(event);
1✔
387
      }
388
    }
1✔
389
    return result;
1✔
390
  }
391
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc