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.
 
 
 

433 lines
11 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. // A runner for the conformance tests.
  15. package firestore
  16. import (
  17. "encoding/json"
  18. "errors"
  19. "fmt"
  20. "io/ioutil"
  21. "math"
  22. "path"
  23. "path/filepath"
  24. "strings"
  25. "testing"
  26. "time"
  27. pb "cloud.google.com/go/firestore/genproto"
  28. "github.com/golang/protobuf/proto"
  29. "github.com/golang/protobuf/ptypes"
  30. ts "github.com/golang/protobuf/ptypes/timestamp"
  31. "github.com/google/go-cmp/cmp"
  32. "golang.org/x/net/context"
  33. "google.golang.org/api/iterator"
  34. fspb "google.golang.org/genproto/googleapis/firestore/v1beta1"
  35. )
  36. const conformanceTestWatchTargetID = 1
  37. func TestConformanceTests(t *testing.T) {
  38. const dir = "testdata"
  39. fis, err := ioutil.ReadDir(dir)
  40. if err != nil {
  41. t.Fatal(err)
  42. }
  43. wtid := watchTargetID
  44. watchTargetID = conformanceTestWatchTargetID
  45. defer func() { watchTargetID = wtid }()
  46. n := 0
  47. for _, fi := range fis {
  48. if strings.HasSuffix(fi.Name(), ".textproto") {
  49. runTestFromFile(t, filepath.Join(dir, fi.Name()))
  50. n++
  51. }
  52. }
  53. t.Logf("ran %d conformance tests", n)
  54. }
  55. func runTestFromFile(t *testing.T, filename string) {
  56. bytes, err := ioutil.ReadFile(filename)
  57. if err != nil {
  58. t.Fatalf("%s: %v", filename, err)
  59. }
  60. var test pb.Test
  61. if err := proto.UnmarshalText(string(bytes), &test); err != nil {
  62. t.Fatalf("unmarshalling %s: %v", filename, err)
  63. }
  64. msg := fmt.Sprintf("%s (file %s)", test.Description, filepath.Base(filename))
  65. runTest(t, msg, &test)
  66. }
  67. func runTest(t *testing.T, msg string, test *pb.Test) {
  68. check := func(gotErr error, wantErr bool) bool {
  69. if wantErr && gotErr == nil {
  70. t.Errorf("%s: got nil, want error", msg)
  71. return false
  72. } else if !wantErr && gotErr != nil {
  73. t.Errorf("%s: %v", msg, gotErr)
  74. return false
  75. }
  76. return true
  77. }
  78. ctx := context.Background()
  79. c, srv := newMock(t)
  80. switch tt := test.Test.(type) {
  81. case *pb.Test_Get:
  82. req := &fspb.BatchGetDocumentsRequest{
  83. Database: c.path(),
  84. Documents: []string{tt.Get.DocRefPath},
  85. }
  86. srv.addRPC(req, []interface{}{
  87. &fspb.BatchGetDocumentsResponse{
  88. Result: &fspb.BatchGetDocumentsResponse_Found{&fspb.Document{
  89. Name: tt.Get.DocRefPath,
  90. CreateTime: &ts.Timestamp{},
  91. UpdateTime: &ts.Timestamp{},
  92. }},
  93. ReadTime: &ts.Timestamp{},
  94. },
  95. })
  96. ref := docRefFromPath(tt.Get.DocRefPath, c)
  97. _, err := ref.Get(ctx)
  98. if err != nil {
  99. t.Errorf("%s: %v", msg, err)
  100. return
  101. }
  102. // Checking response would just be testing the function converting a Document
  103. // proto to a DocumentSnapshot, hence uninteresting.
  104. case *pb.Test_Create:
  105. srv.addRPC(tt.Create.Request, commitResponseForSet)
  106. ref := docRefFromPath(tt.Create.DocRefPath, c)
  107. data, err := convertData(tt.Create.JsonData)
  108. if err != nil {
  109. t.Errorf("%s: %v", msg, err)
  110. return
  111. }
  112. _, err = ref.Create(ctx, data)
  113. check(err, tt.Create.IsError)
  114. case *pb.Test_Set:
  115. srv.addRPC(tt.Set.Request, commitResponseForSet)
  116. ref := docRefFromPath(tt.Set.DocRefPath, c)
  117. data, err := convertData(tt.Set.JsonData)
  118. if err != nil {
  119. t.Errorf("%s: %v", msg, err)
  120. return
  121. }
  122. var opts []SetOption
  123. if tt.Set.Option != nil {
  124. opts = []SetOption{convertSetOption(tt.Set.Option)}
  125. }
  126. _, err = ref.Set(ctx, data, opts...)
  127. check(err, tt.Set.IsError)
  128. case *pb.Test_Update:
  129. // Ignore Update test because we only support UpdatePaths.
  130. // Not to worry, every Update test has a corresponding UpdatePaths test.
  131. case *pb.Test_UpdatePaths:
  132. srv.addRPC(tt.UpdatePaths.Request, commitResponseForSet)
  133. ref := docRefFromPath(tt.UpdatePaths.DocRefPath, c)
  134. preconds := convertPrecondition(t, tt.UpdatePaths.Precondition)
  135. paths := convertFieldPaths(tt.UpdatePaths.FieldPaths)
  136. var ups []Update
  137. for i, path := range paths {
  138. val, err := convertJSONValue(tt.UpdatePaths.JsonValues[i])
  139. if err != nil {
  140. t.Fatalf("%s: %v", msg, err)
  141. }
  142. ups = append(ups, Update{
  143. FieldPath: path,
  144. Value: val,
  145. })
  146. }
  147. _, err := ref.Update(ctx, ups, preconds...)
  148. check(err, tt.UpdatePaths.IsError)
  149. case *pb.Test_Delete:
  150. srv.addRPC(tt.Delete.Request, commitResponseForSet)
  151. ref := docRefFromPath(tt.Delete.DocRefPath, c)
  152. preconds := convertPrecondition(t, tt.Delete.Precondition)
  153. _, err := ref.Delete(ctx, preconds...)
  154. check(err, tt.Delete.IsError)
  155. case *pb.Test_Query:
  156. q := convertQuery(t, tt.Query)
  157. got, err := q.toProto()
  158. if check(err, tt.Query.IsError) && err == nil {
  159. if want := tt.Query.Query; !proto.Equal(got, want) {
  160. t.Errorf("%s\ngot: %s\nwant: %s", msg, proto.MarshalTextString(got), proto.MarshalTextString(want))
  161. }
  162. }
  163. case *pb.Test_Listen:
  164. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  165. defer cancel()
  166. iter := c.Collection("C").OrderBy("a", Asc).Snapshots(ctx)
  167. var rs []interface{}
  168. for _, r := range tt.Listen.Responses {
  169. rs = append(rs, r)
  170. }
  171. srv.addRPC(&fspb.ListenRequest{
  172. Database: "projects/projectID/databases/(default)",
  173. TargetChange: &fspb.ListenRequest_AddTarget{iter.ws.target},
  174. }, rs)
  175. got, err := nSnapshots(iter, len(tt.Listen.Snapshots))
  176. if err != nil {
  177. t.Errorf("%s: %v", msg, err)
  178. } else if diff := cmp.Diff(got, tt.Listen.Snapshots); diff != "" {
  179. t.Errorf("%s:\n%s", msg, diff)
  180. }
  181. if tt.Listen.IsError {
  182. _, err := iter.Next()
  183. if err == nil {
  184. t.Errorf("%s: got nil, want error", msg)
  185. }
  186. }
  187. default:
  188. t.Fatalf("unknown test type %T", tt)
  189. }
  190. }
  191. func nSnapshots(iter *QuerySnapshotIterator, n int) ([]*pb.Snapshot, error) {
  192. var snaps []*pb.Snapshot
  193. for i := 0; i < n; i++ {
  194. diter, err := iter.Next()
  195. if err != nil {
  196. return snaps, err
  197. }
  198. s := &pb.Snapshot{ReadTime: mustTimestampProto(iter.ReadTime)}
  199. for {
  200. doc, err := diter.Next()
  201. if err == iterator.Done {
  202. break
  203. }
  204. if err != nil {
  205. return snaps, err
  206. }
  207. s.Docs = append(s.Docs, doc.proto)
  208. }
  209. for _, c := range iter.Changes {
  210. var k pb.DocChange_Kind
  211. switch c.Kind {
  212. case DocumentAdded:
  213. k = pb.DocChange_ADDED
  214. case DocumentRemoved:
  215. k = pb.DocChange_REMOVED
  216. case DocumentModified:
  217. k = pb.DocChange_MODIFIED
  218. default:
  219. panic("bad kind")
  220. }
  221. s.Changes = append(s.Changes, &pb.DocChange{
  222. Kind: k,
  223. Doc: c.Doc.proto,
  224. OldIndex: int32(c.OldIndex),
  225. NewIndex: int32(c.NewIndex),
  226. })
  227. }
  228. snaps = append(snaps, s)
  229. }
  230. return snaps, nil
  231. }
  232. func docRefFromPath(p string, c *Client) *DocumentRef {
  233. return &DocumentRef{
  234. Path: p,
  235. ID: path.Base(p),
  236. Parent: &CollectionRef{c: c},
  237. }
  238. }
  239. func convertJSONValue(jv string) (interface{}, error) {
  240. var val interface{}
  241. if err := json.Unmarshal([]byte(jv), &val); err != nil {
  242. return nil, err
  243. }
  244. return convertTestValue(val), nil
  245. }
  246. func convertData(jsonData string) (map[string]interface{}, error) {
  247. var m map[string]interface{}
  248. if err := json.Unmarshal([]byte(jsonData), &m); err != nil {
  249. return nil, err
  250. }
  251. return convertTestMap(m), nil
  252. }
  253. func convertTestMap(m map[string]interface{}) map[string]interface{} {
  254. for k, v := range m {
  255. m[k] = convertTestValue(v)
  256. }
  257. return m
  258. }
  259. func convertTestValue(v interface{}) interface{} {
  260. switch v := v.(type) {
  261. case string:
  262. switch v {
  263. case "ServerTimestamp":
  264. return ServerTimestamp
  265. case "Delete":
  266. return Delete
  267. case "NaN":
  268. return math.NaN()
  269. default:
  270. return v
  271. }
  272. case float64:
  273. if v == float64(int(v)) {
  274. return int(v)
  275. }
  276. return v
  277. case []interface{}:
  278. for i, e := range v {
  279. v[i] = convertTestValue(e)
  280. }
  281. return v
  282. case map[string]interface{}:
  283. return convertTestMap(v)
  284. default:
  285. return v
  286. }
  287. }
  288. func convertSetOption(opt *pb.SetOption) SetOption {
  289. if opt.All {
  290. return MergeAll
  291. }
  292. return Merge(convertFieldPaths(opt.Fields)...)
  293. }
  294. func convertFieldPaths(fps []*pb.FieldPath) []FieldPath {
  295. var res []FieldPath
  296. for _, fp := range fps {
  297. res = append(res, fp.Field)
  298. }
  299. return res
  300. }
  301. func convertPrecondition(t *testing.T, fp *fspb.Precondition) []Precondition {
  302. if fp == nil {
  303. return nil
  304. }
  305. var pc Precondition
  306. switch fp := fp.ConditionType.(type) {
  307. case *fspb.Precondition_Exists:
  308. pc = exists(fp.Exists)
  309. case *fspb.Precondition_UpdateTime:
  310. tm, err := ptypes.Timestamp(fp.UpdateTime)
  311. if err != nil {
  312. t.Fatal(err)
  313. }
  314. pc = LastUpdateTime(tm)
  315. default:
  316. t.Fatalf("unknown precondition type %T", fp)
  317. }
  318. return []Precondition{pc}
  319. }
  320. func convertQuery(t *testing.T, qt *pb.QueryTest) Query {
  321. parts := strings.Split(qt.CollPath, "/")
  322. q := Query{
  323. parentPath: strings.Join(parts[:len(parts)-2], "/"),
  324. collectionID: parts[len(parts)-1],
  325. }
  326. for _, c := range qt.Clauses {
  327. switch c := c.Clause.(type) {
  328. case *pb.Clause_Select:
  329. q = q.SelectPaths(convertFieldPaths(c.Select.Fields)...)
  330. case *pb.Clause_OrderBy:
  331. var dir Direction
  332. switch c.OrderBy.Direction {
  333. case "asc":
  334. dir = Asc
  335. case "desc":
  336. dir = Desc
  337. default:
  338. t.Fatalf("bad direction: %q", c.OrderBy.Direction)
  339. }
  340. q = q.OrderByPath(FieldPath(c.OrderBy.Path.Field), dir)
  341. case *pb.Clause_Where:
  342. val, err := convertJSONValue(c.Where.JsonValue)
  343. if err != nil {
  344. t.Fatal(err)
  345. }
  346. q = q.WherePath(FieldPath(c.Where.Path.Field), c.Where.Op, val)
  347. case *pb.Clause_Offset:
  348. q = q.Offset(int(c.Offset))
  349. case *pb.Clause_Limit:
  350. q = q.Limit(int(c.Limit))
  351. case *pb.Clause_StartAt:
  352. q = q.StartAt(convertCursor(t, c.StartAt)...)
  353. case *pb.Clause_StartAfter:
  354. q = q.StartAfter(convertCursor(t, c.StartAfter)...)
  355. case *pb.Clause_EndAt:
  356. q = q.EndAt(convertCursor(t, c.EndAt)...)
  357. case *pb.Clause_EndBefore:
  358. q = q.EndBefore(convertCursor(t, c.EndBefore)...)
  359. default:
  360. t.Fatalf("bad clause type %T", c)
  361. }
  362. }
  363. return q
  364. }
  365. // Returns args to a cursor method (StartAt, etc.).
  366. func convertCursor(t *testing.T, c *pb.Cursor) []interface{} {
  367. if c.DocSnapshot != nil {
  368. ds, err := convertDocSnapshot(c.DocSnapshot)
  369. if err != nil {
  370. t.Fatal(err)
  371. }
  372. return []interface{}{ds}
  373. }
  374. var vals []interface{}
  375. for _, jv := range c.JsonValues {
  376. v, err := convertJSONValue(jv)
  377. if err != nil {
  378. t.Fatal(err)
  379. }
  380. vals = append(vals, v)
  381. }
  382. return vals
  383. }
  384. func convertDocSnapshot(ds *pb.DocSnapshot) (*DocumentSnapshot, error) {
  385. data, err := convertData(ds.JsonData)
  386. if err != nil {
  387. return nil, err
  388. }
  389. doc, transformPaths, err := toProtoDocument(data)
  390. if err != nil {
  391. return nil, err
  392. }
  393. if len(transformPaths) > 0 {
  394. return nil, errors.New("saw transform paths in DocSnapshot")
  395. }
  396. return &DocumentSnapshot{
  397. Ref: &DocumentRef{
  398. Path: ds.Path,
  399. Parent: &CollectionRef{Path: path.Dir(ds.Path)},
  400. },
  401. proto: doc,
  402. }, nil
  403. }