Merge "Remove TODO note"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 915e2fa..617c016 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -14,9 +14,6 @@
 uri = http://127.0.0.1:5000/v2.0/
 # URL for where to find the OpenStack V3 Identity API endpoint (Keystone)
 uri_v3 = http://127.0.0.1:5000/v3/
-# Should typically be left as keystone unless you have a non-Keystone
-# authentication API service
-strategy = keystone
 # The identity region
 region = RegionOne
 
diff --git a/tempest/README.rst b/tempest/README.rst
index 892b0f8..8f07a07 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -12,13 +12,13 @@
 and guidelines. Below is the proposed Havana restructuring for Tempest
 to make this clear.
 
-tempest/
-   api/ - API tests
-   cli/ - CLI tests
-   scenario/ - complex scenario tests
-   stress/ - stress tests
-   thirdparty/ - 3rd party api tests
-   whitebox/ - white box testing
+| tempest/
+|    api/ - API tests
+|    cli/ - CLI tests
+|    scenario/ - complex scenario tests
+|    stress/ - stress tests
+|    thirdparty/ - 3rd party api tests
+|    whitebox/ - white box testing
 
 Each of these directories contains different types of tests. What
 belongs in each directory, the rules and examples for good tests, are
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 1ef30d4..a74bb68 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.api import compute
 from tempest.api.compute import base
 from tempest import clients
@@ -100,11 +98,10 @@
         self.assertRaises(exceptions.Duplicate, self.client.create_image,
                           server['id'], snapshot_name)
 
-    @testtools.skip("Until Bug #1039739 is fixed")
     @attr(type=['negative', 'gate'])
     def test_create_image_when_server_is_rebooting(self):
         # Return error when creating an image of server that is rebooting
-        resp, server = self.create_server()
+        resp, server = self.create_server(wait_until='ACTIVE')
         self.servers_client.reboot(server['id'], 'HARD')
 
         snapshot_name = rand_name('test-snap-')
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/test_users.py
index bcc49aa..c029300 100644
--- a/tempest/api/identity/admin/test_users.py
+++ b/tempest/api/identity/admin/test_users.py
@@ -44,7 +44,7 @@
         self.assertEqual('200', resp['status'])
         self.assertEqual(self.alt_user, user['name'])
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_user_by_unauthorized_user(self):
         # Non-admin should not be authorized to create a user
         self.data.setup_test_tenant()
@@ -53,7 +53,7 @@
                           self.alt_password, self.data.tenant['id'],
                           self.alt_email)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_user_with_empty_name(self):
         # User with an empty name should not be created
         self.data.setup_test_tenant()
@@ -61,15 +61,15 @@
                           self.alt_password, self.data.tenant['id'],
                           self.alt_email)
 
-    @attr(type='gate')
-    def test_create_user_with_name_length_over_64(self):
-        # Length of user name filed should be restricted to 64 characters
+    @attr(type=['negative', 'gate'])
+    def test_create_user_with_name_length_over_255(self):
+        # Length of user name filed should be restricted to 255 characters
         self.data.setup_test_tenant()
         self.assertRaises(exceptions.BadRequest, self.client.create_user,
-                          'a' * 65, self.alt_password,
+                          'a' * 256, self.alt_password,
                           self.data.tenant['id'], self.alt_email)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_user_with_duplicate_name(self):
         # Duplicate user should not be created
         self.data.setup_test_user()
@@ -78,7 +78,7 @@
                           self.data.tenant['id'], self.data.test_email)
 
     @testtools.skip("Until Bug #999084 is fixed")
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_user_with_empty_password(self):
         # User with an empty password should not be created
         self.data.setup_test_tenant()
@@ -87,7 +87,7 @@
                           self.alt_email)
 
     @testtools.skip("Until Bug #999084 is fixed")
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_user_with_long_password(self):
         # User having password exceeding max length should not be created
         self.data.setup_test_tenant()
@@ -96,21 +96,21 @@
                           self.alt_email)
 
     @testtools.skip("Until Bug #999084 is fixed")
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_user_with_invalid_email_format(self):
         # Email format should be validated while creating a user
         self.data.setup_test_tenant()
         self.assertRaises(exceptions.BadRequest, self.client.create_user,
                           self.alt_user, '', self.data.tenant['id'], '12345')
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_user_for_non_existant_tenant(self):
         # Attempt to create a user in a non-existent tenant should fail
         self.assertRaises(exceptions.NotFound, self.client.create_user,
                           self.alt_user, self.alt_password, '49ffgg99999',
                           self.alt_email)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_create_user_request_without_a_token(self):
         # Request to create a user without a valid token should fail
         self.data.setup_test_tenant()
@@ -136,7 +136,7 @@
         resp, body = self.client.delete_user(user['id'])
         self.assertEquals('204', resp['status'])
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_delete_users_by_unauthorized_user(self):
         # Non admin user should not be authorized to delete a user
         self.data.setup_test_user()
@@ -144,7 +144,7 @@
                           self.non_admin_client.delete_user,
                           self.data.user['id'])
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_delete_non_existant_user(self):
         # Attempt to delete a non-existent user should fail
         self.assertRaises(exceptions.NotFound, self.client.delete_user,
@@ -163,7 +163,7 @@
                                             self.data.test_tenant)
         self.assertEqual('200', resp['status'])
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_authentication_for_disabled_user(self):
         # Disabled user's token should not get authenticated
         self.data.setup_test_user()
@@ -173,7 +173,7 @@
                           self.data.test_password,
                           self.data.test_tenant)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_authentication_when_tenant_is_disabled(self):
         # User's token for a disabled tenant should not be authenticated
         self.data.setup_test_user()
@@ -183,7 +183,7 @@
                           self.data.test_password,
                           self.data.test_tenant)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_authentication_with_invalid_tenant(self):
         # User's token for an invalid tenant should not be authenticated
         self.data.setup_test_user()
@@ -192,7 +192,7 @@
                           self.data.test_password,
                           'junktenant1234')
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_authentication_with_invalid_username(self):
         # Non-existent user's token should not get authenticated
         self.data.setup_test_user()
@@ -200,7 +200,7 @@
                           'junkuser123', self.data.test_password,
                           self.data.test_tenant)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_authentication_with_invalid_password(self):
         # User's token with invalid password should not be authenticated
         self.data.setup_test_user()
@@ -234,14 +234,14 @@
                         Contains(self.data.test_user),
                         "Could not find %s" % self.data.test_user)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_get_users_by_unauthorized_user(self):
         # Non admin user should not be authorized to get user list
         self.data.setup_test_user()
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.get_users)
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_get_users_request_without_token(self):
         # Request to get list of users without a valid token should fail
         token = self.client.get_auth()
@@ -316,7 +316,7 @@
                          "Failed to find user %s in fetched list" %
                          ', '.join(m_user for m_user in missing_users))
 
-    @attr(type='gate')
+    @attr(type=['negative', 'gate'])
     def test_list_users_with_invalid_tenant(self):
         # Should not be able to return a list of all
         # users for a nonexistant tenant
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 2839da4..fc510cb 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -128,9 +128,9 @@
         resp, snapshot = cls.snapshots_client.create_snapshot(volume_id,
                                                               **kwargs)
         assert 200 == resp.status
+        cls.snapshots.append(snapshot)
         cls.snapshots_client.wait_for_snapshot_status(snapshot['id'],
                                                       'available')
-        cls.snapshots.append(snapshot)
         return snapshot
 
     #NOTE(afazekas): these create_* and clean_* could be defined
@@ -141,8 +141,8 @@
         """Wrapper utility that returns a test volume."""
         resp, volume = cls.volumes_client.create_volume(size, **kwargs)
         assert 200 == resp.status
-        cls.volumes_client.wait_for_volume_status(volume['id'], 'available')
         cls.volumes.append(volume)
+        cls.volumes_client.wait_for_volume_status(volume['id'], 'available')
         return volume
 
     @classmethod
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 68ab745..eda7153 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -21,7 +21,6 @@
 
 
 class VolumesGetTest(base.BaseVolumeTest):
-
     _interface = "json"
 
     @classmethod
@@ -29,22 +28,17 @@
         super(VolumesGetTest, cls).setUpClass()
         cls.client = cls.volumes_client
 
-    def _volume_create_get_delete(self, image_ref=None):
+    def _volume_create_get_delete(self, **kwargs):
         # Create a volume, Get it's details and Delete the volume
         try:
             volume = {}
-            v_name = rand_name('Volume-')
-            metadata = {'Type': 'work'}
+            v_name = rand_name('Volume')
+            metadata = {'Type': 'Test'}
             #Create a volume
-            if not image_ref:
-                resp, volume = self.client.create_volume(size=1,
-                                                         display_name=v_name,
-                                                         metadata=metadata)
-            else:
-                resp, volume = self.client.create_volume(size=1,
-                                                         display_name=v_name,
-                                                         metadata=metadata,
-                                                         imageRef=image_ref)
+            resp, volume = self.client.create_volume(size=1,
+                                                     display_name=v_name,
+                                                     metadata=metadata,
+                                                     **kwargs)
             self.assertEqual(200, resp.status)
             self.assertTrue('id' in volume)
             self.assertTrue('display_name' in volume)
@@ -107,11 +101,17 @@
 
     @attr(type='smoke')
     def test_volume_create_get_delete(self):
-        self._volume_create_get_delete(image_ref=None)
+        self._volume_create_get_delete()
 
     @attr(type='smoke')
-    def test_volume_from_image(self):
-        self._volume_create_get_delete(image_ref=self.config.compute.image_ref)
+    def test_volume_create_get_delete_from_image(self):
+        self._volume_create_get_delete(imageRef=self.config.compute.image_ref)
+
+    @attr(type='gate')
+    def test_volume_create_get_delete_as_clone(self):
+        origin = self.create_volume(size=1,
+                                    display_name="Volume Origin")
+        self._volume_create_get_delete(source_volid=origin['id'])
 
 
 class VolumesGetTestXML(VolumesGetTest):
diff --git a/tempest/clients.py b/tempest/clients.py
index e778dc1..a5c7b4d 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -274,22 +274,15 @@
         self.auth_url = self.config.identity.uri
         self.auth_url_v3 = self.config.identity.uri_v3
 
-        if self.config.identity.strategy == 'keystone':
-            client_args = (self.config, self.username, self.password,
-                           self.auth_url, self.tenant_name)
+        client_args = (self.config, self.username, self.password,
+                       self.auth_url, self.tenant_name)
 
-            if self.auth_url_v3:
-                auth_version = 'v3'
-                client_args_v3_auth = (self.config, self.username,
-                                       self.password, self.auth_url_v3,
-                                       self.tenant_name, auth_version)
-            else:
-                client_args_v3_auth = None
-
+        if self.auth_url_v3:
+            auth_version = 'v3'
+            client_args_v3_auth = (self.config, self.username,
+                                   self.password, self.auth_url_v3,
+                                   self.tenant_name, auth_version)
         else:
-            client_args = (self.config, self.username, self.password,
-                           self.auth_url)
-
             client_args_v3_auth = None
 
         try:
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index baa3c03..531dfc8 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -51,7 +51,6 @@
         self.base_url = None
         self.region = {'compute': self.config.identity.region}
         self.endpoint_url = 'publicURL'
-        self.strategy = self.config.identity.strategy
         self.headers = {'Content-Type': 'application/%s' % self.TYPE,
                         'Accept': 'application/%s' % self.TYPE}
         self.build_interval = config.compute.build_interval
@@ -72,21 +71,14 @@
         Sets the token and base_url used in requests based on the strategy type
         """
 
-        if self.strategy == 'keystone':
-
-            if self.auth_version == 'v3':
-                auth_func = self.identity_auth_v3
-            else:
-                auth_func = self.keystone_auth
-
-            self.token, self.base_url = (
-                auth_func(self.user, self.password, self.auth_url,
-                          self.service, self.tenant_name))
-
+        if self.auth_version == 'v3':
+            auth_func = self.identity_auth_v3
         else:
-            self.token, self.base_url = self.basic_auth(self.user,
-                                                        self.password,
-                                                        self.auth_url)
+            auth_func = self.keystone_auth
+
+        self.token, self.base_url = (
+            auth_func(self.user, self.password, self.auth_url,
+                      self.service, self.tenant_name))
 
     def clear_auth(self):
         """
diff --git a/tempest/config.py b/tempest/config.py
index 85be7a6..7852eba 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -40,10 +40,6 @@
                help="Full URI of the OpenStack Identity API (Keystone), v2"),
     cfg.StrOpt('uri_v3',
                help='Full URI of the OpenStack Identity API (Keystone), v3'),
-    cfg.StrOpt('strategy',
-               default='keystone',
-               help="Which auth method does the environment use? "
-                    "(basic|keystone)"),
     cfg.StrOpt('region',
                default='RegionOne',
                help="The identity region name to use."),
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 93cf89d..5e941da 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -66,3 +66,4 @@
 def factory(register):
     register(skip_bugs)
     register(import_no_clients_in_api)
+    register(import_no_files_in_tests)
diff --git a/tempest/manager.py b/tempest/manager.py
index 762bc18..4a447f3 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -115,11 +115,8 @@
         if 'tokens' not in auth_url:
             auth_url = auth_url.rstrip('/') + '/tokens'
 
-        if self.config.identity.strategy == 'keystone':
-            client_args = (self.config, username, password, auth_url,
-                           tenant_name)
-        else:
-            client_args = (self.config, username, password, auth_url)
+        client_args = (self.config, username, password, auth_url,
+                       tenant_name)
 
         self.servers_client = ServersClient(*client_args)
         self.flavors_client = FlavorsClient(*client_args)
diff --git a/tempest/services/compute/xml/security_groups_client.py b/tempest/services/compute/xml/security_groups_client.py
index 08b381c..4f9d347 100644
--- a/tempest/services/compute/xml/security_groups_client.py
+++ b/tempest/services/compute/xml/security_groups_client.py
@@ -97,29 +97,18 @@
         group_id : ID of the Source group
         """
         group_rule = Element("security_group_rule")
-        parent_group = Element("parent_group_id")
-        parent_group.append(Text(content=parent_group_id))
-        ip_protocol = Element("ip_protocol")
-        ip_protocol.append(Text(content=ip_proto))
-        from_port_num = Element("from_port")
-        from_port_num.append(Text(content=str(from_port)))
-        to_port_num = Element("to_port")
-        to_port_num.append(Text(content=str(to_port)))
 
-        cidr = kwargs.get('cidr')
-        if cidr is not None:
-            cidr_num = Element("cidr")
-            cidr_num.append(Text(content=cidr))
+        elements = {k: kwargs.get(k) for k in ('cidr', 'group_id')}
+        elements['parent_group_id'] = parent_group_id
+        elements['ip_protocol'] = ip_proto
+        elements['from_port'] = from_port
+        elements['to_port'] = to_port
 
-        group_id = kwargs.get('group_id')
-        if group_id is not None:
-            group_id_num = Element("group_id")
-            group_id_num.append(Text(content=group_id))
-
-        group_rule.append(parent_group)
-        group_rule.append(ip_protocol)
-        group_rule.append(from_port_num)
-        group_rule.append(to_port_num)
+        for k, v in elements.items():
+            if v is not None:
+                element = Element(k)
+                element.append(Text(content=str(v)))
+                group_rule.append(element)
 
         url = 'os-security-group-rules'
         resp, body = self.post(url, str(Document(group_rule)), self.headers)
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 69df472..c894612 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -34,8 +34,11 @@
     def create_object(self, container, object_name, data):
         """Create storage object."""
 
+        headers = dict(self.headers)
+        if not data:
+            headers['content-length'] = '0'
         url = "%s/%s" % (str(container), str(object_name))
-        resp, body = self.put(url, data, self.headers)
+        resp, body = self.put(url, data, headers)
         return resp, body
 
     def update_object(self, container, object_name, data):
@@ -194,6 +197,8 @@
             for key in metadata:
                 headers[str(key)] = metadata[key]
 
+        if not data:
+            headers['content-length'] = '0'
         url = "%s/%s" % (str(container), str(object_name))
         resp, body = self.put(url, data, headers=headers)
         return resp, body
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 7480833..89891d2 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -139,6 +139,7 @@
 
     #NOTE(afazekas): doctored test case,
     # with normal validation it would fail
+    @testtools.skip("Until Bug #1182679 is fixed")
     @attr(type='smoke')
     def test_integration_1(self):
         # EC2 1. integration test (not strict)
diff --git a/tox.ini b/tox.ini
index 634b7df..caa9403 100644
--- a/tox.ini
+++ b/tox.ini
@@ -59,7 +59,7 @@
 commands =
    python -m tools/tempest_coverage -c start --combine
    nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit --xunit-file=nosetests-full.xml -sv tempest/api tempest/scenario tempest/thirdparty tempest/cli
-   python -m tools/tempest_coverage -c report --html
+   python -m tools/tempest_coverage -c report --html {posargs}
 
 [testenv:venv]
 commands = {posargs}