Skip to content

Commit 9efb9f2

Browse files
mathewcyojagad
authored andcommitted
Add null check to ScriptInvocationContextExtensions.ToRpcInvocationRequest (#6478)
1 parent d5369a5 commit 9efb9f2

File tree

2 files changed

+138
-1
lines changed

2 files changed

+138
-1
lines changed

src/WebJobs.Script/Workers/MessageExtensions/ScriptInvocationContextExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,14 @@ public static async Task<InvocationRequest> ToRpcInvocationRequest(this ScriptIn
3434

3535
foreach (var input in context.Inputs)
3636
{
37-
if (!rpcValueCache.TryGetValue(input.val, out TypedData rpcValue))
37+
TypedData rpcValue = null;
38+
if (input.val == null || !rpcValueCache.TryGetValue(input.val, out rpcValue))
3839
{
3940
rpcValue = await input.val.ToRpc(logger, capabilities);
41+
if (input.val != null)
42+
{
43+
rpcValueCache.Add(input.val, rpcValue);
44+
}
4045
}
4146

4247
var parameterBinding = new ParameterBinding

test/WebJobs.Script.Tests/Workers/ScriptInvocationContextExtensionsTests.cs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading.Tasks;
88
using Google.Protobuf.Collections;
99
using Microsoft.AspNetCore.Http;
10+
using Microsoft.AspNetCore.Mvc.ModelBinding;
1011
using Microsoft.Azure.WebJobs.Script.Description;
1112
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
1213
using Microsoft.Azure.WebJobs.Script.Workers;
@@ -149,6 +150,137 @@ public async Task ToRpcInvocationRequest_Http_OmitsDuplicateBodyOfBindingData()
149150
Assert.True(result.TriggerMetadata.ContainsKey("sys"));
150151
}
151152

153+
[Fact]
154+
public async Task ToRpcInvocationRequest_MultipleInputBindings()
155+
{
156+
var logger = new TestLogger("test");
157+
158+
var httpContext = new DefaultHttpContext();
159+
httpContext.Request.Host = new HostString("local");
160+
httpContext.Request.Path = "/test";
161+
httpContext.Request.Method = "Post";
162+
163+
var poco = new TestPoco { Id = 1, Name = "Test" };
164+
165+
var bindingData = new Dictionary<string, object>
166+
{
167+
{ "req", httpContext.Request },
168+
{ "$request", httpContext.Request },
169+
{ "headers", httpContext.Request.Headers.ToDictionary(p => p.Key, p => p.Value) },
170+
{ "query", httpContext.Request.QueryString.ToString() },
171+
{ "sys", new SystemBindingData() }
172+
};
173+
174+
var inputs = new List<(string name, DataType type, object val)>
175+
{
176+
("req", DataType.String, httpContext.Request),
177+
("blob", DataType.String, null), // verify that null values are handled
178+
("foo", DataType.String, "test"),
179+
("bar1", DataType.String, poco),
180+
("bar2", DataType.String, poco)
181+
};
182+
183+
var invocationContext = new ScriptInvocationContext()
184+
{
185+
ExecutionContext = new ExecutionContext()
186+
{
187+
InvocationId = Guid.NewGuid(),
188+
FunctionName = "Test",
189+
},
190+
BindingData = bindingData,
191+
Inputs = inputs,
192+
ResultSource = new TaskCompletionSource<ScriptInvocationResult>(),
193+
Logger = logger,
194+
AsyncExecutionContext = System.Threading.ExecutionContext.Capture()
195+
};
196+
197+
var functionMetadata = new FunctionMetadata
198+
{
199+
Name = "Test"
200+
};
201+
202+
var httpTriggerBinding = new BindingMetadata
203+
{
204+
Name = "req",
205+
Type = "httpTrigger",
206+
Direction = BindingDirection.In,
207+
Raw = new JObject()
208+
};
209+
210+
var blobInputBinding = new BindingMetadata
211+
{
212+
Name = "blob",
213+
Type = "blob",
214+
Direction = BindingDirection.In
215+
};
216+
217+
var fooInputBinding = new BindingMetadata
218+
{
219+
Name = "foo",
220+
Type = "foo",
221+
Direction = BindingDirection.In
222+
};
223+
224+
var barInputBinding1 = new BindingMetadata
225+
{
226+
Name = "bar1",
227+
Type = "bar",
228+
Direction = BindingDirection.In
229+
};
230+
231+
var barInputBinding2 = new BindingMetadata
232+
{
233+
Name = "bar2",
234+
Type = "bar",
235+
Direction = BindingDirection.In
236+
};
237+
238+
var httpOutputBinding = new BindingMetadata
239+
{
240+
Name = "res",
241+
Type = "http",
242+
Direction = BindingDirection.Out,
243+
Raw = new JObject(),
244+
DataType = DataType.String
245+
};
246+
247+
functionMetadata.Bindings.Add(httpTriggerBinding);
248+
functionMetadata.Bindings.Add(blobInputBinding);
249+
functionMetadata.Bindings.Add(fooInputBinding);
250+
functionMetadata.Bindings.Add(barInputBinding1);
251+
functionMetadata.Bindings.Add(barInputBinding2);
252+
functionMetadata.Bindings.Add(httpOutputBinding);
253+
invocationContext.FunctionMetadata = functionMetadata;
254+
255+
Capabilities capabilities = new Capabilities(logger);
256+
var result = await invocationContext.ToRpcInvocationRequest(logger, capabilities);
257+
Assert.Equal(5, result.InputData.Count);
258+
259+
Assert.Equal("req", result.InputData[0].Name);
260+
var resultHttp = result.InputData[0].Data;
261+
Assert.Equal("http://local/test", ((RpcHttp)result.InputData[0].Data.Http).Url);
262+
263+
// verify the null input was propagated properly
264+
Assert.Equal("blob", result.InputData[1].Name);
265+
Assert.Equal(string.Empty, result.InputData[1].Data.String);
266+
267+
Assert.Equal("foo", result.InputData[2].Name);
268+
Assert.Equal("test", result.InputData[2].Data.String);
269+
270+
Assert.Equal("bar1", result.InputData[3].Name);
271+
var resultPoco = result.InputData[3].Data;
272+
Assert.Equal("{\"Name\":\"Test\",\"Id\":1}", resultPoco.Json);
273+
274+
Assert.Equal("bar2", result.InputData[4].Name);
275+
Assert.Same(resultPoco, result.InputData[4].Data);
276+
277+
Assert.Equal(4, result.TriggerMetadata.Count);
278+
Assert.Same(resultHttp, result.TriggerMetadata["req"]);
279+
Assert.Same(resultHttp, result.TriggerMetadata["$request"]);
280+
Assert.True(result.TriggerMetadata.ContainsKey("headers"));
281+
Assert.True(result.TriggerMetadata.ContainsKey("query"));
282+
}
283+
152284
private class TestPoco
153285
{
154286
public string Name { get; set; }

0 commit comments

Comments
 (0)