Skip to content

Commit

Permalink
Add unit tests for wrapper calls (#974)
Browse files Browse the repository at this point in the history
* Add unit tests for wrapper calls
  • Loading branch information
3vilhamster authored Nov 27, 2024
1 parent c39c4c5 commit a59a23c
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,7 @@ public void RestartWorkflowExecution(

@Override
public void GetTaskListsByDomain(
GetTaskListsByDomainRequest request, AsyncMethodCallback resultHandler)
throws org.apache.thrift.TException {
GetTaskListsByDomainRequest request, AsyncMethodCallback resultHandler) throws TException {
impl.GetTaskListsByDomain(request, resultHandler);
}

Expand Down Expand Up @@ -893,16 +892,22 @@ public void DescribeTaskList(DescribeTaskListRequest request, AsyncMethodCallbac
}

@Override
public void GetClusterInfo(AsyncMethodCallback resultHandler) throws TException {}
public void GetClusterInfo(AsyncMethodCallback resultHandler) throws TException {
impl.GetClusterInfo(resultHandler);
}

@Override
public void ListTaskListPartitions(
ListTaskListPartitionsRequest request, AsyncMethodCallback resultHandler)
throws TException {}
throws TException {
impl.ListTaskListPartitions(request, resultHandler);
}

@Override
public void RefreshWorkflowTasks(
RefreshWorkflowTasksRequest request, AsyncMethodCallback resultHandler) throws TException {}
RefreshWorkflowTasksRequest request, AsyncMethodCallback resultHandler) throws TException {
impl.RefreshWorkflowTasks(request, resultHandler);
}

@Override
public void RegisterDomain(RegisterDomainRequest registerRequest)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Modifications copyright (C) 2017 Uber Technologies, Inc.
package com.uber.cadence.internal.sync;

import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.mock;

import com.uber.cadence.WorkflowExecution;
Expand All @@ -28,8 +29,7 @@ Modifications copyright (C) 2017 Uber Technologies, Inc.
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.*;
import java.util.function.BiPredicate;
import java.util.function.Supplier;
import org.junit.Before;
Expand All @@ -44,6 +44,8 @@ public class TestActivityEnvironmentInternalTest {

private Object testActivityExecutor;

private Object testWorkflowServiceWrapper;

// Helper method to find the inner class
private Class<?> findTestActivityExecutorClass() {
for (Class<?> declaredClass : TestActivityEnvironmentInternal.class.getDeclaredClasses()) {
Expand All @@ -54,18 +56,26 @@ private Class<?> findTestActivityExecutorClass() {
throw new RuntimeException("Could not find TestActivityExecutor inner class");
}

// Helper method to print all methods
private void printMethods(Class<?> clazz) {
System.out.println("Methods for " + clazz.getName() + ":");
for (Method method : clazz.getDeclaredMethods()) {
System.out.println(" " + method);
// Helper method to find the inner class
private Class<?> findWorkflowServiceWrapperClass() {
for (Class<?> declaredClass : TestActivityEnvironmentInternal.class.getDeclaredClasses()) {
if (declaredClass.getSimpleName().equals("WorkflowServiceWrapper")) {
return declaredClass;
}
}
throw new RuntimeException("Could not find WorkflowServiceWrapper inner class");
}

@Before
public void setUp() {
MockitoAnnotations.openMocks(this);

setupActivityExecutor();

setupWorkflowServiceWrapper();
}

private void setupActivityExecutor() {
try {
// Find the inner class first
Class<?> innerClass = findTestActivityExecutorClass();
Expand All @@ -83,16 +93,63 @@ public void setUp() {

// Create the instance
testActivityExecutor = constructor.newInstance(outerInstance, mockWorkflowService, mockNext);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to set up test: " + e.getMessage(), e);
}
}

// Debug print the class and methods
System.out.println("TestActivityExecutor class: " + innerClass);
printMethods(innerClass);
private void setupWorkflowServiceWrapper() {
try {
// Find the inner class first
Class<?> innerClass = findWorkflowServiceWrapperClass();

// Get the constructor with the specific parameter types
Constructor<?> constructor =
innerClass.getDeclaredConstructor(
TestActivityEnvironmentInternal.class, IWorkflowService.class);
constructor.setAccessible(true);

// Create an instance of the outer class
TestActivityEnvironmentInternal outerInstance = mock(TestActivityEnvironmentInternal.class);

// Create the instance
testWorkflowServiceWrapper = constructor.newInstance(outerInstance, mockWorkflowService);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to set up test: " + e.getMessage(), e);
}
}

@Test
public void testWorkflowServiceWrapperMethodDelegation() throws Exception {
// Prepare test cases
List<MethodTestCase> testCases = prepareMethodTestCases();

System.out.println(testCases);

// Test each method
for (MethodTestCase testCase : testCases) {
try {
// Find the method on the wrapper
Method wrapperMethod =
testWorkflowServiceWrapper
.getClass()
.getMethod(testCase.methodName, testCase.parameterTypes);

// Invoke the method on the wrapper
wrapperMethod.invoke(testWorkflowServiceWrapper, testCase.arguments);

// Generic verification using reflection
verifyMethodInvocation(mockWorkflowService, testCase);

} catch (Exception e) {
// Rethrow to fail the test if any unexpected exception occurs
throw new AssertionError("Failed to test method: " + testCase.methodName, e);
}
}
}

@Test
public void testAllMethodsThrowUnsupportedOperationException() throws Exception {
// Define test cases for different methods
Expand Down Expand Up @@ -232,4 +289,72 @@ private static class MethodTestCase {
this.arguments = arguments;
}
}

/** Generic method to verify method invocation on mock */
private void verifyMethodInvocation(Object mockObject, MethodTestCase testCase) throws Exception {
// Use Mockito's verify with reflection
if (testCase.arguments.length == 0) {
// For methods with no arguments
verify(mockObject).getClass().getMethod(testCase.methodName).invoke(mockObject);
} else {
// For methods with arguments
Method verifyMethod = org.mockito.Mockito.class.getMethod("verify", Object.class);
Object verifiedMock = verifyMethod.invoke(null, mockObject);

// Invoke the method on the verified mock
verifiedMock
.getClass()
.getMethod(testCase.methodName, testCase.parameterTypes)
.invoke(verifiedMock, testCase.arguments);
}
}

/** Prepares test cases for all methods in IWorkflowService */
private List<MethodTestCase> prepareMethodTestCases() throws Exception {
List<MethodTestCase> testCases = new ArrayList<>();

// You can add more methods here as needed
// Dynamically discover and add more methods from IWorkflowService if required
Method[] allMethods = IWorkflowService.class.getMethods();
for (Method method : allMethods) {
testCases.add(createDefaultMethodTestCase(method));
}
return testCases;
}

/** Creates a default MethodTestCase for a given method */
private MethodTestCase createDefaultMethodTestCase(Method method) throws Exception {
Class<?>[] parameterTypes = method.getParameterTypes();
Object[] arguments = new Object[parameterTypes.length];

for (int i = 0; i < parameterTypes.length; i++) {
arguments[i] = createDefaultArgument(parameterTypes[i]);
}

return new MethodTestCase(method.getName(), parameterTypes, arguments);
}

/** Creates a default argument for different parameter types */
private Object createDefaultArgument(Class<?> type) throws Exception {
if (type.isPrimitive()) {
if (type == boolean.class) return false;
if (type == char.class) return '\u0000';
if (type == byte.class) return (byte) 0;
if (type == short.class) return (short) 0;
if (type == int.class) return 0;
if (type == long.class) return 0L;
if (type == float.class) return 0.0f;
if (type == double.class) return 0.0d;
}

// For non-primitive types, try to create an empty instance
if (type.getConstructors().length > 0
&& Arrays.stream(type.getConstructors())
.anyMatch(constructor -> constructor.getParameterCount() == 0)) {
return type.getDeclaredConstructor().newInstance();
}

// Fallback for complex types
return null;
}
}

0 comments on commit a59a23c

Please sign in to comment.