-
Notifications
You must be signed in to change notification settings - Fork 66
Enable use of nullable maps for headers, params and query #694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 2 commits
ea4df5f
5c74367
1e53683
83d5388
60bb55a
727323c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,7 +6,10 @@ | |
| import java.util.Arrays; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.stream.Collectors; | ||
|
|
||
| import com.microsoft.azure.functions.rpc.messages.NullableTypes; | ||
| import com.microsoft.azure.functions.worker.Util; | ||
| import org.apache.commons.lang3.reflect.TypeUtils; | ||
|
|
||
| import com.microsoft.azure.functions.HttpMethod; | ||
|
|
@@ -22,8 +25,10 @@ public RpcHttpRequestDataSource(String name, RpcHttp value) { | |
| super(name, null, HTTP_DATA_OPERATIONS); | ||
| this.httpPayload = value; | ||
| this.bodyDataSource = BindingDataStore.rpcSourceFromTypedData(null, this.httpPayload.getBody()); | ||
| this.fields = Arrays.asList(this.httpPayload.getHeadersMap(), this.httpPayload.getQueryMap(), | ||
| this.httpPayload.getParamsMap()); | ||
| this.fields = Arrays.asList( | ||
| convertFromNullableMap(this.httpPayload.getNullableHeadersMap()), | ||
| convertFromNullableMap(this.httpPayload.getNullableQueryMap()), | ||
| convertFromNullableMap(this.httpPayload.getNullableParamsMap())); | ||
| this.setValue(this); | ||
| } | ||
|
|
||
|
|
@@ -45,12 +50,12 @@ public HttpMethod getHttpMethod() { | |
|
|
||
| @Override | ||
| public Map<String, String> getHeaders() { | ||
| return this.parentDataSource.httpPayload.getHeadersMap(); | ||
| return convertFromNullableMap(this.parentDataSource.httpPayload.getNullableHeadersMap()); | ||
| } | ||
|
|
||
| @Override | ||
| public Map<String, String> getQueryParameters() { | ||
| return this.parentDataSource.httpPayload.getQueryMap(); | ||
| return convertFromNullableMap(this.parentDataSource.httpPayload.getNullableQueryMap()); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -86,4 +91,16 @@ public Builder createResponseBuilder(HttpStatus status) { | |
| return new HttpRequestMessageImpl(v, bodyData.getValue()); | ||
| }); | ||
| } | ||
|
|
||
| private static Map<String, String> convertFromNullableMap(Map<String, NullableTypes.NullableString> nullableMap) { | ||
| if (Util.isTrue(System.getenv("FUNCTIONS_WORKER_NULLABLE_VALUES_ENABLED"))) { | ||
|
||
| return nullableMap.entrySet().stream().collect( | ||
| Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getValue()) | ||
| ); | ||
| } else { | ||
| return nullableMap.entrySet().stream() | ||
| .filter(e -> e.getValue().getValue() != null && !e.getValue().getValue().trim().isEmpty()) | ||
| .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getValue())); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,11 +5,16 @@ | |
| import java.lang.reflect.Method; | ||
| import java.lang.reflect.Parameter; | ||
| import java.util.*; | ||
|
|
||
| import com.microsoft.azure.functions.rpc.messages.NullableTypes.NullableString; | ||
| import com.microsoft.azure.functions.HttpRequestMessage; | ||
| import com.microsoft.azure.functions.HttpStatus; | ||
| import com.microsoft.azure.functions.rpc.messages.RpcHttp; | ||
| import com.microsoft.azure.functions.rpc.messages.TypedData; | ||
| import com.microsoft.azure.functions.worker.binding.*; | ||
| import com.microsoft.azure.functions.worker.broker.JavaFunctionBroker; | ||
| import com.microsoft.azure.functions.worker.handler.FunctionEnvironmentReloadRequestHandler; | ||
| import com.microsoft.azure.functions.worker.reflect.DefaultClassLoaderProvider; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
|
@@ -26,13 +31,23 @@ public void HttpRequestIntBody(HttpRequestMessage<Integer> request) { | |
| public void HttpRequestBinaryBody(HttpRequestMessage<byte[]> request) { | ||
| } | ||
|
|
||
| public static RpcHttp getTestRpcHttp(Object inputBody) throws Exception { | ||
| public static RpcHttp getTestRpcHttp( | ||
| Object inputBody, | ||
| Map<String, String> headersMap, | ||
| Map<String, String> queryMap) throws Exception { | ||
| TypedData.Builder dataBuilder = TypedData.newBuilder(); | ||
| RpcHttp.Builder httpBuilder = RpcHttp.newBuilder() | ||
| .setStatusCode(Integer.toString(HttpStatus.OK.value())); | ||
| Map<String, String> headers = new HashMap<>(); | ||
| headers.put("header", "testHeader"); | ||
| headers.forEach(httpBuilder::putHeaders); | ||
| if (headersMap != null) { | ||
| for (String key : headersMap.keySet()) { | ||
| httpBuilder.putNullableHeaders(key, NullableString.newBuilder().setValue(headersMap.get(key)).build()); | ||
| } | ||
| } | ||
| if (queryMap != null) { | ||
| for (String key : queryMap.keySet()) { | ||
| httpBuilder.putNullableQuery(key, NullableString.newBuilder().setValue(queryMap.get(key)).build()); | ||
| } | ||
| } | ||
| RpcUnspecifiedDataTarget bodyTarget = new RpcUnspecifiedDataTarget(); | ||
| Object body = inputBody; | ||
| bodyTarget.setValue(body); | ||
|
|
@@ -41,14 +56,150 @@ public static RpcHttp getTestRpcHttp(Object inputBody) throws Exception { | |
| return httpBuilder.build(); | ||
| } | ||
|
|
||
| @Test | ||
| public void rpcHttpDataSource_To_HttpRequestMessage_NullableQueryParamsEmpty_EnvSettingEnabled() throws Exception { | ||
|
||
| DefaultClassLoaderProvider classLoader = new DefaultClassLoaderProvider(); | ||
| JavaFunctionBroker broker = new JavaFunctionBroker(classLoader); | ||
| FunctionEnvironmentReloadRequestHandler envHandler = new FunctionEnvironmentReloadRequestHandler(broker); | ||
| Map<String, String> existingVariables = System.getenv(); | ||
| Map<String, String> newEnvVariables = new HashMap<>(); | ||
| newEnvVariables.putAll(existingVariables); | ||
| newEnvVariables.put("FUNCTIONS_WORKER_NULLABLE_VALUES_ENABLED", "true"); | ||
| envHandler.setEnv(newEnvVariables); | ||
| Method httpRequestMessageStringBodyMethod = getFunctionMethod("HttpRequestStringBody"); | ||
| Map<String, String> queryMap = new HashMap<String, String>() {{ | ||
| put("name", ""); | ||
| }}; | ||
| Parameter[] parameters = httpRequestMessageStringBodyMethod.getParameters(); | ||
| String sourceKey = "testRpcHttp"; | ||
| RpcHttp input = getTestRpcHttp(null, null, queryMap); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
| BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new); | ||
| HttpRequestMessage<?> requestMsg = (HttpRequestMessage<?>) actualArg.getValue(); | ||
| assertEquals(requestMsg.getQueryParameters().get("name"), ""); | ||
|
||
| } | ||
|
|
||
| @Test | ||
| public void rpcHttpDataSource_To_HttpRequestMessage_NullableQueryParamsEmpty_EnvSettingDisabled() throws Exception { | ||
| DefaultClassLoaderProvider classLoader = new DefaultClassLoaderProvider(); | ||
| JavaFunctionBroker broker = new JavaFunctionBroker(classLoader); | ||
| FunctionEnvironmentReloadRequestHandler envHandler = new FunctionEnvironmentReloadRequestHandler(broker); | ||
| Map<String, String> existingVariables = System.getenv(); | ||
| Map<String, String> newEnvVariables = new HashMap<>(); | ||
| newEnvVariables.putAll(existingVariables); | ||
| newEnvVariables.put("FUNCTIONS_WORKER_NULLABLE_VALUES_ENABLED", "false"); | ||
| envHandler.setEnv(newEnvVariables); | ||
| Method httpRequestMessageStringBodyMethod = getFunctionMethod("HttpRequestStringBody"); | ||
| Map<String, String> queryMap = new HashMap<String, String>() {{ | ||
| put("name", ""); | ||
| }}; | ||
| Parameter[] parameters = httpRequestMessageStringBodyMethod.getParameters(); | ||
| String sourceKey = "testRpcHttp"; | ||
| RpcHttp input = getTestRpcHttp(null, null, queryMap); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
| BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new); | ||
| HttpRequestMessage<?> requestMsg = (HttpRequestMessage<?>) actualArg.getValue(); | ||
| assertEquals(requestMsg.getQueryParameters().get("name"), null); | ||
|
||
| } | ||
|
|
||
| @Test | ||
| public void rpcHttpDataSource_To_HttpRequestMessage_NullableQueryParamsNonEmpty() throws Exception { | ||
|
||
|
|
||
| Method httpRequestMessageStringBodyMethod = getFunctionMethod("HttpRequestStringBody"); | ||
| Map<String, String> queryMap = new HashMap<String, String>() {{ | ||
| put("name", "random"); | ||
| }}; | ||
| Parameter[] parameters = httpRequestMessageStringBodyMethod.getParameters(); | ||
| String sourceKey = "testRpcHttp"; | ||
| RpcHttp input = getTestRpcHttp(null, null, queryMap); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
| BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new); | ||
| HttpRequestMessage<?> requestMsg = (HttpRequestMessage<?>) actualArg.getValue(); | ||
| assertEquals(requestMsg.getQueryParameters().get("name"), "random"); | ||
| } | ||
|
|
||
| @Test | ||
| public void rpcHttpDataSource_To_HttpRequestMessage_NullableHeadersEmpty_EnvSettingEnabled() throws Exception { | ||
| DefaultClassLoaderProvider classLoader = new DefaultClassLoaderProvider(); | ||
| JavaFunctionBroker broker = new JavaFunctionBroker(classLoader); | ||
| FunctionEnvironmentReloadRequestHandler envHandler = new FunctionEnvironmentReloadRequestHandler(broker); | ||
| Map<String, String> existingVariables = System.getenv(); | ||
| Map<String, String> newEnvVariables = new HashMap<>(); | ||
| newEnvVariables.putAll(existingVariables); | ||
| newEnvVariables.put("FUNCTIONS_WORKER_NULLABLE_VALUES_ENABLED", "true"); | ||
| envHandler.setEnv(newEnvVariables); | ||
| Method httpRequestMessageStringBodyMethod = getFunctionMethod("HttpRequestStringBody"); | ||
| Map<String, String> headersMap = new HashMap<String, String>() {{ | ||
| put("cookie", ""); | ||
| }}; | ||
| Parameter[] parameters = httpRequestMessageStringBodyMethod.getParameters(); | ||
| String sourceKey = "testRpcHttp"; | ||
| RpcHttp input = getTestRpcHttp(null, headersMap, null); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
| BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new); | ||
| HttpRequestMessage<?> requestMsg = (HttpRequestMessage<?>) actualArg.getValue(); | ||
| assertEquals(requestMsg.getHeaders().get("cookie"), ""); | ||
| } | ||
|
|
||
| @Test | ||
| public void rpcHttpDataSource_To_HttpRequestMessage_NullableHeadersEmpty_EnvSettingDisabled() throws Exception { | ||
| DefaultClassLoaderProvider classLoader = new DefaultClassLoaderProvider(); | ||
| JavaFunctionBroker broker = new JavaFunctionBroker(classLoader); | ||
| FunctionEnvironmentReloadRequestHandler envHandler = new FunctionEnvironmentReloadRequestHandler(broker); | ||
| Map<String, String> existingVariables = System.getenv(); | ||
| Map<String, String> newEnvVariables = new HashMap<>(); | ||
| newEnvVariables.putAll(existingVariables); | ||
| newEnvVariables.put("FUNCTIONS_WORKER_NULLABLE_VALUES_ENABLED", "false"); | ||
| envHandler.setEnv(newEnvVariables); | ||
| Method httpRequestMessageStringBodyMethod = getFunctionMethod("HttpRequestStringBody"); | ||
| Map<String, String> headersMap = new HashMap<String, String>() {{ | ||
| put("cookie", ""); | ||
| }}; | ||
| Parameter[] parameters = httpRequestMessageStringBodyMethod.getParameters(); | ||
| String sourceKey = "testRpcHttp"; | ||
| RpcHttp input = getTestRpcHttp(null, headersMap, null); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
| BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new); | ||
| HttpRequestMessage<?> requestMsg = (HttpRequestMessage<?>) actualArg.getValue(); | ||
| assertEquals(requestMsg.getHeaders().get("cookie"), null); | ||
| } | ||
|
|
||
| @Test | ||
| public void rpcHttpDataSource_To_HttpRequestMessage_NullableHeadersNonEmpty() throws Exception { | ||
|
|
||
| Method httpRequestMessageStringBodyMethod = getFunctionMethod("HttpRequestStringBody"); | ||
| Map<String, String> headersMap = new HashMap<String, String>() {{ | ||
| put("cookie", "foo=bar"); | ||
| }}; | ||
| Parameter[] parameters = httpRequestMessageStringBodyMethod.getParameters(); | ||
| String sourceKey = "testRpcHttp"; | ||
| RpcHttp input = getTestRpcHttp(null, headersMap, null); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
| BindingData actualArg = actualBindingData.orElseThrow(WrongMethodTypeException::new); | ||
| HttpRequestMessage<?> requestMsg = (HttpRequestMessage<?>) actualArg.getValue(); | ||
| assertEquals(requestMsg.getHeaders().get("cookie"), "foo=bar"); | ||
| } | ||
|
|
||
| @Test | ||
| public void rpcHttpDataSource_To_HttpRequestMessage_StringBody() throws Exception { | ||
|
|
||
| Method httpRequestMessageStringBodyMethod = getFunctionMethod("HttpRequestStringBody"); | ||
|
|
||
| Parameter[] parameters = httpRequestMessageStringBodyMethod.getParameters(); | ||
| String sourceKey = "testRpcHttp"; | ||
| RpcHttp input = getTestRpcHttp("testStringBody"); | ||
| RpcHttp input = getTestRpcHttp("testStringBody", null, null); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
|
|
@@ -64,7 +215,7 @@ public void rpcHttpDataSource_To_HttpRequestMessage_IntegerBody() throws Excepti | |
|
|
||
| Parameter[] parameters = httpRequestMessageStringBodyMethod.getParameters(); | ||
| String sourceKey = "testRpcHttp"; | ||
| RpcHttp input = getTestRpcHttp(1234); | ||
| RpcHttp input = getTestRpcHttp(1234, null, null); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
|
|
@@ -82,7 +233,7 @@ public void rpcHttpDataSource_To_HttpRequestMessage_byteArrayBody() throws Excep | |
| String sourceKey = "testRpcHttp"; | ||
| String expectedString = "Example String"; | ||
| byte[] inputBytes = expectedString.getBytes(); | ||
| RpcHttp input = getTestRpcHttp(inputBytes); | ||
| RpcHttp input = getTestRpcHttp(inputBytes, null, null); | ||
| RpcHttpRequestDataSource rpcHttp = new RpcHttpRequestDataSource(sourceKey, input); | ||
| Optional<BindingData> actualBindingData = rpcHttp.computeByName(sourceKey, | ||
| parameters[0].getParameterizedType()); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not related to this PR, but do we know difference between query map and param map?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the host code, it looks like the three key differences between query map and param map are that:
requestobject (i.e.request.Queryvsrequest.HttpContext.Items.TryGetValue(HttpExtensionConstants.AzureWebJobsHttpRouteDataKey, out object routeData))UseNullableValueDictionaryForHttpcapability is onUseNullableValueDictionaryForHttpcapability is off