base_api_tests.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. # Licensed to the Apache Software Foundation (ASF) under one
  2. # or more contributor license agreements. See the NOTICE file
  3. # distributed with this work for additional information
  4. # regarding copyright ownership. The ASF licenses this file
  5. # to you under the Apache License, Version 2.0 (the
  6. # "License"); you may not use this file except in compliance
  7. # with the License. You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing,
  12. # software distributed under the License is distributed on an
  13. # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. # KIND, either express or implied. See the License for the
  15. # specific language governing permissions and limitations
  16. # under the License.
  17. # isort:skip_file
  18. import json
  19. from flask_appbuilder.models.sqla.interface import SQLAInterface
  20. import prison
  21. import tests.test_app
  22. from superset import db, security_manager
  23. from superset.extensions import appbuilder
  24. from superset.models.dashboard import Dashboard
  25. from superset.views.base_api import BaseSupersetModelRestApi
  26. from .base_tests import SupersetTestCase
  27. class Model1Api(BaseSupersetModelRestApi):
  28. datamodel = SQLAInterface(Dashboard)
  29. class_permission_name = "DashboardModelView"
  30. method_permission_name = {
  31. "get_list": "list",
  32. "get": "show",
  33. "export": "mulexport",
  34. "post": "add",
  35. "put": "edit",
  36. "delete": "delete",
  37. "bulk_delete": "delete",
  38. "info": "list",
  39. "related": "list",
  40. }
  41. appbuilder.add_api(Model1Api)
  42. class BaseModelRestApiTests(SupersetTestCase):
  43. def test_default_missing_declaration_get(self):
  44. """
  45. API: Test default missing declaration on get
  46. """
  47. # Check get list response
  48. self.login(username="admin")
  49. uri = "api/v1/model1api/"
  50. rv = self.client.get(uri)
  51. self.assertEqual(rv.status_code, 200)
  52. response = json.loads(rv.data.decode("utf-8"))
  53. self.assertEqual(response["list_columns"], ["id"])
  54. for result in response["result"]:
  55. self.assertEqual(list(result.keys()), ["id"])
  56. # Check get response
  57. dashboard = db.session.query(Dashboard).first()
  58. uri = f"api/v1/model1api/{dashboard.id}"
  59. rv = self.client.get(uri)
  60. self.assertEqual(rv.status_code, 200)
  61. response = json.loads(rv.data.decode("utf-8"))
  62. self.assertEqual(response["show_columns"], ["id"])
  63. self.assertEqual(list(response["result"].keys()), ["id"])
  64. def test_default_missing_declaration_put_spec(self):
  65. self.login(username="admin")
  66. uri = "api/v1/_openapi"
  67. rv = self.client.get(uri)
  68. # dashboard model accepts all fields are null
  69. self.assertEqual(rv.status_code, 200)
  70. response = json.loads(rv.data.decode("utf-8"))
  71. expected_mutation_spec = {
  72. "properties": {"id": {"format": "int32", "type": "integer"}},
  73. "type": "object",
  74. }
  75. self.assertEqual(
  76. response["components"]["schemas"]["Model1Api.post"], expected_mutation_spec
  77. )
  78. self.assertEqual(
  79. response["components"]["schemas"]["Model1Api.put"], expected_mutation_spec
  80. )
  81. def test_default_missing_declaration_post(self):
  82. dashboard_data = {
  83. "dashboard_title": "title1",
  84. "slug": "slug1",
  85. "position_json": '{"a": "A"}',
  86. "css": "css",
  87. "json_metadata": '{"b": "B"}',
  88. "published": True,
  89. }
  90. self.login(username="admin")
  91. uri = "api/v1/model1api/"
  92. rv = self.client.post(uri, json=dashboard_data)
  93. # dashboard model accepts all fields are null
  94. self.assertEqual(rv.status_code, 201)
  95. response = json.loads(rv.data.decode("utf-8"))
  96. self.assertEqual(list(response["result"].keys()), ["id"])
  97. model = db.session.query(Dashboard).get(response["id"])
  98. self.assertEqual(model.dashboard_title, None)
  99. self.assertEqual(model.slug, None)
  100. self.assertEqual(model.position_json, None)
  101. self.assertEqual(model.json_metadata, None)
  102. db.session.delete(model)
  103. db.session.commit()
  104. def test_default_missing_declaration_put(self):
  105. dashboard = db.session.query(Dashboard).first()
  106. dashboard_data = {"dashboard_title": "CHANGED", "slug": "CHANGED"}
  107. self.login(username="admin")
  108. uri = f"api/v1/model1api/{dashboard.id}"
  109. rv = self.client.put(uri, json=dashboard_data)
  110. # dashboard model accepts all fields are null
  111. self.assertEqual(rv.status_code, 200)
  112. response = json.loads(rv.data.decode("utf-8"))
  113. changed_dashboard = db.session.query(Dashboard).get(dashboard.id)
  114. self.assertNotEqual(changed_dashboard.dashboard_title, "CHANGED")
  115. self.assertNotEqual(changed_dashboard.slug, "CHANGED")
  116. class ApiOwnersTestCaseMixin:
  117. """
  118. Implements shared tests for owners related field
  119. """
  120. resource_name: str = ""
  121. def test_get_related_owners(self):
  122. """
  123. API: Test get related owners
  124. """
  125. self.login(username="admin")
  126. uri = f"api/v1/{self.resource_name}/related/owners"
  127. rv = self.client.get(uri)
  128. self.assertEqual(rv.status_code, 200)
  129. response = json.loads(rv.data.decode("utf-8"))
  130. users = db.session.query(security_manager.user_model).all()
  131. expected_users = [str(user) for user in users]
  132. self.assertEqual(response["count"], len(users))
  133. # This needs to be implemented like this, because ordering varies between
  134. # postgres and mysql
  135. response_users = [result["text"] for result in response["result"]]
  136. for expected_user in expected_users:
  137. self.assertIn(expected_user, response_users)
  138. def test_get_filter_related_owners(self):
  139. """
  140. API: Test get filter related owners
  141. """
  142. self.login(username="admin")
  143. argument = {"filter": "a"}
  144. uri = f"api/v1/{self.resource_name}/related/owners?q={prison.dumps(argument)}"
  145. rv = self.client.get(uri)
  146. self.assertEqual(rv.status_code, 200)
  147. response = json.loads(rv.data.decode("utf-8"))
  148. expected_response = {
  149. "count": 2,
  150. "result": [
  151. {"text": "admin user", "value": 1},
  152. {"text": "alpha user", "value": 5},
  153. ],
  154. }
  155. self.assertEqual(response, expected_response)
  156. def test_get_related_fail(self):
  157. """
  158. API: Test get related fail
  159. """
  160. self.login(username="admin")
  161. uri = f"api/v1/{self.resource_name}/related/owner"
  162. rv = self.client.get(uri)
  163. self.assertEqual(rv.status_code, 404)