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

Feature work: Added QueueTrigger function to integration tests #2745

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ public static string ResolveTriggerType(this string triggerTypeName)
resolvedTriggerType = "http";
break;

case "DaprServiceInvocation": // RPC call to another Dapr service - no groupm so other.
case "DaprServiceInvocation": // RPC call to another Dapr service - no group so other.
resolvedTriggerType = "other";
break;
default:
resolvedTriggerType = "other";
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
Expand All @@ -23,9 +23,11 @@
</ItemGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<None Include="local.settings.json" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.23.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.2.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.3.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues" Version="5.5.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.4" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace AzureFunctionApplication
{
public class QueueTriggerFunction
{

private readonly ILogger<QueueTriggerFunction> _logger;

public QueueTriggerFunction(ILogger<QueueTriggerFunction> logger)
{
_logger = logger;
}

[Function("QueueTriggerFunction")]
public void Run([QueueTrigger("my-queue")] string message)
{
_logger.LogInformation($"C# Queue trigger function processed: {message}");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ public AzureFuncTool(string applicationDirectoryName, string targetFramework, Ap
_enableAzureFunctionMode = enableAzureFunctionMode;
}

public override void CopyToRemote()
{
base.CopyToRemote();

// copy local.settings.json from the AzureFunctionApplication project to destination app folder
var deployPath = Path.Combine(DestinationRootDirectoryPath, ApplicationDirectoryName, "local.settings.json");
var localSettingsPath = Path.Combine(SourceApplicationDirectoryPath, "local.settings.json");

File.Copy(localSettingsPath, deployPath, true);
}

public override void Start(string commandLineArguments, Dictionary<string, string> environmentVariables, bool captureStandardOutput = false, bool doProfile = true)
{
var arguments = UsesSpecificPort
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,18 @@ protected void GetAndAssertSuccessStatus(string address, bool expectedSuccessSta
}
}
}

protected void PostJson(string address, string payload)
{
var content = new StringContent(payload);

content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

var result = _httpClient.PostAsync(address, content).GetAwaiter().GetResult();

Assert.True(result.IsSuccessStatusCode);
}

}


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

using System;
using System.Collections.Generic;
using System.Linq;
using NewRelic.Agent.IntegrationTestHelpers;
using NewRelic.Agent.IntegrationTests.RemoteServiceFixtures;
using Xunit;
using Xunit.Abstractions;

namespace NewRelic.Agent.IntegrationTests.AzureFunction
{
public abstract class AzureFunctionQueueTriggerTestsBase<TFixture> : NewRelicIntegrationTest<TFixture>
where TFixture : AzureFunctionApplicationFixture
{
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();
}

[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, string>()
{
{ "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 transactionSample = _fixture.AgentLog.TryGetTransactionSample(transactionName);

var metrics = _fixture.AgentLog.GetMetrics().ToList();

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

if (_fixture.AzureFunctionModeEnabled)
{
Assertions.MetricsExist(expectedMetrics, metrics);

Assert.NotNull(transactionSample);
Assert.NotNull(transaction);

Assertions.TransactionTraceHasAttributes(transactionTraceExpectedAttributes, Tests.TestSerializationHelpers.Models.TransactionTraceAttributeType.Intrinsic, transactionSample);

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);

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 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)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ public string Get(string endpoint)
return GetString(address);
}

public void PostToAzureFuncTool(string triggerName, string payload)
{
var address = $"http://{DestinationServerName}:{Port}/admin/functions/{triggerName}";

var inputPayload = $$"""{"input":"{{payload}}"}""";
PostJson(address, inputPayload);
}

public bool AzureFunctionModeEnabled { get; }
}

Expand All @@ -51,4 +59,17 @@ public AzureFunctionApplicationFixtureInstrumentationDisabledCoreLatest() : base
{
}
}

public class AzureFunctionApplicationFixtureQueueTriggerCoreOldest : AzureFunctionApplicationFixture
{
public AzureFunctionApplicationFixtureQueueTriggerCoreOldest() : base("queueTriggerFunction", "net6.0", true)
{
}
}
public class AzureFunctionApplicationFixtureQueueTriggerCoreLatest : AzureFunctionApplicationFixture
{
public AzureFunctionApplicationFixtureQueueTriggerCoreLatest() : base("queueTriggerFunction", "net8.0", true)
{
}
}
}
Loading