github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/protectedts/ptreconcile/reconciler_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 ptreconcile_test
    12  
    13  import (
    14  	"context"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/base"
    19  	"github.com/cockroachdb/cockroach/pkg/keys"
    20  	"github.com/cockroachdb/cockroach/pkg/kv"
    21  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver"
    22  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts"
    23  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts/ptpb"
    24  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts/ptreconcile"
    25  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    26  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    27  	"github.com/cockroachdb/cockroach/pkg/sql"
    28  	"github.com/cockroachdb/cockroach/pkg/testutils"
    29  	"github.com/cockroachdb/cockroach/pkg/testutils/testcluster"
    30  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    31  	"github.com/cockroachdb/cockroach/pkg/util/syncutil"
    32  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    33  	"github.com/cockroachdb/errors"
    34  	"github.com/stretchr/testify/require"
    35  )
    36  
    37  func TestReconciler(t *testing.T) {
    38  	defer leaktest.AfterTest(t)()
    39  
    40  	ctx := context.Background()
    41  	tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{})
    42  	defer tc.Stopper().Stop(ctx)
    43  
    44  	// Now I want to create some artifacts that should get reconciled away and
    45  	// then make sure that they do and others which should not do not.
    46  	s0 := tc.Server(0)
    47  	ptp := s0.ExecutorConfig().(sql.ExecutorConfig).ProtectedTimestampProvider
    48  
    49  	settings := cluster.MakeTestingClusterSettings()
    50  	const testTaskType = "foo"
    51  	var state = struct {
    52  		mu       syncutil.Mutex
    53  		toRemove map[string]struct{}
    54  	}{}
    55  	state.toRemove = map[string]struct{}{}
    56  	cfg := ptreconcile.Config{
    57  		Settings: settings,
    58  		Stores:   s0.GetStores().(*kvserver.Stores),
    59  		DB:       s0.DB(),
    60  		Storage:  ptp,
    61  		Cache:    ptp,
    62  		StatusFuncs: ptreconcile.StatusFuncs{
    63  			testTaskType: func(
    64  				ctx context.Context, txn *kv.Txn, meta []byte,
    65  			) (shouldRemove bool, err error) {
    66  				state.mu.Lock()
    67  				defer state.mu.Unlock()
    68  				_, shouldRemove = state.toRemove[string(meta)]
    69  				return shouldRemove, nil
    70  			},
    71  		},
    72  	}
    73  	r := ptreconcile.NewReconciler(cfg)
    74  	require.NoError(t, r.Start(ctx, tc.Stopper()))
    75  	recMeta := "a"
    76  	rec1 := ptpb.Record{
    77  		ID:        uuid.MakeV4(),
    78  		Timestamp: s0.Clock().Now(),
    79  		Mode:      ptpb.PROTECT_AFTER,
    80  		MetaType:  testTaskType,
    81  		Meta:      []byte(recMeta),
    82  		Spans: []roachpb.Span{
    83  			{Key: keys.MinKey, EndKey: keys.MaxKey},
    84  		},
    85  	}
    86  	require.NoError(t, s0.DB().Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
    87  		return ptp.Protect(ctx, txn, &rec1)
    88  	}))
    89  
    90  	t.Run("update settings", func(t *testing.T) {
    91  		ptreconcile.ReconcileInterval.Override(&settings.SV, time.Millisecond)
    92  		testutils.SucceedsSoon(t, func() error {
    93  			require.Equal(t, int64(0), r.Metrics().RecordsRemoved.Count())
    94  			require.Equal(t, int64(0), r.Metrics().ReconciliationErrors.Count())
    95  			if processed := r.Metrics().RecordsProcessed.Count(); processed < 1 {
    96  				return errors.Errorf("expected processed to be at least 1, got %d", processed)
    97  			}
    98  			return nil
    99  		})
   100  	})
   101  	t.Run("reconcile", func(t *testing.T) {
   102  		state.mu.Lock()
   103  		state.toRemove[recMeta] = struct{}{}
   104  		state.mu.Unlock()
   105  
   106  		ptreconcile.ReconcileInterval.Override(&settings.SV, time.Millisecond)
   107  		testutils.SucceedsSoon(t, func() error {
   108  			require.Equal(t, int64(0), r.Metrics().ReconciliationErrors.Count())
   109  			if removed := r.Metrics().RecordsRemoved.Count(); removed != 1 {
   110  				return errors.Errorf("expected processed to be 1, got %d", removed)
   111  			}
   112  			return nil
   113  		})
   114  		require.Regexp(t, protectedts.ErrNotExists, s0.DB().Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
   115  			_, err := ptp.GetRecord(ctx, txn, rec1.ID)
   116  			return err
   117  		}))
   118  	})
   119  }