@@ -8,18 +8,22 @@ import (
8
8
"fmt"
9
9
"os"
10
10
"path/filepath"
11
+ "sync"
11
12
"testing"
12
13
13
14
"github.com/golang-migrate/migrate/v4"
14
15
migratepostgres "github.com/golang-migrate/migrate/v4/database/postgres"
15
16
"github.com/golang-migrate/migrate/v4/source"
16
17
"github.com/golang-migrate/migrate/v4/source/iofs"
17
18
"github.com/golang-migrate/migrate/v4/source/stub"
19
+ "github.com/lib/pq"
18
20
"github.com/stretchr/testify/require"
19
21
"go.uber.org/goleak"
22
+ "golang.org/x/exp/slices"
20
23
21
24
"github.com/coder/coder/coderd/database/migrations"
22
25
"github.com/coder/coder/coderd/database/postgres"
26
+ "github.com/coder/coder/testutil"
23
27
)
24
28
25
29
func TestMain (m * testing.M ) {
@@ -165,6 +169,31 @@ func setupMigrate(t *testing.T, db *sql.DB, name, path string) (source.Driver, *
165
169
return d , m
166
170
}
167
171
172
+ type tableStats struct {
173
+ mu sync.Mutex
174
+ s map [string ]int
175
+ }
176
+
177
+ func (s * tableStats ) Add (table string , n int ) {
178
+ s .mu .Lock ()
179
+ defer s .mu .Unlock ()
180
+
181
+ s .s [table ] = s .s [table ] + n
182
+ }
183
+
184
+ func (s * tableStats ) Empty () []string {
185
+ s .mu .Lock ()
186
+ defer s .mu .Unlock ()
187
+
188
+ var m []string
189
+ for table , n := range s .s {
190
+ if n == 0 {
191
+ m = append (m , table )
192
+ }
193
+ }
194
+ return m
195
+ }
196
+
168
197
func TestMigrateUpWithFixtures (t * testing.T ) {
169
198
t .Parallel ()
170
199
@@ -176,11 +205,16 @@ func TestMigrateUpWithFixtures(t *testing.T) {
176
205
type testCase struct {
177
206
name string
178
207
path string
208
+
209
+ // For determining if test case table stats
210
+ // are used to determine test coverage.
211
+ useStats bool
179
212
}
180
213
tests := []testCase {
181
214
{
182
- name : "fixtures" ,
183
- path : filepath .Join ("testdata" , "fixtures" ),
215
+ name : "fixtures" ,
216
+ path : filepath .Join ("testdata" , "fixtures" ),
217
+ useStats : true ,
184
218
},
185
219
// More test cases added via glob below.
186
220
}
@@ -191,11 +225,42 @@ func TestMigrateUpWithFixtures(t *testing.T) {
191
225
require .NoError (t , err )
192
226
for _ , match := range matches {
193
227
tests = append (tests , testCase {
194
- name : filepath .Base (match ),
195
- path : match ,
228
+ name : filepath .Base (match ),
229
+ path : match ,
230
+ useStats : true ,
196
231
})
197
232
}
198
233
234
+ // These tables are allowed to have zero rows for now,
235
+ // but we should eventually add fixtures for them.
236
+ ignoredTablesForStats := []string {
237
+ "audit_logs" ,
238
+ "git_auth_links" ,
239
+ "group_members" ,
240
+ "licenses" ,
241
+ "replicas" ,
242
+ }
243
+ s := & tableStats {s : make (map [string ]int )}
244
+
245
+ // This will run after all subtests have run and fail the test if
246
+ // new tables have been added without covering them with fixtures.
247
+ t .Cleanup (func () {
248
+ emptyTables := s .Empty ()
249
+ slices .Sort (emptyTables )
250
+ for _ , table := range ignoredTablesForStats {
251
+ i := slices .Index (emptyTables , table )
252
+ if i >= 0 {
253
+ emptyTables = slices .Delete (emptyTables , i , i + 1 )
254
+ }
255
+ }
256
+ if len (emptyTables ) > 0 {
257
+ t .Logf ("The following tables have zero rows, consider adding fixtures for them or create a full database dump:" )
258
+ t .Errorf ("tables have zero rows: %v" , emptyTables )
259
+ // TODO(mafredri): Placeholder URL.
260
+ t .Logf ("See https://github.com/coder/coder/blob/main/migrations/README.md#creating-fixtures for more information" )
261
+ }
262
+ })
263
+
199
264
for _ , tt := range tests {
200
265
tt := tt
201
266
@@ -204,6 +269,8 @@ func TestMigrateUpWithFixtures(t *testing.T) {
204
269
205
270
db := testSQLDB (t )
206
271
272
+ ctx , _ := testutil .Context (t )
273
+
207
274
// Prepare database for stepping up.
208
275
err := migrations .Down (db )
209
276
require .NoError (t , err )
@@ -240,6 +307,29 @@ func TestMigrateUpWithFixtures(t *testing.T) {
240
307
241
308
t .Logf ("migrated to version %d, fixture version %d" , version , fixtureVer )
242
309
}
310
+
311
+ // Gather number of rows for all existing tables
312
+ // at the end of the migrations and fixtures.
313
+ var tables pq.StringArray
314
+ err = db .QueryRowContext (ctx , `
315
+ SELECT array_agg(tablename)
316
+ FROM pg_catalog.pg_tables
317
+ WHERE
318
+ schemaname != 'information_schema'
319
+ AND schemaname != 'pg_catalog'
320
+ AND tablename NOT LIKE 'test_migrate_%'
321
+ ` ).Scan (& tables )
322
+ require .NoError (t , err )
323
+
324
+ for _ , table := range tables {
325
+ var count int
326
+ err = db .QueryRowContext (ctx , "SELECT COUNT(*) FROM " + table ).Scan (& count )
327
+ require .NoError (t , err )
328
+
329
+ if tt .useStats {
330
+ s .Add (table , count )
331
+ }
332
+ }
243
333
})
244
334
}
245
335
}
0 commit comments