Skip to content
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

Why does EventGridTriggerBinding need to support multiple types to convert from? #15

Open
drub0y opened this issue Sep 12, 2017 · 3 comments

Comments

@drub0y
Copy link

drub0y commented Sep 12, 2017

Hi all, I was attempting to rebase PR #12 on top of the latest changes and ran into an interesting problem. A unit test was written for the EvenGridTriggerBinding::BindAsync method here:

public async Task bindAsyncTest()
{
MethodBase methodbase = this.GetType().GetMethod("DummyMethod", BindingFlags.NonPublic | BindingFlags.Instance);
ParameterInfo[] arrayParam = methodbase.GetParameters();
ITriggerBinding binding = new EventGridTriggerBinding(arrayParam[0], null, null);
// given GventGridEvent
EventGridEvent eve = JsonConvert.DeserializeObject<EventGridEvent>(FakeData.singleEvent);
JObject data = eve.Data;
ITriggerData triggerDataWithEvent = await binding.BindAsync(eve, null);
Assert.Equal(data, triggerDataWithEvent.BindingData["data"]);
ITriggerData triggerDataWithString = await binding.BindAsync(FakeData.singleEvent, null);
Assert.Equal(data, triggerDataWithString.BindingData["data"]);
// test invalid, batch of events
FormatException formatException = await Assert.ThrowsAsync<FormatException>(() => binding.BindAsync(FakeData.arrayOfOneEvent, null));
Assert.Equal($"Unable to parse {FakeData.arrayOfOneEvent} to {typeof(EventGridEvent)}", formatException.Message);
// test invalid, random object
var testObject = new TestClass();
InvalidOperationException invalidException = await Assert.ThrowsAsync<InvalidOperationException>(() => binding.BindAsync(testObject, null));
Assert.Equal($"Unable to bind {testObject} to type {arrayParam[0].ParameterType}", invalidException.Message);
}

This unit test now passes in two totally different types of source values which the "old" EventGridTriggerBinding did support. They are string and EventGridEvent.

The question I have is: why does this binding need to support more than one? The binding itself is an internal class that closely cooperates with EventGridExtensionConfig's IAsyncConverter<HttpRequestMessage, HttpResponseMessage> whose responsibility it is to provide the value into the binding... albeit indirectly. Seen here:

string jsonArray = await req.Content.ReadAsStringAsync();
List<EventGridEvent> events = JsonConvert.DeserializeObject<List<EventGridEvent>>(jsonArray);
foreach (var ev in events)
{
TriggeredFunctionData triggerData = new TriggeredFunctionData
{
TriggerValue = ev
};
await _listeners[functionName].Executor.TryExecuteAsync(triggerData, CancellationToken.None);
}

In the current implementation, the EventGridExtensionConfig is always translating the incoming HttpRequestMessage body from JSON into a strongly typed List<EventGridEvent> and then triggering the functions with the individual EventGridEvent instances. Given that, the binding will never see string parameter.

So, that said, while the binding implementation supports converting the raw value from a string, it will never have to do that AFAICT and, therefore, the unit test that was added covers a scenario that doesn't really exist and should thus be removed. Additionally I would suggest that the test method is extremely overloaded with way too many responsibilities and should be refactored into multiple tests.

@drub0y
Copy link
Author

drub0y commented Sep 12, 2017

In PR #12 I'm going to go ahead and refactor this test to work against my implementation. I'll push an update to the PR with those changes and await any other feedback the team might have to offer.

@watashiSHUN
Copy link
Contributor

...I should track better of the issues
The answer lies in b6af0df
in short, there is more than 1 way to call bindAsync, one of which is through admin/functions/{name} api which allows user to pass the function argument in HTTP request body, function runtime will first parse it to string and then invoke user function (reference)

@sandromastronardi
Copy link

How about the cloudevent schema? i dont see that in the code currently. I see documentation stating that i could just use CloudEvent but the validation fails because there is nothing in there for cloud events?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants