OLD | NEW |
| (Empty) |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package datastore | |
6 | |
7 import ( | |
8 "bytes" | |
9 "io" | |
10 "testing" | |
11 "time" | |
12 | |
13 "github.com/luci/gae/service/blobstore" | |
14 "github.com/luci/luci-go/common/cmpbin" | |
15 . "github.com/smartystreets/goconvey/convey" | |
16 ) | |
17 | |
18 func init() { | |
19 WritePropertyMapDeterministic = true | |
20 } | |
21 | |
22 type dspmapTC struct { | |
23 name string | |
24 props PropertyMap | |
25 } | |
26 | |
27 func TestPropertyMapSerialization(t *testing.T) { | |
28 t.Parallel() | |
29 | |
30 tests := []dspmapTC{ | |
31 { | |
32 "basic", | |
33 PropertyMap{ | |
34 "R": {mp(false), mp(2.1), mpNI(3)}, | |
35 "S": {mp("hello"), mp("world")}, | |
36 }, | |
37 }, | |
38 { | |
39 "keys", | |
40 PropertyMap{ | |
41 "DS": {mp(mkKey("appy", "ns", "Foo", 7)),
mp(mkKey("other", "", "Yot", "wheeep"))}, | |
42 "blobstore": {mp(blobstore.Key("sup")), mp(blobs
tore.Key("nerds"))}, | |
43 }, | |
44 }, | |
45 { | |
46 "geo", | |
47 PropertyMap{ | |
48 "G": {mp(GeoPoint{Lat: 1, Lng: 2})}, | |
49 }, | |
50 }, | |
51 { | |
52 "data", | |
53 PropertyMap{ | |
54 "S": {mp("sup"), mp("fool"), mp("nerd")
}, | |
55 "D.Foo.Nerd": {mp([]byte("sup")), mp([]byte("foo
l"))}, | |
56 "B": {mp(ByteString("sup")), mp(ByteStr
ing("fool"))}, | |
57 }, | |
58 }, | |
59 { | |
60 "time", | |
61 PropertyMap{ | |
62 "T": { | |
63 mp(time.Now().UTC()), | |
64 mp(time.Now().Add(time.Second).UTC())}, | |
65 }, | |
66 }, | |
67 { | |
68 "empty vals", | |
69 PropertyMap{ | |
70 "T": {mp(true), mp(true)}, | |
71 "F": {mp(false), mp(false)}, | |
72 "N": {mp(nil), mp(nil)}, | |
73 "E": {}, | |
74 }, | |
75 }, | |
76 } | |
77 | |
78 Convey("PropertyMap serialization", t, func() { | |
79 Convey("round trip", func() { | |
80 for _, tc := range tests { | |
81 tc := tc | |
82 Convey(tc.name, func() { | |
83 buf := &bytes.Buffer{} | |
84 tc.props.Write(buf, WithContext) | |
85 dec := PropertyMap{} | |
86 err := dec.Read(buf, WithContext, "", ""
) | |
87 So(err, ShouldBeNil) | |
88 So(dec, ShouldResemble, tc.props) | |
89 }) | |
90 } | |
91 }) | |
92 }) | |
93 } | |
94 | |
95 func TestSerializationReadMisc(t *testing.T) { | |
96 t.Parallel() | |
97 | |
98 Convey("Misc Serialization tests", t, func() { | |
99 buf := &bytes.Buffer{} | |
100 Convey("ReadKey", func() { | |
101 Convey("good cases", func() { | |
102 Convey("w/ ctx decodes normally w/ ctx", func()
{ | |
103 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) | |
104 WriteKey(buf, WithContext, k) | |
105 dk, err := ReadKey(buf, WithContext, "",
"") | |
106 So(err, ShouldBeNil) | |
107 So(dk, ShouldEqualKey, k) | |
108 }) | |
109 Convey("w/ ctx decodes normally w/o ctx", func()
{ | |
110 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) | |
111 WriteKey(buf, WithContext, k) | |
112 dk, err := ReadKey(buf, WithoutContext,
"spam", "nerd") | |
113 So(err, ShouldBeNil) | |
114 So(dk, ShouldEqualKey, mkKey("spam", "ne
rd", "knd", "yo", "other", 10)) | |
115 }) | |
116 Convey("w/o ctx decodes normally w/ ctx", func()
{ | |
117 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) | |
118 WriteKey(buf, WithoutContext, k) | |
119 dk, err := ReadKey(buf, WithContext, "sp
am", "nerd") | |
120 So(err, ShouldBeNil) | |
121 So(dk, ShouldEqualKey, mkKey("", "", "kn
d", "yo", "other", 10)) | |
122 }) | |
123 Convey("w/o ctx decodes normally w/o ctx", func(
) { | |
124 k := mkKey("aid", "ns", "knd", "yo", "ot
her", 10) | |
125 WriteKey(buf, WithoutContext, k) | |
126 dk, err := ReadKey(buf, WithoutContext,
"spam", "nerd") | |
127 So(err, ShouldBeNil) | |
128 So(dk, ShouldEqualKey, mkKey("spam", "ne
rd", "knd", "yo", "other", 10)) | |
129 }) | |
130 Convey("IntIDs always sort before StringIDs", fu
nc() { | |
131 // -1 writes as almost all 1's in the fi
rst byte under cmpbin, even | |
132 // though it's technically not a valid k
ey. | |
133 k := mkKey("aid", "ns", "knd", -1) | |
134 WriteKey(buf, WithoutContext, k) | |
135 | |
136 k = mkKey("aid", "ns", "knd", "hat") | |
137 buf2 := &bytes.Buffer{} | |
138 WriteKey(buf2, WithoutContext, k) | |
139 | |
140 So(bytes.Compare(buf.Bytes(), buf2.Bytes
()), ShouldBeLessThan, 0) | |
141 }) | |
142 }) | |
143 | |
144 Convey("err cases", func() { | |
145 Convey("nil", func() { | |
146 _, err := ReadKey(buf, WithContext, "",
"") | |
147 So(err, ShouldEqual, io.EOF) | |
148 }) | |
149 Convey("str", func() { | |
150 buf.WriteString("sup") | |
151 _, err := ReadKey(buf, WithContext, "",
"") | |
152 So(err, ShouldErrLike, "expected actualC
tx") | |
153 }) | |
154 Convey("truncated 1", func() { | |
155 buf.WriteByte(1) // actualCtx == 1 | |
156 _, err := ReadKey(buf, WithContext, "",
"") | |
157 So(err, ShouldEqual, io.EOF) | |
158 }) | |
159 Convey("truncated 2", func() { | |
160 buf.WriteByte(1) // actualCtx == 1 | |
161 cmpbin.WriteString(buf, "aid") | |
162 _, err := ReadKey(buf, WithContext, "",
"") | |
163 So(err, ShouldEqual, io.EOF) | |
164 }) | |
165 Convey("truncated 3", func() { | |
166 buf.WriteByte(1) // actualCtx == 1 | |
167 cmpbin.WriteString(buf, "aid") | |
168 cmpbin.WriteString(buf, "ns") | |
169 _, err := ReadKey(buf, WithContext, "",
"") | |
170 So(err, ShouldEqual, io.EOF) | |
171 }) | |
172 Convey("huge key", func() { | |
173 buf.WriteByte(1) // actualCtx == 1 | |
174 cmpbin.WriteString(buf, "aid") | |
175 cmpbin.WriteString(buf, "ns") | |
176 cmpbin.WriteUint(buf, 1000) | |
177 _, err := ReadKey(buf, WithContext, "",
"") | |
178 So(err, ShouldErrLike, "huge key") | |
179 }) | |
180 Convey("insufficient tokens", func() { | |
181 buf.WriteByte(1) // actualCtx == 1 | |
182 cmpbin.WriteString(buf, "aid") | |
183 cmpbin.WriteString(buf, "ns") | |
184 cmpbin.WriteUint(buf, 2) | |
185 _, err := ReadKey(buf, WithContext, "",
"") | |
186 So(err, ShouldEqual, io.EOF) | |
187 }) | |
188 Convey("partial token 1", func() { | |
189 buf.WriteByte(1) // actualCtx == 1 | |
190 cmpbin.WriteString(buf, "aid") | |
191 cmpbin.WriteString(buf, "ns") | |
192 cmpbin.WriteUint(buf, 2) | |
193 cmpbin.WriteString(buf, "hi") | |
194 _, err := ReadKey(buf, WithContext, "",
"") | |
195 So(err, ShouldEqual, io.EOF) | |
196 }) | |
197 Convey("partial token 2", func() { | |
198 buf.WriteByte(1) // actualCtx == 1 | |
199 cmpbin.WriteString(buf, "aid") | |
200 cmpbin.WriteString(buf, "ns") | |
201 cmpbin.WriteUint(buf, 2) | |
202 cmpbin.WriteString(buf, "hi") | |
203 buf.WriteByte(byte(PTString)) | |
204 _, err := ReadKey(buf, WithContext, "",
"") | |
205 So(err, ShouldEqual, io.EOF) | |
206 }) | |
207 Convey("bad token (invalid type)", func() { | |
208 buf.WriteByte(1) // actualCtx == 1 | |
209 cmpbin.WriteString(buf, "aid") | |
210 cmpbin.WriteString(buf, "ns") | |
211 cmpbin.WriteUint(buf, 2) | |
212 cmpbin.WriteString(buf, "hi") | |
213 buf.WriteByte(byte(PTBlobKey)) | |
214 _, err := ReadKey(buf, WithContext, "",
"") | |
215 So(err, ShouldErrLike, "invalid type PTB
lobKey") | |
216 }) | |
217 Convey("bad token (invalid IntID)", func() { | |
218 buf.WriteByte(1) // actualCtx == 1 | |
219 cmpbin.WriteString(buf, "aid") | |
220 cmpbin.WriteString(buf, "ns") | |
221 cmpbin.WriteUint(buf, 2) | |
222 cmpbin.WriteString(buf, "hi") | |
223 buf.WriteByte(byte(PTInt)) | |
224 cmpbin.WriteInt(buf, -2) | |
225 _, err := ReadKey(buf, WithContext, "",
"") | |
226 So(err, ShouldErrLike, "zero/negative") | |
227 }) | |
228 }) | |
229 }) | |
230 | |
231 Convey("ReadGeoPoint", func() { | |
232 gp := GeoPoint{} | |
233 Convey("trunc 1", func() { | |
234 err := gp.Read(buf) | |
235 So(err, ShouldEqual, io.EOF) | |
236 }) | |
237 Convey("trunc 2", func() { | |
238 cmpbin.WriteFloat64(buf, 100) | |
239 err := gp.Read(buf) | |
240 So(err, ShouldEqual, io.EOF) | |
241 }) | |
242 Convey("invalid", func() { | |
243 cmpbin.WriteFloat64(buf, 100) | |
244 cmpbin.WriteFloat64(buf, 1000) | |
245 err := gp.Read(buf) | |
246 So(err, ShouldErrLike, "invalid GeoPoint") | |
247 }) | |
248 }) | |
249 | |
250 Convey("WriteTime", func() { | |
251 Convey("in non-UTC!", func() { | |
252 pst, err := time.LoadLocation("America/Los_Angel
es") | |
253 So(err, ShouldBeNil) | |
254 So(func() { | |
255 WriteTime(buf, time.Now().In(pst)) | |
256 }, ShouldPanic) | |
257 }) | |
258 }) | |
259 | |
260 Convey("ReadTime", func() { | |
261 Convey("trunc 1", func() { | |
262 _, err := ReadTime(buf) | |
263 So(err, ShouldEqual, io.EOF) | |
264 }) | |
265 }) | |
266 | |
267 Convey("ReadProperty", func() { | |
268 p := Property{} | |
269 Convey("trunc 1", func() { | |
270 err := p.Read(buf, WithContext, "", "") | |
271 So(err, ShouldEqual, io.EOF) | |
272 So(p.Type(), ShouldEqual, PTNull) | |
273 So(p.Value(), ShouldBeNil) | |
274 }) | |
275 Convey("trunc (PTBytes)", func() { | |
276 buf.WriteByte(byte(PTBytes)) | |
277 err := p.Read(buf, WithContext, "", "") | |
278 So(err, ShouldEqual, io.EOF) | |
279 }) | |
280 Convey("trunc (PTBlobKey)", func() { | |
281 buf.WriteByte(byte(PTBlobKey)) | |
282 err := p.Read(buf, WithContext, "", "") | |
283 So(err, ShouldEqual, io.EOF) | |
284 }) | |
285 Convey("invalid type", func() { | |
286 buf.WriteByte(byte(PTUnknown + 1)) | |
287 err := p.Read(buf, WithContext, "", "") | |
288 So(err, ShouldErrLike, "unknown type!") | |
289 }) | |
290 }) | |
291 | |
292 Convey("ReadPropertyMap", func() { | |
293 pm := PropertyMap{} | |
294 Convey("trunc 1", func() { | |
295 err := pm.Read(buf, WithContext, "", "") | |
296 So(err, ShouldEqual, io.EOF) | |
297 }) | |
298 Convey("too many rows", func() { | |
299 cmpbin.WriteUint(buf, 1000000) | |
300 err := pm.Read(buf, WithContext, "", "") | |
301 So(err, ShouldErrLike, "huge number of rows") | |
302 }) | |
303 Convey("trunc 2", func() { | |
304 cmpbin.WriteUint(buf, 10) | |
305 err := pm.Read(buf, WithContext, "", "") | |
306 So(err, ShouldEqual, io.EOF) | |
307 }) | |
308 Convey("trunc 3", func() { | |
309 cmpbin.WriteUint(buf, 10) | |
310 cmpbin.WriteString(buf, "ohai") | |
311 err := pm.Read(buf, WithContext, "", "") | |
312 So(err, ShouldEqual, io.EOF) | |
313 }) | |
314 Convey("too many values", func() { | |
315 cmpbin.WriteUint(buf, 10) | |
316 cmpbin.WriteString(buf, "ohai") | |
317 cmpbin.WriteUint(buf, 100000) | |
318 err := pm.Read(buf, WithContext, "", "") | |
319 So(err, ShouldErrLike, "huge number of propertie
s") | |
320 }) | |
321 Convey("trunc 4", func() { | |
322 cmpbin.WriteUint(buf, 10) | |
323 cmpbin.WriteString(buf, "ohai") | |
324 cmpbin.WriteUint(buf, 10) | |
325 err := pm.Read(buf, WithContext, "", "") | |
326 So(err, ShouldEqual, io.EOF) | |
327 }) | |
328 }) | |
329 }) | |
330 } | |
OLD | NEW |