• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

golang-migrate / migrate / 24640136570

19 Apr 2026 09:58PM UTC coverage: 56.328% (+1.9%) from 54.432%
24640136570

Pull #1394

github

joschi
fix: address second round of Copilot review comments

- README.md: fix db.system → db.system.name in database span table
- otel.go: call otel.Handle(err) on instrument creation errors instead
  of silently discarding them (doc comment already promised this)
- migrate.go: use attribute.Int64 for uint version fields to avoid
  int overflow on 32-bit platforms
- migrate.go: sanitize database.Error in otelSpanSetError to avoid
  leaking migration SQL into trace span status descriptions
- database/oteldriver.go: same SQL-leak fix in endSpan; add errors import
- source/oteldriver.go: use attribute.Int64 for uint version fields
- source/oteldriver_test.go: assert span.Status().Code != codes.Error
  directly rather than comparing full sdktrace.Status struct
- source/pkger/pkger.go: fix import grouping (stdlib before third-party)
- source/google_cloud_storage/storage.go: merge context into stdlib group

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pull Request #1394: feat: OpenTelemetry instrumentation

1020 of 1236 new or added lines in 47 files covered. (82.52%)

8 existing lines in 7 files now uncovered.

4731 of 8399 relevant lines covered (56.33%)

50.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/database/testing/testing.go
1
// Package testing has the database tests.
2
// All database drivers must pass the Test function.
3
// This lives in it's own package so it stays a test dependency.
4
package testing
5

6
import (
7
        "bytes"
8
        "context"
9
        "errors"
10
        "fmt"
11
        "io"
12
        "testing"
13
        "time"
14

15
        "github.com/golang-migrate/migrate/v4/database"
16
)
17

18
// Test runs tests against database implementations.
19
func Test(t *testing.T, d database.Driver, migration []byte) {
×
20
        if migration == nil {
×
21
                t.Fatal("test must provide migration reader")
×
22
        }
×
23

24
        TestNilVersion(t, d) // test first
×
25
        TestLockAndUnlock(t, d)
×
26
        TestRun(t, d, bytes.NewReader(migration))
×
27
        TestSetVersion(t, d) // also tests Version()
×
28
        // Drop breaks the driver, so test it last.
×
29
        TestDrop(t, d)
×
30
}
31

32
func TestNilVersion(t *testing.T, d database.Driver) {
×
NEW
33
        v, _, err := d.Version(context.Background())
×
34
        if err != nil {
×
35
                t.Fatal(err)
×
36
        }
×
37
        if v != database.NilVersion {
×
38
                t.Fatalf("Version: expected version to be NilVersion (-1), got %v", v)
×
39
        }
×
40
}
41

42
func TestLockAndUnlock(t *testing.T, d database.Driver) {
×
43
        // add a timeout, in case there is a deadlock
×
44
        done := make(chan struct{})
×
45
        errs := make(chan error)
×
46

×
47
        go func() {
×
48
                timeout := time.After(15 * time.Second)
×
49
                for {
×
50
                        select {
×
51
                        case <-done:
×
52
                                return
×
53
                        case <-timeout:
×
54
                                errs <- fmt.Errorf("timeout after 15 seconds, looks like a deadlock in Lock/UnLock\n%#v", d)
×
55
                                return
×
56
                        }
57
                }
58
        }()
59

60
        // run the locking test ...
NEW
61
        ctx := context.Background()
×
62
        go func() {
×
NEW
63
                if err := d.Lock(ctx); err != nil {
×
64
                        errs <- err
×
65
                        return
×
66
                }
×
67

68
                // try to acquire lock again
NEW
69
                if err := d.Lock(ctx); err == nil {
×
70
                        errs <- errors.New("lock: expected err not to be nil")
×
71
                        return
×
72
                }
×
73

74
                // unlock
NEW
75
                if err := d.Unlock(ctx); err != nil {
×
76
                        errs <- err
×
77
                        return
×
78
                }
×
79

80
                // try to lock
NEW
81
                if err := d.Lock(ctx); err != nil {
×
82
                        errs <- err
×
83
                        return
×
84
                }
×
NEW
85
                if err := d.Unlock(ctx); err != nil {
×
86
                        errs <- err
×
87
                        return
×
88
                }
×
89
                // notify everyone
90
                close(done)
×
91
        }()
92

93
        // wait for done or any error
94
        for {
×
95
                select {
×
96
                case <-done:
×
97
                        return
×
98
                case err := <-errs:
×
99
                        t.Fatal(err)
×
100
                }
101
        }
102
}
103

104
func TestRun(t *testing.T, d database.Driver, migration io.Reader) {
×
105
        if migration == nil {
×
106
                t.Fatal("migration can't be nil")
×
107
        }
×
108

NEW
109
        if err := d.Run(context.Background(), migration); err != nil {
×
110
                t.Fatal(err)
×
111
        }
×
112
}
113

114
func TestDrop(t *testing.T, d database.Driver) {
×
NEW
115
        if err := d.Drop(context.Background()); err != nil {
×
116
                t.Fatal(err)
×
117
        }
×
118
}
119

120
func TestSetVersion(t *testing.T, d database.Driver) {
×
121
        testCases := []struct {
×
122
                name            string
×
123
                version         int
×
124
                dirty           bool
×
125
                expectedErr     error
×
126
                expectedReadErr error
×
127
                expectedVersion int
×
128
                expectedDirty   bool
×
129
        }{
×
130
                {name: "set 1 dirty", version: 1, dirty: true, expectedErr: nil, expectedReadErr: nil, expectedVersion: 1, expectedDirty: true},
×
131
                {name: "re-set 1 dirty", version: 1, dirty: true, expectedErr: nil, expectedReadErr: nil, expectedVersion: 1, expectedDirty: true},
×
132
                {name: "set 2 clean", version: 2, dirty: false, expectedErr: nil, expectedReadErr: nil, expectedVersion: 2, expectedDirty: false},
×
133
                {name: "re-set 2 clean", version: 2, dirty: false, expectedErr: nil, expectedReadErr: nil, expectedVersion: 2, expectedDirty: false},
×
134
                {name: "last migration dirty", version: database.NilVersion, dirty: true, expectedErr: nil, expectedReadErr: nil, expectedVersion: database.NilVersion, expectedDirty: true},
×
135
                {name: "last migration clean", version: database.NilVersion, dirty: false, expectedErr: nil, expectedReadErr: nil, expectedVersion: database.NilVersion, expectedDirty: false},
×
136
        }
×
137

×
138
        for _, tc := range testCases {
×
139
                t.Run(tc.name, func(t *testing.T) {
×
NEW
140
                        err := d.SetVersion(context.Background(), tc.version, tc.dirty)
×
141
                        if err != tc.expectedErr {
×
142
                                t.Fatal("Got unexpected error:", err, "!=", tc.expectedErr)
×
143
                        }
×
NEW
144
                        v, dirty, readErr := d.Version(context.Background())
×
145
                        if readErr != tc.expectedReadErr {
×
146
                                t.Fatal("Got unexpected error:", readErr, "!=", tc.expectedReadErr)
×
147
                        }
×
148
                        if v != tc.expectedVersion {
×
149
                                t.Error("Got unexpected version:", v, "!=", tc.expectedVersion)
×
150
                        }
×
151
                        if dirty != tc.expectedDirty {
×
152
                                t.Error("Got unexpected dirty value:", dirty, "!=", tc.dirty)
×
153
                        }
×
154
                })
155
        }
156
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc