chore: initial project import
This commit is contained in:
commit
3fc4e5ca53
347 files changed
+56172
No files matched your search
@@ -0,0 +1,162 @@
|
||||
using Monitor.Backend.Analysis;
|
||||
|
||||
namespace Monitor.Backend.Analysis.Tests;
|
||||
|
||||
public sealed class AccumulatorTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(0.5)]
|
||||
[InlineData(0.9)]
|
||||
[InlineData(0.95)]
|
||||
[InlineData(0.99)]
|
||||
public void Histogram_Quantile_WithinRelativeError(double q)
|
||||
{
|
||||
var rng = new Random(42);
|
||||
var values = new List<double>();
|
||||
var hist = new HistogramAcc();
|
||||
for (int i = 0; i < 20_000; i++)
|
||||
{
|
||||
// 对数正态分布:中位数约 50 ms,长尾
|
||||
double v = 50 * Math.Exp(rng.NextDouble() * 2.5 - 1.2);
|
||||
values.Add(v);
|
||||
hist.Add(v);
|
||||
}
|
||||
|
||||
values.Sort();
|
||||
double exact = values[(int)(q * (values.Count - 1))];
|
||||
double estimate = hist.Quantile(q)!.Value;
|
||||
Assert.InRange(Math.Abs(estimate - exact) / exact, 0, 0.045);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Histogram_Merge_EqualsSingleAccumulator()
|
||||
{
|
||||
var rng = new Random(7);
|
||||
var whole = new HistogramAcc();
|
||||
var left = new HistogramAcc();
|
||||
var right = new HistogramAcc();
|
||||
for (int i = 0; i < 5000; i++)
|
||||
{
|
||||
double v = rng.NextDouble() * 200;
|
||||
whole.Add(v);
|
||||
(i % 2 == 0 ? left : right).Add(v);
|
||||
}
|
||||
|
||||
left.Merge(right);
|
||||
Assert.Equal(whole.Count, left.Count);
|
||||
Assert.Equal(whole.Quantile(0.95), left.Quantile(0.95));
|
||||
Assert.Equal(whole.Quantile(0.5), left.Quantile(0.5));
|
||||
Assert.Equal(whole.Max, left.Max);
|
||||
Assert.Equal(whole.NonEmptyBuckets, left.NonEmptyBuckets);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Histogram_Empty_HasNoQuantiles()
|
||||
{
|
||||
var hist = new HistogramAcc();
|
||||
Assert.Null(hist.Quantile(0.5));
|
||||
Assert.Null(hist.Mean);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Histogram_SingleSample_QuantilesClampToSample()
|
||||
{
|
||||
var hist = new HistogramAcc();
|
||||
hist.Add(42);
|
||||
Assert.Equal(42, hist.Quantile(0.01));
|
||||
Assert.Equal(42, hist.Quantile(0.99));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Histogram_IgnoresNegativeAndNaN()
|
||||
{
|
||||
var hist = new HistogramAcc();
|
||||
hist.Add(-1);
|
||||
hist.Add(double.NaN);
|
||||
Assert.Equal(0UL, hist.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Histogram_ValuesBeyondRange_LandInEdgeBuckets()
|
||||
{
|
||||
var hist = new HistogramAcc();
|
||||
hist.Add(0.01);
|
||||
hist.Add(1_000_000);
|
||||
Assert.Equal(2UL, hist.Count);
|
||||
Assert.Equal(2, hist.NonEmptyBuckets);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Ratio_Merge_SumsNumeratorAndDenominator()
|
||||
{
|
||||
var a = new RatioAcc();
|
||||
a.Add(1, 10);
|
||||
var b = new RatioAcc();
|
||||
b.Add(3, 10);
|
||||
a.Merge(b);
|
||||
Assert.Equal(20.0, a.Percent);
|
||||
Assert.Null(new RatioAcc().Percent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Merge_DifferentKinds_Throws()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => new CounterAcc().Merge(new RatioAcc()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Codec_RoundTrip_PreservesEveryKind()
|
||||
{
|
||||
var set = new MetricSet();
|
||||
set.GetOrAdd("c", AccKind.Counter).Add(5);
|
||||
set.GetOrAdd("r", AccKind.Ratio).Add(2, 9);
|
||||
set.GetOrAdd("s", AccKind.Sum).Add(2.5);
|
||||
set.GetOrAdd("n", AccKind.Min).Add(-3);
|
||||
set.GetOrAdd("x", AccKind.Max).Add(11);
|
||||
set.GetOrAdd("l", AccKind.RunLength).Add(4);
|
||||
var hist = (HistogramAcc)set.GetOrAdd("h", AccKind.Histogram);
|
||||
foreach (double v in new[] { 1.0, 20, 20, 300 })
|
||||
{
|
||||
hist.Add(v);
|
||||
}
|
||||
|
||||
set.GetOrAdd("t", AccKind.Series).Add(2, 7.5);
|
||||
|
||||
MetricSet decoded = AccumulatorCodec.Decode(AccumulatorCodec.Encode(set)).Value;
|
||||
|
||||
Assert.Equal(5UL, ((CounterAcc)decoded.Items["c"]).Value);
|
||||
Assert.Equal(9UL, ((RatioAcc)decoded.Items["r"]).Denominator);
|
||||
Assert.Equal(2.5, ((SumAcc)decoded.Items["s"]).Sum);
|
||||
Assert.Equal(-3, ((MinAcc)decoded.Items["n"]).Value);
|
||||
Assert.Equal(11, ((MaxAcc)decoded.Items["x"]).Value);
|
||||
Assert.Equal(4, ((RunLengthAcc)decoded.Items["l"]).Max);
|
||||
var h2 = (HistogramAcc)decoded.Items["h"];
|
||||
Assert.Equal(hist.Count, h2.Count);
|
||||
Assert.Equal(hist.Quantile(0.5), h2.Quantile(0.5));
|
||||
Assert.Equal(7.5, ((SeriesAcc)decoded.Items["t"]).Points[2]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Codec_Decode_RejectsTruncatedData()
|
||||
{
|
||||
var set = new MetricSet();
|
||||
set.GetOrAdd("h", AccKind.Histogram).Add(10);
|
||||
byte[] bytes = AccumulatorCodec.Encode(set);
|
||||
Assert.False(AccumulatorCodec.Decode(bytes.AsSpan(0, bytes.Length - 3)).IsSuccess);
|
||||
Assert.False(AccumulatorCodec.Decode([200, 200]).IsSuccess);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MetricSet_Merge_CombinesDisjointAndSharedMetrics()
|
||||
{
|
||||
var a = new MetricSet();
|
||||
a.GetOrAdd("x", AccKind.Counter).Add(1);
|
||||
var b = new MetricSet();
|
||||
b.GetOrAdd("x", AccKind.Counter).Add(2);
|
||||
b.GetOrAdd("y", AccKind.Counter).Add(4);
|
||||
a.Merge(b);
|
||||
Assert.Equal(3UL, ((CounterAcc)a.Items["x"]).Value);
|
||||
Assert.Equal(4UL, ((CounterAcc)a.Items["y"]).Value);
|
||||
Assert.Equal(2UL, ((CounterAcc)b.Items["x"]).Value);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user