From 272e48d93be0ad29cd526ea79d0d2c74169a004c Mon Sep 17 00:00:00 2001 From: Chris Schinnerl Date: Tue, 17 Oct 2023 14:11:25 +0200 Subject: [PATCH] testing: add TestRecordContractSetAndChurnMetric --- api/bus.go | 1 + bus/bus.go | 19 +++++++++++++++ bus/client/metrics.go | 25 ++++++++++++++++++++ internal/testing/cluster_test.go | 40 ++++++++++++++++++++++++++------ 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/api/bus.go b/api/bus.go index c909610d8..e2361d9b1 100644 --- a/api/bus.go +++ b/api/bus.go @@ -569,6 +569,7 @@ const ( ChurnDirAdded = "added" ChurnDirRemoved = "removed" + MetricContractSet = "contractset" MetricContractSetChurn = "churn" ) diff --git a/bus/bus.go b/bus/bus.go index 6e3ff63f3..098c4e19b 100644 --- a/bus/bus.go +++ b/bus/bus.go @@ -194,6 +194,7 @@ type ( } MetricsStore interface { + ContractSetMetrics(ctx context.Context, opts api.ContractSetMetricsQueryOpts) ([]api.ContractSetMetric, error) ContractSetChurnMetrics(ctx context.Context, opts api.ContractSetChurnMetricsQueryOpts) ([]api.ContractSetChurnMetric, error) RecordContractSetChurnMetric(ctx context.Context, metrics ...api.ContractSetChurnMetric) error } @@ -1807,6 +1808,24 @@ func (b *bus) metricsHandlerGET(jc jape.Context) { key := jc.PathParam("key") var err error switch key { + case api.MetricContractSet: + var metrics []api.ContractSetMetric + var opts api.ContractSetMetricsQueryOpts + if jc.DecodeForm("after", (*api.TimeRFC3339)(&opts.After)) != nil { + return + } else if jc.DecodeForm("before", (*api.TimeRFC3339)(&opts.Before)) != nil { + return + } else if jc.DecodeForm("name", &opts.Name) != nil { + return + } else if jc.DecodeForm("offset", &opts.Offset) != nil { + return + } else if jc.DecodeForm("limit", &opts.Limit) != nil { + return + } else if metrics, err = b.mtrcs.ContractSetMetrics(jc.Request.Context(), opts); jc.Check("failed to get contract churn metrics", err) != nil { + return + } + jc.Encode(metrics) + return case api.MetricContractSetChurn: var metrics []api.ContractSetChurnMetric var opts api.ContractSetChurnMetricsQueryOpts diff --git a/bus/client/metrics.go b/bus/client/metrics.go index 84a0fab44..1e8914003 100644 --- a/bus/client/metrics.go +++ b/bus/client/metrics.go @@ -9,6 +9,31 @@ import ( "go.sia.tech/renterd/api" ) +func (c *Client) ContractSetMetrics(ctx context.Context, opts api.ContractSetMetricsQueryOpts) ([]api.ContractSetMetric, error) { + values := url.Values{} + if opts.After != (time.Time{}) { + values.Set("after", api.TimeRFC3339(opts.After).String()) + } + if opts.Before != (time.Time{}) { + values.Set("before", api.TimeRFC3339(opts.Before).String()) + } + if opts.Name != "" { + values.Set("name", opts.Name) + } + if opts.Offset != 0 { + values.Set("offset", fmt.Sprint(opts.Offset)) + } + if opts.Limit != 0 { + values.Set("limit", fmt.Sprint(opts.Limit)) + } + var resp []api.ContractSetMetric + err := c.c.WithContext(ctx).GET(fmt.Sprintf("/metrics/%s?"+values.Encode(), api.MetricContractSet), &resp) + if err != nil { + return nil, err + } + return resp, nil +} + func (c *Client) ContractSetChurnMetrics(ctx context.Context, opts api.ContractSetChurnMetricsQueryOpts) ([]api.ContractSetChurnMetric, error) { values := url.Values{} if opts.After != (time.Time{}) { diff --git a/internal/testing/cluster_test.go b/internal/testing/cluster_test.go index 3fc9ba9f2..cc5d02cc8 100644 --- a/internal/testing/cluster_test.go +++ b/internal/testing/cluster_test.go @@ -1944,26 +1944,52 @@ func TestMultipartUploads(t *testing.T) { } } -func TestRecordContractSetChurnMetric(t *testing.T) { +func TestRecordContractSetAndChurnMetric(t *testing.T) { + startTime := time.Now() + cluster := newTestCluster(t, clusterOptsDefault) defer cluster.Shutdown() // Add 1 host. cluster.AddHostsBlocking(1) + // Get contract set metrics. + csMetrics, err := cluster.Bus.ContractSetMetrics(context.Background(), api.ContractSetMetricsQueryOpts{}) + cluster.tt.OK(err) + + for i := 0; i < len(csMetrics); i++ { + // Remove metrics from before contract was formed. + if csMetrics[i].Contracts > 0 { + csMetrics = csMetrics[i:] + break + } + } + if len(csMetrics) == 0 { + t.Fatal("expected at least 1 metric with contracts") + } + for _, m := range csMetrics { + if m.Contracts != 1 { + t.Fatalf("expected 1 contract, got %v", m.Contracts) + } else if m.Name != testContractSet { + t.Fatalf("expected contract set %v, got %v", testContractSet, m.Name) + } else if !m.Time.After(startTime) { + t.Fatal("expected time to be after start time") + } + } + // Get churn metrics. Should have 1 for the new contract. - metrics, err := cluster.Bus.ContractSetChurnMetrics(context.Background(), api.ContractSetChurnMetricsQueryOpts{}) + cscMetrics, err := cluster.Bus.ContractSetChurnMetrics(context.Background(), api.ContractSetChurnMetricsQueryOpts{}) cluster.tt.OK(err) - if len(metrics) != 1 { - t.Fatalf("expected 1 metric, got %v", len(metrics)) - } else if m := metrics[0]; m.Direction != api.ChurnDirAdded { + if len(cscMetrics) != 1 { + t.Fatalf("expected 1 metric, got %v", len(cscMetrics)) + } else if m := cscMetrics[0]; m.Direction != api.ChurnDirAdded { t.Fatalf("expected added churn, got %v", m.Direction) } else if m.FCID == (types.FileContractID{}) { t.Fatal("expected non-zero FCID") } else if m.Name != testContractSet { t.Fatalf("expected contract set %v, got %v", testContractSet, m.Name) - } else if m.Time == (time.Time{}) { - t.Fatal("expected non-zero time") + } else if !m.Time.After(startTime) { + t.Fatal("expected time to be after start time") } }