github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/protectedts/ptverifier/verifier_test.go (about) 1 // Copyright 2019 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 ptverifier_test 12 13 import ( 14 "context" 15 "sync/atomic" 16 "testing" 17 "time" 18 19 "github.com/cockroachdb/cockroach/pkg/base" 20 "github.com/cockroachdb/cockroach/pkg/keys" 21 "github.com/cockroachdb/cockroach/pkg/kv" 22 "github.com/cockroachdb/cockroach/pkg/kv/kvclient/kvcoord" 23 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts" 24 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts/ptpb" 25 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts/ptstorage" 26 "github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts/ptverifier" 27 "github.com/cockroachdb/cockroach/pkg/roachpb" 28 "github.com/cockroachdb/cockroach/pkg/sql/sqlutil" 29 "github.com/cockroachdb/cockroach/pkg/testutils/testcluster" 30 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 31 "github.com/cockroachdb/cockroach/pkg/util/uuid" 32 "github.com/cockroachdb/errors" 33 "github.com/stretchr/testify/require" 34 ) 35 36 // TestVerifier tests the business logic of verification by mocking out the 37 // actual verification requests but using a real implementation of 38 // protectedts.Storage. 39 func TestVerifier(t *testing.T) { 40 defer leaktest.AfterTest(t)() 41 42 ctx := context.Background() 43 tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{}) 44 defer tc.Stopper().Stop(ctx) 45 46 s := tc.Server(0) 47 var senderFunc atomic.Value 48 senderFunc.Store(kv.SenderFunc(nil)) 49 ds := s.DistSenderI().(*kvcoord.DistSender) 50 tsf := kvcoord.NewTxnCoordSenderFactory( 51 kvcoord.TxnCoordSenderFactoryConfig{ 52 AmbientCtx: s.DB().AmbientContext, 53 HeartbeatInterval: time.Second, 54 Settings: s.ClusterSettings(), 55 Clock: s.Clock(), 56 Stopper: s.Stopper(), 57 }, 58 kv.SenderFunc(func(ctx context.Context, ba roachpb.BatchRequest) (*roachpb.BatchResponse, *roachpb.Error) { 59 if f := senderFunc.Load().(kv.SenderFunc); f != nil { 60 return f(ctx, ba) 61 } 62 return ds.Send(ctx, ba) 63 }), 64 ) 65 66 pts := ptstorage.New(s.ClusterSettings(), s.InternalExecutor().(sqlutil.InternalExecutor)) 67 withDB := ptstorage.WithDatabase(pts, s.DB()) 68 db := kv.NewDB(s.DB().AmbientContext, tsf, s.Clock()) 69 ptv := ptverifier.New(db, pts) 70 makeTableSpan := func(tableID uint32) roachpb.Span { 71 k := keys.SystemSQLCodec.TablePrefix(tableID) 72 return roachpb.Span{Key: k, EndKey: k.PrefixEnd()} 73 } 74 75 createRecord := func(t *testing.T, tables ...uint32) *ptpb.Record { 76 spans := make([]roachpb.Span, len(tables)) 77 for i, tid := range tables { 78 spans[i] = makeTableSpan(tid) 79 } 80 r := ptpb.Record{ 81 ID: uuid.MakeV4(), 82 Timestamp: s.Clock().Now(), 83 Mode: ptpb.PROTECT_AFTER, 84 Spans: spans, 85 } 86 require.Nil(t, s.DB().Txn(ctx, func(ctx context.Context, txn *kv.Txn) error { 87 return pts.Protect(ctx, txn, &r) 88 })) 89 return &r 90 } 91 ensureVerified := func(t *testing.T, id uuid.UUID, verified bool) { 92 got, err := withDB.GetRecord(ctx, nil, id) 93 require.NoError(t, err) 94 require.Equal(t, verified, got.Verified) 95 } 96 release := func(t *testing.T, id uuid.UUID) { 97 require.NoError(t, withDB.Release(ctx, nil, id)) 98 } 99 for _, c := range []struct { 100 name string 101 test func(t *testing.T) 102 }{ 103 { 104 name: "record doesn't exist", 105 test: func(t *testing.T) { 106 require.Regexp(t, protectedts.ErrNotExists.Error(), 107 ptv.Verify(ctx, uuid.MakeV4()).Error()) 108 }, 109 }, 110 { 111 name: "verification failed with injected error", 112 test: func(t *testing.T) { 113 defer senderFunc.Store(senderFunc.Load()) 114 r := createRecord(t, 42) 115 senderFunc.Store(kv.SenderFunc(func( 116 ctx context.Context, ba roachpb.BatchRequest, 117 ) (*roachpb.BatchResponse, *roachpb.Error) { 118 if _, ok := ba.GetArg(roachpb.AdminVerifyProtectedTimestamp); ok { 119 return nil, roachpb.NewError(errors.New("boom")) 120 } 121 return ds.Send(ctx, ba) 122 })) 123 require.Regexp(t, "boom", ptv.Verify(ctx, r.ID).Error()) 124 ensureVerified(t, r.ID, false) 125 release(t, r.ID) 126 }, 127 }, 128 { 129 name: "verification failed with injected response", 130 test: func(t *testing.T) { 131 defer senderFunc.Store(senderFunc.Load()) 132 r := createRecord(t, 42) 133 senderFunc.Store(kv.SenderFunc(func( 134 ctx context.Context, ba roachpb.BatchRequest, 135 ) (*roachpb.BatchResponse, *roachpb.Error) { 136 if _, ok := ba.GetArg(roachpb.AdminVerifyProtectedTimestamp); ok { 137 var resp roachpb.BatchResponse 138 resp.Add(&roachpb.AdminVerifyProtectedTimestampResponse{ 139 FailedRanges: []roachpb.RangeDescriptor{{ 140 RangeID: 42, 141 StartKey: roachpb.RKey(r.Spans[0].Key), 142 EndKey: roachpb.RKey(r.Spans[0].EndKey), 143 }}, 144 }) 145 return &resp, nil 146 } 147 return ds.Send(ctx, ba) 148 })) 149 require.Regexp(t, "failed to verify protection.*r42", ptv.Verify(ctx, r.ID).Error()) 150 ensureVerified(t, r.ID, false) 151 release(t, r.ID) 152 }, 153 }, 154 { 155 name: "verification failed with injected response over two spans", 156 test: func(t *testing.T) { 157 defer senderFunc.Store(senderFunc.Load()) 158 r := createRecord(t, 42, 12) 159 senderFunc.Store(kv.SenderFunc(func( 160 ctx context.Context, ba roachpb.BatchRequest, 161 ) (*roachpb.BatchResponse, *roachpb.Error) { 162 if _, ok := ba.GetArg(roachpb.AdminVerifyProtectedTimestamp); ok { 163 var resp roachpb.BatchResponse 164 resp.Add(&roachpb.AdminVerifyProtectedTimestampResponse{ 165 FailedRanges: []roachpb.RangeDescriptor{{ 166 RangeID: 42, 167 StartKey: roachpb.RKey(r.Spans[0].Key), 168 EndKey: roachpb.RKey(r.Spans[0].EndKey), 169 }}, 170 }) 171 resp.Add(&roachpb.AdminVerifyProtectedTimestampResponse{ 172 FailedRanges: []roachpb.RangeDescriptor{{ 173 RangeID: 12, 174 StartKey: roachpb.RKey(r.Spans[1].Key), 175 EndKey: roachpb.RKey(r.Spans[1].EndKey), 176 }}, 177 }) 178 return &resp, nil 179 } 180 return ds.Send(ctx, ba) 181 })) 182 require.Regexp(t, "failed to verify protection.*r42.*r12", ptv.Verify(ctx, r.ID).Error()) 183 ensureVerified(t, r.ID, false) 184 release(t, r.ID) 185 }, 186 }, 187 { 188 name: "verification succeeded", 189 test: func(t *testing.T) { 190 defer senderFunc.Store(senderFunc.Load()) 191 r := createRecord(t, 42) 192 senderFunc.Store(kv.SenderFunc(func( 193 ctx context.Context, ba roachpb.BatchRequest, 194 ) (*roachpb.BatchResponse, *roachpb.Error) { 195 if _, ok := ba.GetArg(roachpb.AdminVerifyProtectedTimestamp); ok { 196 var resp roachpb.BatchResponse 197 resp.Add(&roachpb.AdminVerifyProtectedTimestampResponse{}) 198 return &resp, nil 199 } 200 return ds.Send(ctx, ba) 201 })) 202 require.NoError(t, ptv.Verify(ctx, r.ID)) 203 ensureVerified(t, r.ID, true) 204 // Show that we don't send again once we've already verified. 205 sawVerification := false 206 senderFunc.Store(kv.SenderFunc(func( 207 ctx context.Context, ba roachpb.BatchRequest, 208 ) (*roachpb.BatchResponse, *roachpb.Error) { 209 if _, ok := ba.GetArg(roachpb.AdminVerifyProtectedTimestamp); ok { 210 sawVerification = true 211 } 212 return ds.Send(ctx, ba) 213 })) 214 require.NoError(t, ptv.Verify(ctx, r.ID)) 215 require.False(t, sawVerification) 216 release(t, r.ID) 217 }, 218 }, 219 } { 220 t.Run(c.name, c.test) 221 } 222 }