func createTestServerContext() (*server.Context, *CommandFilters) { ctx := server.NewTestContext() var cmdFilters CommandFilters cmdFilters.AppendFilter(checkEndTransactionTrigger, true) ctx.TestingKnobs.StoreTestingKnobs.TestingCommandFilter = cmdFilters.runFilters return ctx, &cmdFilters }
// benchmarkSelect1 is a benchmark of the simplest SQL query: SELECT 1. This // query requires no tables, expression analysis, etc. As such, it is measuring // the overhead of parsing and other non-table processing (e.g. reading // requests, writing responses). func benchmarkSelect1(b *testing.B, scheme string) { s := &server.TestServer{} s.Ctx = server.NewTestContext() s.Ctx.Insecure = (scheme == "http" || scheme == "rpc") if err := s.Start(); err != nil { b.Fatal(err) } defer s.Stop() db, err := sql.Open("cockroach", scheme+"://node@"+s.ServingAddr()+"?certs="+s.Ctx.Certs) if err != nil { b.Fatal(err) } defer db.Close() b.ResetTimer() for i := 0; i < b.N; i++ { rows, err := db.Query(`SELECT 1`) if err != nil { b.Fatal(err) } rows.Close() } b.StopTimer() }
func TestProtocols(t *testing.T) { defer leaktest.AfterTest(t) // Test that all of the network protocols work. for _, scheme := range []string{"http", "https", "rpc", "rpcs"} { func() { // Start test server in insecure mode. s := &server.TestServer{} s.Ctx = server.NewTestContext() s.Ctx.Insecure = (scheme == "http" || scheme == "rpc") if err := s.Start(); err != nil { t.Fatalf("Could not start server: %v", err) } defer s.Stop() db, err := sql.Open("cockroach", scheme+"://node@"+s.ServingAddr()+"?certs="+s.Ctx.Certs) if err != nil { t.Fatal(err) } defer db.Close() if _, err := db.Exec(`SELECT 1`); err != nil { t.Fatal(err) } }() } }
func ExampleDB_Put_insecure() { s := &server.TestServer{} s.Ctx = server.NewTestContext() s.Ctx.Insecure = true if pErr := s.Start(); pErr != nil { log.Fatalf("Could not start server: %v", pErr) } defer s.Stop() db, err := client.Open(s.Stopper(), "rpc://foo@"+s.ServingAddr()) if err != nil { log.Fatal(err) } if pErr := db.Put("aa", "1"); pErr != nil { panic(pErr) } result, pErr := db.Get("aa") if pErr != nil { panic(pErr) } fmt.Printf("aa=%s\n", result.ValueBytes()) // Output: // aa=1 }
func ExampleDB_Insecure() { s := &server.TestServer{} s.Ctx = server.NewTestContext() s.Ctx.Insecure = true if err := s.Start(); err != nil { log.Fatalf("Could not start server: %v", err) } log.Printf("Test server listening on %s: %s", s.Ctx.RequestScheme(), s.ServingAddr()) defer s.Stop() db, err := client.Open("http://root@" + s.ServingAddr()) if err != nil { log.Fatal(err) } if err := db.Put("aa", "1"); err != nil { panic(err) } result, err := db.Get("aa") if err != nil { panic(err) } fmt.Printf("aa=%s\n", result.ValueBytes()) // Output: // aa=1 }
func (t *parallelTest) setup() { ctx := server.NewTestContext() ctx.MaxOffset = logicMaxOffset ctx.TestingKnobs.ExecutorTestingKnobs.WaitForGossipUpdate = true ctx.TestingKnobs.ExecutorTestingKnobs.CheckStmtStringChange = true t.srv = setupTestServerWithContext(t.T, ctx) }
func TestInsecure(t *testing.T) { defer leaktest.AfterTest(t) // Start test server in insecure mode. s := &server.TestServer{} s.Ctx = server.NewTestContext() s.Ctx.Insecure = true if err := s.Start(); err != nil { t.Fatalf("Could not start server: %v", err) } t.Logf("Test server listening on %s: %s", s.Ctx.RequestScheme(), s.ServingAddr()) defer s.Stop() // We can't attempt a connection through HTTPS since the client just retries forever. // DB connection using plain HTTP. db, err := sql.Open("cockroach", "http://root@"+s.ServingAddr()) if err != nil { t.Fatal(err) } defer func() { _ = db.Close() }() if _, err := db.Exec(`SELECT 1`); err != nil { t.Fatal(err) } }
func createTestServerContext() (*server.Context, *CommandFilters) { ctx := server.NewTestContext() var cmdFilters CommandFilters cmdFilters.AppendFilter(checkEndTransactionTrigger, true) // Disable one phase commits as they otherwise confuse the // various bits of machinery in sql tests which inject via // the testing command filter and inspect the transaction. ctx.TestingKnobs.StoreTestingKnobs.DisableOnePhaseCommits = true ctx.TestingKnobs.StoreTestingKnobs.TestingCommandFilter = cmdFilters.runFilters return ctx, &cmdFilters }
func (t *parallelTest) run(dir string) { fmt.Printf("Running test %s\n", dir) // Set up database defer t.close() ctx := server.NewTestContext() ctx.MaxOffset = logicMaxOffset t.srv = setupTestServer(t.T) // Add the main client and set up the database. t.addClient(true) // Open the main faile. mainFile := filepath.Join(dir, "main") file, err := os.Open(mainFile) if err != nil { t.Fatal(err) } defer file.Close() s := newLineScanner(file) for s.Scan() { fields := strings.Fields(s.Text()) if len(fields) == 0 { continue } cmd := fields[0] if strings.HasPrefix(cmd, "#") { // Skip comment lines. continue } switch cmd { case "run": testFiles := fields[1:] for len(t.clients) < len(testFiles) { t.addClient(false) } if testing.Verbose() || log.V(1) { fmt.Printf("%s:%d: running %s\n", mainFile, s.line, strings.Join(testFiles, ",")) } ch := make(chan bool) for i, f := range testFiles { go t.processTestFile(filepath.Join(dir, f), t.clients[i].db, ch) } // Wait for all clients to complete. for range testFiles { <-ch } default: t.Fatalf("%s:%d: unknown command: %s", mainFile, s.line, cmd) } } }
func TestLeaseManagerReacquire(testingT *testing.T) { defer leaktest.AfterTest(testingT)() t := newLeaseTest(testingT, server.NewTestContext()) defer t.cleanup() const descID = keys.LeaseTableID // Acquire 2 leases from the same node. They should point to the same lease // structure. l1 := t.mustAcquire(1, descID, 0) l2 := t.mustAcquire(1, descID, 0) if l1 != l2 { t.Fatalf("expected same lease, but found %p != %p", l1, l2) } if l1.Refcount() != 2 { t.Fatalf("expected refcount of 2, but found %d", l1.Refcount()) } t.expectLeases(descID, "/1/1") // Set the minimum lease duration such that the next lease acquisition will // require the lease to be reacquired. savedLeaseDuration, savedMinLeaseDuration := csql.LeaseDuration, csql.MinLeaseDuration defer func() { csql.LeaseDuration, csql.MinLeaseDuration = savedLeaseDuration, savedMinLeaseDuration }() csql.MinLeaseDuration = l1.Expiration().Sub(timeutil.Now()) csql.LeaseDuration = 2 * csql.MinLeaseDuration // Another lease acquisition from the same node will result in a new lease. l3 := t.mustAcquire(1, descID, 0) if l1 == l3 { t.Fatalf("expected different leases, but found %p", l1) } if l3.Refcount() != 1 { t.Fatalf("expected refcount of 1, but found %d", l3.Refcount()) } if l3.Expiration().Before(l1.Expiration()) { t.Fatalf("expected new lease expiration (%s) to be after old lease expiration (%s)", l3.Expiration(), l1.Expiration()) } t.expectLeases(descID, "/1/1 /1/1") t.mustRelease(1, l1) t.mustRelease(1, l2) t.mustRelease(1, l3) }
// benchmarkSelect1 is a benchmark of the simplest SQL query: SELECT 1. This // query requires no tables, expression analysis, etc. As such, it is measuring // the overhead of parsing and other non-table processing (e.g. reading // requests, writing responses). func benchmarkSelect1(b *testing.B, scheme string) { s := &server.TestServer{} s.Ctx = server.NewTestContext() s.Ctx.Insecure = (scheme == "http" || scheme == "rpc") if err := s.Start(); err != nil { b.Fatal(err) } defer s.Stop() db, err := sql.Open("cockroach", scheme+"://node@"+s.ServingAddr()+"?certs="+s.Ctx.Certs) if err != nil { b.Fatal(err) } defer db.Close() runBenchmarkSelect1(b, db) }
func (t *logicTest) setup() { // TODO(pmattis): Add a flag to make it easy to run the tests against a local // MySQL or Postgres instance. ctx := server.NewTestContext() ctx.MaxOffset = logicMaxOffset t.srv = setupTestServerWithContext(t.T, ctx) // db may change over the lifetime of this function, with intermediate // values cached in t.clients and finally closed in t.close(). t.cleanupRootUser = t.setUser(security.RootUser) if _, err := t.db.Exec(` CREATE DATABASE test; SET DATABASE = test; `); err != nil { t.Fatal(err) } }
// Test that if there's an error on COMMIT that needs to be reported to the user // the txn will be rolled back. As opposed to an error on a COMMIT in an auto-retry // txn, where we retry the txn (not tested here). func TestErrorOnCommit(t *testing.T) { defer leaktest.AfterTest(t)() ctx := server.NewTestContext() ctx.TestingKnobs.SQLExecutor = &sql.ExecutorTestingKnobs{FixTxnPriority: true} server, sqlDB, _ := setupWithContext(t, ctx) defer cleanup(server, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (k INT PRIMARY KEY, v TEXT); `); err != nil { t.Fatal(err) } tx, err := sqlDB.Begin() if err != nil { t.Fatal(err) } if _, err := tx.Exec("SAVEPOINT cockroach_restart; SET TRANSACTION PRIORITY LOW;"); err != nil { t.Fatal(err) } if _, err = tx.Exec("INSERT INTO t.test (k, v) VALUES (0, 'sentinel');"); err != nil { t.Fatal(err) } abortTxn(t, sqlDB, 0) if err = tx.Commit(); err == nil { t.Fatal("expected commit to fail") } // Check that there's no error reading and we don't see any rows. var rows *gosql.Rows if rows, err = sqlDB.Query("SELECT * FROM t.test"); err != nil { t.Fatal(err) } if rows.Next() { var k int var v string _ = rows.Scan(&k, &v) t.Fatalf("found unexpected row: %d %s", k, v) } rows.Close() }
func Example_insecure() { c := cliTest{} c.TestServer = &server.TestServer{} c.Ctx = server.NewTestContext() c.Ctx.Insecure = true if err := c.Start(); err != nil { log.Fatalf("Could not start server: %v", err) } defer c.Stop() c.Run("kv --insecure put a 1 b 2") c.Run("kv --insecure scan") // Output: // kv --insecure put a 1 b 2 // kv --insecure scan // "a" "1" // "b" "2" // 2 result(s) }
func Example_insecure() { c := cliTest{cleanupFunc: func() {}} c.TestServer = &server.TestServer{} c.Ctx = server.NewTestContext() c.Ctx.Insecure = true if err := c.Start(); err != nil { log.Fatalf("Could not start server: %v", err) } defer c.stop() c.Run("debug kv put --insecure a 1 b 2") c.Run("debug kv scan --insecure") // Output: // debug kv put --insecure a 1 b 2 // debug kv scan --insecure // "a" "1" // "b" "2" // 2 result(s) }
func Example_insecure() { c := cliTest{} c.TestServer = &server.TestServer{} c.Ctx = server.NewTestContext() c.Ctx.Insecure = true if err := c.Start(); err != nil { log.Fatalf("Could not start server: %v", err) } c.Run("kv --insecure put a 1 b 2") c.Run("kv --insecure scan") c.Run("quit --insecure") // Output: // kv --insecure put a 1 b 2 // kv --insecure scan // "a" "1" // "b" "2" // quit --insecure // node drained and shutdown: ok }
func ExampleDB_Put_insecure() { s := &server.TestServer{} s.Ctx = server.NewTestContext() s.Ctx.Insecure = true if pErr := s.Start(); pErr != nil { log.Fatalf("Could not start server: %v", pErr) } defer s.Stop() db := s.DB() if pErr := db.Put("aa", "1"); pErr != nil { panic(pErr) } result, pErr := db.Get("aa") if pErr != nil { panic(pErr) } fmt.Printf("aa=%s\n", result.ValueBytes()) // Output: // aa=1 }
func TestLeaseManagerPublishVersionChanged(testingT *testing.T) { defer leaktest.AfterTest(testingT)() t := newLeaseTest(testingT, server.NewTestContext()) defer t.cleanup() const descID = keys.LeaseTableID // Start two goroutines that are concurrently trying to publish a new version // of the descriptor. The first goroutine progresses to the update function // and then signals the second goroutine to start which is allowed to proceed // through completion. The first goroutine is then signaled and when it // attempts to publish the new version it will encounter an update error and // retry the transaction. Upon retry it will see that the descriptor version // has changed and have to proceed to its outer retry loop and wait for the // number of leases on the previous version to drop to 0. n1 := t.node(1) n2 := t.node(2) n1update := make(chan struct{}) n2start := make(chan struct{}) var wg sync.WaitGroup wg.Add(2) go func(n1update, n2start chan struct{}) { _, err := n1.Publish(descID, func(*sqlbase.TableDescriptor) error { if n2start != nil { // Signal node 2 to start. close(n2start) n2start = nil } // Wait for node 2 signal indicating that node 2 finished publication of // a new version. <-n1update return nil }) if err != nil { panic(err) } wg.Done() }(n1update, n2start) go func(n1update, n2start chan struct{}) { // Wait for node 1 signal indicating that node 1 is in its update() // function. <-n2start _, err := n2.Publish(descID, func(*sqlbase.TableDescriptor) error { return nil }) if err != nil { panic(err) } close(n1update) wg.Done() }(n1update, n2start) wg.Wait() t.mustAcquire(1, descID, 0) t.expectLeases(descID, "/3/1") }
func setupClientBenchData(useSSL bool, numVersions, numKeys int, b *testing.B) ( *server.TestServer, *client.DB) { const cacheSize = 8 << 30 // 8 GB const memtableBudget = 512 << 20 // 512 MB loc := fmt.Sprintf("client_bench_%d_%d", numVersions, numKeys) exists := true if _, err := os.Stat(loc); os.IsNotExist(err) { exists = false } s := &server.TestServer{} s.Ctx = server.NewTestContext() s.SkipBootstrap = exists if !useSSL { s.Ctx.Insecure = true } stopper := stop.NewStopper() s.Ctx.Engines = []engine.Engine{ engine.NewRocksDB(roachpb.Attributes{Attrs: []string{"ssd"}}, loc, cacheSize, memtableBudget, stopper), } if err := s.StartWithStopper(stopper); err != nil { b.Fatal(err) } db, err := client.Open(s.Stopper(), fmt.Sprintf("%s://%s@%s?certs=%s", s.Ctx.RPCRequestScheme(), security.NodeUser, s.ServingAddr(), s.Ctx.Certs)) if err != nil { b.Fatal(err) } if exists { return s, db } rng, _ := randutil.NewPseudoRand() keys := make([]roachpb.Key, numKeys) nvs := make([]int, numKeys) for t := 1; t <= numVersions; t++ { batch := &client.Batch{} for i := 0; i < numKeys; i++ { if t == 1 { keys[i] = roachpb.Key(encoding.EncodeUvarintAscending([]byte("key-"), uint64(i))) nvs[i] = int(rand.Int31n(int32(numVersions)) + 1) } // Only write values if this iteration is less than the random // number of versions chosen for this key. if t <= nvs[i] { batch.Put(roachpb.Key(keys[i]), randutil.RandBytes(rng, valueSize)) } if (i+1)%1000 == 0 { if pErr := db.Run(batch); pErr != nil { b.Fatal(pErr) } batch = &client.Batch{} } } if len(batch.Results) != 0 { if pErr := db.Run(batch); pErr != nil { b.Fatal(pErr) } } } if r, ok := s.Ctx.Engines[0].(*engine.RocksDB); ok { r.CompactRange(engine.NilKey, engine.NilKey) } return s, db }
func setupClientBenchData(useRPC, useSSL bool, numVersions, numKeys int, b *testing.B) ( *server.TestServer, *client.DB) { const cacheSize = 8 << 30 // 8 GB loc := fmt.Sprintf("client_bench_%d_%d", numVersions, numKeys) exists := true if _, err := os.Stat(loc); os.IsNotExist(err) { exists = false } s := &server.TestServer{} s.Ctx = server.NewTestContext() s.Ctx.ExperimentalRPCServer = true s.SkipBootstrap = exists if !useSSL { s.Ctx.Insecure = true } s.Engines = []engine.Engine{engine.NewRocksDB(proto.Attributes{Attrs: []string{"ssd"}}, loc, cacheSize)} if err := s.Start(); err != nil { b.Fatal(err) } var scheme string if useRPC { scheme = "rpcs" } else { scheme = "https" } db, err := client.Open(scheme + "://root@" + s.ServingAddr() + "?certs=" + s.Ctx.Certs) if err != nil { b.Fatal(err) } if exists { return s, db } rng, _ := util.NewPseudoRand() keys := make([]proto.Key, numKeys) nvs := make([]int, numKeys) for t := 1; t <= numVersions; t++ { batch := &client.Batch{} for i := 0; i < numKeys; i++ { if t == 1 { keys[i] = proto.Key(encoding.EncodeUvarint([]byte("key-"), uint64(i))) nvs[i] = int(rand.Int31n(int32(numVersions)) + 1) } // Only write values if this iteration is less than the random // number of versions chosen for this key. if t <= nvs[i] { batch.Put(proto.Key(keys[i]), util.RandBytes(rng, valueSize)) } if (i+1)%1000 == 0 { if err := db.Run(batch); err != nil { b.Fatal(err) } batch = &client.Batch{} } } if len(batch.Results) != 0 { if err := db.Run(batch); err != nil { b.Fatal(err) } } } if r, ok := s.Engines[0].(*engine.RocksDB); ok { r.CompactRange(nil, nil) } return s, db }
func TestPGWire(t *testing.T) { defer leaktest.AfterTest(t) certUser := server.TestUser certPath := security.ClientCertPath(security.EmbeddedCertsDir, certUser) keyPath := security.ClientKeyPath(security.EmbeddedCertsDir, certUser) tempDir, err := ioutil.TempDir("", "TestPGWire") if err != nil { t.Fatal(err) } defer func() { if err := os.RemoveAll(tempDir); err != nil { // Not Fatal() because we might already be panicking. t.Error(err) } }() // Copy these assets to disk from embedded strings, so this test can // run from a standalone binary. tempCertPath := securitytest.RestrictedCopy(t, certPath, tempDir, "cert") tempKeyPath := securitytest.RestrictedCopy(t, keyPath, tempDir, "key") for _, insecure := range [...]bool{true, false} { ctx := server.NewTestContext() ctx.Insecure = insecure s := setupTestServerWithContext(t, ctx) host, port, err := net.SplitHostPort(s.PGAddr()) if err != nil { t.Fatal(err) } basePgUrl := url.URL{ Scheme: "postgres", Host: net.JoinHostPort(host, port), } if err := trivialQuery(basePgUrl); err != nil { if insecure { if err != pq.ErrSSLNotSupported { t.Error(err) } } else { if !testutils.IsError(err, "no client certificates in request") { t.Error(err) } } } { disablePgUrl := basePgUrl disablePgUrl.RawQuery = "sslmode=disable" err := trivialQuery(disablePgUrl) if insecure { if err != nil { t.Error(err) } } else { if !testutils.IsError(err, pgwire.ErrSSLRequired) { t.Error(err) } } } { requirePgUrlNoCert := basePgUrl requirePgUrlNoCert.RawQuery = "sslmode=require" err := trivialQuery(requirePgUrlNoCert) if insecure { if err != pq.ErrSSLNotSupported { t.Error(err) } } else { if !testutils.IsError(err, "no client certificates in request") { t.Error(err) } } } { for _, optUser := range []string{certUser, security.RootUser} { requirePgUrlWithCert := basePgUrl requirePgUrlWithCert.User = url.User(optUser) requirePgUrlWithCert.RawQuery = fmt.Sprintf("sslmode=require&sslcert=%s&sslkey=%s", url.QueryEscape(tempCertPath), url.QueryEscape(tempKeyPath), ) err := trivialQuery(requirePgUrlWithCert) if insecure { if err != pq.ErrSSLNotSupported { t.Error(err) } } else { if optUser == certUser { if err != nil { t.Error(err) } } else { if !testutils.IsError(err, `requested user is \w+, but certificate is for \w+`) { t.Error(err) } } } } } cleanupTestServer(s) } }
func setupTestServer(t *testing.T) *server.TestServer { return setupTestServerWithContext(t, server.NewTestContext()) }
// TestPropagateTxnOnError verifies that DistSender.sendChunk properly // propagates the txn data to a next iteration. Use txn.Writing field to // verify that. func TestPropagateTxnOnError(t *testing.T) { defer leaktest.AfterTest(t)() // Set up a filter to so that the first CPut operation will // get a ReadWithinUncertaintyIntervalError. targetKey := roachpb.Key("b") var numGets int32 ctx := server.NewTestContext() ctx.TestingKnobs.StoreTestingKnobs.TestingCommandFilter = func(fArgs storageutils.FilterArgs) *roachpb.Error { _, ok := fArgs.Req.(*roachpb.ConditionalPutRequest) if ok && fArgs.Req.Header().Key.Equal(targetKey) { if atomic.AddInt32(&numGets, 1) == 1 { z := roachpb.ZeroTimestamp pErr := roachpb.NewReadWithinUncertaintyIntervalError(z, z) return roachpb.NewErrorWithTxn(pErr, fArgs.Hdr.Txn) } } return nil } s := server.StartTestServerWithContext(t, ctx) defer s.Stop() db := setupMultipleRanges(t, s, "b") // Set the initial value on the target key "b". origVal := "val" if pErr := db.Put(targetKey, origVal); pErr != nil { t.Fatal(pErr) } // The following txn creates a batch request that is split // into two requests: Put and CPut. The CPut operation will // get a ReadWithinUncertaintyIntervalError and the txn will be // retried. epoch := 0 if pErr := db.Txn(func(txn *client.Txn) *roachpb.Error { epoch++ if epoch >= 2 { // Writing must be true since we ran the BeginTransaction command. if !txn.Proto.Writing { t.Errorf("unexpected non-writing txn") } } else { // Writing must be false since we haven't run any write command. if txn.Proto.Writing { t.Errorf("unexpected writing txn") } } b := txn.NewBatch() b.Put("a", "val") b.CPut(targetKey, "new_val", origVal) pErr := txn.CommitInBatch(b) if epoch == 1 { if _, ok := pErr.GetDetail().(*roachpb.ReadWithinUncertaintyIntervalError); ok { if !pErr.GetTxn().Writing { t.Errorf("unexpected non-writing txn on error") } } else { t.Errorf("expected ReadWithinUncertaintyIntervalError, but got: %s", pErr) } } return pErr }); pErr != nil { t.Errorf("unexpected error on transactional Puts: %s", pErr) } if epoch != 2 { t.Errorf("unexpected epoch; the txn must be retried exactly once, but got %d", epoch) } }
func setup(t *testing.T) (*testServer, *sql.DB, *client.DB) { return setupWithContext(t, server.NewTestContext()) }
// TODO(tschottdorf): some logic tests currently take a long time to run. // Probably a case of heartbeats timing out or many restarts in some tests. // Need to investigate when all moving parts are in place. func (t *logicTest) run(path string) { defer t.close() file, err := os.Open(path) if err != nil { t.Fatal(err) } defer file.Close() t.lastProgress = time.Now() // TODO(pmattis): Add a flag to make it easy to run the tests against a local // MySQL or Postgres instance. ctx := server.NewTestContext() ctx.MaxOffset = logicMaxOffset t.srv = setupTestServer(t.T) // db may change over the lifetime of this function, with intermediate // values cached in t.clients and finally closed in t.close(). cleanupFunc := t.setUser(security.RootUser) defer cleanupFunc() if _, err := t.db.Exec(` CREATE DATABASE test; SET DATABASE = test; `); err != nil { t.Fatal(err) } s := newLineScanner(file) for s.Scan() { fields := strings.Fields(s.Text()) if len(fields) == 0 { continue } cmd := fields[0] if strings.HasPrefix(cmd, "#") { // Skip comment lines. continue } switch cmd { case "statement": stmt := logicStatement{pos: fmt.Sprintf("%s:%d", path, s.line)} // Parse "query error <regexp>" if m := errorRE.FindStringSubmatch(s.Text()); m != nil { stmt.expectErr = m[1] } var buf bytes.Buffer for s.Scan() { line := s.Text() if line == "" { break } fmt.Fprintln(&buf, line) } stmt.sql = strings.TrimSpace(buf.String()) if !s.skip { t.execStatement(stmt) } else { s.skip = false } t.success(path) case "query": query := logicQuery{pos: fmt.Sprintf("%s:%d", path, s.line)} // Parse "query error <regexp>" if m := errorRE.FindStringSubmatch(s.Text()); m != nil { query.expectErr = m[1] } else if len(fields) < 2 { t.Fatalf("%s: invalid test statement: %s", query.pos, s.Text()) } else { // Parse "query <type-string> <sort-mode> <label>" // The type string specifies the number of columns and their types: // - T for text // - I for integer // - R for floating point // - B for boolean // The sort mode is one of: // - "nosort" (default) // - "rowsort" // - "valuesort" // - "colnames" // // The label is optional. If specified, the test runner stores a hash // of the results of the query under the given label. If the label is // reused, the test runner verifies that the results are the // same. This can be used to verify that two or more queries in the // same test script that are logically equivalent always generate the // same output. query.colTypes = fields[1] if len(fields) >= 3 { for _, opt := range strings.Split(fields[2], ",") { switch opt { case "nosort": query.sorter = nil case "rowsort": query.sorter = rowSort case "valuesort": query.sorter = valueSort case "colnames": query.colNames = true default: t.Fatalf("%s: unknown sort mode: %s", query.pos, opt) } } } if len(fields) >= 4 { query.label = fields[3] } } var buf bytes.Buffer for s.Scan() { line := s.Text() if line == "----" { if query.expectErr != "" { t.Fatalf("%s: invalid ---- delimiter after a query expecting an error: %s", query.pos, query.expectErr) } break } if strings.TrimSpace(s.Text()) == "" { break } fmt.Fprintln(&buf, line) } query.sql = strings.TrimSpace(buf.String()) if query.expectErr == "" { // Query results are either a space separated list of values up to a // blank line or a line of the form "xx values hashing to yyy". The // latter format is used by sqllogictest when a large number of results // match the query. if s.Scan() { if m := resultsRE.FindStringSubmatch(s.Text()); m != nil { var err error query.expectedValues, err = strconv.Atoi(m[1]) if err != nil { t.Fatal(err) } query.expectedHash = m[2] } else { for { results := strings.Fields(s.Text()) if len(results) == 0 { break } query.expectedResults = append(query.expectedResults, results...) if !s.Scan() { break } } query.expectedValues = len(query.expectedResults) } } } if !s.skip { t.execQuery(query) } else { s.skip = false } t.success(path) case "halt", "hash-threshold": break case "user": if len(fields) < 2 { t.Fatalf("user command requires one argument, found: %v", fields) } if len(fields[1]) == 0 { t.Fatal("user command requires a non-blank argument") } cleanupUserFunc := t.setUser(fields[1]) defer cleanupUserFunc() case "skipif": if len(fields) < 2 { t.Fatalf("skipif command requires one argument, found: %v", fields) } switch fields[1] { case "": t.Fatal("skipif command requires a non-blank argument") case "mysql": case "postgresql": s.skip = true continue default: t.Fatalf("unimplemented test statement: %s", s.Text()) } case "onlyif": if len(fields) < 2 { t.Fatalf("onlyif command requires one argument, found: %v", fields) } switch fields[1] { case "": t.Fatal("onlyif command requires a non-blank argument") case "mysql": s.skip = true continue default: t.Fatalf("unimplemented test statement: %s", s.Text()) } case "traceon": if len(fields) != 2 { t.Fatalf("traceon requires a filename argument, found: %v", fields) } t.traceStart(fields[1]) case "traceoff": if t.traceFile == nil { t.Fatalf("no trace active") } t.traceStop() default: t.Fatalf("%s:%d: unknown command: %s", path, s.line, cmd) } } if err := s.Err(); err != nil { t.Fatal(err) } t.traceStop() fmt.Printf("%s: %d\n", path, t.progress) }
// getFastScanContext returns a test context with fast scan. func getFastScanContext() *server.Context { c := server.NewTestContext() c.ScanInterval = time.Millisecond c.ScanMaxIdleTime = time.Millisecond return c }
func TestLeaseManager(testingT *testing.T) { defer leaktest.AfterTest(testingT)() t := newLeaseTest(testingT, server.NewTestContext()) defer t.cleanup() const descID = keys.LeaseTableID // We can't acquire a lease on a non-existent table. expected := "descriptor ID 10000 not found" if _, err := t.acquire(1, 10000, 0); !testutils.IsError(err, expected) { t.Fatalf("expected %s, but found %v", expected, err) } l1 := t.mustAcquire(1, descID, 0) t.expectLeases(descID, "/1/1") // Node 2 never acquired a lease on descID, so we should expect an error. if err := t.release(2, l1); err == nil { t.Fatalf("expected error, but found none") } t.mustRelease(1, l1) t.expectLeases(descID, "/1/1") // It is an error to acquire a lease for a specific version that doesn't // exist yet. expected = "version 2 of table .* does not exist" if _, err := t.acquire(1, descID, 2); !testutils.IsError(err, expected) { t.Fatalf("expected %s, but found %v", expected, err) } // Publish a new version and explicitly acquire it. l2 := t.mustAcquire(1, descID, 0) t.mustPublish(1, descID) l3 := t.mustAcquire(1, descID, 2) t.expectLeases(descID, "/1/1 /2/1") // When the last local reference on the new version is released we don't // release the node lease. t.mustRelease(1, l3) t.expectLeases(descID, "/1/1 /2/1") // We can still acquire a local reference on the old version since it hasn't // expired. l4 := t.mustAcquire(1, descID, 1) t.mustRelease(1, l4) t.expectLeases(descID, "/1/1 /2/1") // When the last local reference on the old version is released the node // lease is also released. t.mustRelease(1, l2) t.expectLeases(descID, "/2/1") // It is an error to acquire a lease for an old version once a new version // exists and there are no local references for the old version. expected = "lease.go.*: table .* unable to acquire lease on old version: 1 < 2" if _, err := t.acquire(1, descID, 1); !testutils.IsError(err, expected) { t.Fatalf("expected %s, but found %v", expected, err) } // Acquire 2 node leases on version 2. l5 := t.mustAcquire(1, descID, 2) l6 := t.mustAcquire(2, descID, 2) // Publish version 3. This will succeed immediately. t.mustPublish(3, descID) // Start a goroutine to publish version 4 which will block until the version // 2 leases are released. var wg sync.WaitGroup wg.Add(1) go func() { t.mustPublish(3, descID) wg.Done() }() // Force both nodes ahead to version 3. l7 := t.mustAcquire(1, descID, 3) l8 := t.mustAcquire(2, descID, 3) t.expectLeases(descID, "/2/1 /2/2 /3/1 /3/2") t.mustRelease(1, l5) t.expectLeases(descID, "/2/2 /3/1 /3/2") t.mustRelease(2, l6) t.expectLeases(descID, "/3/1 /3/2") // Wait for version 4 to be published. wg.Wait() l9 := t.mustAcquire(1, descID, 4) t.mustRelease(1, l7) t.mustRelease(2, l8) t.expectLeases(descID, "/3/2 /4/1") t.mustRelease(1, l9) t.expectLeases(descID, "/3/2 /4/1") }