From 35485b57578160d2abee872322dda8b8a2ac6b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C4=8Ctvrtka?= Date: Thu, 19 Feb 2026 14:43:34 +0100 Subject: [PATCH 1/7] PMM-14527 Ability to have aurora queries. --- .../postgres_exporter_test.go | 2 +- cmd/postgres_exporter/queries.go | 32 +++++-- cmd/postgres_exporter/queries_test.go | 92 +++++++++++++++++++ cmd/postgres_exporter/server.go | 21 ++++- .../medium-resolution/queries.yaml | 5 +- queries-mr.yaml | 3 + 6 files changed, 142 insertions(+), 13 deletions(-) create mode 100644 cmd/postgres_exporter/queries_test.go diff --git a/cmd/postgres_exporter/postgres_exporter_test.go b/cmd/postgres_exporter/postgres_exporter_test.go index 5b2879d94..cb6400caa 100644 --- a/cmd/postgres_exporter/postgres_exporter_test.go +++ b/cmd/postgres_exporter/postgres_exporter_test.go @@ -409,7 +409,7 @@ func (s *FunctionalSuite) TestBooleanConversionToValueAndString(c *C) { func (s *FunctionalSuite) TestParseUserQueries(c *C) { userQueriesData, err := os.ReadFile("./tests/user_queries_ok.yaml") if err == nil { - metricMaps, newQueryOverrides, err := parseUserQueries(userQueriesData) + metricMaps, newQueryOverrides, err := parseUserQueries(userQueriesData, distributionStandard) c.Assert(err, Equals, nil) c.Assert(metricMaps, NotNil) c.Assert(newQueryOverrides, NotNil) diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index 3596b2905..da8a8a47a 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -23,10 +23,16 @@ import ( "gopkg.in/yaml.v2" ) -// UserQuery represents a user defined query +const ( + distributionStandard = "standard" + distributionAurora = "aurora" +) + +// UserQuery represents a user defined query, including support for Aurora, if needed type UserQuery struct { - Query string `yaml:"query"` - Metrics []Mapping `yaml:"metrics"` + Query string `yaml:"query"` // Standard query + QueryAurora string `yaml:"query_aurora"` // Aurora specific query + Metrics []Mapping `yaml:"metrics"` // Metrics to be collected Master bool `yaml:"master"` // Querying only for master database CacheSeconds uint64 `yaml:"cache_seconds"` // Number of seconds to cache the namespace result metrics for. RunOnServer string `yaml:"runonserver"` // Querying to run on which server version @@ -197,7 +203,7 @@ func makeQueryOverrideMap(pgVersion semver.Version, queryOverrides map[string][] return resultMap } -func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[string]string, error) { +func parseUserQueries(content []byte, distribution string) (map[string]intermediateMetricMap, map[string]string, error) { var userQueries UserQueries err := yaml.Unmarshal(content, &userQueries) @@ -211,7 +217,21 @@ func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[str for metric, specs := range userQueries { level.Debug(logger).Log("msg", "New user metric namespace from YAML metric", "metric", metric, "cache_seconds", specs.CacheSeconds) - newQueryOverrides[metric] = specs.Query + + // Query selection logic: + // - For Aurora: use query_aurora if defined and not empty, otherwise use query if defined and not empty. Skip if neither is set. + // - For standard (non-Aurora): always use query. + switch distribution { + case distributionAurora: + if specs.QueryAurora != "" { + newQueryOverrides[metric] = specs.QueryAurora + } else { + newQueryOverrides[metric] = specs.Query + } + default: + newQueryOverrides[metric] = specs.Query + } + metricMap, ok := metricMaps[metric] if !ok { // Namespace for metric not found - add it. @@ -251,7 +271,7 @@ func parseUserQueries(content []byte) (map[string]intermediateMetricMap, map[str // TODO: test code for all cu. // TODO: the YAML this supports is "non-standard" - we should move away from it. func addQueries(content []byte, pgVersion semver.Version, server *Server) error { - metricMaps, newQueryOverrides, err := parseUserQueries(content) + metricMaps, newQueryOverrides, err := parseUserQueries(content, server.distribution) if err != nil { return err } diff --git a/cmd/postgres_exporter/queries_test.go b/cmd/postgres_exporter/queries_test.go new file mode 100644 index 000000000..f8db1077e --- /dev/null +++ b/cmd/postgres_exporter/queries_test.go @@ -0,0 +1,92 @@ +// Copyright 2021 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License 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. + +package main + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseUserQueries_DistributionSelection(t *testing.T) { + cases := []struct { + name string + yamlInput string + distribution string + wantQuery string + }{ + { + name: "Standard uses query", + yamlInput: ` +pg_replication: + query: "standard" + query_aurora: "aurora" +`, + distribution: "standard", + wantQuery: "standard", + }, + { + name: "Aurora uses query_aurora", + yamlInput: ` +pg_replication: + query: "standard" + query_aurora: "aurora" +`, + distribution: "aurora", + wantQuery: "aurora", + }, + { + name: "Aurora falls back to query", + yamlInput: ` +pg_replication: + query: "standard" +`, + distribution: "aurora", + wantQuery: "standard", + }, + { + name: "Aurora skips if neither", + yamlInput: ` +pg_replication: +`, + distribution: "aurora", + wantQuery: "", + }, + { + name: "Standard query only", + yamlInput: ` +pg_replication: + query: "standard" +`, + distribution: "standard", + wantQuery: "standard", + }, + { + name: "Aurora query only", + yamlInput: ` +pg_replication: + query_aurora: "aurora" +`, + distribution: "aurora", + wantQuery: "aurora", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, metricsQueries, err := parseUserQueries([]byte(tc.yamlInput), tc.distribution) + require.NoError(t, err) + require.Equal(t, tc.wantQuery, metricsQueries["pg_replication"]) + }) + } +} diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index fd590a8b8..4060e238a 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -27,10 +27,11 @@ import ( // Server describes a connection to Postgres. // Also it contains metrics map and query overrides. type Server struct { - db *sql.DB - labels prometheus.Labels - master bool - runonserver string + db *sql.DB + distribution string + labels prometheus.Labels + master bool + runonserver string // Last version used to calculate metric map. If mismatch on scrape, // then maps are recalculated. @@ -80,7 +81,17 @@ func NewServer(dsn string, opts ...ServerOpt) (*Server, error) { labels: prometheus.Labels{ serverLabelName: fingerprint, }, - metricCache: make(map[string]cachedMetrics), + metricCache: make(map[string]cachedMetrics), + distribution: distributionStandard, + } + + // Detect Aurora by running SHOW rds.extensions + rows, err := db.Query("SHOW rds.extensions;") + if err == nil { + defer rows.Close() + if rows.Next() { + s.distribution = distributionAurora + } } for _, opt := range opts { diff --git a/percona_tests/custom-queries/medium-resolution/queries.yaml b/percona_tests/custom-queries/medium-resolution/queries.yaml index b28a4f7a2..a4667da25 100644 --- a/percona_tests/custom-queries/medium-resolution/queries.yaml +++ b/percona_tests/custom-queries/medium-resolution/queries.yaml @@ -1,6 +1,9 @@ #### Queries are commented due to PMM-8859 pg_replication: - query: "SELECT CASE WHEN NOT pg_is_in_recovery() THEN 0 ELSE GREATEST (0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))) END AS lag" +# Standard query +- query: "SELECT CASE WHEN NOT pg_is_in_recovery() THEN 0 ELSE GREATEST (0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))) END AS lag" +# Aurora query +- query_aurora: "SELECT CASE WHEN pg_is_in_recovery() THEN (SELECT COALESCE(MAX(replica_lag_in_msec), 0) / 1000.0 FROM aurora_replica_status()) ELSE 0 END AS lag" master: true metrics: - lag: diff --git a/queries-mr.yaml b/queries-mr.yaml index 700e74b65..ac74dd7ea 100644 --- a/queries-mr.yaml +++ b/queries-mr.yaml @@ -1,6 +1,9 @@ #### Queries are commented due to PMM-8859 pg_replication: + # Standard query query: "SELECT CASE WHEN NOT pg_is_in_recovery() THEN 0 ELSE GREATEST (0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))) END AS lag" + # Aurora query + query_aurora: "SELECT CASE WHEN pg_is_in_recovery() THEN (SELECT COALESCE(MAX(replica_lag_in_msec), 0) / 1000.0 FROM aurora_replica_status()) ELSE 0 END AS lag" master: true metrics: - lag: From 7db4817fb9562e003aee547171dc538c04b6a275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C4=8Ctvrtka?= Date: Mon, 23 Feb 2026 14:09:55 +0100 Subject: [PATCH 2/7] PMM-14527 Functionality to skip query for Aurora completely. --- cmd/postgres_exporter/queries.go | 10 ++++++++-- queries-hr.yml | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cmd/postgres_exporter/queries.go b/cmd/postgres_exporter/queries.go index da8a8a47a..2171ecc28 100644 --- a/cmd/postgres_exporter/queries.go +++ b/cmd/postgres_exporter/queries.go @@ -26,6 +26,8 @@ import ( const ( distributionStandard = "standard" distributionAurora = "aurora" + // '!' is a reserved character indicating that the query is not supported on Aurora and should be skipped for Aurora instances. + notSupportedByAurora = "!" ) // UserQuery represents a user defined query, including support for Aurora, if needed @@ -219,11 +221,15 @@ func parseUserQueries(content []byte, distribution string) (map[string]intermedi level.Debug(logger).Log("msg", "New user metric namespace from YAML metric", "metric", metric, "cache_seconds", specs.CacheSeconds) // Query selection logic: - // - For Aurora: use query_aurora if defined and not empty, otherwise use query if defined and not empty. Skip if neither is set. - // - For standard (non-Aurora): always use query. + // For Aurora: use query_aurora if defined and not empty, otherwise use query if defined and not empty. + // If query_aurora is set to '!', skip this query for Aurora (not supported). + // For standard (non-Aurora): always use query. switch distribution { case distributionAurora: if specs.QueryAurora != "" { + if specs.QueryAurora == notSupportedByAurora { + continue + } newQueryOverrides[metric] = specs.QueryAurora } else { newQueryOverrides[metric] = specs.Query diff --git a/queries-hr.yml b/queries-hr.yml index bb979da5e..b822b1be7 100644 --- a/queries-hr.yml +++ b/queries-hr.yml @@ -31,6 +31,7 @@ pg_custom_replication_slots: pg_custom_stat_wal_receiver: master: true + # standard query query: | SELECT status, @@ -43,6 +44,8 @@ pg_custom_stat_wal_receiver: EXTRACT(EPOCH FROM last_msg_send_time) AS last_msg_send_time_seconds, EXTRACT(EPOCH FROM last_msg_receipt_time) AS last_msg_receipt_time_seconds FROM pg_stat_wal_receiver; + # skipped for Aurora by query_aurora == '!' + query_aurora: "!" metrics: - status: usage: "LABEL" From 228599201da364129569cee1c63ac7e65978d151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C4=8Ctvrtka?= Date: Mon, 23 Feb 2026 16:00:00 +0100 Subject: [PATCH 3/7] PMM-14527 Add test case for Aurora skip. --- cmd/postgres_exporter/queries_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmd/postgres_exporter/queries_test.go b/cmd/postgres_exporter/queries_test.go index f8db1077e..555ea8c47 100644 --- a/cmd/postgres_exporter/queries_test.go +++ b/cmd/postgres_exporter/queries_test.go @@ -81,6 +81,16 @@ pg_replication: distribution: "aurora", wantQuery: "aurora", }, + { + name: "Not supported by Aurora", + yamlInput: ` +pg_replication: + query: "standard" + query_aurora: "!" +`, + distribution: "aurora", + wantQuery: "", + }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { From e827f5ef009669982c36a9d3f85e700854da86e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C4=8Ctvrtka?= Date: Tue, 24 Feb 2026 11:52:24 +0100 Subject: [PATCH 4/7] PMM-14527 Better check if Aurora. --- cmd/postgres_exporter/server.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index 4060e238a..f910a3c42 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -16,6 +16,7 @@ package main import ( "database/sql" "fmt" + "strings" "sync" "time" @@ -85,11 +86,12 @@ func NewServer(dsn string, opts ...ServerOpt) (*Server, error) { distribution: distributionStandard, } - // Detect Aurora by running SHOW rds.extensions - rows, err := db.Query("SHOW rds.extensions;") - if err == nil { - defer rows.Close() - if rows.Next() { + // Detect Aurora by checking version string + row := db.QueryRow("SELECT version();") + var versionStr string + if err := row.Scan(&versionStr); err == nil { + level.Info(logger).Log("msg", "Postgres version", "version", versionStr) + if strings.Contains(strings.ToLower(versionStr), "aurora") { s.distribution = distributionAurora } } From 03adf8e3727f7e2b8bcf7669c8c6e5c2b12af503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C4=8Ctvrtka?= Date: Tue, 24 Feb 2026 12:26:54 +0100 Subject: [PATCH 5/7] PMM-14527 Check for func of Aurora. --- cmd/postgres_exporter/server.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index f910a3c42..856fc81fc 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -16,7 +16,6 @@ package main import ( "database/sql" "fmt" - "strings" "sync" "time" @@ -86,12 +85,11 @@ func NewServer(dsn string, opts ...ServerOpt) (*Server, error) { distribution: distributionStandard, } - // Detect Aurora by checking version string - row := db.QueryRow("SELECT version();") - var versionStr string - if err := row.Scan(&versionStr); err == nil { - level.Info(logger).Log("msg", "Postgres version", "version", versionStr) - if strings.Contains(strings.ToLower(versionStr), "aurora") { + // Detect Aurora by checking for aurora_version function + rows, err := db.Query("SELECT 1 FROM pg_proc WHERE proname = 'aurora_version';") + if err == nil { + defer rows.Close() + if rows.Next() { s.distribution = distributionAurora } } From 80d1d65b6abcd4df8f953d2262db2fc4fa2d8a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C4=8Ctvrtka?= Date: Tue, 24 Feb 2026 13:17:09 +0100 Subject: [PATCH 6/7] PMM-14527 Different check for func exists. --- cmd/postgres_exporter/server.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cmd/postgres_exporter/server.go b/cmd/postgres_exporter/server.go index 856fc81fc..df7ab2117 100644 --- a/cmd/postgres_exporter/server.go +++ b/cmd/postgres_exporter/server.go @@ -85,13 +85,11 @@ func NewServer(dsn string, opts ...ServerOpt) (*Server, error) { distribution: distributionStandard, } - // Detect Aurora by checking for aurora_version function - rows, err := db.Query("SELECT 1 FROM pg_proc WHERE proname = 'aurora_version';") - if err == nil { - defer rows.Close() - if rows.Next() { - s.distribution = distributionAurora - } + // Detect Aurora by checking if aurora_version function exists + row := db.QueryRow("SELECT to_regproc('aurora_version') IS NOT NULL;") + var isAurora bool + if err := row.Scan(&isAurora); err == nil && isAurora { + s.distribution = distributionAurora } for _, opt := range opts { From 997161ed57817eabdb0f762a8b49537cd18c595e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20=C4=8Ctvrtka?= Date: Wed, 4 Mar 2026 14:39:05 +0100 Subject: [PATCH 7/7] PMM-14527 Bump minimum PG to 10. --- cmd/postgres_exporter/postgres_exporter.go | 2 +- cmd/postgres_exporter/queries_test.go | 22 +++--- collector/pg_xlog_location.go | 91 ---------------------- collector/pg_xlog_location_test.go | 61 --------------- 4 files changed, 13 insertions(+), 163 deletions(-) delete mode 100644 collector/pg_xlog_location.go delete mode 100644 collector/pg_xlog_location_test.go diff --git a/cmd/postgres_exporter/postgres_exporter.go b/cmd/postgres_exporter/postgres_exporter.go index 3d890a16f..4666d9f83 100644 --- a/cmd/postgres_exporter/postgres_exporter.go +++ b/cmd/postgres_exporter/postgres_exporter.go @@ -81,7 +81,7 @@ type Mapping map[string]MappingOptions // Regex used to get the "short-version" from the postgres version field. var versionRegex = regexp.MustCompile(`^\w+ ((\d+)(\.\d+)?(\.\d+)?)`) -var lowestSupportedVersion = semver.MustParse("9.1.0") +var lowestSupportedVersion = semver.MustParse("10.0.0") // Parses the version of postgres into the short version string we can use to // match behaviors. diff --git a/cmd/postgres_exporter/queries_test.go b/cmd/postgres_exporter/queries_test.go index 555ea8c47..c1e7fd716 100644 --- a/cmd/postgres_exporter/queries_test.go +++ b/cmd/postgres_exporter/queries_test.go @@ -1,15 +1,17 @@ -// Copyright 2021 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at +// Copyright (C) 2023 Percona LLC // -// http://www.apache.org/licenses/LICENSE-2.0 +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// Unless required by applicable law or agreed to in writing, software -// distributed under the License 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. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . package main diff --git a/collector/pg_xlog_location.go b/collector/pg_xlog_location.go deleted file mode 100644 index 237204f7d..000000000 --- a/collector/pg_xlog_location.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2023 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License 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. - -package collector - -import ( - "context" - - "github.com/blang/semver/v4" - "github.com/go-kit/log" - "github.com/go-kit/log/level" - "github.com/prometheus/client_golang/prometheus" -) - -const xlogLocationSubsystem = "xlog_location" - -func init() { - registerCollector(xlogLocationSubsystem, defaultDisabled, NewPGXlogLocationCollector) -} - -type PGXlogLocationCollector struct { - log log.Logger -} - -func NewPGXlogLocationCollector(config collectorConfig) (Collector, error) { - return &PGXlogLocationCollector{log: config.logger}, nil -} - -var ( - xlogLocationBytes = prometheus.NewDesc( - prometheus.BuildFQName(namespace, xlogLocationSubsystem, "bytes"), - "Postgres LSN (log sequence number) being generated on primary or replayed on replica (truncated to low 52 bits)", - []string{}, - prometheus.Labels{}, - ) - - xlogLocationQuery = ` - SELECT CASE - WHEN pg_is_in_recovery() THEN (pg_last_xlog_replay_location() - '0/0') % (2^52)::bigint - ELSE (pg_current_xlog_location() - '0/0') % (2^52)::bigint - END AS bytes - ` -) - -func (c PGXlogLocationCollector) Update(ctx context.Context, instance *instance, ch chan<- prometheus.Metric) error { - db := instance.getDB() - - // xlog was renmaed to WAL in PostgreSQL 10 - // https://wiki.postgresql.org/wiki/New_in_postgres_10#Renaming_of_.22xlog.22_to_.22wal.22_Globally_.28and_location.2Flsn.29 - after10 := instance.version.Compare(semver.MustParse("10.0.0")) - if after10 >= 0 { - level.Warn(c.log).Log("msg", "xlog_location collector is not available on PostgreSQL >= 10.0.0, skipping") - return nil - } - - rows, err := db.QueryContext(ctx, - xlogLocationQuery) - - if err != nil { - return err - } - defer rows.Close() - - for rows.Next() { - var bytes float64 - - if err := rows.Scan(&bytes); err != nil { - return err - } - - ch <- prometheus.MustNewConstMetric( - xlogLocationBytes, - prometheus.GaugeValue, - bytes, - ) - } - if err := rows.Err(); err != nil { - return err - } - return nil -} diff --git a/collector/pg_xlog_location_test.go b/collector/pg_xlog_location_test.go deleted file mode 100644 index 561a7df94..000000000 --- a/collector/pg_xlog_location_test.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2023 The Prometheus Authors -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License 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. -package collector - -import ( - "context" - "testing" - - "github.com/DATA-DOG/go-sqlmock" - "github.com/prometheus/client_golang/prometheus" - dto "github.com/prometheus/client_model/go" - "github.com/smartystreets/goconvey/convey" -) - -func TestPGXlogLocationCollector(t *testing.T) { - db, mock, err := sqlmock.New() - if err != nil { - t.Fatalf("Error opening a stub db connection: %s", err) - } - defer db.Close() - inst := &instance{db: db} - columns := []string{ - "bytes", - } - rows := sqlmock.NewRows(columns). - AddRow(53401) - - mock.ExpectQuery(sanitizeQuery(xlogLocationQuery)).WillReturnRows(rows) - - ch := make(chan prometheus.Metric) - go func() { - defer close(ch) - c := PGXlogLocationCollector{} - - if err := c.Update(context.Background(), inst, ch); err != nil { - t.Errorf("Error calling PGXlogLocationCollector.Update: %s", err) - } - }() - expected := []MetricResult{ - {labels: labelMap{}, value: 53401, metricType: dto.MetricType_GAUGE}, - } - convey.Convey("Metrics comparison", t, func() { - for _, expect := range expected { - m := readMetric(<-ch) - convey.So(expect, convey.ShouldResemble, m) - } - }) - if err := mock.ExpectationsWereMet(); err != nil { - t.Errorf("there were unfulfilled exceptions: %s", err) - } -}