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.
 
 
 

571 lines
14 KiB

  1. // Copyright 2014 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 datastore
  15. import (
  16. "context"
  17. "errors"
  18. "fmt"
  19. "reflect"
  20. "sort"
  21. "testing"
  22. "cloud.google.com/go/internal/testutil"
  23. "github.com/golang/protobuf/proto"
  24. "github.com/google/go-cmp/cmp"
  25. pb "google.golang.org/genproto/googleapis/datastore/v1"
  26. "google.golang.org/grpc"
  27. )
  28. var (
  29. key1 = &pb.Key{
  30. Path: []*pb.Key_PathElement{
  31. {
  32. Kind: "Gopher",
  33. IdType: &pb.Key_PathElement_Id{Id: 6},
  34. },
  35. },
  36. }
  37. key2 = &pb.Key{
  38. Path: []*pb.Key_PathElement{
  39. {
  40. Kind: "Gopher",
  41. IdType: &pb.Key_PathElement_Id{Id: 6},
  42. },
  43. {
  44. Kind: "Gopher",
  45. IdType: &pb.Key_PathElement_Id{Id: 8},
  46. },
  47. },
  48. }
  49. )
  50. type fakeClient struct {
  51. pb.DatastoreClient
  52. queryFn func(*pb.RunQueryRequest) (*pb.RunQueryResponse, error)
  53. commitFn func(*pb.CommitRequest) (*pb.CommitResponse, error)
  54. }
  55. func (c *fakeClient) RunQuery(_ context.Context, req *pb.RunQueryRequest, _ ...grpc.CallOption) (*pb.RunQueryResponse, error) {
  56. return c.queryFn(req)
  57. }
  58. func (c *fakeClient) Commit(_ context.Context, req *pb.CommitRequest, _ ...grpc.CallOption) (*pb.CommitResponse, error) {
  59. return c.commitFn(req)
  60. }
  61. func fakeRunQuery(in *pb.RunQueryRequest) (*pb.RunQueryResponse, error) {
  62. expectedIn := &pb.RunQueryRequest{
  63. QueryType: &pb.RunQueryRequest_Query{Query: &pb.Query{
  64. Kind: []*pb.KindExpression{{Name: "Gopher"}},
  65. }},
  66. }
  67. if !proto.Equal(in, expectedIn) {
  68. return nil, fmt.Errorf("unsupported argument: got %v want %v", in, expectedIn)
  69. }
  70. return &pb.RunQueryResponse{
  71. Batch: &pb.QueryResultBatch{
  72. MoreResults: pb.QueryResultBatch_NO_MORE_RESULTS,
  73. EntityResultType: pb.EntityResult_FULL,
  74. EntityResults: []*pb.EntityResult{
  75. {
  76. Entity: &pb.Entity{
  77. Key: key1,
  78. Properties: map[string]*pb.Value{
  79. "Name": {ValueType: &pb.Value_StringValue{StringValue: "George"}},
  80. "Height": {ValueType: &pb.Value_IntegerValue{IntegerValue: 32}},
  81. },
  82. },
  83. },
  84. {
  85. Entity: &pb.Entity{
  86. Key: key2,
  87. Properties: map[string]*pb.Value{
  88. "Name": {ValueType: &pb.Value_StringValue{StringValue: "Rufus"}},
  89. // No height for Rufus.
  90. },
  91. },
  92. },
  93. },
  94. },
  95. }, nil
  96. }
  97. type StructThatImplementsPLS struct{}
  98. func (StructThatImplementsPLS) Load(p []Property) error { return nil }
  99. func (StructThatImplementsPLS) Save() ([]Property, error) { return nil, nil }
  100. var _ PropertyLoadSaver = StructThatImplementsPLS{}
  101. type StructPtrThatImplementsPLS struct{}
  102. func (*StructPtrThatImplementsPLS) Load(p []Property) error { return nil }
  103. func (*StructPtrThatImplementsPLS) Save() ([]Property, error) { return nil, nil }
  104. var _ PropertyLoadSaver = &StructPtrThatImplementsPLS{}
  105. type PropertyMap map[string]Property
  106. func (m PropertyMap) Load(props []Property) error {
  107. for _, p := range props {
  108. m[p.Name] = p
  109. }
  110. return nil
  111. }
  112. func (m PropertyMap) Save() ([]Property, error) {
  113. props := make([]Property, 0, len(m))
  114. for _, p := range m {
  115. props = append(props, p)
  116. }
  117. return props, nil
  118. }
  119. var _ PropertyLoadSaver = PropertyMap{}
  120. type Gopher struct {
  121. Name string
  122. Height int
  123. }
  124. // typeOfEmptyInterface is the type of interface{}, but we can't use
  125. // reflect.TypeOf((interface{})(nil)) directly because TypeOf takes an
  126. // interface{}.
  127. var typeOfEmptyInterface = reflect.TypeOf((*interface{})(nil)).Elem()
  128. func TestCheckMultiArg(t *testing.T) {
  129. testCases := []struct {
  130. v interface{}
  131. mat multiArgType
  132. elemType reflect.Type
  133. }{
  134. // Invalid cases.
  135. {nil, multiArgTypeInvalid, nil},
  136. {Gopher{}, multiArgTypeInvalid, nil},
  137. {&Gopher{}, multiArgTypeInvalid, nil},
  138. {PropertyList{}, multiArgTypeInvalid, nil}, // This is a special case.
  139. {PropertyMap{}, multiArgTypeInvalid, nil},
  140. {[]*PropertyList(nil), multiArgTypeInvalid, nil},
  141. {[]*PropertyMap(nil), multiArgTypeInvalid, nil},
  142. {[]**Gopher(nil), multiArgTypeInvalid, nil},
  143. {[]*interface{}(nil), multiArgTypeInvalid, nil},
  144. // Valid cases.
  145. {
  146. []PropertyList(nil),
  147. multiArgTypePropertyLoadSaver,
  148. reflect.TypeOf(PropertyList{}),
  149. },
  150. {
  151. []PropertyMap(nil),
  152. multiArgTypePropertyLoadSaver,
  153. reflect.TypeOf(PropertyMap{}),
  154. },
  155. {
  156. []StructThatImplementsPLS(nil),
  157. multiArgTypePropertyLoadSaver,
  158. reflect.TypeOf(StructThatImplementsPLS{}),
  159. },
  160. {
  161. []StructPtrThatImplementsPLS(nil),
  162. multiArgTypePropertyLoadSaver,
  163. reflect.TypeOf(StructPtrThatImplementsPLS{}),
  164. },
  165. {
  166. []Gopher(nil),
  167. multiArgTypeStruct,
  168. reflect.TypeOf(Gopher{}),
  169. },
  170. {
  171. []*Gopher(nil),
  172. multiArgTypeStructPtr,
  173. reflect.TypeOf(Gopher{}),
  174. },
  175. {
  176. []interface{}(nil),
  177. multiArgTypeInterface,
  178. typeOfEmptyInterface,
  179. },
  180. }
  181. for _, tc := range testCases {
  182. mat, elemType := checkMultiArg(reflect.ValueOf(tc.v))
  183. if mat != tc.mat || elemType != tc.elemType {
  184. t.Errorf("checkMultiArg(%T): got %v, %v want %v, %v",
  185. tc.v, mat, elemType, tc.mat, tc.elemType)
  186. }
  187. }
  188. }
  189. func TestSimpleQuery(t *testing.T) {
  190. struct1 := Gopher{Name: "George", Height: 32}
  191. struct2 := Gopher{Name: "Rufus"}
  192. pList1 := PropertyList{
  193. {
  194. Name: "Height",
  195. Value: int64(32),
  196. },
  197. {
  198. Name: "Name",
  199. Value: "George",
  200. },
  201. }
  202. pList2 := PropertyList{
  203. {
  204. Name: "Name",
  205. Value: "Rufus",
  206. },
  207. }
  208. pMap1 := PropertyMap{
  209. "Name": Property{
  210. Name: "Name",
  211. Value: "George",
  212. },
  213. "Height": Property{
  214. Name: "Height",
  215. Value: int64(32),
  216. },
  217. }
  218. pMap2 := PropertyMap{
  219. "Name": Property{
  220. Name: "Name",
  221. Value: "Rufus",
  222. },
  223. }
  224. testCases := []struct {
  225. dst interface{}
  226. want interface{}
  227. }{
  228. // The destination must have type *[]P, *[]S or *[]*S, for some non-interface
  229. // type P such that *P implements PropertyLoadSaver, or for some struct type S.
  230. {new([]Gopher), &[]Gopher{struct1, struct2}},
  231. {new([]*Gopher), &[]*Gopher{&struct1, &struct2}},
  232. {new([]PropertyList), &[]PropertyList{pList1, pList2}},
  233. {new([]PropertyMap), &[]PropertyMap{pMap1, pMap2}},
  234. // Any other destination type is invalid.
  235. {0, nil},
  236. {Gopher{}, nil},
  237. {PropertyList{}, nil},
  238. {PropertyMap{}, nil},
  239. {[]int{}, nil},
  240. {[]Gopher{}, nil},
  241. {[]PropertyList{}, nil},
  242. {new(int), nil},
  243. {new(Gopher), nil},
  244. {new(PropertyList), nil}, // This is a special case.
  245. {new(PropertyMap), nil},
  246. {new([]int), nil},
  247. {new([]map[int]int), nil},
  248. {new([]map[string]Property), nil},
  249. {new([]map[string]interface{}), nil},
  250. {new([]*int), nil},
  251. {new([]*map[int]int), nil},
  252. {new([]*map[string]Property), nil},
  253. {new([]*map[string]interface{}), nil},
  254. {new([]**Gopher), nil},
  255. {new([]*PropertyList), nil},
  256. {new([]*PropertyMap), nil},
  257. }
  258. for _, tc := range testCases {
  259. nCall := 0
  260. client := &Client{
  261. client: &fakeClient{
  262. queryFn: func(req *pb.RunQueryRequest) (*pb.RunQueryResponse, error) {
  263. nCall++
  264. return fakeRunQuery(req)
  265. },
  266. },
  267. }
  268. ctx := context.Background()
  269. var (
  270. expectedErr error
  271. expectedNCall int
  272. )
  273. if tc.want == nil {
  274. expectedErr = ErrInvalidEntityType
  275. } else {
  276. expectedNCall = 1
  277. }
  278. keys, err := client.GetAll(ctx, NewQuery("Gopher"), tc.dst)
  279. if err != expectedErr {
  280. t.Errorf("dst type %T: got error %v, want %v", tc.dst, err, expectedErr)
  281. continue
  282. }
  283. if nCall != expectedNCall {
  284. t.Errorf("dst type %T: Context.Call was called an incorrect number of times: got %d want %d", tc.dst, nCall, expectedNCall)
  285. continue
  286. }
  287. if err != nil {
  288. continue
  289. }
  290. key1 := IDKey("Gopher", 6, nil)
  291. expectedKeys := []*Key{
  292. key1,
  293. IDKey("Gopher", 8, key1),
  294. }
  295. if l1, l2 := len(keys), len(expectedKeys); l1 != l2 {
  296. t.Errorf("dst type %T: got %d keys, want %d keys", tc.dst, l1, l2)
  297. continue
  298. }
  299. for i, key := range keys {
  300. if !keysEqual(key, expectedKeys[i]) {
  301. t.Errorf("dst type %T: got key #%d %v, want %v", tc.dst, i, key, expectedKeys[i])
  302. continue
  303. }
  304. }
  305. // Make sure we sort any PropertyList items (the order is not deterministic).
  306. if pLists, ok := tc.dst.(*[]PropertyList); ok {
  307. for _, p := range *pLists {
  308. sort.Sort(byName(p))
  309. }
  310. }
  311. if !testutil.Equal(tc.dst, tc.want) {
  312. t.Errorf("dst type %T: Entities\ngot %+v\nwant %+v", tc.dst, tc.dst, tc.want)
  313. continue
  314. }
  315. }
  316. }
  317. // keysEqual is like (*Key).Equal, but ignores the App ID.
  318. func keysEqual(a, b *Key) bool {
  319. for a != nil && b != nil {
  320. if a.Kind != b.Kind || a.Name != b.Name || a.ID != b.ID {
  321. return false
  322. }
  323. a, b = a.Parent, b.Parent
  324. }
  325. return a == b
  326. }
  327. func TestQueriesAreImmutable(t *testing.T) {
  328. // Test that deriving q2 from q1 does not modify q1.
  329. q0 := NewQuery("foo")
  330. q1 := NewQuery("foo")
  331. q2 := q1.Offset(2)
  332. if !testutil.Equal(q0, q1, cmp.AllowUnexported(Query{})) {
  333. t.Errorf("q0 and q1 were not equal")
  334. }
  335. if testutil.Equal(q1, q2, cmp.AllowUnexported(Query{})) {
  336. t.Errorf("q1 and q2 were equal")
  337. }
  338. // Test that deriving from q4 twice does not conflict, even though
  339. // q4 has a long list of order clauses. This tests that the arrays
  340. // backed by a query's slice of orders are not shared.
  341. f := func() *Query {
  342. q := NewQuery("bar")
  343. // 47 is an ugly number that is unlikely to be near a re-allocation
  344. // point in repeated append calls. For example, it's not near a power
  345. // of 2 or a multiple of 10.
  346. for i := 0; i < 47; i++ {
  347. q = q.Order(fmt.Sprintf("x%d", i))
  348. }
  349. return q
  350. }
  351. q3 := f().Order("y")
  352. q4 := f()
  353. q5 := q4.Order("y")
  354. q6 := q4.Order("z")
  355. if !testutil.Equal(q3, q5, cmp.AllowUnexported(Query{})) {
  356. t.Errorf("q3 and q5 were not equal")
  357. }
  358. if testutil.Equal(q5, q6, cmp.AllowUnexported(Query{})) {
  359. t.Errorf("q5 and q6 were equal")
  360. }
  361. }
  362. func TestFilterParser(t *testing.T) {
  363. testCases := []struct {
  364. filterStr string
  365. wantOK bool
  366. wantFieldName string
  367. wantOp operator
  368. }{
  369. // Supported ops.
  370. {"x<", true, "x", lessThan},
  371. {"x <", true, "x", lessThan},
  372. {"x <", true, "x", lessThan},
  373. {" x < ", true, "x", lessThan},
  374. {"x <=", true, "x", lessEq},
  375. {"x =", true, "x", equal},
  376. {"x >=", true, "x", greaterEq},
  377. {"x >", true, "x", greaterThan},
  378. {"in >", true, "in", greaterThan},
  379. {"in>", true, "in", greaterThan},
  380. // Valid but (currently) unsupported ops.
  381. {"x!=", false, "", 0},
  382. {"x !=", false, "", 0},
  383. {" x != ", false, "", 0},
  384. {"x IN", false, "", 0},
  385. {"x in", false, "", 0},
  386. // Invalid ops.
  387. {"x EQ", false, "", 0},
  388. {"x lt", false, "", 0},
  389. {"x <>", false, "", 0},
  390. {"x >>", false, "", 0},
  391. {"x ==", false, "", 0},
  392. {"x =<", false, "", 0},
  393. {"x =>", false, "", 0},
  394. {"x !", false, "", 0},
  395. {"x ", false, "", 0},
  396. {"x", false, "", 0},
  397. // Quoted and interesting field names.
  398. {"x > y =", true, "x > y", equal},
  399. {"` x ` =", true, " x ", equal},
  400. {`" x " =`, true, " x ", equal},
  401. {`" \"x " =`, true, ` "x `, equal},
  402. {`" x =`, false, "", 0},
  403. {`" x ="`, false, "", 0},
  404. {"` x \" =", false, "", 0},
  405. }
  406. for _, tc := range testCases {
  407. q := NewQuery("foo").Filter(tc.filterStr, 42)
  408. if ok := q.err == nil; ok != tc.wantOK {
  409. t.Errorf("%q: ok=%t, want %t", tc.filterStr, ok, tc.wantOK)
  410. continue
  411. }
  412. if !tc.wantOK {
  413. continue
  414. }
  415. if len(q.filter) != 1 {
  416. t.Errorf("%q: len=%d, want %d", tc.filterStr, len(q.filter), 1)
  417. continue
  418. }
  419. got, want := q.filter[0], filter{tc.wantFieldName, tc.wantOp, 42}
  420. if got != want {
  421. t.Errorf("%q: got %v, want %v", tc.filterStr, got, want)
  422. continue
  423. }
  424. }
  425. }
  426. func TestNamespaceQuery(t *testing.T) {
  427. gotNamespace := make(chan string, 1)
  428. ctx := context.Background()
  429. client := &Client{
  430. client: &fakeClient{
  431. queryFn: func(req *pb.RunQueryRequest) (*pb.RunQueryResponse, error) {
  432. if part := req.PartitionId; part != nil {
  433. gotNamespace <- part.NamespaceId
  434. } else {
  435. gotNamespace <- ""
  436. }
  437. return nil, errors.New("not implemented")
  438. },
  439. },
  440. }
  441. var gs []Gopher
  442. // Ignore errors for the rest of this test.
  443. client.GetAll(ctx, NewQuery("gopher"), &gs)
  444. if got, want := <-gotNamespace, ""; got != want {
  445. t.Errorf("GetAll: got namespace %q, want %q", got, want)
  446. }
  447. client.Count(ctx, NewQuery("gopher"))
  448. if got, want := <-gotNamespace, ""; got != want {
  449. t.Errorf("Count: got namespace %q, want %q", got, want)
  450. }
  451. const ns = "not_default"
  452. client.GetAll(ctx, NewQuery("gopher").Namespace(ns), &gs)
  453. if got, want := <-gotNamespace, ns; got != want {
  454. t.Errorf("GetAll: got namespace %q, want %q", got, want)
  455. }
  456. client.Count(ctx, NewQuery("gopher").Namespace(ns))
  457. if got, want := <-gotNamespace, ns; got != want {
  458. t.Errorf("Count: got namespace %q, want %q", got, want)
  459. }
  460. }
  461. func TestReadOptions(t *testing.T) {
  462. tid := []byte{1}
  463. for _, test := range []struct {
  464. q *Query
  465. want *pb.ReadOptions
  466. }{
  467. {
  468. q: NewQuery(""),
  469. want: nil,
  470. },
  471. {
  472. q: NewQuery("").Transaction(nil),
  473. want: nil,
  474. },
  475. {
  476. q: NewQuery("").Transaction(&Transaction{id: tid}),
  477. want: &pb.ReadOptions{
  478. ConsistencyType: &pb.ReadOptions_Transaction{
  479. Transaction: tid,
  480. },
  481. },
  482. },
  483. {
  484. q: NewQuery("").EventualConsistency(),
  485. want: &pb.ReadOptions{
  486. ConsistencyType: &pb.ReadOptions_ReadConsistency_{
  487. ReadConsistency: pb.ReadOptions_EVENTUAL,
  488. },
  489. },
  490. },
  491. } {
  492. req := &pb.RunQueryRequest{}
  493. if err := test.q.toProto(req); err != nil {
  494. t.Fatalf("%+v: got %v, want no error", test.q, err)
  495. }
  496. if got := req.ReadOptions; !proto.Equal(got, test.want) {
  497. t.Errorf("%+v:\ngot %+v\nwant %+v", test.q, got, test.want)
  498. }
  499. }
  500. // Test errors.
  501. for _, q := range []*Query{
  502. NewQuery("").Transaction(&Transaction{id: nil}),
  503. NewQuery("").Transaction(&Transaction{id: tid}).EventualConsistency(),
  504. } {
  505. req := &pb.RunQueryRequest{}
  506. if err := q.toProto(req); err == nil {
  507. t.Errorf("%+v: got nil, wanted error", q)
  508. }
  509. }
  510. }
  511. func TestInvalidFilters(t *testing.T) {
  512. client := &Client{
  513. client: &fakeClient{
  514. queryFn: func(req *pb.RunQueryRequest) (*pb.RunQueryResponse, error) {
  515. return fakeRunQuery(req)
  516. },
  517. },
  518. }
  519. // Used for an invalid type
  520. type MyType int
  521. var v MyType = 1
  522. for _, q := range []*Query{
  523. NewQuery("SomeKey").Filter("", 0),
  524. NewQuery("SomeKey").Filter("fld=", v),
  525. } {
  526. if _, err := client.Count(context.Background(), q); err == nil {
  527. t.Errorf("%+v: got nil, wanted error", q)
  528. }
  529. }
  530. }