@@ -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