func TestBasics(t *testing.T) { type X struct { I int S string T time.Time } c := testutil.Context(ScopeDatastore, ScopeUserEmail) x0 := X{66, "99", time.Now().Truncate(time.Millisecond)} k, err := Put(c, NewIncompleteKey(c, "BasicsX", nil), &x0) if err != nil { t.Fatalf("Put: %v", err) } x1 := X{} err = Get(c, k, &x1) if err != nil { t.Errorf("Get: %v", err) } err = Delete(c, k) if err != nil { t.Errorf("Delete: %v", err) } if !reflect.DeepEqual(x0, x1) { t.Errorf("compare: x0=%v, x1=%v", x0, x1) } }
func TestGetAllWithFieldMismatch(t *testing.T) { type Fat struct { X, Y int } type Thin struct { X int } c := testutil.Context(ScopeDatastore, ScopeUserEmail) putKeys := make([]*Key, 3) for i := range putKeys { putKeys[i] = NewKey(c, "GetAllThing", "", int64(10+i), nil) _, err := Put(c, putKeys[i], &Fat{X: 20 + i, Y: 30 + i}) if err != nil { t.Fatalf("Put: %v", err) } } var got []Thin want := []Thin{ {X: 20}, {X: 21}, {X: 22}, } getKeys, err := NewQuery("GetAllThing").GetAll(c, &got) if len(getKeys) != 3 && !reflect.DeepEqual(getKeys, putKeys) { t.Errorf("GetAll: keys differ\ngetKeys=%v\nputKeys=%v", getKeys, putKeys) } if !reflect.DeepEqual(got, want) { t.Errorf("GetAll: entities differ\ngot =%v\nwant=%v", got, want) } if _, ok := err.(*ErrFieldMismatch); !ok { t.Errorf("GetAll: got err=%v, want ErrFieldMismatch", err) } }
func TestProjection(t *testing.T) { c := testutil.Context(ScopeDatastore, ScopeUserEmail) parent := NewKey(c, "SQParent", "TestProjection", 0, nil) now := time.Now().Truncate(time.Millisecond).Unix() children := []*SQChild{ {I: 1 << 0, J: 100, T: now, U: now}, {I: 1 << 1, J: 100, T: now, U: now}, {I: 1 << 2, J: 200, T: now, U: now}, {I: 1 << 3, J: 300, T: now, U: now}, {I: 1 << 4, J: 300, T: now, U: now}, } baseQuery := NewQuery("SQChild").Ancestor(parent).Filter("T=", now).Filter("J>", 150) testSmallQueries(t, c, parent, children, []SQTestCase{ { "project", baseQuery.Project("J"), 3, 200 + 300 + 300, }, { "distinct", baseQuery.Project("J").Distinct(), 2, 200 + 300, }, { "project on meaningful (GD_WHEN) field", baseQuery.Project("U"), 3, 0, }, }) }
func TestACL(t *testing.T) { ctx := testutil.Context(ScopeFullControl) cleanup(t, "acl") entity := ACLEntity("domain-google.com") if err := PutDefaultACLRule(ctx, bucket, entity, RoleReader); err != nil { t.Errorf("Can't put default ACL rule for the bucket, errored with %v", err) } for _, obj := range aclObjects { t.Logf("Writing %v", obj) wc := NewWriter(ctx, bucket, obj) c := randomContents() if _, err := wc.Write(c); err != nil { t.Errorf("Write for %v failed with %v", obj, err) } if err := wc.Close(); err != nil { t.Errorf("Close for %v failed with %v", obj, err) } } name := aclObjects[0] acl, err := ACL(ctx, bucket, name) if err != nil { t.Errorf("Can't retrieve ACL of %v", name) } aclFound := false for _, rule := range acl { if rule.Entity == entity && rule.Role == RoleReader { aclFound = true } } if !aclFound { t.Error("Expected to find an ACL rule for google.com domain users, but not found") } if err := DeleteACLRule(ctx, bucket, name, entity); err != nil { t.Errorf("Can't delete the ACL rule for the entity: %v", entity) } if err := PutBucketACLRule(ctx, bucket, "*****@*****.**", RoleReader); err != nil { t.Errorf("Error while putting bucket ACL rule: %v", err) } bACL, err := BucketACL(ctx, bucket) if err != nil { t.Errorf("Error while getting the ACL of the bucket: %v", err) } bACLFound := false for _, rule := range bACL { if rule.Entity == "*****@*****.**" && rule.Role == RoleReader { bACLFound = true } } if !bACLFound { t.Error("Expected to find an ACL rule for [email protected] user, but not found") } if err := DeleteBucketACLRule(ctx, bucket, "*****@*****.**"); err != nil { t.Errorf("Error while deleting bucket ACL rule: %v", err) } }
func TestGetMulti(t *testing.T) { type X struct { I int } c := testutil.Context(ScopeDatastore, ScopeUserEmail) p := NewKey(c, "X", "", time.Now().Unix(), nil) cases := []struct { key *Key put bool }{ {key: NewKey(c, "X", "item1", 0, p), put: true}, {key: NewKey(c, "X", "item2", 0, p), put: false}, {key: NewKey(c, "X", "item3", 0, p), put: false}, {key: NewKey(c, "X", "item4", 0, p), put: true}, } var src, dst []*X var srcKeys, dstKeys []*Key for _, c := range cases { dst = append(dst, &X{}) dstKeys = append(dstKeys, c.key) if c.put { src = append(src, &X{}) srcKeys = append(srcKeys, c.key) } } if _, err := PutMulti(c, srcKeys, src); err != nil { t.Error(err) } err := GetMulti(c, dstKeys, dst) if err == nil { t.Errorf("GetMulti got %v, expected error", err) } e, ok := err.(MultiError) if !ok { t.Errorf("GetMulti got %t, expected MultiError", err) } for i, err := range e { got, want := err, (error)(nil) if !cases[i].put { got, want = err, ErrNoSuchEntity } if got != want { t.Errorf("MultiError[%d] == %v, want %v", i, got, want) } } }
func TestAllocateIDs(t *testing.T) { c := testutil.Context(ScopeDatastore, ScopeUserEmail) keys := make([]*Key, 5) for i := range keys { keys[i] = NewIncompleteKey(c, "AllocID", nil) } keys, err := AllocateIDs(c, keys) if err != nil { t.Errorf("AllocID #0 failed: %v", err) } if want := len(keys); want != 5 { t.Errorf("Expected to allocate 5 keys, %d keys are found", want) } for _, k := range keys { if k.Incomplete() { t.Errorf("Unexpeceted incomplete key found: %v", k) } } }
func TestEventualConsistency(t *testing.T) { c := testutil.Context(ScopeDatastore, ScopeUserEmail) parent := NewKey(c, "SQParent", "TestEventualConsistency", 0, nil) now := time.Now().Truncate(time.Millisecond).Unix() children := []*SQChild{ {I: 0, T: now, U: now}, {I: 1, T: now, U: now}, {I: 2, T: now, U: now}, } query := NewQuery("SQChild").Ancestor(parent).Filter("T =", now).EventualConsistency() testSmallQueries(t, c, parent, children, nil, func() { got, err := query.Count(c) if err != nil { t.Fatalf("Count: %v", err) } if got < 0 || 3 < got { t.Errorf("Count: got %d, want [0,3]", got) } }) }
func TestListValues(t *testing.T) { p0 := PropertyList{ {Name: "L", Value: int64(12), Multiple: true}, {Name: "L", Value: "string", Multiple: true}, {Name: "L", Value: true, Multiple: true}, } c := testutil.Context(ScopeDatastore, ScopeUserEmail) k, err := Put(c, NewIncompleteKey(c, "ListValue", nil), &p0) if err != nil { t.Fatalf("Put: %v", err) } var p1 PropertyList if err := Get(c, k, &p1); err != nil { t.Errorf("Get: %v", err) } if !reflect.DeepEqual(p0, p1) { t.Errorf("compare:\np0=%v\np1=%#v", p0, p1) } if err = Delete(c, k); err != nil { t.Errorf("Delete: %v", err) } }
func cleanup(t *testing.T, prefix string) { ctx := testutil.Context(ScopeFullControl) var q *Query = &Query{ Prefix: prefix, } for { o, err := ListObjects(ctx, bucket, q) if err != nil { t.Fatalf("Cleanup List for bucket %v failed with error: %v", bucket, err) } for _, obj := range o.Results { t.Logf("Cleanup deletion of %v", obj.Name) if err = DeleteObject(ctx, bucket, obj.Name); err != nil { t.Fatalf("Cleanup Delete for object %v failed with %v", obj.Name, err) } } if o.Next == nil { break } q = o.Next } }
func TestUnindexableValues(t *testing.T) { x500 := strings.Repeat("x", 500) x501 := strings.Repeat("x", 501) testCases := []struct { in Z wantErr bool }{ {in: Z{S: x500}, wantErr: false}, {in: Z{S: x501}, wantErr: true}, {in: Z{T: x500}, wantErr: false}, {in: Z{T: x501}, wantErr: false}, {in: Z{P: []byte(x500)}, wantErr: false}, {in: Z{P: []byte(x501)}, wantErr: true}, {in: Z{K: []byte(x500)}, wantErr: false}, {in: Z{K: []byte(x501)}, wantErr: false}, } c := testutil.Context(ScopeDatastore, ScopeUserEmail) for _, tt := range testCases { _, err := Put(c, NewIncompleteKey(c, "BasicsZ", nil), &tt.in) if (err != nil) != tt.wantErr { t.Errorf("Put %s got err %v, want err %t", tt.in, err, tt.wantErr) } } }
func TestKindlessQueries(t *testing.T) { type Dee struct { I int Why string } type Dum struct { I int Pling string } c := testutil.Context(ScopeDatastore, ScopeUserEmail) parent := NewKey(c, "Tweedle", "tweedle", 0, nil) keys := []*Key{ NewKey(c, "Dee", "dee0", 0, parent), NewKey(c, "Dum", "dum1", 0, parent), NewKey(c, "Dum", "dum2", 0, parent), NewKey(c, "Dum", "dum3", 0, parent), } src := []interface{}{ &Dee{1, "binary0001"}, &Dum{2, "binary0010"}, &Dum{4, "binary0100"}, &Dum{8, "binary1000"}, } keys, err := PutMulti(c, keys, src) if err != nil { t.Fatalf("put: %v", err) } testCases := []struct { desc string query *Query want []int wantErr string }{ { desc: "Dee", query: NewQuery("Dee"), want: []int{1}, }, { desc: "Doh", query: NewQuery("Doh"), want: nil}, { desc: "Dum", query: NewQuery("Dum"), want: []int{2, 4, 8}, }, { desc: "", query: NewQuery(""), want: []int{1, 2, 4, 8}, }, { desc: "Kindless filter", query: NewQuery("").Filter("__key__ =", keys[2]), want: []int{4}, }, { desc: "Kindless order", query: NewQuery("").Order("__key__"), want: []int{1, 2, 4, 8}, }, { desc: "Kindless bad filter", query: NewQuery("").Filter("I =", 4), wantErr: "kind is required for filter: I", }, { desc: "Kindless bad order", query: NewQuery("").Order("-__key__"), wantErr: "kind is required for all orders except __key__ ascending", }, } loop: for _, tc := range testCases { q := tc.query.Ancestor(parent) gotCount, err := q.Count(c) if err != nil { if tc.wantErr == "" || !strings.Contains(err.Error(), tc.wantErr) { t.Errorf("count %q: err %v, want err %q", tc.desc, err, tc.wantErr) } continue } if tc.wantErr != "" { t.Errorf("count %q: want err %q", tc.desc, tc.wantErr) continue } if gotCount != len(tc.want) { t.Errorf("count %q: got %d want %d", tc.desc, gotCount, len(tc.want)) continue } var got []int for iter := q.Run(c); ; { var dst struct { I int Why, Pling string } _, err := iter.Next(&dst) if err == Done { break } if err != nil { t.Errorf("iter.Next %q: %v", tc.desc, err) continue loop } got = append(got, dst.I) } sort.Ints(got) if !reflect.DeepEqual(got, tc.want) { t.Errorf("elems %q: got %+v want %+v", tc.desc, got, tc.want) continue } } }
func TestFilters(t *testing.T) { c := testutil.Context(ScopeDatastore, ScopeUserEmail) parent := NewKey(c, "SQParent", "TestFilters", 0, nil) now := time.Now().Truncate(time.Millisecond).Unix() children := []*SQChild{ {I: 0, T: now, U: now}, {I: 1, T: now, U: now}, {I: 2, T: now, U: now}, {I: 3, T: now, U: now}, {I: 4, T: now, U: now}, {I: 5, T: now, U: now}, {I: 6, T: now, U: now}, {I: 7, T: now, U: now}, } baseQuery := NewQuery("SQChild").Ancestor(parent).Filter("T=", now) testSmallQueries(t, c, parent, children, []SQTestCase{ { "I>1", baseQuery.Filter("I>", 1), 6, 2 + 3 + 4 + 5 + 6 + 7, }, { "I>2 AND I<=5", baseQuery.Filter("I>", 2).Filter("I<=", 5), 3, 3 + 4 + 5, }, { "I>=3 AND I<3", baseQuery.Filter("I>=", 3).Filter("I<", 3), 0, 0, }, { "I=4", baseQuery.Filter("I=", 4), 1, 4, }, }, func() { got := []*SQChild{} want := []*SQChild{ {I: 0, T: now, U: now}, {I: 1, T: now, U: now}, {I: 2, T: now, U: now}, {I: 3, T: now, U: now}, {I: 4, T: now, U: now}, {I: 5, T: now, U: now}, {I: 6, T: now, U: now}, {I: 7, T: now, U: now}, } _, err := baseQuery.Order("I").GetAll(c, &got) if err != nil { t.Errorf("GetAll: %v", err) } if !reflect.DeepEqual(got, want) { t.Errorf("compare: got=%v, want=%v", got, want) } }, func() { got := []*SQChild{} want := []*SQChild{ {I: 7, T: now, U: now}, {I: 6, T: now, U: now}, {I: 5, T: now, U: now}, {I: 4, T: now, U: now}, {I: 3, T: now, U: now}, {I: 2, T: now, U: now}, {I: 1, T: now, U: now}, {I: 0, T: now, U: now}, } _, err := baseQuery.Order("-I").GetAll(c, &got) if err != nil { t.Errorf("GetAll: %v", err) } if !reflect.DeepEqual(got, want) { t.Errorf("compare: got=%v, want=%v", got, want) } }) }
func TestObjects(t *testing.T) { ctx := testutil.Context(ScopeFullControl) bucket = os.Getenv(envBucket) // Cleanup. cleanup(t, "obj") const defaultType = "text/plain" // Test Writer. for _, obj := range objects { t.Logf("Writing %v", obj) wc := NewWriter(ctx, bucket, obj) wc.ContentType = defaultType c := randomContents() if _, err := wc.Write(c); err != nil { t.Errorf("Write for %v failed with %v", obj, err) } if err := wc.Close(); err != nil { t.Errorf("Close for %v failed with %v", obj, err) } contents[obj] = c } // Test Reader. for _, obj := range objects { t.Logf("Creating a reader to read %v", obj) rc, err := NewReader(ctx, bucket, obj) if err != nil { t.Errorf("Can't create a reader for %v, errored with %v", obj, err) } slurp, err := ioutil.ReadAll(rc) if err != nil { t.Errorf("Can't ReadAll object %v, errored with %v", obj, err) } if got, want := slurp, contents[obj]; !bytes.Equal(got, want) { t.Errorf("Contents (%v) = %q; want %q", obj, got, want) } rc.Close() } // Test NotFound. _, err := NewReader(ctx, bucket, "obj-not-exists") if err != ErrObjectNotExist { t.Errorf("Object should not exist, err found to be %v", err) } name := objects[0] // Test StatObject. o, err := StatObject(ctx, bucket, name) if err != nil { t.Error(err) } if got, want := o.Name, name; got != want { t.Errorf("Name (%v) = %q; want %q", name, got, want) } if got, want := o.ContentType, defaultType; got != want { t.Errorf("ContentType (%v) = %q; want %q", name, got, want) } // Test object copy. copy, err := CopyObject(ctx, bucket, name, bucket, ObjectAttrs{ Name: copyObj, ContentType: "text/html", }) if err != nil { t.Errorf("CopyObject failed with %v", err) } if copy.Name != copyObj { t.Errorf("Copy object's name = %q; want %q", copy.Name, copyObj) } if copy.Bucket != bucket { t.Errorf("Copy object's bucket = %q; want %q", copy.Bucket, bucket) } // Test UpdateAttrs. updated, err := UpdateAttrs(ctx, bucket, name, ObjectAttrs{ ContentType: "text/html", ACL: []ACLRule{{Entity: "domain-google.com", Role: RoleReader}}, }) if err != nil { t.Errorf("UpdateAttrs failed with %v", err) } if want := "text/html"; updated.ContentType != want { t.Errorf("updated.ContentType == %q; want %q", updated.ContentType, want) } // Test checksums. checksumCases := []struct { name string contents [][]byte size int64 md5 string crc32c uint32 }{ { name: "checksum-object", contents: [][]byte{[]byte("hello"), []byte("world")}, size: 10, md5: "fc5e038d38a57032085441e7fe7010b0", crc32c: 1456190592, }, { name: "zero-object", contents: [][]byte{}, size: 0, md5: "d41d8cd98f00b204e9800998ecf8427e", crc32c: 0, }, } for _, c := range checksumCases { wc := NewWriter(ctx, bucket, c.name) for _, data := range c.contents { if _, err := wc.Write(data); err != nil { t.Errorf("Write(%q) failed with %q", data, err) } } if err = wc.Close(); err != nil { t.Errorf("%q: close failed with %q", c.name, err) } obj := wc.Object() if got, want := obj.Size, c.size; got != want { t.Errorf("Object (%q) Size = %v; want %v", c.name, got, want) } if got, want := fmt.Sprintf("%x", obj.MD5), c.md5; got != want { t.Errorf("Object (%q) MD5 = %q; want %q", c.name, got, want) } if got, want := obj.CRC32C, c.crc32c; got != want { t.Errorf("Object (%q) CRC32C = %v; want %v", c.name, got, want) } } // Test public ACL. publicObj := objects[0] if err = PutACLRule(ctx, bucket, publicObj, AllUsers, RoleReader); err != nil { t.Errorf("PutACLRule failed with %v", err) } publicCtx := testutil.NoAuthContext() rc, err := NewReader(publicCtx, bucket, publicObj) if err != nil { t.Error(err) } slurp, err := ioutil.ReadAll(rc) if err != nil { t.Errorf("ReadAll failed with %v", err) } if string(slurp) != string(contents[publicObj]) { t.Errorf("Public object's content is expected to be %s, found %s", contents[publicObj], slurp) } rc.Close() // Test writer error handling. wc := NewWriter(publicCtx, bucket, publicObj) if _, err := wc.Write([]byte("hello")); err != nil { t.Errorf("Write unexpectedly failed with %v", err) } if err = wc.Close(); err == nil { t.Error("Close expected an error, found none") } // DeleteObject object. // The rest of the other object will be deleted during // the initial cleanup. This tests exists, so we still can cover // deletion if there are no objects on the bucket to clean. if err := DeleteObject(ctx, bucket, copyObj); err != nil { t.Errorf("Deletion of %v failed with %v", copyObj, err) } _, err = StatObject(ctx, bucket, copyObj) if err != ErrObjectNotExist { t.Errorf("Copy is expected to be deleted, stat errored with %v", err) } }
func TestAll(t *testing.T) { ctx := testutil.Context(ScopePubSub, ScopeCloudPlatform) now := time.Now() topic := fmt.Sprintf("topic-%d", now.Unix()) subscription := fmt.Sprintf("subscription-%d", now.Unix()) if err := CreateTopic(ctx, topic); err != nil { t.Errorf("CreateTopic error: %v", err) } if err := CreateSub(ctx, subscription, topic, time.Duration(0), ""); err != nil { t.Errorf("CreateSub error: %v", err) } exists, err := TopicExists(ctx, topic) if err != nil { t.Errorf("TopicExists error: %v", err) } if !exists { t.Errorf("topic %s should exist, but it doesn't", topic) } exists, err = SubExists(ctx, subscription) if err != nil { t.Errorf("SubExists error: %v", err) } if !exists { t.Errorf("subscription %s should exist, but it doesn't", subscription) } max := 10 msgs := make([]*Message, max) expectedMsgs := make(map[string]bool, max) for i := 0; i < max; i++ { text := fmt.Sprintf("a message with an index %d", i) labels := make(map[string]string) labels["foo"] = "bar" msgs[i] = &Message{ Data: []byte(text), Labels: labels, } expectedMsgs[text] = false } ids, err := Publish(ctx, topic, msgs...) if err != nil { t.Errorf("Publish (1) error: %v", err) } if len(ids) != max { t.Errorf("unexpected number of message IDs received; %d, want %d", len(ids), max) } expectedIDs := make(map[string]bool, max) for _, id := range ids { expectedIDs[id] = false } received, err := PullWait(ctx, subscription, max) if err != nil { t.Errorf("PullWait error: %v", err) } if len(received) != max { t.Errorf("unexpected number of messages received; %d, want %d", len(received), max) } for _, msg := range received { expectedMsgs[string(msg.Data)] = true expectedIDs[msg.ID] = true if msg.Labels["foo"] != "bar" { t.Errorf("message label foo is expected to be 'bar', found '%s'", msg.Labels["foo"]) } } for msg, found := range expectedMsgs { if !found { t.Errorf("message '%s' should be received", msg) } } for id, found := range expectedIDs { if !found { t.Errorf("message with the message id '%s' should be received", id) } } err = DeleteSub(ctx, subscription) if err != nil { t.Errorf("DeleteSub error: %v", err) } err = DeleteTopic(ctx, topic) if err != nil { t.Errorf("DeleteTopic error: %v", err) } }