Skip to content

Commit

Permalink
Add unit tests for WorkflowExecutionUtils
Browse files Browse the repository at this point in the history
  • Loading branch information
Shaddoll committed Nov 8, 2024
1 parent b08b8d7 commit 4cdc969
Showing 1 changed file with 365 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,365 @@
/**
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* <p>Modifications copyright (C) 2017 Uber Technologies, Inc.
*
* <p>Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file
* except in compliance with the License. A copy of the License is located at
*
* <p>http://aws.amazon.com/apache2.0
*
* <p>or in the "license" file accompanying this file. This file 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 com.uber.cadence.internal.common;

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.uber.cadence.client.WorkflowTerminatedException;
import com.uber.cadence.client.WorkflowTimedOutException;
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.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.Before;
import org.junit.Test;

public class WorkflowExecutionUtilsTest {

private IWorkflowService mockService;
private WorkflowExecution workflowExecution;

@Before
public void setUp() {
mockService = mock(IWorkflowService.class);
workflowExecution =
new WorkflowExecution().setWorkflowId("testWorkflowId").setRunId("testRunId");
}

// Helper method to create a response with a single event
private GetWorkflowExecutionHistoryResponse createResponseWithEvent(HistoryEvent event) {
GetWorkflowExecutionHistoryResponse response = new GetWorkflowExecutionHistoryResponse();
response.setHistory(new History().setEvents(Collections.singletonList(event)));
return response;
}

// ===========================
// Test for successful completion case
// ===========================
@Test
public void testGetWorkflowExecutionResult_SuccessfulCompletion() throws Exception {
// Mock a completed event with a result
HistoryEvent completedEvent = new HistoryEvent();
completedEvent.setEventType(EventType.WorkflowExecutionCompleted);
byte[] expectedResult = "result".getBytes();
completedEvent.setWorkflowExecutionCompletedEventAttributes(
new com.uber.cadence.WorkflowExecutionCompletedEventAttributes().setResult(expectedResult));

// Mock the response from GetWorkflowExecutionHistoryWithTimeout
GetWorkflowExecutionHistoryResponse response = createResponseWithEvent(completedEvent);
when(mockService.GetWorkflowExecutionHistoryWithTimeout(any(), anyLong())).thenReturn(response);

byte[] result =
WorkflowExecutionUtils.getWorkflowExecutionResult(
mockService, "testDomain", workflowExecution, Optional.empty(), 5, TimeUnit.SECONDS);

assertArrayEquals(expectedResult, result);
}

// ===========================
// Test for canceled workflow case
// ===========================
@Test(expected = CancellationException.class)
public void testGetWorkflowExecutionResult_CancelledWorkflow() throws Exception {
// Mock a canceled event
HistoryEvent canceledEvent = new HistoryEvent();
canceledEvent.setEventType(EventType.WorkflowExecutionCanceled);
canceledEvent.setWorkflowExecutionCanceledEventAttributes(
new com.uber.cadence.WorkflowExecutionCanceledEventAttributes());

GetWorkflowExecutionHistoryResponse response = createResponseWithEvent(canceledEvent);
when(mockService.GetWorkflowExecutionHistoryWithTimeout(any(), anyLong())).thenReturn(response);

WorkflowExecutionUtils.getWorkflowExecutionResult(
mockService, "testDomain", workflowExecution, Optional.empty(), 5, TimeUnit.SECONDS);
}

// ===========================
// Test for terminated workflow case
// ===========================
@Test(expected = WorkflowTerminatedException.class)
public void testGetWorkflowExecutionResult_TerminatedWorkflow() throws Exception {
// Mock a terminated event
HistoryEvent terminatedEvent = new HistoryEvent();
terminatedEvent.setEventType(EventType.WorkflowExecutionTerminated);
terminatedEvent.setWorkflowExecutionTerminatedEventAttributes(
new com.uber.cadence.WorkflowExecutionTerminatedEventAttributes());

GetWorkflowExecutionHistoryResponse response = createResponseWithEvent(terminatedEvent);
when(mockService.GetWorkflowExecutionHistoryWithTimeout(any(), anyLong())).thenReturn(response);

WorkflowExecutionUtils.getWorkflowExecutionResult(
mockService, "testDomain", workflowExecution, Optional.empty(), 5, TimeUnit.SECONDS);
}

// ===========================
// Test for timed-out workflow case
// ===========================
@Test(expected = WorkflowTimedOutException.class)
public void testGetWorkflowExecutionResult_TimedOutWorkflow() throws Exception {
// Mock a timed-out event
HistoryEvent timedOutEvent = new HistoryEvent();
timedOutEvent.setEventType(EventType.WorkflowExecutionTimedOut);
timedOutEvent.setWorkflowExecutionTimedOutEventAttributes(
new com.uber.cadence.WorkflowExecutionTimedOutEventAttributes());

GetWorkflowExecutionHistoryResponse response = createResponseWithEvent(timedOutEvent);
when(mockService.GetWorkflowExecutionHistoryWithTimeout(any(), anyLong())).thenReturn(response);

WorkflowExecutionUtils.getWorkflowExecutionResult(
mockService, "testDomain", workflowExecution, Optional.empty(), 5, TimeUnit.SECONDS);
}

// ===========================
// Test for an unsupported close event type
// ===========================
@Test(expected = RuntimeException.class)
public void testGetWorkflowExecutionResult_UnsupportedCloseEvent() throws Exception {
// Mock an event type that doesn't represent a closed workflow
HistoryEvent unsupportedEvent = new HistoryEvent();
unsupportedEvent.setEventType(EventType.ActivityTaskScheduled); // Not a close event

GetWorkflowExecutionHistoryResponse response = createResponseWithEvent(unsupportedEvent);
when(mockService.GetWorkflowExecutionHistoryWithTimeout(any(), anyLong())).thenReturn(response);

WorkflowExecutionUtils.getWorkflowExecutionResult(
mockService, "testDomain", workflowExecution, Optional.empty(), 5, TimeUnit.SECONDS);
}

// ===========================
// Test for timeout exceeded while waiting
// ===========================
@Test(expected = TimeoutException.class)
public void testGetWorkflowExecutionResult_TimeoutExceeded() throws Exception {
// Simulate a delay by mocking the service call to throw a TimeoutException
WorkflowExecutionUtils.getWorkflowExecutionResult(
mockService, "testDomain", workflowExecution, Optional.empty(), -1, TimeUnit.MILLISECONDS);
}

// ===========================
// Test getId with StartChildWorkflowExecutionFailedEvent
// ===========================
@Test
public void testGetId_WithStartChildWorkflowExecutionFailedEvent() {
// Create a StartChildWorkflowExecutionFailed event with a workflow ID
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.StartChildWorkflowExecutionFailed);
StartChildWorkflowExecutionFailedEventAttributes attributes =
new StartChildWorkflowExecutionFailedEventAttributes();
attributes.setWorkflowId("testWorkflowId");
event.setStartChildWorkflowExecutionFailedEventAttributes(attributes);

// Call getId and verify it returns the workflow ID
String result = WorkflowExecutionUtils.getId(event);
assertEquals("testWorkflowId", result);
}

// ===========================
// Test getId with other event types (should return null)
// ===========================
@Test
public void testGetId_WithNonChildWorkflowEvent() {
// Create a HistoryEvent of a different type (e.g., WorkflowExecutionStarted)
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.WorkflowExecutionStarted);

// Call getId and verify it returns null
String result = WorkflowExecutionUtils.getId(event);
assertNull(result);
}

@Test
public void testGetId_WithNullEvent() {
// Call getId with a null event and verify it returns null
String result = WorkflowExecutionUtils.getId(null);
assertNull(result);
}

// ===========================
// Test getCloseStatus for each close event type
// ===========================

@Test
public void testGetCloseStatus_Completed() {
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.WorkflowExecutionCompleted);

WorkflowExecutionCloseStatus result = WorkflowExecutionUtils.getCloseStatus(event);
assertEquals(WorkflowExecutionCloseStatus.COMPLETED, result);
}

@Test
public void testGetCloseStatus_Canceled() {
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.WorkflowExecutionCanceled);

WorkflowExecutionCloseStatus result = WorkflowExecutionUtils.getCloseStatus(event);
assertEquals(WorkflowExecutionCloseStatus.CANCELED, result);
}

@Test
public void testGetCloseStatus_Failed() {
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.WorkflowExecutionFailed);

WorkflowExecutionCloseStatus result = WorkflowExecutionUtils.getCloseStatus(event);
assertEquals(WorkflowExecutionCloseStatus.FAILED, result);
}

@Test
public void testGetCloseStatus_TimedOut() {
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.WorkflowExecutionTimedOut);

WorkflowExecutionCloseStatus result = WorkflowExecutionUtils.getCloseStatus(event);
assertEquals(WorkflowExecutionCloseStatus.TIMED_OUT, result);
}

@Test
public void testGetCloseStatus_ContinuedAsNew() {
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.WorkflowExecutionContinuedAsNew);

WorkflowExecutionCloseStatus result = WorkflowExecutionUtils.getCloseStatus(event);
assertEquals(WorkflowExecutionCloseStatus.CONTINUED_AS_NEW, result);
}

@Test
public void testGetCloseStatus_Terminated() {
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.WorkflowExecutionTerminated);

WorkflowExecutionCloseStatus result = WorkflowExecutionUtils.getCloseStatus(event);
assertEquals(WorkflowExecutionCloseStatus.TERMINATED, result);
}

// ===========================
// Test getCloseStatus with an unsupported event type
// ===========================
@Test
public void testGetCloseStatus_InvalidEvent() {
HistoryEvent event = new HistoryEvent();
event.setEventType(EventType.ActivityTaskScheduled); // Unsupported close event type

IllegalArgumentException exception =
assertThrows(
IllegalArgumentException.class,
() -> {
WorkflowExecutionUtils.getCloseStatus(event);
});

assertTrue(exception.getMessage().contains("Not close event"));
}

// Helper method to create a response with events and a next page token
private GetWorkflowExecutionHistoryResponse createResponseWithEvents(
HistoryEvent[] events, byte[] nextPageToken) {
GetWorkflowExecutionHistoryResponse response = new GetWorkflowExecutionHistoryResponse();
response.setHistory(new History().setEvents(Arrays.asList(events)));
response.setNextPageToken(nextPageToken);
return response;
}
// ===========================
// Test for single-page history
// ===========================
@Test
public void testGetHistory_SinglePage() throws Exception {
// Create a single-page history with two events
HistoryEvent event1 =
new HistoryEvent().setEventType(EventType.WorkflowExecutionStarted).setEventId(1);
HistoryEvent event2 =
new HistoryEvent().setEventType(EventType.WorkflowExecutionCompleted).setEventId(2);

GetWorkflowExecutionHistoryResponse response =
createResponseWithEvents(new HistoryEvent[] {event1, event2}, null);
when(mockService.GetWorkflowExecutionHistory(any())).thenReturn(response);

Iterator<HistoryEvent> iterator =
WorkflowExecutionUtils.getHistory(mockService, "testDomain", workflowExecution);

assertTrue(iterator.hasNext());
assertEquals(event1, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(event2, iterator.next());
assertFalse(iterator.hasNext()); // End of history
}

// ===========================
// Test for multi-page history
// ===========================
@Test
public void testGetHistory_MultiPage() throws Exception {
// Create a multi-page history with three events over two pages
HistoryEvent event1 =
new HistoryEvent().setEventType(EventType.WorkflowExecutionStarted).setEventId(1);
HistoryEvent event2 =
new HistoryEvent().setEventType(EventType.ActivityTaskScheduled).setEventId(2);
HistoryEvent event3 =
new HistoryEvent().setEventType(EventType.WorkflowExecutionCompleted).setEventId(3);

// Page 1 with a nextPageToken
byte[] nextPageToken = new byte[] {1};
GetWorkflowExecutionHistoryResponse responsePage1 =
createResponseWithEvents(new HistoryEvent[] {event1, event2}, nextPageToken);

// Page 2 with no nextPageToken, indicating the end of history
GetWorkflowExecutionHistoryResponse responsePage2 =
createResponseWithEvents(new HistoryEvent[] {event3}, null);

when(mockService.GetWorkflowExecutionHistory(any()))
.thenReturn(responsePage1) // First call returns page 1
.thenReturn(responsePage2); // Second call returns page 2

Iterator<HistoryEvent> iterator =
WorkflowExecutionUtils.getHistory(mockService, "testDomain", workflowExecution);

// Verify the iterator iterates over both pages
assertTrue(iterator.hasNext());
assertEquals(event1, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(event2, iterator.next());
assertTrue(iterator.hasNext());
assertEquals(event3, iterator.next());
assertFalse(iterator.hasNext()); // End of history
}

// ===========================
// Test for empty history
// ===========================
@Test
public void testGetHistory_EmptyHistory() throws Exception {
// Create an empty history response
GetWorkflowExecutionHistoryResponse response =
createResponseWithEvents(new HistoryEvent[] {}, null);
when(mockService.GetWorkflowExecutionHistory(any())).thenReturn(response);

Iterator<HistoryEvent> iterator =
WorkflowExecutionUtils.getHistory(mockService, "testDomain", workflowExecution);

// Verify that hasNext() is false immediately
assertFalse(iterator.hasNext());
}
}

0 comments on commit 4cdc969

Please sign in to comment.