test_data_mappers_cognito.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. import mock
  2. import pytest
  3. from copy import deepcopy
  4. from boto3.dynamodb.conditions import Key
  5. pytestmark = [
  6. pytest.mark.acceptance_cognito,
  7. pytest.mark.api,
  8. pytest.mark.data_mappers,
  9. pytest.mark.usefixtures("empty_data_mappers"),
  10. ]
  11. @pytest.mark.auth
  12. def test_auth(api_client_cognito, data_mapper_base_endpoint):
  13. headers = {"Authorization": None}
  14. assert (
  15. 401
  16. == api_client_cognito.put(
  17. "{}/{}".format(data_mapper_base_endpoint, "a"), headers=headers
  18. ).status_code
  19. )
  20. assert (
  21. 401
  22. == api_client_cognito.get(
  23. data_mapper_base_endpoint, headers=headers
  24. ).status_code
  25. )
  26. assert (
  27. 401
  28. == api_client_cognito.delete(
  29. "{}/{}".format(data_mapper_base_endpoint, "a"), headers=headers
  30. ).status_code
  31. )
  32. def test_it_creates_data_mapper(
  33. api_client_cognito,
  34. data_mapper_base_endpoint,
  35. data_mapper_table,
  36. glue_table_factory,
  37. stack,
  38. ):
  39. # Arrange
  40. table = glue_table_factory()
  41. key = "test"
  42. data_mapper = {
  43. "DataMapperId": key,
  44. "Columns": ["a"],
  45. "QueryExecutor": "athena",
  46. "QueryExecutorParameters": {
  47. "DataCatalogProvider": "glue",
  48. "Database": table["Database"],
  49. "Table": table["Table"],
  50. },
  51. "Format": "parquet",
  52. "RoleArn": "arn:aws:iam::123456789012:role/S3F2DataAccessRole",
  53. "DeleteOldVersions": False,
  54. "IgnoreObjectNotFoundExceptions": True,
  55. }
  56. # Act
  57. response = api_client_cognito.put(
  58. "{}/{}".format(data_mapper_base_endpoint, key), json=data_mapper
  59. )
  60. response_body = response.json()
  61. # Assert
  62. expected = deepcopy(data_mapper)
  63. expected["CreatedBy"] = {
  64. "Username": "aws-uk-sa-builders@amazon.com",
  65. "Sub": mock.ANY,
  66. }
  67. expected["DeleteOldVersions"] = False
  68. # Check the response is ok
  69. assert 201 == response.status_code
  70. assert expected == response_body
  71. # Check the item exists in the DDB Table
  72. query_result = data_mapper_table.query(
  73. KeyConditionExpression=Key("DataMapperId").eq(key)
  74. )
  75. assert 1 == len(query_result["Items"])
  76. assert expected == query_result["Items"][0]
  77. assert (
  78. response.headers.get("Access-Control-Allow-Origin")
  79. == stack["APIAccessControlAllowOriginHeader"]
  80. )
  81. def test_it_modifies_data_mapper(
  82. api_client_cognito,
  83. data_mapper_base_endpoint,
  84. data_mapper_table,
  85. glue_table_factory,
  86. stack,
  87. ):
  88. # Arrange
  89. table = glue_table_factory()
  90. key = "test"
  91. data_mapper = {
  92. "DataMapperId": key,
  93. "Columns": ["a"],
  94. "QueryExecutor": "athena",
  95. "QueryExecutorParameters": {
  96. "DataCatalogProvider": "glue",
  97. "Database": table["Database"],
  98. "Table": table["Table"],
  99. },
  100. "Format": "parquet",
  101. "RoleArn": "arn:aws:iam::123456789012:role/S3F2DataAccessRole",
  102. "DeleteOldVersions": False,
  103. "IgnoreObjectNotFoundExceptions": False,
  104. }
  105. # Act
  106. create_response = api_client_cognito.put(
  107. "{}/{}".format(data_mapper_base_endpoint, key), json=data_mapper
  108. )
  109. data_mapper["Columns"] = ["b"]
  110. response = api_client_cognito.put(
  111. "{}/{}".format(data_mapper_base_endpoint, key), json=data_mapper
  112. )
  113. response_body = response.json()
  114. # Assert
  115. assert 201 == response.status_code
  116. assert response_body["Columns"] == ["b"]
  117. # Check the item exists in the DDB Table
  118. query_result = data_mapper_table.query(
  119. KeyConditionExpression=Key("DataMapperId").eq(key)
  120. )
  121. assert 1 == len(query_result["Items"])
  122. assert query_result["Items"][0]["Columns"] == ["b"]
  123. assert (
  124. response.headers.get("Access-Control-Allow-Origin")
  125. == stack["APIAccessControlAllowOriginHeader"]
  126. )
  127. def test_it_creates_without_optionals(
  128. api_client_cognito,
  129. data_mapper_base_endpoint,
  130. data_mapper_table,
  131. glue_table_factory,
  132. stack,
  133. ):
  134. # Arrange
  135. table = glue_table_factory()
  136. key = "test"
  137. data_mapper = {
  138. "DataMapperId": key,
  139. "Columns": ["a"],
  140. "QueryExecutor": "athena",
  141. "QueryExecutorParameters": {
  142. "DataCatalogProvider": "glue",
  143. "Database": table["Database"],
  144. "Table": table["Table"],
  145. },
  146. "RoleArn": "arn:aws:iam::123456789012:role/S3F2DataAccessRole",
  147. }
  148. # Act
  149. response = api_client_cognito.put(
  150. "{}/{}".format(data_mapper_base_endpoint, key), json=data_mapper
  151. )
  152. response_body = response.json()
  153. # Assert
  154. expected = deepcopy(data_mapper)
  155. expected["Format"] = "parquet"
  156. expected["CreatedBy"] = {
  157. "Username": "aws-uk-sa-builders@amazon.com",
  158. "Sub": mock.ANY,
  159. }
  160. expected["DeleteOldVersions"] = True
  161. expected["IgnoreObjectNotFoundExceptions"] = False
  162. # Check the response is ok
  163. assert 201 == response.status_code
  164. assert expected == response_body
  165. # Check the item exists in the DDB Table
  166. query_result = data_mapper_table.query(
  167. KeyConditionExpression=Key("DataMapperId").eq(key)
  168. )
  169. assert 1 == len(query_result["Items"])
  170. assert expected == query_result["Items"][0]
  171. assert (
  172. response.headers.get("Access-Control-Allow-Origin")
  173. == stack["APIAccessControlAllowOriginHeader"]
  174. )
  175. def test_it_rejects_invalid_data_mapper(
  176. api_client_cognito, data_mapper_base_endpoint, glue_table_factory, stack
  177. ):
  178. # Arrange
  179. table = glue_table_factory()
  180. key = "test"
  181. data_mapper = {
  182. "DataMapperId": key,
  183. "Columns": ["a"],
  184. "QueryExecutor": "athena",
  185. "QueryExecutorParameters": {
  186. "DataCatalogProvider": "glue",
  187. "Database": table["Database"],
  188. "Table": table["Table"],
  189. },
  190. "RoleArn": "arn:aws:iam::123456789012:role/WrongRoleName",
  191. }
  192. # Act
  193. response = api_client_cognito.put(
  194. "{}/{}".format(data_mapper_base_endpoint, key), json=data_mapper
  195. )
  196. response_body = response.json()
  197. # Assert
  198. assert 422 == response.status_code
  199. assert (
  200. response.headers.get("Access-Control-Allow-Origin")
  201. == stack["APIAccessControlAllowOriginHeader"]
  202. )
  203. def test_it_rejects_invalid_role(api_client_cognito, data_mapper_base_endpoint, stack):
  204. key = "test"
  205. response = api_client_cognito.put(
  206. "{}/{}".format(data_mapper_base_endpoint, key), json={"INVALID": "PAYLOAD"}
  207. )
  208. assert 422 == response.status_code
  209. assert (
  210. response.headers.get("Access-Control-Allow-Origin")
  211. == stack["APIAccessControlAllowOriginHeader"]
  212. )
  213. def test_it_rejects_invalid_data_source(
  214. api_client_cognito, data_mapper_base_endpoint, stack
  215. ):
  216. key = "test"
  217. response = api_client_cognito.put(
  218. "{}/{}".format(data_mapper_base_endpoint, key),
  219. json={
  220. "Columns": ["column"],
  221. "QueryExecutor": "unsupported",
  222. "QueryExecutorParameters": {},
  223. "Format": "parquet",
  224. },
  225. )
  226. assert 422 == response.status_code
  227. assert (
  228. response.headers.get("Access-Control-Allow-Origin")
  229. == stack["APIAccessControlAllowOriginHeader"]
  230. )
  231. def test_it_rejects_invalid_data_catalog_provider(
  232. api_client_cognito, data_mapper_base_endpoint, stack
  233. ):
  234. key = "test"
  235. response = api_client_cognito.put(
  236. "{}/{}".format(data_mapper_base_endpoint, key),
  237. json={
  238. "Columns": ["column"],
  239. "QueryExecutor": "athena",
  240. "QueryExecutorParameters": {
  241. "Database": "database",
  242. "Table": "table",
  243. "DataCatalogProvider": "invalid",
  244. },
  245. "Format": "parquet",
  246. "RoleArn": "arn:aws:iam::123456789012:role/S3F2DataAccessRole",
  247. },
  248. )
  249. assert 422 == response.status_code
  250. assert (
  251. response.headers.get("Access-Control-Allow-Origin")
  252. == stack["APIAccessControlAllowOriginHeader"]
  253. )
  254. def test_it_rejects_missing_glue_catalog(
  255. api_client_cognito, data_mapper_base_endpoint, stack
  256. ):
  257. key = "test"
  258. response = api_client_cognito.put(
  259. "{}/{}".format(data_mapper_base_endpoint, key),
  260. json={
  261. "Columns": ["column"],
  262. "QueryExecutor": "athena",
  263. "QueryExecutorParameters": {
  264. "Database": "non_existent",
  265. "Table": "non_existent",
  266. "DataCatalogProvider": "glue",
  267. },
  268. "Format": "parquet",
  269. "RoleArn": "arn:aws:iam::123456789012:role/S3F2DataAccessRole",
  270. },
  271. )
  272. assert 400 == response.status_code
  273. assert (
  274. response.headers.get("Access-Control-Allow-Origin")
  275. == stack["APIAccessControlAllowOriginHeader"]
  276. )
  277. def test_it_gets_all_data_mappers(
  278. api_client_cognito, data_mapper_base_endpoint, glue_data_mapper_factory, stack
  279. ):
  280. # Arrange
  281. item = glue_data_mapper_factory()
  282. # Act
  283. response = api_client_cognito.get(data_mapper_base_endpoint)
  284. response_body = response.json()
  285. # Assert
  286. assert response.status_code == 200
  287. assert isinstance(response_body.get("DataMappers"), list)
  288. assert item in response_body["DataMappers"]
  289. assert (
  290. response.headers.get("Access-Control-Allow-Origin")
  291. == stack["APIAccessControlAllowOriginHeader"]
  292. )
  293. def test_it_gets_data_mapper(
  294. api_client_cognito, data_mapper_base_endpoint, glue_data_mapper_factory, stack
  295. ):
  296. # Arrange
  297. item = glue_data_mapper_factory()
  298. key = item["DataMapperId"]
  299. # Act
  300. response = api_client_cognito.get("{}/{}".format(data_mapper_base_endpoint, key))
  301. response_body = response.json()
  302. # Assert
  303. assert response.status_code == 200
  304. assert item == response_body
  305. assert (
  306. response.headers.get("Access-Control-Allow-Origin")
  307. == stack["APIAccessControlAllowOriginHeader"]
  308. )
  309. def test_it_deletes_data_mapper(
  310. api_client_cognito,
  311. glue_data_mapper_factory,
  312. data_mapper_base_endpoint,
  313. data_mapper_table,
  314. stack,
  315. ):
  316. # Arrange
  317. item = glue_data_mapper_factory()
  318. key = item["DataMapperId"]
  319. # Act
  320. response = api_client_cognito.delete("{}/{}".format(data_mapper_base_endpoint, key))
  321. # Assert
  322. assert 204 == response.status_code
  323. # Check the item doesn't exist in the DDB Table
  324. query_result = data_mapper_table.query(
  325. KeyConditionExpression=Key("DataMapperId").eq(key)
  326. )
  327. assert 0 == len(query_result["Items"])
  328. assert (
  329. response.headers.get("Access-Control-Allow-Origin")
  330. == stack["APIAccessControlAllowOriginHeader"]
  331. )