go.mercari.io/datastore@v1.8.2/testsuite/dsmiddleware/localcache/localcache.go (about) 1 package localcache 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "regexp" 8 "strings" 9 "testing" 10 11 "github.com/MakeNowJust/heredoc/v2" 12 "go.mercari.io/datastore" 13 "go.mercari.io/datastore/dsmiddleware/dslog" 14 "go.mercari.io/datastore/dsmiddleware/localcache" 15 "go.mercari.io/datastore/testsuite" 16 "google.golang.org/api/iterator" 17 ) 18 19 // TestSuite contains all the test cases that this package provides. 20 var TestSuite = map[string]testsuite.Test{ 21 "LocalCache_Basic": basic, 22 "LocalCache_WithIncludeKinds": withIncludeKinds, 23 "LocalCache_WithExcludeKinds": withExcludeKinds, 24 "LocalCache_WithKeyFilter": withKeyFilter, 25 "LocalCache_FlushLocalCache": flushLocalCache, 26 "LocalCache_Query": query, 27 "LocalCache_Transaction": transaction, 28 } 29 30 func init() { 31 testsuite.MergeTestSuite(TestSuite) 32 } 33 34 func basic(ctx context.Context, t *testing.T, client datastore.Client) { 35 defer func() { 36 err := client.Close() 37 if err != nil { 38 t.Fatal(err) 39 } 40 }() 41 42 var logs []string 43 logf := func(ctx context.Context, format string, args ...interface{}) { 44 t.Logf(format, args...) 45 logs = append(logs, fmt.Sprintf(format, args...)) 46 } 47 48 // setup. strategies are first in - first apply. 49 50 bLog := dslog.NewLogger("before: ", logf) 51 client.AppendMiddleware(bLog) 52 defer func() { 53 // stop logging before cleanUp func called. 54 client.RemoveMiddleware(bLog) 55 }() 56 57 ch := localcache.New() 58 client.AppendMiddleware(ch) 59 defer func() { 60 // stop logging before cleanUp func called. 61 client.RemoveMiddleware(ch) 62 }() 63 64 aLog := dslog.NewLogger("after: ", logf) 65 client.AppendMiddleware(aLog) 66 defer func() { 67 // stop logging before cleanUp func called. 68 client.RemoveMiddleware(aLog) 69 }() 70 71 // exec. 72 73 type Data struct { 74 Name string 75 } 76 77 // Put. add to dsmiddleware. 78 key := client.IDKey("Data", 111, nil) 79 objBefore := &Data{Name: "Data"} 80 _, err := client.Put(ctx, key, objBefore) 81 if err != nil { 82 t.Fatal(err) 83 } 84 85 if v := ch.HasCache(key); !v { 86 t.Fatalf("unexpected: %v", v) 87 } 88 89 // Get. from dsmiddleware. 90 objAfter := &Data{} 91 err = client.Get(ctx, key, objAfter) 92 if err != nil { 93 t.Fatal(err) 94 } 95 96 // Delete. 97 err = client.Delete(ctx, key) 98 if err != nil { 99 t.Fatal(err) 100 } 101 102 if v := ch.HasCache(key); v { 103 t.Fatalf("unexpected: %v", v) 104 } 105 106 expected := heredoc.Doc(` 107 before: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,111] 108 after: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,111] 109 after: PutMultiWithoutTx #1, keys=[/Data,111] 110 before: PutMultiWithoutTx #1, keys=[/Data,111] 111 before: GetMultiWithoutTx #2, len(keys)=1, keys=[/Data,111] 112 before: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/Data,111] 113 after: DeleteMultiWithoutTx #2, len(keys)=1, keys=[/Data,111] 114 `) 115 116 if v := strings.Join(logs, "\n") + "\n"; v != expected { 117 t.Errorf("unexpected: %v", v) 118 } 119 } 120 121 func withIncludeKinds(ctx context.Context, t *testing.T, client datastore.Client) { 122 defer func() { 123 err := client.Close() 124 if err != nil { 125 t.Fatal(err) 126 } 127 }() 128 129 var logs []string 130 logf := func(ctx context.Context, format string, args ...interface{}) { 131 t.Logf(format, args...) 132 logs = append(logs, fmt.Sprintf(format, args...)) 133 } 134 135 // setup. strategies are first in - first apply. 136 137 bLog := dslog.NewLogger("before: ", logf) 138 client.AppendMiddleware(bLog) 139 defer func() { 140 // stop logging before cleanUp func called. 141 client.RemoveMiddleware(bLog) 142 }() 143 144 ch := localcache.New( 145 localcache.WithIncludeKinds("DataA"), 146 localcache.WithLogger(logf), 147 ) 148 client.AppendMiddleware(ch) 149 defer func() { 150 // stop logging before cleanUp func called. 151 client.RemoveMiddleware(ch) 152 }() 153 154 aLog := dslog.NewLogger("after: ", logf) 155 client.AppendMiddleware(aLog) 156 defer func() { 157 // stop logging before cleanUp func called. 158 client.RemoveMiddleware(aLog) 159 }() 160 161 // exec. 162 163 type Data struct { 164 Name string 165 } 166 167 { // Put. dsmiddleware target. 168 key := client.IDKey("DataA", 111, nil) 169 objBefore := &Data{Name: "A"} 170 _, err := client.Put(ctx, key, objBefore) 171 if err != nil { 172 t.Fatal(err) 173 } 174 175 obj := &Data{} 176 err = client.Get(ctx, key, obj) 177 if err != nil { 178 t.Fatal(err) 179 } 180 if v := obj.Name; v != "A" { 181 t.Errorf("unexpected: %v", v) 182 } 183 184 err = client.Delete(ctx, key) 185 if err != nil { 186 t.Fatal(err) 187 } 188 } 189 { // Put. dsmiddleware ignored. 190 key := client.IDKey("DataB", 111, nil) 191 objBefore := &Data{Name: "B"} 192 _, err := client.Put(ctx, key, objBefore) 193 if err != nil { 194 t.Fatal(err) 195 } 196 197 obj := &Data{} 198 err = client.Get(ctx, key, obj) 199 if err != nil { 200 t.Fatal(err) 201 } 202 if v := obj.Name; v != "B" { 203 t.Errorf("unexpected: %v", v) 204 } 205 206 err = client.Delete(ctx, key) 207 if err != nil { 208 t.Fatal(err) 209 } 210 } 211 { // Put. dsmiddleware target & ignored. 212 keyInc := client.IDKey("DataA", 111, nil) 213 keyExc := client.IDKey("DataB", 111, nil) 214 215 list := []*Data{{Name: "A"}, {Name: "B"}} 216 _, err := client.PutMulti(ctx, []datastore.Key{keyInc, keyExc}, list) 217 if err != nil { 218 t.Fatal(err) 219 } 220 221 list = make([]*Data, 2) 222 err = client.GetMulti(ctx, []datastore.Key{keyInc, keyExc}, list) 223 if err != nil { 224 t.Fatal(err) 225 } 226 if v := len(list); v != 2 { 227 t.Fatalf("unexpected: %v", v) 228 } 229 if v := list[0].Name; v != "A" { 230 t.Errorf("unexpected: %v", v) 231 } 232 if v := list[1].Name; v != "B" { 233 t.Errorf("unexpected: %v", v) 234 } 235 236 err = client.DeleteMulti(ctx, []datastore.Key{keyInc, keyExc}) 237 if err != nil { 238 t.Fatal(err) 239 } 240 } 241 { // Put. partially hit 242 keyIncA := client.IDKey("DataA", 111, nil) 243 keyIncB := client.IDKey("DataA", 222, nil) 244 keyExcA := client.IDKey("DataB", 111, nil) 245 keyExcB := client.IDKey("DataB", 222, nil) 246 247 list := []*Data{{Name: "A1"}, {Name: "A2"}, {Name: "B1"}, {Name: "B2"}} 248 _, err := client.PutMulti(ctx, []datastore.Key{keyIncA, keyIncB, keyExcA, keyExcB}, list) 249 if err != nil { 250 t.Fatal(err) 251 } 252 253 ch.DeleteCache(ctx, keyIncB) 254 ch.DeleteCache(ctx, keyExcB) 255 256 list = make([]*Data, 4) 257 err = client.GetMulti(ctx, []datastore.Key{keyIncA, keyIncB, keyExcA, keyExcB}, list) 258 if err != nil { 259 t.Fatal(err) 260 } 261 if v := len(list); v != 4 { 262 t.Fatalf("unexpected: %v", v) 263 } 264 if v := list[0].Name; v != "A1" { 265 t.Errorf("unexpected: %v", v) 266 } 267 if v := list[1].Name; v != "A2" { 268 t.Errorf("unexpected: %v", v) 269 } 270 if v := list[2].Name; v != "B1" { 271 t.Errorf("unexpected: %v", v) 272 } 273 if v := list[3].Name; v != "B2" { 274 t.Errorf("unexpected: %v", v) 275 } 276 277 err = client.DeleteMulti(ctx, []datastore.Key{keyIncA, keyIncB, keyExcA, keyExcB}) 278 if err != nil { 279 t.Fatal(err) 280 } 281 } 282 283 expected := heredoc.Doc(` 284 before: PutMultiWithoutTx #1, len(keys)=1, keys=[/DataA,111] 285 after: PutMultiWithoutTx #1, len(keys)=1, keys=[/DataA,111] 286 after: PutMultiWithoutTx #1, keys=[/DataA,111] 287 dsmiddleware/localcache.SetMulti: len=1 288 dsmiddleware/localcache.SetMulti: idx=0 key=/DataA,111 len(ps)=1 289 before: PutMultiWithoutTx #1, keys=[/DataA,111] 290 before: GetMultiWithoutTx #2, len(keys)=1, keys=[/DataA,111] 291 dsmiddleware/localcache.GetMulti: len=1 292 dsmiddleware/localcache.GetMulti: idx=0 key=/DataA,111 293 dsmiddleware/localcache.GetMulti: idx=0, hit key=/DataA,111 len(ps)=1 294 before: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/DataA,111] 295 after: DeleteMultiWithoutTx #2, len(keys)=1, keys=[/DataA,111] 296 dsmiddleware/localcache.DeleteMulti: len=1 297 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataA,111 298 before: PutMultiWithoutTx #4, len(keys)=1, keys=[/DataB,111] 299 after: PutMultiWithoutTx #3, len(keys)=1, keys=[/DataB,111] 300 after: PutMultiWithoutTx #3, keys=[/DataB,111] 301 before: PutMultiWithoutTx #4, keys=[/DataB,111] 302 before: GetMultiWithoutTx #5, len(keys)=1, keys=[/DataB,111] 303 after: GetMultiWithoutTx #4, len(keys)=1, keys=[/DataB,111] 304 before: DeleteMultiWithoutTx #6, len(keys)=1, keys=[/DataB,111] 305 after: DeleteMultiWithoutTx #5, len(keys)=1, keys=[/DataB,111] 306 before: PutMultiWithoutTx #7, len(keys)=2, keys=[/DataA,111, /DataB,111] 307 after: PutMultiWithoutTx #6, len(keys)=2, keys=[/DataA,111, /DataB,111] 308 after: PutMultiWithoutTx #6, keys=[/DataA,111, /DataB,111] 309 dsmiddleware/localcache.SetMulti: len=1 310 dsmiddleware/localcache.SetMulti: idx=0 key=/DataA,111 len(ps)=1 311 before: PutMultiWithoutTx #7, keys=[/DataA,111, /DataB,111] 312 before: GetMultiWithoutTx #8, len(keys)=2, keys=[/DataA,111, /DataB,111] 313 dsmiddleware/localcache.GetMulti: len=1 314 dsmiddleware/localcache.GetMulti: idx=0 key=/DataA,111 315 dsmiddleware/localcache.GetMulti: idx=0, hit key=/DataA,111 len(ps)=1 316 after: GetMultiWithoutTx #7, len(keys)=1, keys=[/DataB,111] 317 before: DeleteMultiWithoutTx #9, len(keys)=2, keys=[/DataA,111, /DataB,111] 318 after: DeleteMultiWithoutTx #8, len(keys)=2, keys=[/DataA,111, /DataB,111] 319 dsmiddleware/localcache.DeleteMulti: len=1 320 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataA,111 321 before: PutMultiWithoutTx #10, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 322 after: PutMultiWithoutTx #9, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 323 after: PutMultiWithoutTx #9, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 324 dsmiddleware/localcache.SetMulti: len=2 325 dsmiddleware/localcache.SetMulti: idx=0 key=/DataA,111 len(ps)=1 326 dsmiddleware/localcache.SetMulti: idx=1 key=/DataA,222 len(ps)=1 327 before: PutMultiWithoutTx #10, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 328 dsmiddleware/localcache.DeleteCache: key=/DataA,222 329 dsmiddleware/localcache.DeleteCache: key=/DataB,222 330 before: GetMultiWithoutTx #11, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 331 dsmiddleware/localcache.GetMulti: len=2 332 dsmiddleware/localcache.GetMulti: idx=0 key=/DataA,111 333 dsmiddleware/localcache.GetMulti: idx=1 key=/DataA,222 334 dsmiddleware/localcache.GetMulti: idx=0, hit key=/DataA,111 len(ps)=1 335 dsmiddleware/localcache.GetMulti: idx=1, missed key=/DataA,222 336 after: GetMultiWithoutTx #10, len(keys)=3, keys=[/DataA,222, /DataB,111, /DataB,222] 337 dsmiddleware/localcache.SetMulti: len=1 338 dsmiddleware/localcache.SetMulti: idx=0 key=/DataA,222 len(ps)=1 339 before: DeleteMultiWithoutTx #12, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 340 after: DeleteMultiWithoutTx #11, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 341 dsmiddleware/localcache.DeleteMulti: len=2 342 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataA,111 343 dsmiddleware/localcache.DeleteMulti: idx=1 key=/DataA,222 344 `) 345 346 if v := strings.Join(logs, "\n") + "\n"; v != expected { 347 t.Errorf("unexpected: %v", v) 348 } 349 } 350 351 func withExcludeKinds(ctx context.Context, t *testing.T, client datastore.Client) { 352 defer func() { 353 err := client.Close() 354 if err != nil { 355 t.Fatal(err) 356 } 357 }() 358 359 var logs []string 360 logf := func(ctx context.Context, format string, args ...interface{}) { 361 t.Logf(format, args...) 362 logs = append(logs, fmt.Sprintf(format, args...)) 363 } 364 365 // setup. strategies are first in - first apply. 366 367 bLog := dslog.NewLogger("before: ", logf) 368 client.AppendMiddleware(bLog) 369 defer func() { 370 // stop logging before cleanUp func called. 371 client.RemoveMiddleware(bLog) 372 }() 373 374 ch := localcache.New( 375 localcache.WithExcludeKinds("DataA"), 376 localcache.WithLogger(logf), 377 ) 378 client.AppendMiddleware(ch) 379 defer func() { 380 // stop logging before cleanUp func called. 381 client.RemoveMiddleware(ch) 382 }() 383 384 aLog := dslog.NewLogger("after: ", logf) 385 client.AppendMiddleware(aLog) 386 defer func() { 387 // stop logging before cleanUp func called. 388 client.RemoveMiddleware(aLog) 389 }() 390 391 // exec. 392 393 type Data struct { 394 Name string 395 } 396 397 { // Put. ignored kind. 398 key := client.IDKey("DataA", 111, nil) 399 objBefore := &Data{Name: "A"} 400 _, err := client.Put(ctx, key, objBefore) 401 if err != nil { 402 t.Fatal(err) 403 } 404 405 obj := &Data{} 406 err = client.Get(ctx, key, obj) 407 if err != nil { 408 t.Fatal(err) 409 } 410 if v := obj.Name; v != "A" { 411 t.Errorf("unexpected: %v", v) 412 } 413 414 err = client.Delete(ctx, key) 415 if err != nil { 416 t.Fatal(err) 417 } 418 } 419 { // Put. dsmiddleware ignored. 420 key := client.IDKey("DataB", 111, nil) 421 objBefore := &Data{Name: "B"} 422 _, err := client.Put(ctx, key, objBefore) 423 if err != nil { 424 t.Fatal(err) 425 } 426 427 obj := &Data{} 428 err = client.Get(ctx, key, obj) 429 if err != nil { 430 t.Fatal(err) 431 } 432 if v := obj.Name; v != "B" { 433 t.Errorf("unexpected: %v", v) 434 } 435 436 err = client.Delete(ctx, key) 437 if err != nil { 438 t.Fatal(err) 439 } 440 } 441 { // Put. dsmiddleware target & ignored. 442 keyInc := client.IDKey("DataA", 111, nil) 443 keyExc := client.IDKey("DataB", 111, nil) 444 445 list := []*Data{{Name: "A"}, {Name: "B"}} 446 _, err := client.PutMulti(ctx, []datastore.Key{keyInc, keyExc}, list) 447 if err != nil { 448 t.Fatal(err) 449 } 450 451 list = make([]*Data, 2) 452 err = client.GetMulti(ctx, []datastore.Key{keyInc, keyExc}, list) 453 if err != nil { 454 t.Fatal(err) 455 } 456 if v := len(list); v != 2 { 457 t.Fatalf("unexpected: %v", v) 458 } 459 if v := list[0].Name; v != "A" { 460 t.Errorf("unexpected: %v", v) 461 } 462 if v := list[1].Name; v != "B" { 463 t.Errorf("unexpected: %v", v) 464 } 465 466 err = client.DeleteMulti(ctx, []datastore.Key{keyInc, keyExc}) 467 if err != nil { 468 t.Fatal(err) 469 } 470 } 471 { // Put. partially hit 472 keyIncA := client.IDKey("DataA", 111, nil) 473 keyIncB := client.IDKey("DataA", 222, nil) 474 keyExcA := client.IDKey("DataB", 111, nil) 475 keyExcB := client.IDKey("DataB", 222, nil) 476 477 list := []*Data{{Name: "A1"}, {Name: "A2"}, {Name: "B1"}, {Name: "B2"}} 478 _, err := client.PutMulti(ctx, []datastore.Key{keyIncA, keyIncB, keyExcA, keyExcB}, list) 479 if err != nil { 480 t.Fatal(err) 481 } 482 483 ch.DeleteCache(ctx, keyIncB) 484 ch.DeleteCache(ctx, keyExcB) 485 486 list = make([]*Data, 4) 487 err = client.GetMulti(ctx, []datastore.Key{keyIncA, keyIncB, keyExcA, keyExcB}, list) 488 if err != nil { 489 t.Fatal(err) 490 } 491 if v := len(list); v != 4 { 492 t.Fatalf("unexpected: %v", v) 493 } 494 if v := list[0].Name; v != "A1" { 495 t.Errorf("unexpected: %v", v) 496 } 497 if v := list[1].Name; v != "A2" { 498 t.Errorf("unexpected: %v", v) 499 } 500 if v := list[2].Name; v != "B1" { 501 t.Errorf("unexpected: %v", v) 502 } 503 if v := list[3].Name; v != "B2" { 504 t.Errorf("unexpected: %v", v) 505 } 506 507 err = client.DeleteMulti(ctx, []datastore.Key{keyIncA, keyIncB, keyExcA, keyExcB}) 508 if err != nil { 509 t.Fatal(err) 510 } 511 } 512 513 expected := heredoc.Doc(` 514 before: PutMultiWithoutTx #1, len(keys)=1, keys=[/DataA,111] 515 after: PutMultiWithoutTx #1, len(keys)=1, keys=[/DataA,111] 516 after: PutMultiWithoutTx #1, keys=[/DataA,111] 517 before: PutMultiWithoutTx #1, keys=[/DataA,111] 518 before: GetMultiWithoutTx #2, len(keys)=1, keys=[/DataA,111] 519 after: GetMultiWithoutTx #2, len(keys)=1, keys=[/DataA,111] 520 before: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/DataA,111] 521 after: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/DataA,111] 522 before: PutMultiWithoutTx #4, len(keys)=1, keys=[/DataB,111] 523 after: PutMultiWithoutTx #4, len(keys)=1, keys=[/DataB,111] 524 after: PutMultiWithoutTx #4, keys=[/DataB,111] 525 dsmiddleware/localcache.SetMulti: len=1 526 dsmiddleware/localcache.SetMulti: idx=0 key=/DataB,111 len(ps)=1 527 before: PutMultiWithoutTx #4, keys=[/DataB,111] 528 before: GetMultiWithoutTx #5, len(keys)=1, keys=[/DataB,111] 529 dsmiddleware/localcache.GetMulti: len=1 530 dsmiddleware/localcache.GetMulti: idx=0 key=/DataB,111 531 dsmiddleware/localcache.GetMulti: idx=0, hit key=/DataB,111 len(ps)=1 532 before: DeleteMultiWithoutTx #6, len(keys)=1, keys=[/DataB,111] 533 after: DeleteMultiWithoutTx #5, len(keys)=1, keys=[/DataB,111] 534 dsmiddleware/localcache.DeleteMulti: len=1 535 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataB,111 536 before: PutMultiWithoutTx #7, len(keys)=2, keys=[/DataA,111, /DataB,111] 537 after: PutMultiWithoutTx #6, len(keys)=2, keys=[/DataA,111, /DataB,111] 538 after: PutMultiWithoutTx #6, keys=[/DataA,111, /DataB,111] 539 dsmiddleware/localcache.SetMulti: len=1 540 dsmiddleware/localcache.SetMulti: idx=0 key=/DataB,111 len(ps)=1 541 before: PutMultiWithoutTx #7, keys=[/DataA,111, /DataB,111] 542 before: GetMultiWithoutTx #8, len(keys)=2, keys=[/DataA,111, /DataB,111] 543 dsmiddleware/localcache.GetMulti: len=1 544 dsmiddleware/localcache.GetMulti: idx=0 key=/DataB,111 545 dsmiddleware/localcache.GetMulti: idx=0, hit key=/DataB,111 len(ps)=1 546 after: GetMultiWithoutTx #7, len(keys)=1, keys=[/DataA,111] 547 before: DeleteMultiWithoutTx #9, len(keys)=2, keys=[/DataA,111, /DataB,111] 548 after: DeleteMultiWithoutTx #8, len(keys)=2, keys=[/DataA,111, /DataB,111] 549 dsmiddleware/localcache.DeleteMulti: len=1 550 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataB,111 551 before: PutMultiWithoutTx #10, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 552 after: PutMultiWithoutTx #9, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 553 after: PutMultiWithoutTx #9, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 554 dsmiddleware/localcache.SetMulti: len=2 555 dsmiddleware/localcache.SetMulti: idx=0 key=/DataB,111 len(ps)=1 556 dsmiddleware/localcache.SetMulti: idx=1 key=/DataB,222 len(ps)=1 557 before: PutMultiWithoutTx #10, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 558 dsmiddleware/localcache.DeleteCache: key=/DataA,222 559 dsmiddleware/localcache.DeleteCache: key=/DataB,222 560 before: GetMultiWithoutTx #11, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 561 dsmiddleware/localcache.GetMulti: len=2 562 dsmiddleware/localcache.GetMulti: idx=0 key=/DataB,111 563 dsmiddleware/localcache.GetMulti: idx=1 key=/DataB,222 564 dsmiddleware/localcache.GetMulti: idx=0, hit key=/DataB,111 len(ps)=1 565 dsmiddleware/localcache.GetMulti: idx=1, missed key=/DataB,222 566 after: GetMultiWithoutTx #10, len(keys)=3, keys=[/DataA,111, /DataA,222, /DataB,222] 567 dsmiddleware/localcache.SetMulti: len=1 568 dsmiddleware/localcache.SetMulti: idx=0 key=/DataB,222 len(ps)=1 569 before: DeleteMultiWithoutTx #12, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 570 after: DeleteMultiWithoutTx #11, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 571 dsmiddleware/localcache.DeleteMulti: len=2 572 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataB,111 573 dsmiddleware/localcache.DeleteMulti: idx=1 key=/DataB,222 574 `) 575 576 if v := strings.Join(logs, "\n") + "\n"; v != expected { 577 t.Errorf("unexpected: %v", v) 578 } 579 } 580 581 func withKeyFilter(ctx context.Context, t *testing.T, client datastore.Client) { 582 defer func() { 583 err := client.Close() 584 if err != nil { 585 t.Fatal(err) 586 } 587 }() 588 589 var logs []string 590 logf := func(ctx context.Context, format string, args ...interface{}) { 591 t.Logf(format, args...) 592 logs = append(logs, fmt.Sprintf(format, args...)) 593 } 594 595 // setup. strategies are first in - first apply. 596 597 bLog := dslog.NewLogger("before: ", logf) 598 client.AppendMiddleware(bLog) 599 defer func() { 600 // stop logging before cleanUp func called. 601 client.RemoveMiddleware(bLog) 602 }() 603 604 ch := localcache.New( 605 localcache.WithKeyFilter(func(ctx context.Context, key datastore.Key) bool { 606 return key.ID() != 111 607 }), 608 localcache.WithLogger(logf), 609 ) 610 client.AppendMiddleware(ch) 611 defer func() { 612 // stop logging before cleanUp func called. 613 client.RemoveMiddleware(ch) 614 }() 615 616 aLog := dslog.NewLogger("after: ", logf) 617 client.AppendMiddleware(aLog) 618 defer func() { 619 // stop logging before cleanUp func called. 620 client.RemoveMiddleware(aLog) 621 }() 622 623 // exec. 624 625 type Data struct { 626 Name string 627 } 628 629 { // Put. dsmiddleware target. 630 key := client.IDKey("DataA", 222, nil) 631 objBefore := &Data{Name: "A"} 632 _, err := client.Put(ctx, key, objBefore) 633 if err != nil { 634 t.Fatal(err) 635 } 636 637 obj := &Data{} 638 err = client.Get(ctx, key, obj) 639 if err != nil { 640 t.Fatal(err) 641 } 642 if v := obj.Name; v != "A" { 643 t.Errorf("unexpected: %v", v) 644 } 645 646 err = client.Delete(ctx, key) 647 if err != nil { 648 t.Fatal(err) 649 } 650 } 651 { // Put. dsmiddleware ignored. 652 key := client.IDKey("DataB", 111, nil) 653 objBefore := &Data{Name: "B"} 654 _, err := client.Put(ctx, key, objBefore) 655 if err != nil { 656 t.Fatal(err) 657 } 658 659 obj := &Data{} 660 err = client.Get(ctx, key, obj) 661 if err != nil { 662 t.Fatal(err) 663 } 664 if v := obj.Name; v != "B" { 665 t.Errorf("unexpected: %v", v) 666 } 667 668 err = client.Delete(ctx, key) 669 if err != nil { 670 t.Fatal(err) 671 } 672 } 673 { // Put. dsmiddleware target & ignored. 674 keyIgnore := client.IDKey("DataA", 111, nil) 675 keyTarget := client.IDKey("DataB", 222, nil) 676 677 list := []*Data{{Name: "A"}, {Name: "B"}} 678 _, err := client.PutMulti(ctx, []datastore.Key{keyIgnore, keyTarget}, list) 679 if err != nil { 680 t.Fatal(err) 681 } 682 683 list = make([]*Data, 2) 684 err = client.GetMulti(ctx, []datastore.Key{keyIgnore, keyTarget}, list) 685 if err != nil { 686 t.Fatal(err) 687 } 688 if v := len(list); v != 2 { 689 t.Fatalf("unexpected: %v", v) 690 } 691 if v := list[0].Name; v != "A" { 692 t.Errorf("unexpected: %v", v) 693 } 694 if v := list[1].Name; v != "B" { 695 t.Errorf("unexpected: %v", v) 696 } 697 698 err = client.DeleteMulti(ctx, []datastore.Key{keyIgnore, keyTarget}) 699 if err != nil { 700 t.Fatal(err) 701 } 702 } 703 { // Put. partially hit 704 keyIgnoreA := client.IDKey("DataA", 111, nil) 705 keyIgnoreB := client.IDKey("DataB", 111, nil) 706 keyTargetA := client.IDKey("DataA", 222, nil) 707 keyTargetB := client.IDKey("DataB", 222, nil) 708 709 list := []*Data{{Name: "A1"}, {Name: "A2"}, {Name: "B1"}, {Name: "B2"}} 710 _, err := client.PutMulti(ctx, []datastore.Key{keyIgnoreA, keyTargetA, keyIgnoreB, keyTargetB}, list) 711 if err != nil { 712 t.Fatal(err) 713 } 714 715 ch.DeleteCache(ctx, keyIgnoreA) 716 ch.DeleteCache(ctx, keyTargetA) 717 718 list = make([]*Data, 4) 719 err = client.GetMulti(ctx, []datastore.Key{keyIgnoreA, keyTargetA, keyIgnoreB, keyTargetB}, list) 720 if err != nil { 721 t.Fatal(err) 722 } 723 if v := len(list); v != 4 { 724 t.Fatalf("unexpected: %v", v) 725 } 726 if v := list[0].Name; v != "A1" { 727 t.Errorf("unexpected: %v", v) 728 } 729 if v := list[1].Name; v != "A2" { 730 t.Errorf("unexpected: %v", v) 731 } 732 if v := list[2].Name; v != "B1" { 733 t.Errorf("unexpected: %v", v) 734 } 735 if v := list[3].Name; v != "B2" { 736 t.Errorf("unexpected: %v", v) 737 } 738 739 err = client.DeleteMulti(ctx, []datastore.Key{keyIgnoreA, keyTargetA, keyIgnoreB, keyTargetB}) 740 if err != nil { 741 t.Fatal(err) 742 } 743 } 744 745 expected := heredoc.Doc(` 746 before: PutMultiWithoutTx #1, len(keys)=1, keys=[/DataA,222] 747 after: PutMultiWithoutTx #1, len(keys)=1, keys=[/DataA,222] 748 after: PutMultiWithoutTx #1, keys=[/DataA,222] 749 dsmiddleware/localcache.SetMulti: len=1 750 dsmiddleware/localcache.SetMulti: idx=0 key=/DataA,222 len(ps)=1 751 before: PutMultiWithoutTx #1, keys=[/DataA,222] 752 before: GetMultiWithoutTx #2, len(keys)=1, keys=[/DataA,222] 753 dsmiddleware/localcache.GetMulti: len=1 754 dsmiddleware/localcache.GetMulti: idx=0 key=/DataA,222 755 dsmiddleware/localcache.GetMulti: idx=0, hit key=/DataA,222 len(ps)=1 756 before: DeleteMultiWithoutTx #3, len(keys)=1, keys=[/DataA,222] 757 after: DeleteMultiWithoutTx #2, len(keys)=1, keys=[/DataA,222] 758 dsmiddleware/localcache.DeleteMulti: len=1 759 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataA,222 760 before: PutMultiWithoutTx #4, len(keys)=1, keys=[/DataB,111] 761 after: PutMultiWithoutTx #3, len(keys)=1, keys=[/DataB,111] 762 after: PutMultiWithoutTx #3, keys=[/DataB,111] 763 before: PutMultiWithoutTx #4, keys=[/DataB,111] 764 before: GetMultiWithoutTx #5, len(keys)=1, keys=[/DataB,111] 765 after: GetMultiWithoutTx #4, len(keys)=1, keys=[/DataB,111] 766 before: DeleteMultiWithoutTx #6, len(keys)=1, keys=[/DataB,111] 767 after: DeleteMultiWithoutTx #5, len(keys)=1, keys=[/DataB,111] 768 before: PutMultiWithoutTx #7, len(keys)=2, keys=[/DataA,111, /DataB,222] 769 after: PutMultiWithoutTx #6, len(keys)=2, keys=[/DataA,111, /DataB,222] 770 after: PutMultiWithoutTx #6, keys=[/DataA,111, /DataB,222] 771 dsmiddleware/localcache.SetMulti: len=1 772 dsmiddleware/localcache.SetMulti: idx=0 key=/DataB,222 len(ps)=1 773 before: PutMultiWithoutTx #7, keys=[/DataA,111, /DataB,222] 774 before: GetMultiWithoutTx #8, len(keys)=2, keys=[/DataA,111, /DataB,222] 775 dsmiddleware/localcache.GetMulti: len=1 776 dsmiddleware/localcache.GetMulti: idx=0 key=/DataB,222 777 dsmiddleware/localcache.GetMulti: idx=0, hit key=/DataB,222 len(ps)=1 778 after: GetMultiWithoutTx #7, len(keys)=1, keys=[/DataA,111] 779 before: DeleteMultiWithoutTx #9, len(keys)=2, keys=[/DataA,111, /DataB,222] 780 after: DeleteMultiWithoutTx #8, len(keys)=2, keys=[/DataA,111, /DataB,222] 781 dsmiddleware/localcache.DeleteMulti: len=1 782 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataB,222 783 before: PutMultiWithoutTx #10, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 784 after: PutMultiWithoutTx #9, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 785 after: PutMultiWithoutTx #9, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 786 dsmiddleware/localcache.SetMulti: len=2 787 dsmiddleware/localcache.SetMulti: idx=0 key=/DataA,222 len(ps)=1 788 dsmiddleware/localcache.SetMulti: idx=1 key=/DataB,222 len(ps)=1 789 before: PutMultiWithoutTx #10, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 790 dsmiddleware/localcache.DeleteCache: key=/DataA,111 791 dsmiddleware/localcache.DeleteCache: key=/DataA,222 792 before: GetMultiWithoutTx #11, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 793 dsmiddleware/localcache.GetMulti: len=2 794 dsmiddleware/localcache.GetMulti: idx=0 key=/DataA,222 795 dsmiddleware/localcache.GetMulti: idx=1 key=/DataB,222 796 dsmiddleware/localcache.GetMulti: idx=0, missed key=/DataA,222 797 dsmiddleware/localcache.GetMulti: idx=1, hit key=/DataB,222 len(ps)=1 798 after: GetMultiWithoutTx #10, len(keys)=3, keys=[/DataA,111, /DataA,222, /DataB,111] 799 dsmiddleware/localcache.SetMulti: len=1 800 dsmiddleware/localcache.SetMulti: idx=0 key=/DataA,222 len(ps)=1 801 before: DeleteMultiWithoutTx #12, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 802 after: DeleteMultiWithoutTx #11, len(keys)=4, keys=[/DataA,111, /DataA,222, /DataB,111, /DataB,222] 803 dsmiddleware/localcache.DeleteMulti: len=2 804 dsmiddleware/localcache.DeleteMulti: idx=0 key=/DataA,222 805 dsmiddleware/localcache.DeleteMulti: idx=1 key=/DataB,222 806 `) 807 808 if v := strings.Join(logs, "\n") + "\n"; v != expected { 809 t.Errorf("unexpected: %v", v) 810 } 811 } 812 813 func flushLocalCache(ctx context.Context, t *testing.T, client datastore.Client) { 814 defer func() { 815 err := client.Close() 816 if err != nil { 817 t.Fatal(err) 818 } 819 }() 820 821 ch := localcache.New() 822 client.AppendMiddleware(ch) 823 defer func() { 824 // stop logging before cleanUp func called. 825 client.RemoveMiddleware(ch) 826 }() 827 828 type Data struct { 829 Name string 830 } 831 832 // Put. add to dsmiddleware. 833 key := client.IDKey("Data", 111, nil) 834 objBefore := &Data{Name: "Data"} 835 _, err := client.Put(ctx, key, objBefore) 836 if err != nil { 837 t.Fatal(err) 838 } 839 840 if v := ch.HasCache(key); !v { 841 t.Fatalf("unexpected: %v", v) 842 } 843 844 ch.FlushLocalCache() 845 846 if v := ch.HasCache(key); v { 847 t.Fatalf("unexpected: %v", v) 848 } 849 } 850 851 func query(ctx context.Context, t *testing.T, client datastore.Client) { 852 defer func() { 853 err := client.Close() 854 if err != nil { 855 t.Fatal(err) 856 } 857 }() 858 859 var logs []string 860 logf := func(ctx context.Context, format string, args ...interface{}) { 861 t.Logf(format, args...) 862 logs = append(logs, fmt.Sprintf(format, args...)) 863 } 864 865 // setup. strategies are first in - first apply. 866 867 bLog := dslog.NewLogger("before: ", logf) 868 client.AppendMiddleware(bLog) 869 defer func() { 870 // stop logging before cleanUp func called. 871 client.RemoveMiddleware(bLog) 872 }() 873 874 ch := localcache.New() 875 client.AppendMiddleware(ch) 876 defer func() { 877 // stop logging before cleanUp func called. 878 client.RemoveMiddleware(ch) 879 }() 880 881 aLog := dslog.NewLogger("after: ", logf) 882 client.AppendMiddleware(aLog) 883 defer func() { 884 // stop logging before cleanUp func called. 885 client.RemoveMiddleware(aLog) 886 }() 887 888 // exec. 889 890 type Data struct { 891 Name string 892 } 893 894 const size = 3 895 896 keys := make([]datastore.Key, size) 897 list := make([]*Data, size) 898 for i := 0; i < size; i++ { 899 keys[i] = client.NameKey("Data", fmt.Sprintf("#%d", i+1), nil) 900 list[i] = &Data{ 901 Name: fmt.Sprintf("#%d", i+1), 902 } 903 } 904 _, err := client.PutMulti(ctx, keys, list) 905 if err != nil { 906 t.Fatal(err) 907 } 908 909 q := client.NewQuery("Data").Order("-Name") 910 911 // Run 912 iter := client.Run(ctx, q) 913 914 // Next 915 cnt := 0 916 for { 917 obj := &Data{} 918 key, err := iter.Next(obj) 919 if err == iterator.Done { 920 break 921 } else if err != nil { 922 t.Fatal(err) 923 } 924 if v := obj.Name; v == "" || v != key.Name() { 925 t.Errorf("unexpected: %v", cnt) 926 } 927 cnt++ 928 } 929 if cnt != size { 930 t.Errorf("unexpected: %v", cnt) 931 } 932 933 // GetAll 934 list = nil 935 _, err = client.GetAll(ctx, q, &list) 936 if err != nil { 937 t.Fatal(err) 938 } 939 940 expected := heredoc.Doc(` 941 before: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,#1, /Data,#2, /Data,#3] 942 after: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,#1, /Data,#2, /Data,#3] 943 after: PutMultiWithoutTx #1, keys=[/Data,#1, /Data,#2, /Data,#3] 944 before: PutMultiWithoutTx #1, keys=[/Data,#1, /Data,#2, /Data,#3] 945 before: Run #2, q=v1:Data&or=-Name 946 after: Run #2, q=v1:Data&or=-Name 947 before: Next #3, q=v1:Data&or=-Name 948 after: Next #3, q=v1:Data&or=-Name 949 after: Next #3, key=/Data,#3 950 before: Next #3, key=/Data,#3 951 before: Next #4, q=v1:Data&or=-Name 952 after: Next #4, q=v1:Data&or=-Name 953 after: Next #4, key=/Data,#2 954 before: Next #4, key=/Data,#2 955 before: Next #5, q=v1:Data&or=-Name 956 after: Next #5, q=v1:Data&or=-Name 957 after: Next #5, key=/Data,#1 958 before: Next #5, key=/Data,#1 959 before: Next #6, q=v1:Data&or=-Name 960 after: Next #6, q=v1:Data&or=-Name 961 after: Next #6, err=no more items in iterator 962 before: Next #6, err=no more items in iterator 963 before: GetAll #7, q=v1:Data&or=-Name 964 after: GetAll #7, q=v1:Data&or=-Name 965 after: GetAll #7, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1] 966 before: GetAll #7, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1] 967 `) 968 969 if v := strings.Join(logs, "\n") + "\n"; v != expected { 970 t.Errorf("unexpected: %v", v) 971 } 972 } 973 974 func transaction(ctx context.Context, t *testing.T, client datastore.Client) { 975 defer func() { 976 err := client.Close() 977 if err != nil { 978 t.Fatal(err) 979 } 980 }() 981 982 var logs []string 983 logf := func(ctx context.Context, format string, args ...interface{}) { 984 t.Logf(format, args...) 985 logs = append(logs, fmt.Sprintf(format, args...)) 986 } 987 988 // setup. strategies are first in - first apply. 989 990 bLog := dslog.NewLogger("before: ", logf) 991 client.AppendMiddleware(bLog) 992 defer func() { 993 // stop logging before cleanUp func called. 994 client.RemoveMiddleware(bLog) 995 }() 996 997 ch := localcache.New() 998 client.AppendMiddleware(ch) 999 defer func() { 1000 // stop logging before cleanUp func called. 1001 client.RemoveMiddleware(ch) 1002 }() 1003 1004 aLog := dslog.NewLogger("after: ", logf) 1005 client.AppendMiddleware(aLog) 1006 defer func() { 1007 // stop logging before cleanUp func called. 1008 client.RemoveMiddleware(aLog) 1009 }() 1010 1011 // exec. 1012 1013 type Data struct { 1014 Name string 1015 } 1016 1017 key := client.NameKey("Data", "a", nil) 1018 1019 // put to dsmiddleware 1020 _, err := client.Put(ctx, key, &Data{Name: "Before"}) 1021 if err != nil { 1022 t.Fatal(err) 1023 } 1024 if v := ch.HasCache(key); !v { 1025 t.Fatalf("unexpected: %v", v) 1026 } 1027 1028 { // Rollback 1029 tx, err := client.NewTransaction(ctx) 1030 if err != nil { 1031 t.Fatal(err) 1032 } 1033 1034 // don't put to dsmiddleware before commit 1035 key2 := client.NameKey("Data", "b", nil) 1036 _, err = tx.Put(key2, &Data{Name: "After"}) 1037 if err != nil { 1038 t.Fatal(err) 1039 } 1040 if v := ch.HasCache(key2); v { 1041 t.Fatalf("unexpected: %v", v) 1042 } 1043 1044 obj := &Data{} 1045 err = tx.Get(key, obj) 1046 if err != nil { 1047 t.Fatal(err) 1048 } 1049 1050 // don't delete from dsmiddleware before commit 1051 err = tx.Delete(key) 1052 if err != nil { 1053 t.Fatal(err) 1054 } 1055 if v := ch.HasCache(key); !v { 1056 t.Fatalf("unexpected: %v", v) 1057 } 1058 1059 // rollback. 1060 err = tx.Rollback() 1061 if err != nil { 1062 t.Fatal(err) 1063 } 1064 if v := ch.CacheLen(); v != 1 { 1065 t.Fatalf("unexpected: %v", v) 1066 } 1067 } 1068 1069 { // Commit 1070 tx, err := client.NewTransaction(ctx) 1071 if err != nil { 1072 t.Fatal(err) 1073 } 1074 1075 // don't put to dsmiddleware before commit 1076 key2 := client.IncompleteKey("Data", nil) 1077 pKey, err := tx.Put(key2, &Data{Name: "After"}) 1078 if err != nil { 1079 t.Fatal(err) 1080 } 1081 if v := ch.CacheLen(); v != 1 { 1082 t.Fatalf("unexpected: %v", v) 1083 } 1084 1085 obj := &Data{} 1086 err = tx.Get(key, obj) 1087 if err != nil { 1088 t.Fatal(err) 1089 } 1090 1091 // don't delete from dsmiddleware before commit 1092 err = tx.Delete(key) 1093 if err != nil { 1094 t.Fatal(err) 1095 } 1096 if v := ch.HasCache(key); !v { 1097 t.Fatalf("unexpected: %v", v) 1098 } 1099 1100 // commit. 1101 commit, err := tx.Commit() 1102 if err != nil { 1103 t.Fatal(err) 1104 } 1105 1106 key3 := commit.Key(pKey) 1107 if v := key3.Name(); v != key2.Name() { 1108 t.Errorf("unexpected: %v", v) 1109 } 1110 // committed, but don't put to dsmiddleware in tx. 1111 if v := ch.HasCache(key3); v { 1112 t.Fatalf("unexpected: %v", v) 1113 } 1114 1115 if v := ch.CacheLen(); v != 0 { 1116 t.Fatalf("unexpected: %v", v) 1117 } 1118 } 1119 1120 var expected *regexp.Regexp 1121 { 1122 expectedPattern := heredoc.Doc(` 1123 before: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,a] 1124 after: PutMultiWithoutTx #1, len(keys)=1, keys=[/Data,a] 1125 after: PutMultiWithoutTx #1, keys=[/Data,a] 1126 before: PutMultiWithoutTx #1, keys=[/Data,a] 1127 before: PutMultiWithTx #2, len(keys)=1, keys=[/Data,b] 1128 after: PutMultiWithTx #2, len(keys)=1, keys=[/Data,b] 1129 before: GetMultiWithTx #3, len(keys)=1, keys=[/Data,a] 1130 after: GetMultiWithTx #3, len(keys)=1, keys=[/Data,a] 1131 before: DeleteMultiWithTx #4, len(keys)=1, keys=[/Data,a] 1132 after: DeleteMultiWithTx #4, len(keys)=1, keys=[/Data,a] 1133 before: PostRollback #5 1134 after: PostRollback #5 1135 before: PutMultiWithTx #6, len(keys)=1, keys=[/Data,0] 1136 after: PutMultiWithTx #6, len(keys)=1, keys=[/Data,0] 1137 before: GetMultiWithTx #7, len(keys)=1, keys=[/Data,a] 1138 after: GetMultiWithTx #7, len(keys)=1, keys=[/Data,a] 1139 before: DeleteMultiWithTx #8, len(keys)=1, keys=[/Data,a] 1140 after: DeleteMultiWithTx #8, len(keys)=1, keys=[/Data,a] 1141 before: PostCommit #9 Put keys=[/Data,@####@] 1142 after: PostCommit #9 Put keys=[/Data,@####@] 1143 `) 1144 ss := strings.Split(expectedPattern, "@####@") 1145 var buf bytes.Buffer 1146 for idx, s := range ss { 1147 buf.WriteString(regexp.QuoteMeta(s)) 1148 if idx != (len(ss) - 1) { 1149 buf.WriteString("[0-9]+") 1150 } 1151 } 1152 expected = regexp.MustCompile(buf.String()) 1153 } 1154 1155 if v := strings.Join(logs, "\n") + "\n"; !expected.MatchString(v) { 1156 t.Errorf("unexpected: %v", v) 1157 } 1158 }