Skip to content

Commit

Permalink
Add test suite to analyze ASP.NET Core routing scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
alanwest committed Oct 14, 2023
1 parent 18c85fa commit 26fdf70
Show file tree
Hide file tree
Showing 21 changed files with 1,775 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,16 @@
<ItemGroup Condition="'$(TargetFramework)' == 'net6.0'">
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="6.0.21" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.21" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.21" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="7.0.9" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.9" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="7.0.9" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.0-rc.1.23421.29" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0-rc.1.23421.29" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.0-rc.1.23421.29" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
Expand Down Expand Up @@ -36,4 +37,11 @@
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\InMemoryEventListener.cs" Link="Includes\InMemoryEventListener.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\TestEventListener.cs" Link="Includes\TestEventListener.cs" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="RouteTests\testcases.json">
<LogicalName>RouteTests.testcases.json</LogicalName>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// <copyright file="AnotherAreaController.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

#nullable disable

using Microsoft.AspNetCore.Mvc;

namespace RouteTests.Controllers;

[Area("AnotherArea")]
public class AnotherAreaController : Controller
{
public IActionResult Index() => this.Ok();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// <copyright file="ControllerForMyAreaController.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

#nullable disable

using Microsoft.AspNetCore.Mvc;

namespace RouteTests.Controllers;

[Area("MyArea")]
public class ControllerForMyAreaController : Controller
{
public IActionResult Default() => this.Ok();

public IActionResult NonDefault() => this.Ok();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// <copyright file="AspNetCoreDiagnosticObserver.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

#nullable enable

using System.Diagnostics;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Diagnostics;

namespace RouteTests;

internal sealed class AspNetCoreDiagnosticObserver : IDisposable, IObserver<DiagnosticListener>, IObserver<KeyValuePair<string, object?>>
{
internal const string OnStartEvent = "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start";
internal const string OnStopEvent = "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop";
internal const string OnMvcBeforeActionEvent = "Microsoft.AspNetCore.Mvc.BeforeAction";

private readonly List<IDisposable> listenerSubscriptions;
private IDisposable? allSourcesSubscription;
private long disposed;

public AspNetCoreDiagnosticObserver()
{
this.listenerSubscriptions = new List<IDisposable>();
this.allSourcesSubscription = DiagnosticListener.AllListeners.Subscribe(this);
}

public void OnNext(DiagnosticListener value)
{
if (value.Name == "Microsoft.AspNetCore")
{
var subscription = value.Subscribe(this);

lock (this.listenerSubscriptions)
{
this.listenerSubscriptions.Add(subscription);
}
}
}

public void OnNext(KeyValuePair<string, object?> value)
{
HttpContext? context;
BeforeActionEventData? actionMethodEventData;
RouteInfo? info;

switch (value.Key)
{
case OnStartEvent:
context = value.Value as HttpContext;
Debug.Assert(context != null, "HttpContext was null");
info = new RouteInfo();
info.SetValues(context);
context.Items["RouteInfo"] = info;
break;
case OnMvcBeforeActionEvent:
actionMethodEventData = value.Value as BeforeActionEventData;
Debug.Assert(actionMethodEventData != null, $"expected {nameof(BeforeActionEventData)}");
info = actionMethodEventData.HttpContext.Items["RouteInfo"] as RouteInfo;
Debug.Assert(info != null, "RouteInfo object not present in context.Items");
info.SetValues(actionMethodEventData.HttpContext);
info.SetValues(actionMethodEventData.ActionDescriptor);
break;
case OnStopEvent:
// Can't update RouteInfo here because the response is already written.
break;
default:
break;
}
}

public void OnCompleted()
{
}

public void OnError(Exception error)
{
}

public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
if (Interlocked.CompareExchange(ref this.disposed, 1, 0) == 1)
{
return;
}

lock (this.listenerSubscriptions)
{
foreach (var listenerSubscription in this.listenerSubscriptions)
{
listenerSubscription?.Dispose();
}

this.listenerSubscriptions.Clear();
}

this.allSourcesSubscription?.Dispose();
this.allSourcesSubscription = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// <copyright file="AttributeRouteController.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

#nullable disable

using Microsoft.AspNetCore.Mvc;

namespace RouteTests.Controllers;

[ApiController]
[Route("[controller]")]
public class AttributeRouteController : ControllerBase
{
[HttpGet]
[HttpGet("[action]")]
public IActionResult Get() => this.Ok();

[HttpGet("[action]/{id}")]
public IActionResult Get(int id) => this.Ok();

[HttpGet("{id}/[action]")]
public IActionResult GetWithActionNameInDifferentSpotInTemplate(int id) => this.Ok();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// <copyright file="ConventionalRouteController.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

#nullable disable

using Microsoft.AspNetCore.Mvc;

namespace RouteTests.Controllers;

public class ConventionalRouteController : Controller
{
public IActionResult Default() => this.Ok();

public IActionResult ActionWithParameter(int id) => this.Ok();

public IActionResult ActionWithStringParameter(string id, int num) => this.Ok();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// <copyright file="DebugInfo.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

#nullable enable

namespace RouteTests;

public class DebugInfo
{
public string? RawText { get; set; }

public string? RouteDiagnosticMetadata { get; set; }

public IDictionary<string, string?>? RouteData { get; set; }

public string? AttributeRouteInfo { get; set; }

public IList<string>? ActionParameters { get; set; }

public string? PageActionDescriptorRelativePath { get; set; }

public string? PageActionDescriptorViewEnginePath { get; set; }

public string? ControllerActionDescriptorControllerName { get; set; }

public string? ControllerActionDescriptorActionName { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@page
Hello, OpenTelemetry!
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@page
@{
throw new Exception("Oops.");
}
Loading

0 comments on commit 26fdf70

Please sign in to comment.