github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/roachpb/api_test.go (about) 1 // Copyright 2014 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 roachpb 12 13 import ( 14 "reflect" 15 "testing" 16 17 "github.com/stretchr/testify/require" 18 ) 19 20 // TestCombineResponses tests the behavior of the CombineResponses function, 21 // which attempts to combine two provided responses. 22 func TestCombineResponses(t *testing.T) { 23 t.Run("both combinable", func(t *testing.T) { 24 left := &ScanResponse{ 25 Rows: []KeyValue{ 26 {Key: Key("A"), Value: MakeValueFromString("V")}, 27 }, 28 IntentRows: []KeyValue{ 29 {Key: Key("Ai"), Value: MakeValueFromString("X")}, 30 }, 31 } 32 right := &ScanResponse{ 33 Rows: []KeyValue{ 34 {Key: Key("B"), Value: MakeValueFromString("W")}, 35 }, 36 IntentRows: []KeyValue{ 37 {Key: Key("Bi"), Value: MakeValueFromString("Z")}, 38 }, 39 } 40 expCombined := &ScanResponse{ 41 Rows: append(append([]KeyValue(nil), left.Rows...), right.Rows...), 42 IntentRows: append(append([]KeyValue(nil), left.IntentRows...), right.IntentRows...), 43 } 44 45 err := CombineResponses(left, right) 46 require.NoError(t, err) 47 require.Equal(t, expCombined, left) 48 }) 49 50 t.Run("neither combinable", func(t *testing.T) { 51 left := &GetResponse{ 52 Value: &Value{RawBytes: []byte("V")}, 53 } 54 right := &GetResponse{ 55 Value: &Value{RawBytes: []byte("W")}, 56 } 57 expCombined := &GetResponse{ 58 Value: left.Value.ShallowClone(), 59 } 60 61 err := CombineResponses(left, right) 62 require.NoError(t, err) 63 require.Equal(t, expCombined, left) 64 }) 65 66 t.Run("left combinable", func(t *testing.T) { 67 left := &ScanResponse{ 68 Rows: []KeyValue{ 69 {Key: Key("A"), Value: MakeValueFromString("V")}, 70 }, 71 IntentRows: []KeyValue{ 72 {Key: Key("Ai"), Value: MakeValueFromString("X")}, 73 }, 74 } 75 right := &GetResponse{ 76 Value: &Value{RawBytes: []byte("W")}, 77 } 78 79 err := CombineResponses(left, right) 80 require.Error(t, err) 81 require.Regexp(t, "can not combine", err) 82 }) 83 84 t.Run("right combinable", func(t *testing.T) { 85 left := &GetResponse{ 86 Value: &Value{RawBytes: []byte("V")}, 87 } 88 right := &ScanResponse{ 89 Rows: []KeyValue{ 90 {Key: Key("B"), Value: MakeValueFromString("W")}, 91 }, 92 IntentRows: []KeyValue{ 93 {Key: Key("Bi"), Value: MakeValueFromString("Z")}, 94 }, 95 } 96 97 err := CombineResponses(left, right) 98 require.Error(t, err) 99 require.Regexp(t, "can not combine", err) 100 }) 101 } 102 103 // TestCombinable tests the correct behavior of some types that implement 104 // the combinable interface, notably {Scan,DeleteRange}Response and 105 // ResponseHeader. 106 func TestCombinable(t *testing.T) { 107 t.Run("Get", func(t *testing.T) { 108 // Test that GetResponse doesn't have anything to do with combinable. 109 if _, ok := interface{}(&GetResponse{}).(combinable); ok { 110 t.Fatalf("GetResponse implements combinable, so presumably all Response types will") 111 } 112 }) 113 114 t.Run("Scan", func(t *testing.T) { 115 116 // Test that {Scan,DeleteRange}Response properly implement it. 117 sr1 := &ScanResponse{ 118 Rows: []KeyValue{ 119 {Key: Key("A"), Value: MakeValueFromString("V")}, 120 }, 121 IntentRows: []KeyValue{ 122 {Key: Key("Ai"), Value: MakeValueFromString("X")}, 123 }, 124 } 125 126 if _, ok := interface{}(sr1).(combinable); !ok { 127 t.Fatalf("ScanResponse does not implement combinable") 128 } 129 130 sr2 := &ScanResponse{ 131 Rows: []KeyValue{ 132 {Key: Key("B"), Value: MakeValueFromString("W")}, 133 }, 134 IntentRows: []KeyValue{ 135 {Key: Key("Bi"), Value: MakeValueFromString("Z")}, 136 }, 137 } 138 139 wantedSR := &ScanResponse{ 140 Rows: append(append([]KeyValue(nil), sr1.Rows...), sr2.Rows...), 141 IntentRows: append(append([]KeyValue(nil), sr1.IntentRows...), sr2.IntentRows...), 142 } 143 144 if err := sr1.combine(sr2); err != nil { 145 t.Fatal(err) 146 } 147 if err := sr1.combine(&ScanResponse{}); err != nil { 148 t.Fatal(err) 149 } 150 151 if !reflect.DeepEqual(sr1, wantedSR) { 152 t.Errorf("wanted %v, got %v", wantedSR, sr1) 153 } 154 }) 155 156 t.Run("DeleteRange", func(t *testing.T) { 157 dr1 := &DeleteRangeResponse{ 158 Keys: []Key{[]byte("1")}, 159 } 160 if _, ok := interface{}(dr1).(combinable); !ok { 161 t.Fatalf("DeleteRangeResponse does not implement combinable") 162 } 163 dr2 := &DeleteRangeResponse{ 164 Keys: []Key{[]byte("2")}, 165 } 166 dr3 := &DeleteRangeResponse{ 167 Keys: nil, 168 } 169 wantedDR := &DeleteRangeResponse{ 170 Keys: []Key{[]byte("1"), []byte("2")}, 171 } 172 if err := dr2.combine(dr3); err != nil { 173 t.Fatal(err) 174 } 175 if err := dr1.combine(dr2); err != nil { 176 t.Fatal(err) 177 } 178 179 if !reflect.DeepEqual(dr1, wantedDR) { 180 t.Errorf("wanted %v, got %v", wantedDR, dr1) 181 } 182 }) 183 184 t.Run("AdminVerifyProtectedTimestamp", func(t *testing.T) { 185 v1 := &AdminVerifyProtectedTimestampResponse{ 186 ResponseHeader: ResponseHeader{}, 187 Verified: false, 188 FailedRanges: []RangeDescriptor{ 189 {RangeID: 1}, 190 }, 191 } 192 193 if _, ok := interface{}(v1).(combinable); !ok { 194 t.Fatal("AdminVerifyProtectedTimestampResponse unexpectedly does not implement combinable") 195 } 196 v2 := &AdminVerifyProtectedTimestampResponse{ 197 ResponseHeader: ResponseHeader{}, 198 Verified: true, 199 FailedRanges: nil, 200 } 201 v3 := &AdminVerifyProtectedTimestampResponse{ 202 ResponseHeader: ResponseHeader{}, 203 Verified: false, 204 FailedRanges: []RangeDescriptor{ 205 {RangeID: 2}, 206 }, 207 } 208 require.NoError(t, v1.combine(v2)) 209 require.NoError(t, v1.combine(v3)) 210 require.EqualValues(t, &AdminVerifyProtectedTimestampResponse{ 211 Verified: false, 212 FailedRanges: []RangeDescriptor{ 213 {RangeID: 1}, 214 {RangeID: 2}, 215 }, 216 }, v1) 217 218 }) 219 } 220 221 // TestMustSetInner makes sure that calls to MustSetInner correctly reset the 222 // union before repopulating to avoid having more than one value set. 223 func TestMustSetInner(t *testing.T) { 224 req := RequestUnion{} 225 res := ResponseUnion{} 226 227 // GetRequest is checked first in the generated code for SetInner. 228 req.MustSetInner(&GetRequest{}) 229 res.MustSetInner(&GetResponse{}) 230 req.MustSetInner(&EndTxnRequest{}) 231 res.MustSetInner(&EndTxnResponse{}) 232 233 if m := req.GetInner().Method(); m != EndTxn { 234 t.Fatalf("unexpected request: %s in %+v", m, req) 235 } 236 if _, isET := res.GetInner().(*EndTxnResponse); !isET { 237 t.Fatalf("unexpected response union: %+v", res) 238 } 239 }