carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package metrics
2
3import (
4 "context"
5 "encoding/json"
6 "testing"
7 "time"
8
9 "github.com/carlosframework/platform/internal/release"
10)
11
12func TestHourOf(t *testing.T) {
13 got := HourOf(time.Date(2026, 8, 2, 21, 45, 0, 0, time.UTC))
14 if got != "2026-08-02-21" {
15 t.Fatalf("got %q, want 2026-08-02-21", got)
16 }
17}
18
19func TestRawKeyDayKey(t *testing.T) {
20 if got, want := RawKey("b", "2026-08-02-21"), "metrics/boxes/b/raw/2026-08-02-21.json"; got != want {
21 t.Fatalf("RawKey got %q, want %q", got, want)
22 }
23 if got, want := DayKey("b", "2026-08-02"), "metrics/boxes/b/days/2026-08-02.json"; got != want {
24 t.Fatalf("DayKey got %q, want %q", got, want)
25 }
26}
27
28func sampleFloat(v float64) *float64 { return &v }
29
30func TestWriteRawRoundTrip(t *testing.T) {
31 store := release.NewDirStore(t.TempDir())
32 ctx := context.Background()
33
34 c := RawChunk{
35 V: 1,
36 Box: "b",
37 Hour: "2026-08-02-21",
38 Samples: []Sample{
39 {
40 At: time.Date(2026, 8, 2, 21, 0, 0, 0, time.UTC),
41 Host: HostSample{CPUFrac: sampleFloat(0.5)},
42 Units: map[string]UnitSample{
43 "carlos-app@x.example.com.service": {CPUFrac: sampleFloat(0.1)},
44 },
45 },
46 },
47 }
48
49 if err := WriteRaw(ctx, store, c); err != nil {
50 t.Fatalf("WriteRaw: %v", err)
51 }
52
53 body, _, err := store.Get(ctx, RawKey(c.Box, c.Hour))
54 if err != nil {
55 t.Fatalf("Get: %v", err)
56 }
57 var got RawChunk
58 if err := json.Unmarshal(body, &got); err != nil {
59 t.Fatalf("Unmarshal: %v", err)
60 }
61 if got.V != c.V || got.Box != c.Box || got.Hour != c.Hour || len(got.Samples) != 1 {
62 t.Fatalf("got %+v, want %+v", got, c)
63 }
64 if got.Samples[0].Host.CPUFrac == nil || *got.Samples[0].Host.CPUFrac != 0.5 {
65 t.Fatalf("host cpu round-trip mismatch: %+v", got.Samples[0].Host)
66 }
67}
68
69func TestWriteRawOverwriteSameHour(t *testing.T) {
70 store := release.NewDirStore(t.TempDir())
71 ctx := context.Background()
72
73 first := RawChunk{V: 1, Box: "b", Hour: "2026-08-02-21", Samples: []Sample{
74 {At: time.Date(2026, 8, 2, 21, 0, 0, 0, time.UTC), Host: HostSample{CPUFrac: sampleFloat(0.1)}},
75 }}
76 second := RawChunk{V: 1, Box: "b", Hour: "2026-08-02-21", Samples: []Sample{
77 {At: time.Date(2026, 8, 2, 21, 5, 0, 0, time.UTC), Host: HostSample{CPUFrac: sampleFloat(0.2)}},
78 {At: time.Date(2026, 8, 2, 21, 10, 0, 0, time.UTC), Host: HostSample{CPUFrac: sampleFloat(0.3)}},
79 }}
80
81 if err := WriteRaw(ctx, store, first); err != nil {
82 t.Fatalf("WriteRaw first: %v", err)
83 }
84 if err := WriteRaw(ctx, store, second); err != nil {
85 t.Fatalf("WriteRaw second: %v", err)
86 }
87
88 keys, err := store.List(ctx, "metrics/boxes/b/raw/")
89 if err != nil {
90 t.Fatalf("List: %v", err)
91 }
92 if len(keys) != 1 {
93 t.Fatalf("got %d keys, want exactly one (overwrite, not a new object): %v", len(keys), keys)
94 }
95
96 body, _, err := store.Get(ctx, RawKey("b", "2026-08-02-21"))
97 if err != nil {
98 t.Fatalf("Get: %v", err)
99 }
100 var got RawChunk
101 if err := json.Unmarshal(body, &got); err != nil {
102 t.Fatalf("Unmarshal: %v", err)
103 }
104 if len(got.Samples) != 2 {
105 t.Fatalf("got %d samples, want the latest write's 2 (latest content wins)", len(got.Samples))
106 }
107}
108
109func TestStaleRawKeys(t *testing.T) {
110 now := time.Date(2026, 8, 2, 22, 30, 0, 0, time.UTC)
111 keys := []string{
112 "metrics/boxes/b/raw/2026-07-31-10.json", // stale
113 "metrics/boxes/b/raw/2026-08-02-21.json", // fresh
114 "metrics/boxes/b/raw/garbage.json", // unparsable — never returned
115 }
116 got := StaleRawKeys(keys, now, 48*time.Hour)
117 if len(got) != 1 || got[0] != keys[0] {
118 t.Fatalf("got %v, want only the stale key", got)
119 }
120}
121