Skip to content

Commit 184dce0

Browse files
authored
feat: implement db size monitor (#39)
* feat: implement db size monitor * test: add unit test for db size monitor * test: set tests to run in parallel
1 parent b111f2c commit 184dce0

9 files changed

+131
-5
lines changed

integration_delete_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
func testDelete_SingleTable(t *testing.T, createTestContext func(t testing.TB) *TestContext) {
1010
t.Run("NoTable", func(t *testing.T) {
11+
t.Parallel()
1112
tc := createTestContext(t)
1213
defer tc.CleanUp(t)
1314

@@ -18,6 +19,7 @@ func testDelete_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
1819
})
1920

2021
t.Run("DeleteFromEmptyTable", func(t *testing.T) {
22+
t.Parallel()
2123
tc := createTestContext(t)
2224
defer tc.CleanUp(t)
2325

@@ -29,6 +31,7 @@ func testDelete_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
2931
})
3032

3133
t.Run("DeleteFromNonEmptyTable", func(t *testing.T) {
34+
t.Parallel()
3235
tc := createTestContext(t)
3336
defer tc.CleanUp(t)
3437

@@ -49,6 +52,7 @@ func testDelete_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
4952
})
5053

5154
t.Run("DeleteWithFilter", func(t *testing.T) {
55+
t.Parallel()
5256
tc := createTestContext(t)
5357
defer tc.CleanUp(t)
5458

integration_insert_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
func testInsert_SingleTable(t *testing.T, createTestContext func(t testing.TB) *TestContext) {
1212
t.Run("NoTable", func(t *testing.T) {
13+
t.Parallel()
1314
tc := createTestContext(t)
1415
defer tc.CleanUp(t)
1516

@@ -22,6 +23,7 @@ func testInsert_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
2223
})
2324

2425
t.Run("InsertSingleValue", func(t *testing.T) {
26+
t.Parallel()
2527
tc := createTestContext(t)
2628
defer tc.CleanUp(t)
2729

@@ -45,6 +47,7 @@ func testInsert_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
4547
})
4648

4749
t.Run("InsertValues", func(t *testing.T) {
50+
t.Parallel()
4851
tc := createTestContext(t)
4952
defer tc.CleanUp(t)
5053

@@ -70,6 +73,7 @@ func testInsert_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
7073
})
7174

7275
t.Run("UpsertMergeDuplicates", func(t *testing.T) {
76+
t.Parallel()
7377
tc := createTestContext(t)
7478
defer tc.CleanUp(t)
7579

@@ -99,6 +103,7 @@ func testInsert_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
99103
})
100104

101105
t.Run("UpsertIgnoreDuplicates", func(t *testing.T) {
106+
t.Parallel()
102107
tc := createTestContext(t)
103108
defer tc.CleanUp(t)
104109

@@ -127,6 +132,7 @@ func testInsert_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
127132
})
128133

129134
t.Run("UpsertMergeDuplicatesWithOnConflicts", func(t *testing.T) {
135+
t.Parallel()
130136
tc := createTestContext(t)
131137
defer tc.CleanUp(t)
132138

integration_migrate_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
func TestMigration(t *testing.T) {
1212
t.Run("empty migrations", func(t *testing.T) {
13+
t.Parallel()
1314
tc := NewMigrationTestContext(t, nil)
1415
defer tc.CleanUp(t)
1516

@@ -24,6 +25,7 @@ func TestMigration(t *testing.T) {
2425
})
2526

2627
t.Run("apply all migrations", func(t *testing.T) {
28+
t.Parallel()
2729
tc := NewMigrationTestContext(t, map[string]string{
2830
"1_test.up.sql": `create table test (id int);`,
2931
"1_test.down.sql": `drop table test;`,
@@ -55,6 +57,7 @@ func TestMigration(t *testing.T) {
5557
})
5658

5759
t.Run("apply migrations by step", func(t *testing.T) {
60+
t.Parallel()
5861
tc := NewMigrationTestContext(t, map[string]string{
5962
"1_test.up.sql": `create table test (id int);`,
6063
"1_test.down.sql": `drop table test;`,
@@ -101,6 +104,7 @@ func TestMigration(t *testing.T) {
101104

102105
t.Run("failed migrations", func(t *testing.T) {
103106
t.Run("up", func(t *testing.T) {
107+
t.Parallel()
104108
tc := NewMigrationTestContext(t, map[string]string{
105109
"1_test.up.sql": `create table test invalid sql;`,
106110
"1_test.down.sql": `drop table test;`,
@@ -115,6 +119,7 @@ func TestMigration(t *testing.T) {
115119
})
116120

117121
t.Run("down", func(t *testing.T) {
122+
t.Parallel()
118123
tc := NewMigrationTestContext(t, map[string]string{
119124
"1_test.up.sql": `create table test (id int);`,
120125
"1_test.down.sql": `drop table invalid sql;`,

integration_security_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
func TestSecurityNegativeCases(t *testing.T) {
1313
t.Run("Unauthorized", func(t *testing.T) {
14+
t.Parallel()
1415
tc := createTestContextWithHMACTokenAuth(t)
1516
defer tc.CleanUp(t)
1617

@@ -22,6 +23,7 @@ func TestSecurityNegativeCases(t *testing.T) {
2223
})
2324

2425
t.Run("TableAccessRestricted", func(t *testing.T) {
26+
t.Parallel()
2527
tc := createTestContextWithHMACTokenAuth(t)
2628
defer tc.CleanUp(t)
2729

@@ -34,6 +36,7 @@ func TestSecurityNegativeCases(t *testing.T) {
3436

3537
func TestSecuritySQLInjection(t *testing.T) {
3638
t.Run("Update", func(t *testing.T) {
39+
t.Parallel()
3740
tc := createTestContextWithHMACTokenAuth(t)
3841
defer tc.CleanUp(t)
3942

@@ -65,6 +68,7 @@ func TestSecuritySQLInjection(t *testing.T) {
6568
})
6669

6770
t.Run("Select", func(t *testing.T) {
71+
t.Parallel()
6872
tc := createTestContextWithHMACTokenAuth(t)
6973
defer tc.CleanUp(t)
7074

integration_select_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
1515
t.Helper()
1616

1717
t.Run("NoTable", func(t *testing.T) {
18+
t.Parallel()
1819
tc := createTestContext(t)
1920
defer tc.CleanUp(t)
2021

@@ -26,6 +27,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
2627
})
2728

2829
t.Run("EmptyTable", func(t *testing.T) {
30+
t.Parallel()
2931
tc := createTestContext(t)
3032
defer tc.CleanUp(t)
3133

@@ -42,6 +44,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
4244
})
4345

4446
t.Run("SelectAllColumns", func(t *testing.T) {
47+
t.Parallel()
4548
tc := createTestContext(t)
4649
defer tc.CleanUp(t)
4750

@@ -63,6 +66,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
6366
})
6467

6568
t.Run("SelectSingleColumn", func(t *testing.T) {
69+
t.Parallel()
6670
tc := createTestContext(t)
6771
defer tc.CleanUp(t)
6872

@@ -83,6 +87,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
8387
})
8488

8589
t.Run("SelectWithFilter", func(t *testing.T) {
90+
t.Parallel()
8691
tc := createTestContext(t)
8792
defer tc.CleanUp(t)
8893

@@ -102,6 +107,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
102107
})
103108

104109
t.Run("SelectWithOrder", func(t *testing.T) {
110+
t.Parallel()
105111
tc := createTestContext(t)
106112
defer tc.CleanUp(t)
107113

@@ -163,6 +169,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
163169
})
164170

165171
t.Run("SelectPagination", func(t *testing.T) {
172+
t.Parallel()
166173
const rowsCount = int64(10)
167174

168175
tc := createTestContext(t)
@@ -260,6 +267,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
260267
})
261268

262269
t.Run("SelectView", func(t *testing.T) {
270+
t.Parallel()
263271
tc := createTestContext(t)
264272
defer tc.CleanUp(t)
265273

@@ -281,6 +289,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
281289
})
282290

283291
t.Run("SelectOperator", func(t *testing.T) {
292+
t.Parallel()
284293
tc := createTestContext(t)
285294
defer tc.CleanUp(t)
286295

@@ -395,6 +404,7 @@ func testSelect_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
395404
})
396405

397406
t.Run("SelectWithAdaptingColumns", func(t *testing.T) {
407+
t.Parallel()
398408
tc := createTestContext(t)
399409
defer tc.CleanUp(t)
400410

integration_update_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
func testUpdate_SingleTable(t *testing.T, createTestContext func(t testing.TB) *TestContext) {
1212
t.Run("NoTable", func(t *testing.T) {
13+
t.Parallel()
1314
tc := createTestContext(t)
1415
defer tc.CleanUp(t)
1516

@@ -21,6 +22,7 @@ func testUpdate_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
2122
})
2223

2324
t.Run("UpdateRecords", func(t *testing.T) {
25+
t.Parallel()
2426
tc := createTestContext(t)
2527
defer tc.CleanUp(t)
2628

@@ -45,6 +47,7 @@ func testUpdate_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
4547
})
4648

4749
t.Run("UpdateWithFilter", func(t *testing.T) {
50+
t.Parallel()
4851
tc := createTestContext(t)
4952
defer tc.CleanUp(t)
5053

@@ -71,6 +74,7 @@ func testUpdate_SingleTable(t *testing.T, createTestContext func(t testing.TB) *
7174
})
7275

7376
t.Run("UpdateSingleEntry", func(t *testing.T) {
77+
t.Parallel()
7478
tc := createTestContext(t)
7579
defer tc.CleanUp(t)
7680

metrics.go

+59-5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/go-chi/chi/v5"
1010
"github.com/go-chi/chi/v5/middleware"
1111
"github.com/go-logr/logr"
12+
"github.com/jmoiron/sqlx"
1213
"github.com/prometheus/client_golang/prometheus"
1314
"github.com/prometheus/client_golang/prometheus/promauto"
1415
"github.com/prometheus/client_golang/prometheus/promhttp"
@@ -18,8 +19,9 @@ import (
1819
const metricsServerDisabledAddr = ""
1920

2021
type MetricsServerOptions struct {
21-
Logger logr.Logger
22-
Addr string
22+
Logger logr.Logger
23+
Addr string
24+
Queryer sqlx.QueryerContext
2325
}
2426

2527
func (opts *MetricsServerOptions) bindCLIFlags(fs *pflag.FlagSet) {
@@ -34,12 +36,19 @@ func (opts *MetricsServerOptions) defaults() error {
3436
opts.Logger = logr.Discard()
3537
}
3638

39+
if opts.Addr != metricsServerDisabledAddr {
40+
if opts.Queryer == nil {
41+
return fmt.Errorf(".Queryer is required")
42+
}
43+
}
44+
3745
return nil
3846
}
3947

4048
type metricsServer struct {
41-
logger logr.Logger
42-
server *http.Server
49+
logger logr.Logger
50+
server *http.Server
51+
queryer sqlx.QueryerContext
4352
}
4453

4554
func NewMetricsServer(opts MetricsServerOptions) (*metricsServer, error) {
@@ -48,7 +57,8 @@ func NewMetricsServer(opts MetricsServerOptions) (*metricsServer, error) {
4857
}
4958

5059
srv := &metricsServer{
51-
logger: opts.Logger,
60+
logger: opts.Logger,
61+
queryer: opts.Queryer,
5262
}
5363

5464
if opts.Addr == metricsServerDisabledAddr {
@@ -65,12 +75,48 @@ func NewMetricsServer(opts MetricsServerOptions) (*metricsServer, error) {
6575
return srv, nil
6676
}
6777

78+
func (server *metricsServer) monitorDatabaseSize(
79+
done <-chan struct{},
80+
observeFn func(sizeInBytes float64),
81+
) {
82+
const dbSizeQuery = `SELECT
83+
page_count * page_size
84+
FROM pragma_page_count(), pragma_page_size();`
85+
86+
observe := func() {
87+
var size int64
88+
err := server.queryer.QueryRowxContext(context.Background(), dbSizeQuery).Scan(&size)
89+
if err != nil {
90+
server.logger.Error(err, "failed to get database size")
91+
return
92+
}
93+
94+
observeFn(float64(size))
95+
}
96+
observe()
97+
98+
ticker := time.NewTicker(30 * time.Second)
99+
defer ticker.Stop()
100+
for {
101+
select {
102+
case <-done:
103+
return
104+
case <-ticker.C:
105+
observe()
106+
}
107+
}
108+
}
109+
68110
func (server *metricsServer) Start(done <-chan struct{}) {
69111
if server.server == nil {
70112
server.logger.V(8).Info("metrics server is disabled")
71113
return
72114
}
73115

116+
go server.monitorDatabaseSize(done, func(sizeInBytes float64) {
117+
metricsDatabaseSize.Set(sizeInBytes)
118+
server.logger.V(8).Info("database size", "sizeInBytes", sizeInBytes)
119+
})
74120
go server.server.ListenAndServe()
75121

76122
server.logger.Info("metrics server started", "addr", server.server.Addr)
@@ -124,6 +170,14 @@ var (
124170
},
125171
[]string{metricsLabelTarget, metricsLabelTargetOperation, metricsLabelHTTPCode},
126172
)
173+
174+
metricsDatabaseSize = promauto.NewGauge(
175+
prometheus.GaugeOpts{
176+
Namespace: metricsNamespace,
177+
Name: "database_size_bytes",
178+
Help: "Size of the database file",
179+
},
180+
)
127181
)
128182

129183
func recordRequestMetrics(op string) func(http.Handler) http.Handler {

0 commit comments

Comments
 (0)