Guest User

Untitled

a guest
Feb 1st, 2017
53
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.79 KB | None | 0 0
  1. # Copyright (c) 2016 AT&T Inc.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. # not use this file except in compliance with the License. You may obtain
  5. # a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations
  13. # under the License.
  14.  
  15. import collections
  16. import mock
  17. import testtools
  18.  
  19. from django.conf import settings
  20. from django.utils.translation import ugettext_lazy as _
  21.  
  22. from muranoclient.common import exceptions as exc
  23. from muranodashboard.environments import tables
  24. from muranodashboard.environments import tabs
  25.  
  26.  
  27. class TestOverviewTab(testtools.TestCase):
  28.  
  29. def setUp(self):
  30. super(TestOverviewTab, self).setUp()
  31. self.overview_tab = tabs.OverviewTab(None)
  32.  
  33. self.assertEqual(_('Component'), self.overview_tab.name)
  34. self.assertEqual('_service', self.overview_tab.slug)
  35. self.assertEqual('services/_overview.html',
  36. self.overview_tab.template_name)
  37.  
  38. @mock.patch.object(tabs, 'heat_api')
  39. @mock.patch.object(tabs, 'nova_api')
  40. @mock.patch.object(tabs, 'consts')
  41. def test_get_context_data(self, mock_consts, mock_nova_api, mock_heat_api):
  42. mock_consts.STATUS_DISPLAY_CHOICES = [('foo_status_id', 'foo_status')]
  43. foo_mock_instance = mock.Mock(id='foo_instance_id')
  44. foo_mock_instance.configure_mock(name='foo-instance-name')
  45. foo_mock_environment_id = mock.Mock(id='foo_stack_id')
  46. foo_mock_environment_id.configure_mock(name='foo_stack_name')
  47. bar_mock_instance = mock.Mock(id='bar_instance_id')
  48. bar_mock_instance.configure_mock(name='bar-instance-name')
  49. baz_mock_instance = mock.Mock(id='baz_instance_id')
  50. baz_mock_instance.configure_mock(name='baz-instance-name')
  51. mock_nova_api.server_list.side_effect = [
  52. ([foo_mock_instance], False), ([bar_mock_instance], False),
  53. ([baz_mock_instance], False)
  54. ]
  55. mock_heat_api.stacks_list.side_effect = [
  56. (
  57. [mock.Mock(id='foo_stack_id', stack_name='foo_stack_name')],
  58. False, False
  59. ),
  60. (
  61. [mock.Mock(id='bar_stack_id', stack_name='bar_stack_name')],
  62. False, False
  63. ),
  64. (
  65. [mock.Mock(id='baz_stack_id', stack_name='baz_stack_name')],
  66. False, False
  67. ),
  68. ]
  69.  
  70. mock_heat_api.stack_get.side_effect = [
  71. (
  72. [mock.Mock(id='foo_environment_id', description='foo_stack_id')],
  73. False, False
  74. ),
  75. ]
  76. mock_request = mock.Mock()
  77.  
  78. expected_service = {
  79. 'service': collections.OrderedDict([
  80. ('Name', 'foo_service_data_name'),
  81. ('ID', 'foo_service_data_id'),
  82. ('Type', 'Unknown'),
  83. ('Status', 'foo_status'),
  84. ('Domain', 'foo_domain'),
  85. ('Application repository', 'foo_repository'),
  86. ('Load Balancer URI', 'foo_uri'),
  87. ('Floating IP', 'foo_floatingip'),
  88. ('Instance',
  89. {'name': 'foo-instance-name', 'id': 'foo_instance_id'}),
  90. ('Stack',
  91. {'id': 'foo_stack_id', 'name': 'foo_stack_name'}),
  92. ('Instances', [
  93. {'name': 'bar-instance-name', 'id': 'bar_instance_id'},
  94. {'name': 'baz-instance-name', 'id': 'baz_instance_id'}]),
  95. ('Stacks', [
  96. {'id': 'bar_stack_id', 'name': 'bar_stack_name'},
  97. {'id': 'baz_stack_id', 'name': 'baz_stack_name'}])
  98. ])
  99. }
  100.  
  101. def service_data_side_effect(*args, **kwargs):
  102. if args[0] == 'instances':
  103. return [
  104. {
  105. 'status': 'bar_status_id',
  106. 'id': 'bar_service_data_id',
  107. 'name': 'bar-instance-name',
  108. 'openstackId': 'bar_instance_id',
  109. 'environment_id': 'bar_environment_id'
  110. },
  111. {
  112. 'status': 'baz_status_id',
  113. 'id': 'baz_service_data_id',
  114. 'name': 'baz-instance-name',
  115. 'openstackId': 'baz_instance_id',
  116. 'environment_id': 'baz_environment_id'
  117. }
  118. ]
  119. elif args[0] == 'instance':
  120. return {
  121. 'name': 'foo-instance-name',
  122. 'openstackId': 'foo_instance_id',
  123. 'environment_id': 'foo_environment_id',
  124. 'description': 'foo_environment_id'
  125. }
  126. elif args[0] == '?':
  127. return {
  128. 'status': 'foo_status_id',
  129. 'id': 'foo_service_data_id',
  130. 'environment_id': 'foo_environment_id'
  131. }
  132.  
  133. service_data = mock.MagicMock()
  134. service_data.__getitem__.side_effect = service_data_side_effect
  135. service_data.configure_mock(name='foo_service_data_name')
  136. service_data.domain = 'foo_domain'
  137. service_data.repository = 'foo_repository'
  138. service_data.uri = 'foo_uri'
  139. service_data.floatingip = 'foo_floatingip'
  140. self.overview_tab.tab_group = mock.Mock()
  141. self.overview_tab.tab_group.kwargs = {
  142. 'service': service_data,
  143. 'environment_id': 'foo_environment_id'
  144. }
  145.  
  146. result = self.overview_tab.get_context_data(mock_request)
  147.  
  148. self.assertIsInstance(result, dict)
  149. self.assertIn('service', result)
  150. self.assertEqual(expected_service, result)
  151. self.assertEqual(3, mock_nova_api.server_list.call_count)
  152. self.assertEqual(3, mock_heat_api.stacks_list.call_count)
  153. mock_nova_api.server_list.assert_any_call(mock_request)
  154. mock_heat_api.stacks_list.assert_any_call(mock_request, sort_dir='asc')
  155. mock_heat_api.stack_get.assert_any_call(mock_request)
  156. @mock.patch.object(tabs, 'heat_api')
  157. @mock.patch.object(tabs, 'nova_api')
  158. def test_get_context_data_find_stack_has_more(self, mock_nova_api,
  159. mock_heat_api):
  160. foo_mock_instance = mock.Mock(id='foo_instance_id')
  161. foo_mock_instance.configure_mock(name='foo-instance-name')
  162. mock_nova_api.server_list.side_effect = [
  163. ([foo_mock_instance], False)
  164. ]
  165. mock_heat_api.stacks_list.side_effect = [
  166. (
  167. [mock.Mock(id='bar_environment_id', stack_name='bar_stack_name')],
  168. True, False
  169. ),
  170. (
  171. [mock.Mock(id='foo_environment_id', stack_name='foo_stack_name')],
  172. False, False
  173. )
  174. ]
  175. mock_request = mock.Mock()
  176.  
  177. expected_service = {
  178. 'service': collections.OrderedDict([
  179. ('Name', 'foo_service_data_name'),
  180. ('ID', 'foo_service_data_id'),
  181. ('Type', 'Unknown'),
  182. ('Status', ''),
  183. ('Domain', 'Not in domain'),
  184. ('Application repository', 'foo_repository'),
  185. ('Load Balancer URI', 'foo_uri'),
  186. ('Floating IP', 'foo_floatingip'),
  187. ('Instance',
  188. {'name': 'foo-instance-name', 'id': 'foo_instance_id'}),
  189. ('Stack',
  190. {'id': 'foo_stack_id', 'name': 'foo_stack_name'}),
  191. ])
  192. }
  193.  
  194. expected_mock_calls = [
  195. mock.call(mock_request, sort_dir='asc'),
  196. mock.call(mock_request, sort_dir='asc', marker='bar_stack_id')
  197. ]
  198.  
  199. def service_data_side_effect(*args, **kwargs):
  200. if args[0] == 'instance':
  201. return {
  202. 'name': 'foo-instance-name',
  203. 'openstackId': 'foo_instance_id',
  204. 'environment_id': 'foo_environment_id'
  205.  
  206. }
  207. elif args[0] == '?':
  208. return {
  209. 'status': 'foo_status_id',
  210. 'id': 'foo_service_data_id',
  211. }
  212.  
  213. service_data = mock.MagicMock()
  214. service_data.__getitem__.side_effect = service_data_side_effect
  215. service_data.configure_mock(name='foo_service_data_name')
  216. service_data.domain = None
  217. service_data.repository = 'foo_repository'
  218. service_data.uri = 'foo_uri'
  219. service_data.floatingip = 'foo_floatingip'
  220.  
  221. self.overview_tab.tab_group = mock.Mock()
  222. self.overview_tab.tab_group.kwargs = {
  223. 'service': service_data,
  224. 'environment_id': 'foo_environment_id',
  225. }
  226.  
  227. result = self.overview_tab.get_context_data(mock_request)
  228.  
  229. self.assertIsInstance(result, dict)
  230. self.assertIn('service', result)
  231. self.assertEqual(expected_service, result)
  232. # Test whether the expected number of calls were made. 1 call should
  233. # be made to nova_api but 2 should be made to heat_api, since that
  234. # call is recursive.
  235. self.assertEqual(1, mock_nova_api.server_list.call_count)
  236. self.assertEqual(2, mock_heat_api.stacks_list.call_count)
  237. mock_nova_api.server_list.assert_any_call(mock_request)
  238. self.assertEqual(expected_mock_calls,
  239. mock_heat_api.stacks_list.mock_calls)
  240.  
  241.  
  242. class TestServiceLogsTab(testtools.TestCase):
  243.  
  244. def setUp(self):
  245. super(TestServiceLogsTab, self).setUp()
  246. self.service_logs_tab = tabs.ServiceLogsTab(None)
  247.  
  248. self.assertEqual(_('Logs'), self.service_logs_tab.name)
  249. self.assertEqual('service_logs', self.service_logs_tab.slug)
  250. self.assertEqual('services/_logs.html',
  251. self.service_logs_tab.template_name)
  252. self.assertFalse(self.service_logs_tab.preload)
  253.  
  254. @mock.patch.object(tabs, 'api')
  255. def test_get_context_data(self, mock_api):
  256. mock_api.get_status_messages_for_service.return_value = ['foo_report']
  257. mock_request = mock.Mock()
  258. self.service_logs_tab.tab_group = mock.Mock()
  259.  
  260. self.service_logs_tab.tab_group.kwargs = {
  261. 'service_id': 'foo_service_id',
  262. 'environment_id': 'foo_environment_id'
  263. }
  264.  
  265. reports = self.service_logs_tab.get_context_data(mock_request)
  266.  
  267. self.assertEqual({'reports': ['foo_report']}, reports)
  268. mock_api.get_status_messages_for_service.assert_called_once_with(
  269. mock_request, 'foo_service_id', 'foo_environment_id')
  270.  
  271.  
  272. class TestEnvLogsTab(testtools.TestCase):
  273.  
  274. def setUp(self):
  275. super(TestEnvLogsTab, self).setUp()
  276. self.env_logs_tab = tabs.EnvLogsTab(None)
  277.  
  278. self.assertEqual(_('Logs'), self.env_logs_tab.name)
  279. self.assertEqual('env_logs', self.env_logs_tab.slug)
  280. self.assertEqual('deployments/_logs.html',
  281. self.env_logs_tab.template_name)
  282. self.assertFalse(self.env_logs_tab.preload)
  283.  
  284. def test_get_context_data(self):
  285. mock_report = mock.Mock(created='T12:34')
  286. self.env_logs_tab.tab_group = mock.Mock()
  287. self.env_logs_tab.tab_group.kwargs = {
  288. 'logs': [mock_report]
  289.  
  290. }
  291.  
  292. reports = self.env_logs_tab.get_context_data(None)
  293.  
  294. mock_report.created = ' 12:34'
  295. self.assertEqual({'reports': [mock_report]}, reports)
  296.  
  297.  
  298. class TestLatestLogTab(testtools.TestCase):
  299.  
  300. def test_allowed(self):
  301. latest_logs_tab = tabs.LatestLogsTab(None)
  302. latest_logs_tab.tab_group = mock.Mock()
  303. mock_report = mock.Mock(created='T12:34')
  304. latest_logs_tab.tab_group.kwargs = {'logs': [mock_report]}
  305.  
  306. self.assertEqual(_('Latest Deployment Log'), latest_logs_tab.name)
  307. mock_report.created = ' 12:34'
  308. self.assertEqual([mock_report], latest_logs_tab.allowed(None))
  309.  
  310.  
  311. class TestEnvConfigTab(testtools.TestCase):
  312.  
  313. def setUp(self):
  314. super(TestEnvConfigTab, self).setUp()
  315. mock_tab_group = mock.Mock(kwargs={})
  316. self.env_config_tab = tabs.EnvConfigTab(mock_tab_group, None)
  317.  
  318. self.assertEqual(_('Configuration'), self.env_config_tab.name)
  319. self.assertEqual('env_config', self.env_config_tab.slug)
  320. self.assertEqual((tables.EnvConfigTable,),
  321. self.env_config_tab.table_classes)
  322. self.assertEqual('horizon/common/_detail_table.html',
  323. self.env_config_tab.template_name)
  324. self.assertFalse(self.env_config_tab.preload)
  325.  
  326. def test_get_environment_and_configuration_data(self):
  327. self.env_config_tab.tab_group = mock.Mock()
  328. self.env_config_tab.tab_group.kwargs = {
  329. 'deployment': {
  330. 'services': ['foo_service']
  331. }
  332. }
  333.  
  334. result = self.env_config_tab.get_environment_configuration_data()
  335. self.assertEqual(['foo_service'], result)
  336.  
  337.  
  338. class TestEnvironmentTopologyTab(testtools.TestCase):
  339.  
  340. def setUp(self):
  341. super(TestEnvironmentTopologyTab, self).setUp()
  342. self.env_topology_tab = tabs.EnvironmentTopologyTab(None)
  343.  
  344. self.assertEqual(_('Topology'), self.env_topology_tab.name)
  345. self.assertEqual('topology', self.env_topology_tab.slug)
  346. self.assertEqual('services/_detail_topology.html',
  347. self.env_topology_tab.template_name)
  348. self.assertFalse(self.env_topology_tab.preload)
  349.  
  350. @mock.patch.object(tabs, 'api')
  351. def test_allowed_true(self, mock_api):
  352. self.env_topology_tab.tab_group = mock.Mock()
  353. self.env_topology_tab.tab_group.kwargs = {
  354. 'environment_id': 'foo_env_id'
  355. }
  356.  
  357. mock_api.load_environment_data.return_value =\
  358. '{"environment": {"status": "foo_status"}}' # d3 data
  359. self.assertTrue(self.env_topology_tab.allowed(None))
  360. mock_api.load_environment_data.assert_called_with(None, 'foo_env_id')
  361.  
  362. @mock.patch.object(tabs, 'api')
  363. def test_allowed_false(self, mock_api):
  364. self.env_topology_tab.tab_group = mock.Mock()
  365. self.env_topology_tab.tab_group.kwargs = {
  366. 'environment_id': 'foo_env_id'
  367. }
  368.  
  369. mock_api.load_environment_data.return_value =\
  370. '{"environment": {"status": null}}' # d3 data
  371. self.assertFalse(self.env_topology_tab.allowed(None))
  372. mock_api.load_environment_data.assert_called_with(None, 'foo_env_id')
  373.  
  374.  
  375. @mock.patch.object(tabs, 'api')
  376. class TestEnvironmentServicesTab(testtools.TestCase):
  377.  
  378. def setUp(self):
  379. super(TestEnvironmentServicesTab, self).setUp()
  380.  
  381. test_kwargs = {'environment_id': 'foo_env_id'}
  382. mock_tab_group = mock.Mock(kwargs=test_kwargs)
  383. self.mock_request = mock.Mock()
  384. self.env_services_tab = tabs.EnvironmentServicesTab(mock_tab_group,
  385. self.mock_request)
  386.  
  387. self.assertEqual(_('Components'), self.env_services_tab.name)
  388. self.assertEqual('services', self.env_services_tab.slug)
  389. self.assertEqual((tables.ServicesTable,),
  390. self.env_services_tab.table_classes)
  391. self.assertEqual('services/_service_list.html',
  392. self.env_services_tab.template_name)
  393. self.assertFalse(self.env_services_tab.preload)
  394.  
  395. def test_get_services_data(self, mock_api):
  396. mock_api.services_list.return_value = ['foo_service']
  397.  
  398. services_data = self.env_services_tab.get_services_data()
  399.  
  400. self.assertEqual(['foo_service'], services_data)
  401. self.assertEqual('foo_env_id', self.env_services_tab.environment_id)
  402.  
  403. @mock.patch.object(tabs, 'reverse')
  404. @mock.patch.object(tabs, 'exceptions')
  405. def test_get_services_data_except_http_forbidden(
  406. self, mock_exc, mock_reverse, mock_api):
  407. mock_api.services_list.side_effect = exc.HTTPForbidden
  408. mock_reverse.return_value = 'foo_reverse_url'
  409.  
  410. services_data = self.env_services_tab.get_services_data()
  411.  
  412. self.assertEqual([], services_data)
  413. expected_msg = _(
  414. 'Unable to retrieve list of services. This environment '
  415. 'is deploying or already deployed by other user.')
  416. mock_exc.handle.assert_called_once_with(
  417. self.mock_request, expected_msg, redirect='foo_reverse_url')
  418. mock_reverse.assert_called_once_with(
  419. 'horizon:app-catalog:environments:index')
  420.  
  421. @mock.patch.object(tabs, 'reverse')
  422. @mock.patch.object(tabs, 'exceptions')
  423. def test_get_services_data_except_internal_server_and_not_found_errors(
  424. self, mock_exc, mock_reverse, mock_api):
  425. mock_reverse.return_value = 'foo_reverse_url'
  426. expected_msg = "Environment with id foo_env_id doesn't exist anymore"
  427.  
  428. for exception_cls in (exc.HTTPInternalServerError, exc.HTTPNotFound):
  429. mock_api.services_list.side_effect = exception_cls
  430.  
  431. services_data = self.env_services_tab.get_services_data()
  432.  
  433. self.assertEqual([], services_data)
  434. mock_exc.handle.assert_called_with(
  435. self.mock_request, expected_msg, redirect='foo_reverse_url')
  436. mock_reverse.assert_called_with(
  437. 'horizon:app-catalog:environments:index')
  438.  
  439. @mock.patch.object(tabs, 'exceptions')
  440. def test_get_services_data_except_http_unauthorized(
  441. self, mock_exc, mock_api):
  442. mock_api.services_list.side_effect = exc.HTTPUnauthorized
  443. self.env_services_tab.get_services_data()
  444. mock_exc.handle.assert_called_once_with(self.mock_request)
  445.  
  446. def test_get_context_data(self, _):
  447. setattr(settings, 'MURANO_USE_GLARE', True)
  448.  
  449. expected_context = {
  450. 'MURANO_USE_GLARE': True,
  451. 'table': mock.ANY,
  452. 'services_table': mock.ANY
  453. }
  454.  
  455. context = self.env_services_tab.get_context_data(self.mock_request)
  456.  
  457. for key, val in expected_context.items():
  458. self.assertEqual(val, context.get(key))
  459.  
  460.  
  461. @mock.patch.object(tabs, 'api')
  462. class TestDeploymentTab(testtools.TestCase):
  463.  
  464. def setUp(self):
  465. super(TestDeploymentTab, self).setUp()
  466.  
  467. test_kwargs = {'environment_id': 'foo_env_id'}
  468. mock_tab_group = mock.Mock(kwargs=test_kwargs)
  469. self.mock_request = mock.Mock()
  470. self.deployment_tab = tabs.DeploymentTab(mock_tab_group,
  471. self.mock_request)
  472.  
  473. self.assertEqual(_('Deployment History'), self.deployment_tab.name)
  474. self.assertEqual('deployments', self.deployment_tab.slug)
  475. self.assertEqual((tables.DeploymentsTable,),
  476. self.deployment_tab.table_classes)
  477. self.assertEqual('horizon/common/_detail_table.html',
  478. self.deployment_tab.template_name)
  479. self.assertFalse(self.deployment_tab.preload)
  480.  
  481. @mock.patch.object(tabs, 'policy')
  482. def test_allowed(self, mock_policy, _):
  483. mock_policy.check.return_value = True
  484. self.assertTrue(self.deployment_tab.allowed(self.mock_request))
  485. mock_policy.check.assert_called_once_with(
  486. (("murano", "list_deployments"),), self.mock_request)
  487.  
  488. def test_get_deployments_data(self, mock_api):
  489. mock_api.deployments_list.return_value = ['foo_deployment']
  490. deployments = self.deployment_tab.get_deployments_data()
  491. self.assertEqual(['foo_deployment'], deployments)
  492. mock_api.deployments_list.assert_called_once_with(
  493. self.mock_request, 'foo_env_id')
  494.  
  495. @mock.patch.object(tabs, 'reverse')
  496. @mock.patch.object(tabs, 'exceptions')
  497. def test_get_deployments_data_except_http_forbidden(
  498. self, mock_exc, mock_reverse, mock_api):
  499. mock_api.deployments_list.side_effect = exc.HTTPForbidden
  500. mock_reverse.return_value = 'foo_reverse_url'
  501.  
  502. self.deployment_tab.get_deployments_data()
  503.  
  504. mock_exc.handle.assert_called_once_with(
  505. self.mock_request, _('Unable to retrieve list of deployments'),
  506. redirect='foo_reverse_url')
  507. mock_reverse.assert_called_once_with(
  508. "horizon:app-catalog:environments:index")
  509.  
  510. @mock.patch.object(tabs, 'reverse')
  511. @mock.patch.object(tabs, 'exceptions')
  512. def test_get_deployments_data_except_http_server_error(
  513. self, mock_exc, mock_reverse, mock_api):
  514. mock_api.deployments_list.side_effect = exc.HTTPInternalServerError
  515. mock_reverse.return_value = 'foo_reverse_url'
  516.  
  517. self.deployment_tab.get_deployments_data()
  518.  
  519. mock_exc.handle.assert_called_once_with(
  520. self.mock_request,
  521. "Environment with id foo_env_id doesn't exist anymore",
  522. redirect='foo_reverse_url')
  523. mock_reverse.assert_called_once_with(
  524. "horizon:app-catalog:environments:index")
  525.  
  526.  
  527. class TestEnvironmentDetailsTabs(testtools.TestCase):
  528.  
  529. @mock.patch.object(tabs, 'api')
  530. def test_init(self, mock_api):
  531. mock_api.load_environment_data.return_value =\
  532. '{"environment": {"status": "foo_status"}}'
  533.  
  534. mock_request = mock.Mock(GET={})
  535. env_details_tabs = tabs.EnvironmentDetailsTabs(
  536. mock_request, environment_id='foo_env_id', logs=[mock.Mock()])
  537.  
  538. self.assertEqual('environment_details', env_details_tabs.slug)
  539. self.assertEqual(
  540. (tabs.EnvironmentServicesTab, tabs.EnvironmentTopologyTab,
  541. tabs.DeploymentTab, tabs.LatestLogsTab),
  542. env_details_tabs.tabs)
  543. self.assertTrue(env_details_tabs.sticky)
  544.  
  545.  
  546. class TestServicesTabs(testtools.TestCase):
  547.  
  548. def test_init(self):
  549. mock_request = mock.Mock(GET={})
  550. services_tabs = tabs.ServicesTabs(mock_request)
  551.  
  552. self.assertEqual('services_details', services_tabs.slug)
  553. self.assertEqual(
  554. (tabs.OverviewTab, tabs.ServiceLogsTab),
  555. services_tabs.tabs)
  556. self.assertTrue(services_tabs.sticky)
  557.  
  558.  
  559. class TestDeploymentDetailsTabs(testtools.TestCase):
  560.  
  561. def test_init(self):
  562. mock_request = mock.Mock(GET={})
  563. deployment_details_tabs = tabs.DeploymentDetailsTabs(mock_request)
  564.  
  565. self.assertEqual('deployment_details', deployment_details_tabs.slug)
  566. self.assertEqual((tabs.EnvConfigTab, tabs.EnvLogsTab,),
  567. deployment_details_tabs.tabs)
  568. self.assertTrue(deployment_details_tabs.sticky)
Advertisement
Add Comment
Please, Sign In to add comment