github.com/thiagoyeds/go-cloud@v0.26.0/docstore/gcpfirestore/fs_test.go (about) 1 // Copyright 2019 The Go Cloud Development Kit Authors 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 // https://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 15 package gcpfirestore 16 17 import ( 18 "context" 19 "errors" 20 "testing" 21 22 vkit "cloud.google.com/go/firestore/apiv1" 23 "gocloud.dev/docstore" 24 "gocloud.dev/docstore/driver" 25 "gocloud.dev/docstore/drivertest" 26 "gocloud.dev/internal/testing/setup" 27 "google.golang.org/api/option" 28 pb "google.golang.org/genproto/googleapis/firestore/v1" 29 "google.golang.org/grpc/status" 30 "google.golang.org/protobuf/proto" 31 tspb "google.golang.org/protobuf/types/known/timestamppb" 32 ) 33 34 const ( 35 // projectID is the project ID that was used during the last test run using --record. 36 projectID = "go-cloud-test-216917" 37 collectionName1 = "docstore-test-1" 38 collectionName2 = "docstore-test-2" 39 collectionName3 = "docstore-test-3" 40 endPoint = "firestore.googleapis.com:443" 41 ) 42 43 type harness struct { 44 client *vkit.Client 45 done func() 46 } 47 48 func newHarness(ctx context.Context, t *testing.T) (drivertest.Harness, error) { 49 conn, done := setup.NewGCPgRPCConn(ctx, t, endPoint, "docstore") 50 client, err := vkit.NewClient(ctx, option.WithGRPCConn(conn)) 51 if err != nil { 52 done() 53 return nil, err 54 } 55 return &harness{client, done}, nil 56 } 57 58 func (h *harness) MakeCollection(_ context.Context, kind drivertest.CollectionKind) (driver.Collection, error) { 59 switch kind { 60 case drivertest.SingleKey, drivertest.NoRev: 61 return newCollection(h.client, CollectionResourceID(projectID, collectionName1), drivertest.KeyField, nil, nil) 62 case drivertest.TwoKey: 63 return newCollection(h.client, CollectionResourceID(projectID, collectionName2), "", 64 func(doc docstore.Document) string { 65 return drivertest.HighScoreKey(doc).(string) 66 }, &Options{AllowLocalFilters: true}) 67 case drivertest.AltRev: 68 return newCollection(h.client, CollectionResourceID(projectID, collectionName1), drivertest.KeyField, nil, 69 &Options{RevisionField: drivertest.AlternateRevisionField}) 70 default: 71 panic("bad kind") 72 } 73 } 74 75 func (*harness) BeforeDoTypes() []interface{} { 76 return []interface{}{&pb.BatchGetDocumentsRequest{}, &pb.CommitRequest{}} 77 } 78 79 func (*harness) BeforeQueryTypes() []interface{} { 80 return []interface{}{&pb.RunQueryRequest{}} 81 } 82 83 func (*harness) RevisionsEqual(rev1, rev2 interface{}) bool { 84 return proto.Equal(rev1.(*tspb.Timestamp), rev2.(*tspb.Timestamp)) 85 } 86 87 func (h *harness) Close() { 88 _ = h.client.Close() 89 h.done() 90 } 91 92 // codecTester implements drivertest.CodecTester. 93 type codecTester struct { 94 nc *nativeCodec 95 } 96 97 func (*codecTester) UnsupportedTypes() []drivertest.UnsupportedType { 98 return []drivertest.UnsupportedType{drivertest.Uint, drivertest.Arrays} 99 } 100 101 func (c *codecTester) NativeEncode(x interface{}) (interface{}, error) { 102 return c.nc.Encode(x) 103 } 104 105 func (c *codecTester) NativeDecode(value, dest interface{}) error { 106 return c.nc.Decode(value.(*pb.Document), dest) 107 } 108 109 func (c *codecTester) DocstoreEncode(x interface{}) (interface{}, error) { 110 var e encoder 111 if err := drivertest.MustDocument(x).Encode(&e); err != nil { 112 return nil, err 113 } 114 return &pb.Document{ 115 Name: "projects/P/databases/(default)/documents/C/D", 116 Fields: e.pv.GetMapValue().Fields, 117 }, nil 118 } 119 120 func (c *codecTester) DocstoreDecode(value, dest interface{}) error { 121 mv := &pb.Value{ValueType: &pb.Value_MapValue{MapValue: &pb.MapValue{ 122 Fields: value.(*pb.Document).Fields, 123 }}} 124 return drivertest.MustDocument(dest).Decode(decoder{mv}) 125 } 126 127 type verifyAs struct{} 128 129 func (verifyAs) Name() string { 130 return "verify As" 131 } 132 133 func (verifyAs) CollectionCheck(coll *docstore.Collection) error { 134 var fc *vkit.Client 135 if !coll.As(&fc) { 136 return errors.New("Collection.As failed") 137 } 138 return nil 139 } 140 141 func (verifyAs) QueryCheck(it *docstore.DocumentIterator) error { 142 var c pb.Firestore_RunQueryClient 143 if !it.As(&c) { 144 return errors.New("DocumentIterator.As failed") 145 } 146 _, err := c.Header() 147 return err 148 } 149 150 func (v verifyAs) ErrorCheck(c *docstore.Collection, err error) error { 151 var s *status.Status 152 if !c.ErrorAs(err, &s) { 153 return errors.New("Collection.ErrorAs failed") 154 } 155 return nil 156 } 157 158 func TestConformance(t *testing.T) { 159 drivertest.MakeUniqueStringDeterministicForTesting(1) 160 nc, err := newNativeCodec() 161 if err != nil { 162 t.Fatal(err) 163 } 164 drivertest.RunConformanceTests(t, newHarness, &codecTester{nc}, []drivertest.AsTest{verifyAs{}}) 165 } 166 167 func BenchmarkConformance(b *testing.B) { 168 ctx := context.Background() 169 client, err := vkit.NewClient(ctx) 170 if err != nil { 171 b.Fatal(err) 172 } 173 coll, err := newCollection(client, CollectionResourceID(projectID, collectionName3), drivertest.KeyField, nil, nil) 174 if err != nil { 175 b.Fatal(err) 176 } 177 drivertest.RunBenchmarks(b, docstore.NewCollection(coll)) 178 } 179 180 // gcpfirestore-specific tests. 181 182 func TestResourceIDRegexp(t *testing.T) { 183 for _, good := range []string{ 184 "projects/abc-_.309/databases/(default)/documents/C", 185 "projects/P/databases/(default)/documents/C/D/E", 186 } { 187 if !resourceIDRE.MatchString(good) { 188 t.Errorf("%q did not match but should have", good) 189 } 190 } 191 192 for _, bad := range []string{ 193 "", 194 "Projects/P/databases/(default)/documents/C", 195 "P/databases/(default)/documents/C", 196 "projects/P/Q/databases/(default)/documents/C", 197 "projects/P/databases/mydb/documents/C", 198 "projects/P/databases/(default)/C", 199 "projects/P/databases/(default)/documents/", 200 "projects/P/databases/(default)", 201 } { 202 if resourceIDRE.MatchString(bad) { 203 t.Errorf("%q matched but should not have", bad) 204 } 205 } 206 }