github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/replica_command_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 kvserver 12 13 import ( 14 "context" 15 "encoding/binary" 16 "testing" 17 18 "github.com/cockroachdb/cockroach/pkg/base" 19 "github.com/cockroachdb/cockroach/pkg/keys" 20 "github.com/cockroachdb/cockroach/pkg/roachpb" 21 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 22 "github.com/cockroachdb/cockroach/pkg/util/hlc" 23 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 24 "github.com/stretchr/testify/require" 25 ) 26 27 // Regression test for #38308. Summary: a non-nullable field was added to 28 // RangeDescriptor which broke splits, merges, and replica changes if the 29 // cluster had been upgraded from a previous version of cockroach. 30 func TestRangeDescriptorUpdateProtoChangedAcrossVersions(t *testing.T) { 31 defer leaktest.AfterTest(t)() 32 33 // Control our own split destiny. 34 args := base.TestServerArgs{Knobs: base.TestingKnobs{Store: &StoreTestingKnobs{ 35 DisableSplitQueue: true, 36 DisableMergeQueue: true, 37 }}} 38 ctx := context.Background() 39 s, _, kvDB := serverutils.StartServer(t, args) 40 defer s.Stopper().Stop(ctx) 41 42 bKey := roachpb.Key("b") 43 if err := kvDB.AdminSplit(ctx, bKey, bKey, hlc.MaxTimestamp /* expirationTime */); err != nil { 44 t.Fatal(err) 45 } 46 47 // protoVarintField returns an encoded proto field of type varint with the 48 // given id. 49 protoVarintField := func(fieldID int) []byte { 50 var scratch [binary.MaxVarintLen64]byte 51 const typ = 0 // varint type field 52 tag := uint64(fieldID<<3) | typ 53 tagLen := binary.PutUvarint(scratch[:], tag) 54 // A proto message is a series of <tag><data> where <tag> is a varint 55 // including the field id and the data type and <data> depends on the type. 56 buf := append([]byte(nil), scratch[:tagLen]...) 57 // The test doesn't care what we use for the field data, so use the tag 58 // since the data is a varint and it's already an encoded varint. 59 buf = append(buf, scratch[:tagLen]...) 60 return buf 61 } 62 63 // Update the serialized RangeDescriptor proto for the b to max range to have 64 // an unknown proto field. Previously, this would break splits, merges, 65 // replica changes. The real regression was a missing field, but an extra 66 // unknown field tests the same thing. 67 { 68 bDescKey := keys.RangeDescriptorKey(roachpb.RKey(bKey)) 69 bDescKV, err := kvDB.Get(ctx, bDescKey) 70 require.NoError(t, err) 71 require.NotNil(t, bDescKV.Value, `could not find "b" descriptor`) 72 73 // Update the serialized proto with a new field we don't know about. The 74 // proto encoding is just a series of these, so we can do this simply by 75 // appending it. 76 newBDescBytes, err := bDescKV.Value.GetBytes() 77 require.NoError(t, err) 78 newBDescBytes = append(newBDescBytes, protoVarintField(9999)...) 79 80 newBDescValue := roachpb.MakeValueFromBytes(newBDescBytes) 81 require.NoError(t, kvDB.Put(ctx, bDescKey, &newBDescValue)) 82 } 83 84 // Verify that splits still work. We could also do a similar thing to test 85 // merges and replica changes, but they all go through updateRangeDescriptor 86 // so it's unnecessary. 87 cKey := roachpb.Key("c") 88 if err := kvDB.AdminSplit(ctx, cKey, cKey, hlc.MaxTimestamp /* expirationTime */); err != nil { 89 t.Fatal(err) 90 } 91 }