| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package memory | 5 package memory |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "fmt" | 9 "fmt" |
| 10 "math" | |
| 11 "testing" | 10 "testing" |
| 12 | 11 |
| 13 dsS "github.com/luci/gae/service/datastore" | 12 dsS "github.com/luci/gae/service/datastore" |
| 14 infoS "github.com/luci/gae/service/info" | 13 infoS "github.com/luci/gae/service/info" |
| 15 . "github.com/smartystreets/goconvey/convey" | 14 . "github.com/smartystreets/goconvey/convey" |
| 16 "golang.org/x/net/context" | 15 "golang.org/x/net/context" |
| 17 ) | 16 ) |
| 18 | 17 |
| 19 func TestDatastoreKinder(t *testing.T) { | 18 func TestDatastoreKinder(t *testing.T) { |
| 20 t.Parallel() | 19 t.Parallel() |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 416 So(ds.Get(f), ShouldBeNil) | 415 So(ds.Get(f), ShouldBeNil) |
| 417 So(f.Val, ShouldEqual, 10) | 416 So(f.Val, ShouldEqual, 10) |
| 418 }) | 417 }) |
| 419 }) | 418 }) |
| 420 }) | 419 }) |
| 421 }) | 420 }) |
| 422 | 421 |
| 423 }) | 422 }) |
| 424 } | 423 } |
| 425 | 424 |
| 426 const MaxUint = ^uint(0) | |
| 427 const MaxInt = int(MaxUint >> 1) | |
| 428 const IntIs32Bits = int64(MaxInt) < math.MaxInt64 | |
| 429 | |
| 430 func TestDatastoreQueryer(t *testing.T) { | |
| 431 Convey("Datastore Query suport", t, func() { | |
| 432 c := Use(context.Background()) | |
| 433 ds := dsS.Get(c) | |
| 434 So(ds, ShouldNotBeNil) | |
| 435 | |
| 436 Convey("can create good queries", func() { | |
| 437 q := ds.NewQuery("Foo").KeysOnly().Limit(10).Offset(39) | |
| 438 q = q.Start(queryCursor("kosmik")).End(queryCursor("krab
s")) | |
| 439 So(q, ShouldNotBeNil) | |
| 440 So(q.(*queryImpl).err, ShouldBeNil) | |
| 441 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 442 So(qi.err, ShouldBeNil) | |
| 443 }) | |
| 444 | |
| 445 Convey("normalize ensures orders make sense", func() { | |
| 446 q := ds.NewQuery("Cool") | |
| 447 q = q.Filter("cat =", 19).Filter("bob =", 10).Order("bob
").Order("bob") | |
| 448 | |
| 449 Convey("removes dups and equality orders", func() { | |
| 450 q = q.Order("wat") | |
| 451 qi := q.(*queryImpl).normalize().checkCorrectnes
s("", false) | |
| 452 So(qi.err, ShouldBeNil) | |
| 453 So(qi.order, ShouldResemble, []dsS.IndexColumn{{
Property: "wat"}}) | |
| 454 }) | |
| 455 | |
| 456 Convey("keeps inequality orders", func() { | |
| 457 q = q.Order("wat") | |
| 458 q := q.Filter("bob >", 10).Filter("wat <", 29) | |
| 459 qi := q.(*queryImpl).normalize().checkCorrectnes
s("", false) | |
| 460 So(qi.order, ShouldResemble, []dsS.IndexColumn{{
Property: "bob"}, {Property: "wat"}}) | |
| 461 So(qi.err.Error(), ShouldContainSubstring, "Only
one inequality") | |
| 462 }) | |
| 463 | |
| 464 Convey("if we equality-filter on __key__, order is ditch
ed", func() { | |
| 465 q = q.Order("wat") | |
| 466 q := q.Filter("__key__ =", ds.NewKey("Foo", "wat
", 0, nil)) | |
| 467 qi := q.(*queryImpl).normalize().checkCorrectnes
s("", false) | |
| 468 So(qi.order, ShouldResemble, []dsS.IndexColumn(n
il)) | |
| 469 So(qi.err, ShouldBeNil) | |
| 470 }) | |
| 471 | |
| 472 Convey("if we order by key and something else, key domin
ates", func() { | |
| 473 q := q.Order("__key__").Order("wat") | |
| 474 qi := q.(*queryImpl).normalize().checkCorrectnes
s("", false) | |
| 475 So(qi.order, ShouldResemble, []dsS.IndexColumn{{
Property: "__key__"}}) | |
| 476 So(qi.err, ShouldBeNil) | |
| 477 }) | |
| 478 }) | |
| 479 | |
| 480 Convey("can create bad queries", func() { | |
| 481 q := ds.NewQuery("Foo") | |
| 482 | |
| 483 Convey("bad filter ops", func() { | |
| 484 q := q.Filter("Bob !", "value") | |
| 485 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "invalid operator \"!\"") | |
| 486 }) | |
| 487 Convey("bad filter", func() { | |
| 488 q := q.Filter("Bob", "value") | |
| 489 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "invalid filter") | |
| 490 }) | |
| 491 Convey("bad order", func() { | |
| 492 q := q.Order("+Bob") | |
| 493 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "invalid order") | |
| 494 }) | |
| 495 Convey("empty", func() { | |
| 496 q := q.Order("") | |
| 497 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "empty order") | |
| 498 }) | |
| 499 Convey("OOB limit", func() { | |
| 500 // this is supremely stupid. The SDK uses 'int'
which measn we have to | |
| 501 // use it too, but then THEY BOUNDS CHECK IT FOR
32 BITS... *sigh* | |
| 502 if !IntIs32Bits { | |
| 503 q := q.Limit(MaxInt) | |
| 504 So(q.(*queryImpl).err.Error(), ShouldCon
tainSubstring, "query limit overflow") | |
| 505 } | |
| 506 }) | |
| 507 Convey("underflow offset", func() { | |
| 508 q := q.Offset(-29) | |
| 509 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "negative query offset") | |
| 510 }) | |
| 511 Convey("OOB offset", func() { | |
| 512 if !IntIs32Bits { | |
| 513 q := q.Offset(MaxInt) | |
| 514 So(q.(*queryImpl).err.Error(), ShouldCon
tainSubstring, "query offset overflow") | |
| 515 } | |
| 516 }) | |
| 517 Convey("Bad cursors", func() { | |
| 518 q := q.Start(queryCursor("")).End(queryCursor(""
)) | |
| 519 So(q.(*queryImpl).err.Error(), ShouldContainSubs
tring, "invalid cursor") | |
| 520 }) | |
| 521 Convey("Bad ancestors", func() { | |
| 522 q := q.Ancestor(ds.NewKey("Goop", "wat", 10, nil
)) | |
| 523 So(q, ShouldNotBeNil) | |
| 524 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 525 So(qi.err, ShouldEqual, dsS.ErrInvalidKey) | |
| 526 }) | |
| 527 Convey("nil ancestors", func() { | |
| 528 qi := q.Ancestor(nil).(*queryImpl).checkCorrectn
ess("", false) | |
| 529 So(qi.err.Error(), ShouldContainSubstring, "nil
query ancestor") | |
| 530 }) | |
| 531 Convey("Bad key filters", func() { | |
| 532 q := q.Filter("__key__ =", ds.NewKey("Goop", "wa
t", 10, nil)) | |
| 533 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 534 So(qi.err, ShouldEqual, dsS.ErrInvalidKey) | |
| 535 }) | |
| 536 Convey("non-ancestor queries in a transaction", func() { | |
| 537 qi := q.(*queryImpl).checkCorrectness("", true) | |
| 538 So(qi.err.Error(), ShouldContainSubstring, "Only
ancestor queries") | |
| 539 }) | |
| 540 Convey("absurd numbers of filters are prohibited", func(
) { | |
| 541 q := q.Ancestor(ds.NewKey("thing", "wat", 0, nil
)) | |
| 542 for i := 0; i < 100; i++ { | |
| 543 q = q.Filter("something =", 10) | |
| 544 } | |
| 545 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 546 So(qi.err.Error(), ShouldContainSubstring, "quer
y is too large") | |
| 547 }) | |
| 548 Convey("filters for __key__ that aren't keys", func() { | |
| 549 q := q.Filter("__key__ = ", 10) | |
| 550 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 551 So(qi.err.Error(), ShouldContainSubstring, "must
be a Key") | |
| 552 }) | |
| 553 Convey("multiple inequalities", func() { | |
| 554 q := q.Filter("bob > ", 19).Filter("charlie < ",
20) | |
| 555 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 556 So(qi.err.Error(), ShouldContainSubstring, "one
inequality filter") | |
| 557 }) | |
| 558 Convey("bad sort orders", func() { | |
| 559 q := q.Filter("bob > ", 19).Order("-charlie") | |
| 560 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 561 So(qi.err.Error(), ShouldContainSubstring, "firs
t sort property") | |
| 562 }) | |
| 563 Convey("kindless with non-__key__ filters", func() { | |
| 564 q := ds.NewQuery("").Filter("face <", 25.3) | |
| 565 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 566 So(qi.err.Error(), ShouldContainSubstring, "kind
is required for non-__key__") | |
| 567 }) | |
| 568 Convey("kindless with non-__key__ orders", func() { | |
| 569 q := ds.NewQuery("").Order("face") | |
| 570 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 571 So(qi.err.Error(), ShouldContainSubstring, "kind
is required for all orders") | |
| 572 }) | |
| 573 Convey("kindless with decending-__key__ orders", func()
{ | |
| 574 q := ds.NewQuery("").Order("-__key__") | |
| 575 qi := q.(*queryImpl).checkCorrectness("", false) | |
| 576 So(qi.err.Error(), ShouldContainSubstring, "kind
is required for all orders") | |
| 577 }) | |
| 578 }) | |
| 579 | |
| 580 }) | |
| 581 } | |
| 582 | |
| 583 func TestCompoundIndexes(t *testing.T) { | 425 func TestCompoundIndexes(t *testing.T) { |
| 584 t.Parallel() | 426 t.Parallel() |
| 585 | 427 |
| 586 idxKey := func(def *dsS.IndexDefinition) string { | 428 idxKey := func(def *dsS.IndexDefinition) string { |
| 587 buf := &bytes.Buffer{} | 429 buf := &bytes.Buffer{} |
| 588 buf.WriteString("idx::") | 430 buf.WriteString("idx::") |
| 589 So(def.Write(buf), ShouldBeNil) | 431 So(def.Write(buf), ShouldBeNil) |
| 590 return buf.String() | 432 return buf.String() |
| 591 } | 433 } |
| 592 | 434 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 | 470 |
| 629 idx.SortBy = append(idx.SortBy, dsS.IndexColumn{Property: "Field
1"}) | 471 idx.SortBy = append(idx.SortBy, dsS.IndexColumn{Property: "Field
1"}) |
| 630 So(store.GetCollection(idxKey(idx)), ShouldBeNil) | 472 So(store.GetCollection(idxKey(idx)), ShouldBeNil) |
| 631 | 473 |
| 632 t.AddIndexes(idx) | 474 t.AddIndexes(idx) |
| 633 coll = store.GetCollection(idxKey(idx)) | 475 coll = store.GetCollection(idxKey(idx)) |
| 634 So(coll, ShouldNotBeNil) | 476 So(coll, ShouldNotBeNil) |
| 635 So(numItms(coll), ShouldEqual, 4) | 477 So(numItms(coll), ShouldEqual, 4) |
| 636 }) | 478 }) |
| 637 } | 479 } |
| OLD | NEW |