go.mercari.io/datastore@v1.8.2/dsmiddleware/rediscache/rediscache_test.go (about) 1 package rediscache 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "net" 8 "os" 9 "regexp" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/MakeNowJust/heredoc/v2" 15 "github.com/gomodule/redigo/redis" 16 "go.mercari.io/datastore" 17 "go.mercari.io/datastore/dsmiddleware/dslog" 18 "go.mercari.io/datastore/dsmiddleware/storagecache" 19 "go.mercari.io/datastore/internal/testutils" 20 "google.golang.org/api/iterator" 21 ) 22 23 func inCache(ctx context.Context, ch storagecache.Storage, key datastore.Key) (bool, error) { 24 resp, err := ch.GetMulti(ctx, []datastore.Key{key}) 25 if err != nil { 26 return false, err 27 } else if v := len(resp); v != 1 { 28 return false, nil 29 } else if v := resp[0]; v == nil { 30 return false, nil 31 } 32 33 return true, nil 34 } 35 36 func TestRedisCache_Basic(t *testing.T) { 37 ctx, client, cleanUp := testutils.SetupCloudDatastore(t) 38 defer cleanUp() 39 40 var logs []string 41 logf := func(ctx context.Context, format string, args ...interface{}) { 42 t.Logf(format, args...) 43 logs = append(logs, fmt.Sprintf(format, args...)) 44 } 45 46 // setup. strategies are first in - first apply. 47 48 bLog := dslog.NewLogger("before: ", logf) 49 client.AppendMiddleware(bLog) 50 defer func() { 51 // stop logging before cleanUp func called. 52 client.RemoveMiddleware(bLog) 53 }() 54 55 dial, err := net.Dial("tcp", os.Getenv("REDIS_HOST")+":"+os.Getenv("REDIS_PORT")) 56 if err != nil { 57 t.Fatal(err) 58 } 59 defer dial.Close() 60 conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) 61 defer conn.Close() 62 ch := New( 63 conn, 64 WithLogger(logf), 65 ) 66 client.AppendMiddleware(ch) 67 defer func() { 68 _, err := conn.Do("FLUSHALL") 69 if err != nil { 70 t.Fatal(err) 71 } 72 // stop logging before cleanUp func called. 73 client.RemoveMiddleware(ch) 74 }() 75 76 aLog := dslog.NewLogger("after: ", logf) 77 client.AppendMiddleware(aLog) 78 defer func() { 79 // stop logging before cleanUp func called. 80 client.RemoveMiddleware(aLog) 81 }() 82 83 // exec. 84 85 type Data struct { 86 Name string 87 } 88 89 // Put. add to cache. 90 key := client.IDKey("Data", 111, nil) 91 objBefore := &Data{Name: "Data"} 92 _, err = client.Put(ctx, key, objBefore) 93 if err != nil { 94 t.Fatal(err) 95 } 96 97 hit, err := inCache(ctx, ch, key) 98 if err != nil { 99 t.Fatal(err) 100 } else if v := hit; !v { 101 t.Fatalf("unexpected: %v", v) 102 } 103 104 // Get. from cache. 105 objAfter := &Data{} 106 err = client.Get(ctx, key, objAfter) 107 if err != nil { 108 t.Fatal(err) 109 } 110 111 // Delete. 112 err = client.Delete(ctx, key) 113 if err != nil { 114 t.Fatal(err) 115 } 116 117 hit, err = inCache(ctx, ch, key) 118 if err != nil { 119 t.Fatal(err) 120 } else if v := hit; v { 121 t.Fatalf("unexpected: %v", v) 122 } 123 124 expected := heredoc.Doc(` 125 before: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,111] 126 after: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,111] 127 after: PutMultiWithoutTx #1, keys=[/Data,111] 128 dsmiddleware/rediscache.SetMulti: incoming len=1 129 dsmiddleware/rediscache.SetMulti: len=1 130 before: PutMultiWithoutTx #1, keys=[/Data,111] 131 dsmiddleware/rediscache.GetMulti: incoming len=1 132 dsmiddleware/rediscache.GetMulti: hit=1 miss=0 133 before: GetMultiWithoutTx #2, len(keys)=1, keys=[/Data,111] 134 dsmiddleware/rediscache.GetMulti: incoming len=1 135 dsmiddleware/rediscache.GetMulti: hit=1 miss=0 136 before: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/Data,111] 137 after: DeleteMultiWithoutTx #2, len(keys)=1, keys=[/Data,111] 138 dsmiddleware/rediscache.DeleteMulti: incoming len=1 139 dsmiddleware/rediscache.GetMulti: incoming len=1 140 dsmiddleware/rediscache.GetMulti: hit=0 miss=1 141 `) 142 143 if v := strings.Join(logs, "\n") + "\n"; v != expected { 144 t.Errorf("unexpected: %v", v) 145 } 146 } 147 148 func TestRedisCache_BasicWithoutExpire(t *testing.T) { 149 ctx, client, cleanUp := testutils.SetupCloudDatastore(t) 150 defer cleanUp() 151 152 var logs []string 153 logf := func(ctx context.Context, format string, args ...interface{}) { 154 t.Logf(format, args...) 155 logs = append(logs, fmt.Sprintf(format, args...)) 156 } 157 158 // setup. strategies are first in - first apply. 159 160 bLog := dslog.NewLogger("before: ", logf) 161 client.AppendMiddleware(bLog) 162 defer func() { 163 // stop logging before cleanUp func called. 164 client.RemoveMiddleware(bLog) 165 }() 166 167 dial, err := net.Dial("tcp", os.Getenv("REDIS_HOST")+":"+os.Getenv("REDIS_PORT")) 168 if err != nil { 169 t.Fatal(err) 170 } 171 defer dial.Close() 172 conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) 173 defer conn.Close() 174 ch := New( 175 conn, 176 WithExpireDuration(0), 177 WithLogger(logf), 178 ) 179 client.AppendMiddleware(ch) 180 defer func() { 181 _, err := conn.Do("FLUSHALL") 182 if err != nil { 183 t.Fatal(err) 184 } 185 // stop logging before cleanUp func called. 186 client.RemoveMiddleware(ch) 187 }() 188 189 aLog := dslog.NewLogger("after: ", logf) 190 client.AppendMiddleware(aLog) 191 defer func() { 192 // stop logging before cleanUp func called. 193 client.RemoveMiddleware(aLog) 194 }() 195 196 // exec. 197 198 type Data struct { 199 Name string 200 } 201 202 // Put. add to cache. 203 key := client.IDKey("Data", 111, nil) 204 objBefore := &Data{Name: "Data"} 205 _, err = client.Put(ctx, key, objBefore) 206 if err != nil { 207 t.Fatal(err) 208 } 209 210 hit, err := inCache(ctx, ch, key) 211 if err != nil { 212 t.Fatal(err) 213 } else if v := hit; !v { 214 t.Fatalf("unexpected: %v", v) 215 } 216 217 // Get. from cache. 218 objAfter := &Data{} 219 err = client.Get(ctx, key, objAfter) 220 if err != nil { 221 t.Fatal(err) 222 } 223 224 // Delete. 225 err = client.Delete(ctx, key) 226 if err != nil { 227 t.Fatal(err) 228 } 229 230 hit, err = inCache(ctx, ch, key) 231 if err != nil { 232 t.Fatal(err) 233 } else if v := hit; v { 234 t.Fatalf("unexpected: %v", v) 235 } 236 237 expected := heredoc.Doc(` 238 before: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,111] 239 after: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,111] 240 after: PutMultiWithoutTx #1, keys=[/Data,111] 241 dsmiddleware/rediscache.SetMulti: incoming len=1 242 dsmiddleware/rediscache.SetMulti: len=1 243 before: PutMultiWithoutTx #1, keys=[/Data,111] 244 dsmiddleware/rediscache.GetMulti: incoming len=1 245 dsmiddleware/rediscache.GetMulti: hit=1 miss=0 246 before: GetMultiWithoutTx #2, len(keys)=1, keys=[/Data,111] 247 dsmiddleware/rediscache.GetMulti: incoming len=1 248 dsmiddleware/rediscache.GetMulti: hit=1 miss=0 249 before: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/Data,111] 250 after: DeleteMultiWithoutTx #2, len(keys)=1, keys=[/Data,111] 251 dsmiddleware/rediscache.DeleteMulti: incoming len=1 252 dsmiddleware/rediscache.GetMulti: incoming len=1 253 dsmiddleware/rediscache.GetMulti: hit=0 miss=1 254 `) 255 256 if v := strings.Join(logs, "\n") + "\n"; v != expected { 257 t.Errorf("unexpected: %v", v) 258 } 259 } 260 261 func TestRedisCache_Query(t *testing.T) { 262 ctx, client, cleanUp := testutils.SetupCloudDatastore(t) 263 defer cleanUp() 264 265 var logs []string 266 logf := func(ctx context.Context, format string, args ...interface{}) { 267 t.Logf(format, args...) 268 logs = append(logs, fmt.Sprintf(format, args...)) 269 } 270 271 // setup. strategies are first in - first apply. 272 273 bLog := dslog.NewLogger("before: ", logf) 274 client.AppendMiddleware(bLog) 275 defer func() { 276 // stop logging before cleanUp func called. 277 client.RemoveMiddleware(bLog) 278 }() 279 280 dial, err := net.Dial("tcp", os.Getenv("REDIS_HOST")+":"+os.Getenv("REDIS_PORT")) 281 if err != nil { 282 t.Fatal(err) 283 } 284 defer dial.Close() 285 conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) 286 defer conn.Close() 287 ch := New( 288 conn, 289 WithLogger(logf), 290 ) 291 client.AppendMiddleware(ch) 292 defer func() { 293 _, err := conn.Do("FLUSHALL") 294 if err != nil { 295 t.Fatal(err) 296 } 297 // stop logging before cleanUp func called. 298 client.RemoveMiddleware(ch) 299 }() 300 301 aLog := dslog.NewLogger("after: ", logf) 302 client.AppendMiddleware(aLog) 303 defer func() { 304 // stop logging before cleanUp func called. 305 client.RemoveMiddleware(aLog) 306 }() 307 308 // exec. 309 310 type Data struct { 311 Name string 312 } 313 314 const size = 3 315 316 keys := make([]datastore.Key, size) 317 list := make([]*Data, size) 318 for i := 0; i < size; i++ { 319 keys[i] = client.NameKey("Data", fmt.Sprintf("#%d", i+1), nil) 320 list[i] = &Data{ 321 Name: fmt.Sprintf("#%d", i+1), 322 } 323 } 324 _, err = client.PutMulti(ctx, keys, list) 325 if err != nil { 326 t.Fatal(err) 327 } 328 329 q := client.NewQuery("Data").Order("-Name") 330 331 // Run 332 iter := client.Run(ctx, q) 333 334 // Next 335 cnt := 0 336 for { 337 obj := &Data{} 338 key, err := iter.Next(obj) 339 if err == iterator.Done { 340 break 341 } else if err != nil { 342 t.Fatal(err) 343 } 344 if v := obj.Name; v == "" || v != key.Name() { 345 t.Errorf("unexpected: %v", cnt) 346 } 347 cnt++ 348 } 349 if cnt != size { 350 t.Errorf("unexpected: %v", cnt) 351 } 352 353 // GetAll 354 list = nil 355 _, err = client.GetAll(ctx, q, &list) 356 if err != nil { 357 t.Fatal(err) 358 } 359 360 expected := heredoc.Doc(` 361 before: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,#1, /Data,#2, /Data,#3] 362 after: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,#1, /Data,#2, /Data,#3] 363 after: PutMultiWithoutTx #1, keys=[/Data,#1, /Data,#2, /Data,#3] 364 dsmiddleware/rediscache.SetMulti: incoming len=3 365 dsmiddleware/rediscache.SetMulti: len=3 366 before: PutMultiWithoutTx #1, keys=[/Data,#1, /Data,#2, /Data,#3] 367 before: Run #2, q=v1:Data&or=-Name 368 after: Run #2, q=v1:Data&or=-Name 369 before: Next #3, q=v1:Data&or=-Name 370 after: Next #3, q=v1:Data&or=-Name 371 after: Next #3, key=/Data,#3 372 before: Next #3, key=/Data,#3 373 before: Next #4, q=v1:Data&or=-Name 374 after: Next #4, q=v1:Data&or=-Name 375 after: Next #4, key=/Data,#2 376 before: Next #4, key=/Data,#2 377 before: Next #5, q=v1:Data&or=-Name 378 after: Next #5, q=v1:Data&or=-Name 379 after: Next #5, key=/Data,#1 380 before: Next #5, key=/Data,#1 381 before: Next #6, q=v1:Data&or=-Name 382 after: Next #6, q=v1:Data&or=-Name 383 after: Next #6, err=no more items in iterator 384 before: Next #6, err=no more items in iterator 385 before: GetAll #7, q=v1:Data&or=-Name 386 after: GetAll #7, q=v1:Data&or=-Name 387 after: GetAll #7, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1] 388 before: GetAll #7, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1] 389 `) 390 391 if v := strings.Join(logs, "\n") + "\n"; v != expected { 392 t.Errorf("unexpected: %v", v) 393 } 394 } 395 396 func TestRedisCache_Transaction(t *testing.T) { 397 ctx, client, cleanUp := testutils.SetupCloudDatastore(t) 398 defer cleanUp() 399 400 var logs []string 401 logf := func(ctx context.Context, format string, args ...interface{}) { 402 t.Logf(format, args...) 403 logs = append(logs, fmt.Sprintf(format, args...)) 404 } 405 406 // setup. strategies are first in - first apply. 407 bLog := dslog.NewLogger("before: ", logf) 408 client.AppendMiddleware(bLog) 409 defer func() { 410 // stop logging before cleanUp func called. 411 client.RemoveMiddleware(bLog) 412 }() 413 414 dial, err := net.Dial("tcp", os.Getenv("REDIS_HOST")+":"+os.Getenv("REDIS_PORT")) 415 if err != nil { 416 t.Fatal(err) 417 } 418 defer dial.Close() 419 conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) 420 defer conn.Close() 421 ch := New( 422 conn, 423 WithLogger(logf), 424 ) 425 client.AppendMiddleware(ch) 426 defer func() { 427 _, err := conn.Do("FLUSHALL") 428 if err != nil { 429 t.Fatal(err) 430 } 431 // stop logging before cleanUp func called. 432 client.RemoveMiddleware(ch) 433 }() 434 435 aLog := dslog.NewLogger("after: ", logf) 436 client.AppendMiddleware(aLog) 437 defer func() { 438 // stop logging before cleanUp func called. 439 client.RemoveMiddleware(aLog) 440 }() 441 442 // exec. 443 444 type Data struct { 445 Name string 446 } 447 448 key := client.NameKey("Data", "a", nil) 449 450 // put to cache 451 _, err = client.Put(ctx, key, &Data{Name: "Before"}) 452 if err != nil { 453 t.Fatal(err) 454 } 455 hit, err := inCache(ctx, ch, key) 456 if err != nil { 457 t.Fatal(err) 458 } else if v := hit; !v { 459 t.Fatalf("unexpected: %v", v) 460 } 461 462 { // Rollback 463 tx, err := client.NewTransaction(ctx) 464 if err != nil { 465 t.Fatal(err) 466 } 467 468 // don't put to cache before commit 469 key2 := client.NameKey("Data", "b", nil) 470 _, err = tx.Put(key2, &Data{Name: "After"}) 471 if err != nil { 472 t.Fatal(err) 473 } 474 hit, err = inCache(ctx, ch, key2) 475 if err != nil { 476 t.Fatal(err) 477 } else if v := hit; v { 478 t.Fatalf("unexpected: %v", v) 479 } 480 481 obj := &Data{} 482 err = tx.Get(key, obj) 483 if err != nil { 484 t.Fatal(err) 485 } 486 487 // don't delete from cache before commit 488 err = tx.Delete(key) 489 if err != nil { 490 t.Fatal(err) 491 } 492 hit, err = inCache(ctx, ch, key) 493 if err != nil { 494 t.Fatal(err) 495 } else if v := hit; !v { 496 t.Fatalf("unexpected: %v", v) 497 } 498 499 // rollback. 500 err = tx.Rollback() 501 if err != nil { 502 t.Fatal(err) 503 } 504 } 505 506 { // Commit 507 tx, err := client.NewTransaction(ctx) 508 if err != nil { 509 t.Fatal(err) 510 } 511 512 // don't put to cache before commit 513 key2 := client.IncompleteKey("Data", nil) 514 pKey, err := tx.Put(key2, &Data{Name: "After"}) 515 if err != nil { 516 t.Fatal(err) 517 } 518 519 obj := &Data{} 520 err = tx.Get(key, obj) 521 if err != nil { 522 t.Fatal(err) 523 } 524 525 // don't delete from cache before commit 526 err = tx.Delete(key) 527 if err != nil { 528 t.Fatal(err) 529 } 530 hit, err = inCache(ctx, ch, key) 531 if err != nil { 532 t.Fatal(err) 533 } else if v := hit; !v { 534 t.Fatalf("unexpected: %v", v) 535 } 536 537 // commit. 538 commit, err := tx.Commit() 539 if err != nil { 540 t.Fatal(err) 541 } 542 543 key3 := commit.Key(pKey) 544 if v := key3.Name(); v != key2.Name() { 545 t.Errorf("unexpected: %v", v) 546 } 547 // committed, but don't put to cache in tx. 548 hit, err = inCache(ctx, ch, key3) 549 if err != nil { 550 t.Fatal(err) 551 } else if v := hit; v { 552 t.Fatalf("unexpected: %v", v) 553 } 554 } 555 556 var expected *regexp.Regexp 557 { 558 expectedPattern := heredoc.Doc(` 559 before: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,a] 560 after: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,a] 561 after: PutMultiWithoutTx #1, keys=[/Data,a] 562 dsmiddleware/rediscache.SetMulti: incoming len=1 563 dsmiddleware/rediscache.SetMulti: len=1 564 before: PutMultiWithoutTx #1, keys=[/Data,a] 565 dsmiddleware/rediscache.GetMulti: incoming len=1 566 dsmiddleware/rediscache.GetMulti: hit=1 miss=0 567 before: PutMultiWithTx #2, len(keys)=1, keys=[/Data,b] 568 after: PutMultiWithTx #2, len(keys)=1, keys=[/Data,b] 569 dsmiddleware/rediscache.GetMulti: incoming len=1 570 dsmiddleware/rediscache.GetMulti: hit=0 miss=1 571 before: GetMultiWithTx #3, len(keys)=1, keys=[/Data,a] 572 after: GetMultiWithTx #3, len(keys)=1, keys=[/Data,a] 573 before: DeleteMultiWithTx #4, len(keys)=1, keys=[/Data,a] 574 after: DeleteMultiWithTx #4, len(keys)=1, keys=[/Data,a] 575 dsmiddleware/rediscache.GetMulti: incoming len=1 576 dsmiddleware/rediscache.GetMulti: hit=1 miss=0 577 before: PostRollback #5 578 after: PostRollback #5 579 before: PutMultiWithTx #6, len(keys)=1, keys=[/Data,0] 580 after: PutMultiWithTx #6, len(keys)=1, keys=[/Data,0] 581 before: GetMultiWithTx #7, len(keys)=1, keys=[/Data,a] 582 after: GetMultiWithTx #7, len(keys)=1, keys=[/Data,a] 583 before: DeleteMultiWithTx #8, len(keys)=1, keys=[/Data,a] 584 after: DeleteMultiWithTx #8, len(keys)=1, keys=[/Data,a] 585 dsmiddleware/rediscache.GetMulti: incoming len=1 586 dsmiddleware/rediscache.GetMulti: hit=1 miss=0 587 before: PostCommit #9 Put keys=[/Data,@####@] 588 dsmiddleware/rediscache.DeleteMulti: incoming len=3 589 after: PostCommit #9 Put keys=[/Data,@####@] 590 dsmiddleware/rediscache.GetMulti: incoming len=1 591 dsmiddleware/rediscache.GetMulti: hit=0 miss=1 592 `) 593 ss := strings.Split(expectedPattern, "@####@") 594 var buf bytes.Buffer 595 for idx, s := range ss { 596 buf.WriteString(regexp.QuoteMeta(s)) 597 if idx != (len(ss) - 1) { 598 buf.WriteString("[0-9]+") 599 } 600 } 601 expected = regexp.MustCompile(buf.String()) 602 } 603 if v := strings.Join(logs, "\n") + "\n"; !expected.MatchString(v) { 604 t.Errorf("unexpected: %v", v) 605 } 606 } 607 608 func TestRedisCache_MultiError(t *testing.T) { 609 ctx, client, cleanUp := testutils.SetupCloudDatastore(t) 610 defer cleanUp() 611 612 var logs []string 613 logf := func(ctx context.Context, format string, args ...interface{}) { 614 t.Logf(format, args...) 615 logs = append(logs, fmt.Sprintf(format, args...)) 616 } 617 618 // setup. strategies are first in - first apply. 619 bLog := dslog.NewLogger("before: ", logf) 620 client.AppendMiddleware(bLog) 621 defer func() { 622 // stop logging before cleanUp func called. 623 client.RemoveMiddleware(bLog) 624 }() 625 626 dial, err := net.Dial("tcp", os.Getenv("REDIS_HOST")+":"+os.Getenv("REDIS_PORT")) 627 if err != nil { 628 t.Fatal(err) 629 } 630 defer dial.Close() 631 conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) 632 defer conn.Close() 633 ch := New( 634 conn, 635 WithLogger(logf), 636 ) 637 client.AppendMiddleware(ch) 638 defer func() { 639 _, err := conn.Do("FLUSHALL") 640 if err != nil { 641 t.Fatal(err) 642 } 643 // stop logging before cleanUp func called. 644 client.RemoveMiddleware(ch) 645 }() 646 647 aLog := dslog.NewLogger("after: ", logf) 648 client.AppendMiddleware(aLog) 649 defer func() { 650 // stop logging before cleanUp func called. 651 client.RemoveMiddleware(aLog) 652 }() 653 654 // exec. 655 656 type Data struct { 657 Name string 658 } 659 660 const size = 10 661 662 keys := make([]datastore.Key, 0, size) 663 list := make([]*Data, 0, size) 664 for i := 1; i <= size; i++ { 665 keys = append(keys, client.IDKey("Data", int64(i), nil)) 666 list = append(list, &Data{ 667 Name: fmt.Sprintf("#%d", i), 668 }) 669 } 670 671 _, err = client.PutMulti(ctx, keys, list) 672 if err != nil { 673 t.Fatal(err) 674 } 675 676 for _, key := range keys { 677 if key.ID()%2 == 0 { 678 // delete cache id=2, 4, 6, 8, 10 679 err := ch.DeleteMulti(ctx, []datastore.Key{key}) 680 if err != nil { 681 t.Fatal(err) 682 } 683 } 684 if key.ID()%3 == 0 { 685 // Delete entity where out of redis scope 686 // delete entity id=3, 6, 9 687 client.RemoveMiddleware(ch) 688 err := client.Delete(ctx, key) 689 if err != nil { 690 t.Fatal(err) 691 } 692 693 client.RemoveMiddleware(aLog) 694 client.AppendMiddleware(ch) 695 client.AppendMiddleware(aLog) 696 } 697 } 698 699 list = make([]*Data, size) 700 err = client.GetMulti(ctx, keys, list) 701 merr, ok := err.(datastore.MultiError) 702 if !ok { 703 t.Fatal(err) 704 } 705 706 if v := len(merr); v != size { 707 t.Fatalf("unexpected: %v", v) 708 } 709 for idx, err := range merr { 710 key := keys[idx] 711 if key.ID()%2 == 0 && key.ID()%3 == 0 { 712 // not exists on cache & datastore both 713 if err != datastore.ErrNoSuchEntity { 714 t.Error(err) 715 } 716 } else { 717 if v := list[idx].Name; v != fmt.Sprintf("#%d", idx+1) { 718 t.Errorf("unexpected: %v", v) 719 } 720 } 721 } 722 723 expected := heredoc.Doc(` 724 before: PutMultiWithoutTx #1, len(keys)=10, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5, /Data,6, /Data,7, /Data,8, /Data,9, /Data,10] 725 after: PutMultiWithoutTx #1, len(keys)=10, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5, /Data,6, /Data,7, /Data,8, /Data,9, /Data,10] 726 after: PutMultiWithoutTx #1, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5, /Data,6, /Data,7, /Data,8, /Data,9, /Data,10] 727 dsmiddleware/rediscache.SetMulti: incoming len=10 728 dsmiddleware/rediscache.SetMulti: len=10 729 before: PutMultiWithoutTx #1, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5, /Data,6, /Data,7, /Data,8, /Data,9, /Data,10] 730 dsmiddleware/rediscache.DeleteMulti: incoming len=1 731 before: DeleteMultiWithoutTx #2, len(keys)=1, keys=[/Data,3] 732 after: DeleteMultiWithoutTx #2, len(keys)=1, keys=[/Data,3] 733 dsmiddleware/rediscache.DeleteMulti: incoming len=1 734 dsmiddleware/rediscache.DeleteMulti: incoming len=1 735 before: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/Data,6] 736 after: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/Data,6] 737 dsmiddleware/rediscache.DeleteMulti: incoming len=1 738 before: DeleteMultiWithoutTx #4, len(keys)=1, keys=[/Data,9] 739 after: DeleteMultiWithoutTx #4, len(keys)=1, keys=[/Data,9] 740 dsmiddleware/rediscache.DeleteMulti: incoming len=1 741 before: GetMultiWithoutTx #5, len(keys)=10, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5, /Data,6, /Data,7, /Data,8, /Data,9, /Data,10] 742 dsmiddleware/rediscache.GetMulti: incoming len=10 743 dsmiddleware/rediscache.GetMulti: hit=5 miss=5 744 after: GetMultiWithoutTx #5, len(keys)=5, keys=[/Data,2, /Data,4, /Data,6, /Data,8, /Data,10] 745 after: GetMultiWithoutTx #5, err=datastore: no such entity 746 dsmiddleware/rediscache.SetMulti: incoming len=4 747 dsmiddleware/rediscache.SetMulti: len=4 748 before: GetMultiWithoutTx #5, err=datastore: no such entity 749 `) 750 751 if v := strings.Join(logs, "\n") + "\n"; v != expected { 752 t.Errorf("unexpected: %v", v) 753 } 754 }