datastore_test.go 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499
  1. // Copyright 2011 Google Inc. All Rights Reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package datastore
  5. import (
  6. "encoding/json"
  7. "errors"
  8. "fmt"
  9. "reflect"
  10. "strings"
  11. "testing"
  12. "time"
  13. "google.golang.org/appengine"
  14. pb "google.golang.org/appengine/internal/datastore"
  15. )
  16. const testAppID = "testApp"
  17. type (
  18. myBlob []byte
  19. myByte byte
  20. myString string
  21. )
  22. func makeMyByteSlice(n int) []myByte {
  23. b := make([]myByte, n)
  24. for i := range b {
  25. b[i] = myByte(i)
  26. }
  27. return b
  28. }
  29. func makeInt8Slice(n int) []int8 {
  30. b := make([]int8, n)
  31. for i := range b {
  32. b[i] = int8(i)
  33. }
  34. return b
  35. }
  36. func makeUint8Slice(n int) []uint8 {
  37. b := make([]uint8, n)
  38. for i := range b {
  39. b[i] = uint8(i)
  40. }
  41. return b
  42. }
  43. func newKey(stringID string, parent *Key) *Key {
  44. return &Key{
  45. kind: "kind",
  46. stringID: stringID,
  47. intID: 0,
  48. parent: parent,
  49. appID: testAppID,
  50. }
  51. }
  52. var (
  53. testKey0 = newKey("name0", nil)
  54. testKey1a = newKey("name1", nil)
  55. testKey1b = newKey("name1", nil)
  56. testKey2a = newKey("name2", testKey0)
  57. testKey2b = newKey("name2", testKey0)
  58. testGeoPt0 = appengine.GeoPoint{Lat: 1.2, Lng: 3.4}
  59. testGeoPt1 = appengine.GeoPoint{Lat: 5, Lng: 10}
  60. testBadGeoPt = appengine.GeoPoint{Lat: 1000, Lng: 34}
  61. )
  62. type B0 struct {
  63. B []byte
  64. }
  65. type B1 struct {
  66. B []int8
  67. }
  68. type B2 struct {
  69. B myBlob
  70. }
  71. type B3 struct {
  72. B []myByte
  73. }
  74. type B4 struct {
  75. B [][]byte
  76. }
  77. type B5 struct {
  78. B ByteString
  79. }
  80. type C0 struct {
  81. I int
  82. C chan int
  83. }
  84. type C1 struct {
  85. I int
  86. C *chan int
  87. }
  88. type C2 struct {
  89. I int
  90. C []chan int
  91. }
  92. type C3 struct {
  93. C string
  94. }
  95. type E struct{}
  96. type G0 struct {
  97. G appengine.GeoPoint
  98. }
  99. type G1 struct {
  100. G []appengine.GeoPoint
  101. }
  102. type K0 struct {
  103. K *Key
  104. }
  105. type K1 struct {
  106. K []*Key
  107. }
  108. type N0 struct {
  109. X0
  110. Nonymous X0
  111. Ignore string `datastore:"-"`
  112. Other string
  113. }
  114. type N1 struct {
  115. X0
  116. Nonymous []X0
  117. Ignore string `datastore:"-"`
  118. Other string
  119. }
  120. type N2 struct {
  121. N1 `datastore:"red"`
  122. Green N1 `datastore:"green"`
  123. Blue N1
  124. White N1 `datastore:"-"`
  125. }
  126. type O0 struct {
  127. I int64
  128. }
  129. type O1 struct {
  130. I int32
  131. }
  132. type U0 struct {
  133. U uint
  134. }
  135. type U1 struct {
  136. U string
  137. }
  138. type T struct {
  139. T time.Time
  140. }
  141. type X0 struct {
  142. S string
  143. I int
  144. i int
  145. }
  146. type X1 struct {
  147. S myString
  148. I int32
  149. J int64
  150. }
  151. type X2 struct {
  152. Z string
  153. i int
  154. }
  155. type X3 struct {
  156. S bool
  157. I int
  158. }
  159. type Y0 struct {
  160. B bool
  161. F []float64
  162. G []float64
  163. }
  164. type Y1 struct {
  165. B bool
  166. F float64
  167. }
  168. type Y2 struct {
  169. B bool
  170. F []int64
  171. }
  172. type Tagged struct {
  173. A int `datastore:"a,noindex"`
  174. B []int `datastore:"b"`
  175. C int `datastore:",noindex"`
  176. D int `datastore:""`
  177. E int
  178. I int `datastore:"-"`
  179. J int `datastore:",noindex" json:"j"`
  180. Y0 `datastore:"-"`
  181. Z chan int `datastore:"-,"`
  182. }
  183. type InvalidTagged1 struct {
  184. I int `datastore:"\t"`
  185. }
  186. type InvalidTagged2 struct {
  187. I int
  188. J int `datastore:"I"`
  189. }
  190. type Inner1 struct {
  191. W int32
  192. X string
  193. }
  194. type Inner2 struct {
  195. Y float64
  196. }
  197. type Inner3 struct {
  198. Z bool
  199. }
  200. type Outer struct {
  201. A int16
  202. I []Inner1
  203. J Inner2
  204. Inner3
  205. }
  206. type OuterEquivalent struct {
  207. A int16
  208. IDotW []int32 `datastore:"I.W"`
  209. IDotX []string `datastore:"I.X"`
  210. JDotY float64 `datastore:"J.Y"`
  211. Z bool
  212. }
  213. type Dotted struct {
  214. A DottedA `datastore:"A0.A1.A2"`
  215. }
  216. type DottedA struct {
  217. B DottedB `datastore:"B3"`
  218. }
  219. type DottedB struct {
  220. C int `datastore:"C4.C5"`
  221. }
  222. type SliceOfSlices struct {
  223. I int
  224. S []struct {
  225. J int
  226. F []float64
  227. }
  228. }
  229. type Recursive struct {
  230. I int
  231. R []Recursive
  232. }
  233. type MutuallyRecursive0 struct {
  234. I int
  235. R []MutuallyRecursive1
  236. }
  237. type MutuallyRecursive1 struct {
  238. I int
  239. R []MutuallyRecursive0
  240. }
  241. type Doubler struct {
  242. S string
  243. I int64
  244. B bool
  245. }
  246. func (d *Doubler) Load(props []Property) error {
  247. return LoadStruct(d, props)
  248. }
  249. func (d *Doubler) Save() ([]Property, error) {
  250. // Save the default Property slice to an in-memory buffer (a PropertyList).
  251. props, err := SaveStruct(d)
  252. if err != nil {
  253. return nil, err
  254. }
  255. var list PropertyList
  256. if err := list.Load(props); err != nil {
  257. return nil, err
  258. }
  259. // Edit that PropertyList, and send it on.
  260. for i := range list {
  261. switch v := list[i].Value.(type) {
  262. case string:
  263. // + means string concatenation.
  264. list[i].Value = v + v
  265. case int64:
  266. // + means integer addition.
  267. list[i].Value = v + v
  268. }
  269. }
  270. return list.Save()
  271. }
  272. var _ PropertyLoadSaver = (*Doubler)(nil)
  273. type Deriver struct {
  274. S, Derived, Ignored string
  275. }
  276. func (e *Deriver) Load(props []Property) error {
  277. for _, p := range props {
  278. if p.Name != "S" {
  279. continue
  280. }
  281. e.S = p.Value.(string)
  282. e.Derived = "derived+" + e.S
  283. }
  284. return nil
  285. }
  286. func (e *Deriver) Save() ([]Property, error) {
  287. return []Property{
  288. {
  289. Name: "S",
  290. Value: e.S,
  291. },
  292. }, nil
  293. }
  294. var _ PropertyLoadSaver = (*Deriver)(nil)
  295. type BadMultiPropEntity struct{}
  296. func (e *BadMultiPropEntity) Load(props []Property) error {
  297. return errors.New("unimplemented")
  298. }
  299. func (e *BadMultiPropEntity) Save() ([]Property, error) {
  300. // Write multiple properties with the same name "I", but Multiple is false.
  301. var props []Property
  302. for i := 0; i < 3; i++ {
  303. props = append(props, Property{
  304. Name: "I",
  305. Value: int64(i),
  306. })
  307. }
  308. return props, nil
  309. }
  310. var _ PropertyLoadSaver = (*BadMultiPropEntity)(nil)
  311. type BK struct {
  312. Key appengine.BlobKey
  313. }
  314. type testCase struct {
  315. desc string
  316. src interface{}
  317. want interface{}
  318. putErr string
  319. getErr string
  320. }
  321. var testCases = []testCase{
  322. {
  323. "chan save fails",
  324. &C0{I: -1},
  325. &E{},
  326. "unsupported struct field",
  327. "",
  328. },
  329. {
  330. "*chan save fails",
  331. &C1{I: -1},
  332. &E{},
  333. "unsupported struct field",
  334. "",
  335. },
  336. {
  337. "[]chan save fails",
  338. &C2{I: -1, C: make([]chan int, 8)},
  339. &E{},
  340. "unsupported struct field",
  341. "",
  342. },
  343. {
  344. "chan load fails",
  345. &C3{C: "not a chan"},
  346. &C0{},
  347. "",
  348. "type mismatch",
  349. },
  350. {
  351. "*chan load fails",
  352. &C3{C: "not a *chan"},
  353. &C1{},
  354. "",
  355. "type mismatch",
  356. },
  357. {
  358. "[]chan load fails",
  359. &C3{C: "not a []chan"},
  360. &C2{},
  361. "",
  362. "type mismatch",
  363. },
  364. {
  365. "empty struct",
  366. &E{},
  367. &E{},
  368. "",
  369. "",
  370. },
  371. {
  372. "geopoint",
  373. &G0{G: testGeoPt0},
  374. &G0{G: testGeoPt0},
  375. "",
  376. "",
  377. },
  378. {
  379. "geopoint invalid",
  380. &G0{G: testBadGeoPt},
  381. &G0{},
  382. "invalid GeoPoint value",
  383. "",
  384. },
  385. {
  386. "geopoint as props",
  387. &G0{G: testGeoPt0},
  388. &PropertyList{
  389. Property{Name: "G", Value: testGeoPt0, NoIndex: false, Multiple: false},
  390. },
  391. "",
  392. "",
  393. },
  394. {
  395. "geopoint slice",
  396. &G1{G: []appengine.GeoPoint{testGeoPt0, testGeoPt1}},
  397. &G1{G: []appengine.GeoPoint{testGeoPt0, testGeoPt1}},
  398. "",
  399. "",
  400. },
  401. {
  402. "key",
  403. &K0{K: testKey1a},
  404. &K0{K: testKey1b},
  405. "",
  406. "",
  407. },
  408. {
  409. "key with parent",
  410. &K0{K: testKey2a},
  411. &K0{K: testKey2b},
  412. "",
  413. "",
  414. },
  415. {
  416. "nil key",
  417. &K0{},
  418. &K0{},
  419. "",
  420. "",
  421. },
  422. {
  423. "all nil keys in slice",
  424. &K1{[]*Key{nil, nil}},
  425. &K1{[]*Key{nil, nil}},
  426. "",
  427. "",
  428. },
  429. {
  430. "some nil keys in slice",
  431. &K1{[]*Key{testKey1a, nil, testKey2a}},
  432. &K1{[]*Key{testKey1b, nil, testKey2b}},
  433. "",
  434. "",
  435. },
  436. {
  437. "overflow",
  438. &O0{I: 1 << 48},
  439. &O1{},
  440. "",
  441. "overflow",
  442. },
  443. {
  444. "time",
  445. &T{T: time.Unix(1e9, 0)},
  446. &T{T: time.Unix(1e9, 0)},
  447. "",
  448. "",
  449. },
  450. {
  451. "time as props",
  452. &T{T: time.Unix(1e9, 0)},
  453. &PropertyList{
  454. Property{Name: "T", Value: time.Unix(1e9, 0), NoIndex: false, Multiple: false},
  455. },
  456. "",
  457. "",
  458. },
  459. {
  460. "uint save",
  461. &U0{U: 1},
  462. &U0{},
  463. "unsupported struct field",
  464. "",
  465. },
  466. {
  467. "uint load",
  468. &U1{U: "not a uint"},
  469. &U0{},
  470. "",
  471. "type mismatch",
  472. },
  473. {
  474. "zero",
  475. &X0{},
  476. &X0{},
  477. "",
  478. "",
  479. },
  480. {
  481. "basic",
  482. &X0{S: "one", I: 2, i: 3},
  483. &X0{S: "one", I: 2},
  484. "",
  485. "",
  486. },
  487. {
  488. "save string/int load myString/int32",
  489. &X0{S: "one", I: 2, i: 3},
  490. &X1{S: "one", I: 2},
  491. "",
  492. "",
  493. },
  494. {
  495. "missing fields",
  496. &X0{S: "one", I: 2, i: 3},
  497. &X2{},
  498. "",
  499. "no such struct field",
  500. },
  501. {
  502. "save string load bool",
  503. &X0{S: "one", I: 2, i: 3},
  504. &X3{I: 2},
  505. "",
  506. "type mismatch",
  507. },
  508. {
  509. "basic slice",
  510. &Y0{B: true, F: []float64{7, 8, 9}},
  511. &Y0{B: true, F: []float64{7, 8, 9}},
  512. "",
  513. "",
  514. },
  515. {
  516. "save []float64 load float64",
  517. &Y0{B: true, F: []float64{7, 8, 9}},
  518. &Y1{B: true},
  519. "",
  520. "requires a slice",
  521. },
  522. {
  523. "save []float64 load []int64",
  524. &Y0{B: true, F: []float64{7, 8, 9}},
  525. &Y2{B: true},
  526. "",
  527. "type mismatch",
  528. },
  529. {
  530. "single slice is too long",
  531. &Y0{F: make([]float64, maxIndexedProperties+1)},
  532. &Y0{},
  533. "too many indexed properties",
  534. "",
  535. },
  536. {
  537. "two slices are too long",
  538. &Y0{F: make([]float64, maxIndexedProperties), G: make([]float64, maxIndexedProperties)},
  539. &Y0{},
  540. "too many indexed properties",
  541. "",
  542. },
  543. {
  544. "one slice and one scalar are too long",
  545. &Y0{F: make([]float64, maxIndexedProperties), B: true},
  546. &Y0{},
  547. "too many indexed properties",
  548. "",
  549. },
  550. {
  551. "long blob",
  552. &B0{B: makeUint8Slice(maxIndexedProperties + 1)},
  553. &B0{B: makeUint8Slice(maxIndexedProperties + 1)},
  554. "",
  555. "",
  556. },
  557. {
  558. "long []int8 is too long",
  559. &B1{B: makeInt8Slice(maxIndexedProperties + 1)},
  560. &B1{},
  561. "too many indexed properties",
  562. "",
  563. },
  564. {
  565. "short []int8",
  566. &B1{B: makeInt8Slice(3)},
  567. &B1{B: makeInt8Slice(3)},
  568. "",
  569. "",
  570. },
  571. {
  572. "long myBlob",
  573. &B2{B: makeUint8Slice(maxIndexedProperties + 1)},
  574. &B2{B: makeUint8Slice(maxIndexedProperties + 1)},
  575. "",
  576. "",
  577. },
  578. {
  579. "short myBlob",
  580. &B2{B: makeUint8Slice(3)},
  581. &B2{B: makeUint8Slice(3)},
  582. "",
  583. "",
  584. },
  585. {
  586. "long []myByte",
  587. &B3{B: makeMyByteSlice(maxIndexedProperties + 1)},
  588. &B3{B: makeMyByteSlice(maxIndexedProperties + 1)},
  589. "",
  590. "",
  591. },
  592. {
  593. "short []myByte",
  594. &B3{B: makeMyByteSlice(3)},
  595. &B3{B: makeMyByteSlice(3)},
  596. "",
  597. "",
  598. },
  599. {
  600. "slice of blobs",
  601. &B4{B: [][]byte{
  602. makeUint8Slice(3),
  603. makeUint8Slice(4),
  604. makeUint8Slice(5),
  605. }},
  606. &B4{B: [][]byte{
  607. makeUint8Slice(3),
  608. makeUint8Slice(4),
  609. makeUint8Slice(5),
  610. }},
  611. "",
  612. "",
  613. },
  614. {
  615. "short ByteString",
  616. &B5{B: ByteString(makeUint8Slice(3))},
  617. &B5{B: ByteString(makeUint8Slice(3))},
  618. "",
  619. "",
  620. },
  621. {
  622. "short ByteString as props",
  623. &B5{B: ByteString(makeUint8Slice(3))},
  624. &PropertyList{
  625. Property{Name: "B", Value: ByteString(makeUint8Slice(3)), NoIndex: false, Multiple: false},
  626. },
  627. "",
  628. "",
  629. },
  630. {
  631. "short ByteString into string",
  632. &B5{B: ByteString("legacy")},
  633. &struct{ B string }{"legacy"},
  634. "",
  635. "",
  636. },
  637. {
  638. "[]byte must be noindex",
  639. &PropertyList{
  640. Property{Name: "B", Value: makeUint8Slice(3), NoIndex: false},
  641. },
  642. nil,
  643. "cannot index a []byte valued Property",
  644. "",
  645. },
  646. {
  647. "save tagged load props",
  648. &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6, J: 7},
  649. &PropertyList{
  650. // A and B are renamed to a and b; A and C are noindex, I is ignored.
  651. // Indexed properties are loaded before raw properties. Thus, the
  652. // result is: b, b, b, D, E, a, c.
  653. Property{Name: "b", Value: int64(21), NoIndex: false, Multiple: true},
  654. Property{Name: "b", Value: int64(22), NoIndex: false, Multiple: true},
  655. Property{Name: "b", Value: int64(23), NoIndex: false, Multiple: true},
  656. Property{Name: "D", Value: int64(4), NoIndex: false, Multiple: false},
  657. Property{Name: "E", Value: int64(5), NoIndex: false, Multiple: false},
  658. Property{Name: "a", Value: int64(1), NoIndex: true, Multiple: false},
  659. Property{Name: "C", Value: int64(3), NoIndex: true, Multiple: false},
  660. Property{Name: "J", Value: int64(7), NoIndex: true, Multiple: false},
  661. },
  662. "",
  663. "",
  664. },
  665. {
  666. "save tagged load tagged",
  667. &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, I: 6, J: 7},
  668. &Tagged{A: 1, B: []int{21, 22, 23}, C: 3, D: 4, E: 5, J: 7},
  669. "",
  670. "",
  671. },
  672. {
  673. "save props load tagged",
  674. &PropertyList{
  675. Property{Name: "A", Value: int64(11), NoIndex: true, Multiple: false},
  676. Property{Name: "a", Value: int64(12), NoIndex: true, Multiple: false},
  677. },
  678. &Tagged{A: 12},
  679. "",
  680. `cannot load field "A"`,
  681. },
  682. {
  683. "invalid tagged1",
  684. &InvalidTagged1{I: 1},
  685. &InvalidTagged1{},
  686. "struct tag has invalid property name",
  687. "",
  688. },
  689. {
  690. "invalid tagged2",
  691. &InvalidTagged2{I: 1, J: 2},
  692. &InvalidTagged2{},
  693. "struct tag has repeated property name",
  694. "",
  695. },
  696. {
  697. "doubler",
  698. &Doubler{S: "s", I: 1, B: true},
  699. &Doubler{S: "ss", I: 2, B: true},
  700. "",
  701. "",
  702. },
  703. {
  704. "save struct load props",
  705. &X0{S: "s", I: 1},
  706. &PropertyList{
  707. Property{Name: "S", Value: "s", NoIndex: false, Multiple: false},
  708. Property{Name: "I", Value: int64(1), NoIndex: false, Multiple: false},
  709. },
  710. "",
  711. "",
  712. },
  713. {
  714. "save props load struct",
  715. &PropertyList{
  716. Property{Name: "S", Value: "s", NoIndex: false, Multiple: false},
  717. Property{Name: "I", Value: int64(1), NoIndex: false, Multiple: false},
  718. },
  719. &X0{S: "s", I: 1},
  720. "",
  721. "",
  722. },
  723. {
  724. "nil-value props",
  725. &PropertyList{
  726. Property{Name: "I", Value: nil, NoIndex: false, Multiple: false},
  727. Property{Name: "B", Value: nil, NoIndex: false, Multiple: false},
  728. Property{Name: "S", Value: nil, NoIndex: false, Multiple: false},
  729. Property{Name: "F", Value: nil, NoIndex: false, Multiple: false},
  730. Property{Name: "K", Value: nil, NoIndex: false, Multiple: false},
  731. Property{Name: "T", Value: nil, NoIndex: false, Multiple: false},
  732. Property{Name: "J", Value: nil, NoIndex: false, Multiple: true},
  733. Property{Name: "J", Value: int64(7), NoIndex: false, Multiple: true},
  734. Property{Name: "J", Value: nil, NoIndex: false, Multiple: true},
  735. },
  736. &struct {
  737. I int64
  738. B bool
  739. S string
  740. F float64
  741. K *Key
  742. T time.Time
  743. J []int64
  744. }{
  745. J: []int64{0, 7, 0},
  746. },
  747. "",
  748. "",
  749. },
  750. {
  751. "save outer load props",
  752. &Outer{
  753. A: 1,
  754. I: []Inner1{
  755. {10, "ten"},
  756. {20, "twenty"},
  757. {30, "thirty"},
  758. },
  759. J: Inner2{
  760. Y: 3.14,
  761. },
  762. Inner3: Inner3{
  763. Z: true,
  764. },
  765. },
  766. &PropertyList{
  767. Property{Name: "A", Value: int64(1), NoIndex: false, Multiple: false},
  768. Property{Name: "I.W", Value: int64(10), NoIndex: false, Multiple: true},
  769. Property{Name: "I.X", Value: "ten", NoIndex: false, Multiple: true},
  770. Property{Name: "I.W", Value: int64(20), NoIndex: false, Multiple: true},
  771. Property{Name: "I.X", Value: "twenty", NoIndex: false, Multiple: true},
  772. Property{Name: "I.W", Value: int64(30), NoIndex: false, Multiple: true},
  773. Property{Name: "I.X", Value: "thirty", NoIndex: false, Multiple: true},
  774. Property{Name: "J.Y", Value: float64(3.14), NoIndex: false, Multiple: false},
  775. Property{Name: "Z", Value: true, NoIndex: false, Multiple: false},
  776. },
  777. "",
  778. "",
  779. },
  780. {
  781. "save props load outer-equivalent",
  782. &PropertyList{
  783. Property{Name: "A", Value: int64(1), NoIndex: false, Multiple: false},
  784. Property{Name: "I.W", Value: int64(10), NoIndex: false, Multiple: true},
  785. Property{Name: "I.X", Value: "ten", NoIndex: false, Multiple: true},
  786. Property{Name: "I.W", Value: int64(20), NoIndex: false, Multiple: true},
  787. Property{Name: "I.X", Value: "twenty", NoIndex: false, Multiple: true},
  788. Property{Name: "I.W", Value: int64(30), NoIndex: false, Multiple: true},
  789. Property{Name: "I.X", Value: "thirty", NoIndex: false, Multiple: true},
  790. Property{Name: "J.Y", Value: float64(3.14), NoIndex: false, Multiple: false},
  791. Property{Name: "Z", Value: true, NoIndex: false, Multiple: false},
  792. },
  793. &OuterEquivalent{
  794. A: 1,
  795. IDotW: []int32{10, 20, 30},
  796. IDotX: []string{"ten", "twenty", "thirty"},
  797. JDotY: 3.14,
  798. Z: true,
  799. },
  800. "",
  801. "",
  802. },
  803. {
  804. "save outer-equivalent load outer",
  805. &OuterEquivalent{
  806. A: 1,
  807. IDotW: []int32{10, 20, 30},
  808. IDotX: []string{"ten", "twenty", "thirty"},
  809. JDotY: 3.14,
  810. Z: true,
  811. },
  812. &Outer{
  813. A: 1,
  814. I: []Inner1{
  815. {10, "ten"},
  816. {20, "twenty"},
  817. {30, "thirty"},
  818. },
  819. J: Inner2{
  820. Y: 3.14,
  821. },
  822. Inner3: Inner3{
  823. Z: true,
  824. },
  825. },
  826. "",
  827. "",
  828. },
  829. {
  830. "dotted names save",
  831. &Dotted{A: DottedA{B: DottedB{C: 88}}},
  832. &PropertyList{
  833. Property{Name: "A0.A1.A2.B3.C4.C5", Value: int64(88), NoIndex: false, Multiple: false},
  834. },
  835. "",
  836. "",
  837. },
  838. {
  839. "dotted names load",
  840. &PropertyList{
  841. Property{Name: "A0.A1.A2.B3.C4.C5", Value: int64(99), NoIndex: false, Multiple: false},
  842. },
  843. &Dotted{A: DottedA{B: DottedB{C: 99}}},
  844. "",
  845. "",
  846. },
  847. {
  848. "save struct load deriver",
  849. &X0{S: "s", I: 1},
  850. &Deriver{S: "s", Derived: "derived+s"},
  851. "",
  852. "",
  853. },
  854. {
  855. "save deriver load struct",
  856. &Deriver{S: "s", Derived: "derived+s", Ignored: "ignored"},
  857. &X0{S: "s"},
  858. "",
  859. "",
  860. },
  861. {
  862. "bad multi-prop entity",
  863. &BadMultiPropEntity{},
  864. &BadMultiPropEntity{},
  865. "Multiple is false",
  866. "",
  867. },
  868. // Regression: CL 25062824 broke handling of appengine.BlobKey fields.
  869. {
  870. "appengine.BlobKey",
  871. &BK{Key: "blah"},
  872. &BK{Key: "blah"},
  873. "",
  874. "",
  875. },
  876. {
  877. "zero time.Time",
  878. &T{T: time.Time{}},
  879. &T{T: time.Time{}},
  880. "",
  881. "",
  882. },
  883. {
  884. "time.Time near Unix zero time",
  885. &T{T: time.Unix(0, 4e3)},
  886. &T{T: time.Unix(0, 4e3)},
  887. "",
  888. "",
  889. },
  890. {
  891. "time.Time, far in the future",
  892. &T{T: time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)},
  893. &T{T: time.Date(99999, 1, 1, 0, 0, 0, 0, time.UTC)},
  894. "",
  895. "",
  896. },
  897. {
  898. "time.Time, very far in the past",
  899. &T{T: time.Date(-300000, 1, 1, 0, 0, 0, 0, time.UTC)},
  900. &T{},
  901. "time value out of range",
  902. "",
  903. },
  904. {
  905. "time.Time, very far in the future",
  906. &T{T: time.Date(294248, 1, 1, 0, 0, 0, 0, time.UTC)},
  907. &T{},
  908. "time value out of range",
  909. "",
  910. },
  911. {
  912. "structs",
  913. &N0{
  914. X0: X0{S: "one", I: 2, i: 3},
  915. Nonymous: X0{S: "four", I: 5, i: 6},
  916. Ignore: "ignore",
  917. Other: "other",
  918. },
  919. &N0{
  920. X0: X0{S: "one", I: 2},
  921. Nonymous: X0{S: "four", I: 5},
  922. Other: "other",
  923. },
  924. "",
  925. "",
  926. },
  927. {
  928. "slice of structs",
  929. &N1{
  930. X0: X0{S: "one", I: 2, i: 3},
  931. Nonymous: []X0{
  932. {S: "four", I: 5, i: 6},
  933. {S: "seven", I: 8, i: 9},
  934. {S: "ten", I: 11, i: 12},
  935. {S: "thirteen", I: 14, i: 15},
  936. },
  937. Ignore: "ignore",
  938. Other: "other",
  939. },
  940. &N1{
  941. X0: X0{S: "one", I: 2},
  942. Nonymous: []X0{
  943. {S: "four", I: 5},
  944. {S: "seven", I: 8},
  945. {S: "ten", I: 11},
  946. {S: "thirteen", I: 14},
  947. },
  948. Other: "other",
  949. },
  950. "",
  951. "",
  952. },
  953. {
  954. "structs with slices of structs",
  955. &N2{
  956. N1: N1{
  957. X0: X0{S: "rouge"},
  958. Nonymous: []X0{
  959. {S: "rosso0"},
  960. {S: "rosso1"},
  961. },
  962. },
  963. Green: N1{
  964. X0: X0{S: "vert"},
  965. Nonymous: []X0{
  966. {S: "verde0"},
  967. {S: "verde1"},
  968. {S: "verde2"},
  969. },
  970. },
  971. Blue: N1{
  972. X0: X0{S: "bleu"},
  973. Nonymous: []X0{
  974. {S: "blu0"},
  975. {S: "blu1"},
  976. {S: "blu2"},
  977. {S: "blu3"},
  978. },
  979. },
  980. },
  981. &N2{
  982. N1: N1{
  983. X0: X0{S: "rouge"},
  984. Nonymous: []X0{
  985. {S: "rosso0"},
  986. {S: "rosso1"},
  987. },
  988. },
  989. Green: N1{
  990. X0: X0{S: "vert"},
  991. Nonymous: []X0{
  992. {S: "verde0"},
  993. {S: "verde1"},
  994. {S: "verde2"},
  995. },
  996. },
  997. Blue: N1{
  998. X0: X0{S: "bleu"},
  999. Nonymous: []X0{
  1000. {S: "blu0"},
  1001. {S: "blu1"},
  1002. {S: "blu2"},
  1003. {S: "blu3"},
  1004. },
  1005. },
  1006. },
  1007. "",
  1008. "",
  1009. },
  1010. {
  1011. "save structs load props",
  1012. &N2{
  1013. N1: N1{
  1014. X0: X0{S: "rouge"},
  1015. Nonymous: []X0{
  1016. {S: "rosso0"},
  1017. {S: "rosso1"},
  1018. },
  1019. },
  1020. Green: N1{
  1021. X0: X0{S: "vert"},
  1022. Nonymous: []X0{
  1023. {S: "verde0"},
  1024. {S: "verde1"},
  1025. {S: "verde2"},
  1026. },
  1027. },
  1028. Blue: N1{
  1029. X0: X0{S: "bleu"},
  1030. Nonymous: []X0{
  1031. {S: "blu0"},
  1032. {S: "blu1"},
  1033. {S: "blu2"},
  1034. {S: "blu3"},
  1035. },
  1036. },
  1037. },
  1038. &PropertyList{
  1039. Property{Name: "red.S", Value: "rouge", NoIndex: false, Multiple: false},
  1040. Property{Name: "red.I", Value: int64(0), NoIndex: false, Multiple: false},
  1041. Property{Name: "red.Nonymous.S", Value: "rosso0", NoIndex: false, Multiple: true},
  1042. Property{Name: "red.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1043. Property{Name: "red.Nonymous.S", Value: "rosso1", NoIndex: false, Multiple: true},
  1044. Property{Name: "red.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1045. Property{Name: "red.Other", Value: "", NoIndex: false, Multiple: false},
  1046. Property{Name: "green.S", Value: "vert", NoIndex: false, Multiple: false},
  1047. Property{Name: "green.I", Value: int64(0), NoIndex: false, Multiple: false},
  1048. Property{Name: "green.Nonymous.S", Value: "verde0", NoIndex: false, Multiple: true},
  1049. Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1050. Property{Name: "green.Nonymous.S", Value: "verde1", NoIndex: false, Multiple: true},
  1051. Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1052. Property{Name: "green.Nonymous.S", Value: "verde2", NoIndex: false, Multiple: true},
  1053. Property{Name: "green.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1054. Property{Name: "green.Other", Value: "", NoIndex: false, Multiple: false},
  1055. Property{Name: "Blue.S", Value: "bleu", NoIndex: false, Multiple: false},
  1056. Property{Name: "Blue.I", Value: int64(0), NoIndex: false, Multiple: false},
  1057. Property{Name: "Blue.Nonymous.S", Value: "blu0", NoIndex: false, Multiple: true},
  1058. Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1059. Property{Name: "Blue.Nonymous.S", Value: "blu1", NoIndex: false, Multiple: true},
  1060. Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1061. Property{Name: "Blue.Nonymous.S", Value: "blu2", NoIndex: false, Multiple: true},
  1062. Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1063. Property{Name: "Blue.Nonymous.S", Value: "blu3", NoIndex: false, Multiple: true},
  1064. Property{Name: "Blue.Nonymous.I", Value: int64(0), NoIndex: false, Multiple: true},
  1065. Property{Name: "Blue.Other", Value: "", NoIndex: false, Multiple: false},
  1066. },
  1067. "",
  1068. "",
  1069. },
  1070. {
  1071. "save props load structs with ragged fields",
  1072. &PropertyList{
  1073. Property{Name: "red.S", Value: "rot", NoIndex: false, Multiple: false},
  1074. Property{Name: "green.Nonymous.I", Value: int64(10), NoIndex: false, Multiple: true},
  1075. Property{Name: "green.Nonymous.I", Value: int64(11), NoIndex: false, Multiple: true},
  1076. Property{Name: "green.Nonymous.I", Value: int64(12), NoIndex: false, Multiple: true},
  1077. Property{Name: "green.Nonymous.I", Value: int64(13), NoIndex: false, Multiple: true},
  1078. Property{Name: "Blue.Nonymous.S", Value: "blau0", NoIndex: false, Multiple: true},
  1079. Property{Name: "Blue.Nonymous.I", Value: int64(20), NoIndex: false, Multiple: true},
  1080. Property{Name: "Blue.Nonymous.S", Value: "blau1", NoIndex: false, Multiple: true},
  1081. Property{Name: "Blue.Nonymous.I", Value: int64(21), NoIndex: false, Multiple: true},
  1082. Property{Name: "Blue.Nonymous.S", Value: "blau2", NoIndex: false, Multiple: true},
  1083. },
  1084. &N2{
  1085. N1: N1{
  1086. X0: X0{S: "rot"},
  1087. },
  1088. Green: N1{
  1089. Nonymous: []X0{
  1090. {I: 10},
  1091. {I: 11},
  1092. {I: 12},
  1093. {I: 13},
  1094. },
  1095. },
  1096. Blue: N1{
  1097. Nonymous: []X0{
  1098. {S: "blau0", I: 20},
  1099. {S: "blau1", I: 21},
  1100. {S: "blau2"},
  1101. },
  1102. },
  1103. },
  1104. "",
  1105. "",
  1106. },
  1107. {
  1108. "save structs with noindex tags",
  1109. &struct {
  1110. A struct {
  1111. X string `datastore:",noindex"`
  1112. Y string
  1113. } `datastore:",noindex"`
  1114. B struct {
  1115. X string `datastore:",noindex"`
  1116. Y string
  1117. }
  1118. }{},
  1119. &PropertyList{
  1120. Property{Name: "B.Y", Value: "", NoIndex: false, Multiple: false},
  1121. Property{Name: "A.X", Value: "", NoIndex: true, Multiple: false},
  1122. Property{Name: "A.Y", Value: "", NoIndex: true, Multiple: false},
  1123. Property{Name: "B.X", Value: "", NoIndex: true, Multiple: false},
  1124. },
  1125. "",
  1126. "",
  1127. },
  1128. {
  1129. "embedded struct with name override",
  1130. &struct {
  1131. Inner1 `datastore:"foo"`
  1132. }{},
  1133. &PropertyList{
  1134. Property{Name: "foo.W", Value: int64(0), NoIndex: false, Multiple: false},
  1135. Property{Name: "foo.X", Value: "", NoIndex: false, Multiple: false},
  1136. },
  1137. "",
  1138. "",
  1139. },
  1140. {
  1141. "slice of slices",
  1142. &SliceOfSlices{},
  1143. nil,
  1144. "flattening nested structs leads to a slice of slices",
  1145. "",
  1146. },
  1147. {
  1148. "recursive struct",
  1149. &Recursive{},
  1150. nil,
  1151. "recursive struct",
  1152. "",
  1153. },
  1154. {
  1155. "mutually recursive struct",
  1156. &MutuallyRecursive0{},
  1157. nil,
  1158. "recursive struct",
  1159. "",
  1160. },
  1161. {
  1162. "non-exported struct fields",
  1163. &struct {
  1164. i, J int64
  1165. }{i: 1, J: 2},
  1166. &PropertyList{
  1167. Property{Name: "J", Value: int64(2), NoIndex: false, Multiple: false},
  1168. },
  1169. "",
  1170. "",
  1171. },
  1172. {
  1173. "json.RawMessage",
  1174. &struct {
  1175. J json.RawMessage
  1176. }{
  1177. J: json.RawMessage("rawr"),
  1178. },
  1179. &PropertyList{
  1180. Property{Name: "J", Value: []byte("rawr"), NoIndex: true, Multiple: false},
  1181. },
  1182. "",
  1183. "",
  1184. },
  1185. {
  1186. "json.RawMessage to myBlob",
  1187. &struct {
  1188. B json.RawMessage
  1189. }{
  1190. B: json.RawMessage("rawr"),
  1191. },
  1192. &B2{B: myBlob("rawr")},
  1193. "",
  1194. "",
  1195. },
  1196. }
  1197. // checkErr returns the empty string if either both want and err are zero,
  1198. // or if want is a non-empty substring of err's string representation.
  1199. func checkErr(want string, err error) string {
  1200. if err != nil {
  1201. got := err.Error()
  1202. if want == "" || strings.Index(got, want) == -1 {
  1203. return got
  1204. }
  1205. } else if want != "" {
  1206. return fmt.Sprintf("want error %q", want)
  1207. }
  1208. return ""
  1209. }
  1210. func TestRoundTrip(t *testing.T) {
  1211. for _, tc := range testCases {
  1212. p, err := saveEntity(testAppID, testKey0, tc.src)
  1213. if s := checkErr(tc.putErr, err); s != "" {
  1214. t.Errorf("%s: save: %s", tc.desc, s)
  1215. continue
  1216. }
  1217. if p == nil {
  1218. continue
  1219. }
  1220. var got interface{}
  1221. if _, ok := tc.want.(*PropertyList); ok {
  1222. got = new(PropertyList)
  1223. } else {
  1224. got = reflect.New(reflect.TypeOf(tc.want).Elem()).Interface()
  1225. }
  1226. err = loadEntity(got, p)
  1227. if s := checkErr(tc.getErr, err); s != "" {
  1228. t.Errorf("%s: load: %s", tc.desc, s)
  1229. continue
  1230. }
  1231. equal := false
  1232. if gotT, ok := got.(*T); ok {
  1233. // Round tripping a time.Time can result in a different time.Location: Local instead of UTC.
  1234. // We therefore test equality explicitly, instead of relying on reflect.DeepEqual.
  1235. equal = gotT.T.Equal(tc.want.(*T).T)
  1236. } else {
  1237. equal = reflect.DeepEqual(got, tc.want)
  1238. }
  1239. if !equal {
  1240. t.Errorf("%s: compare: got %v want %v", tc.desc, got, tc.want)
  1241. continue
  1242. }
  1243. }
  1244. }
  1245. func TestQueryConstruction(t *testing.T) {
  1246. tests := []struct {
  1247. q, exp *Query
  1248. err string
  1249. }{
  1250. {
  1251. q: NewQuery("Foo"),
  1252. exp: &Query{
  1253. kind: "Foo",
  1254. limit: -1,
  1255. },
  1256. },
  1257. {
  1258. // Regular filtered query with standard spacing.
  1259. q: NewQuery("Foo").Filter("foo >", 7),
  1260. exp: &Query{
  1261. kind: "Foo",
  1262. filter: []filter{
  1263. {
  1264. FieldName: "foo",
  1265. Op: greaterThan,
  1266. Value: 7,
  1267. },
  1268. },
  1269. limit: -1,
  1270. },
  1271. },
  1272. {
  1273. // Filtered query with no spacing.
  1274. q: NewQuery("Foo").Filter("foo=", 6),
  1275. exp: &Query{
  1276. kind: "Foo",
  1277. filter: []filter{
  1278. {
  1279. FieldName: "foo",
  1280. Op: equal,
  1281. Value: 6,
  1282. },
  1283. },
  1284. limit: -1,
  1285. },
  1286. },
  1287. {
  1288. // Filtered query with funky spacing.
  1289. q: NewQuery("Foo").Filter(" foo< ", 8),
  1290. exp: &Query{
  1291. kind: "Foo",
  1292. filter: []filter{
  1293. {
  1294. FieldName: "foo",
  1295. Op: lessThan,
  1296. Value: 8,
  1297. },
  1298. },
  1299. limit: -1,
  1300. },
  1301. },
  1302. {
  1303. // Filtered query with multicharacter op.
  1304. q: NewQuery("Foo").Filter("foo >=", 9),
  1305. exp: &Query{
  1306. kind: "Foo",
  1307. filter: []filter{
  1308. {
  1309. FieldName: "foo",
  1310. Op: greaterEq,
  1311. Value: 9,
  1312. },
  1313. },
  1314. limit: -1,
  1315. },
  1316. },
  1317. {
  1318. // Query with ordering.
  1319. q: NewQuery("Foo").Order("bar"),
  1320. exp: &Query{
  1321. kind: "Foo",
  1322. order: []order{
  1323. {
  1324. FieldName: "bar",
  1325. Direction: ascending,
  1326. },
  1327. },
  1328. limit: -1,
  1329. },
  1330. },
  1331. {
  1332. // Query with reverse ordering, and funky spacing.
  1333. q: NewQuery("Foo").Order(" - bar"),
  1334. exp: &Query{
  1335. kind: "Foo",
  1336. order: []order{
  1337. {
  1338. FieldName: "bar",
  1339. Direction: descending,
  1340. },
  1341. },
  1342. limit: -1,
  1343. },
  1344. },
  1345. {
  1346. // Query with an empty ordering.
  1347. q: NewQuery("Foo").Order(""),
  1348. err: "empty order",
  1349. },
  1350. {
  1351. // Query with a + ordering.
  1352. q: NewQuery("Foo").Order("+bar"),
  1353. err: "invalid order",
  1354. },
  1355. }
  1356. for i, test := range tests {
  1357. if test.q.err != nil {
  1358. got := test.q.err.Error()
  1359. if !strings.Contains(got, test.err) {
  1360. t.Errorf("%d: error mismatch: got %q want something containing %q", i, got, test.err)
  1361. }
  1362. continue
  1363. }
  1364. if !reflect.DeepEqual(test.q, test.exp) {
  1365. t.Errorf("%d: mismatch: got %v want %v", i, test.q, test.exp)
  1366. }
  1367. }
  1368. }
  1369. func TestStringMeaning(t *testing.T) {
  1370. var xx [4]interface{}
  1371. xx[0] = &struct {
  1372. X string
  1373. }{"xx0"}
  1374. xx[1] = &struct {
  1375. X string `datastore:",noindex"`
  1376. }{"xx1"}
  1377. xx[2] = &struct {
  1378. X []byte
  1379. }{[]byte("xx2")}
  1380. xx[3] = &struct {
  1381. X []byte `datastore:",noindex"`
  1382. }{[]byte("xx3")}
  1383. indexed := [4]bool{
  1384. true,
  1385. false,
  1386. false, // A []byte is always no-index.
  1387. false,
  1388. }
  1389. want := [4]pb.Property_Meaning{
  1390. pb.Property_NO_MEANING,
  1391. pb.Property_TEXT,
  1392. pb.Property_BLOB,
  1393. pb.Property_BLOB,
  1394. }
  1395. for i, x := range xx {
  1396. props, err := SaveStruct(x)
  1397. if err != nil {
  1398. t.Errorf("i=%d: SaveStruct: %v", i, err)
  1399. continue
  1400. }
  1401. e, err := propertiesToProto("appID", testKey0, props)
  1402. if err != nil {
  1403. t.Errorf("i=%d: propertiesToProto: %v", i, err)
  1404. continue
  1405. }
  1406. var p *pb.Property
  1407. switch {
  1408. case indexed[i] && len(e.Property) == 1:
  1409. p = e.Property[0]
  1410. case !indexed[i] && len(e.RawProperty) == 1:
  1411. p = e.RawProperty[0]
  1412. default:
  1413. t.Errorf("i=%d: EntityProto did not have expected property slice", i)
  1414. continue
  1415. }
  1416. if got := p.GetMeaning(); got != want[i] {
  1417. t.Errorf("i=%d: meaning: got %v, want %v", i, got, want[i])
  1418. continue
  1419. }
  1420. }
  1421. }