summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-05-04 10:11:23 +0000
committerGerrit Code Review <review@openstack.org>2016-05-04 10:11:23 +0000
commitc116704394ad188e16c3244a046abf9b5c83f711 (patch)
tree092ecb602a6243b433661452e458662fd682374c
parentbf294e4d63f9dbb85ae07cd23909d0c990bbf801 (diff)
parentf623281b2979294eec7ad010e61e2ad9de2ea598 (diff)
Merge "Provide integration test for managing a project's members"
-rw-r--r--openstack_dashboard/test/integration_tests/config.py7
-rw-r--r--openstack_dashboard/test/integration_tests/horizon.conf6
-rw-r--r--openstack_dashboard/test/integration_tests/pages/identity/projectspage.py34
-rw-r--r--openstack_dashboard/test/integration_tests/pages/pageobject.py15
-rw-r--r--openstack_dashboard/test/integration_tests/regions/menus.py113
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_projects.py35
6 files changed, 200 insertions, 10 deletions
diff --git a/openstack_dashboard/test/integration_tests/config.py b/openstack_dashboard/test/integration_tests/config.py
index c5cfc2f..bd95cde 100644
--- a/openstack_dashboard/test/integration_tests/config.py
+++ b/openstack_dashboard/test/integration_tests/config.py
@@ -47,6 +47,13 @@ IdentityGroup = [
47 cfg.StrOpt('admin_home_project', 47 cfg.StrOpt('admin_home_project',
48 default='admin', 48 default='admin',
49 help="Project to keep all objects belonging to an admin user."), 49 help="Project to keep all objects belonging to an admin user."),
50 cfg.StrOpt('default_keystone_role',
51 default='Member',
52 help="Name of default role every user gets in his new project"),
53 cfg.StrOpt('default_keystone_admin_role',
54 default='admin',
55 help="Name of the role that grants admin rights to a user in "
56 "his project"),
50] 57]
51 58
52ImageGroup = [ 59ImageGroup = [
diff --git a/openstack_dashboard/test/integration_tests/horizon.conf b/openstack_dashboard/test/integration_tests/horizon.conf
index a570280..85dc419 100644
--- a/openstack_dashboard/test/integration_tests/horizon.conf
+++ b/openstack_dashboard/test/integration_tests/horizon.conf
@@ -60,6 +60,12 @@ admin_password=secretadmin
60# Project in which an admin user creates everything by default 60# Project in which an admin user creates everything by default
61admin_home_project=admin 61admin_home_project=admin
62 62
63# Name of default role every user gets in his new project
64default_keystone_role=Member
65
66# Name of the role that grants admin rights to a user in his project
67default_keystone_admin_role=admin
68
63[network] 69[network]
64# The cidr block to allocate tenant ipv4 subnets from (string value) 70# The cidr block to allocate tenant ipv4 subnets from (string value)
65tenant_network_cidr=10.100.0.0/16 71tenant_network_cidr=10.100.0.0/16
diff --git a/openstack_dashboard/test/integration_tests/pages/identity/projectspage.py b/openstack_dashboard/test/integration_tests/pages/identity/projectspage.py
index b282102..e377dc5 100644
--- a/openstack_dashboard/test/integration_tests/pages/identity/projectspage.py
+++ b/openstack_dashboard/test/integration_tests/pages/identity/projectspage.py
@@ -12,19 +12,31 @@
12 12
13from openstack_dashboard.test.integration_tests.pages import basepage 13from openstack_dashboard.test.integration_tests.pages import basepage
14from openstack_dashboard.test.integration_tests.regions import forms 14from openstack_dashboard.test.integration_tests.regions import forms
15from openstack_dashboard.test.integration_tests.regions import menus
15from openstack_dashboard.test.integration_tests.regions import tables 16from openstack_dashboard.test.integration_tests.regions import tables
16 17
17 18
19class ProjectForm(forms.TabbedFormRegion):
20 FIELDS = (("name", "description", "enabled"),
21 {'members': menus.MembershipMenuRegion})
22
23 def __init__(self, driver, conf, tab=0):
24 super(ProjectForm, self).__init__(
25 driver, conf, field_mappings=self.FIELDS, default_tab=tab)
26
27
18class ProjectsTable(tables.TableRegion): 28class ProjectsTable(tables.TableRegion):
19 name = 'tenants' 29 name = 'tenants'
20 CREATE_PROJECT_FORM_FIELDS = (("name", "description", "enabled"),)
21 30
22 @tables.bind_table_action('create') 31 @tables.bind_table_action('create')
23 def create_project(self, create_button): 32 def create_project(self, create_button):
24 create_button.click() 33 create_button.click()
25 return forms.TabbedFormRegion( 34 return ProjectForm(self.driver, self.conf)
26 self.driver, self.conf, 35
27 field_mappings=self.CREATE_PROJECT_FORM_FIELDS) 36 @tables.bind_row_action('update')
37 def update_members(self, members_button, row):
38 members_button.click()
39 return ProjectForm(self.driver, self.conf, tab=1)
28 40
29 @tables.bind_table_action('delete') 41 @tables.bind_table_action('delete')
30 def delete_project(self, delete_button): 42 def delete_project(self, delete_button):
@@ -72,3 +84,17 @@ class ProjectsPage(basepage.BaseNavigationPage):
72 def get_project_id_from_row(self, name): 84 def get_project_id_from_row(self, name):
73 row = self._get_row_with_project_name(name) 85 row = self._get_row_with_project_name(name)
74 return row.cells[self.PROJECT_ID_TABLE_NAME_COLUMN].text 86 return row.cells[self.PROJECT_ID_TABLE_NAME_COLUMN].text
87
88 def allocate_user_to_project(self, user_name, roles, project_name):
89 row = self._get_row_with_project_name(project_name)
90 members_form = self.projects_table.update_members(row)
91 members_form.members.allocate_member(user_name)
92 members_form.members.allocate_member_roles(user_name, roles)
93 members_form.submit()
94
95 def get_user_roles_at_project(self, user_name, project_name):
96 row = self._get_row_with_project_name(project_name)
97 members_form = self.projects_table.update_members(row)
98 roles = members_form.members.get_member_allocated_roles(user_name)
99 members_form.cancel()
100 return set(roles)
diff --git a/openstack_dashboard/test/integration_tests/pages/pageobject.py b/openstack_dashboard/test/integration_tests/pages/pageobject.py
index cf2e44d..89c3b0f 100644
--- a/openstack_dashboard/test/integration_tests/pages/pageobject.py
+++ b/openstack_dashboard/test/integration_tests/pages/pageobject.py
@@ -29,11 +29,14 @@ class PageObject(basewebobject.BaseWebObject):
29 def page_title(self): 29 def page_title(self):
30 return self.driver.title 30 return self.driver.title
31 31
32 def is_the_current_page(self): 32 def is_the_current_page(self, do_assert=False):
33 self.assertIn(self._page_title, self.page_title, 33 found_expected_title = self.page_title.startswith(self._page_title)
34 "Expected to find %s in page title, instead found: %s" 34 if do_assert:
35 % (self._page_title, self.page_title)) 35 self.assertTrue(
36 return True 36 found_expected_title,
37 "Expected to find %s in page title, instead found: %s"
38 % (self._page_title, self.page_title))
39 return found_expected_title
37 40
38 @property 41 @property
39 def login_url(self): 42 def login_url(self):
@@ -87,4 +90,4 @@ class PageObject(basewebobject.BaseWebObject):
87 90
88 def go_to_login_page(self): 91 def go_to_login_page(self):
89 self.driver.get(self.login_url) 92 self.driver.get(self.login_url)
90 self.is_the_current_page() 93 self.is_the_current_page(do_assert=True)
diff --git a/openstack_dashboard/test/integration_tests/regions/menus.py b/openstack_dashboard/test/integration_tests/regions/menus.py
index cb8e0e6..bfc159e 100644
--- a/openstack_dashboard/test/integration_tests/regions/menus.py
+++ b/openstack_dashboard/test/integration_tests/regions/menus.py
@@ -262,3 +262,116 @@ class ProjectDropDownRegion(DropDownMenuRegion):
262 else: 262 else:
263 raise exceptions.NoSuchElementException( 263 raise exceptions.NoSuchElementException(
264 "Not found element with text: %s" % name) 264 "Not found element with text: %s" % name)
265
266
267class MembershipMenuRegion(baseregion.BaseRegion):
268 _available_members_locator = (
269 by.By.CSS_SELECTOR, 'ul.available_members > ul.btn-group')
270
271 _allocated_members_locator = (
272 by.By.CSS_SELECTOR, 'ul.members > ul.btn-group')
273
274 _add_remove_member_sublocator = (
275 by.By.CSS_SELECTOR, 'li > a[href="#add_remove"]')
276
277 _member_name_sublocator = (
278 by.By.CSS_SELECTOR, 'li.member > span.display_name')
279
280 _member_roles_widget_sublocator = (by.By.CSS_SELECTOR, 'li.role_options')
281
282 _member_roles_widget_open_subsublocator = (by.By.CSS_SELECTOR, 'a.btn')
283
284 _member_roles_widget_roles_subsublocator = (
285 by.By.CSS_SELECTOR, 'ul.role_dropdown > li')
286
287 def _get_member_name(self, element):
288 return element.find_element(*self._member_name_sublocator).text
289
290 @property
291 def available_members(self):
292 return {self._get_member_name(el): el for el in
293 self._get_elements(*self._available_members_locator)}
294
295 @property
296 def allocated_members(self):
297 return {self._get_member_name(el): el for el in
298 self._get_elements(*self._allocated_members_locator)}
299
300 def allocate_member(self, name, available_members=None):
301 # NOTE(tsufiev): available_members here (and allocated_members below)
302 # are meant to be used for performance optimization to reduce the
303 # amount of calls to selenium by reusing still valid element reference
304 if available_members is None:
305 available_members = self.available_members
306
307 available_members[name].find_element(
308 *self._add_remove_member_sublocator).click()
309
310 def deallocate_member(self, name, allocated_members=None):
311 if allocated_members is None:
312 allocated_members = self.allocated_members
313
314 allocated_members[name].find_element(
315 *self._add_remove_member_sublocator).click()
316
317 def _get_member_roles_widget(self, name, allocated_members=None):
318 if allocated_members is None:
319 allocated_members = self.allocated_members
320
321 return allocated_members[name].find_element(
322 *self._member_roles_widget_sublocator)
323
324 def _get_member_all_roles(self, name, allocated_members=None):
325 roles_widget = self._get_member_roles_widget(name, allocated_members)
326 return roles_widget.find_elements(
327 *self._member_roles_widget_roles_subsublocator)
328
329 @staticmethod
330 def _is_role_selected(role):
331 return 'selected' in role.get_attribute('class').split()
332
333 @staticmethod
334 def _get_hidden_text(role):
335 return role.get_attribute('textContent')
336
337 def get_member_available_roles(self, name, allocated_members=None,
338 strip=True):
339 roles = self._get_member_all_roles(name, allocated_members)
340 return [(self._get_hidden_text(role).strip() if strip else role)
341 for role in roles if not self._is_role_selected(role)]
342
343 def get_member_allocated_roles(self, name, allocated_members=None,
344 strip=True):
345 roles = self._get_member_all_roles(name, allocated_members)
346 return [(self._get_hidden_text(role).strip() if strip else role)
347 for role in roles if self._is_role_selected(role)]
348
349 def open_member_roles_dropdown(self, name, allocated_members=None):
350 widget = self._get_member_roles_widget(name, allocated_members)
351 button = widget.find_element(
352 *self._member_roles_widget_open_subsublocator)
353 button.click()
354
355 def _switch_member_roles(self, name, roles2toggle, method,
356 allocated_members=None):
357 self.open_member_roles_dropdown(name, allocated_members)
358 roles = method(name, allocated_members, False)
359 roles2toggle = set(roles2toggle)
360 for role in roles:
361 role_name = role.text.strip()
362 if role_name in roles2toggle:
363 role.click()
364 roles2toggle.remove(role_name)
365 if not roles2toggle:
366 break
367
368 def allocate_member_roles(self, name, roles2add, allocated_members=None):
369 self._switch_member_roles(
370 name, roles2add, self.get_member_available_roles,
371 allocated_members=allocated_members)
372
373 def deallocate_member_roles(self, name, roles2remove,
374 allocated_members=None):
375 self._switch_member_roles(
376 name, roles2remove, self.get_member_allocated_roles,
377 allocated_members=allocated_members)
diff --git a/openstack_dashboard/test/integration_tests/tests/test_projects.py b/openstack_dashboard/test/integration_tests/tests/test_projects.py
index 5ccec67..bb8f41f 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_projects.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_projects.py
@@ -9,6 +9,7 @@
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations 10# License for the specific language governing permissions and limitations
11# under the License. 11# under the License.
12
12from openstack_dashboard.test.integration_tests import helpers 13from openstack_dashboard.test.integration_tests import helpers
13from openstack_dashboard.test.integration_tests.regions import messages 14from openstack_dashboard.test.integration_tests.regions import messages
14 15
@@ -36,3 +37,37 @@ class TestCreateDeleteProject(helpers.AdminTestCase):
36 self.assertFalse( 37 self.assertFalse(
37 self.projects_page.find_message_and_dismiss(messages.ERROR)) 38 self.projects_page.find_message_and_dismiss(messages.ERROR))
38 self.assertFalse(self.projects_page.is_project_present(PROJECT_NAME)) 39 self.assertFalse(self.projects_page.is_project_present(PROJECT_NAME))
40
41
42class TestModifyProject(helpers.AdminTestCase):
43
44 def setUp(self):
45 super(TestModifyProject, self).setUp()
46 self.projects_page = self.home_pg.go_to_identity_projectspage()
47 self.projects_page.create_project(PROJECT_NAME)
48 self.assertTrue(
49 self.projects_page.find_message_and_dismiss(messages.SUCCESS))
50
51 def test_add_member(self):
52 admin_name = self.CONFIG.identity.admin_username
53 regular_role_name = self.CONFIG.identity.default_keystone_role
54 admin_role_name = self.CONFIG.identity.default_keystone_admin_role
55 roles2add = {regular_role_name, admin_role_name}
56
57 self.projects_page.allocate_user_to_project(
58 admin_name, roles2add, PROJECT_NAME)
59 self.assertTrue(
60 self.projects_page.find_message_and_dismiss(messages.SUCCESS))
61 self.assertFalse(
62 self.projects_page.find_message_and_dismiss(messages.ERROR))
63
64 user_roles = self.projects_page.get_user_roles_at_project(
65 admin_name, PROJECT_NAME)
66 self.assertEqual(roles2add, user_roles,
67 "The requested roles haven't been set for the user!")
68
69 def tearDown(self):
70 if not self.projects_page.is_the_current_page():
71 self.home_pg.go_to_identity_projectspage()
72 self.projects_page.delete_project(PROJECT_NAME)
73 super(TestModifyProject, self).tearDown()