PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/y/google-cloud-sdk/platform/gsutil/third_party/boto/tests/unit/dynamodb2/test_table.py

https://bitbucket.org/kartik894/assignment6
Python | 3068 lines | 2821 code | 171 blank | 76 comment | 42 complexity | dd4ffca3cd58e4f194f6e82094e89047 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. from tests.compat import mock, unittest
  2. from boto.dynamodb2 import exceptions
  3. from boto.dynamodb2.fields import (HashKey, RangeKey,
  4. AllIndex, KeysOnlyIndex, IncludeIndex,
  5. GlobalAllIndex, GlobalKeysOnlyIndex,
  6. GlobalIncludeIndex)
  7. from boto.dynamodb2.items import Item
  8. from boto.dynamodb2.layer1 import DynamoDBConnection
  9. from boto.dynamodb2.results import ResultSet, BatchGetResultSet
  10. from boto.dynamodb2.table import Table
  11. from boto.dynamodb2.types import (STRING, NUMBER, BINARY,
  12. FILTER_OPERATORS, QUERY_OPERATORS)
  13. from boto.exception import JSONResponseError
  14. from boto.compat import six, long_type
  15. FakeDynamoDBConnection = mock.create_autospec(DynamoDBConnection)
  16. class SchemaFieldsTestCase(unittest.TestCase):
  17. def test_hash_key(self):
  18. hash_key = HashKey('hello')
  19. self.assertEqual(hash_key.name, 'hello')
  20. self.assertEqual(hash_key.data_type, STRING)
  21. self.assertEqual(hash_key.attr_type, 'HASH')
  22. self.assertEqual(hash_key.definition(), {
  23. 'AttributeName': 'hello',
  24. 'AttributeType': 'S'
  25. })
  26. self.assertEqual(hash_key.schema(), {
  27. 'AttributeName': 'hello',
  28. 'KeyType': 'HASH'
  29. })
  30. def test_range_key(self):
  31. range_key = RangeKey('hello')
  32. self.assertEqual(range_key.name, 'hello')
  33. self.assertEqual(range_key.data_type, STRING)
  34. self.assertEqual(range_key.attr_type, 'RANGE')
  35. self.assertEqual(range_key.definition(), {
  36. 'AttributeName': 'hello',
  37. 'AttributeType': 'S'
  38. })
  39. self.assertEqual(range_key.schema(), {
  40. 'AttributeName': 'hello',
  41. 'KeyType': 'RANGE'
  42. })
  43. def test_alternate_type(self):
  44. alt_key = HashKey('alt', data_type=NUMBER)
  45. self.assertEqual(alt_key.name, 'alt')
  46. self.assertEqual(alt_key.data_type, NUMBER)
  47. self.assertEqual(alt_key.attr_type, 'HASH')
  48. self.assertEqual(alt_key.definition(), {
  49. 'AttributeName': 'alt',
  50. 'AttributeType': 'N'
  51. })
  52. self.assertEqual(alt_key.schema(), {
  53. 'AttributeName': 'alt',
  54. 'KeyType': 'HASH'
  55. })
  56. class IndexFieldTestCase(unittest.TestCase):
  57. def test_all_index(self):
  58. all_index = AllIndex('AllKeys', parts=[
  59. HashKey('username'),
  60. RangeKey('date_joined')
  61. ])
  62. self.assertEqual(all_index.name, 'AllKeys')
  63. self.assertEqual([part.attr_type for part in all_index.parts], [
  64. 'HASH',
  65. 'RANGE'
  66. ])
  67. self.assertEqual(all_index.projection_type, 'ALL')
  68. self.assertEqual(all_index.definition(), [
  69. {'AttributeName': 'username', 'AttributeType': 'S'},
  70. {'AttributeName': 'date_joined', 'AttributeType': 'S'}
  71. ])
  72. self.assertEqual(all_index.schema(), {
  73. 'IndexName': 'AllKeys',
  74. 'KeySchema': [
  75. {
  76. 'AttributeName': 'username',
  77. 'KeyType': 'HASH'
  78. },
  79. {
  80. 'AttributeName': 'date_joined',
  81. 'KeyType': 'RANGE'
  82. }
  83. ],
  84. 'Projection': {
  85. 'ProjectionType': 'ALL'
  86. }
  87. })
  88. def test_keys_only_index(self):
  89. keys_only = KeysOnlyIndex('KeysOnly', parts=[
  90. HashKey('username'),
  91. RangeKey('date_joined')
  92. ])
  93. self.assertEqual(keys_only.name, 'KeysOnly')
  94. self.assertEqual([part.attr_type for part in keys_only.parts], [
  95. 'HASH',
  96. 'RANGE'
  97. ])
  98. self.assertEqual(keys_only.projection_type, 'KEYS_ONLY')
  99. self.assertEqual(keys_only.definition(), [
  100. {'AttributeName': 'username', 'AttributeType': 'S'},
  101. {'AttributeName': 'date_joined', 'AttributeType': 'S'}
  102. ])
  103. self.assertEqual(keys_only.schema(), {
  104. 'IndexName': 'KeysOnly',
  105. 'KeySchema': [
  106. {
  107. 'AttributeName': 'username',
  108. 'KeyType': 'HASH'
  109. },
  110. {
  111. 'AttributeName': 'date_joined',
  112. 'KeyType': 'RANGE'
  113. }
  114. ],
  115. 'Projection': {
  116. 'ProjectionType': 'KEYS_ONLY'
  117. }
  118. })
  119. def test_include_index(self):
  120. include_index = IncludeIndex('IncludeKeys', parts=[
  121. HashKey('username'),
  122. RangeKey('date_joined')
  123. ], includes=[
  124. 'gender',
  125. 'friend_count'
  126. ])
  127. self.assertEqual(include_index.name, 'IncludeKeys')
  128. self.assertEqual([part.attr_type for part in include_index.parts], [
  129. 'HASH',
  130. 'RANGE'
  131. ])
  132. self.assertEqual(include_index.projection_type, 'INCLUDE')
  133. self.assertEqual(include_index.definition(), [
  134. {'AttributeName': 'username', 'AttributeType': 'S'},
  135. {'AttributeName': 'date_joined', 'AttributeType': 'S'}
  136. ])
  137. self.assertEqual(include_index.schema(), {
  138. 'IndexName': 'IncludeKeys',
  139. 'KeySchema': [
  140. {
  141. 'AttributeName': 'username',
  142. 'KeyType': 'HASH'
  143. },
  144. {
  145. 'AttributeName': 'date_joined',
  146. 'KeyType': 'RANGE'
  147. }
  148. ],
  149. 'Projection': {
  150. 'ProjectionType': 'INCLUDE',
  151. 'NonKeyAttributes': [
  152. 'gender',
  153. 'friend_count',
  154. ]
  155. }
  156. })
  157. def test_global_all_index(self):
  158. all_index = GlobalAllIndex('AllKeys', parts=[
  159. HashKey('username'),
  160. RangeKey('date_joined')
  161. ],
  162. throughput={
  163. 'read': 6,
  164. 'write': 2,
  165. })
  166. self.assertEqual(all_index.name, 'AllKeys')
  167. self.assertEqual([part.attr_type for part in all_index.parts], [
  168. 'HASH',
  169. 'RANGE'
  170. ])
  171. self.assertEqual(all_index.projection_type, 'ALL')
  172. self.assertEqual(all_index.definition(), [
  173. {'AttributeName': 'username', 'AttributeType': 'S'},
  174. {'AttributeName': 'date_joined', 'AttributeType': 'S'}
  175. ])
  176. self.assertEqual(all_index.schema(), {
  177. 'IndexName': 'AllKeys',
  178. 'KeySchema': [
  179. {
  180. 'AttributeName': 'username',
  181. 'KeyType': 'HASH'
  182. },
  183. {
  184. 'AttributeName': 'date_joined',
  185. 'KeyType': 'RANGE'
  186. }
  187. ],
  188. 'Projection': {
  189. 'ProjectionType': 'ALL'
  190. },
  191. 'ProvisionedThroughput': {
  192. 'ReadCapacityUnits': 6,
  193. 'WriteCapacityUnits': 2
  194. }
  195. })
  196. def test_global_keys_only_index(self):
  197. keys_only = GlobalKeysOnlyIndex('KeysOnly', parts=[
  198. HashKey('username'),
  199. RangeKey('date_joined')
  200. ],
  201. throughput={
  202. 'read': 3,
  203. 'write': 4,
  204. })
  205. self.assertEqual(keys_only.name, 'KeysOnly')
  206. self.assertEqual([part.attr_type for part in keys_only.parts], [
  207. 'HASH',
  208. 'RANGE'
  209. ])
  210. self.assertEqual(keys_only.projection_type, 'KEYS_ONLY')
  211. self.assertEqual(keys_only.definition(), [
  212. {'AttributeName': 'username', 'AttributeType': 'S'},
  213. {'AttributeName': 'date_joined', 'AttributeType': 'S'}
  214. ])
  215. self.assertEqual(keys_only.schema(), {
  216. 'IndexName': 'KeysOnly',
  217. 'KeySchema': [
  218. {
  219. 'AttributeName': 'username',
  220. 'KeyType': 'HASH'
  221. },
  222. {
  223. 'AttributeName': 'date_joined',
  224. 'KeyType': 'RANGE'
  225. }
  226. ],
  227. 'Projection': {
  228. 'ProjectionType': 'KEYS_ONLY'
  229. },
  230. 'ProvisionedThroughput': {
  231. 'ReadCapacityUnits': 3,
  232. 'WriteCapacityUnits': 4
  233. }
  234. })
  235. def test_global_include_index(self):
  236. # Lean on the default throughput
  237. include_index = GlobalIncludeIndex('IncludeKeys', parts=[
  238. HashKey('username'),
  239. RangeKey('date_joined')
  240. ], includes=[
  241. 'gender',
  242. 'friend_count'
  243. ])
  244. self.assertEqual(include_index.name, 'IncludeKeys')
  245. self.assertEqual([part.attr_type for part in include_index.parts], [
  246. 'HASH',
  247. 'RANGE'
  248. ])
  249. self.assertEqual(include_index.projection_type, 'INCLUDE')
  250. self.assertEqual(include_index.definition(), [
  251. {'AttributeName': 'username', 'AttributeType': 'S'},
  252. {'AttributeName': 'date_joined', 'AttributeType': 'S'}
  253. ])
  254. self.assertEqual(include_index.schema(), {
  255. 'IndexName': 'IncludeKeys',
  256. 'KeySchema': [
  257. {
  258. 'AttributeName': 'username',
  259. 'KeyType': 'HASH'
  260. },
  261. {
  262. 'AttributeName': 'date_joined',
  263. 'KeyType': 'RANGE'
  264. }
  265. ],
  266. 'Projection': {
  267. 'ProjectionType': 'INCLUDE',
  268. 'NonKeyAttributes': [
  269. 'gender',
  270. 'friend_count',
  271. ]
  272. },
  273. 'ProvisionedThroughput': {
  274. 'ReadCapacityUnits': 5,
  275. 'WriteCapacityUnits': 5
  276. }
  277. })
  278. def test_global_include_index_throughput(self):
  279. include_index = GlobalIncludeIndex('IncludeKeys', parts=[
  280. HashKey('username'),
  281. RangeKey('date_joined')
  282. ], includes=[
  283. 'gender',
  284. 'friend_count'
  285. ], throughput={
  286. 'read': 10,
  287. 'write': 8
  288. })
  289. self.assertEqual(include_index.schema(), {
  290. 'IndexName': 'IncludeKeys',
  291. 'KeySchema': [
  292. {
  293. 'AttributeName': 'username',
  294. 'KeyType': 'HASH'
  295. },
  296. {
  297. 'AttributeName': 'date_joined',
  298. 'KeyType': 'RANGE'
  299. }
  300. ],
  301. 'Projection': {
  302. 'ProjectionType': 'INCLUDE',
  303. 'NonKeyAttributes': [
  304. 'gender',
  305. 'friend_count',
  306. ]
  307. },
  308. 'ProvisionedThroughput': {
  309. 'ReadCapacityUnits': 10,
  310. 'WriteCapacityUnits': 8
  311. }
  312. })
  313. class ItemTestCase(unittest.TestCase):
  314. if six.PY2:
  315. assertCountEqual = unittest.TestCase.assertItemsEqual
  316. def setUp(self):
  317. super(ItemTestCase, self).setUp()
  318. self.table = Table('whatever', connection=FakeDynamoDBConnection())
  319. self.johndoe = self.create_item({
  320. 'username': 'johndoe',
  321. 'first_name': 'John',
  322. 'date_joined': 12345,
  323. })
  324. def create_item(self, data):
  325. return Item(self.table, data=data)
  326. def test_initialization(self):
  327. empty_item = Item(self.table)
  328. self.assertEqual(empty_item.table, self.table)
  329. self.assertEqual(empty_item._data, {})
  330. full_item = Item(self.table, data={
  331. 'username': 'johndoe',
  332. 'date_joined': 12345,
  333. })
  334. self.assertEqual(full_item.table, self.table)
  335. self.assertEqual(full_item._data, {
  336. 'username': 'johndoe',
  337. 'date_joined': 12345,
  338. })
  339. # The next couple methods make use of ``sorted(...)`` so we get consistent
  340. # ordering everywhere & no erroneous failures.
  341. def test_keys(self):
  342. self.assertCountEqual(self.johndoe.keys(), [
  343. 'date_joined',
  344. 'first_name',
  345. 'username',
  346. ])
  347. def test_values(self):
  348. self.assertCountEqual(self.johndoe.values(),
  349. [12345, 'John', 'johndoe'])
  350. def test_contains(self):
  351. self.assertIn('username', self.johndoe)
  352. self.assertIn('first_name', self.johndoe)
  353. self.assertIn('date_joined', self.johndoe)
  354. self.assertNotIn('whatever', self.johndoe)
  355. def test_iter(self):
  356. self.assertCountEqual(self.johndoe,
  357. ['johndoe', 'John', 12345])
  358. def test_get(self):
  359. self.assertEqual(self.johndoe.get('username'), 'johndoe')
  360. self.assertEqual(self.johndoe.get('first_name'), 'John')
  361. self.assertEqual(self.johndoe.get('date_joined'), 12345)
  362. # Test a missing key. No default yields ``None``.
  363. self.assertEqual(self.johndoe.get('last_name'), None)
  364. # This time with a default.
  365. self.assertEqual(self.johndoe.get('last_name', True), True)
  366. def test_items(self):
  367. self.assertCountEqual(
  368. self.johndoe.items(),
  369. [
  370. ('date_joined', 12345),
  371. ('first_name', 'John'),
  372. ('username', 'johndoe'),
  373. ])
  374. def test_attribute_access(self):
  375. self.assertEqual(self.johndoe['username'], 'johndoe')
  376. self.assertEqual(self.johndoe['first_name'], 'John')
  377. self.assertEqual(self.johndoe['date_joined'], 12345)
  378. # Test a missing key.
  379. self.assertEqual(self.johndoe['last_name'], None)
  380. # Set a key.
  381. self.johndoe['last_name'] = 'Doe'
  382. # Test accessing the new key.
  383. self.assertEqual(self.johndoe['last_name'], 'Doe')
  384. # Delete a key.
  385. del self.johndoe['last_name']
  386. # Test the now-missing-again key.
  387. self.assertEqual(self.johndoe['last_name'], None)
  388. def test_needs_save(self):
  389. self.johndoe.mark_clean()
  390. self.assertFalse(self.johndoe.needs_save())
  391. self.johndoe['last_name'] = 'Doe'
  392. self.assertTrue(self.johndoe.needs_save())
  393. def test_needs_save_set_changed(self):
  394. # First, ensure we're clean.
  395. self.johndoe.mark_clean()
  396. self.assertFalse(self.johndoe.needs_save())
  397. # Add a friends collection.
  398. self.johndoe['friends'] = set(['jane', 'alice'])
  399. self.assertTrue(self.johndoe.needs_save())
  400. # Now mark it clean, then change the collection.
  401. # This does NOT call ``__setitem__``, so the item used to be
  402. # incorrectly appearing to be clean, when it had in fact been changed.
  403. self.johndoe.mark_clean()
  404. self.assertFalse(self.johndoe.needs_save())
  405. self.johndoe['friends'].add('bob')
  406. self.assertTrue(self.johndoe.needs_save())
  407. def test_mark_clean(self):
  408. self.johndoe['last_name'] = 'Doe'
  409. self.assertTrue(self.johndoe.needs_save())
  410. self.johndoe.mark_clean()
  411. self.assertFalse(self.johndoe.needs_save())
  412. def test_load(self):
  413. empty_item = Item(self.table)
  414. empty_item.load({
  415. 'Item': {
  416. 'username': {'S': 'johndoe'},
  417. 'first_name': {'S': 'John'},
  418. 'last_name': {'S': 'Doe'},
  419. 'date_joined': {'N': '1366056668'},
  420. 'friend_count': {'N': '3'},
  421. 'friends': {'SS': ['alice', 'bob', 'jane']},
  422. }
  423. })
  424. self.assertEqual(empty_item['username'], 'johndoe')
  425. self.assertEqual(empty_item['date_joined'], 1366056668)
  426. self.assertEqual(sorted(empty_item['friends']), sorted([
  427. 'alice',
  428. 'bob',
  429. 'jane'
  430. ]))
  431. def test_get_keys(self):
  432. # Setup the data.
  433. self.table.schema = [
  434. HashKey('username'),
  435. RangeKey('date_joined'),
  436. ]
  437. self.assertEqual(self.johndoe.get_keys(), {
  438. 'username': 'johndoe',
  439. 'date_joined': 12345,
  440. })
  441. def test_get_raw_keys(self):
  442. # Setup the data.
  443. self.table.schema = [
  444. HashKey('username'),
  445. RangeKey('date_joined'),
  446. ]
  447. self.assertEqual(self.johndoe.get_raw_keys(), {
  448. 'username': {'S': 'johndoe'},
  449. 'date_joined': {'N': '12345'},
  450. })
  451. def test_build_expects(self):
  452. # Pristine.
  453. self.assertEqual(self.johndoe.build_expects(), {
  454. 'first_name': {
  455. 'Exists': False,
  456. },
  457. 'username': {
  458. 'Exists': False,
  459. },
  460. 'date_joined': {
  461. 'Exists': False,
  462. },
  463. })
  464. # Without modifications.
  465. self.johndoe.mark_clean()
  466. self.assertEqual(self.johndoe.build_expects(), {
  467. 'first_name': {
  468. 'Exists': True,
  469. 'Value': {
  470. 'S': 'John',
  471. },
  472. },
  473. 'username': {
  474. 'Exists': True,
  475. 'Value': {
  476. 'S': 'johndoe',
  477. },
  478. },
  479. 'date_joined': {
  480. 'Exists': True,
  481. 'Value': {
  482. 'N': '12345',
  483. },
  484. },
  485. })
  486. # Change some data.
  487. self.johndoe['first_name'] = 'Johann'
  488. # Add some data.
  489. self.johndoe['last_name'] = 'Doe'
  490. # Delete some data.
  491. del self.johndoe['date_joined']
  492. # All fields (default).
  493. self.assertEqual(self.johndoe.build_expects(), {
  494. 'first_name': {
  495. 'Exists': True,
  496. 'Value': {
  497. 'S': 'John',
  498. },
  499. },
  500. 'last_name': {
  501. 'Exists': False,
  502. },
  503. 'username': {
  504. 'Exists': True,
  505. 'Value': {
  506. 'S': 'johndoe',
  507. },
  508. },
  509. 'date_joined': {
  510. 'Exists': True,
  511. 'Value': {
  512. 'N': '12345',
  513. },
  514. },
  515. })
  516. # Only a subset of the fields.
  517. self.assertEqual(self.johndoe.build_expects(fields=[
  518. 'first_name',
  519. 'last_name',
  520. 'date_joined',
  521. ]), {
  522. 'first_name': {
  523. 'Exists': True,
  524. 'Value': {
  525. 'S': 'John',
  526. },
  527. },
  528. 'last_name': {
  529. 'Exists': False,
  530. },
  531. 'date_joined': {
  532. 'Exists': True,
  533. 'Value': {
  534. 'N': '12345',
  535. },
  536. },
  537. })
  538. def test_prepare_full(self):
  539. self.assertEqual(self.johndoe.prepare_full(), {
  540. 'username': {'S': 'johndoe'},
  541. 'first_name': {'S': 'John'},
  542. 'date_joined': {'N': '12345'}
  543. })
  544. self.johndoe['friends'] = set(['jane', 'alice'])
  545. data = self.johndoe.prepare_full()
  546. self.assertEqual(data['username'], {'S': 'johndoe'})
  547. self.assertEqual(data['first_name'], {'S': 'John'})
  548. self.assertEqual(data['date_joined'], {'N': '12345'})
  549. self.assertCountEqual(data['friends']['SS'],
  550. ['jane', 'alice'])
  551. def test_prepare_full_empty_set(self):
  552. self.johndoe['friends'] = set()
  553. self.assertEqual(self.johndoe.prepare_full(), {
  554. 'username': {'S': 'johndoe'},
  555. 'first_name': {'S': 'John'},
  556. 'date_joined': {'N': '12345'}
  557. })
  558. def test_prepare_partial(self):
  559. self.johndoe.mark_clean()
  560. # Change some data.
  561. self.johndoe['first_name'] = 'Johann'
  562. # Add some data.
  563. self.johndoe['last_name'] = 'Doe'
  564. # Delete some data.
  565. del self.johndoe['date_joined']
  566. final_data, fields = self.johndoe.prepare_partial()
  567. self.assertEqual(final_data, {
  568. 'date_joined': {
  569. 'Action': 'DELETE',
  570. },
  571. 'first_name': {
  572. 'Action': 'PUT',
  573. 'Value': {'S': 'Johann'},
  574. },
  575. 'last_name': {
  576. 'Action': 'PUT',
  577. 'Value': {'S': 'Doe'},
  578. },
  579. })
  580. self.assertEqual(fields, set([
  581. 'first_name',
  582. 'last_name',
  583. 'date_joined'
  584. ]))
  585. def test_prepare_partial_empty_set(self):
  586. self.johndoe.mark_clean()
  587. # Change some data.
  588. self.johndoe['first_name'] = 'Johann'
  589. # Add some data.
  590. self.johndoe['last_name'] = 'Doe'
  591. # Delete some data.
  592. del self.johndoe['date_joined']
  593. # Put an empty set on the ``Item``.
  594. self.johndoe['friends'] = set()
  595. final_data, fields = self.johndoe.prepare_partial()
  596. self.assertEqual(final_data, {
  597. 'date_joined': {
  598. 'Action': 'DELETE',
  599. },
  600. 'first_name': {
  601. 'Action': 'PUT',
  602. 'Value': {'S': 'Johann'},
  603. },
  604. 'last_name': {
  605. 'Action': 'PUT',
  606. 'Value': {'S': 'Doe'},
  607. },
  608. })
  609. self.assertEqual(fields, set([
  610. 'first_name',
  611. 'last_name',
  612. 'date_joined'
  613. ]))
  614. def test_save_no_changes(self):
  615. # Unchanged, no save.
  616. with mock.patch.object(self.table, '_put_item', return_value=True) \
  617. as mock_put_item:
  618. # Pretend we loaded it via ``get_item``...
  619. self.johndoe.mark_clean()
  620. self.assertFalse(self.johndoe.save())
  621. self.assertFalse(mock_put_item.called)
  622. def test_save_with_changes(self):
  623. # With changed data.
  624. with mock.patch.object(self.table, '_put_item', return_value=True) \
  625. as mock_put_item:
  626. self.johndoe.mark_clean()
  627. self.johndoe['first_name'] = 'J'
  628. self.johndoe['new_attr'] = 'never_seen_before'
  629. self.assertTrue(self.johndoe.save())
  630. self.assertFalse(self.johndoe.needs_save())
  631. self.assertTrue(mock_put_item.called)
  632. mock_put_item.assert_called_once_with({
  633. 'username': {'S': 'johndoe'},
  634. 'first_name': {'S': 'J'},
  635. 'new_attr': {'S': 'never_seen_before'},
  636. 'date_joined': {'N': '12345'}
  637. }, expects={
  638. 'username': {
  639. 'Value': {
  640. 'S': 'johndoe',
  641. },
  642. 'Exists': True,
  643. },
  644. 'first_name': {
  645. 'Value': {
  646. 'S': 'John',
  647. },
  648. 'Exists': True,
  649. },
  650. 'new_attr': {
  651. 'Exists': False,
  652. },
  653. 'date_joined': {
  654. 'Value': {
  655. 'N': '12345',
  656. },
  657. 'Exists': True,
  658. },
  659. })
  660. def test_save_with_changes_overwrite(self):
  661. # With changed data.
  662. with mock.patch.object(self.table, '_put_item', return_value=True) \
  663. as mock_put_item:
  664. self.johndoe['first_name'] = 'J'
  665. self.johndoe['new_attr'] = 'never_seen_before'
  666. # OVERWRITE ALL THE THINGS
  667. self.assertTrue(self.johndoe.save(overwrite=True))
  668. self.assertFalse(self.johndoe.needs_save())
  669. self.assertTrue(mock_put_item.called)
  670. mock_put_item.assert_called_once_with({
  671. 'username': {'S': 'johndoe'},
  672. 'first_name': {'S': 'J'},
  673. 'new_attr': {'S': 'never_seen_before'},
  674. 'date_joined': {'N': '12345'}
  675. }, expects=None)
  676. def test_partial_no_changes(self):
  677. # Unchanged, no save.
  678. with mock.patch.object(self.table, '_update_item', return_value=True) \
  679. as mock_update_item:
  680. # Pretend we loaded it via ``get_item``...
  681. self.johndoe.mark_clean()
  682. self.assertFalse(self.johndoe.partial_save())
  683. self.assertFalse(mock_update_item.called)
  684. def test_partial_with_changes(self):
  685. # Setup the data.
  686. self.table.schema = [
  687. HashKey('username'),
  688. ]
  689. # With changed data.
  690. with mock.patch.object(self.table, '_update_item', return_value=True) \
  691. as mock_update_item:
  692. # Pretend we loaded it via ``get_item``...
  693. self.johndoe.mark_clean()
  694. # Now... MODIFY!!!
  695. self.johndoe['first_name'] = 'J'
  696. self.johndoe['last_name'] = 'Doe'
  697. del self.johndoe['date_joined']
  698. self.assertTrue(self.johndoe.partial_save())
  699. self.assertFalse(self.johndoe.needs_save())
  700. self.assertTrue(mock_update_item.called)
  701. mock_update_item.assert_called_once_with({
  702. 'username': 'johndoe',
  703. }, {
  704. 'first_name': {
  705. 'Action': 'PUT',
  706. 'Value': {'S': 'J'},
  707. },
  708. 'last_name': {
  709. 'Action': 'PUT',
  710. 'Value': {'S': 'Doe'},
  711. },
  712. 'date_joined': {
  713. 'Action': 'DELETE',
  714. }
  715. }, expects={
  716. 'first_name': {
  717. 'Value': {
  718. 'S': 'John',
  719. },
  720. 'Exists': True
  721. },
  722. 'last_name': {
  723. 'Exists': False
  724. },
  725. 'date_joined': {
  726. 'Value': {
  727. 'N': '12345',
  728. },
  729. 'Exists': True
  730. },
  731. })
  732. def test_delete(self):
  733. # Setup the data.
  734. self.table.schema = [
  735. HashKey('username'),
  736. RangeKey('date_joined'),
  737. ]
  738. with mock.patch.object(self.table, 'delete_item', return_value=True) \
  739. as mock_delete_item:
  740. self.johndoe.delete()
  741. self.assertTrue(mock_delete_item.called)
  742. mock_delete_item.assert_called_once_with(
  743. username='johndoe',
  744. date_joined=12345
  745. )
  746. def test_nonzero(self):
  747. self.assertTrue(self.johndoe)
  748. self.assertFalse(self.create_item({}))
  749. class ItemFromItemTestCase(ItemTestCase):
  750. def setUp(self):
  751. super(ItemFromItemTestCase, self).setUp()
  752. self.johndoe = self.create_item(self.johndoe)
  753. def fake_results(name, greeting='hello', exclusive_start_key=None, limit=None):
  754. if exclusive_start_key is None:
  755. exclusive_start_key = -1
  756. if limit == 0:
  757. raise Exception("Web Service Returns '400 Bad Request'")
  758. end_cap = 13
  759. results = []
  760. start_key = exclusive_start_key + 1
  761. for i in range(start_key, start_key + 5):
  762. if i < end_cap:
  763. results.append("%s %s #%s" % (greeting, name, i))
  764. # Don't return more than limit results
  765. if limit < len(results):
  766. results = results[:limit]
  767. retval = {
  768. 'results': results,
  769. }
  770. if exclusive_start_key + 5 < end_cap:
  771. retval['last_key'] = exclusive_start_key + 5
  772. return retval
  773. class ResultSetTestCase(unittest.TestCase):
  774. def setUp(self):
  775. super(ResultSetTestCase, self).setUp()
  776. self.results = ResultSet()
  777. self.result_function = mock.MagicMock(side_effect=fake_results)
  778. self.results.to_call(self.result_function, 'john', greeting='Hello', limit=20)
  779. def test_first_key(self):
  780. self.assertEqual(self.results.first_key, 'exclusive_start_key')
  781. def test_max_page_size_fetch_more(self):
  782. self.results = ResultSet(max_page_size=10)
  783. self.results.to_call(self.result_function, 'john', greeting='Hello')
  784. self.results.fetch_more()
  785. self.result_function.assert_called_with('john', greeting='Hello', limit=10)
  786. self.result_function.reset_mock()
  787. def test_max_page_size_and_smaller_limit_fetch_more(self):
  788. self.results = ResultSet(max_page_size=10)
  789. self.results.to_call(self.result_function, 'john', greeting='Hello', limit=5)
  790. self.results.fetch_more()
  791. self.result_function.assert_called_with('john', greeting='Hello', limit=5)
  792. self.result_function.reset_mock()
  793. def test_max_page_size_and_bigger_limit_fetch_more(self):
  794. self.results = ResultSet(max_page_size=10)
  795. self.results.to_call(self.result_function, 'john', greeting='Hello', limit=15)
  796. self.results.fetch_more()
  797. self.result_function.assert_called_with('john', greeting='Hello', limit=10)
  798. self.result_function.reset_mock()
  799. def test_fetch_more(self):
  800. # First "page".
  801. self.results.fetch_more()
  802. self.assertEqual(self.results._results, [
  803. 'Hello john #0',
  804. 'Hello john #1',
  805. 'Hello john #2',
  806. 'Hello john #3',
  807. 'Hello john #4',
  808. ])
  809. self.result_function.assert_called_with('john', greeting='Hello', limit=20)
  810. self.result_function.reset_mock()
  811. # Fake in a last key.
  812. self.results._last_key_seen = 4
  813. # Second "page".
  814. self.results.fetch_more()
  815. self.assertEqual(self.results._results, [
  816. 'Hello john #5',
  817. 'Hello john #6',
  818. 'Hello john #7',
  819. 'Hello john #8',
  820. 'Hello john #9',
  821. ])
  822. self.result_function.assert_called_with('john', greeting='Hello', limit=20, exclusive_start_key=4)
  823. self.result_function.reset_mock()
  824. # Fake in a last key.
  825. self.results._last_key_seen = 9
  826. # Last "page".
  827. self.results.fetch_more()
  828. self.assertEqual(self.results._results, [
  829. 'Hello john #10',
  830. 'Hello john #11',
  831. 'Hello john #12',
  832. ])
  833. # Fake in a key outside the range.
  834. self.results._last_key_seen = 15
  835. # Empty "page". Nothing new gets added
  836. self.results.fetch_more()
  837. self.assertEqual(self.results._results, [])
  838. # Make sure we won't check for results in the future.
  839. self.assertFalse(self.results._results_left)
  840. def test_iteration(self):
  841. # First page.
  842. self.assertEqual(next(self.results), 'Hello john #0')
  843. self.assertEqual(next(self.results), 'Hello john #1')
  844. self.assertEqual(next(self.results), 'Hello john #2')
  845. self.assertEqual(next(self.results), 'Hello john #3')
  846. self.assertEqual(next(self.results), 'Hello john #4')
  847. self.assertEqual(self.results._limit, 15)
  848. # Second page.
  849. self.assertEqual(next(self.results), 'Hello john #5')
  850. self.assertEqual(next(self.results), 'Hello john #6')
  851. self.assertEqual(next(self.results), 'Hello john #7')
  852. self.assertEqual(next(self.results), 'Hello john #8')
  853. self.assertEqual(next(self.results), 'Hello john #9')
  854. self.assertEqual(self.results._limit, 10)
  855. # Third page.
  856. self.assertEqual(next(self.results), 'Hello john #10')
  857. self.assertEqual(next(self.results), 'Hello john #11')
  858. self.assertEqual(next(self.results), 'Hello john #12')
  859. self.assertRaises(StopIteration, self.results.next)
  860. self.assertEqual(self.results._limit, 7)
  861. def test_limit_smaller_than_first_page(self):
  862. results = ResultSet()
  863. results.to_call(fake_results, 'john', greeting='Hello', limit=2)
  864. self.assertEqual(next(results), 'Hello john #0')
  865. self.assertEqual(next(results), 'Hello john #1')
  866. self.assertRaises(StopIteration, results.next)
  867. def test_limit_equals_page(self):
  868. results = ResultSet()
  869. results.to_call(fake_results, 'john', greeting='Hello', limit=5)
  870. # First page
  871. self.assertEqual(next(results), 'Hello john #0')
  872. self.assertEqual(next(results), 'Hello john #1')
  873. self.assertEqual(next(results), 'Hello john #2')
  874. self.assertEqual(next(results), 'Hello john #3')
  875. self.assertEqual(next(results), 'Hello john #4')
  876. self.assertRaises(StopIteration, results.next)
  877. def test_limit_greater_than_page(self):
  878. results = ResultSet()
  879. results.to_call(fake_results, 'john', greeting='Hello', limit=6)
  880. # First page
  881. self.assertEqual(next(results), 'Hello john #0')
  882. self.assertEqual(next(results), 'Hello john #1')
  883. self.assertEqual(next(results), 'Hello john #2')
  884. self.assertEqual(next(results), 'Hello john #3')
  885. self.assertEqual(next(results), 'Hello john #4')
  886. # Second page
  887. self.assertEqual(next(results), 'Hello john #5')
  888. self.assertRaises(StopIteration, results.next)
  889. def test_iteration_noresults(self):
  890. def none(limit=10):
  891. return {
  892. 'results': [],
  893. }
  894. results = ResultSet()
  895. results.to_call(none, limit=20)
  896. self.assertRaises(StopIteration, results.next)
  897. def test_iteration_sporadic_pages(self):
  898. # Some pages have no/incomplete results but have a ``LastEvaluatedKey``
  899. # (for instance, scans with filters), so we need to accommodate that.
  900. def sporadic():
  901. # A dict, because Python closures have read-only access to the
  902. # reference itself.
  903. count = {'value': -1}
  904. def _wrapper(limit=10, exclusive_start_key=None):
  905. count['value'] = count['value'] + 1
  906. if count['value'] == 0:
  907. # Full page.
  908. return {
  909. 'results': [
  910. 'Result #0',
  911. 'Result #1',
  912. 'Result #2',
  913. 'Result #3',
  914. ],
  915. 'last_key': 'page-1'
  916. }
  917. elif count['value'] == 1:
  918. # Empty page but continue.
  919. return {
  920. 'results': [],
  921. 'last_key': 'page-2'
  922. }
  923. elif count['value'] == 2:
  924. # Final page.
  925. return {
  926. 'results': [
  927. 'Result #4',
  928. 'Result #5',
  929. 'Result #6',
  930. ],
  931. }
  932. return _wrapper
  933. results = ResultSet()
  934. results.to_call(sporadic(), limit=20)
  935. # First page
  936. self.assertEqual(next(results), 'Result #0')
  937. self.assertEqual(next(results), 'Result #1')
  938. self.assertEqual(next(results), 'Result #2')
  939. self.assertEqual(next(results), 'Result #3')
  940. # Second page (misses!)
  941. # Moves on to the third page
  942. self.assertEqual(next(results), 'Result #4')
  943. self.assertEqual(next(results), 'Result #5')
  944. self.assertEqual(next(results), 'Result #6')
  945. self.assertRaises(StopIteration, results.next)
  946. def test_list(self):
  947. self.assertEqual(list(self.results), [
  948. 'Hello john #0',
  949. 'Hello john #1',
  950. 'Hello john #2',
  951. 'Hello john #3',
  952. 'Hello john #4',
  953. 'Hello john #5',
  954. 'Hello john #6',
  955. 'Hello john #7',
  956. 'Hello john #8',
  957. 'Hello john #9',
  958. 'Hello john #10',
  959. 'Hello john #11',
  960. 'Hello john #12'
  961. ])
  962. def fake_batch_results(keys):
  963. results = []
  964. simulate_unprocessed = True
  965. if len(keys) and keys[0] == 'johndoe':
  966. simulate_unprocessed = False
  967. for key in keys:
  968. if simulate_unprocessed and key == 'johndoe':
  969. continue
  970. results.append("hello %s" % key)
  971. retval = {
  972. 'results': results,
  973. 'last_key': None,
  974. }
  975. if simulate_unprocessed:
  976. retval['unprocessed_keys'] = ['johndoe']
  977. return retval
  978. class BatchGetResultSetTestCase(unittest.TestCase):
  979. def setUp(self):
  980. super(BatchGetResultSetTestCase, self).setUp()
  981. self.results = BatchGetResultSet(keys=[
  982. 'alice',
  983. 'bob',
  984. 'jane',
  985. 'johndoe',
  986. ])
  987. self.results.to_call(fake_batch_results)
  988. def test_fetch_more(self):
  989. # First "page".
  990. self.results.fetch_more()
  991. self.assertEqual(self.results._results, [
  992. 'hello alice',
  993. 'hello bob',
  994. 'hello jane',
  995. ])
  996. self.assertEqual(self.results._keys_left, ['johndoe'])
  997. # Second "page".
  998. self.results.fetch_more()
  999. self.assertEqual(self.results._results, [
  1000. 'hello johndoe',
  1001. ])
  1002. # Empty "page". Nothing new gets added
  1003. self.results.fetch_more()
  1004. self.assertEqual(self.results._results, [])
  1005. # Make sure we won't check for results in the future.
  1006. self.assertFalse(self.results._results_left)
  1007. def test_fetch_more_empty(self):
  1008. self.results.to_call(lambda keys: {'results': [], 'last_key': None})
  1009. self.results.fetch_more()
  1010. self.assertEqual(self.results._results, [])
  1011. self.assertRaises(StopIteration, self.results.next)
  1012. def test_iteration(self):
  1013. # First page.
  1014. self.assertEqual(next(self.results), 'hello alice')
  1015. self.assertEqual(next(self.results), 'hello bob')
  1016. self.assertEqual(next(self.results), 'hello jane')
  1017. self.assertEqual(next(self.results), 'hello johndoe')
  1018. self.assertRaises(StopIteration, self.results.next)
  1019. class TableTestCase(unittest.TestCase):
  1020. def setUp(self):
  1021. super(TableTestCase, self).setUp()
  1022. self.users = Table('users', connection=FakeDynamoDBConnection())
  1023. self.default_connection = DynamoDBConnection(
  1024. aws_access_key_id='access_key',
  1025. aws_secret_access_key='secret_key'
  1026. )
  1027. def test__introspect_schema(self):
  1028. raw_schema_1 = [
  1029. {
  1030. "AttributeName": "username",
  1031. "KeyType": "HASH"
  1032. },
  1033. {
  1034. "AttributeName": "date_joined",
  1035. "KeyType": "RANGE"
  1036. }
  1037. ]
  1038. raw_attributes_1 = [
  1039. {
  1040. 'AttributeName': 'username',
  1041. 'AttributeType': 'S'
  1042. },
  1043. {
  1044. 'AttributeName': 'date_joined',
  1045. 'AttributeType': 'S'
  1046. },
  1047. ]
  1048. schema_1 = self.users._introspect_schema(raw_schema_1, raw_attributes_1)
  1049. self.assertEqual(len(schema_1), 2)
  1050. self.assertTrue(isinstance(schema_1[0], HashKey))
  1051. self.assertEqual(schema_1[0].name, 'username')
  1052. self.assertTrue(isinstance(schema_1[1], RangeKey))
  1053. self.assertEqual(schema_1[1].name, 'date_joined')
  1054. raw_schema_2 = [
  1055. {
  1056. "AttributeName": "username",
  1057. "KeyType": "BTREE"
  1058. },
  1059. ]
  1060. raw_attributes_2 = [
  1061. {
  1062. 'AttributeName': 'username',
  1063. 'AttributeType': 'S'
  1064. },
  1065. ]
  1066. self.assertRaises(
  1067. exceptions.UnknownSchemaFieldError,
  1068. self.users._introspect_schema,
  1069. raw_schema_2,
  1070. raw_attributes_2
  1071. )
  1072. # Test a complex schema & ensure the types come back correctly.
  1073. raw_schema_3 = [
  1074. {
  1075. "AttributeName": "user_id",
  1076. "KeyType": "HASH"
  1077. },
  1078. {
  1079. "AttributeName": "junk",
  1080. "KeyType": "RANGE"
  1081. }
  1082. ]
  1083. raw_attributes_3 = [
  1084. {
  1085. 'AttributeName': 'user_id',
  1086. 'AttributeType': 'N'
  1087. },
  1088. {
  1089. 'AttributeName': 'junk',
  1090. 'AttributeType': 'B'
  1091. },
  1092. ]
  1093. schema_3 = self.users._introspect_schema(raw_schema_3, raw_attributes_3)
  1094. self.assertEqual(len(schema_3), 2)
  1095. self.assertTrue(isinstance(schema_3[0], HashKey))
  1096. self.assertEqual(schema_3[0].name, 'user_id')
  1097. self.assertEqual(schema_3[0].data_type, NUMBER)
  1098. self.assertTrue(isinstance(schema_3[1], RangeKey))
  1099. self.assertEqual(schema_3[1].name, 'junk')
  1100. self.assertEqual(schema_3[1].data_type, BINARY)
  1101. def test__introspect_indexes(self):
  1102. raw_indexes_1 = [
  1103. {
  1104. "IndexName": "MostRecentlyJoinedIndex",
  1105. "KeySchema": [
  1106. {
  1107. "AttributeName": "username",
  1108. "KeyType": "HASH"
  1109. },
  1110. {
  1111. "AttributeName": "date_joined",
  1112. "KeyType": "RANGE"
  1113. }
  1114. ],
  1115. "Projection": {
  1116. "ProjectionType": "KEYS_ONLY"
  1117. }
  1118. },
  1119. {
  1120. "IndexName": "EverybodyIndex",
  1121. "KeySchema": [
  1122. {
  1123. "AttributeName": "username",
  1124. "KeyType": "HASH"
  1125. },
  1126. ],
  1127. "Projection": {
  1128. "ProjectionType": "ALL"
  1129. }
  1130. },
  1131. {
  1132. "IndexName": "GenderIndex",
  1133. "KeySchema": [
  1134. {
  1135. "AttributeName": "username",
  1136. "KeyType": "HASH"
  1137. },
  1138. {
  1139. "AttributeName": "date_joined",
  1140. "KeyType": "RANGE"
  1141. }
  1142. ],
  1143. "Projection": {
  1144. "ProjectionType": "INCLUDE",
  1145. "NonKeyAttributes": [
  1146. 'gender',
  1147. ]
  1148. }
  1149. }
  1150. ]
  1151. indexes_1 = self.users._introspect_indexes(raw_indexes_1)
  1152. self.assertEqual(len(indexes_1), 3)
  1153. self.assertTrue(isinstance(indexes_1[0], KeysOnlyIndex))
  1154. self.assertEqual(indexes_1[0].name, 'MostRecentlyJoinedIndex')
  1155. self.assertEqual(len(indexes_1[0].parts), 2)
  1156. self.assertTrue(isinstance(indexes_1[1], AllIndex))
  1157. self.assertEqual(indexes_1[1].name, 'EverybodyIndex')
  1158. self.assertEqual(len(indexes_1[1].parts), 1)
  1159. self.assertTrue(isinstance(indexes_1[2], IncludeIndex))
  1160. self.assertEqual(indexes_1[2].name, 'GenderIndex')
  1161. self.assertEqual(len(indexes_1[2].parts), 2)
  1162. self.assertEqual(indexes_1[2].includes_fields, ['gender'])
  1163. raw_indexes_2 = [
  1164. {
  1165. "IndexName": "MostRecentlyJoinedIndex",
  1166. "KeySchema": [
  1167. {
  1168. "AttributeName": "username",
  1169. "KeyType": "HASH"
  1170. },
  1171. {
  1172. "AttributeName": "date_joined",
  1173. "KeyType": "RANGE"
  1174. }
  1175. ],
  1176. "Projection": {
  1177. "ProjectionType": "SOMETHING_CRAZY"
  1178. }
  1179. },
  1180. ]
  1181. self.assertRaises(
  1182. exceptions.UnknownIndexFieldError,
  1183. self.users._introspect_indexes,
  1184. raw_indexes_2
  1185. )
  1186. def test_initialization(self):
  1187. users = Table('users', connection=self.default_connection)
  1188. self.assertEqual(users.table_name, 'users')
  1189. self.assertTrue(isinstance(users.connection, DynamoDBConnection))
  1190. self.assertEqual(users.throughput['read'], 5)
  1191. self.assertEqual(users.throughput['write'], 5)
  1192. self.assertEqual(users.schema, None)
  1193. self.assertEqual(users.indexes, None)
  1194. groups = Table('groups', connection=FakeDynamoDBConnection())
  1195. self.assertEqual(groups.table_name, 'groups')
  1196. self.assertTrue(hasattr(groups.connection, 'assert_called_once_with'))
  1197. def test_create_simple(self):
  1198. conn = FakeDynamoDBConnection()
  1199. with mock.patch.object(conn, 'create_table', return_value={}) \
  1200. as mock_create_table:
  1201. retval = Table.create('users', schema=[
  1202. HashKey('username'),
  1203. RangeKey('date_joined', data_type=NUMBER)
  1204. ], connection=conn)
  1205. self.assertTrue(retval)
  1206. self.assertTrue(mock_create_table.called)
  1207. mock_create_table.assert_called_once_with(attribute_definitions=[
  1208. {
  1209. 'AttributeName': 'username',
  1210. 'AttributeType': 'S'
  1211. },
  1212. {
  1213. 'AttributeName': 'date_joined',
  1214. 'AttributeType': 'N'
  1215. }
  1216. ],
  1217. table_name='users',
  1218. key_schema=[
  1219. {
  1220. 'KeyType': 'HASH',
  1221. 'AttributeName': 'username'
  1222. },
  1223. {
  1224. 'KeyType': 'RANGE',
  1225. 'AttributeName': 'date_joined'
  1226. }
  1227. ],
  1228. provisioned_throughput={
  1229. 'WriteCapacityUnits': 5,
  1230. 'ReadCapacityUnits': 5
  1231. })
  1232. def test_create_full(self):
  1233. conn = FakeDynamoDBConnection()
  1234. with mock.patch.object(conn, 'create_table', return_value={}) \
  1235. as mock_create_table:
  1236. retval = Table.create('users', schema=[
  1237. HashKey('username'),
  1238. RangeKey('date_joined', data_type=NUMBER)
  1239. ], throughput={
  1240. 'read':20,
  1241. 'write': 10,
  1242. }, indexes=[
  1243. KeysOnlyIndex('FriendCountIndex', parts=[
  1244. RangeKey('friend_count')
  1245. ]),
  1246. ], global_indexes=[
  1247. GlobalKeysOnlyIndex('FullFriendCountIndex', parts=[
  1248. RangeKey('friend_count')
  1249. ], throughput={
  1250. 'read': 10,
  1251. 'write': 8,
  1252. }),
  1253. ], connection=conn)
  1254. self.assertTrue(retval)
  1255. self.assertTrue(mock_create_table.called)
  1256. mock_create_table.assert_called_once_with(attribute_definitions=[
  1257. {
  1258. 'AttributeName': 'username',
  1259. 'AttributeType': 'S'
  1260. },
  1261. {
  1262. 'AttributeName': 'date_joined',
  1263. 'AttributeType': 'N'
  1264. },
  1265. {
  1266. 'AttributeName': 'friend_count',
  1267. 'AttributeType': 'S'
  1268. }
  1269. ],
  1270. key_schema=[
  1271. {
  1272. 'KeyType': 'HASH',
  1273. 'AttributeName': 'username'
  1274. },
  1275. {
  1276. 'KeyType': 'RANGE',
  1277. 'AttributeName': 'date_joined'
  1278. }
  1279. ],
  1280. table_name='users',
  1281. provisioned_throughput={
  1282. 'WriteCapacityUnits': 10,
  1283. 'ReadCapacityUnits': 20
  1284. },
  1285. global_secondary_indexes=[
  1286. {
  1287. 'KeySchema': [
  1288. {
  1289. 'KeyType': 'RANGE',
  1290. 'AttributeName': 'friend_count'
  1291. }
  1292. ],
  1293. 'IndexName': 'FullFriendCountIndex',
  1294. 'Projection': {
  1295. 'ProjectionType': 'KEYS_ONLY'
  1296. },
  1297. 'ProvisionedThroughput': {
  1298. 'WriteCapacityUnits': 8,
  1299. 'ReadCapacityUnits': 10
  1300. }
  1301. }
  1302. ],
  1303. local_secondary_indexes=[
  1304. {
  1305. 'KeySchema': [
  1306. {
  1307. 'KeyType': 'RANGE',
  1308. 'AttributeName': 'friend_count'
  1309. }
  1310. ],
  1311. 'IndexName': 'FriendCountIndex',
  1312. 'Projection': {
  1313. 'ProjectionType': 'KEYS_ONLY'
  1314. }
  1315. }
  1316. ])
  1317. def test_describe(self):
  1318. expected = {
  1319. "Table": {
  1320. "AttributeDefinitions": [
  1321. {
  1322. "AttributeName": "username",
  1323. "AttributeType": "S"
  1324. }
  1325. ],
  1326. "ItemCount": 5,
  1327. "KeySchema": [
  1328. {
  1329. "AttributeName": "username",
  1330. "KeyType": "HASH"
  1331. }
  1332. ],
  1333. "LocalSecondaryIndexes": [
  1334. {
  1335. "IndexName": "UsernameIndex",
  1336. "KeySchema": [
  1337. {
  1338. "AttributeName": "username",
  1339. "KeyType": "HASH"
  1340. }
  1341. ],
  1342. "Projection": {
  1343. "ProjectionType": "KEYS_ONLY"
  1344. }
  1345. }
  1346. ],
  1347. "ProvisionedThroughput": {
  1348. "ReadCapacityUnits": 20,
  1349. "WriteCapacityUnits": 6
  1350. },
  1351. "TableName": "Thread",
  1352. "TableStatus": "ACTIVE"
  1353. }
  1354. }
  1355. with mock.patch.object(
  1356. self.users.connection,
  1357. 'describe_table',
  1358. return_value=expected) as mock_describe:
  1359. self.assertEqual(self.users.throughput['read'], 5)
  1360. self.assertEqual(self.users.throughput['write'], 5)
  1361. self.assertEqual(self.users.schema, None)
  1362. self.assertEqual(self.users.indexes, None)
  1363. self.users.describe()
  1364. self.assertEqual(self.users.throughput['read'], 20)
  1365. self.assertEqual(self.users.throughput['write'], 6)
  1366. self.assertEqual(len(self.users.schema), 1)
  1367. self.assertEqual(isinstance(self.users.schema[0], HashKey), 1)
  1368. self.assertEqual(len(self.users.indexes), 1)

Large files files are truncated, but you can click here to view the full file