github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/changefeedccl/validations_test.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Licensed as a CockroachDB Enterprise file under the Cockroach Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt 8 9 package changefeedccl 10 11 import ( 12 "context" 13 gosql "database/sql" 14 "math/rand" 15 "sync/atomic" 16 "testing" 17 18 "github.com/cockroachdb/cockroach/pkg/ccl/changefeedccl/cdctest" 19 "github.com/cockroachdb/cockroach/pkg/ccl/utilccl" 20 "github.com/cockroachdb/cockroach/pkg/util/ctxgroup" 21 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 22 "github.com/cockroachdb/cockroach/pkg/workload/bank" 23 "github.com/cockroachdb/cockroach/pkg/workload/workloadsql" 24 "github.com/stretchr/testify/require" 25 ) 26 27 func TestCatchupScanOrdering(t *testing.T) { 28 defer leaktest.AfterTest(t)() 29 defer utilccl.TestingEnableEnterprise()() 30 31 testFn := func(t *testing.T, db *gosql.DB, f cdctest.TestFeedFactory) { 32 t.Run("bank", func(t *testing.T) { 33 ctx := context.Background() 34 const numRows, numRanges, payloadBytes, maxTransfer = 10, 10, 10, 999 35 gen := bank.FromConfig(numRows, numRows, payloadBytes, numRanges) 36 var l workloadsql.InsertsDataLoader 37 if _, err := workloadsql.Setup(ctx, db, gen, l); err != nil { 38 t.Fatal(err) 39 } 40 41 var nowString string 42 require.NoError(t, db.QueryRow("SELECT cluster_logical_timestamp()").Scan(&nowString)) 43 44 existingChangeCount := 50 45 for i := 0; i < existingChangeCount; i++ { 46 if err := randomBankTransfer(numRows, maxTransfer, db); err != nil { 47 t.Fatal(err) 48 } 49 } 50 51 bankFeed := feed(t, f, `CREATE CHANGEFEED FOR bank WITH updated, cursor=$1`, nowString) 52 defer closeFeed(t, bankFeed) 53 54 var done int64 55 g := ctxgroup.WithContext(ctx) 56 g.GoCtx(func(ctx context.Context) error { 57 for { 58 if atomic.LoadInt64(&done) > 0 { 59 return nil 60 } 61 62 if err := randomBankTransfer(numRows, maxTransfer, db); err != nil { 63 return err 64 } 65 } 66 }) 67 68 v := cdctest.NewOrderValidator(`bank`) 69 seenChanges := 0 70 for { 71 m, err := bankFeed.Next() 72 if err != nil { 73 t.Fatal(err) 74 } else if len(m.Key) > 0 || len(m.Value) > 0 { 75 updated, _, err := cdctest.ParseJSONValueTimestamps(m.Value) 76 if err != nil { 77 t.Fatal(err) 78 } 79 err = v.NoteRow(m.Partition, string(m.Key), string(m.Value), updated) 80 if err != nil { 81 t.Fatal(err) 82 } 83 seenChanges++ 84 if seenChanges >= 200 { 85 atomic.StoreInt64(&done, 1) 86 break 87 } 88 } 89 } 90 for _, f := range v.Failures() { 91 t.Error(f) 92 } 93 94 if err := g.Wait(); err != nil { 95 t.Errorf(`%+v`, err) 96 } 97 }) 98 } 99 t.Run(`sinkless`, sinklessTest(testFn)) 100 t.Run(`enterprise`, enterpriseTest(testFn)) 101 } 102 103 // TODO(dan): This bit is copied from the bank workload. It's 104 // currently much easier to do this than to use the real Ops, 105 // which is silly. Fixme. 106 func randomBankTransfer(numRows, maxTransfer int, db *gosql.DB) error { 107 from := rand.Intn(numRows) 108 to := rand.Intn(numRows) 109 for from == to { 110 to = rand.Intn(numRows) 111 } 112 amount := rand.Intn(maxTransfer) 113 _, err := db.Exec(`UPDATE bank 114 SET balance = CASE id WHEN $1 THEN balance-$3 WHEN $2 THEN balance+$3 END 115 WHERE id IN ($1, $2) 116 `, from, to, amount) 117 return err 118 }