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 |