diff --git a/pkg/index/sqlite/sqlite.go b/pkg/index/sqlite/sqlite.go index 3c54438ad..95397d9a7 100644 --- a/pkg/index/sqlite/sqlite.go +++ b/pkg/index/sqlite/sqlite.go @@ -64,7 +64,6 @@ func NewStorage(file string) (index.Storage, error) { if err != nil { return nil, err } - // TODO(bradfitz): ping db, check that it's reachable. return &storage{ file: file, db: db, diff --git a/pkg/index/sqlite/sqlite_test.go b/pkg/index/sqlite/sqlite_test.go index 2c0e584d2..bf9f7b2b0 100644 --- a/pkg/index/sqlite/sqlite_test.go +++ b/pkg/index/sqlite/sqlite_test.go @@ -45,28 +45,45 @@ func do(db *sql.DB, sql string) { panic(fmt.Sprintf("Error %v running SQL: %s", err, sql)) } -type sqliteTester struct{} - -func (sqliteTester) test(t *testing.T, tfn func(*testing.T, func() *index.Index)) { +func makeStorage(t *testing.T) (s index.Storage, clean func()) { f, err := ioutil.TempFile("", "sqlite-test") if err != nil { t.Fatal(err) } - defer os.Remove(f.Name()) + clean = func() { + os.Remove(f.Name()) + } + db, err := sql.Open("sqlite3", f.Name()) + if err != nil { + t.Fatalf("opening test database: %v", err) + } + for _, tableSql := range sqlite.SQLCreateTables() { + do(db, tableSql) + } + do(db, fmt.Sprintf(`REPLACE INTO meta VALUES ('version', '%d')`, sqlite.SchemaVersion())) + s, err = sqlite.NewStorage(f.Name()) + if err != nil { + panic(err) + } + return s, clean +} + +type sqliteTester struct{} + +func (sqliteTester) test(t *testing.T, tfn func(*testing.T, func() *index.Index)) { + var mu sync.Mutex // guards cleanups + var cleanups []func() + defer func() { + mu.Lock() // never unlocked + for _, fn := range cleanups { + fn() + } + }() makeIndex := func() *index.Index { - db, err := sql.Open("sqlite3", f.Name()) - if err != nil { - t.Fatalf("opening test database: %v", err) - return nil - } - for _, tableSql := range sqlite.SQLCreateTables() { - do(db, tableSql) - } - do(db, fmt.Sprintf(`REPLACE INTO meta VALUES ('version', '%d')`, sqlite.SchemaVersion())) - s, err := sqlite.NewStorage(f.Name()) - if err != nil { - panic(err) - } + s, cleanup := makeStorage(t) + mu.Lock() + cleanups = append(cleanups, cleanup) + mu.Unlock() return index.New(s) } tfn(t, makeIndex) @@ -87,3 +104,27 @@ func TestFiles_SQLite(t *testing.T) { func TestEdgesTo_SQLite(t *testing.T) { sqliteTester{}.test(t, indextest.EdgesTo) } + +func TestConcurrency(t *testing.T) { + t.Logf("skipping; fails. http://camlistore.org/issue/114") + return + + s, clean := makeStorage(t) + defer clean() + const n = 100 + ch := make(chan error) + for i := 0; i < n; i++ { + i := i + go func() { + bm := s.BeginBatch() + bm.Set("keyA-" + fmt.Sprint(i), fmt.Sprintf("valA=%d", i)) + bm.Set("keyB-" + fmt.Sprint(i), fmt.Sprintf("valB=%d", i)) + ch <- s.CommitBatch(bm) + }() + } + for i := 0; i < n; i++ { + if err := <-ch; err != nil { + t.Errorf("%d: %v", i, err) + } + } +}