package storage import ( "testing" "github.com/prometheus/client_golang/prometheus" ) // Every cluster counts towards every day it reported on, not just towards the // one day it last reported on. func TestGetMetricsSumsEachDay(t *testing.T) { s := newPrometheusStorage(prometheus.NewRegistry()) // Reported every day of the window. seedSamples(s, "daily", HistorySample{TotalDiskBytes: 300, VolumeServerCount: 3}, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0) // Stopped reporting past the active window: counts on its own days only. seedSamples(s, "gone", HistorySample{TotalDiskBytes: 900, VolumeServerCount: 9}, -14, -13, -12, -11, -10, -9, -8) metrics, err := s.GetMetrics(10) if err != nil { t.Fatal(err) } if got := metrics["dates"].([]string); len(got) != 10 { t.Fatalf("dates = %v, want 10 days", got) } if got := metrics["disk_usage"].([]uint64); !equal(got, []uint64{1200, 1200, 300, 300, 300, 300, 300, 300, 300, 300}) { t.Errorf("disk_usage = %v, want the fleet total per day", got) } if got := metrics["server_counts"].([]int64); !equalInt64(got, []int64{12, 12, 3, 3, 3, 3, 3, 3, 3, 3}) { t.Errorf("server_counts = %v, want the fleet total per day", got) } } // A cluster that skipped a day keeps its size on that day rather than dipping // the fleet total to zero and back. func TestGetMetricsCarriesSkippedDaysForward(t *testing.T) { s := newPrometheusStorage(prometheus.NewRegistry()) seedSamples(s, "gappy", HistorySample{TotalDiskBytes: 500, VolumeServerCount: 5}, -8, -7, -6, -5, -4, -3, -1) metrics, err := s.GetMetrics(4) if err != nil { t.Fatal(err) } if got := metrics["disk_usage"].([]uint64); !equal(got, []uint64{500, 500, 500, 500}) { t.Errorf("disk_usage = %v, want the skipped days carried forward", got) } } // The window starts at the oldest sample the server actually has, so a server // with less history than the caller asked for does not report a fleet that grew // out of nothing on its first day of data. func TestGetMetricsWindowStartsAtOldestSample(t *testing.T) { s := newPrometheusStorage(prometheus.NewRegistry()) seedSamples(s, "recent", HistorySample{TotalDiskBytes: 100, VolumeServerCount: 1}, -6, -5, -4, -3, -2, -1, 0) metrics, err := s.GetMetrics(30) if err != nil { t.Fatal(err) } if got := metrics["dates"].([]string); len(got) != 7 { t.Errorf("dates = %v, want the 7 days with history, not 30", got) } if got := metrics["disk_usage"].([]uint64); !equal(got, []uint64{100, 100, 100, 100, 100, 100, 100}) { t.Errorf("disk_usage = %v, want no leading zero days", got) } // History reaching past the requested window still clips to the window. seedSamples(s, "old", HistorySample{TotalDiskBytes: 50, VolumeServerCount: 1}, -45, -44, -43, -42, -41, -40, -39) metrics, err = s.GetMetrics(10) if err != nil { t.Fatal(err) } if got := metrics["dates"].([]string); len(got) != 10 { t.Errorf("dates = %v, want 10 days", got) } } // /api/metrics is the fleet total that /api/cluster-sizes breaks down per // cluster, so their last day has to add up to the same number. func TestGetMetricsAgreesWithClusterSizes(t *testing.T) { s := newPrometheusStorage(prometheus.NewRegistry()) seedSamples(s, "daily", HistorySample{TotalDiskBytes: 300, VolumeServerCount: 3}, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0) seedSamples(s, "lagging", HistorySample{TotalDiskBytes: 200, VolumeServerCount: 2}, -8, -7, -6, -5, -4, -3, -2) seedSamples(s, "gone", HistorySample{TotalDiskBytes: 900, VolumeServerCount: 9}, -14, -13, -12, -11, -10, -9, -8) metrics, err := s.GetMetrics(10) if err != nil { t.Fatal(err) } disk := metrics["disk_usage"].([]uint64) sizes := s.GetClusterSizeSeries(10, 1) // limit forces the Other fold-in too if got, want := disk[len(disk)-1], sizes.TotalDisk; got != want { t.Errorf("metrics last day = %d, cluster sizes total = %d", got, want) } if len(disk) != len(sizes.Dates) { t.Errorf("metrics has %d days, cluster sizes has %d", len(disk), len(sizes.Dates)) } } // Short-lived clusters -- a CI run, a docker-compose demo -- report once under a // fresh raft topology id and never again. Held forward for the whole active // window they would stack up into a fleet that grows every day, so they stay out // of the totals until they are confirmed. func TestGetMetricsExcludesUnconfirmedClusters(t *testing.T) { s := newPrometheusStorage(prometheus.NewRegistry()) seedSamples(s, "real", HistorySample{TotalDiskBytes: 300, VolumeServerCount: 3}, -6, -5, -4, -3, -2, -1, 0) for _, id := range []string{"ci-1", "ci-2", "ci-3"} { seedSamples(s, id, HistorySample{TotalDiskBytes: 5, VolumeServerCount: 14}, -1) } metrics, err := s.GetMetrics(4) if err != nil { t.Fatal(err) } if got := metrics["server_counts"].([]int64); !equalInt64(got, []int64{3, 3, 3, 3}) { t.Errorf("server_counts = %v, want the confirmed cluster alone", got) } if got := metrics["disk_usage"].([]uint64); !equal(got, []uint64{300, 300, 300, 300}) { t.Errorf("disk_usage = %v, want the confirmed cluster alone", got) } } // Until any cluster has a week of history the charts fall back to every // cluster, so a fresh server doesn't serve empty series. func TestGetMetricsFallsBackWhenNoneConfirmed(t *testing.T) { s := newPrometheusStorage(prometheus.NewRegistry()) seedSamples(s, "new", HistorySample{TotalDiskBytes: 100, VolumeServerCount: 2}, 0) metrics, err := s.GetMetrics(7) if err != nil { t.Fatal(err) } if got := metrics["server_counts"].([]int64); !equalInt64(got, []int64{2}) { t.Errorf("server_counts = %v, want today's only cluster", got) } } func equalInt64(a, b []int64) bool { if len(a) != len(b) { return false } for i := range a { if a[i] != b[i] { return false } } return true }