diff --git a/internal/sqladapter/testing/adapter.go.tpl b/internal/sqladapter/testing/adapter.go.tpl index 81774a2c2a526118c31c3281b7d4e85d35da1e83..41150ddfa5b81f94fdaaf83a60d5dc4f7b22d2d9 100644 --- a/internal/sqladapter/testing/adapter.go.tpl +++ b/internal/sqladapter/testing/adapter.go.tpl @@ -72,14 +72,12 @@ func TestOpenMustSucceed(t *testing.T) { assert.NoError(t, err) assert.NotNil(t, sess) - err = sess.Close() - assert.NoError(t, err) + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestPreparedStatementsCache(t *testing.T) { - sess, err := Open(settings) - assert.NoError(t, err) - defer sess.Close() + sess := mustOpen() var tMu sync.Mutex tFatal := func(err error) { @@ -88,19 +86,33 @@ func TestPreparedStatementsCache(t *testing.T) { t.Fatal(err) } + // QL and SQLite don't have the same concurrency capabilities PostgreSQL and + // MySQL have, so they have special limits. + defaultLimit := 1000 + + limits := map[string]int { + "sqlite": 20, + "ql": 20, + } + + limit := limits[Adapter] + if limit < 1 { + limit = defaultLimit + } + // The max number of elements we can have on our LRU is 128, if an statement // is evicted it will be marked as dead and will be closed only when no other // queries are using it. const maxPreparedStatements = 128 * 2 var wg sync.WaitGroup - for i := 0; i < 1000; i++ { + for i := 0; i < limit; i++ { wg.Add(1) go func(i int) { defer wg.Done() // This query is different with each iteration and thus generates a new // prepared statement everytime it's called. - res := sess.Collection("artist").Find().Select(db.Raw(fmt.Sprintf("count(%d)", i))) + res := sess.Collection("artist").Find().Select(db.Raw(fmt.Sprintf("count(%d)", i%200))) var count map[string]uint64 err := res.One(&count) if err != nil { @@ -114,14 +126,36 @@ func TestPreparedStatementsCache(t *testing.T) { wg.Wait() } } + wg.Wait() + for i := 0; i < limit; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + // This query is different with each iteration and thus generates a new + // prepared statement everytime it's called. + _, err := sess.Collection("artist").Insert(artistType{ + Name: fmt.Sprintf("artist-%d", i%200), + }) + if err != nil { + tFatal(err) + } + if activeStatements := sqladapter.NumActiveStatements(); activeStatements > maxPreparedStatements { + tFatal(fmt.Errorf("The number of active statements cannot exceed %d (got %d).", maxPreparedStatements, activeStatements)) + } + }(i) + if i%50 == 0 { + wg.Wait() + } + } wg.Wait() + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestTruncateAllCollections(t *testing.T) { - sess, err := Open(settings) - assert.NoError(t, err) - defer sess.Close() + sess := mustOpen() collections, err := sess.Collections() assert.NoError(t, err) @@ -136,28 +170,31 @@ func TestTruncateAllCollections(t *testing.T) { } } } + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestCustomQueryLogger(t *testing.T) { - sess, err := Open(settings) - assert.NoError(t, err) - defer sess.Close() + sess := mustOpen() db.Conf.SetLogger(&customLogger{}) defer func() { db.Conf.SetLogger(nil) }() - _, err = sess.Collection("artist").Find().Count() + _, err := sess.Collection("artist").Find().Count() assert.Equal(t, nil, err) _, err = sess.Collection("artist_x").Find().Count() assert.NotEqual(t, nil, err) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestExpectCursorError(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") @@ -169,11 +206,13 @@ func TestExpectCursorError(t *testing.T) { var item map[string]interface{} err = res.One(&item) assert.Error(t, err) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestInsertReturning(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") @@ -228,11 +267,13 @@ func TestInsertReturning(t *testing.T) { count, err = artist.Find().Count() assert.NoError(t, err) assert.Equal(t, uint64(2), count, "Expecting 2 elements") + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestInsertReturningWithinTransaction(t *testing.T) { sess := mustOpen() - defer sess.Close() err := sess.Collection("artist").Truncate() assert.NoError(t, err) @@ -300,11 +341,13 @@ func TestInsertReturningWithinTransaction(t *testing.T) { count, err = sess.Collection("artist").Find().Count() assert.NoError(t, err) assert.Equal(t, uint64(0), count, "Expecting 0 elements, everything was rolled back!") + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestInsertIntoArtistsTable(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") @@ -384,20 +427,24 @@ func TestInsertIntoArtistsTable(t *testing.T) { count, err = artist.Find(db.Cond{"name": "Ozzie"}).And(db.Cond{"name": "Flea"}).Count() assert.NoError(t, err) assert.Equal(t, uint64(0), count) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestQueryNonExistentCollection(t *testing.T) { sess := mustOpen() - defer sess.Close() count, err := sess.Collection("doesnotexist").Find().Count() assert.Error(t, err) assert.Zero(t, count) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestGetOneResult(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") @@ -419,11 +466,13 @@ func TestGetOneResult(t *testing.T) { if Adapter != "ql" { assert.NotZero(t, someArtist.ID) } + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestGetResultsOneByOne(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") @@ -483,7 +532,7 @@ func TestGetResultsOneByOne(t *testing.T) { assert.Equal(t, 4, len(allRowsMap)) for _, singleRowMap := range allRowsMap { - if pk, ok := singleRowMap["id"].(int64); !ok || pk == 0 { + if fmt.Sprintf("%d", singleRowMap["id"]) == "0" { t.Fatalf("Expecting a not null ID.") } } @@ -528,11 +577,13 @@ func TestGetResultsOneByOne(t *testing.T) { for _, singleRowStruct := range allRowsStruct2 { assert.NotZero(t, singleRowStruct.Value1) } + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestGetAllResults(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") @@ -562,6 +613,9 @@ func TestGetAllResults(t *testing.T) { assert.NotZero(t, len(artistObjs)) assert.NotZero(t, artistObjs[0].Name) assert.NotZero(t, artistObjs[0].ID) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestInlineStructs(t *testing.T) { @@ -578,7 +632,6 @@ func TestInlineStructs(t *testing.T) { } sess := mustOpen() - defer sess.Close() review := sess.Collection("review") @@ -614,11 +667,13 @@ func TestInlineStructs(t *testing.T) { assert.NoError(t, err) assert.Equal(t, rec, recChk) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestUpdate(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") @@ -742,11 +797,13 @@ func TestUpdate(t *testing.T) { // Verifying assert.Equal(t, value.Name, rowStruct3.Value1) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestFunction(t *testing.T) { sess := mustOpen() - defer sess.Close() rowStruct := struct { ID int64 @@ -805,11 +862,13 @@ func TestFunction(t *testing.T) { total, err = res.Count() assert.NoError(t, err) assert.Equal(t, uint64(4), total) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestNullableFields(t *testing.T) { sess := mustOpen() - defer sess.Close() type testType struct { ID int64 `db:"id,omitempty"` @@ -861,11 +920,13 @@ func TestNullableFields(t *testing.T) { assert.True(t, test.NullInt64Test.Valid) assert.True(t, test.NullBoolTest.Valid) assert.True(t, test.NullStringTest.Valid) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestGroup(t *testing.T) { sess := mustOpen() - defer sess.Close() type statsType struct { Numeric int `db:"numeric"` @@ -897,11 +958,13 @@ func TestGroup(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 5, len(results)) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestDelete(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") res := artist.Find() @@ -916,6 +979,9 @@ func TestDelete(t *testing.T) { total, err = res.Count() assert.NoError(t, err) assert.Equal(t, uint64(0), total) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestCompositeKeys(t *testing.T) { @@ -924,7 +990,6 @@ func TestCompositeKeys(t *testing.T) { } sess := mustOpen() - defer sess.Close() compositeKeys := sess.Collection("composite_keys") @@ -948,6 +1013,9 @@ func TestCompositeKeys(t *testing.T) { assert.NoError(t, err) assert.Equal(t, item2.SomeVal, item.SomeVal) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } // Attempts to test database transactions. @@ -957,7 +1025,6 @@ func TestTransactionsAndRollback(t *testing.T) { } sess := mustOpen() - defer sess.Close() // Simple transaction that should not fail. tx, err := sess.NewTx() @@ -1070,6 +1137,9 @@ func TestTransactionsAndRollback(t *testing.T) { count, err = artist.Find().Count() assert.NoError(t, err) assert.Equal(t, uint64(3), count) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestDataTypes(t *testing.T) { @@ -1104,7 +1174,6 @@ func TestDataTypes(t *testing.T) { } sess := mustOpen() - defer sess.Close() // Getting a pointer to the "data_types" collection. dataTypes := sess.Collection("data_types") @@ -1166,11 +1235,13 @@ func TestDataTypes(t *testing.T) { // The original value and the test subject must match. assert.Equal(t, testValues, item) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestUpdateWithNullColumn(t *testing.T) { sess := mustOpen() - defer sess.Close() artist := sess.Collection("artist") err := artist.Truncate() @@ -1200,11 +1271,13 @@ func TestUpdateWithNullColumn(t *testing.T) { assert.NoError(t, err) assert.Equal(t, (*string)(nil), item2.Name) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestBatchInsert(t *testing.T) { sess := mustOpen() - defer sess.Close() for batchSize := 0; batchSize < 17; batchSize++ { err := sess.Collection("artist").Truncate() @@ -1235,11 +1308,13 @@ func TestBatchInsert(t *testing.T) { assert.Equal(t, uint64(1), c) } } + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestBatchInsertNoColumns(t *testing.T) { sess := mustOpen() - defer sess.Close() for batchSize := 0; batchSize < 17; batchSize++ { err := sess.Collection("artist").Truncate() @@ -1273,6 +1348,9 @@ func TestBatchInsertNoColumns(t *testing.T) { assert.Equal(t, uint64(1), c) } } + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestBatchInsertReturningKeys(t *testing.T) { @@ -1281,7 +1359,6 @@ func TestBatchInsertReturningKeys(t *testing.T) { } sess := mustOpen() - defer sess.Close() err := sess.Collection("artist").Truncate() assert.NoError(t, err) @@ -1322,11 +1399,13 @@ func TestBatchInsertReturningKeys(t *testing.T) { c, err := sess.Collection("artist").Find().Count() assert.NoError(t, err) assert.Equal(t, uint64(totalItems), c) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestBuilder(t *testing.T) { sess := mustOpen() - defer sess.Close() var all []map[string]interface{} @@ -1427,6 +1506,11 @@ func TestBuilder(t *testing.T) { err = q.All(&all) assert.NoError(t, err) assert.NotZero(t, all) + + assert.NoError(t, tx.Commit()) + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) } func TestExhaustConnectionPool(t *testing.T) { @@ -1449,10 +1533,9 @@ func TestExhaustConnectionPool(t *testing.T) { } sess := mustOpen() - defer sess.Close() var wg sync.WaitGroup - for i := 0; i < 300; i++ { + for i := 0; i < 100; i++ { tLogf("Tx %d: Pending", i) wg.Add(1) @@ -1461,7 +1544,7 @@ func TestExhaustConnectionPool(t *testing.T) { // Requesting a new transaction session. start := time.Now() - tLogf("Tx: %d: NewTx") + tLogf("Tx: %d: NewTx", i) tx, err := sess.NewTx() if err != nil { tFatal(err) @@ -1536,4 +1619,7 @@ func TestExhaustConnectionPool(t *testing.T) { } wg.Wait() + + assert.NoError(t, cleanUpCheck(sess)) + assert.NoError(t, sess.Close()) }