func TestBadRequest(t *testing.T) { defer leaktest.AfterTest(t) s := server.StartTestServer(t) db := createTestClient(t, s.Stopper(), s.ServingAddr()) defer s.Stop() // Write key "a". if err := db.Put("a", "value"); err != nil { t.Fatal(err) } if _, err := db.Scan("a", "a", 0); !testutils.IsError(err, "truncation resulted in empty batch") { t.Fatalf("unexpected error on scan with startkey == endkey: %v", err) } if _, err := db.ReverseScan("a", "a", 0); !testutils.IsError(err, "truncation resulted in empty batch") { t.Fatalf("unexpected error on reverse scan with startkey == endkey: %v", err) } if err := db.DelRange("x", "a"); !testutils.IsError(err, "truncation resulted in empty batch") { t.Fatalf("unexpected error on deletion on [x, a): %v", err) } if err := db.DelRange("", "z"); !testutils.IsError(err, "must be greater than LocalMax") { t.Fatalf("unexpected error on deletion on [KeyMin, z): %v", err) } }
// TestRollbackToSavepointStatement tests that issuing a RESTART outside of a // txn produces the proper error. func TestRollbackToSavepointStatement(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, _ := serverutils.StartServer(t, params) defer s.Stopper().Stop() // ROLLBACK TO SAVEPOINT without a transaction _, err := sqlDB.Exec("ROLLBACK TO SAVEPOINT cockroach_restart") if !testutils.IsError(err, "the transaction is not in a retriable state") { t.Fatalf("expected to fail here. err: %v", err) } // ROLLBACK TO SAVEPOINT with a wrong name _, err = sqlDB.Exec("ROLLBACK TO SAVEPOINT foo") if !testutils.IsError(err, "SAVEPOINT not supported except for COCKROACH_RESTART") { t.Fatalf("expected to fail here. err: %v", err) } // ROLLBACK TO SAVEPOINT in a non-retriable transaction tx, err := sqlDB.Begin() if err != nil { t.Fatal(err) } if _, err := tx.Exec("SAVEPOINT cockroach_restart"); err != nil { t.Fatal(err) } if _, err = tx.Exec("BOGUS SQL STATEMENT"); err == nil { t.Fatalf("expected to fail here. err: %v", err) } _, err = tx.Exec("ROLLBACK TO SAVEPOINT cockroach_restart") if !testutils.IsError(err, "SAVEPOINT COCKROACH_RESTART has not been used or a non-retriable error was encountered") { t.Fatalf("expected to fail here. err: %v", err) } }
// Test that rando commands while in COMMIT_WAIT return a particular error. func TestCommitWaitState(t *testing.T) { defer leaktest.AfterTest(t)() params, _ := createTestServerParams() s, sqlDB, _ := serverutils.StartServer(t, params) defer s.Stopper().Stop() 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; RELEASE cockroach_restart;"); err != nil { t.Fatal(err) } _, err = tx.Exec("INSERT INTO t.test (k, v) VALUES (0, 'sentinel');") if !testutils.IsError(err, "current transaction is committed") { t.Fatal(err) } // Rollback should respond with a COMMIT command tag. err = tx.Rollback() if !testutils.IsError(err, "unexpected command tag COMMIT") { t.Fatal(err) } }
// TestRestartStatement tests that issuing a RESTART outside of a txn produces // the proper error. func TestRestartStatement(t *testing.T) { defer leaktest.AfterTest(t)() server, sqlDB, _ := setup(t) defer cleanup(server, sqlDB) // RESTART without a transaction _, err := sqlDB.Exec("RESTART TRANSACTION") if !testutils.IsError(err, "the transaction is not in a retriable state") { t.Fatal("expected to fail here. err: ", err) } // RESTART in a non-retriable transaction tx, err := sqlDB.Begin() if err != nil { t.Fatal(err) } if _, err := tx.Exec("RETRY INTENT"); err != nil { t.Fatal(err) } if _, err = tx.Exec("BOGUS SQL STATEMENT"); err == nil { t.Fatalf("expected to fail here. err: %s", err) } _, err = tx.Exec("RESTART TRANSACTION") if !testutils.IsError(err, "RETRY INTENT has not been used or a non-retriable error was encountered") { t.Fatal("expected to fail here. err: ", err) } }
// Test that rando commands while in COMMIT_WAIT return a particular error. func TestCommitWaitState(t *testing.T) { defer leaktest.AfterTest(t)() server, sqlDB, _ := setup(t) 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("RETRY INTENT; RELEASE;"); err != nil { t.Fatal(err) } _, err = tx.Exec("INSERT INTO t.test (k, v) VALUES (0, 'sentinel');") if !testutils.IsError(err, "current transaction is committed") { t.Fatal(err) } // Rollback should respond with a COMMIT command tag. err = tx.Rollback() if !testutils.IsError(err, "unexpected command tag COMMIT") { t.Fatal(err) } }
// TestBatchError verifies that Range returns an error if a request has an invalid range. func TestBatchError(t *testing.T) { testCases := []struct { req [2]string errMsg string }{ { req: [2]string{"\xff\xff\xff\xff", "a"}, errMsg: "must be less than KeyMax", }, { req: [2]string{"a", "\xff\xff\xff\xff"}, errMsg: "must be less than or equal to KeyMax", }, } for i, c := range testCases { var ba roachpb.BatchRequest ba.Add(&roachpb.ScanRequest{Span: roachpb.Span{Key: roachpb.Key(c.req[0]), EndKey: roachpb.Key(c.req[1])}}) if _, err := Range(ba); !testutils.IsError(err, c.errMsg) { t.Errorf("%d: unexpected error %v", i, err) } } // Test a case where a non-range request has an end key. var ba roachpb.BatchRequest ba.Add(&roachpb.GetRequest{Span: roachpb.Span{Key: roachpb.Key("a"), EndKey: roachpb.Key("b")}}) if _, err := Range(ba); !testutils.IsError(err, "end key specified for non-range operation") { t.Errorf("unexpected error %v", err) } }
func TestApplySnapshotDenyPreemptive(t *testing.T) { defer leaktest.AfterTest(t)() var tc testContext tc.Start(t) defer tc.Stop() key := roachpb.RKey("a") realRng := tc.store.LookupReplica(key, nil) // Use Raft to get a nontrivial term for our snapshot. if pErr := realRng.redirectOnOrAcquireLease(context.Background()); pErr != nil { t.Fatal(pErr) } snap, err := realRng.GetSnapshot() if err != nil { t.Fatal(err) } // Make sure that the Term is behind our first range term (raftInitialLogTerm) snap.Metadata.Term-- // Create an uninitialized version of the first range. This is only ok // because in the case we test, there's an error (and so we don't clobber // our actual first range in the Store). If we want snapshots to apply // successfully during tests, we need to adapt the snapshots to a new // RangeID first and generally do a lot more work. rng, err := NewReplica(&roachpb.RangeDescriptor{RangeID: 1}, tc.store, 0) if err != nil { t.Fatal(err) } if _, err := rng.applySnapshot(snap, raftpb.HardState{}); !testutils.IsError( err, "cannot apply preemptive snapshot from past term", ) { t.Fatal(err) } // Do something that extends the Raft log past what we have in the // snapshot. put := putArgs(roachpb.Key("a"), []byte("foo")) if _, pErr := tc.SendWrapped(&put); pErr != nil { t.Fatal(pErr) } snap.Metadata.Term++ // restore the "real" term of the snapshot if _, err := rng.applySnapshot(snap, raftpb.HardState{}); !testutils.IsError( err, "would erase acknowledged log entries", ) { t.Fatal(err) } }
// TestKVDBInternalMethods verifies no internal methods are available // HTTP DB interface. func TestKVDBInternalMethods(t *testing.T) { defer leaktest.AfterTest(t) t.Skip("test broken & disabled; obsolete after after #2271") s := server.StartTestServer(t) defer s.Stop() testCases := []proto.Request{ &proto.HeartbeatTxnRequest{}, &proto.GCRequest{}, &proto.PushTxnRequest{}, &proto.RangeLookupRequest{}, &proto.ResolveIntentRequest{}, &proto.ResolveIntentRangeRequest{}, &proto.MergeRequest{}, &proto.TruncateLogRequest{}, &proto.LeaderLeaseRequest{}, &proto.EndTransactionRequest{ InternalCommitTrigger: &proto.InternalCommitTrigger{}, }, } // Verify internal methods experience bad request errors. db := createTestClient(t, s.Stopper(), s.ServingAddr()) for i, args := range testCases { args.Header().Key = proto.Key("a") if proto.IsRange(args) { args.Header().EndKey = args.Header().Key.Next() } b := &client.Batch{} b.InternalAddCall(proto.Call{Args: args, Reply: args.CreateReply()}) err := db.Run(b).GoError() if err == nil { t.Errorf("%d: unexpected success calling %s", i, args.Method()) } else if !testutils.IsError(err, "(couldn't find method|contains commit trigger)") { t.Errorf("%d: expected missing method %s; got %s", i, args.Method(), err) } // Verify same but within a Batch request. ba := &proto.BatchRequest{} ba.Add(args) b = &client.Batch{} b.InternalAddCall(proto.Call{Args: ba, Reply: &proto.BatchResponse{}}) if err := db.Run(b).GoError(); err == nil { t.Errorf("%d: unexpected success calling %s", i, args.Method()) } else if !testutils.IsError(err, "(contains an internal request|contains commit trigger)") { t.Errorf("%d: expected disallowed method error %s; got %s", i, args.Method(), err) } } }
func TestEvalExprError(t *testing.T) { testData := []struct { expr string expected string }{ {`1 % 0`, `zero modulus`}, {`1 / 0`, `division by zero`}, {`'2010-09-28 12:00:00.1'::date`, `parsing time "2010-09-28 12:00:00.1": extra text`}, {`'2010-09-28 12:00.1 MST'::timestamp`, `parsing time "2010-09-28 12:00.1 MST" as "2006-01-02 15:04:05.999999999 MST": cannot parse ".1 MST" as ":"`}, {`'11h2m'::interval / 0`, `division by zero`}, {`'hello' || b'world'`, `unsupported binary operator: <string> || <bytes>`}, {`b'\xff\xfe\xfd'::string`, `invalid utf8: "\xff\xfe\xfd"`}, // TODO(pmattis): Check for overflow. // {`~0 + 1`, `0`}, } for _, d := range testData { q, err := ParseTraditional("SELECT " + d.expr) if err != nil { t.Fatalf("%s: %v", d.expr, err) } expr := q[0].(*Select).Exprs[0].Expr if _, err := defaultContext.EvalExpr(expr); !testutils.IsError(err, regexp.QuoteMeta(d.expected)) { t.Errorf("%s: expected %s, but found %v", d.expr, d.expected, err) } } }
func TestTypeCheckSameTypedExprsError(t *testing.T) { floatConst := func(s string) Expr { return &NumVal{Value: constant.MakeFromLiteral(s, token.FLOAT, 0), OrigString: s} } floatIntMismatchErr := `expected .* to be of type (float|int), found type (float|int)` paramErr := `could not determine data type of parameter .*` testData := []struct { args MapArgs desired Datum exprs []Expr expectedErr string }{ {nil, nil, []Expr{NewDInt(1), floatConst("1.1")}, floatIntMismatchErr}, {nil, nil, []Expr{NewDInt(1), NewDFloat(1)}, floatIntMismatchErr}, {MapArgs{"a": TypeInt}, nil, []Expr{NewDFloat(1.1), ValArg{"a"}}, floatIntMismatchErr}, {MapArgs{"a": TypeInt}, nil, []Expr{floatConst("1.1"), ValArg{"a"}}, floatIntMismatchErr}, {MapArgs{"a": TypeFloat, "b": TypeInt}, nil, []Expr{ValArg{"b"}, ValArg{"a"}}, floatIntMismatchErr}, {nil, nil, []Expr{ValArg{"b"}, ValArg{"a"}}, paramErr}, } for i, d := range testData { forEachPerm(d.exprs, 0, func(exprs []Expr) { if _, _, err := typeCheckSameTypedExprs(d.args, d.desired, exprs...); !testutils.IsError(err, d.expectedErr) { t.Errorf("%d: expected %s, but found %v", i, d.expectedErr, err) } }) } }
func TestScanError(t *testing.T) { testData := []struct { sql string err string }{ {`1e`, "invalid floating point literal"}, {`1e-`, "invalid floating point literal"}, {`1e+`, "invalid floating point literal"}, {`0x`, "invalid hexadecimal literal"}, {`1x`, "invalid hexadecimal literal"}, {`1.x`, "invalid hexadecimal literal"}, {`1.0x`, "invalid hexadecimal literal"}, {`0x0x`, "invalid hexadecimal literal"}, {`00x0x`, "invalid hexadecimal literal"}, {`9223372036854775809`, "integer value out of range"}, {`$9223372036854775809`, "integer value out of range"}, } for _, d := range testData { s := makeScanner(d.sql, Traditional) var lval sqlSymType id := s.Lex(&lval) if id != ERROR { t.Errorf("%s: expected ERROR, but found %d", d.sql, id) } if !testutils.IsError(errors.New(lval.str), d.err) { t.Errorf("%s: expected %s, but found %s", d.sql, d.err, lval.str) } } }
func TestTxnAbortCount(t *testing.T) { defer leaktest.AfterTest(t)() _, sender, cleanupFn := setupMetricsTest(t) defer cleanupFn() value := []byte("value") db := client.NewDB(sender) intentionalErrText := "intentional error to cause abort" // Test aborted transaction. if err := db.Txn(func(txn *client.Txn) error { key := []byte("key-abort") if err := txn.SetIsolation(roachpb.SNAPSHOT); err != nil { return err } if err := txn.Put(key, value); err != nil { t.Fatal(err) } return errors.New(intentionalErrText) }); !testutils.IsError(err, intentionalErrText) { t.Fatalf("unexpected error: %s", err) } teardownHeartbeats(sender) checkTxnMetrics(t, sender, "abort txn", 0, 0, 0, 1, 0) }
// TestTxnCoordSenderErrorWithIntent validates that if a transactional request // returns an error but also indicates a Writing transaction, the coordinator // tracks it just like a successful request. func TestTxnCoordSenderErrorWithIntent(t *testing.T) { defer leaktest.AfterTest(t) stopper := stop.NewStopper() manual := hlc.NewManualClock(0) clock := hlc.NewClock(manual.UnixNano) clock.SetMaxOffset(20) ts := NewTxnCoordSender(senderFn(func(_ context.Context, ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) { txn := ba.Txn.Clone() txn.Writing = true return nil, roachpb.NewError(roachpb.NewTransactionRetryError(txn)) }), clock, false, nil, stopper) defer stopper.Stop() var ba roachpb.BatchRequest key := roachpb.Key("test") ba.Add(&roachpb.BeginTransactionRequest{Span: roachpb.Span{Key: key}}) ba.Add(&roachpb.PutRequest{Span: roachpb.Span{Key: key}}) ba.Add(&roachpb.EndTransactionRequest{}) ba.Txn = &roachpb.Transaction{Name: "test"} if _, pErr := ts.Send(context.Background(), ba); !testutils.IsError(pErr.GoError(), "retry txn") { t.Fatalf("unexpected error: %v", pErr) } defer teardownHeartbeats(ts) ts.Lock() defer ts.Unlock() if len(ts.txns) != 1 { t.Fatalf("expected transaction to be tracked") } }
// Tests that a retryable error for an inner txn doesn't cause the outer txn to // be retried. func TestWrongTxnRetry(t *testing.T) { defer leaktest.AfterTest(t)() db := NewDB(newTestSender(nil, nil)) var retries int txnClosure := func(outerTxn *Txn) error { log.Infof(context.Background(), "outer retry") retries++ // Ensure the KV transaction is created. if err := outerTxn.Put("a", "b"); err != nil { t.Fatal(err) } var execOpt TxnExecOptions execOpt.AutoRetry = false err := outerTxn.Exec( execOpt, func(innerTxn *Txn, opt *TxnExecOptions) error { // Ensure the KV transaction is created. if err := innerTxn.Put("x", "y"); err != nil { t.Fatal(err) } return roachpb.NewErrorWithTxn(&roachpb.TransactionPushError{ PusheeTxn: outerTxn.Proto}, &innerTxn.Proto).GoError() }) return err } if err := db.Txn(context.TODO(), txnClosure); !testutils.IsError(err, "failed to push") { t.Fatal(err) } if retries != 1 { t.Fatalf("unexpected retries: %d", retries) } }
// TestAuthentication tests authentication for the KV endpoint. func TestAuthentication(t *testing.T) { defer leaktest.AfterTest(t)() s, _, _ := serverutils.StartServer(t, base.TestServerArgs{}) defer s.Stopper().Stop() var b1 client.Batch b1.Put("a", "b") // Create a node user client and call Run() on it which lets us build our own // request, specifying the user. db1 := createTestClientForUser(t, s.Stopper(), s.ServingAddr(), security.NodeUser) if err := db1.Run(&b1); err != nil { t.Fatal(err) } var b2 client.Batch b2.Put("c", "d") // Try again, but this time with certs for a non-node user (even the root // user has no KV permissions). db2 := createTestClientForUser(t, s.Stopper(), s.ServingAddr(), security.RootUser) if err := db2.Run(&b2); !testutils.IsError(err, "is not allowed") { t.Fatal(err) } }
func TestVerifyClockOffset(t *testing.T) { defer leaktest.AfterTest(t)() clock := hlc.NewClock(hlc.NewManualClock(123).UnixNano) clock.SetMaxOffset(50 * time.Nanosecond) monitor := newRemoteClockMonitor(clock, time.Hour) for idx, tc := range []struct { offsets []RemoteOffset expectedError bool }{ // no error if no offsets. {[]RemoteOffset{}, false}, // no error when a majority of offsets are under the maximum offset. {[]RemoteOffset{{Offset: 20, Uncertainty: 10}, {Offset: 58, Uncertainty: 20}, {Offset: 71, Uncertainty: 25}, {Offset: 91, Uncertainty: 31}}, false}, // error when less than a majority of offsets are under the maximum offset. {[]RemoteOffset{{Offset: 20, Uncertainty: 10}, {Offset: 58, Uncertainty: 20}, {Offset: 85, Uncertainty: 25}, {Offset: 91, Uncertainty: 31}}, true}, } { monitor.mu.offsets = make(map[string]RemoteOffset) for i, offset := range tc.offsets { monitor.mu.offsets[strconv.Itoa(i)] = offset } if tc.expectedError { if err := monitor.VerifyClockOffset(); !testutils.IsError(err, errOffsetGreaterThanMaxOffset) { t.Errorf("%d: unexpected error %v", idx, err) } } else { if err := monitor.VerifyClockOffset(); err != nil { t.Errorf("%d: unexpected error %s", idx, err) } } } }
// verifyError checks that either no error was found where none was // expected, or that an error was found when one was expected. Returns // "true" to indicate the behavior was as expected. func (t *logicTest) verifyError( sql string, pos string, expectErr string, expectErrCode string, err error) bool { if expectErr == "" && expectErrCode == "" && err != nil { return t.unexpectedError(sql, pos, err) } if expectErr != "" && !testutils.IsError(err, expectErr) { if err != nil { t.Errorf("%s: expected %q, but found\n%s", pos, expectErr, err) } else { t.Errorf("%s: expected %q, but found success", pos, expectErr) } return false } if expectErrCode != "" { if err != nil { pqErr, ok := err.(*pq.Error) if !ok { t.Errorf("%s: expected error code %q, but the error we found is not "+ "a libpq error: %s", pos, expectErrCode, err) return false } if pqErr.Code != pq.ErrorCode(expectErrCode) { t.Errorf("%s: expected error code %q, but found code %q (%s)", pos, expectErrCode, pqErr.Code, pqErr.Code.Name()) return false } } else { t.Errorf("%s: expected error code %q, but found success", pos, expectErrCode) return false } } return true }
// TestNonRetryableError verifies that a non-retryable error is propagated to the client. func TestNonRetryableError(t *testing.T) { defer leaktest.AfterTest(t)() ctx, cmdFilters := createTestServerContext() server, sqlDB, _ := setupWithContext(t, &ctx) defer cleanup(server, sqlDB) testKey := []byte("test_key") hitError := false cleanupFilter := cmdFilters.AppendFilter( func(args storagebase.FilterArgs) *roachpb.Error { if req, ok := args.Req.(*roachpb.ScanRequest); ok { if bytes.Contains(req.Key, testKey) { hitError = true return roachpb.NewErrorWithTxn(fmt.Errorf("testError"), args.Hdr.Txn) } } return nil }, false) defer cleanupFilter() sqlDB.SetMaxOpenConns(1) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.test (k TEXT PRIMARY KEY, v TEXT); INSERT INTO t.test (k, v) VALUES ('test_key', 'test_val'); SELECT * from t.test WHERE k = 'test_key'; `); !testutils.IsError(err, "pq: testError") { t.Errorf("unexpected error %s", err) } if !hitError { t.Errorf("expected to hit error, but it didn't happen") } }
func TestTxnAbandonCount(t *testing.T) { defer leaktest.AfterTest(t)() manual, sender, cleanupFn := setupMetricsTest(t) defer cleanupFn() value := []byte("value") db := client.NewDB(sender) // Test abandoned transaction by making the client timeout ridiculously short. We also set // the sender to heartbeat very frequently, because the heartbeat detects and tears down // abandoned transactions. sender.heartbeatInterval = 2 * time.Millisecond sender.clientTimeout = 1 * time.Millisecond if err := db.Txn(func(txn *client.Txn) error { key := []byte("key-abandon") if err := txn.SetIsolation(roachpb.SNAPSHOT); err != nil { return err } if err := txn.Put(key, value); err != nil { return err } manual.Increment(int64(sender.clientTimeout + sender.heartbeatInterval*2)) checkTxnMetrics(t, sender, "abandon txn", 0, 0, 1, 0, 0) return nil }); !testutils.IsError(err, "writing transaction timed out") { t.Fatalf("unexpected error: %s", err) } }
func TestEvalExprError(t *testing.T) { testData := []struct { expr string expected string }{ {`'1' + '2'`, `unsupported binary operator:`}, {`'a' + 0`, `unsupported binary operator:`}, {`1.1 # 3.1`, `unsupported binary operator:`}, {`~0.1`, `unsupported unary operator:`}, {`'10' > 2`, `unsupported comparison operator:`}, {`1 IN ('a', 'b')`, `unsupported comparison operator:`}, {`a`, `column \"a\" not found`}, {`1 AND true`, `cannot convert int to bool`}, {`1.0 AND true`, `cannot convert float to bool`}, {`'a' AND true`, `cannot convert string to bool`}, {`(1, 2) AND true`, `cannot convert tuple to bool`}, {`lower()`, `incorrect number of arguments`}, {`lower(1, 2)`, `incorrect number of arguments`}, {`lower(1)`, `argument type mismatch`}, // TODO(pmattis): Check for overflow. // {`~0 + 1`, `0`, nil}, } for _, d := range testData { q, err := Parse("SELECT " + d.expr) if err != nil { t.Fatalf("%s: %v", d.expr, err) } expr := q[0].(*Select).Exprs[0].(*NonStarExpr).Expr if _, err := EvalExpr(expr, mapEnv{}); !testutils.IsError(err, d.expected) { t.Errorf("%s: expected %s, but found %v", d.expr, d.expected, err) } } }
// TestTxnCoordIdempotentCleanup verifies that cleanupTxnLocked is idempotent. func TestTxnCoordIdempotentCleanup(t *testing.T) { defer leaktest.AfterTest(t)() s, sender := createTestDB(t) defer s.Stop() defer teardownHeartbeats(sender) txn := client.NewTxn(context.Background(), *s.DB) ba := txn.NewBatch() ba.Put(roachpb.Key("a"), []byte("value")) if err := txn.Run(ba); err != nil { t.Fatal(err) } sender.Lock() // Clean up twice successively. sender.cleanupTxnLocked(context.Background(), txn.Proto) sender.cleanupTxnLocked(context.Background(), txn.Proto) sender.Unlock() // For good measure, try to commit (which cleans up once more if it // succeeds, which it may not if the previous cleanup has already // terminated the heartbeat goroutine) ba = txn.NewBatch() ba.AddRawRequest(&roachpb.EndTransactionRequest{}) err := txn.Run(ba) if err != nil && !testutils.IsError(err, errNoState.Error()) { t.Fatal(err) } }
func (t *logicTest) verifyError( pos string, expectErr string, expectErrCode string, err error) { if expectErr == "" && expectErrCode == "" && err != nil { t.Fatalf("%s: expected success, but found\n%s", pos, err) } if expectErr != "" && !testutils.IsError(err, expectErr) { if err != nil { t.Fatalf("%s: expected %q, but found\n%s", pos, expectErr, err) } else { t.Fatalf("%s: expected %q, but found success", pos, expectErr) } } if expectErrCode != "" { if err != nil { pqErr, ok := err.(*pq.Error) if !ok { t.Fatalf("%s: expected error code %q, but the error we found is not "+ "a libpq error: %s", pos, expectErrCode, err) } if pqErr.Code != pq.ErrorCode(expectErrCode) { t.Fatalf("%s: expected error code %q, but found code %q (%s)", pos, expectErrCode, pqErr.Code, pqErr.Code.Name()) } } else { t.Fatalf("%s: expected error code %q, but found success", pos, expectErrCode) } } }
// Returns true on retriable errors. func runTestTxn(t *testing.T, magicVals *filterVals, expectedErr string, injectReleaseError *bool, sqlDB *gosql.DB, tx *gosql.Tx) bool { retriesNeeded := (magicVals.restartCounts["boulanger"] + magicVals.abortCounts["boulanger"]) > 0 var err error if retriesNeeded { _, err = tx.Exec("INSERT INTO t.test (k, v) VALUES (1, 'boulanger')") if !testutils.IsError(err, expectedErr) { t.Fatalf("expected to fail here. err: %v", err) } return isRetryableErr(err) } // Now the INSERT should succeed. _, err = tx.Exec("DELETE FROM t.test WHERE true; INSERT INTO t.test (k, v) VALUES (0, 'sentinel');") if err != nil { t.Fatal(err) } retriesNeeded = *injectReleaseError if retriesNeeded { *injectReleaseError = false abortTxn(t, sqlDB, 0) } _, err = tx.Exec("RELEASE SAVEPOINT cockroach_restart") if retriesNeeded { if err == nil { t.Fatal("expected RELEASE to fail") } } else { if err != nil { t.Fatal(err) } } return isRetryableErr(err) }
// TestNonRetryableError verifies that a non-retryable error from the // execution of EndTransactionRequests is propagated to the client. func TestNonRetryableErrorFromCommit(t *testing.T) { defer leaktest.AfterTest(t)() params, cmdFilters := createTestServerParams() s, sqlDB, _ := serverutils.StartServer(t, params) defer s.Stopper().Stop() hitError := false cleanupFilter := cmdFilters.AppendFilter( func(args storagebase.FilterArgs) *roachpb.Error { if req, ok := args.Req.(*roachpb.EndTransactionRequest); ok { if bytes.Contains(req.Key, []byte(keys.DescIDGenerator)) { hitError = true return roachpb.NewErrorWithTxn(fmt.Errorf("testError"), args.Hdr.Txn) } } return nil }, false) defer cleanupFilter() if _, err := sqlDB.Exec("CREATE DATABASE t;"); !testutils.IsError(err, "pq: testError") { t.Errorf("unexpected error %v", err) } if !hitError { t.Errorf("expected to hit error, but it didn't happen") } }
// TestClientForwardUnresolved verifies that a client does not resolve a forward // address prematurely. func TestClientForwardUnresolved(t *testing.T) { defer leaktest.AfterTest(t)() stopper := stop.NewStopper() defer stopper.Stop() const nodeID = 1 local := startGossip(nodeID, stopper, t) local.mu.Lock() addr := local.is.NodeAddr local.mu.Unlock() client := newClient(&addr) // never started newAddr := util.UnresolvedAddr{ NetworkField: "tcp", AddressField: "localhost:2345", } reply := &Response{ NodeID: nodeID, Addr: addr, AlternateNodeID: nodeID + 1, AlternateAddr: &newAddr, } if err := client.handleResponse(local, reply); !testutils.IsError(err, "received forward") { t.Fatal(err) } if !proto.Equal(client.forwardAddr, &newAddr) { t.Fatalf("unexpected forward address %v, expected %v", client.forwardAddr, &newAddr) } }
// TestCorruptedClusterID verifies that a node fails to start when a // store's cluster ID is empty. func TestCorruptedClusterID(t *testing.T) { defer leaktest.AfterTest(t) engineStopper := stop.NewStopper() e := engine.NewInMem(roachpb.Attributes{}, 1<<20, engineStopper) defer engineStopper.Stop() if _, err := bootstrapCluster([]engine.Engine{e}); err != nil { t.Fatal(err) } // Set the cluster ID to an empty string. sIdent := roachpb.StoreIdent{ ClusterID: "", NodeID: 1, StoreID: 1, } if err := engine.MVCCPutProto(e, nil, keys.StoreIdentKey(), roachpb.ZeroTimestamp, nil, &sIdent); err != nil { t.Fatal(err) } engines := []engine.Engine{e} server, serverAddr, _, node, stopper := createTestNode(util.CreateTestAddr("tcp"), engines, nil, t) stopper.Stop() if err := node.start(server, serverAddr, engines, roachpb.Attributes{}); !testutils.IsError(err, "unidentified store") { t.Errorf("unexpected error %v", err) } }
func TestEvalExprError(t *testing.T) { testData := []struct { expr string expected string }{ {`'1' + '2'`, `unsupported binary operator:`}, {`'a' + 0`, `unsupported binary operator:`}, {`1.1 # 3.1`, `unsupported binary operator:`}, {`~0.1`, `unsupported unary operator:`}, {`'10' > 2`, `unsupported comparison operator:`}, {`a`, `column \"a\" not found`}, // TODO(pmattis): Check for overflow. // {`~0 + 1`, `0`, nil}, } for _, d := range testData { q, err := Parse("SELECT " + d.expr) if err != nil { t.Fatalf("%s: %v: %s", d.expr, err, d.expr) } expr := q[0].(*Select).Exprs[0].(*NonStarExpr).Expr if _, err := EvalExpr(expr, mapEnv{}); !testutils.IsError(err, d.expected) { t.Errorf("%s: expected %s, but found %v", d.expr, d.expected, err) } } }
// TestCorruptedClusterID verifies that a node fails to start when a // store's cluster ID is empty. func TestCorruptedClusterID(t *testing.T) { defer leaktest.AfterTest(t)() engineStopper := stop.NewStopper() e := engine.NewInMem(roachpb.Attributes{}, 1<<20, engineStopper) defer engineStopper.Stop() if _, err := bootstrapCluster([]engine.Engine{e}, kv.NewTxnMetrics(metric.NewRegistry())); err != nil { t.Fatal(err) } // Set the cluster ID to the empty UUID. sIdent := roachpb.StoreIdent{ ClusterID: *uuid.EmptyUUID, NodeID: 1, StoreID: 1, } if err := engine.MVCCPutProto(context.Background(), e, nil, keys.StoreIdentKey(), roachpb.ZeroTimestamp, nil, &sIdent); err != nil { t.Fatal(err) } engines := []engine.Engine{e} _, serverAddr, _, node, stopper := createTestNode(util.TestAddr, engines, nil, t) stopper.Stop() if err := node.start(serverAddr, engines, roachpb.Attributes{}); !testutils.IsError(err, "unidentified store") { t.Errorf("unexpected error %v", err) } }
// TestRocksDBOpenWithVersions verifies the version checking in Open() // functions correctly. func TestRocksDBOpenWithVersions(t *testing.T) { defer leaktest.AfterTest(t)() testCases := []struct { hasFile bool ver Version expectedErr string }{ {false, Version{}, ""}, {true, Version{versionCurrent}, ""}, {true, Version{versionMinimum}, ""}, {true, Version{-1}, "incompatible rocksdb data version, current:1, on disk:-1, minimum:0"}, {true, Version{2}, "incompatible rocksdb data version, current:1, on disk:2, minimum:0"}, } for i, testCase := range testCases { err := openRocksDBWithVersion(t, testCase.hasFile, testCase.ver) if err == nil && len(testCase.expectedErr) == 0 { continue } if !testutils.IsError(err, testCase.expectedErr) { t.Errorf("%d: expected error '%s', actual '%s'", i, testCase.expectedErr, err) } } }
func TestDropTableInTxn(t *testing.T) { defer leaktest.AfterTest(t)() s, sqlDB, _ := setup(t) defer cleanup(s, sqlDB) if _, err := sqlDB.Exec(` CREATE DATABASE t; CREATE TABLE t.kv (k CHAR PRIMARY KEY, v CHAR); `); err != nil { t.Fatal(err) } tx, err := sqlDB.Begin() if err != nil { t.Fatal(err) } if _, err := tx.Exec(`DROP TABLE t.kv`); err != nil { t.Fatal(err) } // We might still be able to read/write in the table inside this transaction // until the schema changer runs, but we shouldn't be able to ALTER it. if _, err := tx.Exec(`ALTER TABLE t.kv ADD COLUMN w CHAR`); !testutils.IsError(err, `table "kv" has been deleted`) { t.Fatalf("different error than expected: %s", err) } // Can't commit after ALTER errored, so we ROLLBACK. if err := tx.Rollback(); err != nil { t.Fatal(err) } }