github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/kv/kvserver/rangefeed/registry_test.go (about) 1 // Copyright 2018 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 rangefeed 12 13 import ( 14 "context" 15 "fmt" 16 "testing" 17 18 _ "github.com/cockroachdb/cockroach/pkg/keys" // hook up pretty printer 19 "github.com/cockroachdb/cockroach/pkg/roachpb" 20 "github.com/cockroachdb/cockroach/pkg/storage" 21 "github.com/cockroachdb/cockroach/pkg/util/hlc" 22 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 23 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 24 "github.com/cockroachdb/cockroach/pkg/util/uuid" 25 "github.com/stretchr/testify/require" 26 ) 27 28 var ( 29 keyA, keyB = roachpb.Key("a"), roachpb.Key("b") 30 keyC, keyD = roachpb.Key("c"), roachpb.Key("d") 31 keyX, keyY = roachpb.Key("x"), roachpb.Key("y") 32 33 spAB = roachpb.Span{Key: keyA, EndKey: keyB} 34 spBC = roachpb.Span{Key: keyB, EndKey: keyC} 35 spCD = roachpb.Span{Key: keyC, EndKey: keyD} 36 spAC = roachpb.Span{Key: keyA, EndKey: keyC} 37 spXY = roachpb.Span{Key: keyX, EndKey: keyY} 38 ) 39 40 type testStream struct { 41 ctx context.Context 42 ctxDone func() 43 mu struct { 44 syncutil.Mutex 45 sendErr error 46 events []*roachpb.RangeFeedEvent 47 } 48 } 49 50 func newTestStream() *testStream { 51 ctx, done := context.WithCancel(context.Background()) 52 return &testStream{ctx: ctx, ctxDone: done} 53 } 54 55 func (s *testStream) Context() context.Context { 56 return s.ctx 57 } 58 59 func (s *testStream) Cancel() { 60 s.ctxDone() 61 } 62 63 func (s *testStream) Send(e *roachpb.RangeFeedEvent) error { 64 s.mu.Lock() 65 defer s.mu.Unlock() 66 if s.mu.sendErr != nil { 67 return s.mu.sendErr 68 } 69 s.mu.events = append(s.mu.events, e) 70 return nil 71 } 72 73 func (s *testStream) SetSendErr(err error) { 74 s.mu.Lock() 75 defer s.mu.Unlock() 76 s.mu.sendErr = err 77 } 78 79 func (s *testStream) Events() []*roachpb.RangeFeedEvent { 80 s.mu.Lock() 81 defer s.mu.Unlock() 82 es := s.mu.events 83 s.mu.events = nil 84 return es 85 } 86 87 func (s *testStream) BlockSend() func() { 88 s.mu.Lock() 89 return s.mu.Unlock 90 } 91 92 type testRegistration struct { 93 registration 94 stream *testStream 95 errC <-chan *roachpb.Error 96 } 97 98 func newTestRegistration( 99 span roachpb.Span, ts hlc.Timestamp, catchup storage.SimpleIterator, withDiff bool, 100 ) *testRegistration { 101 s := newTestStream() 102 errC := make(chan *roachpb.Error, 1) 103 return &testRegistration{ 104 registration: newRegistration( 105 span, 106 ts, 107 catchup, 108 withDiff, 109 5, 110 NewMetrics(), 111 s, 112 errC, 113 ), 114 stream: s, 115 errC: errC, 116 } 117 } 118 119 func (r *testRegistration) Events() []*roachpb.RangeFeedEvent { 120 return r.stream.Events() 121 } 122 123 func (r *testRegistration) Err() *roachpb.Error { 124 select { 125 case pErr := <-r.errC: 126 return pErr 127 default: 128 return nil 129 } 130 } 131 132 func TestRegistrationBasic(t *testing.T) { 133 defer leaktest.AfterTest(t)() 134 135 val := roachpb.Value{RawBytes: []byte("val"), Timestamp: hlc.Timestamp{WallTime: 1}} 136 ev1, ev2 := new(roachpb.RangeFeedEvent), new(roachpb.RangeFeedEvent) 137 ev1.MustSetValue(&roachpb.RangeFeedValue{Key: keyA, Value: val}) 138 ev2.MustSetValue(&roachpb.RangeFeedValue{Key: keyB, Value: val}) 139 140 // Registration with no catchup scan specified. 141 noCatchupReg := newTestRegistration(spAB, hlc.Timestamp{}, nil, false) 142 noCatchupReg.publish(ev1) 143 noCatchupReg.publish(ev2) 144 require.Equal(t, len(noCatchupReg.buf), 2) 145 go noCatchupReg.runOutputLoop(context.Background()) 146 require.NoError(t, noCatchupReg.waitForCaughtUp()) 147 require.Equal(t, []*roachpb.RangeFeedEvent{ev1, ev2}, noCatchupReg.stream.Events()) 148 noCatchupReg.disconnect(nil) 149 <-noCatchupReg.errC 150 151 // Registration with catchup scan. 152 catchupReg := newTestRegistration(spBC, hlc.Timestamp{WallTime: 1}, newTestIterator([]storage.MVCCKeyValue{ 153 makeKV("b", "val1", 10), 154 makeInline("ba", "val2"), 155 makeKV("bc", "val3", 11), 156 makeKV("bd", "val4", 9), 157 }), false) 158 catchupReg.publish(ev1) 159 catchupReg.publish(ev2) 160 require.Equal(t, len(catchupReg.buf), 2) 161 go catchupReg.runOutputLoop(context.Background()) 162 require.NoError(t, catchupReg.waitForCaughtUp()) 163 events := catchupReg.stream.Events() 164 require.Equal(t, 6, len(events)) 165 require.Equal(t, []*roachpb.RangeFeedEvent{ev1, ev2}, events[4:]) 166 catchupReg.disconnect(nil) 167 <-catchupReg.errC 168 169 // EXIT CONDITIONS 170 // External Disconnect. 171 disconnectReg := newTestRegistration(spAB, hlc.Timestamp{}, nil, false) 172 disconnectReg.publish(ev1) 173 disconnectReg.publish(ev2) 174 go disconnectReg.runOutputLoop(context.Background()) 175 require.NoError(t, disconnectReg.waitForCaughtUp()) 176 discErr := roachpb.NewError(fmt.Errorf("disconnection error")) 177 disconnectReg.disconnect(discErr) 178 err := <-disconnectReg.errC 179 require.Equal(t, discErr, err) 180 181 // Overflow. 182 overflowReg := newTestRegistration(spAB, hlc.Timestamp{}, nil, false) 183 for i := 0; i < cap(overflowReg.buf)+3; i++ { 184 overflowReg.publish(ev1) 185 } 186 go overflowReg.runOutputLoop(context.Background()) 187 err = <-overflowReg.errC 188 require.Equal(t, newErrBufferCapacityExceeded(), err) 189 require.Equal(t, cap(overflowReg.buf), len(overflowReg.Events())) 190 191 // Stream Error. 192 streamErrReg := newTestRegistration(spAB, hlc.Timestamp{}, nil, false) 193 streamErr := fmt.Errorf("stream error") 194 streamErrReg.stream.SetSendErr(streamErr) 195 go streamErrReg.runOutputLoop(context.Background()) 196 streamErrReg.publish(ev1) 197 err = <-streamErrReg.errC 198 require.Equal(t, streamErr.Error(), err.GoError().Error()) 199 200 // Stream Context Canceled. 201 streamCancelReg := newTestRegistration(spAB, hlc.Timestamp{}, nil, false) 202 streamCancelReg.stream.Cancel() 203 go streamCancelReg.runOutputLoop(context.Background()) 204 require.NoError(t, streamCancelReg.waitForCaughtUp()) 205 err = <-streamCancelReg.errC 206 require.Equal(t, streamCancelReg.stream.Context().Err().Error(), err.GoError().Error()) 207 } 208 209 func TestRegistrationCatchUpScan(t *testing.T) { 210 defer leaktest.AfterTest(t)() 211 212 // Run a catch-up scan for a registration over a test 213 // iterator with the following keys. 214 txn1, txn2 := uuid.MakeV4(), uuid.MakeV4() 215 iter := newTestIterator([]storage.MVCCKeyValue{ 216 makeKV("a", "valA1", 10), 217 makeInline("b", "valB1"), 218 makeIntent("c", txn1, "txnKeyC", 15), 219 makeProvisionalKV("c", "txnKeyC", 15), 220 makeKV("c", "valC2", 11), 221 makeKV("c", "valC1", 9), 222 makeIntent("d", txn2, "txnKeyD", 21), 223 makeProvisionalKV("d", "txnKeyD", 21), 224 makeKV("d", "valD5", 20), 225 makeKV("d", "valD4", 19), 226 makeKV("d", "valD3", 16), 227 makeKV("d", "valD2", 3), 228 makeKV("d", "valD1", 1), 229 makeKV("e", "valE3", 6), 230 makeKV("e", "valE2", 5), 231 makeKV("e", "valE1", 4), 232 makeKV("f", "valF3", 7), 233 makeKV("f", "valF2", 6), 234 makeKV("f", "valF1", 5), 235 makeInline("g", "valG1"), 236 makeKV("h", "valH1", 15), 237 makeKV("m", "valM1", 1), 238 makeIntent("n", txn1, "txnKeyN", 12), 239 makeProvisionalKV("n", "txnKeyN", 12), 240 makeIntent("r", txn1, "txnKeyR", 19), 241 makeProvisionalKV("r", "txnKeyR", 19), 242 makeKV("r", "valR1", 4), 243 makeIntent("w", txn1, "txnKeyW", 3), 244 makeProvisionalKV("w", "txnKeyW", 3), 245 makeInline("x", "valX1"), 246 makeIntent("z", txn2, "txnKeyZ", 21), 247 makeProvisionalKV("z", "txnKeyZ", 21), 248 makeKV("z", "valZ1", 4), 249 }) 250 r := newTestRegistration(roachpb.Span{ 251 Key: roachpb.Key("d"), 252 EndKey: roachpb.Key("w"), 253 }, hlc.Timestamp{WallTime: 4}, iter, true /* withDiff */) 254 255 require.Zero(t, r.metrics.RangeFeedCatchupScanNanos.Count()) 256 require.NoError(t, r.runCatchupScan()) 257 require.True(t, iter.closed) 258 require.NotZero(t, r.metrics.RangeFeedCatchupScanNanos.Count()) 259 260 // Compare the events sent on the registration's Stream to the expected events. 261 expEvents := []*roachpb.RangeFeedEvent{ 262 rangeFeedValueWithPrev( 263 roachpb.Key("d"), 264 roachpb.Value{RawBytes: []byte("valD3"), Timestamp: hlc.Timestamp{WallTime: 16}}, 265 roachpb.Value{RawBytes: []byte("valD2")}, 266 ), 267 rangeFeedValueWithPrev( 268 roachpb.Key("d"), 269 roachpb.Value{RawBytes: []byte("valD4"), Timestamp: hlc.Timestamp{WallTime: 19}}, 270 roachpb.Value{RawBytes: []byte("valD3")}, 271 ), 272 rangeFeedValueWithPrev( 273 roachpb.Key("d"), 274 roachpb.Value{RawBytes: []byte("valD5"), Timestamp: hlc.Timestamp{WallTime: 20}}, 275 roachpb.Value{RawBytes: []byte("valD4")}, 276 ), 277 rangeFeedValueWithPrev( 278 roachpb.Key("e"), 279 roachpb.Value{RawBytes: []byte("valE2"), Timestamp: hlc.Timestamp{WallTime: 5}}, 280 roachpb.Value{RawBytes: []byte("valE1")}, 281 ), 282 rangeFeedValueWithPrev( 283 roachpb.Key("e"), 284 roachpb.Value{RawBytes: []byte("valE3"), Timestamp: hlc.Timestamp{WallTime: 6}}, 285 roachpb.Value{RawBytes: []byte("valE2")}, 286 ), 287 rangeFeedValue( 288 roachpb.Key("f"), 289 roachpb.Value{RawBytes: []byte("valF1"), Timestamp: hlc.Timestamp{WallTime: 5}}, 290 ), 291 rangeFeedValueWithPrev( 292 roachpb.Key("f"), 293 roachpb.Value{RawBytes: []byte("valF2"), Timestamp: hlc.Timestamp{WallTime: 6}}, 294 roachpb.Value{RawBytes: []byte("valF1")}, 295 ), 296 rangeFeedValueWithPrev( 297 roachpb.Key("f"), 298 roachpb.Value{RawBytes: []byte("valF3"), Timestamp: hlc.Timestamp{WallTime: 7}}, 299 roachpb.Value{RawBytes: []byte("valF2")}, 300 ), 301 rangeFeedValue( 302 roachpb.Key("g"), 303 roachpb.Value{RawBytes: []byte("valG1"), Timestamp: hlc.Timestamp{WallTime: 0}}, 304 ), 305 rangeFeedValue( 306 roachpb.Key("h"), 307 roachpb.Value{RawBytes: []byte("valH1"), Timestamp: hlc.Timestamp{WallTime: 15}}, 308 ), 309 } 310 require.Equal(t, expEvents, r.Events()) 311 } 312 313 func TestRegistryBasic(t *testing.T) { 314 defer leaktest.AfterTest(t)() 315 316 val := roachpb.Value{RawBytes: []byte("val"), Timestamp: hlc.Timestamp{WallTime: 1}} 317 ev1, ev2 := new(roachpb.RangeFeedEvent), new(roachpb.RangeFeedEvent) 318 ev3, ev4 := new(roachpb.RangeFeedEvent), new(roachpb.RangeFeedEvent) 319 ev1.MustSetValue(&roachpb.RangeFeedValue{Key: keyA, Value: val, PrevValue: val}) 320 ev2.MustSetValue(&roachpb.RangeFeedValue{Key: keyB, Value: val, PrevValue: val}) 321 ev3.MustSetValue(&roachpb.RangeFeedValue{Key: keyC, Value: val, PrevValue: val}) 322 ev4.MustSetValue(&roachpb.RangeFeedValue{Key: keyD, Value: val, PrevValue: val}) 323 err1 := roachpb.NewErrorf("error1") 324 noPrev := func(ev *roachpb.RangeFeedEvent) *roachpb.RangeFeedEvent { 325 ev = ev.ShallowCopy() 326 ev.GetValue().(*roachpb.RangeFeedValue).PrevValue = roachpb.Value{} 327 return ev 328 } 329 330 reg := makeRegistry() 331 require.Equal(t, 0, reg.Len()) 332 require.NotPanics(t, func() { reg.PublishToOverlapping(spAB, ev1) }) 333 require.NotPanics(t, func() { reg.Disconnect(spAB) }) 334 require.NotPanics(t, func() { reg.DisconnectWithErr(spAB, err1) }) 335 336 rAB := newTestRegistration(spAB, hlc.Timestamp{}, nil, false /* withDiff */) 337 rBC := newTestRegistration(spBC, hlc.Timestamp{}, nil, true /* withDiff */) 338 rCD := newTestRegistration(spCD, hlc.Timestamp{}, nil, true /* withDiff */) 339 rAC := newTestRegistration(spAC, hlc.Timestamp{}, nil, false /* withDiff */) 340 go rAB.runOutputLoop(context.Background()) 341 go rBC.runOutputLoop(context.Background()) 342 go rCD.runOutputLoop(context.Background()) 343 go rAC.runOutputLoop(context.Background()) 344 defer rAB.disconnect(nil) 345 defer rBC.disconnect(nil) 346 defer rCD.disconnect(nil) 347 defer rAC.disconnect(nil) 348 349 // Register 4 registrations. 350 reg.Register(&rAB.registration) 351 require.Equal(t, 1, reg.Len()) 352 reg.Register(&rBC.registration) 353 require.Equal(t, 2, reg.Len()) 354 reg.Register(&rCD.registration) 355 require.Equal(t, 3, reg.Len()) 356 reg.Register(&rAC.registration) 357 require.Equal(t, 4, reg.Len()) 358 359 // Publish to different spans. 360 reg.PublishToOverlapping(spAB, ev1) 361 reg.PublishToOverlapping(spBC, ev2) 362 reg.PublishToOverlapping(spCD, ev3) 363 reg.PublishToOverlapping(spAC, ev4) 364 require.NoError(t, reg.waitForCaughtUp(all)) 365 require.Equal(t, []*roachpb.RangeFeedEvent{noPrev(ev1), noPrev(ev4)}, rAB.Events()) 366 require.Equal(t, []*roachpb.RangeFeedEvent{ev2, ev4}, rBC.Events()) 367 require.Equal(t, []*roachpb.RangeFeedEvent{ev3}, rCD.Events()) 368 require.Equal(t, []*roachpb.RangeFeedEvent{noPrev(ev1), noPrev(ev2), noPrev(ev4)}, rAC.Events()) 369 require.Nil(t, rAB.Err()) 370 require.Nil(t, rBC.Err()) 371 require.Nil(t, rCD.Err()) 372 require.Nil(t, rAC.Err()) 373 374 // Check the registry's operation filter. 375 f := reg.NewFilter() 376 // Testing NeedVal. 377 require.True(t, f.NeedVal(spAB)) 378 require.True(t, f.NeedVal(spBC)) 379 require.True(t, f.NeedVal(spCD)) 380 require.True(t, f.NeedVal(spAC)) 381 require.False(t, f.NeedVal(spXY)) 382 require.True(t, f.NeedVal(roachpb.Span{Key: keyA})) 383 require.True(t, f.NeedVal(roachpb.Span{Key: keyB})) 384 require.True(t, f.NeedVal(roachpb.Span{Key: keyC})) 385 require.False(t, f.NeedVal(roachpb.Span{Key: keyX})) 386 // Testing NeedPrevVal. 387 require.False(t, f.NeedPrevVal(spAB)) 388 require.True(t, f.NeedPrevVal(spBC)) 389 require.True(t, f.NeedPrevVal(spCD)) 390 require.True(t, f.NeedPrevVal(spAC)) 391 require.False(t, f.NeedPrevVal(spXY)) 392 require.False(t, f.NeedPrevVal(roachpb.Span{Key: keyA})) 393 require.True(t, f.NeedPrevVal(roachpb.Span{Key: keyB})) 394 require.True(t, f.NeedPrevVal(roachpb.Span{Key: keyC})) 395 require.False(t, f.NeedPrevVal(roachpb.Span{Key: keyX})) 396 397 // Disconnect span that overlaps with rCD. 398 reg.DisconnectWithErr(spCD, err1) 399 require.Equal(t, 3, reg.Len()) 400 require.Equal(t, err1.GoError(), rCD.Err().GoError()) 401 402 // Can still publish to rAB. 403 reg.PublishToOverlapping(spAB, ev4) 404 reg.PublishToOverlapping(spBC, ev3) 405 reg.PublishToOverlapping(spCD, ev2) 406 reg.PublishToOverlapping(spAC, ev1) 407 require.NoError(t, reg.waitForCaughtUp(all)) 408 require.Equal(t, []*roachpb.RangeFeedEvent{noPrev(ev4), noPrev(ev1)}, rAB.Events()) 409 410 // Disconnect from rAB without error. 411 reg.Disconnect(spAB) 412 require.Nil(t, rAC.Err()) 413 require.Nil(t, rAB.Err()) 414 require.Equal(t, 1, reg.Len()) 415 416 // Check the registry's operation filter again. 417 f = reg.NewFilter() 418 // Testing NeedVal. 419 require.False(t, f.NeedVal(spAB)) 420 require.True(t, f.NeedVal(spBC)) 421 require.False(t, f.NeedVal(spCD)) 422 require.True(t, f.NeedVal(spAC)) 423 require.False(t, f.NeedVal(spXY)) 424 require.False(t, f.NeedVal(roachpb.Span{Key: keyA})) 425 require.True(t, f.NeedVal(roachpb.Span{Key: keyB})) 426 require.False(t, f.NeedVal(roachpb.Span{Key: keyC})) 427 require.False(t, f.NeedVal(roachpb.Span{Key: keyX})) 428 // Testing NeedPrevVal. 429 require.False(t, f.NeedPrevVal(spAB)) 430 require.True(t, f.NeedPrevVal(spBC)) 431 require.False(t, f.NeedPrevVal(spCD)) 432 require.True(t, f.NeedPrevVal(spAC)) 433 require.False(t, f.NeedPrevVal(spXY)) 434 require.False(t, f.NeedPrevVal(roachpb.Span{Key: keyA})) 435 require.True(t, f.NeedPrevVal(roachpb.Span{Key: keyB})) 436 require.False(t, f.NeedPrevVal(roachpb.Span{Key: keyC})) 437 require.False(t, f.NeedPrevVal(roachpb.Span{Key: keyX})) 438 439 // Unregister the rBC registration. 440 reg.Unregister(&rBC.registration) 441 require.Equal(t, 0, reg.Len()) 442 } 443 444 func TestRegistryPublishAssertsPopulatedInformation(t *testing.T) { 445 defer leaktest.AfterTest(t)() 446 reg := makeRegistry() 447 448 rNoDiff := newTestRegistration(spAB, hlc.Timestamp{}, nil, false /* withDiff */) 449 go rNoDiff.runOutputLoop(context.Background()) 450 reg.Register(&rNoDiff.registration) 451 452 rWithDiff := newTestRegistration(spCD, hlc.Timestamp{}, nil, true /* withDiff */) 453 go rWithDiff.runOutputLoop(context.Background()) 454 reg.Register(&rWithDiff.registration) 455 456 key := roachpb.Key("a") 457 val := roachpb.Value{RawBytes: []byte("val"), Timestamp: hlc.Timestamp{WallTime: 1}} 458 noVal := roachpb.Value{Timestamp: hlc.Timestamp{WallTime: 1}} 459 ev := new(roachpb.RangeFeedEvent) 460 461 // Both registrations require RangeFeedValue events to have a Key. 462 ev.MustSetValue(&roachpb.RangeFeedValue{ 463 Key: nil, 464 Value: val, 465 PrevValue: val, 466 }) 467 require.Panics(t, func() { reg.PublishToOverlapping(spAB, ev) }) 468 require.Panics(t, func() { reg.PublishToOverlapping(spCD, ev) }) 469 require.NoError(t, reg.waitForCaughtUp(all)) 470 471 // Both registrations require RangeFeedValue events to have a Value. 472 ev.MustSetValue(&roachpb.RangeFeedValue{ 473 Key: key, 474 Value: noVal, 475 PrevValue: val, 476 }) 477 require.Panics(t, func() { reg.PublishToOverlapping(spAB, ev) }) 478 require.Panics(t, func() { reg.PublishToOverlapping(spCD, ev) }) 479 require.NoError(t, reg.waitForCaughtUp(all)) 480 481 // Neither registrations require RangeFeedValue events to have a PrevValue. 482 // Even when they are requested, the previous value can always be nil. 483 ev.MustSetValue(&roachpb.RangeFeedValue{ 484 Key: key, 485 Value: val, 486 PrevValue: roachpb.Value{}, 487 }) 488 require.NotPanics(t, func() { reg.PublishToOverlapping(spAB, ev) }) 489 require.NotPanics(t, func() { reg.PublishToOverlapping(spCD, ev) }) 490 require.NoError(t, reg.waitForCaughtUp(all)) 491 492 rNoDiff.disconnect(nil) 493 rWithDiff.disconnect(nil) 494 } 495 496 func TestRegistryPublishBeneathStartTimestamp(t *testing.T) { 497 defer leaktest.AfterTest(t)() 498 reg := makeRegistry() 499 500 r := newTestRegistration(spAB, hlc.Timestamp{WallTime: 10}, nil, false) 501 go r.runOutputLoop(context.Background()) 502 reg.Register(&r.registration) 503 504 // Publish a value with a timestamp beneath the registration's start 505 // timestamp. Should be ignored. 506 ev := new(roachpb.RangeFeedEvent) 507 ev.MustSetValue(&roachpb.RangeFeedValue{ 508 Value: roachpb.Value{Timestamp: hlc.Timestamp{WallTime: 5}}, 509 }) 510 reg.PublishToOverlapping(spAB, ev) 511 require.NoError(t, reg.waitForCaughtUp(all)) 512 require.Nil(t, r.Events()) 513 514 // Publish a value with a timestamp equal to the registration's start 515 // timestamp. Should be ignored. 516 ev.MustSetValue(&roachpb.RangeFeedValue{ 517 Value: roachpb.Value{Timestamp: hlc.Timestamp{WallTime: 10}}, 518 }) 519 reg.PublishToOverlapping(spAB, ev) 520 require.NoError(t, reg.waitForCaughtUp(all)) 521 require.Nil(t, r.Events()) 522 523 // Publish a checkpoint with a timestamp beneath the registration's. Should 524 // be delivered. 525 ev.MustSetValue(&roachpb.RangeFeedCheckpoint{ 526 Span: spAB, ResolvedTS: hlc.Timestamp{WallTime: 5}, 527 }) 528 reg.PublishToOverlapping(spAB, ev) 529 require.NoError(t, reg.waitForCaughtUp(all)) 530 require.Equal(t, []*roachpb.RangeFeedEvent{ev}, r.Events()) 531 532 r.disconnect(nil) 533 <-r.errC 534 } 535 536 func TestRegistrationString(t *testing.T) { 537 testCases := []struct { 538 r registration 539 exp string 540 }{ 541 { 542 r: registration{ 543 span: roachpb.Span{Key: roachpb.Key("a")}, 544 }, 545 exp: `[a @ 0,0+]`, 546 }, 547 { 548 r: registration{span: roachpb.Span{ 549 Key: roachpb.Key("a"), EndKey: roachpb.Key("c")}, 550 }, 551 exp: `[{a-c} @ 0,0+]`, 552 }, 553 { 554 r: registration{ 555 span: roachpb.Span{Key: roachpb.Key("d")}, 556 catchupTimestamp: hlc.Timestamp{WallTime: 10, Logical: 1}, 557 }, 558 exp: `[d @ 0.000000010,1+]`, 559 }, 560 { 561 r: registration{span: roachpb.Span{ 562 Key: roachpb.Key("d"), EndKey: roachpb.Key("z")}, 563 catchupTimestamp: hlc.Timestamp{WallTime: 40, Logical: 9}, 564 }, 565 exp: `[{d-z} @ 0.000000040,9+]`, 566 }, 567 } 568 for _, tc := range testCases { 569 require.Equal(t, tc.exp, tc.r.String()) 570 } 571 }