You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

213 lines
6.0 KiB

  1. // Copyright 2017 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package firestore
  15. import (
  16. "testing"
  17. tspb "github.com/golang/protobuf/ptypes/timestamp"
  18. "golang.org/x/net/context"
  19. pb "google.golang.org/genproto/googleapis/firestore/v1beta1"
  20. "google.golang.org/grpc/codes"
  21. "google.golang.org/grpc/status"
  22. )
  23. var testClient = &Client{
  24. projectID: "projectID",
  25. databaseID: "(default)",
  26. }
  27. func TestClientCollectionAndDoc(t *testing.T) {
  28. coll1 := testClient.Collection("X")
  29. db := "projects/projectID/databases/(default)"
  30. wantc1 := &CollectionRef{
  31. c: testClient,
  32. parentPath: db,
  33. Parent: nil,
  34. ID: "X",
  35. Path: "projects/projectID/databases/(default)/documents/X",
  36. Query: Query{c: testClient, collectionID: "X", parentPath: db},
  37. }
  38. if !testEqual(coll1, wantc1) {
  39. t.Fatalf("got\n%+v\nwant\n%+v", coll1, wantc1)
  40. }
  41. doc1 := testClient.Doc("X/a")
  42. wantd1 := &DocumentRef{
  43. Parent: coll1,
  44. ID: "a",
  45. Path: "projects/projectID/databases/(default)/documents/X/a",
  46. }
  47. if !testEqual(doc1, wantd1) {
  48. t.Fatalf("got %+v, want %+v", doc1, wantd1)
  49. }
  50. coll2 := testClient.Collection("X/a/Y")
  51. parentPath := "projects/projectID/databases/(default)/documents/X/a"
  52. wantc2 := &CollectionRef{
  53. c: testClient,
  54. parentPath: parentPath,
  55. Parent: doc1,
  56. ID: "Y",
  57. Path: "projects/projectID/databases/(default)/documents/X/a/Y",
  58. Query: Query{c: testClient, collectionID: "Y", parentPath: parentPath},
  59. }
  60. if !testEqual(coll2, wantc2) {
  61. t.Fatalf("\ngot %+v\nwant %+v", coll2, wantc2)
  62. }
  63. doc2 := testClient.Doc("X/a/Y/b")
  64. wantd2 := &DocumentRef{
  65. Parent: coll2,
  66. ID: "b",
  67. Path: "projects/projectID/databases/(default)/documents/X/a/Y/b",
  68. }
  69. if !testEqual(doc2, wantd2) {
  70. t.Fatalf("got %+v, want %+v", doc2, wantd2)
  71. }
  72. }
  73. func TestClientCollDocErrors(t *testing.T) {
  74. for _, badColl := range []string{"", "/", "/a/", "/a/b", "a/b/", "a//b"} {
  75. coll := testClient.Collection(badColl)
  76. if coll != nil {
  77. t.Errorf("coll path %q: got %+v, want nil", badColl, coll)
  78. }
  79. }
  80. for _, badDoc := range []string{"", "a", "/", "/a", "a/", "a/b/c", "a//b/c"} {
  81. doc := testClient.Doc(badDoc)
  82. if doc != nil {
  83. t.Errorf("doc path %q: got %+v, want nil", badDoc, doc)
  84. }
  85. }
  86. }
  87. func TestGetAll(t *testing.T) {
  88. c, srv := newMock(t)
  89. defer c.Close()
  90. const dbPath = "projects/projectID/databases/(default)"
  91. req := &pb.BatchGetDocumentsRequest{
  92. Database: dbPath,
  93. Documents: []string{
  94. dbPath + "/documents/C/a",
  95. dbPath + "/documents/C/b",
  96. dbPath + "/documents/C/c",
  97. },
  98. }
  99. testGetAll(t, c, srv, dbPath, func(drs []*DocumentRef) ([]*DocumentSnapshot, error) {
  100. return c.GetAll(context.Background(), drs)
  101. }, req)
  102. }
  103. func testGetAll(t *testing.T, c *Client, srv *mockServer, dbPath string, getAll func([]*DocumentRef) ([]*DocumentSnapshot, error), req *pb.BatchGetDocumentsRequest) {
  104. wantPBDocs := []*pb.Document{
  105. {
  106. Name: dbPath + "/documents/C/a",
  107. CreateTime: aTimestamp,
  108. UpdateTime: aTimestamp,
  109. Fields: map[string]*pb.Value{"f": intval(2)},
  110. },
  111. nil,
  112. {
  113. Name: dbPath + "/documents/C/c",
  114. CreateTime: aTimestamp,
  115. UpdateTime: aTimestamp,
  116. Fields: map[string]*pb.Value{"f": intval(1)},
  117. },
  118. }
  119. wantReadTimes := []*tspb.Timestamp{aTimestamp, aTimestamp2, aTimestamp3}
  120. srv.addRPC(req,
  121. []interface{}{
  122. // deliberately put these out of order
  123. &pb.BatchGetDocumentsResponse{
  124. Result: &pb.BatchGetDocumentsResponse_Found{wantPBDocs[2]},
  125. ReadTime: aTimestamp3,
  126. },
  127. &pb.BatchGetDocumentsResponse{
  128. Result: &pb.BatchGetDocumentsResponse_Found{wantPBDocs[0]},
  129. ReadTime: aTimestamp,
  130. },
  131. &pb.BatchGetDocumentsResponse{
  132. Result: &pb.BatchGetDocumentsResponse_Missing{dbPath + "/documents/C/b"},
  133. ReadTime: aTimestamp2,
  134. },
  135. },
  136. )
  137. coll := c.Collection("C")
  138. var docRefs []*DocumentRef
  139. for _, name := range []string{"a", "b", "c"} {
  140. docRefs = append(docRefs, coll.Doc(name))
  141. }
  142. docs, err := getAll(docRefs)
  143. if err != nil {
  144. t.Fatal(err)
  145. }
  146. if got, want := len(docs), len(wantPBDocs); got != want {
  147. t.Errorf("got %d docs, wanted %d", got, want)
  148. }
  149. for i, got := range docs {
  150. want, err := newDocumentSnapshot(docRefs[i], wantPBDocs[i], c, wantReadTimes[i])
  151. if err != nil {
  152. t.Fatal(err)
  153. }
  154. if diff := testDiff(got, want); diff != "" {
  155. t.Errorf("#%d: got=--, want==++\n%s", i, diff)
  156. }
  157. }
  158. }
  159. func TestGetAllErrors(t *testing.T) {
  160. ctx := context.Background()
  161. const (
  162. dbPath = "projects/projectID/databases/(default)"
  163. docPath = dbPath + "/documents/C/a"
  164. )
  165. c, srv := newMock(t)
  166. if _, err := c.GetAll(ctx, []*DocumentRef{nil}); err != errNilDocRef {
  167. t.Errorf("got %v, want errNilDocRef", err)
  168. }
  169. // Internal server error.
  170. srv.addRPC(
  171. &pb.BatchGetDocumentsRequest{
  172. Database: dbPath,
  173. Documents: []string{docPath},
  174. },
  175. []interface{}{status.Errorf(codes.Internal, "")},
  176. )
  177. _, err := c.GetAll(ctx, []*DocumentRef{c.Doc("C/a")})
  178. codeEq(t, "GetAll #1", codes.Internal, err)
  179. // Doc appears as both found and missing (server bug).
  180. srv.reset()
  181. srv.addRPC(
  182. &pb.BatchGetDocumentsRequest{
  183. Database: dbPath,
  184. Documents: []string{docPath},
  185. },
  186. []interface{}{
  187. &pb.BatchGetDocumentsResponse{
  188. Result: &pb.BatchGetDocumentsResponse_Found{&pb.Document{Name: docPath}},
  189. ReadTime: aTimestamp,
  190. },
  191. &pb.BatchGetDocumentsResponse{
  192. Result: &pb.BatchGetDocumentsResponse_Missing{docPath},
  193. ReadTime: aTimestamp,
  194. },
  195. },
  196. )
  197. if _, err := c.GetAll(ctx, []*DocumentRef{c.Doc("C/a")}); err == nil {
  198. t.Error("got nil, want error")
  199. }
  200. }