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.
 
 
 

444 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. "context"
  18. "encoding/json"
  19. "errors"
  20. "fmt"
  21. "io/ioutil"
  22. "math"
  23. "path"
  24. "path/filepath"
  25. "strings"
  26. "testing"
  27. "time"
  28. pb "cloud.google.com/go/firestore/genproto"
  29. "github.com/golang/protobuf/proto"
  30. "github.com/golang/protobuf/ptypes"
  31. ts "github.com/golang/protobuf/ptypes/timestamp"
  32. "github.com/google/go-cmp/cmp"
  33. "google.golang.org/api/iterator"
  34. fspb "google.golang.org/genproto/googleapis/firestore/v1"
  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.Fatalf("%s: got nil, want error", msg)
  71. return false
  72. } else if !wantErr && gotErr != nil {
  73. t.Fatalf("%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.Fatalf("%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.Fatalf("%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.Fatalf("%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.Fatalf("%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.Fatalf("%s: %v", msg, err)
  178. } else if diff := cmp.Diff(got, tt.Listen.Snapshots); diff != "" {
  179. t.Fatalf("%s:\n%s", msg, diff)
  180. }
  181. if tt.Listen.IsError {
  182. _, err := iter.Next()
  183. if err == nil {
  184. t.Fatalf("%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. qsnap, err := iter.Next()
  195. if err != nil {
  196. return snaps, err
  197. }
  198. s := &pb.Snapshot{ReadTime: mustTimestampProto(qsnap.ReadTime)}
  199. for {
  200. doc, err := qsnap.Documents.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 qsnap.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. if len(v) > 0 {
  279. if fv, ok := v[0].(string); ok {
  280. if fv == "ArrayUnion" {
  281. return ArrayUnion(convertTestValue(v[1:]).([]interface{})...)
  282. }
  283. if fv == "ArrayRemove" {
  284. return ArrayRemove(convertTestValue(v[1:]).([]interface{})...)
  285. }
  286. }
  287. }
  288. for i, e := range v {
  289. v[i] = convertTestValue(e)
  290. }
  291. return v
  292. case map[string]interface{}:
  293. return convertTestMap(v)
  294. default:
  295. return v
  296. }
  297. }
  298. func convertSetOption(opt *pb.SetOption) SetOption {
  299. if opt.All {
  300. return MergeAll
  301. }
  302. return Merge(convertFieldPaths(opt.Fields)...)
  303. }
  304. func convertFieldPaths(fps []*pb.FieldPath) []FieldPath {
  305. var res []FieldPath
  306. for _, fp := range fps {
  307. res = append(res, fp.Field)
  308. }
  309. return res
  310. }
  311. func convertPrecondition(t *testing.T, fp *fspb.Precondition) []Precondition {
  312. if fp == nil {
  313. return nil
  314. }
  315. var pc Precondition
  316. switch fp := fp.ConditionType.(type) {
  317. case *fspb.Precondition_Exists:
  318. pc = exists(fp.Exists)
  319. case *fspb.Precondition_UpdateTime:
  320. tm, err := ptypes.Timestamp(fp.UpdateTime)
  321. if err != nil {
  322. t.Fatal(err)
  323. }
  324. pc = LastUpdateTime(tm)
  325. default:
  326. t.Fatalf("unknown precondition type %T", fp)
  327. }
  328. return []Precondition{pc}
  329. }
  330. func convertQuery(t *testing.T, qt *pb.QueryTest) Query {
  331. parts := strings.Split(qt.CollPath, "/")
  332. q := Query{
  333. parentPath: strings.Join(parts[:len(parts)-2], "/"),
  334. collectionID: parts[len(parts)-1],
  335. path: qt.CollPath,
  336. }
  337. for _, c := range qt.Clauses {
  338. switch c := c.Clause.(type) {
  339. case *pb.Clause_Select:
  340. q = q.SelectPaths(convertFieldPaths(c.Select.Fields)...)
  341. case *pb.Clause_OrderBy:
  342. var dir Direction
  343. switch c.OrderBy.Direction {
  344. case "asc":
  345. dir = Asc
  346. case "desc":
  347. dir = Desc
  348. default:
  349. t.Fatalf("bad direction: %q", c.OrderBy.Direction)
  350. }
  351. q = q.OrderByPath(FieldPath(c.OrderBy.Path.Field), dir)
  352. case *pb.Clause_Where:
  353. val, err := convertJSONValue(c.Where.JsonValue)
  354. if err != nil {
  355. t.Fatal(err)
  356. }
  357. q = q.WherePath(FieldPath(c.Where.Path.Field), c.Where.Op, val)
  358. case *pb.Clause_Offset:
  359. q = q.Offset(int(c.Offset))
  360. case *pb.Clause_Limit:
  361. q = q.Limit(int(c.Limit))
  362. case *pb.Clause_StartAt:
  363. q = q.StartAt(convertCursor(t, c.StartAt)...)
  364. case *pb.Clause_StartAfter:
  365. q = q.StartAfter(convertCursor(t, c.StartAfter)...)
  366. case *pb.Clause_EndAt:
  367. q = q.EndAt(convertCursor(t, c.EndAt)...)
  368. case *pb.Clause_EndBefore:
  369. q = q.EndBefore(convertCursor(t, c.EndBefore)...)
  370. default:
  371. t.Fatalf("bad clause type %T", c)
  372. }
  373. }
  374. return q
  375. }
  376. // Returns args to a cursor method (StartAt, etc.).
  377. func convertCursor(t *testing.T, c *pb.Cursor) []interface{} {
  378. if c.DocSnapshot != nil {
  379. ds, err := convertDocSnapshot(c.DocSnapshot)
  380. if err != nil {
  381. t.Fatal(err)
  382. }
  383. return []interface{}{ds}
  384. }
  385. var vals []interface{}
  386. for _, jv := range c.JsonValues {
  387. v, err := convertJSONValue(jv)
  388. if err != nil {
  389. t.Fatal(err)
  390. }
  391. vals = append(vals, v)
  392. }
  393. return vals
  394. }
  395. func convertDocSnapshot(ds *pb.DocSnapshot) (*DocumentSnapshot, error) {
  396. data, err := convertData(ds.JsonData)
  397. if err != nil {
  398. return nil, err
  399. }
  400. doc, transformPaths, err := toProtoDocument(data)
  401. if err != nil {
  402. return nil, err
  403. }
  404. if len(transformPaths) > 0 {
  405. return nil, errors.New("saw transform paths in DocSnapshot")
  406. }
  407. return &DocumentSnapshot{
  408. Ref: &DocumentRef{
  409. Path: ds.Path,
  410. Parent: &CollectionRef{Path: path.Dir(ds.Path)},
  411. },
  412. proto: doc,
  413. }, nil
  414. }