Skip to content

Commit 18d833f

Browse files
authored
fix: Prevent NullReferenceExeption on APIGatewayProxyRequest (#2529)
1 parent 2bfc317 commit 18d833f

File tree

5 files changed

+112
-8
lines changed

5 files changed

+112
-8
lines changed

src/Agent/NewRelic/Agent/Extensions/NewRelic.Agent.Extensions/Lambda/LambdaEventHelpers.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ private static void SetWebRequestProperties(IAgent agent, ITransaction transacti
292292
transaction.SetUri(webReqEvent.Path);
293293
}
294294

295-
transaction.SetRequestParameters(webReqEvent.QueryStringParameters);
295+
if (webReqEvent.QueryStringParameters != null)
296+
transaction.SetRequestParameters(webReqEvent.QueryStringParameters);
296297
}
297298

298299
private static TransportType GetDistributedTransportType(string forwardedProto)

tests/Agent/IntegrationTests/IntegrationTests/AwsLambda/AwsLambdaAPIGatewayHttpApiV2ProxyRequestTest.cs

+34-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ protected AwsLambdaAPIGatewayHttpApiV2ProxyRequestTest(T fixture, ITestOutputHel
3434
{
3535
_fixture.EnqueueAPIGatewayHttpApiV2ProxyRequest();
3636
_fixture.EnqueueAPIGatewayHttpApiV2ProxyRequestWithDTHeaders(TestTraceId, TestParentSpanId);
37-
_fixture.AgentLog.WaitForLogLines(AgentLogBase.ServerlessPayloadLogLineRegex, TimeSpan.FromMinutes(1), 2);
37+
_fixture.EnqueueMinimalAPIGatewayHttpApiV2ProxyRequest();
38+
_fixture.AgentLog.WaitForLogLines(AgentLogBase.ServerlessPayloadLogLineRegex, TimeSpan.FromMinutes(1), 3);
3839
}
3940
);
4041
_fixture.Initialize();
@@ -46,8 +47,10 @@ public void Test()
4647
var serverlessPayloads = _fixture.AgentLog.GetServerlessPayloads().ToList();
4748

4849
Assert.Multiple(
49-
() => Assert.Equal(2, serverlessPayloads.Count),
50-
() => Assert.All(serverlessPayloads, ValidateServerlessPayload),
50+
() => Assert.Equal(3, serverlessPayloads.Count),
51+
// validate the first 2 payloads separately from the 3rd
52+
() => Assert.All(serverlessPayloads.GetRange(0, 2), ValidateServerlessPayload),
53+
() => ValidateMinimalRequestPayload(serverlessPayloads[2]),
5154
() => ValidateTraceHasNoParent(serverlessPayloads[0]),
5255
() => ValidateTraceHasParent(serverlessPayloads[1])
5356
);
@@ -88,6 +91,34 @@ private void ValidateServerlessPayload(ServerlessPayload serverlessPayload)
8891
Assertions.TransactionEventHasAttributes(expectedAgentAttributeValues, TransactionEventAttributeType.Agent, transactionEvent);
8992
}
9093

94+
private void ValidateMinimalRequestPayload(ServerlessPayload serverlessPayload)
95+
{
96+
var transactionEvent = serverlessPayload.Telemetry.TransactionEventsPayload.TransactionEvents.Single();
97+
98+
var expectedAgentAttributes = new[]
99+
{
100+
"aws.lambda.arn",
101+
"aws.requestId",
102+
"host.displayName"
103+
};
104+
105+
var expectedAgentAttributeValues = new Dictionary<string, object>
106+
{
107+
{ "aws.lambda.eventSource.eventType", "apiGateway" },
108+
{"request.method", "POST" },
109+
{"request.uri", "/path/to/resource" },
110+
{ "http.statusCode", 200 },
111+
{ "response.status", "200" },
112+
{ "response.headers.content-type", "application/json" },
113+
{ "response.headers.content-length", "12345" }
114+
};
115+
116+
Assert.Equal(_expectedTransactionName, transactionEvent.IntrinsicAttributes["name"]);
117+
118+
Assertions.TransactionEventHasAttributes(expectedAgentAttributes, TransactionEventAttributeType.Agent, transactionEvent);
119+
Assertions.TransactionEventHasAttributes(expectedAgentAttributeValues, TransactionEventAttributeType.Agent, transactionEvent);
120+
}
121+
91122
private void ValidateTraceHasNoParent(ServerlessPayload serverlessPayload)
92123
{
93124
var entrySpan = serverlessPayload.Telemetry.SpanEventsPayload.SpanEvents.Single(s => (string)s.IntrinsicAttributes["name"] == _expectedTransactionName);

tests/Agent/IntegrationTests/IntegrationTests/AwsLambda/AwsLambdaAPIGatewayRequestTest.cs

+39-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ protected AwsLambdaAPIGatewayProxyRequestTest(T fixture, ITestOutputHelper outpu
3434
{
3535
_fixture.EnqueueAPIGatewayProxyRequest();
3636
_fixture.EnqueueAPIGatewayProxyRequestWithDTHeaders(TestTraceId, TestParentSpanId);
37-
_fixture.AgentLog.WaitForLogLines(AgentLogBase.ServerlessPayloadLogLineRegex, TimeSpan.FromMinutes(1), 2);
37+
_fixture.EnqueueMinimalAPIGatewayProxyRequest();
38+
_fixture.AgentLog.WaitForLogLines(AgentLogBase.ServerlessPayloadLogLineRegex, TimeSpan.FromMinutes(1), 3);
3839
}
3940
);
4041
_fixture.Initialize();
@@ -46,8 +47,10 @@ public void Test()
4647
var serverlessPayloads = _fixture.AgentLog.GetServerlessPayloads().ToList();
4748

4849
Assert.Multiple(
49-
() => Assert.Equal(2, serverlessPayloads.Count),
50-
() => Assert.All(serverlessPayloads, ValidateServerlessPayload),
50+
() => Assert.Equal(3, serverlessPayloads.Count),
51+
// validate the first 2 payloads separately from the 3rd
52+
() => Assert.All(serverlessPayloads.GetRange(0, 2), ValidateServerlessPayload),
53+
() => ValidateMinimalRequestPayload(serverlessPayloads[2]),
5154
() => ValidateTraceHasNoParent(serverlessPayloads[0]),
5255
() => ValidateTraceHasParent(serverlessPayloads[1])
5356
);
@@ -97,7 +100,7 @@ private void ValidateServerlessPayload(ServerlessPayload serverlessPayload)
97100
expectedAgentAttributeValues.Add("response.status", "200");
98101
expectedAgentAttributeValues.Add("response.headers.content-type", "application/json");
99102
expectedAgentAttributeValues.Add("response.headers.content-length", "12345");
100-
};
103+
}
101104

102105
Assert.Equal(_expectedTransactionName, transactionEvent.IntrinsicAttributes["name"]);
103106

@@ -112,6 +115,38 @@ private void ValidateServerlessPayload(ServerlessPayload serverlessPayload)
112115
}
113116
}
114117

118+
private void ValidateMinimalRequestPayload(ServerlessPayload serverlessPayload)
119+
{
120+
var transactionEvent = serverlessPayload.Telemetry.TransactionEventsPayload.TransactionEvents.Single();
121+
122+
var expectedAgentAttributes = new[]
123+
{
124+
"aws.lambda.arn",
125+
"aws.requestId",
126+
"host.displayName"
127+
};
128+
129+
var expectedAgentAttributeValues = new Dictionary<string, object>
130+
{
131+
{ "aws.lambda.eventSource.eventType", "apiGateway" },
132+
{"request.method", "POST" },
133+
{"request.uri", "/path/to/resource" },
134+
};
135+
136+
if (!_returnsStream) // stream response type won't have response attributes
137+
{
138+
expectedAgentAttributeValues.Add("http.statusCode", 200);
139+
expectedAgentAttributeValues.Add("response.status", "200");
140+
expectedAgentAttributeValues.Add("response.headers.content-type", "application/json");
141+
expectedAgentAttributeValues.Add("response.headers.content-length", "12345");
142+
}
143+
144+
Assert.Equal(_expectedTransactionName, transactionEvent.IntrinsicAttributes["name"]);
145+
146+
Assertions.TransactionEventHasAttributes(expectedAgentAttributes, TransactionEventAttributeType.Agent, transactionEvent);
147+
Assertions.TransactionEventHasAttributes(expectedAgentAttributeValues, TransactionEventAttributeType.Agent, transactionEvent);
148+
}
149+
115150
private void ValidateTraceHasNoParent(ServerlessPayload serverlessPayload)
116151
{
117152
var entrySpan = serverlessPayload.Telemetry.SpanEventsPayload.SpanEvents.Single(s => (string)s.IntrinsicAttributes["name"] == _expectedTransactionName);

tests/Agent/IntegrationTests/IntegrationTests/RemoteServiceFixtures/AwsLambda/LambdaAPIGatewayHttpApiV2ProxyRequestTriggerFixture.cs

+22
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,28 @@ public void EnqueueAPIGatewayHttpApiV2ProxyRequestWithDTHeaders(string traceId,
181181
""";
182182
EnqueueLambdaEvent(apiGatewayProxyRequestJson);
183183
}
184+
185+
/// <summary>
186+
/// A minimal payload to validate the fix for https://github.com/newrelic/newrelic-dotnet-agent/issues/2528
187+
/// </summary>
188+
public void EnqueueMinimalAPIGatewayHttpApiV2ProxyRequest()
189+
{
190+
var apiGatewayProxyRequestJson = $$"""
191+
{
192+
"version": "2.0",
193+
"routeKey": "$default",
194+
"rawPath": "/path/to/resource",
195+
"requestContext": {
196+
"http": {
197+
"method": "POST",
198+
"path": "/path/to/resource"
199+
}
200+
},
201+
"body": "{\"test\":\"body\"}"
202+
}
203+
""";
204+
EnqueueLambdaEvent(apiGatewayProxyRequestJson);
205+
}
184206
}
185207

186208
public class LambdaAPIGatewayHttpApiV2ProxyRequestTriggerFixtureNet6 : LambdaAPIGatewayHttpApiV2ProxyRequestTriggerFixtureBase

tests/Agent/IntegrationTests/IntegrationTests/RemoteServiceFixtures/AwsLambda/LambdaAPIGatewayProxyRequestTriggerFixture.cs

+15
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,21 @@ public void EnqueueAPIGatewayProxyRequestWithDTHeaders(string traceId, string sp
151151
""";
152152
EnqueueLambdaEvent(apiGatewayProxyRequestJson);
153153
}
154+
155+
/// <summary>
156+
/// A minimal payload to validate the fix for https://github.com/newrelic/newrelic-dotnet-agent/issues/2528
157+
/// </summary>
158+
public void EnqueueMinimalAPIGatewayProxyRequest()
159+
{
160+
var apiGatewayProxyRequestJson = $$"""
161+
{
162+
"body": "{\"test\":\"body\"}",
163+
"path": "/path/to/resource",
164+
"httpMethod": "POST"
165+
}
166+
""";
167+
EnqueueLambdaEvent(apiGatewayProxyRequestJson);
168+
}
154169
}
155170

156171
public class LambdaAPIGatewayProxyRequestTriggerFixtureNet6 : LambdaAPIGatewayProxyRequestTriggerFixtureBase

0 commit comments

Comments
 (0)