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.
 
 
 

447 lines
11 KiB

  1. package dynamodb_test
  2. import (
  3. "github.com/goamz/goamz/dynamodb"
  4. . "gopkg.in/check.v1"
  5. )
  6. type ItemSuite struct {
  7. TableDescriptionT dynamodb.TableDescriptionT
  8. DynamoDBTest
  9. WithRange bool
  10. }
  11. func (s *ItemSuite) SetUpSuite(c *C) {
  12. setUpAuth(c)
  13. s.DynamoDBTest.TableDescriptionT = s.TableDescriptionT
  14. s.server = &dynamodb.Server{dynamodb_auth, dynamodb_region}
  15. pk, err := s.TableDescriptionT.BuildPrimaryKey()
  16. if err != nil {
  17. c.Skip(err.Error())
  18. }
  19. s.table = s.server.NewTable(s.TableDescriptionT.TableName, pk)
  20. // Cleanup
  21. s.TearDownSuite(c)
  22. _, err = s.server.CreateTable(s.TableDescriptionT)
  23. if err != nil {
  24. c.Fatal(err)
  25. }
  26. s.WaitUntilStatus(c, "ACTIVE")
  27. }
  28. var item_suite = &ItemSuite{
  29. TableDescriptionT: dynamodb.TableDescriptionT{
  30. TableName: "DynamoDBTestMyTable",
  31. AttributeDefinitions: []dynamodb.AttributeDefinitionT{
  32. dynamodb.AttributeDefinitionT{"TestHashKey", "S"},
  33. dynamodb.AttributeDefinitionT{"TestRangeKey", "N"},
  34. },
  35. KeySchema: []dynamodb.KeySchemaT{
  36. dynamodb.KeySchemaT{"TestHashKey", "HASH"},
  37. dynamodb.KeySchemaT{"TestRangeKey", "RANGE"},
  38. },
  39. ProvisionedThroughput: dynamodb.ProvisionedThroughputT{
  40. ReadCapacityUnits: 1,
  41. WriteCapacityUnits: 1,
  42. },
  43. },
  44. WithRange: true,
  45. }
  46. var item_without_range_suite = &ItemSuite{
  47. TableDescriptionT: dynamodb.TableDescriptionT{
  48. TableName: "DynamoDBTestMyTable",
  49. AttributeDefinitions: []dynamodb.AttributeDefinitionT{
  50. dynamodb.AttributeDefinitionT{"TestHashKey", "S"},
  51. },
  52. KeySchema: []dynamodb.KeySchemaT{
  53. dynamodb.KeySchemaT{"TestHashKey", "HASH"},
  54. },
  55. ProvisionedThroughput: dynamodb.ProvisionedThroughputT{
  56. ReadCapacityUnits: 1,
  57. WriteCapacityUnits: 1,
  58. },
  59. },
  60. WithRange: false,
  61. }
  62. var _ = Suite(item_suite)
  63. var _ = Suite(item_without_range_suite)
  64. func (s *ItemSuite) TestConditionalPutUpdateDeleteItem(c *C) {
  65. if s.WithRange {
  66. // No rangekey test required
  67. return
  68. }
  69. attrs := []dynamodb.Attribute{
  70. *dynamodb.NewStringAttribute("Attr1", "Attr1Val"),
  71. }
  72. pk := &dynamodb.Key{HashKey: "NewHashKeyVal"}
  73. // Put
  74. if ok, err := s.table.PutItem("NewHashKeyVal", "", attrs); !ok {
  75. c.Fatal(err)
  76. }
  77. {
  78. // Put with condition failed
  79. expected := []dynamodb.Attribute{
  80. *dynamodb.NewStringAttribute("Attr1", "expectedAttr1Val").SetExists(true),
  81. *dynamodb.NewStringAttribute("AttrNotExists", "").SetExists(false),
  82. }
  83. if ok, err := s.table.ConditionalPutItem("NewHashKeyVal", "", attrs, expected); ok {
  84. c.Errorf("Expect condition does not meet.")
  85. } else {
  86. c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
  87. }
  88. // Add attributes with condition failed
  89. if ok, err := s.table.ConditionalAddAttributes(pk, attrs, expected); ok {
  90. c.Errorf("Expect condition does not meet.")
  91. } else {
  92. c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
  93. }
  94. // Update attributes with condition failed
  95. if ok, err := s.table.ConditionalUpdateAttributes(pk, attrs, expected); ok {
  96. c.Errorf("Expect condition does not meet.")
  97. } else {
  98. c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
  99. }
  100. // Delete attributes with condition failed
  101. if ok, err := s.table.ConditionalDeleteAttributes(pk, attrs, expected); ok {
  102. c.Errorf("Expect condition does not meet.")
  103. } else {
  104. c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
  105. }
  106. }
  107. {
  108. expected := []dynamodb.Attribute{
  109. *dynamodb.NewStringAttribute("Attr1", "Attr1Val").SetExists(true),
  110. }
  111. // Add attributes with condition met
  112. addNewAttrs := []dynamodb.Attribute{
  113. *dynamodb.NewNumericAttribute("AddNewAttr1", "10"),
  114. *dynamodb.NewNumericAttribute("AddNewAttr2", "20"),
  115. }
  116. if ok, err := s.table.ConditionalAddAttributes(pk, addNewAttrs, nil); !ok {
  117. c.Errorf("Expect condition met. %s", err)
  118. }
  119. // Update attributes with condition met
  120. updateAttrs := []dynamodb.Attribute{
  121. *dynamodb.NewNumericAttribute("AddNewAttr1", "100"),
  122. }
  123. if ok, err := s.table.ConditionalUpdateAttributes(pk, updateAttrs, expected); !ok {
  124. c.Errorf("Expect condition met. %s", err)
  125. }
  126. // Delete attributes with condition met
  127. deleteAttrs := []dynamodb.Attribute{
  128. *dynamodb.NewNumericAttribute("AddNewAttr2", ""),
  129. }
  130. if ok, err := s.table.ConditionalDeleteAttributes(pk, deleteAttrs, expected); !ok {
  131. c.Errorf("Expect condition met. %s", err)
  132. }
  133. // Get to verify operations that condition are met
  134. item, err := s.table.GetItem(pk)
  135. if err != nil {
  136. c.Fatal(err)
  137. }
  138. if val, ok := item["AddNewAttr1"]; ok {
  139. c.Check(val, DeepEquals, dynamodb.NewNumericAttribute("AddNewAttr1", "100"))
  140. } else {
  141. c.Error("Expect AddNewAttr1 attribute to be added and updated")
  142. }
  143. if _, ok := item["AddNewAttr2"]; ok {
  144. c.Error("Expect AddNewAttr2 attribute to be deleted")
  145. }
  146. }
  147. {
  148. // Put with condition met
  149. expected := []dynamodb.Attribute{
  150. *dynamodb.NewStringAttribute("Attr1", "Attr1Val").SetExists(true),
  151. }
  152. newattrs := []dynamodb.Attribute{
  153. *dynamodb.NewStringAttribute("Attr1", "Attr2Val"),
  154. }
  155. if ok, err := s.table.ConditionalPutItem("NewHashKeyVal", "", newattrs, expected); !ok {
  156. c.Errorf("Expect condition met. %s", err)
  157. }
  158. // Get to verify Put operation that condition are met
  159. item, err := s.table.GetItem(pk)
  160. if err != nil {
  161. c.Fatal(err)
  162. }
  163. if val, ok := item["Attr1"]; ok {
  164. c.Check(val, DeepEquals, dynamodb.NewStringAttribute("Attr1", "Attr2Val"))
  165. } else {
  166. c.Error("Expect Attr1 attribute to be updated")
  167. }
  168. }
  169. {
  170. // Delete with condition failed
  171. expected := []dynamodb.Attribute{
  172. *dynamodb.NewStringAttribute("Attr1", "expectedAttr1Val").SetExists(true),
  173. }
  174. if ok, err := s.table.ConditionalDeleteItem(pk, expected); ok {
  175. c.Errorf("Expect condition does not meet.")
  176. } else {
  177. c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
  178. }
  179. }
  180. {
  181. // Delete with condition met
  182. expected := []dynamodb.Attribute{
  183. *dynamodb.NewStringAttribute("Attr1", "Attr2Val").SetExists(true),
  184. }
  185. if ok, _ := s.table.ConditionalDeleteItem(pk, expected); !ok {
  186. c.Errorf("Expect condition met.")
  187. }
  188. // Get to verify Delete operation
  189. _, err := s.table.GetItem(pk)
  190. c.Check(err.Error(), Matches, "Item not found")
  191. }
  192. }
  193. func (s *ItemSuite) TestPutGetDeleteItem(c *C) {
  194. attrs := []dynamodb.Attribute{
  195. *dynamodb.NewStringAttribute("Attr1", "Attr1Val"),
  196. }
  197. var rk string
  198. if s.WithRange {
  199. rk = "1"
  200. }
  201. // Put
  202. if ok, err := s.table.PutItem("NewHashKeyVal", rk, attrs); !ok {
  203. c.Fatal(err)
  204. }
  205. // Get to verify Put operation
  206. pk := &dynamodb.Key{HashKey: "NewHashKeyVal", RangeKey: rk}
  207. item, err := s.table.GetItem(pk)
  208. if err != nil {
  209. c.Fatal(err)
  210. }
  211. if val, ok := item["TestHashKey"]; ok {
  212. c.Check(val, DeepEquals, dynamodb.NewStringAttribute("TestHashKey", "NewHashKeyVal"))
  213. } else {
  214. c.Error("Expect TestHashKey to be found")
  215. }
  216. if s.WithRange {
  217. if val, ok := item["TestRangeKey"]; ok {
  218. c.Check(val, DeepEquals, dynamodb.NewNumericAttribute("TestRangeKey", "1"))
  219. } else {
  220. c.Error("Expect TestRangeKey to be found")
  221. }
  222. }
  223. // Delete
  224. if ok, _ := s.table.DeleteItem(pk); !ok {
  225. c.Fatal(err)
  226. }
  227. // Get to verify Delete operation
  228. _, err = s.table.GetItem(pk)
  229. c.Check(err.Error(), Matches, "Item not found")
  230. }
  231. func (s *ItemSuite) TestUpdateItem(c *C) {
  232. attrs := []dynamodb.Attribute{
  233. *dynamodb.NewNumericAttribute("count", "0"),
  234. }
  235. var rk string
  236. if s.WithRange {
  237. rk = "1"
  238. }
  239. if ok, err := s.table.PutItem("NewHashKeyVal", rk, attrs); !ok {
  240. c.Fatal(err)
  241. }
  242. // UpdateItem with Add
  243. attrs = []dynamodb.Attribute{
  244. *dynamodb.NewNumericAttribute("count", "10"),
  245. }
  246. pk := &dynamodb.Key{HashKey: "NewHashKeyVal", RangeKey: rk}
  247. if ok, err := s.table.AddAttributes(pk, attrs); !ok {
  248. c.Error(err)
  249. }
  250. // Get to verify Add operation
  251. if item, err := s.table.GetItemConsistent(pk, true); err != nil {
  252. c.Error(err)
  253. } else {
  254. if val, ok := item["count"]; ok {
  255. c.Check(val, DeepEquals, dynamodb.NewNumericAttribute("count", "10"))
  256. } else {
  257. c.Error("Expect count to be found")
  258. }
  259. }
  260. // UpdateItem with Put
  261. attrs = []dynamodb.Attribute{
  262. *dynamodb.NewNumericAttribute("count", "100"),
  263. }
  264. if ok, err := s.table.UpdateAttributes(pk, attrs); !ok {
  265. c.Error(err)
  266. }
  267. // Get to verify Put operation
  268. if item, err := s.table.GetItem(pk); err != nil {
  269. c.Fatal(err)
  270. } else {
  271. if val, ok := item["count"]; ok {
  272. c.Check(val, DeepEquals, dynamodb.NewNumericAttribute("count", "100"))
  273. } else {
  274. c.Error("Expect count to be found")
  275. }
  276. }
  277. // UpdateItem with Delete
  278. attrs = []dynamodb.Attribute{
  279. *dynamodb.NewNumericAttribute("count", ""),
  280. }
  281. if ok, err := s.table.DeleteAttributes(pk, attrs); !ok {
  282. c.Error(err)
  283. }
  284. // Get to verify Delete operation
  285. if item, err := s.table.GetItem(pk); err != nil {
  286. c.Error(err)
  287. } else {
  288. if _, ok := item["count"]; ok {
  289. c.Error("Expect count not to be found")
  290. }
  291. }
  292. }
  293. func (s *ItemSuite) TestUpdateItemWithSet(c *C) {
  294. attrs := []dynamodb.Attribute{
  295. *dynamodb.NewStringSetAttribute("list", []string{"A", "B"}),
  296. }
  297. var rk string
  298. if s.WithRange {
  299. rk = "1"
  300. }
  301. if ok, err := s.table.PutItem("NewHashKeyVal", rk, attrs); !ok {
  302. c.Error(err)
  303. }
  304. // UpdateItem with Add
  305. attrs = []dynamodb.Attribute{
  306. *dynamodb.NewStringSetAttribute("list", []string{"C"}),
  307. }
  308. pk := &dynamodb.Key{HashKey: "NewHashKeyVal", RangeKey: rk}
  309. if ok, err := s.table.AddAttributes(pk, attrs); !ok {
  310. c.Error(err)
  311. }
  312. // Get to verify Add operation
  313. if item, err := s.table.GetItem(pk); err != nil {
  314. c.Error(err)
  315. } else {
  316. if val, ok := item["list"]; ok {
  317. c.Check(val, DeepEquals, dynamodb.NewStringSetAttribute("list", []string{"A", "B", "C"}))
  318. } else {
  319. c.Error("Expect count to be found")
  320. }
  321. }
  322. // UpdateItem with Delete
  323. attrs = []dynamodb.Attribute{
  324. *dynamodb.NewStringSetAttribute("list", []string{"A"}),
  325. }
  326. if ok, err := s.table.DeleteAttributes(pk, attrs); !ok {
  327. c.Error(err)
  328. }
  329. // Get to verify Delete operation
  330. if item, err := s.table.GetItem(pk); err != nil {
  331. c.Error(err)
  332. } else {
  333. if val, ok := item["list"]; ok {
  334. c.Check(val, DeepEquals, dynamodb.NewStringSetAttribute("list", []string{"B", "C"}))
  335. } else {
  336. c.Error("Expect list to be remained")
  337. }
  338. }
  339. }
  340. func (s *ItemSuite) TestUpdateItem_new(c *C) {
  341. attrs := []dynamodb.Attribute{
  342. *dynamodb.NewStringAttribute("intval", "1"),
  343. }
  344. var rk string
  345. if s.WithRange {
  346. rk = "1"
  347. }
  348. pk := &dynamodb.Key{HashKey: "UpdateKeyVal", RangeKey: rk}
  349. num := func(a, b string) dynamodb.Attribute {
  350. return *dynamodb.NewNumericAttribute(a, b)
  351. }
  352. checkVal := func(i string) {
  353. if item, err := s.table.GetItem(pk); err != nil {
  354. c.Error(err)
  355. } else {
  356. c.Check(item["intval"], DeepEquals, dynamodb.NewNumericAttribute("intval", i))
  357. }
  358. }
  359. if ok, err := s.table.PutItem("UpdateKeyVal", rk, attrs); !ok {
  360. c.Error(err)
  361. }
  362. checkVal("1")
  363. // Simple Increment
  364. s.table.UpdateItem(pk).UpdateExpression("SET intval = intval + :incr", num(":incr", "5")).Execute()
  365. checkVal("6")
  366. conditionalUpdate := func(check string) {
  367. s.table.UpdateItem(pk).
  368. ConditionExpression("intval = :check").
  369. UpdateExpression("SET intval = intval + :incr").
  370. ExpressionAttributes(num(":check", check), num(":incr", "4")).
  371. Execute()
  372. }
  373. // Conditional increment should be a no-op.
  374. conditionalUpdate("42")
  375. checkVal("6")
  376. // conditional increment should succeed this time
  377. conditionalUpdate("6")
  378. checkVal("10")
  379. // Update with new values getting values
  380. result, err := s.table.UpdateItem(pk).
  381. ReturnValues(dynamodb.UPDATED_NEW).
  382. UpdateExpression("SET intval = intval + :incr", num(":incr", "2")).
  383. Execute()
  384. c.Check(err, IsNil)
  385. c.Check(result.Attributes["intval"], DeepEquals, num("intval", "12"))
  386. checkVal("12")
  387. }