Skip to content

Commit 2bc845a

Browse files
authored
Fix durable return type void issue (#711)
* fix durable return type void issue add unit tests * fix stupid test name
1 parent 9881b3a commit 2bc845a

File tree

3 files changed

+84
-3
lines changed

3 files changed

+84
-3
lines changed

src/main/java/com/microsoft/azure/functions/worker/broker/ParameterResolver.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ else if (paramName == null && !paramBindingNameAnnotation.isEmpty()) {
5252
BindingData actualArg = argument.orElseThrow(WrongMethodTypeException::new);
5353
invokeInfo.appendArgument(actualArg.getValue());
5454
}
55-
if (!method.getMethod().getReturnType().equals(void.class) && !method.getMethod().getReturnType().equals(Void.class)) {
55+
// For function annotated with @HasImplicitOutput, we should allow it to send back data even function's return type is void
56+
// Reference to https://github.com/microsoft/durabletask-java/issues/126
57+
if (!method.getMethod().getReturnType().equals(void.class)
58+
&& !method.getMethod().getReturnType().equals(Void.class)
59+
|| method.hasImplicitOutput()) {
5660
dataStore.getOrAddDataTarget(invokeInfo.getOutputsId(), BindingDataStore.RETURN_NAME, method.getMethod().getReturnType(), method.hasImplicitOutput());
5761
}
5862
return invokeInfo;
@@ -63,8 +67,8 @@ else if (paramName == null && !paramBindingNameAnnotation.isEmpty()) {
6367
}
6468

6569
public static final class InvokeInfoBuilder extends JavaMethodInvokeInfo.Builder {
66-
public InvokeInfoBuilder(MethodBindInfo method) { super.setMethod(method.getMethod()); }
6770
private final UUID outputsId = UUID.randomUUID();
71+
public InvokeInfoBuilder(MethodBindInfo method) { super.setMethod(method.getMethod()); }
6872

6973
public UUID getOutputsId() {
7074
return outputsId;

src/test/java/com/microsoft/azure/functions/worker/broker/JavaFunctionBrokerTest.java

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
import java.util.*;
1313

1414
import static org.junit.jupiter.api.Assertions.*;
15-
import static org.mockito.Mockito.lenient;
1615
import static org.mockito.Mockito.when;
1716

1817
@ExtendWith(MockitoExtension.class)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.microsoft.azure.functions.worker.broker;
2+
3+
import com.microsoft.azure.functions.rpc.messages.RpcException;
4+
import com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector;
5+
import com.microsoft.azure.functions.worker.WorkerLogManager;
6+
import com.microsoft.azure.functions.worker.binding.BindingDataStore;
7+
import com.microsoft.azure.functions.worker.binding.ExecutionContextDataSource;
8+
import com.microsoft.azure.functions.worker.binding.ExecutionRetryContext;
9+
import com.microsoft.azure.functions.worker.binding.ExecutionTraceContext;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.extension.ExtendWith;
13+
import org.mockito.Mock;
14+
import org.mockito.MockedStatic;
15+
import org.mockito.Mockito;
16+
import org.mockito.junit.jupiter.MockitoExtension;
17+
18+
import java.lang.reflect.Method;
19+
import java.util.ArrayList;
20+
import java.util.HashMap;
21+
import java.util.logging.Logger;
22+
23+
import static org.junit.jupiter.api.Assertions.*;
24+
import static org.mockito.Mockito.when;
25+
26+
27+
@ExtendWith(MockitoExtension.class)
28+
public class ParameterResolverTest {
29+
30+
private ExecutionContextDataSource executionContextDataSource;
31+
@Mock
32+
private MethodBindInfo methodBindInfo;
33+
34+
@BeforeEach
35+
public void setup() {
36+
String invocationId = "testInvocationId";
37+
ExecutionTraceContext traceContext = new ExecutionTraceContext("traceParent", "traceState", new HashMap<>());
38+
ExecutionRetryContext retryContext = new ExecutionRetryContext(1, 2, RpcException.newBuilder().build());
39+
String functionName = "ParameterResolverTest";
40+
BindingDataStore dataStore = new BindingDataStore();
41+
dataStore.setBindingDefinitions(new HashMap<>());
42+
try (MockedStatic<WorkerLogManager> workerLogManagerMockedStatic = Mockito.mockStatic(WorkerLogManager.class)) {
43+
workerLogManagerMockedStatic.when(() -> WorkerLogManager.getInvocationLogger(invocationId))
44+
.thenReturn(Logger.getAnonymousLogger());
45+
executionContextDataSource = new ExecutionContextDataSource(invocationId,
46+
traceContext, retryContext, functionName, dataStore, methodBindInfo,
47+
this.getClass(), new ArrayList<>(), new FunctionInstanceInjector() {
48+
@Override
49+
public <T> T getInstance(Class<T> functionClass) throws Exception {
50+
return null;
51+
}
52+
});
53+
}
54+
55+
}
56+
57+
@Test
58+
public void testResolveArgumentsHasImplicitOutputTrue() throws Exception {
59+
Method testMethod = this.getClass().getDeclaredMethod("testMethod");
60+
when(methodBindInfo.hasImplicitOutput()).thenReturn(true);
61+
when(methodBindInfo.getMethod()).thenReturn(testMethod);
62+
when(methodBindInfo.getParams()).thenReturn(new ArrayList<>());
63+
ParameterResolver.resolveArguments(executionContextDataSource);
64+
assertTrue(executionContextDataSource.getDataStore().getDataTargetTypedValue(BindingDataStore.RETURN_NAME).isPresent());
65+
}
66+
67+
@Test
68+
public void testResolveArgumentsHasImplicitOutputFalse() throws Exception {
69+
Method testMethod = this.getClass().getDeclaredMethod("testMethod");
70+
when(methodBindInfo.hasImplicitOutput()).thenReturn(false);
71+
when(methodBindInfo.getMethod()).thenReturn(testMethod);
72+
when(methodBindInfo.getParams()).thenReturn(new ArrayList<>());
73+
ParameterResolver.resolveArguments(executionContextDataSource);
74+
assertFalse(executionContextDataSource.getDataStore().getDataTargetTypedValue(BindingDataStore.RETURN_NAME).isPresent());
75+
}
76+
77+
public void testMethod() {}
78+
}

0 commit comments

Comments
 (0)