github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/jobs/jobsprotectedts/jobs_protected_ts_test.go (about)

     1  // Copyright 2017 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 jobsprotectedts_test
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"io"
    17  	"testing"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/base"
    20  	"github.com/cockroachdb/cockroach/pkg/jobs"
    21  	"github.com/cockroachdb/cockroach/pkg/jobs/jobspb"
    22  	"github.com/cockroachdb/cockroach/pkg/jobs/jobsprotectedts"
    23  	"github.com/cockroachdb/cockroach/pkg/keys"
    24  	"github.com/cockroachdb/cockroach/pkg/kv"
    25  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts"
    26  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/protectedts/ptpb"
    27  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    28  	"github.com/cockroachdb/cockroach/pkg/sql"
    29  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    30  	"github.com/cockroachdb/cockroach/pkg/testutils"
    31  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    32  	"github.com/cockroachdb/cockroach/pkg/testutils/testcluster"
    33  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    34  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    35  	"github.com/cockroachdb/errors"
    36  	"github.com/stretchr/testify/require"
    37  )
    38  
    39  // TestJobsProtectedTimestamp is an end-to-end test of protected timestamp
    40  // reconciliation for jobs.
    41  func TestJobsProtectedTimestamp(t *testing.T) {
    42  	defer leaktest.AfterTest(t)()
    43  
    44  	ctx := context.Background()
    45  	tc := testcluster.StartTestCluster(t, 1, base.TestClusterArgs{})
    46  	defer tc.Stopper().Stop(ctx)
    47  
    48  	// Now I want to create some artifacts that should get reconciled away and
    49  	// then make sure that they do and others which should not do not.
    50  	s0 := tc.Server(0)
    51  	ptp := s0.ExecutorConfig().(sql.ExecutorConfig).ProtectedTimestampProvider
    52  	runner := sqlutils.MakeSQLRunner(tc.ServerConn(0))
    53  	runner.Exec(t, "SET CLUSTER SETTING kv.protectedts.reconciliation.interval = '1ms';")
    54  	jr := s0.JobRegistry().(*jobs.Registry)
    55  	mkJobRec := func() jobs.Record {
    56  		return jobs.Record{
    57  			Description: "testing",
    58  			Statement:   "SELECT 1",
    59  			Username:    "root",
    60  			Details: jobspb.SchemaChangeGCDetails{
    61  				Tables: []jobspb.SchemaChangeGCDetails_DroppedID{
    62  					{
    63  						ID:       42,
    64  						DropTime: s0.Clock().PhysicalNow(),
    65  					},
    66  				},
    67  			},
    68  			Progress:      jobspb.SchemaChangeGCProgress{},
    69  			DescriptorIDs: []sqlbase.ID{42},
    70  		}
    71  	}
    72  	mkJobAndRecord := func() (j *jobs.Job, rec *ptpb.Record) {
    73  		ts := s0.Clock().Now()
    74  		require.NoError(t, s0.DB().Txn(ctx, func(ctx context.Context, txn *kv.Txn) (err error) {
    75  			if j, err = jr.CreateJobWithTxn(ctx, mkJobRec(), txn); err != nil {
    76  				return err
    77  			}
    78  			rec = jobsprotectedts.MakeRecord(uuid.MakeV4(), *j.ID(), ts, []roachpb.Span{{Key: keys.MinKey, EndKey: keys.MaxKey}})
    79  			return ptp.Protect(ctx, txn, rec)
    80  		}))
    81  		return j, rec
    82  	}
    83  	jMovedToFailed, recMovedToFailed := mkJobAndRecord()
    84  	require.NoError(t, s0.DB().Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
    85  		return jr.Failed(ctx, txn, *jMovedToFailed.ID(), io.ErrUnexpectedEOF)
    86  	}))
    87  	jFinished, recFinished := mkJobAndRecord()
    88  	require.NoError(t, s0.DB().Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
    89  		return jr.Succeeded(ctx, txn, *jFinished.ID())
    90  	}))
    91  	_, recRemains := mkJobAndRecord()
    92  	ensureNotExists := func(ctx context.Context, txn *kv.Txn, ptsID uuid.UUID) (err error) {
    93  		_, err = ptp.GetRecord(ctx, txn, ptsID)
    94  		if errors.Is(err, protectedts.ErrNotExists) {
    95  			return nil
    96  		}
    97  		return fmt.Errorf("waiting for %v, got %v", protectedts.ErrNotExists, err)
    98  	}
    99  	testutils.SucceedsSoon(t, func() (err error) {
   100  		return s0.DB().Txn(ctx, func(ctx context.Context, txn *kv.Txn) error {
   101  			if err := ensureNotExists(ctx, txn, recMovedToFailed.ID); err != nil {
   102  				return err
   103  			}
   104  			if err := ensureNotExists(ctx, txn, recFinished.ID); err != nil {
   105  				return err
   106  			}
   107  			_, err := ptp.GetRecord(ctx, txn, recRemains.ID)
   108  			require.NoError(t, err)
   109  			return err
   110  		})
   111  	})
   112  
   113  	// Verify that the two jobs we just observed as removed were recorded in the
   114  	// metrics.
   115  	var removed int
   116  	runner.QueryRow(t, `
   117  SELECT
   118      value
   119  FROM
   120      crdb_internal.node_metrics
   121  WHERE
   122      name = 'kv.protectedts.reconciliation.records_removed';
   123  `).Scan(&removed)
   124  	require.Equal(t, 2, removed)
   125  }