Skip to content
This repository was archived by the owner on Jul 5, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
514aa15
Add heartbeat provider for Azure App Services (in particular, Web App…
d3r3kk Mar 26, 2018
e9c2d47
Move new TelemetryModule AppServicesHeartbeat out of Web package and …
d3r3kk Mar 27, 2018
f2bd436
Fix stylecop issues
d3r3kk Mar 28, 2018
53fba65
Update for PR suggestions
d3r3kk Mar 28, 2018
710d4bb
Fix for build - stylecop
d3r3kk Mar 28, 2018
d4a21c3
Add monitor to keep track of current value of App Services env vars
d3r3kk Mar 30, 2018
0c261da
Add tests, clean up AppServiceHearbeatModule class (unused variables)…
d3r3kk Mar 30, 2018
fc44730
Fix for installed modules count test
d3r3kk Mar 30, 2018
aab6721
Correct perf issues and suggestions from PR, add tests
d3r3kk Mar 30, 2018
86911c0
Make container of env vars cached into a readonly member
d3r3kk Mar 30, 2018
9c407f9
Update AzureWebAppRoleEnvironmentTelemetryInitializer to use the AppS…
d3r3kk Mar 30, 2018
3f31500
Re-add the WindowsServer.Shared.Tests shared project into the Windows…
d3r3kk Apr 2, 2018
cb857fb
Merge PR #869 and #870 into a single PR for submission to 2.6.0-beta3
d3r3kk Apr 2, 2018
1635111
Merge PR #870 and #869, regarding heartbeat providers for App Services
d3r3kk Apr 2, 2018
1bbe3a2
Fix tests to allow for parallel testing of methods that alter environ…
d3r3kk Apr 3, 2018
da7e4d0
Finish merging PR #869 and #870
d3r3kk Apr 3, 2018
275271a
Cleanup of some comments and usings
d3r3kk Apr 3, 2018
09a28fb
Update file name for tests to match module being tested
d3r3kk Apr 3, 2018
f4487c9
For App Services heartbeats, handle detected environment variable cha…
d3r3kk Apr 3, 2018
e173905
Separate the environment variable monitor from the App Services envir…
d3r3kk Apr 3, 2018
571f92e
Construct tests for the subscriber-model environment variable monitor
d3r3kk Apr 3, 2018
8a1c079
Update tests for AzureWebRoleEnvironmentTelemetryInitializer module
d3r3kk Apr 3, 2018
43d6bc8
PR suggestion: Correct access level of abstract class EnvironmentVari…
d3r3kk Apr 3, 2018
3f9cc36
PR Suggestions
d3r3kk Apr 4, 2018
87c1fd7
Fix PR CI Build break due to StyleCop rules
d3r3kk Apr 4, 2018
74cb7d5
PR Suggestions: Disable monitor if we don't detect that we are in Azu…
d3r3kk Apr 4, 2018
13715bc
PR Suggestion: Correct AppServicesEnvVarMonitor to properly follow C#…
d3r3kk Apr 4, 2018
d31e0e9
PR Suggestion: Handle exceptions during timer callback for environmen…
d3r3kk Apr 4, 2018
50e876f
PR suggestions/fixes for tests and log warnings
d3r3kk Apr 4, 2018
be1ffe6
Ensure test for updated environment values operates correctly
d3r3kk Apr 4, 2018
c61fb45
PR Suggestion: Change informational message to warning.
d3r3kk Apr 5, 2018
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
- `BuildInfoConfigComponentVersionTelemetryInitializer`
- `DeveloperModeWithDebuggerAttachedTelemetryModule`
- `UnobservedExceptionTelemetryModule`

- [Add default heartbeat properties for Azure App Services (web apps).](https://github.com/Microsoft/ApplicationInsights-dotnet-server/issues/868)

## Version 2.6.0-beta2
- [Added a max length restriction to values passed in through requests.](https://github.com/Microsoft/ApplicationInsights-dotnet-server/pull/810)
Expand Down
1 change: 1 addition & 0 deletions Src/Microsoft.ApplicationInsights.Web.sln
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ Global
Common\Common.projitems*{ea2d14aa-ae1e-4982-9326-11d4dcbb9529}*SharedItemsImports = 4
DependencyCollector\Shared\DependencyCollector.Shared.projitems*{ea2d14aa-ae1e-4982-9326-11d4dcbb9529}*SharedItemsImports = 4
TestFramework\Shared\TestFramework.Shared.projitems*{f05eb480-b209-47dd-90e3-1ddc47efc579}*SharedItemsImports = 4
WindowsServer\WindowsServer.Shared.Tests\WindowsServer.Shared.Tests.projitems*{f05eb480-b209-47dd-90e3-1ddc47efc579}*SharedItemsImports = 4
PerformanceCollector\Perf.Shared.Tests\Perf.Shared.Tests.projitems*{f254d4fb-428d-408e-8251-39bca7b4b5ce}*SharedItemsImports = 4
TestFramework\Shared\TestFramework.Shared.projitems*{f254d4fb-428d-408e-8251-39bca7b4b5ce}*SharedItemsImports = 4
TestFramework\Shared\TestFramework.Shared.projitems*{f71138bb-b3f8-4767-b394-857b0776038e}*SharedItemsImports = 4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'Common.targets'))\Common.targets" />
<Import Project="..\..\TestFramework\Shared\TestFramework.Shared.projitems" Label="Shared" />
<Import Project="..\WindowsServer.Shared.Tests\WindowsServer.Shared.Tests.projitems" Label="Shared" />
<Import Project="..\..\..\..\packages\StyleCop.MSBuild.5.0.0\build\StyleCop.MSBuild.targets" Condition="Exists('..\..\..\..\packages\StyleCop.MSBuild.5.0.0\build\StyleCop.MSBuild.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void InstallDoesNotInstallExtraModules()

Type typeToFind = typeof(FirstChanceExceptionStatisticsTelemetryModule);

Assert.AreEqual(4, ConfigurationHelpers.GetTelemetryModules(configAfterTransform).Descendants().Count());
Assert.AreEqual(5, ConfigurationHelpers.GetTelemetryModules(configAfterTransform).Descendants().Count());
}

[TestMethod]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</TelemetryInitializers>

<TelemetryModules xdt:Transform="InsertIfMissing">
<Add xdt:Transform="InsertIfMissing" xdt:Locator="Match(Type)" Type="Microsoft.ApplicationInsights.WindowsServer.AppServicesHeartbeatTelemetryModule, Microsoft.AI.WindowsServer" />
<Add xdt:Transform="InsertIfMissing" xdt:Locator="Match(Type)" Type="Microsoft.ApplicationInsights.WindowsServer.AzureInstanceMetadataTelemetryModule, Microsoft.AI.WindowsServer">
<!--
Remove individual fields collected here by adding them to the ApplicationInsighs.HeartbeatProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<TelemetryInitializers xdt:Transform="Remove" xdt:Locator="Condition(count(*)=0)"/>

<TelemetryModules>
<Add xdt:Transform="Remove" xdt:Locator="Match(Type)" Type="Microsoft.ApplicationInsights.WindowsServer.AppServicesHeartbeatTelemetryModule, Microsoft.AI.WindowsServer" />
<Add xdt:Transform="Remove" xdt:Locator="Match(Type)" Type="Microsoft.ApplicationInsights.WindowsServer.AzureInstanceMetadataTelemetryModule, Microsoft.AI.WindowsServer" />
<Add xdt:Transform="Remove" xdt:Locator="Match(Type)" Type="Microsoft.ApplicationInsights.WindowsServer.DeveloperModeWithDebuggerAttachedTelemetryModule, Microsoft.AI.WindowsServer" />
<Add xdt:Transform="Remove" xdt:Locator="Match(Type)" Type="Microsoft.ApplicationInsights.WindowsServer.UnhandledExceptionTelemetryModule, Microsoft.AI.WindowsServer" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
namespace Microsoft.ApplicationInsights.WindowsServer
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.WindowsServer.Implementation;
using Microsoft.ApplicationInsights.WindowsServer.Implementation.DataContracts;
using Microsoft.ApplicationInsights.WindowsServer.Mock;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Assert = Xunit.Assert;

[TestClass]
public class AppServicesHeartbeatTelemetryModuleTests
{
private HeartbeatProviderMock testHeartbeatPropertyManager;
private AppServicesHeartbeatTelemetryModule testAppServiceHbeatModule;
private Dictionary<string, string> testEnvironmentVariables;

[TestInitialize]
public void BeforeEachTestMethod()
{
this.testHeartbeatPropertyManager = new HeartbeatProviderMock();
this.testAppServiceHbeatModule = this.GetAppServiceHeartbeatModuleWithUniqueTestEnvVars(this.testHeartbeatPropertyManager);
this.testEnvironmentVariables = this.GetEnvVarsAssociatedToModule(this.testAppServiceHbeatModule);
}

[TestCleanup]
public void AfterEachTestMethod()
{
this.RemoveTestEnvVarsAssociatedToModule(this.testAppServiceHbeatModule);
}

[TestMethod]
public void InitializeIsWorking()
{
this.testAppServiceHbeatModule.Initialize(null);

foreach (var kvp in this.testAppServiceHbeatModule.WebHeartbeatPropertyNameEnvVarMap)
{
Assert.True(this.testHeartbeatPropertyManager.HbeatProps.ContainsKey(kvp.Key));
Assert.Equal(this.testHeartbeatPropertyManager.HbeatProps[kvp.Key], this.testEnvironmentVariables[kvp.Value]);
}
}

[TestMethod]
[Description("This test causes a delay and must be updated to be more deterministic.")]
[Owner("dekeeler")]
public void UpdateEnvVarsWorksWhenEnvironmentValuesChange()
{
this.testAppServiceHbeatModule.Initialize(null);

// update each environment variable to have a different value
foreach (var envVarKvp in this.testEnvironmentVariables)
{
string newVal = string.Concat(envVarKvp.Value, "_1");
Environment.SetEnvironmentVariable(envVarKvp.Key, newVal);
}

// wait for the delay set into the monitor, plus one second to ensure we got updated
Task.Delay(
AppServiceEnvironmentVariableMonitor.Instance.MonitorInterval + TimeSpan.FromSeconds(1))
.ConfigureAwait(false).GetAwaiter().GetResult();

var updatedEnvVars = this.GetEnvVarsAssociatedToModule(this.testAppServiceHbeatModule);

foreach (var kvp in this.testAppServiceHbeatModule.WebHeartbeatPropertyNameEnvVarMap)
{
Assert.True(this.testHeartbeatPropertyManager.HbeatProps.ContainsKey(kvp.Key));
Assert.Equal(this.testHeartbeatPropertyManager.HbeatProps[kvp.Key], updatedEnvVars[kvp.Value]);
}
}

[TestMethod]
public void NoHeartbeatManagerAvailableDoesntThrow()
{
var appSrvHbeatModule = new AppServicesHeartbeatTelemetryModule();
var envVars = this.GetEnvVarsAssociatedToModule(appSrvHbeatModule);

try
{
appSrvHbeatModule.Initialize(null);
}
catch (Exception any)
{
Assert.False(any == null);
}
}

[TestMethod]
public void NoAppServicesEnvVarsWorksWithoutFailure()
{
// ensure all environment variables are set to nothing (remove them from the environment)
this.RemoveTestEnvVarsAssociatedToModule(this.testAppServiceHbeatModule);

this.testAppServiceHbeatModule.UpdateHeartbeatWithAppServiceEnvVarValues();
foreach (var kvp in this.testAppServiceHbeatModule.WebHeartbeatPropertyNameEnvVarMap)
{
Assert.Null(this.testHeartbeatPropertyManager.HbeatProps[kvp.Key]);
}
}

/// <summary>
/// Return a dictionary containing the expected environment variables for the AppServicesHeartbeat module. If
/// the environment does not contain a value for them, set the environment to have them.
/// </summary>
/// <returns>Dictionary with expected environment variable names as the key, current environment variable content as the value.</returns>
private Dictionary<string, string> GetEnvVarsAssociatedToModule(AppServicesHeartbeatTelemetryModule testAppServicesHeartbeatModule)
{
Dictionary<string, string> uniqueTestEnvironmentVariables = new Dictionary<string, string>();
foreach (var kvp in testAppServicesHeartbeatModule.WebHeartbeatPropertyNameEnvVarMap)
{
uniqueTestEnvironmentVariables.Add(kvp.Value, Environment.GetEnvironmentVariable(kvp.Value));
if (string.IsNullOrEmpty(uniqueTestEnvironmentVariables[kvp.Value]))
{
Environment.SetEnvironmentVariable(kvp.Value, kvp.Key);
uniqueTestEnvironmentVariables[kvp.Value] = kvp.Key;
}
}

return uniqueTestEnvironmentVariables;
}

private AppServicesHeartbeatTelemetryModule GetAppServiceHeartbeatModuleWithUniqueTestEnvVars(HeartbeatProviderMock heartbeatProvider)
{
var appServicesHbeatModule = new AppServicesHeartbeatTelemetryModule(heartbeatProvider);
string testSuffix = Guid.NewGuid().ToString();
for (int i = 0; i < appServicesHbeatModule.WebHeartbeatPropertyNameEnvVarMap.Length; ++i)
{
var kvp = appServicesHbeatModule.WebHeartbeatPropertyNameEnvVarMap[i];
appServicesHbeatModule.WebHeartbeatPropertyNameEnvVarMap[i] = new KeyValuePair<string, string>(kvp.Key, string.Concat(kvp.Value, "_", testSuffix));
}

return appServicesHbeatModule;
}

private void RemoveTestEnvVarsAssociatedToModule(AppServicesHeartbeatTelemetryModule appServicesHbeatModule)
{
foreach (var kvp in appServicesHbeatModule.WebHeartbeatPropertyNameEnvVarMap)
{
Environment.SetEnvironmentVariable(kvp.Value, string.Empty);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ public void AzureImsResponseTooLargeStopsCollection()
var testStuff = new char[AzureMetadataRequestor.AzureImsMaxResponseBufferSize + 1];
for (int i = 0; i < (AzureMetadataRequestor.AzureImsMaxResponseBufferSize + 1); ++i)
{
testStuff[i] = (char)( (int)'a' + (i % 26) );
testStuff[i] = (char)((int)'a' + (i % 26));
}
tester.Publisher = new string(testStuff);

tester.Publisher = new string(testStuff);
var jsonStream = this.GetTestMetadataStream(tester);
response.SetContentLength(3 * jsonStream.Length);
response.ContentType = "application/json";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,77 +21,98 @@ public void AzureWebAppRoleEnvironmentTelemetryInitializerSetsRoleName()
{
var telemetryItem = new EventTelemetry();

Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", "TestRoleName.AzureWebSites.net");
var testVarName = "WEBSITE_" + Guid.NewGuid().ToString() + "_HOSTNAME";
Environment.SetEnvironmentVariable(testVarName, "TestRoleName.azurewebsites.net");

var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer()
{
WebAppHostNameEnvironmentVariable = testVarName
};

var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer();
initializer.Initialize(telemetryItem);

Assert.Equal("TestRoleName", telemetryItem.Context.Cloud.RoleName);
Assert.Equal("TestRoleName.AzureWebSites.net", telemetryItem.Context.GetInternalContext().NodeName);
Assert.Equal("TestRoleName.azurewebsites.net", telemetryItem.Context.GetInternalContext().NodeName);

Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", null);
Environment.SetEnvironmentVariable(testVarName, null);
}

[TestMethod]
public void AzureWebAppRoleEnvironmentTelemetryInitializerDoesNotOverrideRoleName()
{
Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", "TestRoleName.azurewebsites.net");
var testVarName = "WEBSITE_" + Guid.NewGuid().ToString() + "_HOSTNAME";
Environment.SetEnvironmentVariable(testVarName, "TestRoleName.azurewebsites.net");

var telemetryItem = new EventTelemetry();
telemetryItem.Context.Cloud.RoleName = "Test";

var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer();
var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer()
{
WebAppHostNameEnvironmentVariable = testVarName
};
initializer.Initialize(telemetryItem);

Assert.Equal("Test", telemetryItem.Context.Cloud.RoleName);
Assert.Equal("TestRoleName.azurewebsites.net", telemetryItem.Context.GetInternalContext().NodeName);

Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", null);
Environment.SetEnvironmentVariable(testVarName, null);
}

[TestMethod]
public void AzureWebAppRoleEnvironmentTelemetryInitializerDoesNotOverrideRoleInstance()
{
Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", "TestRoleName.azurewebsites.net");
var testVarName = "WEBSITE_" + Guid.NewGuid().ToString() + "_HOSTNAME";
Environment.SetEnvironmentVariable(testVarName, "TestRoleName.azurewebsites.net");

var telemetryItem = new EventTelemetry();
telemetryItem.Context.Cloud.RoleInstance = "Test";

var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer();
var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer()
{
WebAppHostNameEnvironmentVariable = testVarName
};
initializer.Initialize(telemetryItem);

Assert.Equal("TestRoleName", telemetryItem.Context.Cloud.RoleName);
Assert.Equal("Test", telemetryItem.Context.Cloud.RoleInstance);
Assert.Equal("TestRoleName.azurewebsites.net", telemetryItem.Context.GetInternalContext().NodeName);

Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", null);
Environment.SetEnvironmentVariable(testVarName, null);
}

[TestMethod]
public void AzureWebAppRoleEnvironmentTelemetryInitializerDoesNotOverrideNodeName()
{
Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", "TestRoleName.azurewebsites.net");

var testVarName = "WEBSITE_" + Guid.NewGuid().ToString() + "_HOSTNAME";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we change the ENV vars?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now have 3 classes that all use the same environment variables and testing each of them means we update/clear/change that small set of environment variables as we go. If we run the tests in parallel, tests will have that value changed unexpectedly during their execution by other tests.

Environment.SetEnvironmentVariable(testVarName, "TestRoleName.azurewebsites.net");

var telemetryItem = new EventTelemetry();
telemetryItem.Context.GetInternalContext().NodeName = "Test";

var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer();
var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer()
{
WebAppHostNameEnvironmentVariable = testVarName
};
initializer.Initialize(telemetryItem);

Assert.Equal("TestRoleName", telemetryItem.Context.Cloud.RoleName);
Assert.Equal("Test", telemetryItem.Context.GetInternalContext().NodeName);

Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", null);
Environment.SetEnvironmentVariable(testVarName, null);
}

[TestMethod]
public void AzureWebAppRoleEnvironmentTelemetryInitializerEmptyVariable()
{
Environment.SetEnvironmentVariable("WEBSITE_HOSTNAME", null);
var testVarName = "WEBSITE_" + Guid.NewGuid().ToString() + "_HOSTNAME";
Environment.SetEnvironmentVariable(testVarName, null);

var telemetryItem = new EventTelemetry();

var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer();
var initializer = new AzureWebAppRoleEnvironmentTelemetryInitializer()
{
WebAppHostNameEnvironmentVariable = testVarName
};
initializer.Initialize(telemetryItem);

Assert.Null(telemetryItem.Context.Cloud.RoleName);
Expand Down
Loading