-
Notifications
You must be signed in to change notification settings - Fork 206
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Azure App Service Metadata gherkin spec (#1221)
This commit adds the scenario implementations for testing the collection of Azure App Service Metadata. EnvironmentHelper is changed to IEnvironmentVariables, to introduce a test seam for environment variables, to isolate the manipulation of environment variables to tests. Update AzureAppServiceMetadataProvider to handle the additional test case. Co-authored-by: Russ Cam <[email protected]> Co-authored-by: Gergely Kalapos <[email protected]>
- Loading branch information
1 parent
26ebf44
commit d9c163f
Showing
9 changed files
with
303 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Licensed to Elasticsearch B.V under | ||
// one or more agreements. | ||
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. | ||
// See the LICENSE file in the project root for more information | ||
|
||
using System; | ||
using System.Collections; | ||
using Elastic.Apm.Logging; | ||
|
||
namespace Elastic.Apm.Helpers | ||
{ | ||
internal interface IEnvironmentVariables | ||
{ | ||
IDictionary GetEnvironmentVariables(); | ||
} | ||
|
||
internal sealed class EnvironmentVariables : IEnvironmentVariables | ||
{ | ||
private readonly IApmLogger _logger; | ||
public EnvironmentVariables(IApmLogger logger) => _logger = logger.Scoped(nameof(EnvironmentVariables)); | ||
|
||
public IDictionary GetEnvironmentVariables() | ||
{ | ||
try | ||
{ | ||
return Environment.GetEnvironmentVariables(); | ||
} | ||
catch (Exception e) | ||
{ | ||
_logger.Error()?.LogException(e, "could not get environment variables"); | ||
return null; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// Licensed to Elasticsearch B.V under | ||
// one or more agreements. | ||
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. | ||
// See the LICENSE file in the project root for more information | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Net; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using Elastic.Apm.Api; | ||
using Elastic.Apm.Logging; | ||
using Elastic.Apm.Report; | ||
using Elastic.Apm.Tests.Utilities; | ||
using Elastic.Apm.Tests.Utilities.XUnit; | ||
using FluentAssertions; | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Linq; | ||
using RichardSzalay.MockHttp; | ||
using TechTalk.SpecFlow; | ||
using Xunit.Abstractions; | ||
using static Elastic.Apm.BackendComm.BackendCommUtils.ApmServerEndpoints; | ||
using MockHttpMessageHandler = RichardSzalay.MockHttp.MockHttpMessageHandler; | ||
|
||
namespace Elastic.Apm.Feature.Tests | ||
{ | ||
[Binding] | ||
public class CloudProviderSteps | ||
{ | ||
private static readonly JsonSerializer _serializer = new JsonSerializer(); | ||
private readonly ScenarioContext _scenarioContext; | ||
|
||
public CloudProviderSteps(ScenarioContext scenarioContext) => _scenarioContext = scenarioContext; | ||
|
||
[Given(@"^an instrumented application is configured to collect cloud provider metadata for (.*?)$")] | ||
public void AgentWithCloudMetadata(string cloudProvider) | ||
{ | ||
var output = _scenarioContext.ScenarioContainer.Resolve<ITestOutputHelper>(); | ||
var logger = new XUnitLogger(LogLevel.Trace, output); | ||
var config = new MockConfigSnapshot(logger, cloudProvider: cloudProvider); | ||
|
||
var payloadCollector = new PayloadCollector(); | ||
_scenarioContext.Set(payloadCollector); | ||
|
||
var handler = new MockHttpMessageHandler(); | ||
handler.When(BuildIntakeV2EventsAbsoluteUrl(config.ServerUrl).AbsoluteUri) | ||
.Respond(r => | ||
{ | ||
var json = r.Content.ReadAsStringAsync().Result; | ||
if (json.Contains("\"metadata\"")) | ||
{ | ||
payloadCollector.Request = ParseJObjects(json); | ||
payloadCollector.WaitHandle.Set(); | ||
} | ||
|
||
return new HttpResponseMessage(HttpStatusCode.OK); | ||
}); | ||
|
||
var environmentVariables = new TestEnvironmentVariables(); | ||
_scenarioContext.Set(environmentVariables); | ||
|
||
var payloadSender = new PayloadSenderV2( | ||
logger, | ||
config, | ||
Service.GetDefaultService(config, new NoopLogger()), | ||
new Api.System(), | ||
MockApmServerInfo.Version710, | ||
handler, | ||
environmentVariables: environmentVariables); | ||
|
||
var lazyAgent = new Lazy<ApmAgent>(() => | ||
new ApmAgent(new TestAgentComponents(logger, config, payloadSender))); | ||
|
||
_scenarioContext.Set(lazyAgent); | ||
} | ||
|
||
[Given("^the following environment variables are present$")] | ||
public void EnvironmentVariablesSet(Table table) | ||
{ | ||
var environmentVariables = _scenarioContext.Get<TestEnvironmentVariables>(); | ||
|
||
foreach(var row in table.Rows) | ||
environmentVariables[row[0]] = row[1]; | ||
} | ||
|
||
[When("^cloud metadata is collected$")] | ||
public void CollectCloudMetadata() | ||
{ | ||
var lazyAgent = _scenarioContext.Get<Lazy<ApmAgent>>(); | ||
// create the agent and capture a transaction to send metadata | ||
var agent = lazyAgent.Value; | ||
agent.Tracer.CaptureTransaction("Transaction", "feature", () => { }); | ||
|
||
var payloadCollector = _scenarioContext.Get<PayloadCollector>(); | ||
|
||
// wait for the wait handle to be signalled | ||
var timeout = TimeSpan.FromSeconds(30); | ||
if (!payloadCollector.WaitHandle.Wait(timeout)) | ||
throw new Exception($"Did not receive payload within {timeout}"); | ||
} | ||
|
||
[Then("^cloud metadata is not null$")] | ||
public void CloudMetadataIsNotNull() | ||
{ | ||
var payloadCollector = _scenarioContext.Get<PayloadCollector>(); | ||
|
||
payloadCollector.Request.Should().NotBeNull(); | ||
var cloudMetadata = payloadCollector.Request[0]["metadata"]["cloud"]; | ||
cloudMetadata.Should().NotBeNull(); | ||
} | ||
|
||
[Then("^cloud metadata is null$")] | ||
public void CloudMetadataIsNull() | ||
{ | ||
var payloadCollector = _scenarioContext.Get<PayloadCollector>(); | ||
|
||
payloadCollector.Request.Should().NotBeNull(); | ||
var cloudMetadata = payloadCollector.Request[0]["metadata"]["cloud"]; | ||
cloudMetadata.Should().BeNull(); | ||
} | ||
|
||
[Then("^cloud metadata '(.*?)' is '(.*?)'$")] | ||
public void CloudMetadataKeyEqualsValue(string key, string value) | ||
{ | ||
var payloadCollector = _scenarioContext.Get<PayloadCollector>(); | ||
var token = payloadCollector.Request[0].SelectToken($"metadata.cloud.{key}"); | ||
|
||
token.Should().NotBeNull(); | ||
token.Value<string>().Should().Be(value); | ||
} | ||
|
||
private class PayloadCollector | ||
{ | ||
public ManualResetEventSlim WaitHandle { get; } | ||
|
||
public PayloadCollector() => WaitHandle = new ManualResetEventSlim(false); | ||
|
||
public List<JObject> Request { get; set; } | ||
} | ||
|
||
private static List<JObject> ParseJObjects(string json) | ||
{ | ||
var jObjects = new List<JObject>(); | ||
using var stringReader = new StringReader(json); | ||
using var jsonReader = new JsonTextReader(stringReader) { SupportMultipleContent = true }; | ||
while (jsonReader.Read()) | ||
jObjects.Add(_serializer.Deserialize<JObject>(jsonReader)); | ||
return jObjects; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
test/Elastic.Apm.Feature.Tests/Features/azure_app_service_metadata.feature
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
Feature: Extracting Metadata for Azure App Service | ||
|
||
Background: | ||
Given an instrumented application is configured to collect cloud provider metadata for azure | ||
|
||
Scenario Outline: Azure App Service with all environment variables present in expected format | ||
Given the following environment variables are present | ||
| name | value | | ||
| WEBSITE_OWNER_NAME | <WEBSITE_OWNER_NAME> | | ||
| WEBSITE_RESOURCE_GROUP | resource_group | | ||
| WEBSITE_SITE_NAME | site_name | | ||
| WEBSITE_INSTANCE_ID | instance_id | | ||
When cloud metadata is collected | ||
Then cloud metadata is not null | ||
And cloud metadata 'account.id' is 'f5940f10-2e30-3e4d-a259-63451ba6dae4' | ||
And cloud metadata 'provider' is 'azure' | ||
And cloud metadata 'instance.id' is 'instance_id' | ||
And cloud metadata 'instance.name' is 'site_name' | ||
And cloud metadata 'project.name' is 'resource_group' | ||
And cloud metadata 'region' is 'AustraliaEast' | ||
Examples: | ||
| WEBSITE_OWNER_NAME | | ||
| f5940f10-2e30-3e4d-a259-63451ba6dae4+elastic-apm-AustraliaEastwebspace | | ||
| f5940f10-2e30-3e4d-a259-63451ba6dae4+appsvc_linux_australiaeast-AustraliaEastwebspace-Linux | | ||
|
||
# WEBSITE_OWNER_NAME is expected to include a + character | ||
Scenario: WEBSITE_OWNER_NAME environment variable not expected format | ||
Given the following environment variables are present | ||
| name | value | | ||
| WEBSITE_OWNER_NAME | f5940f10-2e30-3e4d-a259-63451ba6dae4-elastic-apm-AustraliaEastwebspace | | ||
| WEBSITE_RESOURCE_GROUP | resource_group | | ||
| WEBSITE_SITE_NAME | site_name | | ||
| WEBSITE_INSTANCE_ID | instance_id | | ||
When cloud metadata is collected | ||
Then cloud metadata is null | ||
|
||
Scenario: Missing WEBSITE_OWNER_NAME environment variable | ||
Given the following environment variables are present | ||
| name | value | | ||
| WEBSITE_RESOURCE_GROUP | resource_group | | ||
| WEBSITE_SITE_NAME | site_name | | ||
| WEBSITE_INSTANCE_ID | instance_id | | ||
When cloud metadata is collected | ||
Then cloud metadata is null | ||
|
||
Scenario: Missing WEBSITE_RESOURCE_GROUP environment variable | ||
Given the following environment variables are present | ||
| name | value | | ||
| WEBSITE_OWNER_NAME | f5940f10-2e30-3e4d-a259-63451ba6dae4+elastic-apm-AustraliaEastwebspace | | ||
| WEBSITE_SITE_NAME | site_name | | ||
| WEBSITE_INSTANCE_ID | instance_id | | ||
When cloud metadata is collected | ||
Then cloud metadata is null | ||
|
||
Scenario: Missing WEBSITE_SITE_NAME environment variable | ||
Given the following environment variables are present | ||
| name | value | | ||
| WEBSITE_OWNER_NAME | f5940f10-2e30-3e4d-a259-63451ba6dae4+elastic-apm-AustraliaEastwebspace | | ||
| WEBSITE_RESOURCE_GROUP | resource_group | | ||
| WEBSITE_INSTANCE_ID | instance_id | | ||
When cloud metadata is collected | ||
Then cloud metadata is null | ||
|
||
Scenario: Missing WEBSITE_INSTANCE_ID environment variable | ||
Given the following environment variables are present | ||
| name | value | | ||
| WEBSITE_OWNER_NAME | f5940f10-2e30-3e4d-a259-63451ba6dae4+elastic-apm-AustraliaEastwebspace | | ||
| WEBSITE_RESOURCE_GROUP | resource_group | | ||
| WEBSITE_SITE_NAME | site_name | | ||
When cloud metadata is collected | ||
Then cloud metadata is null |
Oops, something went wrong.