diff --git a/executor/calibrate_resource.go b/executor/calibrate_resource.go index 2bb353ceb9d92..55081c4e5d192 100644 --- a/executor/calibrate_resource.go +++ b/executor/calibrate_resource.go @@ -195,11 +195,6 @@ func (e *calibrateResourceExec) Next(ctx context.Context, req *chunk.Chunk) erro return e.staticCalibrate(ctx, req, exec) } -var ( - errLowUsage = errors.Errorf("The workload in selected time window is too low, with which TiDB is unable to reach a capacity estimation; please select another time window with higher workload, or calibrate resource by hardware instead") - errNoCPUQuotaMetrics = errors.Normalize("There is no CPU quota metrics, %v") -) - func (e *calibrateResourceExec) dynamicCalibrate(ctx context.Context, req *chunk.Chunk, exec sqlexec.RestrictedSQLExecutor) error { startTs, endTs, err := e.parseCalibrateDuration() if err != nil { @@ -210,11 +205,11 @@ func (e *calibrateResourceExec) dynamicCalibrate(ctx context.Context, req *chunk totalKVCPUQuota, err := getTiKVTotalCPUQuota(ctx, exec) if err != nil { - return errNoCPUQuotaMetrics.FastGenByArgs(err.Error()) + return err } totalTiDBCPU, err := getTiDBTotalCPUQuota(ctx, exec) if err != nil { - return errNoCPUQuotaMetrics.FastGenByArgs(err.Error()) + return err } rus, err := getRUPerSec(ctx, exec, startTime, endTime) if err != nil { @@ -246,9 +241,8 @@ func (e *calibrateResourceExec) dynamicCalibrate(ctx context.Context, req *chunk } } if len(quotas) < 5 { - return errLowUsage + return errors.Errorf("There are too few metrics points available in selected time window") } -<<<<<<< HEAD if float64(len(quotas))/float64(len(quotas)+lowCount) > percentOfPass { sort.Slice(quotas, func(i, j int) bool { return quotas[i] > quotas[j] @@ -263,10 +257,6 @@ func (e *calibrateResourceExec) dynamicCalibrate(ctx context.Context, req *chunk req.AppendUint64(0, uint64(quota)) } else { return errors.Errorf("The workload in selected time window is too low, with which TiDB is unable to reach a capacity estimation; please select another time window with higher workload, or calibrate resource by hardware instead") -======= - if float64(len(quotas))/float64(len(quotas)+lowCount) <= percentOfPass { - return errLowUsage ->>>>>>> 841aed8d95a (calibrate: refactor metrics error (#44451)) } return nil } @@ -282,11 +272,11 @@ func (e *calibrateResourceExec) staticCalibrate(ctx context.Context, req *chunk. totalKVCPUQuota, err := getTiKVTotalCPUQuota(ctx, exec) if err != nil { - return errNoCPUQuotaMetrics.FastGenByArgs(err.Error()) + return err } totalTiDBCPU, err := getTiDBTotalCPUQuota(ctx, exec) if err != nil { - return errNoCPUQuotaMetrics.FastGenByArgs(err.Error()) + return err } // The default workload to calculate the RU capacity. @@ -349,14 +339,10 @@ func getValuesFromMetrics(ctx context.Context, exec sqlexec.RestrictedSQLExecuto if err != nil { return nil, errors.Trace(err) } -<<<<<<< HEAD if len(rows) == 0 { return nil, errors.Errorf("metrics '%s' is empty", metrics) } ret := make([]float64, 0, len(rows)) -======= - ret := make([]*timePointValue, 0, len(rows)) ->>>>>>> 841aed8d95a (calibrate: refactor metrics error (#44451)) for _, row := range rows { ret = append(ret, row.GetFloat64(0)) } diff --git a/executor/calibrate_resource_test.go b/executor/calibrate_resource_test.go index c90cfa50820a2..874eca8ddae38 100644 --- a/executor/calibrate_resource_test.go +++ b/executor/calibrate_resource_test.go @@ -95,30 +95,24 @@ func TestCalibrateResource(t *testing.T) { return time } - mockData := make(map[string][][]types.Datum) + mockData := map[string][][]types.Datum{ + "tikv_cpu_quota": { + types.MakeDatums(datetime("2020-02-12 10:35:00"), "tikv-0", 8.0), + types.MakeDatums(datetime("2020-02-12 10:35:00"), "tikv-1", 8.0), + types.MakeDatums(datetime("2020-02-12 10:35:00"), "tikv-2", 8.0), + types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-0", 8.0), + types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-1", 8.0), + types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-2", 8.0), + }, + "tidb_server_maxprocs": { + types.MakeDatums(datetime("2020-02-12 10:35:00"), "tidb-0", 40.0), + types.MakeDatums(datetime("2020-02-12 10:36:00"), "tidb-0", 40.0), + }, + } ctx := context.WithValue(context.Background(), "__mockMetricsTableData", mockData) ctx = failpoint.WithHook(ctx, func(_ context.Context, fpname string) bool { return fpName == fpname }) - rs, err = tk.Exec("CALIBRATE RESOURCE") - require.NoError(t, err) - require.NotNil(t, rs) - err = rs.Next(ctx, rs.NewChunk(nil)) - // because when mock metrics is empty, error is always `pd unavailable`, don't check detail. - require.ErrorContains(t, err, "There is no CPU quota metrics, query metric error: pd unavailable") - - mockData["tikv_cpu_quota"] = [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:35:00"), "tikv-0", 8.0), - types.MakeDatums(datetime("2020-02-12 10:35:00"), "tikv-1", 8.0), - types.MakeDatums(datetime("2020-02-12 10:35:00"), "tikv-2", 8.0), - types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-0", 8.0), - types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-1", 8.0), - types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-2", 8.0), - } - mockData["tidb_server_maxprocs"] = [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:35:00"), "tidb-0", 40.0), - types.MakeDatums(datetime("2020-02-12 10:36:00"), "tidb-0", 40.0), - } tk.MustQueryWithContext(ctx, "CALIBRATE RESOURCE").Check(testkit.Rows("69768")) tk.MustQueryWithContext(ctx, "CALIBRATE RESOURCE WORKLOAD TPCC").Check(testkit.Rows("69768")) tk.MustQueryWithContext(ctx, "CALIBRATE RESOURCE WORKLOAD OLTP_READ_WRITE").Check(testkit.Rows("55823")) @@ -249,211 +243,6 @@ func TestCalibrateResource(t *testing.T) { tk.MustQueryWithContext(ctx, "CALIBRATE RESOURCE END_TIME '2020-02-12 10:45:00' START_TIME '2020-02-12 10:35:00'").Check(testkit.Rows("5616")) tk.MustQueryWithContext(ctx, "CALIBRATE RESOURCE END_TIME '2020-02-12 10:45:00' DURATION '5m' START_TIME '2020-02-12 10:35:00' ").Check(testkit.Rows("5616")) -<<<<<<< HEAD -======= - // Statistical time points do not correspond - ruModify1 := [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:25:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:26:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:27:00"), 4.0), - types.MakeDatums(datetime("2020-02-12 10:28:00"), 6.0), - types.MakeDatums(datetime("2020-02-12 10:29:00"), 3.0), - types.MakeDatums(datetime("2020-02-12 10:30:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:31:00"), 7.0), - types.MakeDatums(datetime("2020-02-12 10:32:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:33:00"), 7.0), - types.MakeDatums(datetime("2020-02-12 10:34:00"), 8.0), - types.MakeDatums(datetime("2020-02-12 10:35:00"), 2200.0), - types.MakeDatums(datetime("2020-02-12 10:36:00"), 2100.0), - types.MakeDatums(datetime("2020-02-12 10:37:00"), 2250.0), - types.MakeDatums(datetime("2020-02-12 10:38:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:39:00"), 2230.0), - types.MakeDatums(datetime("2020-02-12 10:40:00"), 2210.0), - types.MakeDatums(datetime("2020-02-12 10:41:00"), 2250.0), - types.MakeDatums(datetime("2020-02-12 10:42:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:43:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:44:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:45:00"), 2280.0), - types.MakeDatums(datetime("2020-02-12 10:46:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:47:00"), 7.0), - types.MakeDatums(datetime("2020-02-12 10:48:00"), 8.0), - } - mockData["resource_manager_resource_unit"] = ruModify1 - tk.MustQueryWithContext(ctx, "CALIBRATE RESOURCE START_TIME '2020-02-12 10:25:00' DURATION '20m'").Check(testkit.Rows("5616")) - - ruModify2 := [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:25:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:26:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:27:00"), 4.0), - types.MakeDatums(datetime("2020-02-12 10:28:00"), 6.0), - types.MakeDatums(datetime("2020-02-12 10:29:00"), 2200.0), - types.MakeDatums(datetime("2020-02-12 10:30:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:31:00"), 7.0), - types.MakeDatums(datetime("2020-02-12 10:32:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:33:00"), 7.0), - types.MakeDatums(datetime("2020-02-12 10:34:00"), 8.0), - types.MakeDatums(datetime("2020-02-12 10:35:00"), 29.0), - types.MakeDatums(datetime("2020-02-12 10:36:00"), 2100.0), - types.MakeDatums(datetime("2020-02-12 10:37:00"), 49.0), - types.MakeDatums(datetime("2020-02-12 10:38:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:39:00"), 2230.0), - types.MakeDatums(datetime("2020-02-12 10:40:00"), 2210.0), - types.MakeDatums(datetime("2020-02-12 10:41:00"), 47.0), - types.MakeDatums(datetime("2020-02-12 10:42:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:43:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:44:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:45:00"), 2280.0), - types.MakeDatums(datetime("2020-02-12 10:47:00"), 2250.0), - types.MakeDatums(datetime("2020-02-12 10:49:00"), 2250.0), - } - mockData["resource_manager_resource_unit"] = ruModify2 - cpu2Mofidy := [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:29:00"), "tidb-0", "tidb", 3.212), - types.MakeDatums(datetime("2020-02-12 10:36:00"), "tidb-0", "tidb", 3.233), - types.MakeDatums(datetime("2020-02-12 10:38:00"), "tidb-0", "tidb", 3.213), - types.MakeDatums(datetime("2020-02-12 10:39:00"), "tidb-0", "tidb", 3.209), - types.MakeDatums(datetime("2020-02-12 10:40:00"), "tidb-0", "tidb", 3.213), - types.MakeDatums(datetime("2020-02-12 10:42:00"), "tidb-0", "tidb", 3.228), - types.MakeDatums(datetime("2020-02-12 10:43:00"), "tidb-0", "tidb", 3.219), - types.MakeDatums(datetime("2020-02-12 10:44:00"), "tidb-0", "tidb", 3.220), - types.MakeDatums(datetime("2020-02-12 10:45:00"), "tidb-0", "tidb", 3.221), - types.MakeDatums(datetime("2020-02-12 10:46:00"), "tidb-0", "tidb", 3.220), - types.MakeDatums(datetime("2020-02-12 10:47:00"), "tidb-0", "tidb", 3.236), - types.MakeDatums(datetime("2020-02-12 10:48:00"), "tidb-0", "tidb", 3.220), - types.MakeDatums(datetime("2020-02-12 10:49:00"), "tidb-0", "tidb", 3.234), - types.MakeDatums(datetime("2020-02-12 10:29:00"), "tikv-1", "tikv", 2.212), - types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-1", "tikv", 2.233), - types.MakeDatums(datetime("2020-02-12 10:49:00"), "tikv-1", "tikv", 2.234), - types.MakeDatums(datetime("2020-02-12 10:38:00"), "tikv-1", "tikv", 2.213), - types.MakeDatums(datetime("2020-02-12 10:39:00"), "tikv-1", "tikv", 2.209), - types.MakeDatums(datetime("2020-02-12 10:46:00"), "tikv-1", "tikv", 3.220), - types.MakeDatums(datetime("2020-02-12 10:40:00"), "tikv-1", "tikv", 2.213), - types.MakeDatums(datetime("2020-02-12 10:47:00"), "tikv-1", "tikv", 2.236), - types.MakeDatums(datetime("2020-02-12 10:42:00"), "tikv-1", "tikv", 2.228), - types.MakeDatums(datetime("2020-02-12 10:43:00"), "tikv-1", "tikv", 2.219), - types.MakeDatums(datetime("2020-02-12 10:44:00"), "tikv-1", "tikv", 2.220), - types.MakeDatums(datetime("2020-02-12 10:45:00"), "tikv-1", "tikv", 2.281), - types.MakeDatums(datetime("2020-02-12 10:29:00"), "tikv-0", "tikv", 2.282), - types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-0", "tikv", 2.283), - types.MakeDatums(datetime("2020-02-12 10:49:00"), "tikv-0", "tikv", 2.284), - types.MakeDatums(datetime("2020-02-12 10:38:00"), "tikv-0", "tikv", 2.283), - types.MakeDatums(datetime("2020-02-12 10:39:00"), "tikv-0", "tikv", 2.289), - types.MakeDatums(datetime("2020-02-12 10:40:00"), "tikv-0", "tikv", 2.283), - types.MakeDatums(datetime("2020-02-12 10:47:00"), "tikv-0", "tikv", 2.286), - types.MakeDatums(datetime("2020-02-12 10:42:00"), "tikv-0", "tikv", 2.288), - types.MakeDatums(datetime("2020-02-12 10:43:00"), "tikv-0", "tikv", 2.289), - types.MakeDatums(datetime("2020-02-12 10:44:00"), "tikv-0", "tikv", 2.280), - types.MakeDatums(datetime("2020-02-12 10:45:00"), "tikv-0", "tikv", 2.281), - types.MakeDatums(datetime("2020-02-12 10:29:00"), "tikv-2", "tikv", 2.112), - types.MakeDatums(datetime("2020-02-12 10:36:00"), "tikv-2", "tikv", 2.133), - types.MakeDatums(datetime("2020-02-12 10:49:00"), "tikv-2", "tikv", 2.134), - types.MakeDatums(datetime("2020-02-12 10:38:00"), "tikv-2", "tikv", 2.113), - types.MakeDatums(datetime("2020-02-12 10:39:00"), "tikv-2", "tikv", 2.109), - types.MakeDatums(datetime("2020-02-12 10:40:00"), "tikv-2", "tikv", 2.113), - types.MakeDatums(datetime("2020-02-12 10:47:00"), "tikv-2", "tikv", 2.136), - types.MakeDatums(datetime("2020-02-12 10:42:00"), "tikv-2", "tikv", 2.128), - types.MakeDatums(datetime("2020-02-12 10:43:00"), "tikv-2", "tikv", 2.119), - types.MakeDatums(datetime("2020-02-12 10:44:00"), "tikv-2", "tikv", 2.120), - types.MakeDatums(datetime("2020-02-12 10:45:00"), "tikv-2", "tikv", 2.281), - types.MakeDatums(datetime("2020-02-12 10:48:00"), "tikv-2", "tikv", 3.220), - } - mockData["process_cpu_usage"] = cpu2Mofidy - tk.MustQueryWithContext(ctx, "CALIBRATE RESOURCE START_TIME '2020-02-12 10:25:00' DURATION '20m'").Check(testkit.Rows("5616")) - - ruModify3 := [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:25:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:26:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:27:00"), 4.0), - types.MakeDatums(datetime("2020-02-12 10:28:00"), 6.0), - types.MakeDatums(datetime("2020-02-12 10:29:00"), 2200.0), - types.MakeDatums(datetime("2020-02-12 10:30:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:31:00"), 7.0), - types.MakeDatums(datetime("2020-02-12 10:32:00"), 5.0), - types.MakeDatums(datetime("2020-02-12 10:33:00"), 7.0), - types.MakeDatums(datetime("2020-02-12 10:34:00"), 8.0), - types.MakeDatums(datetime("2020-02-12 10:35:00"), 29.0), - types.MakeDatums(datetime("2020-02-12 10:36:20"), 2100.0), - types.MakeDatums(datetime("2020-02-12 10:37:00"), 49.0), - types.MakeDatums(datetime("2020-02-12 10:38:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:39:00"), 2230.0), - types.MakeDatums(datetime("2020-02-12 10:40:00"), 2210.0), - types.MakeDatums(datetime("2020-02-12 10:41:00"), 47.0), - types.MakeDatums(datetime("2020-02-12 10:42:20"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:43:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:44:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:45:00"), 2280.0), - types.MakeDatums(datetime("2020-02-12 10:47:00"), 2250.0), - types.MakeDatums(datetime("2020-02-12 10:49:00"), 2250.0), - } - mockData["resource_manager_resource_unit"] = ruModify3 - // because there are 20s difference in two time points, the result is changed. - tk.MustQueryWithContext(ctx, "CALIBRATE RESOURCE START_TIME '2020-02-12 10:25:00' DURATION '20m'").Check(testkit.Rows("5613")) - - ru2 := [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:25:00"), 2200.0), - types.MakeDatums(datetime("2020-02-12 10:26:00"), 2100.0), - types.MakeDatums(datetime("2020-02-12 10:27:00"), 2250.0), - types.MakeDatums(datetime("2020-02-12 10:28:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:29:00"), 2230.0), - types.MakeDatums(datetime("2020-02-12 10:30:00"), 2210.0), - types.MakeDatums(datetime("2020-02-12 10:31:00"), 2250.0), - types.MakeDatums(datetime("2020-02-12 10:32:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:33:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:34:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:35:00"), 2280.0), - } - mockData["resource_manager_resource_unit"] = ru2 - rs, err = tk.Exec("CALIBRATE RESOURCE START_TIME '2020-02-12 10:25:00' DURATION '20m'") - require.NoError(t, err) - require.NotNil(t, rs) - err = rs.Next(ctx, rs.NewChunk(nil)) - require.ErrorContains(t, err, "The workload in selected time window is too low") - - ru3 := [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:25:00"), 2200.0), - types.MakeDatums(datetime("2020-02-12 10:27:00"), 2100.0), - types.MakeDatums(datetime("2020-02-12 10:28:00"), 2250.0), - types.MakeDatums(datetime("2020-02-12 10:30:00"), 2300.0), - types.MakeDatums(datetime("2020-02-12 10:31:00"), 2230.0), - types.MakeDatums(datetime("2020-02-12 10:33:00"), 2210.0), - types.MakeDatums(datetime("2020-02-12 10:34:00"), 2250.0), - types.MakeDatums(datetime("2020-02-12 10:36:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:37:00"), 2330.0), - types.MakeDatums(datetime("2020-02-12 10:39:00"), 2280.0), - types.MakeDatums(datetime("2020-02-12 10:40:00"), 2280.0), - types.MakeDatums(datetime("2020-02-12 10:42:00"), 2280.0), - types.MakeDatums(datetime("2020-02-12 10:43:00"), 2280.0), - } - mockData["resource_manager_resource_unit"] = ru3 - cpu3 := [][]types.Datum{ - types.MakeDatums(datetime("2020-02-12 10:26:00"), "tidb-0", "tidb", 3.212), - types.MakeDatums(datetime("2020-02-12 10:29:00"), "tidb-0", "tidb", 3.233), - types.MakeDatums(datetime("2020-02-12 10:32:00"), "tidb-0", "tidb", 3.213), - types.MakeDatums(datetime("2020-02-12 10:35:00"), "tidb-0", "tidb", 3.209), - types.MakeDatums(datetime("2020-02-12 10:38:00"), "tidb-0", "tidb", 3.213), - types.MakeDatums(datetime("2020-02-12 10:41:00"), "tidb-0", "tidb", 3.228), - types.MakeDatums(datetime("2020-02-12 10:44:00"), "tidb-0", "tidb", 3.219), - - types.MakeDatums(datetime("2020-02-12 10:26:00"), "tikv-0", "tikv", 2.282), - types.MakeDatums(datetime("2020-02-12 10:29:00"), "tikv-0", "tikv", 2.283), - types.MakeDatums(datetime("2020-02-12 10:32:00"), "tikv-0", "tikv", 2.284), - types.MakeDatums(datetime("2020-02-12 10:35:00"), "tikv-0", "tikv", 2.283), - types.MakeDatums(datetime("2020-02-12 10:38:00"), "tikv-0", "tikv", 2.289), - types.MakeDatums(datetime("2020-02-12 10:41:00"), "tikv-0", "tikv", 2.283), - types.MakeDatums(datetime("2020-02-12 10:44:00"), "tikv-0", "tikv", 2.286), - } - mockData["process_cpu_usage"] = cpu3 - rs, err = tk.Exec("CALIBRATE RESOURCE START_TIME '2020-02-12 10:25:00' DURATION '20m'") - require.NoError(t, err) - require.NotNil(t, rs) - err = rs.Next(ctx, rs.NewChunk(nil)) - require.ErrorContains(t, err, "The workload in selected time window is too low") - - // flash back to init data. - mockData["resource_manager_resource_unit"] = ru1 - mockData["process_cpu_usage"] = cpu2 - ->>>>>>> 841aed8d95a (calibrate: refactor metrics error (#44451)) rs, err = tk.Exec("CALIBRATE RESOURCE START_TIME '2020-02-12 10:35:00'") require.NoError(t, err) require.NotNil(t, rs) @@ -559,14 +348,7 @@ func TestCalibrateResource(t *testing.T) { require.NoError(t, err) require.NotNil(t, rs) err = rs.Next(ctx, rs.NewChunk(nil)) - require.ErrorContains(t, err, "The workload in selected time window is too low") - - delete(mockData, "process_cpu_usage") - rs, err = tk.Exec("CALIBRATE RESOURCE START_TIME '2020-02-12 10:35:00' END_TIME '2020-02-12 10:45:00'") - require.NoError(t, err) - require.NotNil(t, rs) - err = rs.Next(ctx, rs.NewChunk(nil)) - require.ErrorContains(t, err, "query metric error: pd unavailable") + require.ErrorContains(t, err, "There are too few metrics points available in selected time window") } type mockResourceGroupProvider struct {