fix: correct OpenWrt API metadata and earliest sample queries [CI]
ci/woodpecker/push/web-build Pipeline was successful
ci/woodpecker/push/verify Pipeline was successful
ci/woodpecker/push/dev-image Pipeline was successful

This commit is contained in:
justme committed 2026-10-20 14:56:39 +08:00
1 parent cd193378a6
commit 0066a947da
6 files changed
+85 -11

No files matched your search

@@ -52,7 +52,7 @@ public sealed partial class OpenApiConformanceTests : IClassFixture<BackendFixtu
foreach ((string path, _) in doc["paths"]!.AsObject())
{
string[] prefixes = ["/api/public/", "/api/admin/", "/api/agent/v1/"];
string[] roots = ["/healthz", "/metrics", "/install", "/install.ps1", "/install/manifest", "/install/manifest.sig", "/install/compose/{file}", "/install/quadlet/{file}", "/api/release/offer"];
string[] roots = ["/healthz", "/metrics", "/install", "/install.ps1", "/install/openwrt.sh", "/install/manifest", "/install/manifest.sig", "/install/compose/{file}", "/install/quadlet/{file}", "/api/release/offer"];
Assert.True(prefixes.Any(p => path.StartsWith(p, StringComparison.Ordinal)) || roots.Contains(path), $"{path} is outside the documented layers");
foreach (string segment in path.Split('/', StringSplitOptions.RemoveEmptyEntries))
{
@@ -0,0 +1,72 @@
using Fleet.Core;
using Microsoft.Extensions.Time.Testing;
using MoShiro.Backend.Analysis;
using MoShiro.Backend.Application;
using MoShiro.Backend.Storage.Sqlite;
using MoShiro.Protocol;
using MoShiro.TestSupport;
namespace MoShiro.Backend.Tests;
public sealed class RowLoaderTests : IDisposable
{
private static readonly NodeId s_agent = new("agt_earliest");
private readonly string _directory = Path.Combine(Path.GetTempPath(), "moshiro-earliest-" + Guid.NewGuid().ToString("N"));
private readonly SqliteDatabase _database;
private readonly RawQueryGate _gate = new();
public RowLoaderTests()
{
_database = new SqliteDatabase(_directory);
}
[Theory]
[InlineData(0L, 1_800_000L, 1_920_000L, 1_930_000L, 1_931_000L, 1_931_000L)]
[InlineData(0L, 7_200_000L, null, null, 1_800_000L, 1_800_000L)]
[InlineData(0L, 7_200_000L, 1_800_000L, null, null, 1_800_000L)]
[InlineData(0L, 3_600_000L, 3_660_000L, 3_670_000L, null, 0L)]
[InlineData(null, null, null, null, null, null)]
[InlineData(null, null, null, null, 1_850_000L, 1_850_000L)]
[InlineData(null, null, 1_800_000L, null, 1_801_000L, 1_801_000L)]
[InlineData(null, null, 1_800_000L, null, 1_860_000L, 1_800_000L)]
[InlineData(0L, null, 0L, null, null, 0L)]
[InlineData(0L, null, 3_540_000L, null, null, 3_540_000L)]
[InlineData(0L, null, 3_600_000L, null, null, 0L)]
[InlineData(null, null, null, 1_930_000L, null, 1_930_000L)]
public async Task EarliestSampleMs_RefinesWithinTheFirstBucket_WithoutDiscardingOlderHistory(
long? hourStart, long? fiveMinuteStart, long? minuteStart, long? tenSecondStart, long? hotStart, long? expected)
{
var time = new FakeTimeProvider(DateTimeOffset.UnixEpoch.AddHours(1));
var store = new SqliteMetricStore(_database);
var hot = new HotLayer(time);
const string Series = "line";
foreach ((MetricLevel level, long? start) in new[]
{
(MetricLevel.H1, hourStart), (MetricLevel.M5, fiveMinuteStart),
(MetricLevel.M1, minuteStart), (MetricLevel.S10, tenSecondStart),
})
{
if (start is { } at)
{
var row = new MetricRow(s_agent, Series, at, false, AccumulatorCodec.Encode(new MetricSet()));
await store.UpsertAsync(level, [row], default);
}
}
if (hotStart is { } sample)
{
hot.Merge(s_agent, Series, ChunkFactory.UdpEchoClean(s_agent, sample));
}
var loader = new RowLoader(store, hot, new WindowComputer(new SqliteRawStore(_database)), _gate);
Assert.Equal(expected, await loader.EarliestSampleMsAsync(s_agent, Series, time.GetUtcNow().ToUnixTimeMilliseconds(), default));
}
public void Dispose()
{
_gate.Dispose();
_database.Dispose();
Directory.Delete(_directory, recursive: true);
}
}