Merge "Remove deprecated switch_role method"
diff --git a/.zuul.yaml b/.zuul.yaml
index 949ad2f..089ba6e 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -84,7 +84,7 @@
         # Use Member for py3 because arguably negative testing is more
         # important than admin, which is already covered by patrole-admin job.
         RBAC_TEST_ROLE: Member
-        USE_PYTHON3: True
+        USE_PYTHON3: true
       devstack_services:
         s-account: false
         s-container: false
@@ -101,8 +101,10 @@
         - patrole-py35-member
         - patrole-multinode-admin
         - patrole-multinode-member
+        - openstack-tox-lower-constraints
     gate:
       jobs:
         - patrole-admin
         - patrole-member
         - patrole-py35-member
+        - openstack-tox-lower-constraints
diff --git a/lower-constraints.txt b/lower-constraints.txt
new file mode 100644
index 0000000..a5ff1ca
--- /dev/null
+++ b/lower-constraints.txt
@@ -0,0 +1,84 @@
+alabaster==0.7.10
+appdirs==1.4.3
+asn1crypto==0.24.0
+Babel==2.5.3
+bcrypt==3.1.4
+certifi==2018.1.18
+cffi==1.11.5
+chardet==3.0.4
+cliff==2.11.0
+cmd2==0.8.1
+coverage==4.5.1
+cryptography==2.1.4
+debtcollector==1.19.0
+docutils==0.14
+dulwich==0.19.0
+extras==1.0.0
+fasteners==0.14.1
+fixtures==3.0.0
+flake8==2.5.5
+future==0.16.0
+hacking==1.0.0
+idna==2.6
+imagesize==1.0.0
+iso8601==0.1.12
+Jinja2==2.10
+jsonschema==2.6.0
+keystoneauth1==3.4.0
+linecache2==1.0.0
+MarkupSafe==1.0
+mccabe==0.2.1
+mock==2.0.0
+monotonic==1.4
+mox3==0.25.0
+msgpack==0.5.6
+netaddr==0.7.19
+netifaces==0.10.6
+nose==1.3.7
+nosexcover==1.0.11
+openstackdocstheme==1.20.0
+os-client-config==1.29.0
+oslo.concurrency==3.26.0
+oslo.config==5.2.0
+oslo.context==2.20.0
+oslo.i18n==3.20.0
+oslo.log==3.37.0
+oslo.policy==1.34.0
+oslo.serialization==2.25.0
+oslo.utils==3.36.0
+oslotest==3.3.0
+paramiko==2.4.1
+pbr==3.1.1
+pep8==1.5.7
+prettytable==0.7.2
+pyasn1==0.4.2
+pycparser==2.18
+pyflakes==0.8.1
+Pygments==2.2.0
+pyinotify==0.9.6
+PyNaCl==1.2.1
+pyparsing==2.2.0
+pyperclip==1.6.0
+python-dateutil==2.7.0
+python-mimeparse==1.6.0
+python-subunit==1.2.0
+pytz==2018.3
+PyYAML==3.12
+reno==2.7.0
+requests==2.18.4
+requestsexceptions==1.4.0
+rfc3986==1.1.0
+six==1.11.0
+snowballstemmer==1.2.1
+Sphinx==1.6.5
+sphinxcontrib-websupport==1.0.1
+stestr==2.0.0
+stevedore==1.28.0
+tempest==18.0.0
+testrepository==0.0.20
+testtools==2.3.0
+traceback2==1.4.0
+unittest2==1.1.0
+urllib3==1.22
+voluptuous==0.11.1
+wrapt==1.10.11
diff --git a/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
index 226411f..1c5fb2e 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
@@ -47,15 +47,6 @@
         self.snapshots_client.create_snapshot_metadata(
             self.snapshot_id, metadata)['metadata']
 
-    @rbac_rule_validation.action(
-        service="cinder",
-        rule="volume_extension:extended_snapshot_attributes")
-    @decorators.idempotent_id('c9cbec1c-edfe-46b8-825b-7b6ac0a58c25')
-    def test_create_snapshot_metadata(self):
-        # Create metadata for the snapshot
-        with self.rbac_utils.override_role(self):
-            self._create_test_snapshot_metadata()
-
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:get_snapshot_metadata")
     @decorators.idempotent_id('f6912bb1-62e6-483d-bcd0-e98c1641f4c3')
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py
index df4fd10..7d721c4 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py
@@ -17,6 +17,7 @@
 from tempest import config
 from tempest.lib import decorators
 
+from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
 
@@ -39,20 +40,15 @@
         # Create a test shared snapshot for tests
         cls.snapshot = cls.create_snapshot(cls.volume['id'])
 
-    def _list_by_param_values(self, params, with_detail=False):
-        # Perform list or list_details action with given params
-        # and validates result.
-        if with_detail:
-            self.snapshots_client.list_snapshots(
-                detail=True, params=params)['snapshots']
-        else:
-            self.snapshots_client.list_snapshots(
-                params=params)['snapshots']
+    def _list_by_param_values(self, with_detail=False, **params):
+        # Perform list or list_details action with given params.
+        return self.snapshots_client.list_snapshots(
+            detail=with_detail, **params)['snapshots']
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:create_snapshot")
     @decorators.idempotent_id('ac7b2ee5-fbc0-4360-afc2-de8fa4881ede')
-    def test_snapshot_create(self):
+    def test_create_snapshot(self):
         # Create a temp snapshot
         with self.rbac_utils.override_role(self):
             self.create_snapshot(self.volume['id'])
@@ -60,16 +56,33 @@
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:get_snapshot")
     @decorators.idempotent_id('93a11b40-1ba8-44d6-a196-f8d97220f796')
-    def test_snapshot_get(self):
+    def test_show_snapshot(self):
         # Get the snapshot
         with self.rbac_utils.override_role(self):
-            self.snapshots_client.show_snapshot(self.snapshot
-                                                ['id'])['snapshot']
+            self.snapshots_client.show_snapshot(
+                self.snapshot['id'])['snapshot']
+
+    @decorators.idempotent_id('5d6f5f21-9293-4f2a-8f44-cabdc24d92cb')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:extended_snapshot_attributes")
+    def test_show_snapshot_with_extended_attributes(self):
+        """List snapshots with extended attributes."""
+        expected_attrs = ('os-extended-snapshot-attributes:project_id',
+                          'os-extended-snapshot-attributes:progress')
+
+        with self.rbac_utils.override_role(self):
+            resp = self.snapshots_client.show_snapshot(
+                self.snapshot['id'])['snapshot']
+        for expected_attr in expected_attrs:
+            if expected_attr not in resp:
+                raise rbac_exceptions.RbacMalformedResponse(
+                    attribute=expected_attr)
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:update_snapshot")
     @decorators.idempotent_id('53fe8ee3-3bea-4ae8-a979-3c98ea72f620')
-    def test_snapshot_update(self):
+    def test_update_snapshot(self):
         new_desc = 'This is the new description of snapshot.'
         params = {'description': new_desc}
         # Updates snapshot with new values
@@ -80,19 +93,9 @@
             self.snapshots_client, self.snapshot['id'], 'available')
 
     @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:get_all_snapshots")
-    @decorators.idempotent_id('e4edf0c0-2cd3-420f-b8ab-4d98a0718608')
-    def test_snapshots_get_all(self):
-        """list snapshots with params."""
-        # Verify list snapshots by display_name filter
-        params = {'name': self.snapshot['name']}
-        with self.rbac_utils.override_role(self):
-            self._list_by_param_values(params)
-
-    @rbac_rule_validation.action(service="cinder",
                                  rule="volume:delete_snapshot")
     @decorators.idempotent_id('c7fe54ec-3b70-4772-ba11-f166d95888a3')
-    def test_snapshot_delete(self):
+    def test_delete_snapshot(self):
         # Create a temp snapshot
         temp_snapshot = self.create_snapshot(self.volume['id'])
         with self.rbac_utils.override_role(self):
@@ -100,3 +103,38 @@
             self.snapshots_client.delete_snapshot(temp_snapshot['id'])
         self.snapshots_client.wait_for_resource_deletion(
             temp_snapshot['id'])
+
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:get_all_snapshots")
+    @decorators.idempotent_id('e4edf0c0-2cd3-420f-b8ab-4d98a0718608')
+    def test_list_snapshots(self):
+        """List snapshots with params."""
+        params = {'name': self.snapshot['name']}
+        with self.rbac_utils.override_role(self):
+            self._list_by_param_values(**params)
+
+    @decorators.idempotent_id('f3155d8e-45ee-45c9-910d-18c0242229e1')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:get_all_snapshots")
+    def test_list_snapshots_details(self):
+        """List snapshots details with params."""
+        params = {'name': self.snapshot['name']}
+        with self.rbac_utils.override_role(self):
+            self._list_by_param_values(with_detail=True, **params)
+
+    @decorators.idempotent_id('dd37f388-2731-446d-a78f-676997ebb04a')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:extended_snapshot_attributes")
+    def test_list_snapshots_details_with_extended_attributes(self):
+        """List snapshots details with extended attributes."""
+        expected_attrs = ('os-extended-snapshot-attributes:project_id',
+                          'os-extended-snapshot-attributes:progress')
+        params = {'name': self.snapshot['name']}
+
+        with self.rbac_utils.override_role(self):
+            resp = self._list_by_param_values(with_detail=True, **params)
+        for expected_attr in expected_attrs:
+            if expected_attr not in resp[0]:
+                raise rbac_exceptions.RbacMalformedResponse(
+                    attribute=expected_attr)
diff --git a/tox.ini b/tox.ini
index d5e3b91..3c2c8ad 100644
--- a/tox.ini
+++ b/tox.ini
@@ -78,3 +78,10 @@
 
 [hacking]
 local-check-factory = patrole_tempest_plugin.hacking.checks.factory
+
+[testenv:lower-constraints]
+basepython = python3
+deps =
+  -c{toxinidir}/lower-constraints.txt
+  -r{toxinidir}/test-requirements.txt
+  -r{toxinidir}/requirements.txt