Skip to content

Commit

Permalink
Merge pull request #117 from prom-client-net/test/add-units
Browse files Browse the repository at this point in the history
test: add & improve unit tests
  • Loading branch information
phnx47 authored Oct 19, 2024
2 parents 06ae296 + c3bbfbc commit 0e95031
Show file tree
Hide file tree
Showing 10 changed files with 383 additions and 55 deletions.
3 changes: 3 additions & 0 deletions src/ApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public static IApplicationBuilder UsePrometheusRequestDurations(this IApplicatio
/// <param name="setupOptions">Setup Options</param>
public static IApplicationBuilder UsePrometheusRequestDurations(this IApplicationBuilder app, Action<HttpRequestDurationsOptions> setupOptions)
{
if (app == null)
throw new ArgumentNullException(nameof(app));

var options = new HttpRequestDurationsOptions();
setupOptions?.Invoke(options);

Expand Down
15 changes: 15 additions & 0 deletions src/Defaults.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Prometheus.Client.HttpRequestDurations;

internal static class Defaults
{
internal const string MetricName = "http_request_duration_seconds";

internal static class LabelNames
{
internal const string StatusCode = "status_code";
internal const string Method = "method";
internal const string Controller = "controller";
internal const string Action = "action";
internal const string Path = "path";
}
}
10 changes: 5 additions & 5 deletions src/HttpRequestDurationsMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ public HttpRequestDurationsMiddleware(RequestDelegate next, HttpRequestDurations
var labels = new List<string>();

if (_options.IncludeStatusCode)
labels.Add("status_code");
labels.Add(Defaults.LabelNames.StatusCode);

if (_options.IncludeMethod)
labels.Add("method");
labels.Add(Defaults.LabelNames.Method);

if (_options.IncludeController)
labels.Add("controller");
labels.Add(Defaults.LabelNames.Controller);

if (_options.IncludeAction)
labels.Add("action");
labels.Add(Defaults.LabelNames.Action);

if (_options.IncludePath)
labels.Add("path");
labels.Add(Defaults.LabelNames.Path);

if (_options.IncludeCustomLabels)
labels.AddRange(_options.CustomLabels.Select(customLabel => customLabel.Key));
Expand Down
7 changes: 2 additions & 5 deletions src/HttpRequestDurationsOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Prometheus.Client.HttpRequestDurations;

/// <summary>
/// Options for RequestDurationsMiddleware
/// Options for HttpRequestDurationsMiddleware
/// </summary>
public class HttpRequestDurationsOptions
{
Expand Down Expand Up @@ -108,10 +108,7 @@ public class HttpRequestDurationsOptions
/// </summary>
public HttpRequestDurationsOptions()
{
MetricName = "http_request_duration_seconds";

MetricName = Defaults.MetricName;
IncludeStatusCode = true;
IncludeMethod = false;
IncludePath = false;
}
}
2 changes: 1 addition & 1 deletion src/Prometheus.Client.HttpRequestDurations.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Metrics logging of request durations for the Prometheus.Client</Description>
<Description>HTTP request durations for the Prometheus.Client</Description>
<TargetFramework>net6.0</TargetFramework>
<RepositoryUrl>https://github.com/prom-client-net/prom-client-httprequestdurations</RepositoryUrl>
</PropertyGroup>
Expand Down
70 changes: 70 additions & 0 deletions tests/ApplicationBuilderExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Prometheus.Client.Collectors;
using Xunit;

namespace Prometheus.Client.HttpRequestDurations.Tests;

public class ApplicationBuilderExtensionsTests
{
private readonly ServiceCollection _services = new();

[Fact]
public void AppBuilderIsNull_Throws_ArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => ((ApplicationBuilder)null).UsePrometheusRequestDurations());
}

[Fact]
public void TargetIsType_HttpRequestDurationsMiddleware()
{
var app = new ApplicationBuilder(_services.BuildServiceProvider());
_services.AddSingleton<ICollectorRegistry, CollectorRegistry>();
app.UsePrometheusRequestDurations();

Assert.IsType<HttpRequestDurationsMiddleware>(app.Build().Target);
}

[Fact]
public void With_DefaultCollectorRegistry()
{
var app = new ApplicationBuilder(_services.BuildServiceProvider());
app.UsePrometheusRequestDurations();
app.Build();

Assert.True(Metrics.DefaultCollectorRegistry.TryGet(Defaults.MetricName, out var defaultCollector));

// Cleanup
Metrics.DefaultCollectorRegistry?.Remove(defaultCollector);
}

[Fact]
public void With_DICollecorRegistry()
{
var registry = new CollectorRegistry();
_services.AddSingleton<ICollectorRegistry>(registry);
var app = new ApplicationBuilder(_services.BuildServiceProvider());
app.UsePrometheusRequestDurations();
app.Build();

Assert.True(registry.TryGet(Defaults.MetricName, out _));

Assert.False(Metrics.DefaultCollectorRegistry.TryGet(Defaults.MetricName, out _));
}

[Fact]
public void With_CustomCollecorRegistry()
{
var registry = new CollectorRegistry();

var app = new ApplicationBuilder(_services.BuildServiceProvider());
app.UsePrometheusRequestDurations(q => q.CollectorRegistry = registry);
app.Build();

Assert.True(registry.TryGet(Defaults.MetricName, out _));

Assert.False(Metrics.DefaultCollectorRegistry.TryGet(Defaults.MetricName, out _));
}
}
26 changes: 26 additions & 0 deletions tests/HttpContextExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Microsoft.AspNetCore.Http;
using Xunit;

namespace Prometheus.Client.HttpRequestDurations.Tests;

public class HttpContextExtensionsTests
{
[Fact]
public void GetRouteName_When_HttpContextIsNull_Throws_ArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => ((HttpContext)null).GetRouteName());
}

[Fact]
public void GetControllerName_When_HttpContextIsNull_Throws_ArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => ((HttpContext)null).GetControllerName());
}

[Fact]
public void GetActionName_When_HttpContextIsNull_Throws_ArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => ((HttpContext)null).GetActionName());
}
}
196 changes: 196 additions & 0 deletions tests/HttpRequestDurationsMiddlewareTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Prometheus.Client.Collectors;
using Xunit;

namespace Prometheus.Client.HttpRequestDurations.Tests;

public class HttpRequestDurationsMiddlewareTests
{
private readonly ICollectorRegistry _registry;
private readonly IApplicationBuilder _app;

public HttpRequestDurationsMiddlewareTests()
{
_registry = new CollectorRegistry();

var services = new ServiceCollection();
services.AddSingleton(_registry);
_app = new ApplicationBuilder(services.BuildServiceProvider());
}

[Fact]
public void Use_DefaultCollectorNotNull()
{
UseBuildApp();

_registry.TryGet(Defaults.MetricName, out var collector);

Assert.NotNull(collector);
}

[Theory]
[InlineData("custom_name")]
[InlineData("http_seconds")]
[InlineData("myapp_http_request_duration_seconds")]
public void Use_WithCustomMetricName_CustomCollectorNotNull(string metricName)
{
UseBuildApp(q => q.MetricName = metricName);

_registry.TryGet(metricName, out var collector);

Assert.NotNull(collector);
}

[Fact]
public void Use_WithCustomMetricName_DefaultCollectorIsNull()
{
UseBuildApp(q => q.MetricName = "custom_name");

_registry.TryGet(Defaults.MetricName, out var collector);

Assert.Null(collector);
}

[Fact]
public void Collector_IsHistogram()
{
UseBuildApp();

_registry.TryGet(Defaults.MetricName, out var collector);
Assert.IsAssignableFrom<IMetricFamily<IHistogram>>(collector);
}

[Fact]
public void Metric_ContainsStatusCodeLabel()
{
UseBuildApp(q => q.IncludeStatusCode = true);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.Contains(Defaults.LabelNames.StatusCode, metric.LabelNames);
}

[Fact]
public void Metric_DoesNotContainStatusCodeLabel()
{
UseBuildApp(q => q.IncludeStatusCode = false);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.DoesNotContain(Defaults.LabelNames.StatusCode, metric.LabelNames);
}

[Fact]
public void Metric_ContainsMethodLabel()
{
UseBuildApp(q => q.IncludeMethod = true);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.Contains(Defaults.LabelNames.Method, metric.LabelNames);
}

[Fact]
public void Metric_DoesNotContainMethodLabel()
{
UseBuildApp(q => q.IncludeMethod = false);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.DoesNotContain(Defaults.LabelNames.Method, metric.LabelNames);
}

[Fact]
public void Metric_ContainsControllerLabel()
{
UseBuildApp(q => q.IncludeController = true);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.Contains(Defaults.LabelNames.Controller, metric.LabelNames);
}

[Fact]
public void Metric_DoesNotContainControllerLabel()
{
UseBuildApp(q => q.IncludeController = false);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.DoesNotContain(Defaults.LabelNames.Controller, metric.LabelNames);
}

[Fact]
public void Metric_ContainsActionLabel()
{
UseBuildApp(q => q.IncludeAction = true);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.Contains(Defaults.LabelNames.Action, metric.LabelNames);
}

[Fact]
public void Metric_DoesNotContainActionLabel()
{
UseBuildApp(q => q.IncludeAction = false);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.DoesNotContain(Defaults.LabelNames.Action, metric.LabelNames);
}

[Fact]
public void Metric_ContainsPathLabel()
{
UseBuildApp(q => q.IncludePath = true);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.Contains(Defaults.LabelNames.Path, metric.LabelNames);
}

[Fact]
public void Metric_DoesNotContainPathLabel()
{
UseBuildApp(q => q.IncludePath = false);

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.DoesNotContain(Defaults.LabelNames.Path, metric.LabelNames);
}

[Fact]
public void Metric_ContainsCustomLabel()
{
UseBuildApp(q => q.CustomLabels = new Dictionary<string, Func<string>>
{
{
"custom_label", () => "custom_value"
}
});

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.Contains("custom_label", metric.LabelNames);
Assert.DoesNotContain("custom_value", metric.LabelNames);
}

[Fact]
public void Metric_DoesNotContainCustomLabel()
{
UseBuildApp();

_registry.TryGet(Defaults.MetricName, out var collector);
var metric = (IMetricFamily<IHistogram>)collector;
Assert.DoesNotContain("custom_label", metric.LabelNames);
}

private void UseBuildApp(Action<HttpRequestDurationsOptions> setupOptions = null)
{
_app.UsePrometheusRequestDurations(setupOptions).Build();
}
}
Loading

0 comments on commit 0e95031

Please sign in to comment.