1 package storage
2
3
4
5
6 import (
7 "encoding/json"
8 "fmt"
9 "strings"
10 "time"
11
12 "github.com/gofrs/uuid"
13 chk "gopkg.in/check.v1"
14 )
15
16 type StorageEntitySuite struct{}
17
18 var _ = chk.Suite(&StorageEntitySuite{})
19
20 func (s *StorageEntitySuite) TestGet(c *chk.C) {
21 cli := getTableClient(c)
22 rec := cli.client.appendRecorder(c)
23 defer rec.Stop()
24
25 table := cli.GetTableReference(tableName(c))
26
27 err := table.Create(30, EmptyPayload, nil)
28 c.Assert(err, chk.IsNil)
29 defer table.Delete(30, nil)
30
31 entity := table.GetEntityReference("mypartitionkey", "myrowkey")
32
33 props := map[string]interface{}{
34 "AmountDue": float32(200.23),
35 "CustomerCode": uuid.FromStringOrNil("c9da6455-213d-42c9-9a79-3e9149a57833"),
36 "CustomerSince": time.Date(1992, time.December, 20, 21, 55, 0, 0, time.UTC),
37 "IsActive": true,
38 "NumberOfOrders": int64(255),
39 }
40 entity.Properties = props
41 err = entity.Insert(EmptyPayload, nil)
42 c.Assert(err, chk.IsNil)
43
44 err = entity.Get(30, FullMetadata, &GetEntityOptions{
45 Select: []string{"IsActive"},
46 })
47 c.Assert(err, chk.IsNil)
48 c.Assert(entity.Properties, chk.HasLen, 1)
49
50 err = entity.Get(30, FullMetadata, &GetEntityOptions{
51 Select: []string{
52 "AmountDue",
53 "CustomerCode",
54 "CustomerSince",
55 "IsActive",
56 "NumberOfOrders",
57 }})
58 c.Assert(err, chk.IsNil)
59 c.Assert(entity.Properties, chk.HasLen, 5)
60
61 err = entity.Get(30, FullMetadata, nil)
62 c.Assert(err, chk.IsNil)
63 c.Assert(entity.Properties, chk.HasLen, 5)
64 }
65
66 const (
67 validEtag = "W/\"datetime''2017-04-01T01%3A07%3A23.8881885Z''\""
68 )
69
70 func (s *StorageEntitySuite) TestInsert(c *chk.C) {
71 cli := getTableClient(c)
72 rec := cli.client.appendRecorder(c)
73 defer rec.Stop()
74
75 table := cli.GetTableReference(tableName(c))
76 err := table.Create(30, EmptyPayload, nil)
77 c.Assert(err, chk.IsNil)
78 defer table.Delete(30, nil)
79
80 entity := table.GetEntityReference("mypartitionkey", "myrowkey")
81
82 props := map[string]interface{}{
83 "AmountDue": float32(200.23),
84 "CustomerCode": uuid.FromStringOrNil("c9da6455-213d-42c9-9a79-3e9149a57833"),
85 "CustomerSince": time.Date(1992, time.December, 20, 21, 55, 0, 0, time.UTC),
86 "IsActive": true,
87 "NumberOfOrders": int64(255),
88 }
89 entity.Properties = props
90 err = entity.Insert(EmptyPayload, nil)
91 c.Assert(err, chk.IsNil)
92
93 c.Assert(entity.TimeStamp, chk.Equals, time.Time{})
94 c.Assert(entity.OdataMetadata, chk.Equals, "")
95 c.Assert(entity.OdataType, chk.Equals, "")
96 c.Assert(entity.OdataID, chk.Equals, "")
97 c.Assert(entity.OdataEtag, chk.Equals, "")
98 c.Assert(entity.OdataEditLink, chk.Equals, "")
99
100
101 entity.PartitionKey = "mypartitionkey2"
102 entity.RowKey = "myrowkey2"
103 err = entity.Insert(FullMetadata, nil)
104 c.Assert(err, chk.IsNil)
105
106 c.Assert(entity.TimeStamp, chk.NotNil)
107 c.Assert(entity.OdataMetadata, chk.Not(chk.Equals), "")
108 c.Assert(entity.OdataType, chk.Not(chk.Equals), "")
109 c.Assert(entity.OdataID, chk.Not(chk.Equals), "")
110 c.Assert(entity.OdataEtag, chk.Not(chk.Equals), "")
111 c.Assert(entity.OdataEditLink, chk.Not(chk.Equals), "")
112 }
113
114 func (s *StorageEntitySuite) TestUpdate(c *chk.C) {
115 cli := getTableClient(c)
116 rec := cli.client.appendRecorder(c)
117 defer rec.Stop()
118
119 table := cli.GetTableReference(tableName(c))
120 err := table.Create(30, EmptyPayload, nil)
121 c.Assert(err, chk.IsNil)
122 defer table.Delete(30, nil)
123
124 entity := table.GetEntityReference("mypartitionkey", "myrowkey")
125 entity.Properties = map[string]interface{}{
126 "AmountDue": float32(200.23),
127 "CustomerCode": uuid.FromStringOrNil("c9da6455-213d-42c9-9a79-3e9149a57833"),
128 "CustomerSince": time.Date(1992, time.December, 20, 21, 55, 0, 0, time.UTC),
129 "IsActive": true,
130 "NumberOfOrders": int64(255),
131 }
132
133 err = entity.Insert(FullMetadata, nil)
134 c.Assert(err, chk.IsNil)
135
136 etag := entity.OdataEtag
137 timestamp := entity.TimeStamp
138
139 props := map[string]interface{}{
140 "Name": "Anakin",
141 "FamilyName": "Skywalker",
142 "HasEpicTheme": true,
143 }
144 entity.Properties = props
145
146 err = entity.Update(false, nil)
147 c.Assert(err, chk.IsNil)
148
149 c.Assert(entity.Properties, chk.DeepEquals, props)
150 c.Assert(entity.OdataEtag, chk.Not(chk.Equals), etag)
151 c.Assert(entity.TimeStamp, chk.Not(chk.Equals), timestamp)
152
153
154 entity.OdataEtag = validEtag
155 err = entity.Update(false, nil)
156 c.Assert(err, chk.NotNil)
157 c.Assert(strings.Contains(err.Error(), "Etag didn't match"), chk.Equals, true)
158
159
160 props = map[string]interface{}{
161 "Name": "Leia",
162 "FamilyName": "Organa",
163 "HasAwesomeDress": true,
164 }
165 entity.Properties = props
166 err = entity.Update(true, nil)
167 c.Assert(err, chk.IsNil)
168 c.Assert(entity.Properties, chk.DeepEquals, props)
169 }
170
171 func (s *StorageEntitySuite) TestMerge(c *chk.C) {
172 cli := getTableClient(c)
173 rec := cli.client.appendRecorder(c)
174 defer rec.Stop()
175
176 table := cli.GetTableReference(tableName(c))
177 err := table.Create(30, EmptyPayload, nil)
178 c.Assert(err, chk.IsNil)
179 defer table.Delete(30, nil)
180
181 entity := table.GetEntityReference("mypartitionkey", "myrowkey")
182 entity.Properties = map[string]interface{}{
183 "Country": "Mexico",
184 "MalePoet": "Nezahualcoyotl",
185 }
186 c.Assert(entity.Insert(FullMetadata, nil), chk.IsNil)
187
188 etag := entity.OdataEtag
189 timestamp := entity.TimeStamp
190
191 entity.Properties = map[string]interface{}{
192 "FemalePoet": "Sor Juana Ines de la Cruz",
193 }
194
195 err = entity.Merge(false, nil)
196 c.Assert(err, chk.IsNil)
197 c.Assert(entity.OdataEtag, chk.Not(chk.Equals), etag)
198 c.Assert(entity.TimeStamp, chk.Not(chk.Equals), timestamp)
199
200
201 entity.OdataEtag = validEtag
202 err = entity.Merge(false, nil)
203 c.Assert(err, chk.NotNil)
204 c.Assert(strings.Contains(err.Error(), "Etag didn't match"), chk.Equals, true)
205
206
207 entity.Properties = map[string]interface{}{
208 "MalePainter": "Diego Rivera",
209 "FemalePainter": "Frida Kahlo",
210 }
211 err = entity.Merge(true, nil)
212 c.Assert(err, chk.IsNil)
213 }
214
215 func (s *StorageEntitySuite) TestDelete(c *chk.C) {
216 cli := getTableClient(c)
217 rec := cli.client.appendRecorder(c)
218 defer rec.Stop()
219
220 table := cli.GetTableReference(tableName(c))
221 err := table.Create(30, EmptyPayload, nil)
222 c.Assert(err, chk.IsNil)
223 defer table.Delete(30, nil)
224
225
226 entity1 := table.GetEntityReference("pkey1", "rowkey1")
227 c.Assert(entity1.Insert(FullMetadata, nil), chk.IsNil)
228
229 err = entity1.Delete(false, nil)
230 c.Assert(err, chk.IsNil)
231
232
233 entity2 := table.GetEntityReference("pkey2", "rowkey2")
234 c.Assert(entity2.Insert(EmptyPayload, nil), chk.IsNil)
235 entity2.OdataEtag = "GolangRocksOnAzure"
236
237 err = entity2.Delete(false, nil)
238 c.Assert(err, chk.NotNil)
239
240
241 err = entity2.Delete(true, nil)
242 c.Assert(err, chk.IsNil)
243 }
244
245 func (s *StorageEntitySuite) TestInsertOrReplace(c *chk.C) {
246 cli := getTableClient(c)
247 rec := cli.client.appendRecorder(c)
248 defer rec.Stop()
249
250 table := cli.GetTableReference(tableName(c))
251 err := table.Create(30, EmptyPayload, nil)
252 c.Assert(err, chk.IsNil)
253 defer table.Delete(30, nil)
254
255 entity := table.GetEntityReference("mypartitionkey", "myrowkey")
256 entity.Properties = map[string]interface{}{
257 "Name": "Anakin",
258 "FamilyName": "Skywalker",
259 "HasEpicTheme": true,
260 }
261
262 err = entity.InsertOrReplace(nil)
263 c.Assert(err, chk.IsNil)
264
265 entity.Properties = map[string]interface{}{
266 "Name": "Leia",
267 "FamilyName": "Organa",
268 "HasAwesomeDress": true,
269 }
270 err = entity.InsertOrReplace(nil)
271 c.Assert(err, chk.IsNil)
272 }
273
274 func (s *StorageEntitySuite) TestInsertOrMerge(c *chk.C) {
275 cli := getTableClient(c)
276 rec := cli.client.appendRecorder(c)
277 defer rec.Stop()
278
279 table := cli.GetTableReference(tableName(c))
280 err := table.Create(30, EmptyPayload, nil)
281 c.Assert(err, chk.IsNil)
282 defer table.Delete(30, nil)
283
284 entity := table.GetEntityReference("mypartitionkey", "myrowkey")
285 entity.Properties = map[string]interface{}{
286 "Name": "Luke",
287 "FamilyName": "Skywalker",
288 }
289
290 err = entity.InsertOrMerge(nil)
291 c.Assert(err, chk.IsNil)
292
293 entity.Properties = map[string]interface{}{
294 "Father": "Anakin",
295 "Mentor": "Yoda",
296 }
297 err = entity.InsertOrMerge(nil)
298 c.Assert(err, chk.IsNil)
299 }
300
301 func (s *StorageEntitySuite) Test_InsertAndGetEntities(c *chk.C) {
302 cli := getTableClient(c)
303 rec := cli.client.appendRecorder(c)
304 defer rec.Stop()
305
306 table := cli.GetTableReference(tableName(c))
307 err := table.Create(30, EmptyPayload, nil)
308 c.Assert(err, chk.IsNil)
309 defer table.Delete(30, nil)
310
311 entity := table.GetEntityReference("mypartitionkey", "100")
312 entity.Properties = map[string]interface{}{
313 "Name": "Luke",
314 "FamilyName": "Skywalker",
315 "HasCoolWeapon": true,
316 }
317 c.Assert(entity.Insert(EmptyPayload, nil), chk.IsNil)
318
319 entity.RowKey = "200"
320 c.Assert(entity.Insert(FullMetadata, nil), chk.IsNil)
321
322 entities, err := table.QueryEntities(30, FullMetadata, nil)
323 c.Assert(err, chk.IsNil)
324
325 c.Assert(entities.Entities, chk.HasLen, 2)
326 c.Assert(entities.OdataMetadata+"/@Element", chk.Equals, entity.OdataMetadata)
327
328 compareEntities(entities.Entities[1], entity, c)
329 }
330
331 func (s *StorageEntitySuite) Test_InsertAndExecuteQuery(c *chk.C) {
332 cli := getTableClient(c)
333 rec := cli.client.appendRecorder(c)
334 defer rec.Stop()
335
336 table := cli.GetTableReference(tableName(c))
337 err := table.Create(30, EmptyPayload, nil)
338 c.Assert(err, chk.IsNil)
339 defer table.Delete(30, nil)
340
341 entity := table.GetEntityReference("mypartitionkey", "100")
342 entity.Properties = map[string]interface{}{
343 "Name": "Luke",
344 "FamilyName": "Skywalker",
345 "HasCoolWeapon": true,
346 }
347 c.Assert(entity.Insert(EmptyPayload, nil), chk.IsNil)
348
349 entity.RowKey = "200"
350 c.Assert(entity.Insert(EmptyPayload, nil), chk.IsNil)
351
352 queryOptions := QueryOptions{
353 Filter: "RowKey eq '200'",
354 }
355
356 entities, err := table.QueryEntities(30, FullMetadata, &queryOptions)
357 c.Assert(err, chk.IsNil)
358
359 c.Assert(entities.Entities, chk.HasLen, 1)
360 c.Assert(entities.Entities[0].RowKey, chk.Equals, entity.RowKey)
361 }
362
363 func (s *StorageEntitySuite) Test_InsertAndDeleteEntities(c *chk.C) {
364 cli := getTableClient(c)
365 rec := cli.client.appendRecorder(c)
366 defer rec.Stop()
367
368 table := cli.GetTableReference(tableName(c))
369 err := table.Create(30, EmptyPayload, nil)
370 c.Assert(err, chk.IsNil)
371 defer table.Delete(30, nil)
372
373 entity := table.GetEntityReference("mypartitionkey", "100")
374 entity.Properties = map[string]interface{}{
375 "FamilyName": "Skywalker",
376 "Name": "Luke",
377 "Number": 3,
378 }
379 c.Assert(entity.Insert(EmptyPayload, nil), chk.IsNil)
380
381 entity.Properties["Number"] = 1
382 entity.RowKey = "200"
383 c.Assert(entity.Insert(FullMetadata, nil), chk.IsNil)
384
385 options := QueryOptions{
386 Filter: "Number eq 1",
387 }
388
389 result, err := table.QueryEntities(30, FullMetadata, &options)
390 c.Assert(err, chk.IsNil)
391 c.Assert(result.Entities, chk.HasLen, 1)
392 compareEntities(result.Entities[0], entity, c)
393
394 err = result.Entities[0].Delete(true, nil)
395 c.Assert(err, chk.IsNil)
396
397 result, err = table.QueryEntities(30, FullMetadata, nil)
398 c.Assert(err, chk.IsNil)
399
400
401 c.Assert(result.Entities, chk.HasLen, 1)
402 }
403
404 func (s *StorageEntitySuite) TestExecuteQueryNextResults(c *chk.C) {
405 cli := getTableClient(c)
406 rec := cli.client.appendRecorder(c)
407 defer rec.Stop()
408
409 table := cli.GetTableReference(tableName(c))
410 err := table.Create(30, EmptyPayload, nil)
411 c.Assert(err, chk.IsNil)
412 defer table.Delete(30, nil)
413
414 var entityList []*Entity
415
416 for i := 0; i < 5; i++ {
417 entity := table.GetEntityReference("pkey", fmt.Sprintf("r%d", i))
418 err := entity.Insert(FullMetadata, nil)
419 c.Assert(err, chk.IsNil)
420 entityList = append(entityList, entity)
421 }
422
423
424
425 options := QueryOptions{
426 Top: 2,
427 }
428 results, err := table.QueryEntities(30, FullMetadata, &options)
429 c.Assert(err, chk.IsNil)
430 c.Assert(results.Entities, chk.HasLen, 2)
431 c.Assert(results.NextLink, chk.NotNil)
432 compareEntities(results.Entities[0], entityList[0], c)
433 compareEntities(results.Entities[1], entityList[1], c)
434
435 results, err = results.NextResults(nil)
436 c.Assert(err, chk.IsNil)
437 c.Assert(results.Entities, chk.HasLen, 2)
438 c.Assert(results.NextLink, chk.NotNil)
439 compareEntities(results.Entities[0], entityList[2], c)
440 compareEntities(results.Entities[1], entityList[3], c)
441
442 results, err = results.NextResults(nil)
443 c.Assert(err, chk.IsNil)
444 c.Assert(results.Entities, chk.HasLen, 1)
445 c.Assert(results.NextLink, chk.IsNil)
446 compareEntities(results.Entities[0], entityList[4], c)
447 }
448
449 func (s *StorageEntitySuite) Test_entityMarshalJSON(c *chk.C) {
450 expected := `{"Address":"Mountain View","Age":23,"AmountDue":"200.23","AmountDue@odata.type":"Edm.Double","Binary":"YWJjZA==","Binary@odata.type":"Edm.Binary","CustomerCode":"c9da6455-213d-42c9-9a79-3e9149a57833","CustomerCode@odata.type":"Edm.Guid","CustomerSince":"1992-12-20T21:55:00Z","CustomerSince@odata.type":"Edm.DateTime","IsActive":true,"NumberOfOrders":"255","NumberOfOrders@odata.type":"Edm.Int64","PartitionKey":"mypartitionkey","RowKey":"myrowkey"}`
451
452 entity := Entity{
453 PartitionKey: "mypartitionkey",
454 RowKey: "myrowkey",
455 Properties: map[string]interface{}{
456 "Address": "Mountain View",
457 "Age": 23,
458 "AmountDue": float64(200.23),
459 "Binary": []byte("abcd"),
460 "CustomerCode": uuid.FromStringOrNil("c9da6455-213d-42c9-9a79-3e9149a57833"),
461 "CustomerSince": time.Date(1992, time.December, 20, 21, 55, 0, 0, time.UTC),
462 "IsActive": true,
463 "NumberOfOrders": int64(255),
464 },
465 }
466 got, err := json.Marshal(&entity)
467 c.Assert(err, chk.IsNil)
468 c.Assert(string(got), chk.Equals, expected)
469
470 entity.Properties["Contoso@odata.type"] = "Edm.Trololololol"
471 got, err = json.Marshal(&entity)
472 c.Assert(got, chk.IsNil)
473 c.Assert(err, chk.ErrorMatches, ".*Odata.type annotation Contoso@odata.type value is not valid")
474
475 entity.Properties["Contoso@odata.type"] = OdataGUID
476 got, err = json.Marshal(&entity)
477 c.Assert(got, chk.IsNil)
478 c.Assert(err, chk.ErrorMatches, ".*Odata.type annotation Contoso@odata.type defined without value defined")
479 }
480
481 func (s *StorageEntitySuite) Test_entityUnmarshalJSON(c *chk.C) {
482 input := `{
483 "odata.metadata":"https://azuregosdkstoragetests.table.core.windows.net/$metadata#SampleTable/@Element",
484 "odata.type":"azuregosdkstoragetests.SampleTable",
485 "odata.id":"https://azuregosdkstoragetests.table.core.windows.net/SampleTable(PartitionKey=''mypartitionkey'',RowKey=''myrowkey'')",
486 "odata.etag":"W/\"datetime''2017-01-27T01%3A01%3A44.151805Z''\"",
487 "odata.editLink":"SampleTable(PartitionKey=''mypartitionkey'',RowKey=''myrowkey'')",
488 "PartitionKey":"mypartitionkey",
489 "RowKey":"myrowkey",
490 "Timestamp":"2017-01-27T01:01:44.151805Z",
491 "Timestamp@odata.type":"Edm.DateTime",
492 "Address": "Mountain View",
493 "Age": 23,
494 "AmountDue":"200.23",
495 "AmountDue@odata.type":"Edm.Double",
496 "Binary@odata.type": "Edm.Binary",
497 "Binary": "YWJjZA==",
498 "CustomerCode@odata.type":"Edm.Guid",
499 "CustomerCode":"c9da6455-213d-42c9-9a79-3e9149a57833",
500 "CustomerSince@odata.type":"Edm.DateTime",
501 "CustomerSince":"1992-12-20T21:55:00Z",
502 "IsActive":true,
503 "NumberOfOrders@odata.type":"Edm.Int64",
504 "NumberOfOrders":"255"}`
505
506 var entity Entity
507 data := []byte(input)
508 err := json.Unmarshal(data, &entity)
509 c.Assert(err, chk.IsNil)
510
511 expectedProperties := map[string]interface{}{
512 "Address": "Mountain View",
513 "Age": 23,
514 "AmountDue": float64(200.23),
515 "Binary": []byte("abcd"),
516 "CustomerCode": uuid.FromStringOrNil("c9da6455-213d-42c9-9a79-3e9149a57833"),
517 "CustomerSince": time.Date(1992, 12, 20, 21, 55, 0, 0, time.UTC),
518 "IsActive": true,
519 "NumberOfOrders": int64(255),
520 }
521
522 c.Assert(entity.OdataMetadata, chk.Equals, "https://azuregosdkstoragetests.table.core.windows.net/$metadata#SampleTable/@Element")
523 c.Assert(entity.OdataType, chk.Equals, "azuregosdkstoragetests.SampleTable")
524 c.Assert(entity.OdataID, chk.Equals, "https://azuregosdkstoragetests.table.core.windows.net/SampleTable(PartitionKey=''mypartitionkey'',RowKey=''myrowkey'')")
525 c.Assert(entity.OdataEtag, chk.Equals, "W/\"datetime''2017-01-27T01%3A01%3A44.151805Z''\"")
526 c.Assert(entity.OdataEditLink, chk.Equals, "SampleTable(PartitionKey=''mypartitionkey'',RowKey=''myrowkey'')")
527 c.Assert(entity.PartitionKey, chk.Equals, "mypartitionkey")
528 c.Assert(entity.RowKey, chk.Equals, "myrowkey")
529 c.Assert(entity.TimeStamp, chk.Equals, time.Date(2017, 1, 27, 1, 1, 44, 151805000, time.UTC))
530
531 c.Assert(entity.Properties, chk.HasLen, len(expectedProperties))
532 c.Assert(entity.Properties["Address"], chk.Equals, expectedProperties["Address"])
533
534 c.Assert(entity.Properties["Age"], chk.Equals, float64(expectedProperties["Age"].(int)))
535 c.Assert(entity.Properties["AmountDue"], chk.Equals, expectedProperties["AmountDue"])
536 c.Assert(entity.Properties["Binary"], chk.DeepEquals, expectedProperties["Binary"])
537 c.Assert(entity.Properties["CustomerSince"], chk.Equals, expectedProperties["CustomerSince"])
538 c.Assert(entity.Properties["IsActive"], chk.Equals, expectedProperties["IsActive"])
539 c.Assert(entity.Properties["NumberOfOrders"], chk.Equals, expectedProperties["NumberOfOrders"])
540
541 }
542
543 func compareEntities(got, expected *Entity, c *chk.C) {
544 c.Assert(got.PartitionKey, chk.Equals, expected.PartitionKey)
545 c.Assert(got.RowKey, chk.Equals, expected.RowKey)
546 c.Assert(got.TimeStamp, chk.Equals, expected.TimeStamp)
547
548 c.Assert(got.OdataEtag, chk.Equals, expected.OdataEtag)
549 c.Assert(got.OdataType, chk.Equals, expected.OdataType)
550 c.Assert(got.OdataID, chk.Equals, expected.OdataID)
551 c.Assert(got.OdataEditLink, chk.Equals, expected.OdataEditLink)
552
553 c.Assert(got.Properties, chk.DeepEquals, expected.Properties)
554 }
555
View as plain text