From 0ebc36b2a7118d62829c70b78e413fcc5600a3cf Mon Sep 17 00:00:00 2001 From: Fred Park Date: Fri, 3 Jan 2025 09:03:57 -0800 Subject: [PATCH 1/6] correctness testing 2.0 --- Dockerfile | 3 - correctness/README.md | 48 +- correctness/config/correctness_testing.yml | 19 - correctness/correctness_test.go | 675 +++++++++++++++++---- correctness/data/expectedOutput.csv | 77 --- correctness/data/functions.txt | 50 -- correctness/data/operators.txt | 9 - correctness/data/series.txt | 17 - correctness/go.mod | 40 ++ correctness/go.sum | 192 ++++++ correctness/mockmetheus.go | 281 +++++++++ docker-compose.yml | 6 +- main.go | 11 +- main_test.go | 19 +- timestream/client.go | 10 +- 15 files changed, 1146 insertions(+), 311 deletions(-) delete mode 100644 correctness/config/correctness_testing.yml delete mode 100644 correctness/data/expectedOutput.csv delete mode 100644 correctness/data/functions.txt delete mode 100644 correctness/data/operators.txt delete mode 100644 correctness/data/series.txt create mode 100644 correctness/go.mod create mode 100644 correctness/go.sum create mode 100644 correctness/mockmetheus.go diff --git a/Dockerfile b/Dockerfile index a335ec8..e478721 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,9 +34,6 @@ RUN go mod download COPY . . -# Run unit tests for main.go and client.go -RUN CGO_ENABLED=0 go test -tags=unit -cover -v ./timestream ./ - # Build the binary for Linux. RUN CGO_ENABLED=0 GOOS=linux go build -o ./timestream-prometheus-connector . diff --git a/correctness/README.md b/correctness/README.md index d6289fe..5b23c0c 100644 --- a/correctness/README.md +++ b/correctness/README.md @@ -1,18 +1,36 @@ # Correctness Testing for Prometheus Connector ## Prerequisites -Prior to running the tests in correctness_test.go, ensure the following: -1. Have a database called correctness_testing with the table named correctness_testing created. -2. Ingested data to the correctness_testing table for at least an hour. -3. Updated the basic_auth section within [correctness_testing.yml](./config/correctness_testing.yml). -2. Download or build the Prometheus Connector Docker image and store it in a new directory named `resources` in the repository root. - -## How to build and save the docker image -1. Execute the following command to build the docker image: -`docker buildx build . -t timestream-prometheus-connector-docker` -2. Execute the following command to save the docker image as a compressed file and update the `version` appropriately: -`docker save timestream-prometheus-connector-docker | gzip > timestream-prometheus-connector-docker-image-.tar.gz` - -## How to execute tests -1. Run the following command to execute the correctness tests: -`go test -v ./correctness` +1. Ensure your AWS credentials are configured for your environment. You can configure it with `aws configure`. + +2. Create a new Timestream database and table: +``` +aws timestream-write create-database --database-name CorrectnessDB --region us-west-2 && aws timestream-write create-table --database-name CorrectnessDB --table-name CorrectnessMetrics +``` + +## Run Correctness Tests +1. Update the default database and table in [`docker-compose.yml`](https://github.com/awslabs/amazon-timestream-connector-prometheus/blob/main/docker-compose.yml) with your new Timestream database and table. + +2. Bring up the Prometheus Connector: +``` +`docker compose -f ../docker-compose.yml up -d` +``` + +3. Run `go test -v`. Tests can take between 15~20 seconds to complete. + +### Tips + +- To run correctness tests against an existing Timestream database, ensure the `freshTSDB` flag is disabled in the test suite. +- The `ingestionWaitTime` parameter is adjustable to account for network latency, ensuring data ingestion is complete before evaluating test outputs. + +## Clean up +1. Delete your Timestream database: + +``` +aws timestream-write delete-table --database-name CorrDB --table-name CorrMetrics --region us-west-2 && aws timestream-write delete-database --database-name CorrDB +```` + +2. Bring down the Connector with: +``` +docker compose -f ../docker-compose.yml down +``` diff --git a/correctness/config/correctness_testing.yml b/correctness/config/correctness_testing.yml deleted file mode 100644 index 542c68f..0000000 --- a/correctness/config/correctness_testing.yml +++ /dev/null @@ -1,19 +0,0 @@ -global: - scrape_interval: 60s - evaluation_interval: 60s - -scrape_configs: - - job_name: 'prometheus' - scrape_interval: 15s - - static_configs: - - targets: ['localhost:9090'] - -remote_read: - - url: "http://host.docker.internal:9201/read" - read_recent: true - - basic_auth: - # Update the user name and password with valid IAM credentials. - username: accessKey - password: secretAccessKey diff --git a/correctness/correctness_test.go b/correctness/correctness_test.go index 849991a..118f71f 100644 --- a/correctness/correctness_test.go +++ b/correctness/correctness_test.go @@ -11,155 +11,616 @@ CONDITIONS OF ANY KIND, either express or implied. See the License for the speci and limitations under the License. */ -// This package executes all types of PromQLs Prometheus may send to the Prometheus Connector, which will output the -// responses for the PromQLs to expectedOutput.csv for manual verification. The intent of this test is to ensure the -// Prometheus Connector can properly translate PromQLs to Amazon Timestream SQLs. -// -// Prior to running the tests in this file, ensure valid IAM credentials are specified in the basic auth section within -// config/prometheus.yml. +// This test suite validates the correctness of the Prometheus Connector using Mockmetheus +// to execute remote-read and remote-write operations. It covers various scenarios by +// executing queries against a locally hosted Connector connected to a Timestream database. package correctness import ( - "bufio" "context" - "encoding/csv" - "io" + "fmt" + "math/rand" "os" - "path/filepath" + "strings" "testing" "time" - "timestream-prometheus-connector/integration" - "timestream-prometheus-connector/timestream" +) - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" +// Enable this flag when working with a fresh Timestream database. +var freshTSDB = false - "github.com/docker/docker/client" -) +// ingestionWaitTime is the duration to wait for data ingestion. +var ingestionWaitTime = 1 * time.Second -const ( - expectedOutputFilePath = "data/expectedOutput.csv" - prometheusDockerImage = "docker.io/prom/prometheus" - prometheusConfigPath = "config/correctness_testing.yml" - prometheusDockerImageName = "prom/prometheus" - connectorDockerImageName = "timestream-prometheus-connector-docker" -) +// Shared Mockmetheus instance +var m *Mockmetheus -var ( - containerIDs []string - connectorCMDs = []string{"--default-database=timestreamDatabase", "--default-table=timestreamTable", "--log.level=debug"} - headers = []string{"PromQL", "Read Response"} -) +func TestMain(main *testing.M) { + var err error + m, err = NewMockmetheus("http://0.0.0.0:9201") + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to initialize Mockmetheus: %v\n", err) + os.Exit(1) + } + + code := main.Run() + + os.Exit(code) +} -func TestQueries(t *testing.T) { - files, err := filepath.Glob("data/*.txt") - require.NoError(t, err) +func TestEmptyOnInit(t *testing.T) { + ctx := context.Background() + var query string + + if freshTSDB { + // Test empty on initialization + query = "prometheus_http_requests_total{}" + } else { + // For running against an existing Timestream DB, wait for a few + // seconds to avoid conflicting results + time.Sleep(3 * time.Second) + query = "prometheus_http_requests_total{}[3s]" + } - var promQL []string - for _, file := range files { - promQL = loadPromQLFromFile(t, file, promQL) + resp, err := m.RemoteRead(ctx, query) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) } - dockerClient, ctx := integration.CreateDockerClient(t) + if !isEmpty(resp) { + t.Errorf("expected empty results but got non-empty") + } +} + +func TestReadMetricDNE(t *testing.T) { + ctx := context.Background() - connectorConfig := integration.ConnectorContainerConfig{ - DockerImage: "../resources/timestream-prometheus-connector-docker-image-" + timestream.Version + ".tar.gz", - ImageName: connectorDockerImageName, - ConnectorCommands: connectorCMDs, + query := "non_existent_metric" + resp, err := m.RemoteRead(ctx, query) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) + } + if !isEmpty(resp) { + t.Errorf("expected empty results for DNE metric but got non-empty") } +} - containerIDs = append(containerIDs, integration.StartConnector(t, dockerClient, ctx, connectorConfig)) +func TestWriteNoData(t *testing.T) { + ctx := context.Background() - prometheusConfig := integration.PrometheusContainerConfig{ - DockerImage: prometheusDockerImage, - ImageName: prometheusDockerImageName, - ConfigPath: prometheusConfigPath, + var data []TimeSeriesData // empty + err := m.RemoteWrite(ctx, data) + if err != nil { + t.Fatalf("RemoteWrite returned an error: %v", err) } - containerIDs = append(containerIDs, integration.StartPrometheus(t, dockerClient, ctx, prometheusConfig)) +} - output, err := sendRequest(t, promQL) - errorCheck(t, err, dockerClient, ctx) - err = writeToFile(output) - errorCheck(t, err, dockerClient, ctx) +func TestWriteNoLabels(t *testing.T) { + ctx := context.Background() - integration.StopContainer(t, dockerClient, ctx, containerIDs) + data := []TimeSeriesData{ + { + Labels: map[string]string{}, + Samples: []SampleData{ + {Value: 220, Timestamp: time.Now().UnixMilli()}, + }, + }, + } + err := m.RemoteWrite(ctx, data) + if err == nil { + t.Fatal("expected an error (status code 400), but got nil") + } + if !strings.Contains(err.Error(), "status code 400") { + t.Errorf("expected status code 400 error, got: %v", err) + } } -// loadPromQLFromFile loads the PromQL for correctness testing from the specified filepath. -func loadPromQLFromFile(t *testing.T, filePath string, queries []string) []string { - file, err := os.Open(filePath) - require.NoError(t, err) +func TestWriteNoSamples(t *testing.T) { + ctx := context.Background() - defer file.Close() + name := "prometheus_http_requests_total" + instance := "mockmetheus" - scanner := bufio.NewScanner(file) - for scanner.Scan() { - text := scanner.Text() - if len(text) != 0 { - queries = append(queries, scanner.Text()) - } + data := []TimeSeriesData{ + { + Labels: map[string]string{ + "__name__": name, + "instance": instance, + }, + Samples: []SampleData{}, // no samples + }, } + if err := m.RemoteWrite(ctx, data); err != nil { + t.Fatalf("RemoteWrite error: %v", err) + } + + // Wait to ensure ingestion + time.Sleep(ingestionWaitTime) - assert.Nil(t, scanner.Err()) - return queries + // query for within the last 2 seconds, accounting for ingestion delay + waitSeconds := int(ingestionWaitTime.Seconds()) + 2 + query := fmt.Sprintf(`%s{instance="%s"}[%ds]`, name, instance, waitSeconds) + resp, err := m.RemoteRead(ctx, query) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) + } + if !isEmpty(resp) { + t.Errorf("expected empty results but got non-empty") + } } -// sendRequest executes the given slice of PromQL through the Prometheus HTTP API. -func sendRequest(t *testing.T, queries []string) ([][]string, error) { - output := [][]string{headers} - - httpClient := integration.CreateHTTPClient() - now := time.Now() - prevHour := now.Add(time.Duration(-1) * time.Hour) - - for i := range queries { - query := queries[i] - req := integration.CreateReadRequest(t, query, now, prevHour) - - // Requests will fail while the Prometheus server is still setting up, retry until Prometheus server is ready to receive web requests. - retries := 0 - for retries <= 10 { - resp, err := httpClient.Do(req) - if err == nil { - body, err := io.ReadAll(resp.Body) - if err != nil { - return output, err - } - output = append(output, []string{query, string(body)}) - break - } - - time.Sleep(5 * time.Second) - retries++ - } +func TestSuccess(t *testing.T) { + ctx := context.Background() + + name := "prometheus_http_requests_total" + instance := "mockmetheus" + expectedSample := 220.0 + testID := generateTestRunID() + + data := []TimeSeriesData{ + { + Labels: map[string]string{ + "__name__": name, + "instance": instance, + "test_id": testID, + }, + Samples: []SampleData{ + {Value: expectedSample, Timestamp: time.Now().UnixMilli()}, + }, + }, + } + if err := m.RemoteWrite(ctx, data); err != nil { + t.Fatalf("RemoteWrite error: %v", err) } - return output, nil + time.Sleep(ingestionWaitTime) + + waitSeconds := int(ingestionWaitTime.Seconds()) + 2 + query := fmt.Sprintf(`%s{instance="%s", test_id="%s"}[%ds]`, name, instance, testID, waitSeconds) + resp, err := m.RemoteRead(ctx, query) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) + } + if isEmpty(resp) { + t.Errorf("expected non-empty results but got empty") + } + + // Validate the returned value by parsing out the time series + v, err := getFirstSampleValue(resp) + if err != nil { + t.Fatalf("error getting sample value: %v", err) + } + if v != expectedSample { + t.Errorf("expected sample value %.2f, got %.2f", expectedSample, v) + } } -// errorCheck stops and removes the Docker container if an error has occurred. -func errorCheck(t *testing.T, err error, dockerClient *client.Client, ctx context.Context) { +func TestSuccessWriteMultipleMetrics(t *testing.T) { + ctx := context.Background() + + name := "prometheus_http_requests_total" + handler := "/api/v1/query" + instance := "mockmetheus" + job := "prometheus" + sample1 := 300.0 + + name2 := "mockmetheus_custom_metric" + sample2 := 400.0 + testID := generateTestRunID() + + data := []TimeSeriesData{ + { + Labels: map[string]string{ + "__name__": name, + "handler": handler, + "instance": instance, + "test_id": testID, + "job": job, + }, + Samples: []SampleData{ + {Value: sample1, Timestamp: time.Now().UnixMilli()}, + }, + }, + { + Labels: map[string]string{ + "__name__": name2, + "handler": handler, + "instance": instance, + "test_id": testID, + "job": job, + }, + Samples: []SampleData{ + {Value: sample2, Timestamp: time.Now().UnixMilli()}, + }, + }, + } + if err := m.RemoteWrite(ctx, data); err != nil { + t.Fatalf("RemoteWrite error: %v", err) + } + + time.Sleep(ingestionWaitTime) + + waitSeconds := int(ingestionWaitTime.Seconds()) + 2 + + // Query for first metric + query1 := fmt.Sprintf(`%s{instance="%s", test_id="%s"}[%ds]`, name, instance, testID, waitSeconds) + resp1, err := m.RemoteRead(ctx, query1) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) + } + if isEmpty(resp1) { + t.Errorf("expected non-empty results (metric1) but got empty") + } + v1, err := getFirstSampleValue(resp1) + if err != nil { + t.Fatalf("error getting sample value (metric1): %v", err) + } + if v1 != sample1 { + t.Errorf("expected sample value %.2f, got %.2f (metric1)", sample1, v1) + } + + // Query for second metric + query2 := fmt.Sprintf(`%s{instance="%s", job="%s", test_id="%s"}[3s]`, name2, instance, job, testID) + resp2, err := m.RemoteRead(ctx, query2) if err != nil { - integration.StopContainer(t, dockerClient, ctx, containerIDs) - t.Fail() + t.Fatalf("RemoteRead error: %v", err) + } + if isEmpty(resp2) { + t.Errorf("expected non-empty results (metric2) but got empty") + } + v2, err := getFirstSampleValue(resp2) + if err != nil { + t.Fatalf("error getting sample value (metric2): %v", err) + } + if v2 != sample2 { + t.Errorf("expected sample value %.2f, got %.2f (metric2)", sample2, v2) } } -// writeToFile writes the PromQL executed and the prompb.ReadResponse to a CSV file. -func writeToFile(output [][]string) error { - file, err := os.OpenFile(expectedOutputFilePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) +func TestSuccessMultipleSamples(t *testing.T) { + ctx := context.Background() + + name := "prometheus_http_requests_total" + handler := "/api/v1/query" + instance := "mockmetheus" + job := "prometheus" + sample1 := 300.0 + sample2 := 400.0 + testID := generateTestRunID() + + data := []TimeSeriesData{ + { + Labels: map[string]string{ + "__name__": name, + "handler": handler, + "instance": instance, + "test_id": testID, + "job": job, + }, + Samples: []SampleData{ + {Value: sample1, Timestamp: time.Now().UnixMilli()}, + {Value: sample2, Timestamp: time.Now().UnixMilli() - 100}, + }, + }, + } + if err := m.RemoteWrite(ctx, data); err != nil { + t.Fatalf("RemoteWrite error: %v", err) + } + + time.Sleep(ingestionWaitTime) + + waitSeconds := int(ingestionWaitTime.Seconds()) + 2 + + // Query for first metric + query := fmt.Sprintf(`%s{handler="%s", instance="%s", job="%s", test_id="%s"}[%ds]`, + name, handler, instance, job, testID, waitSeconds, + ) + resp, err := m.RemoteRead(ctx, query) if err != nil { - return err + t.Fatalf("RemoteRead error: %v", err) + } + if isEmpty(resp) { + t.Errorf("expected non-empty results but got empty") } - csvWriter := csv.NewWriter(file) - defer csvWriter.Flush() + // We expect multiple samples in ascending order by timestamp + tsSamples, err := getSampleValues(resp) + if err != nil { + t.Fatalf("error parsing samples: %v", err) + } + if len(tsSamples) != 2 { + t.Fatalf("expected 2 samples, got %d", len(tsSamples)) + } + if tsSamples[0] != sample2 { + t.Errorf("expected first sample value=%.2f, got=%.2f", sample2, tsSamples[0]) + } + if tsSamples[1] != sample1 { + t.Errorf("expected second sample value=%.2f, got=%.2f", sample1, tsSamples[1]) + } +} - if err := csvWriter.WriteAll(output); err != nil { - file.Close() - return err +func TestSuccessLabelMatchers(t *testing.T) { + ctx := context.Background() + + name := "prometheus_http_requests_total" + handler := "/api/v1/query" + instance := "mockmetheus" + job1 := "prometheus" + code1 := "200" + expected1 := 100.0 + + // second job & code + job2 := "mockmetheus" + code2 := "400" + expected2 := 200.0 + expected3 := 300.0 // third sample for job2 + + // third code + code3 := "404" + expected4 := 100.0 + + testID := generateTestRunID() + + data := []TimeSeriesData{ + { + // timeseries #1 + Labels: map[string]string{ + "__name__": name, + "handler": handler, + "instance": instance, + "test_id": testID, + "job": job1, + "code": code1, + }, + Samples: []SampleData{ + {Value: expected1, Timestamp: time.Now().UnixMilli()}, + {Value: expected2, Timestamp: time.Now().UnixMilli() - 100}, + }, + }, + { + // timeseries #2 + Labels: map[string]string{ + "__name__": name, + "handler": handler, + "instance": instance, + "test_id": testID, + "job": job2, + "code": code2, + }, + Samples: []SampleData{ + {Value: expected1, Timestamp: time.Now().UnixMilli()}, + {Value: expected2, Timestamp: time.Now().UnixMilli() - 100}, + {Value: expected3, Timestamp: time.Now().UnixMilli() - 200}, + }, + }, + { + // timeseries #3 + Labels: map[string]string{ + "__name__": name, + "handler": handler, + "instance": instance, + "test_id": testID, + "job": job1, + "code": code3, + }, + Samples: []SampleData{ + {Value: expected4, Timestamp: time.Now().UnixMilli()}, + }, + }, } + if err := m.RemoteWrite(ctx, data); err != nil { + t.Fatalf("RemoteWrite error: %v", err) + } + time.Sleep(ingestionWaitTime) + + waitSeconds := int(ingestionWaitTime.Seconds()) + 2 - file.Close() - return nil + // NEQ matcher: job != job1 + // => Should return only timeseries #2 + query := fmt.Sprintf(`%s{job!="%s", test_id="%s"}[%ds]`, name, job1, testID, waitSeconds) + resp, err := m.RemoteRead(ctx, query) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) + } + if isEmpty(resp) { + t.Fatalf("expected non-empty results but got empty (NEQ matcher)") + } + numTS, numSamples := countTimeSeriesAndSamples(resp) + if numTS != 1 { + t.Errorf("expected 1 timeseries for job!=%s, got %d", job1, numTS) + } + // timeseries #2 has 3 samples + if numSamples != 3 { + t.Errorf("expected 3 samples in timeseries #2, got %d", numSamples) + } + + // NRE matcher: code!~"2.." + // => Should return any timeseries whose code does not match 2xx + // timeseries #1 has code=200 (excluded), #2 has code=400 (included), #3 has code=404 (included) + query = fmt.Sprintf(`%s{code!~"2..", test_id="%s"}[%ds]`, name, testID, waitSeconds) + resp, err = m.RemoteRead(ctx, query) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) + } + if isEmpty(resp) { + t.Fatalf("expected non-empty results but got empty (NRE matcher)") + } + numTS, _ = countTimeSeriesAndSamples(resp) + if numTS != 2 { + t.Errorf("expected 2 timeseries (codes 400,404), got %d", numTS) + } + + // NEQ + NRE matcher + // job="{job2}" AND code!~"2.." + // => Should return timeseries #2 only + query = fmt.Sprintf(`%s{job="%s", code!~"2..", test_id="%s"}[%ds]`, name, job2, testID, waitSeconds+1) + resp, err = m.RemoteRead(ctx, query) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) + } + if isEmpty(resp) { + t.Fatalf("expected non-empty results but got empty (NEQ+NRE matcher)") + } + numTS, numSamples = countTimeSeriesAndSamples(resp) + if numTS != 1 { + t.Errorf("expected 1 timeseries, got %d", numTS) + } + if numSamples != 3 { + t.Errorf("expected 3 samples for that timeseries, got %d", numSamples) + } +} + +// ---------------------------------------------------------------------------- +// Helper functions +// ---------------------------------------------------------------------------- +// Checks if the `results` array is empty or if the first result has no `timeseries`. +func isEmpty(response map[string]interface{}) bool { + results, ok := response["results"].([]interface{}) + if !ok || len(results) == 0 { + return true + } + + firstResult, ok := results[0].(map[string]interface{}) + if !ok { + return true + } + + timeseriesList, ok := firstResult["timeseries"].([]interface{}) + if !ok || len(timeseriesList) == 0 { + return true + } + + return false +} + +// getFirstSampleValue tries to return the first sample value from the first timeseries. +func getFirstSampleValue(response map[string]interface{}) (float64, error) { + results, ok := response["results"].([]interface{}) + if !ok || len(results) == 0 { + return 0, fmt.Errorf("no results found") + } + + firstResult, ok := results[0].(map[string]interface{}) + if !ok { + return 0, fmt.Errorf("invalid results[0] format") + } + + timeseriesList, ok := firstResult["timeseries"].([]interface{}) + if !ok || len(timeseriesList) == 0 { + return 0, fmt.Errorf("no timeseries in firstResult") + } + + firstTimeseries, ok := timeseriesList[0].(map[string]interface{}) + if !ok { + return 0, fmt.Errorf("invalid timeseries[0] format") + } + + samplesList, ok := firstTimeseries["samples"].([]interface{}) + if !ok || len(samplesList) == 0 { + return 0, fmt.Errorf("no samples in firstTimeseries") + } + + firstSample, ok := samplesList[0].(map[string]interface{}) + if !ok { + return 0, fmt.Errorf("invalid sample format") + } + + value, ok := firstSample["value"].(float64) + if !ok { + return 0, fmt.Errorf("sample value not float64") + } + + return value, nil +} + +// getSampleValues returns all sample values from the first timeseries. +func getSampleValues(response map[string]interface{}) ([]float64, error) { + var sampleValues []float64 + + results, ok := response["results"].([]interface{}) + if !ok || len(results) == 0 { + return sampleValues, fmt.Errorf("no results found") + } + + firstResult, ok := results[0].(map[string]interface{}) + if !ok { + return sampleValues, fmt.Errorf("invalid results[0] format") + } + + timeseriesList, ok := firstResult["timeseries"].([]interface{}) + if !ok || len(timeseriesList) == 0 { + return sampleValues, fmt.Errorf("no timeseries in firstResult") + } + + firstTimeseries, ok := timeseriesList[0].(map[string]interface{}) + if !ok { + return sampleValues, fmt.Errorf("invalid timeseries[0] format") + } + + samplesList, ok := firstTimeseries["samples"].([]interface{}) + if !ok || len(samplesList) == 0 { + // Return an empty slice rather than an error, since "no samples" may be valid + return sampleValues, nil + } + + for _, sample := range samplesList { + sampleMap, ok := sample.(map[string]interface{}) + if !ok { + continue + } + + value, ok := sampleMap["value"].(float64) + if !ok { + continue + } + + sampleValues = append(sampleValues, value) + } + + return sampleValues, nil +} + +// countTimeSeriesAndSamples returns the number of timeseries and total number of samples across all timeseries. +func countTimeSeriesAndSamples(response map[string]interface{}) (int, int) { + results, ok := response["results"].([]interface{}) + if !ok || len(results) == 0 { + return 0, 0 + } + + firstResult, ok := results[0].(map[string]interface{}) + if !ok { + return 0, 0 + } + + timeseriesList, ok := firstResult["timeseries"].([]interface{}) + if !ok { + return 0, 0 + } + + numTimeSeries := len(timeseriesList) + var totalSamples int + + for _, ts := range timeseriesList { + timeseriesMap, ok := ts.(map[string]interface{}) + if !ok { + continue + } + samplesList, ok := timeseriesMap["samples"].([]interface{}) + if !ok { + continue + } + totalSamples += len(samplesList) + } + + return numTimeSeries, totalSamples +} + +func generateTestRunID() string { + rand.Seed(time.Now().UnixNano()) + alphabet := []rune("abcde12345") + idRunes := make([]rune, 4) + for i := 0; i < 4; i++ { + idRunes[i] = alphabet[rand.Intn(len(alphabet))] + } + return string(idRunes) } diff --git a/correctness/data/expectedOutput.csv b/correctness/data/expectedOutput.csv deleted file mode 100644 index 9e7f83c..0000000 --- a/correctness/data/expectedOutput.csv +++ /dev/null @@ -1,77 +0,0 @@ -PromQL,Read Response -"abs(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"absent(nonexistent{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing"", job=""testJob""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""job"":""testJob"",""timestreamDatabase"":""correctness_testing"",""timestreamTable"":""correctness_testing""},""value"":[1604712569,""1""]}]}}" -"absent(sum(nonexistent{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing"", job=""testJob""}))","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{},""value"":[1604712569,""1""]}]}}" -"absent_over_time(nonexistent{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing"", job=""testJob""}[1h])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""job"":""testJob"",""timestreamDatabase"":""correctness_testing"",""timestreamTable"":""correctness_testing""},""value"":[1604712569,""1""]}]}}" -"ceil(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h]))","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"changes(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""11""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""19""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"clamp_max(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}, 10)","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""10""]}]}}" -"clamp_min(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}, 5)","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"day_of_month(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]}]}}" -"day_of_week(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""4""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""4""]}]}}" -"days_in_month(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""31""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""31""]}]}}" -"delta(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""7.384903812304428""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""11.62984884790696""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"deriv(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[30s:5s])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"exp(prometheus_remote_storage_sent_bytes_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""instance"":""localhost:9090"",""job"":""prometheus"",""remote_name"":""9a7824"",""url"":""http://localhost:9201/write""},""value"":[1604605150,""+Inf""]}]}}" -"round(deriv(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[30s:5s]))","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"histogram_quantile(0.9, rate(prometheus_http_request_duration_seconds_bucket{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m]))","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""2.000000000000001""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.09000000000000001""]}]}}" -"histogram_quantile(0.9, sum by (job, le) (rate(prometheus_http_request_duration_seconds_bucket{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m])))","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""job"":""prometheus""},""value"":[1604605150,""0.8111111111111113""]}]}}" -"histogram_quantile(0.9, sum by (le) (rate(prometheus_http_request_duration_seconds_bucket{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m])))","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{},""value"":[1604605150,""0.8111111111111113""]}]}}" -"holt_winters(prometheus_http_request_duration_seconds_bucket{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h], 0.5, 0.5)","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""7.80976472646671""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""0.029462333756782755""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""0.029462333756782755""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""1.993069645005562""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""5.940009108192498""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""7.80976472646671""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""7.80976472646671""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""7.80976472646671""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""7.80976472646671""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""7.80976472646671""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""12.103487372398376""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""2""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""2""]}]}}" -"hour(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"idelta(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"increase(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""18.989752660211384""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""20.612920737293834""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"irate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.06666666666666667""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"label_join(prometheus_http_requests_total{job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}, ""des"", ""handler"", ""job"")","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""des"":""prometheus"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""des"":""prometheus"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"label_replace(prometheus_http_requests_total{instance=""localhost:9090"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}, ""port"", ""$1"", ""instance"", "".*:(.*)"")","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""port"":""9090""},""value"":[1604605150,""8""]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""port"":""9090""},""value"":[1604605150,""12""]}]}}" -"ln(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""2.0794415416798357""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""2.4849066497880004""]}]}}" -"log2(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""3""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""3.584962500721156""]}]}}" -"log10(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.9030899869919435""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1.0791812460476249""]}]}}" -"minute(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"month(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]}]}}" -"predict_linear(prometheus_http_request_duration_seconds_bucket{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h], 10)","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""1""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""6.84890365759245""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""-0.7111333170503134""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""-0.7111333170503134""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""1.177490106013557""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""5.512381163744855""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""6.84890365759245""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""6.84890365759245""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""6.84890365759245""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""6.84890365759245""]},{""metric"":{""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""6.84890365759245""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""0.9999999999998508""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""7.093384731845187""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""+Inf""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.1""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.2""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""0.4""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""1""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""120""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""20""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""3""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""60""},""value"":[1604605150,""1.9999999999997016""]},{""metric"":{""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus"",""le"":""8""},""value"":[1604605150,""1.9999999999997016""]}]}}" -"rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[5m])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.018055555555555554""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.04166666666666667""]}]}}" -"rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[5m])[30m:1m]","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604120,""0""],[1604604180,""0""],[1604604240,""0""],[1604604300,""0""],[1604604360,""0""],[1604604420,""0""]]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604120,""0.023286666666666667""],[1604604180,""0.039483465236839016""],[1604604240,""0.03904761904761905""],[1604604300,""0.04788076190476191""],[1604604360,""0.04338907936507937""],[1604604420,""0.026619600000000004""],[1604604480,""0.008333333333333333""],[1604604540,""0.008333333333333333""],[1604604960,""0.013943737084194389""],[1604605020,""0.016244245632280458""],[1604605080,""0.014950406770379808""],[1604605140,""0.018055555555555554""]]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604120,""0""],[1604604180,""0""],[1604604240,""0""],[1604604300,""0""],[1604604360,""0""],[1604604420,""0""]]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604120,""0.015305333333333332""],[1604604180,""0.028638425665787313""],[1604604240,""0.028333333333333332""],[1604604300,""0.03303161904761905""],[1604604360,""0.029111238095238096""],[1604604420,""0.015544533333333332""],[1604605020,""0.018638666666666664""],[1604605080,""0.031971761346433224""],[1604605140,""0.04166666666666667""]]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604120,""0""],[1604604180,""0""],[1604604240,""0""],[1604604300,""0""],[1604604360,""0""],[1604604420,""0""]]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604120,""0""],[1604604180,""0""],[1604604240,""0""],[1604604300,""0""],[1604604360,""0""],[1604604420,""0""]]}]}}" -"rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[5m] offset 1h)","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"resets(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"round(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}, 1)","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"scalar(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""scalar"",""result"":[1604605150,""NaN""]}}" -"sort(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"sort_desc(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]}]}}" -"timestamp(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1604605116.128""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1604605116.128""]}]}}" -"vector(scalar(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}))","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{},""value"":[1604605150,""NaN""]}]}}" -"year(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1970""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1970""]}]}}" -"avg_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])[30s:5s])[10m:])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.0000020307349970838386""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.000004191642057676422""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"min_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])[30s:5s])[10m:])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""-0.0000058691360303773726""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""-0.000009855334349684569""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"max_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])[30s:5s])[10m:])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.000024600465275114645""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.000019762929293777084""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"sum_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])[30s:5s])[10m:])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.000020307349970838385""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.00004191642057676422""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"count_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])[30s:5s])[10m:])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""10""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""10""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""10""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""10""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""10""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""10""]}]}}" -"quantile_over_time(0.5, deriv(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])[30s:5s])[10m:])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""-0.00000000000000000007930164461608261""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"stddev_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])[30s:5s])[10m:])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.000007762256416118168""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.000009226502739002935""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"stdvar_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[1h])[30s:5s])[10m:])","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/label/:name/values"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.00000000006025262466956767""]},{""metric"":{""code"":""200"",""handler"":""/graph"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0.00000000008512835279282868""]},{""metric"":{""code"":""200"",""handler"":""/static/*filepath"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""code"":""302"",""handler"":""/"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]}]}}" -"prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} + max(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} - max(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} * min(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} / max(prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""})","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} % 5","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""3""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""2""]}]}}" -"prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} ^ 2","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""64""]},{""metric"":{""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""144""]}]}}" -"net_conntrack_dialer_conn_attempted_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} and prometheus_http_response_size_bytes_count{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"net_conntrack_dialer_conn_attempted_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} or prometheus_http_response_size_bytes_count{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""net_conntrack_dialer_conn_attempted_total"",""dialer_name"":""default"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""__name__"":""net_conntrack_dialer_conn_attempted_total"",""dialer_name"":""prometheus"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""__name__"":""net_conntrack_dialer_conn_attempted_total"",""dialer_name"":""remote_storage"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""2""]},{""metric"":{""__name__"":""prometheus_http_response_size_bytes_count"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""__name__"":""prometheus_http_response_size_bytes_count"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"net_conntrack_dialer_conn_attempted_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} unless prometheus_http_response_size_bytes_count{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""net_conntrack_dialer_conn_attempted_total"",""dialer_name"":""default"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""0""]},{""metric"":{""__name__"":""net_conntrack_dialer_conn_attempted_total"",""dialer_name"":""prometheus"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""1""]},{""metric"":{""__name__"":""net_conntrack_dialer_conn_attempted_total"",""dialer_name"":""remote_storage"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""2""]}]}}" -"prometheus_http_requests_total{timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"prometheus_http_requests_total{handler=""/api/v1/query"", job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]}]}}" -"prometheus_http_requests_total{handler!=""/api/v1/query"", job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"prometheus_http_requests_total{code!~""4.."", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"prometheus_http_requests_total{code=~""2.."", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""8""]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""value"":[1604605150,""12""]}]}}" -"prometheus_http_requests_total{handler!=""/api/v1/query"", job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m]","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604951.126,""1""],[1604604966.126,""2""],[1604604981.126,""3""],[1604604996.126,""4""],[1604605011.126,""5""],[1604605026.126,""6""],[1604605041.127,""7""],[1604605056.127,""8""],[1604605071.127,""9""],[1604605086.128,""10""],[1604605101.128,""11""],[1604605116.128,""12""]]}]}}" -"prometheus_http_requests_total{handler=""/api/v1/query"", job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m]","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604936.125,""3""],[1604604951.126,""5""],[1604604966.126,""6""],[1604604981.126,""7""],[1604604996.126,""7""],[1604605011.126,""7""],[1604605026.126,""7""],[1604605041.127,""7""],[1604605056.127,""7""],[1604605071.127,""7""],[1604605086.128,""7""],[1604605101.128,""8""],[1604605116.128,""8""]]}]}}" -"prometheus_http_requests_total{code!~""4.."", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m]","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604936.125,""3""],[1604604951.126,""5""],[1604604966.126,""6""],[1604604981.126,""7""],[1604604996.126,""7""],[1604605011.126,""7""],[1604605026.126,""7""],[1604605041.127,""7""],[1604605056.127,""7""],[1604605071.127,""7""],[1604605086.128,""7""],[1604605101.128,""8""],[1604605116.128,""8""]]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604951.126,""1""],[1604604966.126,""2""],[1604604981.126,""3""],[1604604996.126,""4""],[1604605011.126,""5""],[1604605026.126,""6""],[1604605041.127,""7""],[1604605056.127,""8""],[1604605071.127,""9""],[1604605086.128,""10""],[1604605101.128,""11""],[1604605116.128,""12""]]}]}}" -"prometheus_http_requests_total{code=~""2.."", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m]","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604936.125,""3""],[1604604951.126,""5""],[1604604966.126,""6""],[1604604981.126,""7""],[1604604996.126,""7""],[1604605011.126,""7""],[1604605026.126,""7""],[1604605041.127,""7""],[1604605056.127,""7""],[1604605071.127,""7""],[1604605086.128,""7""],[1604605101.128,""8""],[1604605116.128,""8""]]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604951.126,""1""],[1604604966.126,""2""],[1604604981.126,""3""],[1604604996.126,""4""],[1604605011.126,""5""],[1604605026.126,""6""],[1604605041.127,""7""],[1604605056.127,""8""],[1604605071.127,""9""],[1604605086.128,""10""],[1604605101.128,""11""],[1604605116.128,""12""]]}]}}" -"prometheus_http_requests_total{handler!=""/api/v1/query"", job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} offset 5m","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"prometheus_http_requests_total{handler=""/api/v1/query"", job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} offset 5m","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"prometheus_http_requests_total{code!~""4.."", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} offset 5m","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"prometheus_http_requests_total{code=~""2.."", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""} offset 5m","{""status"":""success"",""data"":{""resultType"":""vector"",""result"":[]}}" -"prometheus_http_requests_total{handler!=""/api/v1/query"", job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m] offset 5m","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604276.126,""1""]]}]}}" -"prometheus_http_requests_total{handler=""/api/v1/query"", job=""prometheus"", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m] offset 5m","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604261.125,""1""],[1604604276.126,""2""]]}]}}" -"prometheus_http_requests_total{code!~""4.."", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m] offset 5m","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604261.125,""1""],[1604604276.126,""2""]]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604276.126,""1""]]}]}}" -"prometheus_http_requests_total{code=~""2.."", timestreamDatabase=""correctness_testing"", timestreamTable=""correctness_testing""}[10m] offset 5m","{""status"":""success"",""data"":{""resultType"":""matrix"",""result"":[{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/api/v1/query"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604261.125,""1""],[1604604276.126,""2""]]},{""metric"":{""__name__"":""prometheus_http_requests_total"",""code"":""200"",""handler"":""/metrics"",""instance"":""localhost:9090"",""job"":""prometheus""},""values"":[[1604604276.126,""1""]]}]}}" diff --git a/correctness/data/functions.txt b/correctness/data/functions.txt deleted file mode 100644 index 84f5a53..0000000 --- a/correctness/data/functions.txt +++ /dev/null @@ -1,50 +0,0 @@ -abs(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -absent(nonexistent{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing", job="testJob"}) -absent(sum(nonexistent{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing", job="testJob"})) -absent_over_time(nonexistent{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing", job="testJob"}[1h]) -ceil(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])) -changes(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h]) -clamp_max(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}, 10) -clamp_min(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}, 5) -day_of_month(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -day_of_week(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -days_in_month(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -delta(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h]) -deriv(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[30s:5s]) -exp(prometheus_remote_storage_sent_bytes_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -round(deriv(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[30s:5s])) -histogram_quantile(0.9, rate(prometheus_http_request_duration_seconds_bucket{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m])) -histogram_quantile(0.9, sum by (job, le) (rate(prometheus_http_request_duration_seconds_bucket{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m]))) -histogram_quantile(0.9, sum by (le) (rate(prometheus_http_request_duration_seconds_bucket{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m]))) -holt_winters(prometheus_http_request_duration_seconds_bucket{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h], 0.5, 0.5) -hour(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -idelta(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h]) -increase(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h]) -irate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h]) -label_join(prometheus_http_requests_total{job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}, "des", "handler", "job") -label_replace(prometheus_http_requests_total{instance="localhost:9090", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}, "port", "$1", "instance", ".*:(.*)") -ln(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -log2(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -log10(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -minute(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -month(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -predict_linear(prometheus_http_request_duration_seconds_bucket{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h], 10) -rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[5m]) -rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[5m])[30m:1m] -rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[5m] offset 1h) -resets(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h]) -round(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}, 1) -scalar(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -sort(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -sort_desc(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -timestamp(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -vector(scalar(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"})) -year(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -avg_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])[30s:5s])[10m:]) -min_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])[30s:5s])[10m:]) -max_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])[30s:5s])[10m:]) -sum_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])[30s:5s])[10m:]) -count_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])[30s:5s])[10m:]) -quantile_over_time(0.5, deriv(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])[30s:5s])[10m:]) -stddev_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])[30s:5s])[10m:]) -stdvar_over_time(deriv(rate(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[1h])[30s:5s])[10m:]) diff --git a/correctness/data/operators.txt b/correctness/data/operators.txt deleted file mode 100644 index 1f590f3..0000000 --- a/correctness/data/operators.txt +++ /dev/null @@ -1,9 +0,0 @@ -prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} + max(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} - max(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} * min(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} / max(prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}) -prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} % 5 -prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} ^ 2 -net_conntrack_dialer_conn_attempted_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} and prometheus_http_response_size_bytes_count{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} -net_conntrack_dialer_conn_attempted_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} or prometheus_http_response_size_bytes_count{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} -net_conntrack_dialer_conn_attempted_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} unless prometheus_http_response_size_bytes_count{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} diff --git a/correctness/data/series.txt b/correctness/data/series.txt deleted file mode 100644 index 62a2d09..0000000 --- a/correctness/data/series.txt +++ /dev/null @@ -1,17 +0,0 @@ -prometheus_http_requests_total{timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} -prometheus_http_requests_total{handler="/api/v1/query", job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} -prometheus_http_requests_total{handler!="/api/v1/query", job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} -prometheus_http_requests_total{code!~"4..", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} -prometheus_http_requests_total{code=~"2..", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} -prometheus_http_requests_total{handler!="/api/v1/query", job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m] -prometheus_http_requests_total{handler="/api/v1/query", job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m] -prometheus_http_requests_total{code!~"4..", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m] -prometheus_http_requests_total{code=~"2..", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m] -prometheus_http_requests_total{handler!="/api/v1/query", job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} offset 5m -prometheus_http_requests_total{handler="/api/v1/query", job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} offset 5m -prometheus_http_requests_total{code!~"4..", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} offset 5m -prometheus_http_requests_total{code=~"2..", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"} offset 5m -prometheus_http_requests_total{handler!="/api/v1/query", job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m] offset 5m -prometheus_http_requests_total{handler="/api/v1/query", job="prometheus", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m] offset 5m -prometheus_http_requests_total{code!~"4..", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m] offset 5m -prometheus_http_requests_total{code=~"2..", timestreamDatabase="correctness_testing", timestreamTable="correctness_testing"}[10m] offset 5m diff --git a/correctness/go.mod b/correctness/go.mod new file mode 100644 index 0000000..6a99a42 --- /dev/null +++ b/correctness/go.mod @@ -0,0 +1,40 @@ +module correctness + +go 1.23.3 + +require ( + github.com/aws/aws-sdk-go-v2/config v1.28.7 + github.com/golang/protobuf v1.5.4 + github.com/golang/snappy v0.0.4 + github.com/prometheus/prometheus v0.300.1 +) + +require ( + github.com/aws/aws-sdk-go-v2 v1.32.7 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.48 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 // indirect + github.com/aws/smithy-go v1.22.1 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/dennwc/varint v1.0.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.60.1 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/stretchr/testify v1.10.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect +) diff --git a/correctness/go.sum b/correctness/go.sum new file mode 100644 index 0000000..2362913 --- /dev/null +++ b/correctness/go.sum @@ -0,0 +1,192 @@ +cloud.google.com/go/auth v0.9.5 h1:4CTn43Eynw40aFVr3GpPqsQponx2jv0BQpjvajsbbzw= +cloud.google.com/go/auth v0.9.5/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= +cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg= +github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= +github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw= +github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE= +github.com/aws/aws-sdk-go-v2/config v1.28.7/go.mod h1:vZGX6GVkIE8uECSUHB6MWAUsd4ZcG2Yq/dMa4refR3M= +github.com/aws/aws-sdk-go-v2/credentials v1.17.48 h1:IYdLD1qTJ0zanRavulofmqut4afs45mOWEI+MzZtTfQ= +github.com/aws/aws-sdk-go-v2/credentials v1.17.48/go.mod h1:tOscxHN3CGmuX9idQ3+qbkzrjVIx32lqDSU1/0d/qXs= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 h1:8eUsivBQzZHqe/3FE+cqwfH+0p5Jo8PFM/QYQSmeZ+M= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7/go.mod h1:kLPQvGUmxn/fqiCrDeohwG33bq2pQpGeY62yRO6Nrh0= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 h1:CvuUmnXI7ebaUAhbJcDy9YQx8wHR69eZ9I7q5hszt/g= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.8/go.mod h1:XDeGv1opzwm8ubxddF0cgqkZWsyOtw4lr6dxwmb6YQg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 h1:F2rBfNAL5UyswqoeWv9zs74N/NanhK16ydHW1pahX6E= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7/go.mod h1:JfyQ0g2JG8+Krq0EuZNnRwX0mU0HrwY/tG6JNfcqh4k= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 h1:Xgv/hyNgvLda/M9l9qxXc4UFSgppnRczLxlMs5Ae/QY= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.3/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc= +github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= +github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps= +github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= +github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0= +github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= +github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= +github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/prometheus v0.300.1 h1:9KKcTTq80gkzmXW0Et/QCFSrBPgmwiS3Hlcxc6o8KlM= +github.com/prometheus/prometheus v0.300.1/go.mod h1:gtTPY/XVyCdqqnjA3NzDMb0/nc5H9hOu1RMame+gHyM= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= +golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.199.0 h1:aWUXClp+VFJmqE0JPvpZOK3LDQMyFKYIow4etYd9qxs= +google.golang.org/api v0.199.0/go.mod h1:ohG4qSztDJmZdjK/Ar6MhbAmb/Rpi4JHOqagsh90K28= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= diff --git a/correctness/mockmetheus.go b/correctness/mockmetheus.go new file mode 100644 index 0000000..23a5095 --- /dev/null +++ b/correctness/mockmetheus.go @@ -0,0 +1,281 @@ +/* +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with +the License. A copy of the License is located at + +http://www.apache.org/licenses/LICENSE-2.0 + +or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions +and limitations under the License. +*/ + +// Mockmetheus provides methods to remotely read/write Prometheus data for +// correctness testing the Prometheus connector. +package correctness + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "time" + + "github.com/aws/aws-sdk-go-v2/config" + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" + "github.com/golang/snappy" + "github.com/prometheus/prometheus/model/labels" + "github.com/prometheus/prometheus/prompb" + "github.com/prometheus/prometheus/promql/parser" +) + +type Mockmetheus struct { + username string + password string + connectorURL string + httpClient *http.Client +} + +func NewMockmetheus(connectorURL string) (*Mockmetheus, error) { + if connectorURL == "" { + return nil, fmt.Errorf("connectorURL cannot be empty") + } + + cfg, err := config.LoadDefaultConfig(context.Background()) + if err != nil { + return nil, fmt.Errorf("unable to load AWS SDK config: %w", err) + } + + creds, err := cfg.Credentials.Retrieve(context.Background()) + if err != nil { + return nil, fmt.Errorf("unable to retrieve AWS credentials: %w", err) + } + + username := creds.AccessKeyID + password := creds.SecretAccessKey + + return &Mockmetheus{ + username: username, + password: password, + connectorURL: connectorURL, + httpClient: &http.Client{Timeout: 30 * time.Second}, + }, nil +} + +func (m *Mockmetheus) RemoteRead(ctx context.Context, query string) (map[string]interface{}, error) { + rreq, err := m.constructReadRequest(query) + if err != nil { + return nil, err + } + + data, err := proto.Marshal(rreq) + if err != nil { + return nil, err + } + encoded := snappy.Encode(nil, data) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, m.connectorURL+"/read", bytes.NewReader(encoded)) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-protobuf") + req.Header.Set("Content-Encoding", "snappy") + req.SetBasicAuth(m.username, m.password) + + resp, err := m.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode > 299 { + bodyBytes, _ := io.ReadAll(resp.Body) + return nil, fmt.Errorf("status code %d: %s", resp.StatusCode, string(bodyBytes)) + } + + bodyBytes, err := parseResponse(resp) + if err != nil { + return nil, err + } + + body, err := snappy.Decode(nil, bodyBytes) + if err != nil { + return nil, err + } + + var rr prompb.ReadResponse + if err := proto.Unmarshal(body, &rr); err != nil { + return nil, err + } + + marshaller := &jsonpb.Marshaler{EmitDefaults: true} + var buf bytes.Buffer + if err := marshaller.Marshal(&buf, &rr); err != nil { + return nil, err + } + + var out map[string]interface{} + if err := json.Unmarshal(buf.Bytes(), &out); err != nil { + return nil, err + } + + return out, nil +} + +func (m *Mockmetheus) RemoteWrite(ctx context.Context, seriesData []TimeSeriesData) error { + wreq := m.constructWriteRequest(seriesData) + + b, err := proto.Marshal(wreq) + if err != nil { + return err + } + encoded := snappy.Encode(nil, b) + + req, err := http.NewRequestWithContext(ctx, http.MethodPost, m.connectorURL+"/write", bytes.NewReader(encoded)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/x-protobuf") + req.Header.Set("Content-Encoding", "snappy") + req.SetBasicAuth(m.username, m.password) + + resp, err := m.httpClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + fmt.Printf("Server responded with status code: %d\n", resp.StatusCode) + + if resp.StatusCode < 200 || resp.StatusCode > 299 { + bodyBytes, _ := io.ReadAll(resp.Body) + return fmt.Errorf("status code %d: %s", resp.StatusCode, string(bodyBytes)) + } + return nil +} + +type TimeSeriesData struct { + Labels map[string]string + Samples []SampleData +} + +type SampleData struct { + Value float64 + Timestamp int64 +} + +func (m *Mockmetheus) constructWriteRequest(timeSeriesData []TimeSeriesData) *prompb.WriteRequest { + var tsList []prompb.TimeSeries + for _, row := range timeSeriesData { + var ts prompb.TimeSeries + for k, v := range row.Labels { + ts.Labels = append(ts.Labels, prompb.Label{Name: k, Value: v}) + } + for _, s := range row.Samples { + ts.Samples = append(ts.Samples, prompb.Sample{Value: s.Value, Timestamp: s.Timestamp}) + } + tsList = append(tsList, ts) + } + return &prompb.WriteRequest{Timeseries: tsList} +} + +func (m *Mockmetheus) constructReadRequest(query string) (*prompb.ReadRequest, error) { + expression, err := parser.ParseExpr(query) + if err != nil { + return nil, err + } + + var ( + metric string + labels []*prompb.LabelMatcher + duration = time.Hour + ) + + switch node := expression.(type) { + case *parser.MatrixSelector: + v, ok := node.VectorSelector.(*parser.VectorSelector) + if !ok { + return nil, fmt.Errorf("invalid matrix selector in query") + } + if v.Name != "" { + metric = v.Name + } else { + metric = "__name__" + } + for _, labelMatcher := range v.LabelMatchers { + labels = append(labels, &prompb.LabelMatcher{ + Name: labelMatcher.Name, + Value: labelMatcher.Value, + Type: toPrompbMatcherType(labelMatcher.Type), + }) + } + duration = node.Range + + case *parser.VectorSelector: + if node.Name != "" { + metric = node.Name + } else { + metric = "__name__" + } + for _, labelMatcher := range node.LabelMatchers { + labels = append(labels, &prompb.LabelMatcher{ + Name: labelMatcher.Name, + Value: labelMatcher.Value, + Type: toPrompbMatcherType(labelMatcher.Type), + }) + } + + default: + return nil, fmt.Errorf("unsupported query expression type %T", expression) + } + + nowMS := time.Now().UnixMilli() + startMS := nowMS - int64(duration.Milliseconds()) + + prompbQuery := &prompb.Query{ + StartTimestampMs: startMS, + EndTimestampMs: nowMS, + } + + if metric != "" && metric != "__name__" { + prompbQuery.Matchers = append(prompbQuery.Matchers, &prompb.LabelMatcher{ + Type: prompb.LabelMatcher_EQ, + Name: "__name__", + Value: metric, + }) + } + prompbQuery.Matchers = append(prompbQuery.Matchers, labels...) + + return &prompb.ReadRequest{ + Queries: []*prompb.Query{prompbQuery}, + AcceptedResponseTypes: []prompb.ReadRequest_ResponseType{prompb.ReadRequest_SAMPLES}, + }, nil +} + +// toPrompbMatcherType converts PromQL match types to Prometheus prompb label matcher types. +func toPrompbMatcherType(matchType labels.MatchType) prompb.LabelMatcher_Type { + switch matchType { + case labels.MatchEqual: + return prompb.LabelMatcher_EQ + case labels.MatchNotEqual: + return prompb.LabelMatcher_NEQ + case labels.MatchRegexp: + return prompb.LabelMatcher_RE + case labels.MatchNotRegexp: + return prompb.LabelMatcher_NRE + } + return prompb.LabelMatcher_EQ +} + +func parseResponse(resp *http.Response) ([]byte, error) { + defer resp.Body.Close() + b := new(bytes.Buffer) + if _, err := io.Copy(b, resp.Body); err != nil { + return nil, err + } + return b.Bytes(), nil +} diff --git a/docker-compose.yml b/docker-compose.yml index bdae10b..e0e9ea6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: volumes: - .:/home command: - - --default-database=PrometheusDatabase - - --default-table=PrometheusMetricsTable - - --region=us-east-1 + - --default-database=CorrDB + - --default-table=CorrMetrics + - --region=us-west-2 - --log.level=debug diff --git a/main.go b/main.go index cc98f88..ec1f87b 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ import ( "github.com/aws/aws-sdk-go-v2/credentials" wtypes "github.com/aws/aws-sdk-go-v2/service/timestreamwrite/types" "github.com/aws/smithy-go" + smithyhttp "github.com/aws/smithy-go/transport/http" "io" "net/http" @@ -230,6 +231,7 @@ func handleWriteRequest(reqBuf []byte, timestreamClient *timestream.Client, awsC timestream.LogInfo(logger, fmt.Sprintf("Timestream write connection is initialized (Database: %s, Table: %s, Region: %s)", cfg.defaultDatabase, cfg.defaultTable, cfg.clientConfig.region)) if err := getWriteClient(timestreamClient).Write(context.Background(), &writeRequest, credentialsProvider); err != nil { + fmt.Println("A - 1") errorCode := http.StatusBadRequest return events.APIGatewayProxyResponse{ StatusCode: errorCode, @@ -520,8 +522,10 @@ func createWriteHandler(logger log.Logger, writers []writer) func(w http.Respons } if err := writers[0].Write(context.Background(), &req, awsCredentials); err != nil { switch err := err.(type) { + case *smithyhttp.ResponseError: + http.Error(w, err.Error(), http.StatusBadRequest) case *wtypes.RejectedRecordsException: - http.Error(w, err.Error(), http.StatusBadRequest) + http.Error(w, err.Error(), http.StatusUnprocessableEntity) case *smithy.OperationError: var apiError *smithy.GenericAPIError if goErrors.As(err, &apiError) { @@ -532,9 +536,9 @@ func createWriteHandler(logger log.Logger, writers []writer) func(w http.Respons case *errors.SDKNonRequestError: http.Error(w, err.Error(), http.StatusBadRequest) case *errors.MissingDatabaseWithWriteError: - http.Error(w, err.Error(), http.StatusBadRequest) + http.Error(w, err.Error(), http.StatusNotFound) case *errors.MissingTableWithWriteError: - http.Error(w, err.Error(), http.StatusBadRequest) + http.Error(w, err.Error(), http.StatusNotFound) default: halt(1) } @@ -610,6 +614,7 @@ func createReadHandler(logger log.Logger, readers []reader) func(w http.Response w.Header().Set("Content-Encoding", "snappy") if _, err := w.Write(snappy.Encode(nil, data)); err != nil { + fmt.Println("C - 1") timestream.LogError(logger, "Error occurred while writing the encoded ReadResponse to the connection as part of an HTTP reply.", err) http.Error(w, err.Error(), http.StatusBadRequest) return diff --git a/main_test.go b/main_test.go index ebda8d6..b2c2e83 100644 --- a/main_test.go +++ b/main_test.go @@ -779,6 +779,12 @@ func TestParseEnvironmentVariables(t *testing.T) { func TestWriteHandler(t *testing.T) { var emptyTimeSeries *prompb.TimeSeries + invalidTimeSeries := &prompb.TimeSeries{ + Labels: []*prompb.Label{}, + Samples: []prompb.Sample{}, + } + invalidWriteRequest := &prompb.WriteRequest{Timeseries: []*prompb.TimeSeries{invalidTimeSeries}} + tests := []struct { name string request proto.Message @@ -853,6 +859,15 @@ func TestWriteHandler(t *testing.T) { getWriteRequestReader: getReaderHelper, basicAuthHeader: basicAuthHeader, encodedBasicAuth: encodedBasicAuth, + expectedStatusCode: http.StatusUnprocessableEntity, + }, + { + name: "SDK validation error from write", + request: invalidWriteRequest, + returnError: errors.NewSDKNonRequestError(goErrors.New("")), + getWriteRequestReader: getReaderHelper, + basicAuthHeader: basicAuthHeader, + encodedBasicAuth: encodedBasicAuth, expectedStatusCode: http.StatusBadRequest, }, { @@ -871,7 +886,7 @@ func TestWriteHandler(t *testing.T) { getWriteRequestReader: getReaderHelper, basicAuthHeader: basicAuthHeader, encodedBasicAuth: encodedBasicAuth, - expectedStatusCode: http.StatusBadRequest, + expectedStatusCode: http.StatusNotFound, }, { name: "Missing table name from write", @@ -880,7 +895,7 @@ func TestWriteHandler(t *testing.T) { getWriteRequestReader: getReaderHelper, basicAuthHeader: basicAuthHeader, encodedBasicAuth: encodedBasicAuth, - expectedStatusCode: http.StatusBadRequest, + expectedStatusCode: http.StatusNotFound, }, { name: "smithy error - ThrottlingException", diff --git a/timestream/client.go b/timestream/client.go index 6557638..fc98cef 100644 --- a/timestream/client.go +++ b/timestream/client.go @@ -347,7 +347,6 @@ func (qc *QueryClient) Read( }, nil } -// handleSDKErr parses and logs the error from SDK (if any) func (wc *WriteClient) handleSDKErr(req *prompb.WriteRequest, currErr error, errToReturn error) error { var responseError *http.ResponseError if !goErrors.As(currErr, &responseError) { @@ -355,19 +354,18 @@ func (wc *WriteClient) handleSDKErr(req *prompb.WriteRequest, currErr error, err return currErr } - if errToReturn == nil { - errToReturn = currErr - } - statusCode := responseError.HTTPStatusCode() switch statusCode / 100 { case 4: LogDebug(wc.logger, "Error occurred while ingesting data due to invalid write request. "+ "Some Prometheus Samples were not ingested into Timestream, please review the write request and check the documentation for troubleshooting.", "request", req) + return responseError case 5: - errToReturn = currErr LogDebug(wc.logger, "Internal server error occurred. Samples will be retried by Prometheus", "request", req) + if errToReturn == nil { + errToReturn = currErr + } } return errToReturn From 2b7da7853ef859bcf96d7acceb7f837e47c19ff9 Mon Sep 17 00:00:00 2001 From: Fred Park Date: Fri, 3 Jan 2025 09:19:33 -0800 Subject: [PATCH 2/6] cleaning up --- correctness/README.md | 4 ++-- docker-compose.yml | 6 +++--- main.go | 4 +--- timestream/client.go | 1 + 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/correctness/README.md b/correctness/README.md index 5b23c0c..168cc1c 100644 --- a/correctness/README.md +++ b/correctness/README.md @@ -13,7 +13,7 @@ aws timestream-write create-database --database-name CorrectnessDB --region us-w 2. Bring up the Prometheus Connector: ``` -`docker compose -f ../docker-compose.yml up -d` +docker compose -f ../docker-compose.yml up -d ``` 3. Run `go test -v`. Tests can take between 15~20 seconds to complete. @@ -21,7 +21,7 @@ aws timestream-write create-database --database-name CorrectnessDB --region us-w ### Tips - To run correctness tests against an existing Timestream database, ensure the `freshTSDB` flag is disabled in the test suite. -- The `ingestionWaitTime` parameter is adjustable to account for network latency, ensuring data ingestion is complete before evaluating test outputs. +- The `ingestionWaitTime` parameter is adjustable to account for network latency, ensuring data ingestion is complete before evaluating test outputs. The default of 1 second should be sufficient (and functionally expected), but can increase as needed. ## Clean up 1. Delete your Timestream database: diff --git a/docker-compose.yml b/docker-compose.yml index e0e9ea6..bdae10b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: volumes: - .:/home command: - - --default-database=CorrDB - - --default-table=CorrMetrics - - --region=us-west-2 + - --default-database=PrometheusDatabase + - --default-table=PrometheusMetricsTable + - --region=us-east-1 - --log.level=debug diff --git a/main.go b/main.go index ec1f87b..7156c03 100644 --- a/main.go +++ b/main.go @@ -231,7 +231,6 @@ func handleWriteRequest(reqBuf []byte, timestreamClient *timestream.Client, awsC timestream.LogInfo(logger, fmt.Sprintf("Timestream write connection is initialized (Database: %s, Table: %s, Region: %s)", cfg.defaultDatabase, cfg.defaultTable, cfg.clientConfig.region)) if err := getWriteClient(timestreamClient).Write(context.Background(), &writeRequest, credentialsProvider); err != nil { - fmt.Println("A - 1") errorCode := http.StatusBadRequest return events.APIGatewayProxyResponse{ StatusCode: errorCode, @@ -523,7 +522,7 @@ func createWriteHandler(logger log.Logger, writers []writer) func(w http.Respons if err := writers[0].Write(context.Background(), &req, awsCredentials); err != nil { switch err := err.(type) { case *smithyhttp.ResponseError: - http.Error(w, err.Error(), http.StatusBadRequest) + http.Error(w, err.Error(), http.StatusBadRequest) case *wtypes.RejectedRecordsException: http.Error(w, err.Error(), http.StatusUnprocessableEntity) case *smithy.OperationError: @@ -614,7 +613,6 @@ func createReadHandler(logger log.Logger, readers []reader) func(w http.Response w.Header().Set("Content-Encoding", "snappy") if _, err := w.Write(snappy.Encode(nil, data)); err != nil { - fmt.Println("C - 1") timestream.LogError(logger, "Error occurred while writing the encoded ReadResponse to the connection as part of an HTTP reply.", err) http.Error(w, err.Error(), http.StatusBadRequest) return diff --git a/timestream/client.go b/timestream/client.go index fc98cef..28e463c 100644 --- a/timestream/client.go +++ b/timestream/client.go @@ -347,6 +347,7 @@ func (qc *QueryClient) Read( }, nil } +// handleSDKErr parses and logs the error from SDK (if any) func (wc *WriteClient) handleSDKErr(req *prompb.WriteRequest, currErr error, errToReturn error) error { var responseError *http.ResponseError if !goErrors.As(currErr, &responseError) { From efd7e33f6749d987c0d388614635b5b4daba6361 Mon Sep 17 00:00:00 2001 From: Fred Park Date: Fri, 3 Jan 2025 09:26:14 -0800 Subject: [PATCH 3/6] readme --- correctness/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/correctness/README.md b/correctness/README.md index 168cc1c..34ab293 100644 --- a/correctness/README.md +++ b/correctness/README.md @@ -5,11 +5,11 @@ 2. Create a new Timestream database and table: ``` -aws timestream-write create-database --database-name CorrectnessDB --region us-west-2 && aws timestream-write create-table --database-name CorrectnessDB --table-name CorrectnessMetrics +aws timestream-write create-database --database-name CorrectnessDB --region us-east-1 && aws timestream-write create-table --database-name CorrectnessDB --table-name CorrectnessMetrics ``` ## Run Correctness Tests -1. Update the default database and table in [`docker-compose.yml`](https://github.com/awslabs/amazon-timestream-connector-prometheus/blob/main/docker-compose.yml) with your new Timestream database and table. +1. Update the default database, table and region in [`docker-compose.yml`](https://github.com/awslabs/amazon-timestream-connector-prometheus/blob/main/docker-compose.yml) with your new Timestream database, table and region. 2. Bring up the Prometheus Connector: ``` @@ -21,13 +21,13 @@ docker compose -f ../docker-compose.yml up -d ### Tips - To run correctness tests against an existing Timestream database, ensure the `freshTSDB` flag is disabled in the test suite. -- The `ingestionWaitTime` parameter is adjustable to account for network latency, ensuring data ingestion is complete before evaluating test outputs. The default of 1 second should be sufficient (and functionally expected), but can increase as needed. +- The `ingestionWaitTime` parameter is adjustable to account for network latency, ensuring data ingestion is complete before evaluating test outputs. The default of 1 second should be sufficient (and functionally expected), but can be increased as needed. ## Clean up -1. Delete your Timestream database: +1. Delete your new Timestream database and table: ``` -aws timestream-write delete-table --database-name CorrDB --table-name CorrMetrics --region us-west-2 && aws timestream-write delete-database --database-name CorrDB +aws timestream-write delete-table --database-name CorrectnessDB --table-name CorrectnessMetrics --region us-east-1 && aws timestream-write delete-database --database-name CorrectnessDB ```` 2. Bring down the Connector with: From 80751e60bb9b7583b1d344be90f5c11e38e36aa7 Mon Sep 17 00:00:00 2001 From: Fred Park Date: Tue, 7 Jan 2025 16:26:03 -0800 Subject: [PATCH 4/6] addressing comments --- correctness/README.md | 80 +++++++++++++++++++++++---------- correctness/correctness_test.go | 27 ++++++++++- docker-compose.yml | 6 +-- main_test.go | 2 +- timestream/client.go | 17 ++++++- 5 files changed, 102 insertions(+), 30 deletions(-) diff --git a/correctness/README.md b/correctness/README.md index 34ab293..f3981f7 100644 --- a/correctness/README.md +++ b/correctness/README.md @@ -1,36 +1,70 @@ # Correctness Testing for Prometheus Connector ## Prerequisites -1. Ensure your AWS credentials are configured for your environment. You can configure it with `aws configure`. -2. Create a new Timestream database and table: -``` -aws timestream-write create-database --database-name CorrectnessDB --region us-east-1 && aws timestream-write create-table --database-name CorrectnessDB --table-name CorrectnessMetrics -``` +1. **Configure AWS Credentials** + + Ensure your AWS credentials are configured for your environment. You can set them up using: + ```bash + aws configure + ``` + + **Note:** MFA credentials are not supported. + +2. **Create a New Timestream Database and Table** + + Execute the following command to create a new Timestream database and table: + ```bash + aws timestream-write create-database --database-name CorrectnessDB --region && \ + aws timestream-write create-table --database-name CorrectnessDB --table-name CorrectnessMetrics --region + ``` ## Run Correctness Tests -1. Update the default database, table and region in [`docker-compose.yml`](https://github.com/awslabs/amazon-timestream-connector-prometheus/blob/main/docker-compose.yml) with your new Timestream database, table and region. -2. Bring up the Prometheus Connector: -``` -docker compose -f ../docker-compose.yml up -d -``` +1. **Start the Prometheus Connector** + + Bring up the Prometheus Connector using the following command: + ```bash + DEFAULT_DATABASE=CorrectnessDB DEFAULT_TABLE=CorrectnessMetrics AWS_REGION= docker compose -f ../docker-compose.yml up -d + ``` + +2. **Execute Tests** + + Run the tests with: + ```bash + go test -v + ``` + + *Note:* Tests typically take between 15 to 20 seconds to complete. + +## Flags + +The correctness test suite (`correctness_test.go`) accepts several flags to customize its behavior during correctness testing. Below is a list of available flags along with their descriptions and default values: + +| **Flag** | **Description** | **Default Value** | +|----------|----------------|-------------------| +| `freshTSDB` | Indicates whether the tests should expect a clean database state. Set to `true` for a fresh database, `false` for an existing database with data. | `true` | +| `ingestionWaitTime` | Sets the wait time (in seconds) after data ingestion to allow for data consistency before tests are evaluated. | `1s` | + +For example, to run against an existing Timestream database and table: -3. Run `go test -v`. Tests can take between 15~20 seconds to complete. + ```bash + go test -v -freshTSDB=false + ``` -### Tips +## Clean Up -- To run correctness tests against an existing Timestream database, ensure the `freshTSDB` flag is disabled in the test suite. -- The `ingestionWaitTime` parameter is adjustable to account for network latency, ensuring data ingestion is complete before evaluating test outputs. The default of 1 second should be sufficient (and functionally expected), but can be increased as needed. +1. **Delete the Timestream Database and Table** -## Clean up -1. Delete your new Timestream database and table: + Remove your newly created Timestream database and table using: + ```bash + aws timestream-write delete-table --database-name CorrectnessDB --table-name CorrectnessMetrics --region && \ + aws timestream-write delete-database --database-name CorrectnessDB --region + ``` -``` -aws timestream-write delete-table --database-name CorrectnessDB --table-name CorrectnessMetrics --region us-east-1 && aws timestream-write delete-database --database-name CorrectnessDB -```` +2. **Stop the Prometheus Connector** -2. Bring down the Connector with: -``` -docker compose -f ../docker-compose.yml down -``` + Bring down the Connector with: + ```bash + docker compose -f ../docker-compose.yml down + ``` diff --git a/correctness/correctness_test.go b/correctness/correctness_test.go index 118f71f..4c70651 100644 --- a/correctness/correctness_test.go +++ b/correctness/correctness_test.go @@ -18,6 +18,7 @@ package correctness import ( "context" + "flag" "fmt" "math/rand" "os" @@ -27,15 +28,22 @@ import ( ) // Enable this flag when working with a fresh Timestream database. -var freshTSDB = false +var freshTSDB bool // ingestionWaitTime is the duration to wait for data ingestion. -var ingestionWaitTime = 1 * time.Second +var ingestionWaitTime time.Duration // Shared Mockmetheus instance var m *Mockmetheus +func init() { + flag.BoolVar(&freshTSDB, "freshTSDB", true, "Use a fresh Timestream DB") + flag.DurationVar(&ingestionWaitTime, "ingestionWaitTime", 1*time.Second, "Delay to wait for data ingestion.") +} + func TestMain(main *testing.M) { + flag.Parse() + var err error m, err = NewMockmetheus("http://0.0.0.0:9201") if err != nil { @@ -85,6 +93,21 @@ func TestReadMetricDNE(t *testing.T) { } } +func TestReadLabelDNE(t *testing.T) { + ctx := context.Background() + + metric := "non_existent_metric" + label := "some_label_value" + query := fmt.Sprintf(`%s{non_existent_label="%s"}`, metric, label) + resp, err := m.RemoteRead(ctx, query) + if err != nil { + t.Fatalf("RemoteRead error: %v", err) + } + if !isEmpty(resp) { + t.Errorf("expected empty results for DNE metric but got non-empty") + } +} + func TestWriteNoData(t *testing.T) { ctx := context.Background() diff --git a/docker-compose.yml b/docker-compose.yml index bdae10b..89ca7a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: volumes: - .:/home command: - - --default-database=PrometheusDatabase - - --default-table=PrometheusMetricsTable - - --region=us-east-1 + - --default-database=${DEFAULT_DATABASE:-PrometheusDatabase} + - --default-table=${DEFAULT_TABLE:-PrometheusMetricsTable} + - --region=${AWS_REGION:-us-east-1} - --log.level=debug diff --git a/main_test.go b/main_test.go index b2c2e83..1e239d0 100644 --- a/main_test.go +++ b/main_test.go @@ -780,7 +780,7 @@ func TestWriteHandler(t *testing.T) { var emptyTimeSeries *prompb.TimeSeries invalidTimeSeries := &prompb.TimeSeries{ - Labels: []*prompb.Label{}, + Labels: []*prompb.Label{}, Samples: []prompb.Sample{}, } invalidWriteRequest := &prompb.WriteRequest{Timeseries: []*prompb.TimeSeries{invalidTimeSeries}} diff --git a/timestream/client.go b/timestream/client.go index 28e463c..16f60ca 100644 --- a/timestream/client.go +++ b/timestream/client.go @@ -308,7 +308,7 @@ func (qc *QueryClient) Read( begin := time.Now() var queryPageError error - for _, queryInput := range queryInputs { + for idx, queryInput := range queryInputs { paginator := initPaginatorFactory(qc.timestreamQuery, queryInput) for paginator.HasMorePages() { page, err := paginator.NextPage(ctx) @@ -328,6 +328,21 @@ func (qc *QueryClient) Read( } if queryPageError != nil { + // If columns are missing, Timestream's strict schema validation throws an OperationError exception. + // Return an empty set to ensure compatibility with Prometheus behavior. + var opError *smithy.OperationError + if goErrors.As(queryPageError, &opError) { + underlyingErr := opError.Unwrap() + if underlyingErr != nil { + errMessage := underlyingErr.Error() + if strings.Contains(errMessage, "does not exist") && strings.Contains(errMessage, "Column") { + LogInfo(qc.logger, "Returning empty result for this query due to missing column.") + results[idx] = &prompb.QueryResult{} + queryPageError = nil + continue + } + } + } var apiError *smithy.GenericAPIError if goErrors.As(queryPageError, &apiError) && apiError.Code == "ValidationException" && isRelatedToRegex { LogError(qc.logger, "Error occurred due to unsupported query. Please validate the regular expression used in the query. Check the documentation for unsupported RE2 syntax.", queryPageError) From 440d8def93f5232afb0fd8a1afa11a1b6cce4f3f Mon Sep 17 00:00:00 2001 From: Fred Park Date: Tue, 7 Jan 2025 16:28:42 -0800 Subject: [PATCH 5/6] comment --- correctness/correctness_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/correctness/correctness_test.go b/correctness/correctness_test.go index 4c70651..98029ff 100644 --- a/correctness/correctness_test.go +++ b/correctness/correctness_test.go @@ -104,7 +104,7 @@ func TestReadLabelDNE(t *testing.T) { t.Fatalf("RemoteRead error: %v", err) } if !isEmpty(resp) { - t.Errorf("expected empty results for DNE metric but got non-empty") + t.Errorf("expected empty results for DNE label but got non-empty") } } From 5479db26b104e112fb5f6334bc80c677a37c6ce3 Mon Sep 17 00:00:00 2001 From: Fred Park Date: Wed, 8 Jan 2025 08:58:57 -0800 Subject: [PATCH 6/6] missed using delayed offset --- correctness/correctness_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/correctness/correctness_test.go b/correctness/correctness_test.go index 98029ff..29a2c73 100644 --- a/correctness/correctness_test.go +++ b/correctness/correctness_test.go @@ -283,7 +283,7 @@ func TestSuccessWriteMultipleMetrics(t *testing.T) { } // Query for second metric - query2 := fmt.Sprintf(`%s{instance="%s", job="%s", test_id="%s"}[3s]`, name2, instance, job, testID) + query2 := fmt.Sprintf(`%s{instance="%s", job="%s", test_id="%s"}[%ds]`, name2, instance, job, testID, waitSeconds) resp2, err := m.RemoteRead(ctx, query2) if err != nil { t.Fatalf("RemoteRead error: %v", err)