Skip to content

Commit f588ca8

Browse files
author
Pierre SOUCHAY
committed
test: added TestPGDatabaseTimeout to ensure our timing behaves as it should
Signed-off-by: Pierre Souchay <pierre.souchay@pelico.io>
1 parent 8d229a3 commit f588ca8

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

collector/collector.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,6 @@ func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) {
178178

179179
// Collect implements the prometheus.Collector interface.
180180
func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) {
181-
ctx, cancel := context.WithTimeout(context.Background(), p.CollectionTimeout)
182-
defer cancel()
183181
// copy the instance so that concurrent scrapes have independent instances
184182
inst := p.instance.copy()
185183

@@ -190,6 +188,12 @@ func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) {
190188
p.logger.Error("Error opening connection to database", "err", err)
191189
return
192190
}
191+
p.collectFromConnection(inst, ch)
192+
}
193+
194+
func (p PostgresCollector) collectFromConnection(inst *instance, ch chan<- prometheus.Metric) {
195+
ctx, cancel := context.WithTimeout(context.Background(), p.CollectionTimeout)
196+
defer cancel()
193197

194198
wg := sync.WaitGroup{}
195199
wg.Add(len(p.Collectors))

collector/pg_database_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,80 @@ package collector
1515
import (
1616
"context"
1717
"testing"
18+
"time"
1819

1920
"github.com/DATA-DOG/go-sqlmock"
2021
"github.com/prometheus/client_golang/prometheus"
22+
2123
dto "github.com/prometheus/client_model/go"
24+
"github.com/prometheus/common/promslog"
2225
"github.com/smartystreets/goconvey/convey"
2326
)
2427

28+
// We ensure that when the database respond after a long time
29+
// The collection process still occurs in a predictable manner
30+
// Will avoid accumulation of queries on a completely frozen DB
31+
func TestPGDatabaseTimeout(t *testing.T) {
32+
33+
timeoutForQuery := time.Duration(100 * time.Millisecond)
34+
35+
db, mock, err := sqlmock.New()
36+
if err != nil {
37+
t.Fatalf("Error opening a stub db connection: %s", err)
38+
}
39+
defer db.Close()
40+
41+
inst := &instance{db: db}
42+
43+
columns := []string{"pg_roles.rolname", "pg_roles.rolconnlimit"}
44+
rows := sqlmock.NewRows(columns).AddRow("role1", 2)
45+
mock.ExpectQuery(pgRolesConnectionLimitsQuery).
46+
WillDelayFor(30 * time.Second).
47+
WillReturnRows(rows)
48+
49+
log_config := promslog.Config{}
50+
51+
logger := promslog.New(&log_config)
52+
53+
c, err := NewPostgresCollector(logger, []string{}, "postgresql://local", []string{}, CollectionTimeout(timeoutForQuery.String()))
54+
if err != nil {
55+
t.Fatalf("error creating NewPostgresCollector: %s", err)
56+
}
57+
collector_config := collectorConfig{
58+
logger: logger,
59+
excludeDatabases: []string{},
60+
}
61+
62+
collector, err := NewPGRolesCollector(collector_config)
63+
if err != nil {
64+
t.Fatalf("error creating collector: %s", err)
65+
}
66+
c.Collectors["test"] = collector
67+
c.instance = inst
68+
69+
ch := make(chan prometheus.Metric)
70+
defer close(ch)
71+
72+
go func() {
73+
for {
74+
<-ch
75+
time.Sleep(1 * time.Millisecond)
76+
}
77+
}()
78+
79+
startTime := time.Now()
80+
c.collectFromConnection(inst, ch)
81+
elapsed := time.Since(startTime)
82+
83+
if elapsed <= timeoutForQuery {
84+
t.Errorf("elapsed time was %v, should be bigger than timeout=%v", elapsed, timeoutForQuery)
85+
}
86+
87+
if err := mock.ExpectationsWereMet(); err != nil {
88+
t.Errorf("there were unfulfilled exceptions: %s", err)
89+
}
90+
}
91+
2592
func TestPGDatabaseCollector(t *testing.T) {
2693
db, mock, err := sqlmock.New()
2794
if err != nil {

0 commit comments

Comments
 (0)