Skip to content

Commit 2a5889f

Browse files
authored
Merge pull request #151 from darwish/master
adds missing lock around e.fulfilled() in ExpectationsWereMet()
2 parents f7b0b93 + e671f17 commit 2a5889f

File tree

2 files changed

+55
-1
lines changed

2 files changed

+55
-1
lines changed

sqlmock.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,11 @@ func (c *sqlmock) Close() error {
166166

167167
func (c *sqlmock) ExpectationsWereMet() error {
168168
for _, e := range c.expected {
169-
if !e.fulfilled() {
169+
e.Lock()
170+
fulfilled := e.fulfilled()
171+
e.Unlock()
172+
173+
if !fulfilled {
170174
return fmt.Errorf("there is a remaining expectation which was not matched: %s", e)
171175
}
172176

sqlmock_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,3 +1167,53 @@ func TestNewRows(t *testing.T) {
11671167
t.Errorf("expecting to create a row with columns %v, actual colmns are %v", r.cols, columns)
11681168
}
11691169
}
1170+
1171+
// This is actually a test of ExpectationsWereMet. Without a lock around e.fulfilled() inside
1172+
// ExpectationWereMet, the race detector complains if e.triggered is being read while it is also
1173+
// being written by the query running in another goroutine.
1174+
func TestQueryWithTimeout(t *testing.T) {
1175+
db, mock, err := New()
1176+
if err != nil {
1177+
t.Errorf("an error '%s' was not expected when opening a stub database connection", err)
1178+
}
1179+
defer db.Close()
1180+
1181+
rs := NewRows([]string{"id", "title"}).FromCSVString("5,hello world")
1182+
1183+
mock.ExpectQuery("SELECT (.+) FROM articles WHERE id = ?").
1184+
WillDelayFor(15 * time.Millisecond). // Query will take longer than timeout
1185+
WithArgs(5).
1186+
WillReturnRows(rs)
1187+
1188+
_, err = queryWithTimeout(10*time.Millisecond, db, "SELECT (.+) FROM articles WHERE id = ?", 5)
1189+
if err == nil {
1190+
t.Errorf("expecting query to time out")
1191+
}
1192+
1193+
if err := mock.ExpectationsWereMet(); err != nil {
1194+
t.Errorf("there were unfulfilled expectations: %s", err)
1195+
}
1196+
}
1197+
1198+
func queryWithTimeout(t time.Duration, db *sql.DB, query string, args ...interface{}) (*sql.Rows, error) {
1199+
rowsChan := make(chan *sql.Rows, 1)
1200+
errChan := make(chan error, 1)
1201+
1202+
go func() {
1203+
rows, err := db.Query(query, args...)
1204+
if err != nil {
1205+
errChan <- err
1206+
return
1207+
}
1208+
rowsChan <- rows
1209+
}()
1210+
1211+
select {
1212+
case rows := <-rowsChan:
1213+
return rows, nil
1214+
case err := <-errChan:
1215+
return nil, err
1216+
case <-time.After(t):
1217+
return nil, fmt.Errorf("query timed out after %v", t)
1218+
}
1219+
}

0 commit comments

Comments
 (0)