Skip to content

Commit

Permalink
PR feedback, unit test update, code cleanup/formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
tippmar-nr committed Sep 20, 2024
1 parent 1771b62 commit 94d4855
Show file tree
Hide file tree
Showing 8 changed files with 617 additions and 601 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.0.1" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using Microsoft.AspNetCore.Http;
using NewRelic.Agent.Api;
using NewRelic.Agent.Extensions.Providers.Wrapper;

namespace NewRelic.Providers.Wrapper.AzureFunction;

public class FunctionsHttpProxyingMiddlewareWrapper : IWrapper
{
private const string WrapperName = "FunctionsHttpProxyingMiddlewareWrapper";
Expand All @@ -24,29 +25,26 @@ public AfterWrappedMethodDelegate BeforeWrappedMethod(InstrumentedMethodCall ins
{
if (agent.Configuration.AzureFunctionModeEnabled)
{
dynamic httpContext;
switch (instrumentedMethodCall.MethodCall.Method.MethodName)
{
case "AddHttpContextToFunctionContext":
var httpContext = (HttpContext)instrumentedMethodCall.MethodCall.MethodArguments[1];
httpContext = instrumentedMethodCall.MethodCall.MethodArguments[1];

agent.CurrentTransaction.SetRequestMethod(httpContext.Request.Method);
agent.CurrentTransaction.SetUri(httpContext.Request.Path);
break;
case "TryHandleHttpResult":
if (!agent.CurrentTransaction.HasHttpResponseStatusCode) // these handlers seem to get called more than once; only set the status code one time
{
object result = instrumentedMethodCall.MethodCall.MethodArguments[0];

httpContext = (HttpContext)instrumentedMethodCall.MethodCall.MethodArguments[2];
bool isInvocationResult = (bool)instrumentedMethodCall.MethodCall.MethodArguments[3];

httpContext = instrumentedMethodCall.MethodCall.MethodArguments[2];
agent.CurrentTransaction.SetHttpResponseStatusCode(httpContext.Response.StatusCode);
}
break;
case "TryHandleOutputBindingsHttpResult":
if (!agent.CurrentTransaction.HasHttpResponseStatusCode) // these handlers seem to get called more than once; only set the status code one time
{
httpContext = (HttpContext)instrumentedMethodCall.MethodCall.MethodArguments[1];
httpContext = instrumentedMethodCall.MethodCall.MethodArguments[1];
agent.CurrentTransaction.SetHttpResponseStatusCode(httpContext.Response.StatusCode);
}
break;
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
using NewRelic.Agent.IntegrationTests.RemoteServiceFixtures;
using Xunit.Abstractions;

namespace NewRelic.Agent.IntegrationTests.AzureFunction
namespace NewRelic.Agent.IntegrationTests.AzureFunction;

[NetCoreTest]
public class AzureFunctionInstrumentationDisabledTestsCoreLatest : AzureFunctionHttpTriggerTestsBase<AzureFunctionApplicationFixtureInstrumentationDisabledCoreLatest>
{
[NetCoreTest]
public class AzureFunctionInstrumentationDisabledTestsCoreLatest : AzureFunctionHttpTriggerTestsBase<AzureFunctionApplicationFixtureInstrumentationDisabledCoreLatest>
public AzureFunctionInstrumentationDisabledTestsCoreLatest(AzureFunctionApplicationFixtureInstrumentationDisabledCoreLatest fixture, ITestOutputHelper output)
: base(fixture, output, AzureFunctionHttpTriggerTestMode.AspNetCorePipeline) // test mode doesn't really matter here
{
public AzureFunctionInstrumentationDisabledTestsCoreLatest(AzureFunctionApplicationFixtureInstrumentationDisabledCoreLatest fixture, ITestOutputHelper output)
: base(fixture, output, AzureFunctionHttpTriggerTestMode.AspNetCorePipeline) // test mode doesn't really matter here
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,124 +9,123 @@
using Xunit;
using Xunit.Abstractions;

namespace NewRelic.Agent.IntegrationTests.AzureFunction
namespace NewRelic.Agent.IntegrationTests.AzureFunction;

public abstract class AzureFunctionQueueTriggerTestsBase<TFixture> : NewRelicIntegrationTest<TFixture>
where TFixture : AzureFunctionApplicationFixture
{
public abstract class AzureFunctionQueueTriggerTestsBase<TFixture> : NewRelicIntegrationTest<TFixture>
where TFixture : AzureFunctionApplicationFixture
{
private readonly TFixture _fixture;
private readonly TFixture _fixture;

protected AzureFunctionQueueTriggerTestsBase(TFixture fixture, ITestOutputHelper output) : base(fixture)
{
_fixture = fixture;
_fixture.TestLogger = output;

_fixture.AddActions(
setupConfiguration: () =>
{
new NewRelicConfigModifier(fixture.DestinationNewRelicConfigFilePath)
.ForceTransactionTraces()
.ConfigureFasterTransactionTracesHarvestCycle(20)
.ConfigureFasterMetricsHarvestCycle(15)
.ConfigureFasterSpanEventsHarvestCycle(15)
.SetLogLevel("finest");
},
exerciseApplication: () =>
{
_fixture.PostToAzureFuncTool("QueueTriggerFunction", "test message");
_fixture.AgentLog.WaitForLogLines(AgentLogBase.TransactionSampleLogLineRegex, TimeSpan.FromMinutes(2));
}
);

_fixture.Initialize();
}
protected AzureFunctionQueueTriggerTestsBase(TFixture fixture, ITestOutputHelper output) : base(fixture)
{
_fixture = fixture;
_fixture.TestLogger = output;

[Fact]
public void Test()
{
var transactionExpectedTransactionEventIntrinsicAttributes = new List<string>
{
"faas.coldStart",
"faas.invocation_id",
"faas.name",
"faas.trigger",
"cloud.resource_id"
};

var transactionTraceExpectedAttributes = new Dictionary<string, object>()
_fixture.AddActions(
setupConfiguration: () =>
{
{ "faas.coldStart", true},
//new("faas.invocation_id", "test_invocation_id"), This one is a random guid, not something we can specifically look for
{ "faas.name", "QueueTriggerFunction" },
{ "faas.trigger", "datasource" },
{ "cloud.resource_id", "/subscriptions/subscription_id/resourceGroups/my_resource_group/providers/Microsoft.Web/sites/IntegrationTestAppName/functions/QueueTriggerFunction" }
};

var transactionName = "OtherTransaction/AzureFunction/QueueTriggerFunction";
var expectedMetrics = new List<Assertions.ExpectedMetric>()
new NewRelicConfigModifier(fixture.DestinationNewRelicConfigFilePath)
.ForceTransactionTraces()
.ConfigureFasterTransactionTracesHarvestCycle(20)
.ConfigureFasterMetricsHarvestCycle(15)
.ConfigureFasterSpanEventsHarvestCycle(15)
.SetLogLevel("finest");
},
exerciseApplication: () =>
{
new() {metricName = "DotNet/QueueTriggerFunction", callCount = 1},
new() {metricName = "DotNet/QueueTriggerFunction", metricScope = transactionName, callCount = 1},
new() {metricName = transactionName, callCount = 1},
};
_fixture.PostToAzureFuncTool("QueueTriggerFunction", "test message");
_fixture.AgentLog.WaitForLogLines(AgentLogBase.TransactionSampleLogLineRegex, TimeSpan.FromMinutes(2));
}
);

var transactionSample = _fixture.AgentLog.TryGetTransactionSample(transactionName);
_fixture.Initialize();
}

var metrics = _fixture.AgentLog.GetMetrics().ToList();
[Fact]
public void Test()
{
var transactionExpectedTransactionEventIntrinsicAttributes = new List<string>
{
"faas.coldStart",
"faas.invocation_id",
"faas.name",
"faas.trigger",
"cloud.resource_id"
};

var transactionTraceExpectedAttributes = new Dictionary<string, object>()
{
{ "faas.coldStart", true},
//new("faas.invocation_id", "test_invocation_id"), This one is a random guid, not something we can specifically look for
{ "faas.name", "QueueTriggerFunction" },
{ "faas.trigger", "datasource" },
{ "cloud.resource_id", "/subscriptions/subscription_id/resourceGroups/my_resource_group/providers/Microsoft.Web/sites/IntegrationTestAppName/functions/QueueTriggerFunction" }
};

var transactionName = "OtherTransaction/AzureFunction/QueueTriggerFunction";
var expectedMetrics = new List<Assertions.ExpectedMetric>()
{
new() {metricName = "DotNet/QueueTriggerFunction", callCount = 1},
new() {metricName = "DotNet/QueueTriggerFunction", metricScope = transactionName, callCount = 1},
new() {metricName = transactionName, callCount = 1},
};

var transaction = _fixture.AgentLog.TryGetTransactionEvent(transactionName);

if (_fixture.AzureFunctionModeEnabled)
{
Assertions.MetricsExist(expectedMetrics, metrics);
var transactionSample = _fixture.AgentLog.TryGetTransactionSample(transactionName);

Assert.NotNull(transactionSample);
Assert.NotNull(transaction);
var metrics = _fixture.AgentLog.GetMetrics().ToList();

Assertions.TransactionTraceHasAttributes(transactionTraceExpectedAttributes, Tests.TestSerializationHelpers.Models.TransactionTraceAttributeType.Intrinsic, transactionSample);
var transaction = _fixture.AgentLog.TryGetTransactionEvent(transactionName);

Assertions.TransactionEventHasAttributes(transactionExpectedTransactionEventIntrinsicAttributes, Tests.TestSerializationHelpers.Models.TransactionEventAttributeType.Intrinsic, transaction);
if (_fixture.AzureFunctionModeEnabled)
{
Assertions.MetricsExist(expectedMetrics, metrics);

Assert.True(transaction.IntrinsicAttributes.TryGetValue("cloud.resource_id", out var cloudResourceIdValue));
Assert.Equal("/subscriptions/subscription_id/resourceGroups/my_resource_group/providers/Microsoft.Web/sites/IntegrationTestAppName/functions/QueueTriggerFunction", cloudResourceIdValue);
Assert.True(transaction.IntrinsicAttributes.TryGetValue("faas.name", out var faasNameValue));
Assert.Equal("QueueTriggerFunction", faasNameValue);
Assert.True(transaction.IntrinsicAttributes.TryGetValue("faas.trigger", out var faasTriggerValue));
Assert.Equal("datasource", faasTriggerValue);
}
else
{
Assertions.MetricsDoNotExist(expectedMetrics, metrics);
Assert.Null(transactionSample);
Assert.NotNull(transactionSample);
Assert.NotNull(transaction);

Assert.Null(transaction);
}
Assertions.TransactionTraceHasAttributes(transactionTraceExpectedAttributes, Tests.TestSerializationHelpers.Models.TransactionTraceAttributeType.Intrinsic, transactionSample);

if (!_fixture.AzureFunctionModeEnabled) // look for a specific log line that indicates azure function mode is disabled
{
var disabledLogLine = _fixture.AgentLog.TryGetLogLine(AgentLogBase.AzureFunctionModeDisabledLogLineRegex);
Assert.NotNull(disabledLogLine);
}
Assertions.TransactionEventHasAttributes(transactionExpectedTransactionEventIntrinsicAttributes, Tests.TestSerializationHelpers.Models.TransactionEventAttributeType.Intrinsic, transaction);

Assert.True(transaction.IntrinsicAttributes.TryGetValue("cloud.resource_id", out var cloudResourceIdValue));
Assert.Equal("/subscriptions/subscription_id/resourceGroups/my_resource_group/providers/Microsoft.Web/sites/IntegrationTestAppName/functions/QueueTriggerFunction", cloudResourceIdValue);
Assert.True(transaction.IntrinsicAttributes.TryGetValue("faas.name", out var faasNameValue));
Assert.Equal("QueueTriggerFunction", faasNameValue);
Assert.True(transaction.IntrinsicAttributes.TryGetValue("faas.trigger", out var faasTriggerValue));
Assert.Equal("datasource", faasTriggerValue);
}
}
else
{
Assertions.MetricsDoNotExist(expectedMetrics, metrics);
Assert.Null(transactionSample);

[NetCoreTest]
public class AzureFunctionQueueTriggerTestsCoreOldest : AzureFunctionQueueTriggerTestsBase<AzureFunctionApplicationFixtureQueueTriggerCoreOldest>
{
public AzureFunctionQueueTriggerTestsCoreOldest(AzureFunctionApplicationFixtureQueueTriggerCoreOldest fixture, ITestOutputHelper output)
: base(fixture, output)
Assert.Null(transaction);
}

if (!_fixture.AzureFunctionModeEnabled) // look for a specific log line that indicates azure function mode is disabled
{
var disabledLogLine = _fixture.AgentLog.TryGetLogLine(AgentLogBase.AzureFunctionModeDisabledLogLineRegex);
Assert.NotNull(disabledLogLine);
}
}
}

[NetCoreTest]
public class AzureFunctionQueueTriggerTestsCoreLatest : AzureFunctionQueueTriggerTestsBase<AzureFunctionApplicationFixtureQueueTriggerCoreLatest>
[NetCoreTest]
public class AzureFunctionQueueTriggerTestsCoreOldest : AzureFunctionQueueTriggerTestsBase<AzureFunctionApplicationFixtureQueueTriggerCoreOldest>
{
public AzureFunctionQueueTriggerTestsCoreOldest(AzureFunctionApplicationFixtureQueueTriggerCoreOldest fixture, ITestOutputHelper output)
: base(fixture, output)
{
}
}

[NetCoreTest]
public class AzureFunctionQueueTriggerTestsCoreLatest : AzureFunctionQueueTriggerTestsBase<AzureFunctionApplicationFixtureQueueTriggerCoreLatest>
{
public AzureFunctionQueueTriggerTestsCoreLatest(AzureFunctionApplicationFixtureQueueTriggerCoreLatest fixture, ITestOutputHelper output)
: base(fixture, output)
{
public AzureFunctionQueueTriggerTestsCoreLatest(AzureFunctionApplicationFixtureQueueTriggerCoreLatest fixture, ITestOutputHelper output)
: base(fixture, output)
{
}
}
}
Loading

0 comments on commit 94d4855

Please sign in to comment.