github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvnemesis/applier_test.go (about) 1 // Copyright 2020 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package kvnemesis 12 13 import ( 14 "context" 15 "regexp" 16 "strings" 17 "testing" 18 19 "github.com/cockroachdb/cockroach/pkg/base" 20 "github.com/cockroachdb/cockroach/pkg/testutils/testcluster" 21 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func TestApplier(t *testing.T) { 27 defer leaktest.AfterTest(t)() 28 29 ctx := context.Background() 30 tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{}) 31 defer tc.Stopper().Stop(ctx) 32 db := tc.Server(0).DB() 33 34 a := MakeApplier(db, db) 35 check := func(t *testing.T, s Step, expected string) { 36 t.Helper() 37 require.NoError(t, a.Apply(ctx, &s)) 38 actual := s.String() 39 // Trim out the txn stuff. It has things like timestamps in it that are not 40 // stable from run to run. 41 actual = regexp.MustCompile(` // nil txnpb:\(.*\)`).ReplaceAllString(actual, ` // nil txnpb:(...)`) 42 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(actual)) 43 } 44 checkErr := func(t *testing.T, s Step, expected string) { 45 t.Helper() 46 cancelledCtx, cancel := context.WithCancel(context.Background()) 47 cancel() 48 require.NoError(t, a.Apply(cancelledCtx, &s)) 49 assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(s.String())) 50 } 51 52 // Basic operations 53 check(t, step(get(`a`)), `db0.Get(ctx, "a") // (nil, nil)`) 54 55 check(t, step(put(`a`, `1`)), `db1.Put(ctx, "a", 1) // nil`) 56 check(t, step(get(`a`)), `db0.Get(ctx, "a") // ("1", nil)`) 57 58 checkErr(t, step(get(`a`)), `db1.Get(ctx, "a") // (nil, aborted in distSender: context canceled)`) 59 checkErr(t, step(put(`a`, `1`)), `db0.Put(ctx, "a", 1) // aborted in distSender: context canceled`) 60 61 // Batch 62 check(t, step(batch(put(`b`, `2`), get(`a`))), ` 63 { 64 b := &Batch{} 65 b.Put(ctx, "b", 2) // nil 66 b.Get(ctx, "a") // ("1", nil) 67 db1.Run(ctx, b) // nil 68 } 69 `) 70 checkErr(t, step(batch(put(`b`, `2`), get(`a`))), ` 71 { 72 b := &Batch{} 73 b.Put(ctx, "b", 2) // aborted in distSender: context canceled 74 b.Get(ctx, "a") // (nil, aborted in distSender: context canceled) 75 db0.Run(ctx, b) // aborted in distSender: context canceled 76 } 77 `) 78 79 // Txn commit 80 check(t, step(closureTxn(ClosureTxnType_Commit, put(`e`, `5`), batch(put(`f`, `6`)))), ` 81 db1.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 82 txn.Put(ctx, "e", 5) // nil 83 { 84 b := &Batch{} 85 b.Put(ctx, "f", 6) // nil 86 txn.Run(ctx, b) // nil 87 } 88 return nil 89 }) // nil txnpb:(...) 90 `) 91 92 // Txn commit in batch 93 check(t, step(closureTxnCommitInBatch(opSlice(get(`a`), put(`f`, `6`)), put(`e`, `5`))), ` 94 db0.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 95 txn.Put(ctx, "e", 5) // nil 96 b := &Batch{} 97 b.Get(ctx, "a") // ("1", nil) 98 b.Put(ctx, "f", 6) // nil 99 txn.CommitInBatch(ctx, b) // nil 100 return nil 101 }) // nil txnpb:(...) 102 `) 103 104 // Txn rollback 105 check(t, step(closureTxn(ClosureTxnType_Rollback, put(`e`, `5`))), ` 106 db1.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 107 txn.Put(ctx, "e", 5) // nil 108 return errors.New("rollback") 109 }) // rollback 110 `) 111 112 // Txn error 113 checkErr(t, step(closureTxn(ClosureTxnType_Rollback, put(`e`, `5`))), ` 114 db0.Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 115 txn.Put(ctx, "e", 5) 116 return errors.New("rollback") 117 }) // context canceled 118 `) 119 120 // Splits and merges 121 check(t, step(split(`foo`)), `db1.AdminSplit(ctx, "foo") // nil`) 122 check(t, step(merge(`foo`)), `db0.AdminMerge(ctx, "foo") // nil`) 123 checkErr(t, step(split(`foo`)), 124 `db1.AdminSplit(ctx, "foo") // aborted in distSender: context canceled`) 125 checkErr(t, step(merge(`foo`)), 126 `db0.AdminMerge(ctx, "foo") // aborted in distSender: context canceled`) 127 }