Skip to content

Commit 98631d1

Browse files
authored
Merge pull request src-d#246 from kamichidu/fix-leaking
refs src-d#245 add test to check connection leaking
2 parents 0f81f1a + c4daf22 commit 98631d1

File tree

4 files changed

+97
-0
lines changed

4 files changed

+97
-0
lines changed

store.go

+1
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ func (s *Store) Reload(schema Schema, record Record) error {
439439
if err != nil {
440440
return err
441441
}
442+
defer rows.Close()
442443

443444
rs := NewResultSet(rows, false, nil, columns...)
444445
if !rs.Next() {

tests/common_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ type BaseTestSuite struct {
2222
db *sql.DB
2323
schemas []string
2424
tables []string
25+
26+
// the count of opened connections.
27+
// this will be set in the SetupTest function.
28+
openConnectionsBeforeTest int
2529
}
2630

2731
func NewBaseSuite(schemas []string, tables ...string) BaseTestSuite {
@@ -41,6 +45,11 @@ func (s *BaseTestSuite) SetupSuite() {
4145
panic(fmt.Sprintf("It was unable to connect to the DB.\n%s\n", err))
4246
}
4347

48+
// set all connections will be closed immediately.
49+
// this is required to check connections are leaked or not.
50+
// because database/sql keep connection in the pool by default.
51+
db.SetMaxIdleConns(0)
52+
4453
s.db = db
4554
}
4655

@@ -49,6 +58,9 @@ func (s *BaseTestSuite) TearDownSuite() {
4958
}
5059

5160
func (s *BaseTestSuite) SetupTest() {
61+
// save current open connection count for detecting that connection was leaked while a test.
62+
s.openConnectionsBeforeTest = s.db.Stats().OpenConnections
63+
5264
if len(s.tables) == 0 {
5365
return
5466
}
@@ -57,6 +69,12 @@ func (s *BaseTestSuite) SetupTest() {
5769
}
5870

5971
func (s *BaseTestSuite) TearDownTest() {
72+
openConnections := s.db.Stats().OpenConnections
73+
leakedConnections := openConnections - s.openConnectionsBeforeTest
74+
if leakedConnections > 0 {
75+
s.Fail(fmt.Sprintf("%d database connections were leaked", leakedConnections))
76+
}
77+
6078
if len(s.tables) == 0 {
6179
return
6280
}
@@ -113,6 +131,24 @@ func (s *BaseTestSuite) resultOrError(res interface{}, err error) bool {
113131
return true
114132
}
115133

134+
func (s *BaseTestSuite) resultsOrError(res interface{}, err error) bool {
135+
if reflect.ValueOf(res).Kind() != reflect.Slice {
136+
panic("resultsOrError expects res is a slice")
137+
}
138+
139+
if err == nil && res == nil {
140+
s.Fail("FindAll should return an error or a documents, but nothing was returned")
141+
return false
142+
}
143+
144+
if err != nil && res != nil {
145+
s.Fail("FindAll should return only an error or a documents, but it was returned both")
146+
return false
147+
}
148+
149+
return true
150+
}
151+
116152
func envOrDefault(key string, def string) string {
117153
v := os.Getenv(key)
118154
if v == "" {

tests/resultset_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ func (s *ResulsetSuite) TestResultSetForEachError() {
128128

129129
s.NotPanics(func() {
130130
rs := store.MustFind(NewResultSetFixtureQuery())
131+
defer rs.Close()
131132
err := rs.ForEach(func(*ResultSetFixture) error {
132133
return fail
133134
})

tests/store_test.go

+59
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func (s *StoreSuite) TestStoreMustFind() {
8989
query := NewStoreFixtureQuery()
9090
s.NotPanics(func() {
9191
rs := store.MustFind(query)
92+
defer rs.Close()
9293
s.NotNil(rs)
9394
})
9495
}
@@ -111,6 +112,64 @@ func (s *StoreSuite) TestStoreFindOneReturnValues() {
111112
s.resultOrError(doc, err)
112113
}
113114

115+
func (s *StoreSuite) TestStoreFindAllReturnValues() {
116+
store := NewStoreWithConstructFixtureStore(s.db)
117+
s.Nil(store.Insert(NewStoreWithConstructFixture("foo")))
118+
s.Nil(store.Insert(NewStoreWithConstructFixture("bar")))
119+
120+
notFoundQuery := NewStoreWithConstructFixtureQuery()
121+
notFoundQuery.Where(kallax.Eq(Schema.ResultSetFixture.ID, kallax.NewULID()))
122+
docs, err := store.FindAll(notFoundQuery)
123+
s.resultsOrError(docs, err)
124+
s.NotPanics(func() {
125+
s.Equal(0, len(docs))
126+
})
127+
128+
docs, err = store.FindAll(NewStoreWithConstructFixtureQuery().Order(kallax.Asc(Schema.StoreWithConstructFixture.Foo)))
129+
s.resultsOrError(docs, err)
130+
s.NotPanics(func() {
131+
s.Equal(2, len(docs))
132+
s.Equal("bar", docs[0].Foo)
133+
s.Equal("foo", docs[1].Foo)
134+
})
135+
}
136+
137+
func (s *StoreSuite) TestStoreCount() {
138+
store := NewStoreWithConstructFixtureStore(s.db)
139+
s.Nil(store.Insert(NewStoreWithConstructFixture("foo")))
140+
s.Nil(store.Insert(NewStoreWithConstructFixture("bar")))
141+
142+
notFoundQuery := NewStoreWithConstructFixtureQuery()
143+
notFoundQuery.Where(kallax.Eq(Schema.ResultSetFixture.ID, kallax.NewULID()))
144+
count, err := store.Count(notFoundQuery)
145+
s.Nil(err)
146+
s.NotPanics(func() {
147+
s.Equal(int64(0), count)
148+
})
149+
150+
count, err = store.Count(NewStoreWithConstructFixtureQuery())
151+
s.Nil(err)
152+
s.NotPanics(func() {
153+
s.Equal(int64(2), count)
154+
})
155+
}
156+
157+
func (s *StoreSuite) TestStoreReload() {
158+
store := NewStoreWithConstructFixtureStore(s.db)
159+
s.Nil(store.Insert(NewStoreWithConstructFixture("bar")))
160+
161+
doc, err := store.FindOne(NewStoreWithConstructFixtureQuery().FindByFoo("bar").Select(Schema.StoreWithConstructFixture.ID))
162+
s.Nil(err)
163+
s.NotPanics(func() {
164+
s.Equal("", doc.Foo)
165+
})
166+
err = store.Reload(doc)
167+
s.Nil(err)
168+
s.NotPanics(func() {
169+
s.Equal("bar", doc.Foo)
170+
})
171+
}
172+
114173
func (s *StoreSuite) TestStoreInsertUpdateMustFind() {
115174
store := NewStoreWithConstructFixtureStore(s.db)
116175

0 commit comments

Comments
 (0)