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  }