Skip to content

Commit 389e90b

Browse files
committed
chore: upgrade to .NET 10 and add unit tests
- Upgrade from .NET 8 to .NET 10 - Update all NuGet packages to latest versions (.NET 10.0.0, xunit 2.9.3) - Add 29 new unit and integration tests - Fix CA2022 warning in IntegrationTests - Add macOS support for local development (NullStateCollector) - Update GitHub Actions workflow to .NET 10 - Update README to reflect .NET 10
1 parent b0d3c44 commit 389e90b

14 files changed

Lines changed: 743 additions & 28 deletions

.github/workflows/dotnetcore.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ jobs:
1717
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
1818
- run: git fetch --prune --unshallow
1919

20-
- name: Setup .NET Core 8
20+
- name: Setup .NET 10
2121
uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # v4
2222
with:
23-
dotnet-version: '8.0.x'
23+
dotnet-version: '10.0.x'
2424

2525
- name: Install dependencies
2626
run: dotnet restore

Directory.Packages.props

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,30 @@
44
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
55
</PropertyGroup>
66
<ItemGroup>
7-
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.22" />
87
<PackageVersion Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.652701" />
98
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.28" />
10-
<PackageVersion Include="Microsoft.Extensions.Diagnostics.Testing" Version="9.10.0" />
11-
<PackageVersion Include="Microsoft.Extensions.Hosting.Systemd" Version="9.0.11" />
12-
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.11" />
13-
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.14.0" />
14-
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.14.0" />
15-
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.14.0" />
16-
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.14.0" />
17-
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="9.0.11" />
18-
<PackageVersion Include="System.IO.Pipelines" Version="9.0.11" />
9+
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.11.2" />
10+
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.11.2" />
11+
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.11.2" />
12+
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.11.1" />
1913
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
20-
<PackageVersion Include="coverlet.msbuild" Version="6.0.4">
14+
<PackageVersion Include="coverlet.collector" Version="6.0.4">
2115
<PrivateAssets>all</PrivateAssets>
2216
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2317
</PackageVersion>
2418
<PackageVersion Include="xunit" Version="2.9.3" />
25-
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5">
19+
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2">
2620
<PrivateAssets>all</PrivateAssets>
2721
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2822
</PackageVersion>
2923
</ItemGroup>
24+
<ItemGroup>
25+
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
26+
<PackageVersion Include="Microsoft.Extensions.Diagnostics.Testing" Version="10.0.0" />
27+
<PackageVersion Include="Microsoft.Extensions.Hosting.Systemd" Version="10.0.0" />
28+
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.0" />
29+
<PackageVersion Include="System.Diagnostics.PerformanceCounter" Version="10.0.0" />
30+
</ItemGroup>
3031
<ItemGroup>
3132
<GlobalPackageReference Include="SonarAnalyzer.CSharp" Version="10.16.0.128591" />
3233
</ItemGroup>
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
using Lucca.Infra.Haproxy.AgentCheck.Config;
2+
using Lucca.Infra.Haproxy.AgentCheck.Metrics;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Logging;
5+
using Xunit;
6+
using Xunit.Abstractions;
7+
8+
namespace Lucca.Infra.Haproxy.AgentCheck.Tests;
9+
10+
public class CountersStateTests(ITestOutputHelper testOutputHelper)
11+
{
12+
[Fact]
13+
public void UpdateState_WithCounterValue_UpdatesWeight()
14+
{
15+
var serviceProvider = CreateServiceProvider(
16+
new RuleConfig
17+
{
18+
Name = "custom-counter",
19+
Source = RuleSource.Counters,
20+
Weight = new WeightRule
21+
{
22+
SystemResponse = SystemResponse.Linear,
23+
MinValue = 0,
24+
MaxValue = 100,
25+
MinWeight = 0,
26+
MaxWeight = 100
27+
}
28+
});
29+
30+
var sut = serviceProvider.GetRequiredService<State>();
31+
sut.UpdateState(new CountersState
32+
{
33+
Values = new Dictionary<string, double> { ["custom-counter"] = 50 }
34+
});
35+
36+
Assert.True(sut.IsUp);
37+
Assert.Equal(50, sut.Weight, 0.01);
38+
}
39+
40+
[Fact]
41+
public void UpdateState_WithCounterAboveThreshold_BreaksCircuit()
42+
{
43+
var serviceProvider = CreateServiceProvider(
44+
new RuleConfig
45+
{
46+
Name = "error-rate",
47+
Source = RuleSource.Counters,
48+
Failure = new FailureRule
49+
{
50+
EnterThreshold = 10,
51+
LeaveThreshold = 5
52+
}
53+
});
54+
55+
var sut = serviceProvider.GetRequiredService<State>();
56+
sut.UpdateState(new CountersState
57+
{
58+
Values = new Dictionary<string, double> { ["error-rate"] = 15 }
59+
});
60+
61+
Assert.False(sut.IsUp);
62+
Assert.Contains("Counters/error-rate", sut.BrokenCircuitsBreakers);
63+
}
64+
65+
[Fact]
66+
public void UpdateState_WhenCounterRemoved_RemovesBrokenCircuit()
67+
{
68+
var serviceProvider = CreateServiceProvider(
69+
new RuleConfig
70+
{
71+
Name = "temp-counter",
72+
Source = RuleSource.Counters,
73+
Failure = new FailureRule
74+
{
75+
EnterThreshold = 10,
76+
LeaveThreshold = 5
77+
}
78+
});
79+
80+
var sut = serviceProvider.GetRequiredService<State>();
81+
82+
// First update with counter above threshold
83+
sut.UpdateState(new CountersState
84+
{
85+
Values = new Dictionary<string, double> { ["temp-counter"] = 15 }
86+
});
87+
Assert.Contains("Counters/temp-counter", sut.BrokenCircuitsBreakers);
88+
89+
// Second update without the counter
90+
sut.UpdateState(new CountersState
91+
{
92+
Values = new Dictionary<string, double>()
93+
});
94+
95+
Assert.DoesNotContain("Counters/temp-counter", sut.BrokenCircuitsBreakers);
96+
}
97+
98+
[Fact]
99+
public void UpdateState_WithMultipleCounters_UsesLowestWeight()
100+
{
101+
var serviceProvider = CreateServiceProvider(
102+
new RuleConfig
103+
{
104+
Name = "counter1",
105+
Source = RuleSource.Counters,
106+
Weight = new WeightRule
107+
{
108+
SystemResponse = SystemResponse.Linear,
109+
MinValue = 0,
110+
MaxValue = 100,
111+
MinWeight = 0,
112+
MaxWeight = 100
113+
}
114+
},
115+
new RuleConfig
116+
{
117+
Name = "counter2",
118+
Source = RuleSource.Counters,
119+
Weight = new WeightRule
120+
{
121+
SystemResponse = SystemResponse.Linear,
122+
MinValue = 0,
123+
MaxValue = 100,
124+
MinWeight = 0,
125+
MaxWeight = 100
126+
}
127+
});
128+
129+
var sut = serviceProvider.GetRequiredService<State>();
130+
sut.UpdateState(new CountersState
131+
{
132+
Values = new Dictionary<string, double>
133+
{
134+
["counter1"] = 20, // Weight would be 80
135+
["counter2"] = 90 // Weight would be 10
136+
}
137+
});
138+
139+
Assert.True(sut.IsUp);
140+
Assert.Equal(10, sut.Weight, 0.01);
141+
}
142+
143+
[Fact]
144+
public void UpdateState_CombineSystemAndCounters_UsesLowestWeight()
145+
{
146+
var serviceProvider = CreateServiceProvider(
147+
new RuleConfig
148+
{
149+
Name = "CPU",
150+
Source = RuleSource.System,
151+
Weight = new WeightRule
152+
{
153+
SystemResponse = SystemResponse.Linear,
154+
MinValue = 0,
155+
MaxValue = 100,
156+
MinWeight = 0,
157+
MaxWeight = 100
158+
}
159+
},
160+
new RuleConfig
161+
{
162+
Name = "custom-metric",
163+
Source = RuleSource.Counters,
164+
Weight = new WeightRule
165+
{
166+
SystemResponse = SystemResponse.Linear,
167+
MinValue = 0,
168+
MaxValue = 100,
169+
MinWeight = 0,
170+
MaxWeight = 100
171+
}
172+
});
173+
174+
var sut = serviceProvider.GetRequiredService<State>();
175+
176+
// CPU at 30% -> weight 70
177+
sut.UpdateState(new SystemState { CpuPercent = 30 });
178+
179+
// Custom metric at 80 -> weight 20
180+
sut.UpdateState(new CountersState
181+
{
182+
Values = new Dictionary<string, double> { ["custom-metric"] = 80 }
183+
});
184+
185+
Assert.True(sut.IsUp);
186+
Assert.Equal(20, sut.Weight, 0.01);
187+
}
188+
189+
private IServiceProvider CreateServiceProvider(params RuleConfig[] rules)
190+
{
191+
return new ServiceCollection()
192+
.AddOptions()
193+
.Configure<RulesConfig>(o => o.AddRange(rules))
194+
.AddFakeLogging(o => o.OutputSink = testOutputHelper.WriteLine)
195+
.AddSingleton<TestTimeProvider>()
196+
.AddSingleton<TimeProvider>(p => p.GetRequiredService<TestTimeProvider>())
197+
.AddSingleton<State>()
198+
.BuildServiceProvider();
199+
}
200+
}

Haproxy.AgentCheck.Tests/Haproxy.AgentCheck.Tests.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>net8.0</TargetFramework>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<IsTestProject>true</IsTestProject>
56
</PropertyGroup>
67

78
<ItemGroup>
89
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
910
<PackageReference Include="Microsoft.Extensions.Diagnostics.Testing" />
1011
<PackageReference Include="Microsoft.NET.Test.Sdk" />
11-
<PackageReference Include="coverlet.msbuild">
12+
<PackageReference Include="coverlet.collector">
1213
<PrivateAssets>all</PrivateAssets>
1314
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1415
</PackageReference>

0 commit comments

Comments
 (0)