Merge "Added tests for servers API as per bug/992299"
diff --git a/tempest/tests/base_compute_test.py b/tempest/tests/base_compute_test.py
index 2436bb0..2b16d8c 100644
--- a/tempest/tests/base_compute_test.py
+++ b/tempest/tests/base_compute_test.py
@@ -1,7 +1,6 @@
 from tempest import exceptions
 from tempest import openstack
-from tempest.config import TempestConfig
-
+from tempest.common.utils.data_utils import rand_name
 import unittest2 as unittest
 
 
@@ -21,6 +20,7 @@
     build_interval = config.compute.build_interval
     build_timeout = config.compute.build_timeout
     ssh_user = config.compute.ssh_user
+    servers = []
 
     # Validate reference data exists
     # If not, attempt to auto-configure
@@ -82,3 +82,16 @@
                     if flavors[i]['ram'] > flavors[0]['ram']:
                         flavor_ref_alt = flavors[i]['id']
                         break
+
+    def create_server(self, image_id=None):
+        """Wrapper utility that returns a test server"""
+        server_name = rand_name('test-vm-')
+        flavor = self.flavor_ref
+        if not image_id:
+            image_id = self.image_ref
+
+        resp, server = self.servers_client.create_server(
+                                                server_name, image_id, flavor)
+        self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
+        self.servers.append(server)
+        return server
diff --git a/tempest/tests/test_list_servers_negative.py b/tempest/tests/test_list_servers_negative.py
index 18030b7..0729e57 100644
--- a/tempest/tests/test_list_servers_negative.py
+++ b/tempest/tests/test_list_servers_negative.py
@@ -39,7 +39,7 @@
         try:
             resp, body = cls.client.list_servers()
             for server in body['servers']:
-                resp, body = cls.client.delete_server(server['id'])
+                resp, body = cls.client.delete_server(server)
         except exceptions.NotFound:
             pass
 
@@ -69,23 +69,11 @@
         servers_needed = server_count - num_of_active_servers
 
         for i in range(0, servers_needed):
-            instance = self.create_instance()
-            active_servers.append(instance)
+            srv = self.create_server()
+            active_servers.append(srv)
 
         return active_servers
 
-    def create_instance(self, image_id=None):
-        name = rand_name('test-vm-')
-        flavor = self.flavor_ref
-
-        if not image_id:
-            image_id = self.image_ref
-
-        body, server = self.client.create_server(name, image_id, flavor)
-        self.client.wait_for_server_status(server['id'], 'ACTIVE')
-        self.servers.append(server['id'])
-        return server
-
     def test_list_servers_when_no_servers_running(self):
         """Return an empty list when there are no active servers"""
         # Delete Active servers
@@ -134,7 +122,7 @@
             self.images_client.wait_for_image_status(snapshot_id, 'ACTIVE')
 
             # Create a server from the snapshot
-            snap_server = self.create_instance(image_id=snapshot_id)
+            snap_server = self.create_server(image_id=snapshot_id)
             self.servers.append(snap_server['id'])
 
             # List base servers by image
@@ -238,7 +226,7 @@
 
     def test_list_servers_by_active_status(self):
         """Return a listing of servers by active status"""
-        self.create_instance()
+        self.create_server()
         resp, body = self.client.list_servers({'status': 'ACTIVE'})
         self.assertEqual('200', resp['status'])
         self.assertTrue(len(body['servers']) > 0)
diff --git a/tempest/tests/test_servers.py b/tempest/tests/test_servers.py
index aab7a96..ec9911f 100644
--- a/tempest/tests/test_servers.py
+++ b/tempest/tests/test_servers.py
@@ -1,8 +1,6 @@
 from nose.plugins.attrib import attr
-from tempest import openstack
 from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
-import base64
 
 
 class ServersTest(BaseComputeTest):
@@ -31,6 +29,53 @@
         finally:
             self.client.delete_server(server['id'])
 
+    def test_create_with_existing_server_name(self):
+        """Creating a server with a name that already exists is allowed"""
+
+        try:
+            server_name = rand_name('server')
+            resp, server = self.client.create_server(server_name,
+                                                    self.image_ref,
+                                                    self.flavor_ref)
+            self.client.wait_for_server_status(server['id'], 'ACTIVE')
+            id1 = server['id']
+            resp, server = self.client.create_server(server_name,
+                                                    self.image_ref,
+                                                    self.flavor_ref)
+            self.client.wait_for_server_status(server['id'], 'ACTIVE')
+            id2 = server['id']
+            self.assertNotEqual(id1, id2, "Did not create a new server")
+            resp, server = self.client.get_server(id1)
+            name1 = server['name']
+            resp, server = self.client.get_server(id2)
+            name2 = server['name']
+            self.assertEqual(name1, name2)
+        finally:
+            for server_id in (id1, id2):
+                if server_id:
+                    self.client.delete_server(server_id)
+
+    @attr(type='smoke')
+    def test_create_specify_keypair(self):
+        """Specify a keypair while creating a server"""
+
+        try:
+            key_name = rand_name('key')
+            resp, keypair = self.keypairs_client.create_keypair(key_name)
+            resp, body = self.keypairs_client.list_keypairs()
+            server_name = rand_name('server')
+            resp, server = self.client.create_server(server_name,
+                                                    self.image_ref,
+                                                    self.flavor_ref,
+                                                    key_name=key_name)
+            self.assertEqual('202', resp['status'])
+            self.client.wait_for_server_status(server['id'], 'ACTIVE')
+            resp, server = self.client.get_server(server['id'])
+            self.assertEqual(key_name, server['key_name'])
+        finally:
+            if server:
+                self.client.delete_server(server['id'])
+
     @attr(type='smoke')
     def test_update_server_name(self):
         """The server name should be changed to the the provided value"""
@@ -80,3 +125,12 @@
         #Teardown
         finally:
             self.client.delete_server(server['id'])
+
+    def test_delete_server_while_in_building_state(self):
+        """Delete a server while it's VM state is Building"""
+        name = rand_name('server')
+        resp, server = self.client.create_server(name, self.image_ref,
+                                                self.flavor_ref)
+        self.client.wait_for_server_status(server['id'], 'BUILD')
+        resp, _ = self.client.delete_server(server['id'])
+        self.assertEqual('204', resp['status'])
diff --git a/tempest/tests/test_servers_negative.py b/tempest/tests/test_servers_negative.py
index d1088f3..87f184f 100644
--- a/tempest/tests/test_servers_negative.py
+++ b/tempest/tests/test_servers_negative.py
@@ -1,8 +1,10 @@
-from tempest import openstack
+import sys
+import unittest2 as unittest
+from nose.plugins.attrib import attr
 from tempest.common.utils.data_utils import rand_name
 from base_compute_test import BaseComputeTest
 from tempest import exceptions
-import tempest.config
+from tempest import openstack
 
 
 class ServersNegativeTest(BaseComputeTest):
@@ -10,17 +12,30 @@
     @classmethod
     def setUpClass(cls):
         cls.client = cls.servers_client
+        cls.img_client = cls.images_client
+        cls.alt_os = openstack.AltManager()
+        cls.alt_client = cls.alt_os.servers_client
 
+    @classmethod
+    def tearDownClass(cls):
+        for server in cls.servers:
+            try:
+                cls.client.delete_server(server['id'])
+            except exceptions.NotFound:
+                continue
+
+    @attr(type='negative')
     def test_server_name_blank(self):
         """Create a server with name parameter empty"""
         try:
-            resp, server = self.client.create_server('', self.image_ref,
-                                                     self.flavor_ref)
+                resp, server = self.client.create_server('', self.image_ref,
+                                                         self.flavor_ref)
         except exceptions.BadRequest:
             pass
         else:
             self.fail('Server name cannot be blank')
 
+    @attr(type='negative')
     def test_personality_file_contents_not_encoded(self):
         """Use an unencoded file when creating a server with personality"""
         file_contents = 'This is a test file.'
@@ -37,6 +52,7 @@
         else:
             self.fail('Unencoded file contents should not be accepted')
 
+    @attr(type='negative')
     def test_create_with_invalid_image(self):
         """Create a server with an unknown image"""
         try:
@@ -47,6 +63,7 @@
         else:
             self.fail('Cannot create a server with an invalid image')
 
+    @attr(type='negative')
     def test_create_with_invalid_flavor(self):
         """Create a server with an unknown flavor"""
         try:
@@ -56,6 +73,7 @@
         else:
             self.fail('Cannot create a server with an invalid flavor')
 
+    @attr(type='negative')
     def test_invalid_access_ip_v4_address(self):
         """An access IPv4 address must match a valid address pattern"""
         accessIPv4 = '1.1.1.1.1.1'
@@ -70,6 +88,7 @@
         else:
             self.fail('Access IPv4 address must match the correct format')
 
+    @attr(type='negative')
     def test_invalid_ip_v6_address(self):
         """An access IPv6 address must match a valid address pattern"""
         accessIPv6 = 'notvalid'
@@ -84,6 +103,7 @@
         else:
             self.fail('Access IPv6 address must match the correct format')
 
+    @attr(type='negative')
     def test_reboot_deleted_server(self):
         """Reboot a deleted server"""
         self.name = rand_name('server')
@@ -99,6 +119,7 @@
         else:
             self.fail('Should not be able to reboot a deleted server')
 
+    @attr(type='negative')
     def test_rebuild_deleted_server(self):
         """Rebuild a deleted server"""
         self.name = rand_name('server')
@@ -114,3 +135,121 @@
             pass
         else:
             self.fail('Should not be able to rebuild a deleted server')
+
+    @attr(type='negative')
+    def test_create_numeric_server_name(self):
+        """Create a server with a numeric name"""
+
+        server_name = 12345
+        self.assertRaises(exceptions.BadRequest, self.client.create_server,
+                          server_name, self.image_ref, self.flavor_ref)
+
+    @attr(type='negative')
+    def test_create_server_name_length_exceeds_256(self):
+        """Create a server with name length exceeding 256 characters"""
+
+        server_name = 'a' * 256
+        self.assertRaises(exceptions.BadRequest, self.client.create_server,
+                          server_name, self.image_ref, self.flavor_ref)
+
+    @attr(type='negative')
+    def test_create_with_invalid_network_uuid(self):
+        """Pass invalid network uuid while creating a server"""
+
+        server_name = rand_name('server')
+        networks = [{'fixed_ip': '10.0.1.1', 'uuid':'a-b-c-d-e-f-g-h-i-j'}]
+
+        self.assertRaises(exceptions.BadRequest, self.client.create_server,
+                         server_name, self.image_ref, self.flavor_ref,
+                         networks=networks)
+
+    @attr(type='negative')
+    def test_create_with_non_existant_keypair(self):
+        """Pass a non existant keypair while creating a server"""
+
+        key_name = rand_name('key')
+        server_name = rand_name('server')
+        self.assertRaises(exceptions.BadRequest, self.client.create_server,
+                        server_name, self.image_ref, self.flavor_ref,
+                        key_name=key_name)
+
+    @unittest.skip("Until Bug 1004007 is fixed")
+    @attr(type='negative')
+    def test_create_server_metadata_exceeds_length_limit(self):
+        """Pass really long metadata while creating a server"""
+
+        server_name = rand_name('server')
+        metadata = {'a': 'b' * 260}
+        self.assertRaises(exceptions.OverLimit, self.client.create_server,
+                        server_name, self.image_ref, self.flavor_ref,
+                        meta=metadata)
+
+    @attr(type='negative')
+    def test_update_name_of_non_existent_server(self):
+        """Update name of a non-existent server"""
+
+        server_name = rand_name('server')
+        new_name = rand_name('server') + '_updated'
+
+        self.assertRaises(exceptions.NotFound, self.client.update_server,
+                        server_name, name=new_name)
+
+    @attr(type='negative')
+    def test_update_server_set_empty_name(self):
+        """Update name of the server to an empty string"""
+
+        server_name = rand_name('server')
+        new_name = ''
+
+        self.assertRaises(exceptions.BadRequest, self.client.update_server,
+                        server_name, name=new_name)
+
+    @attr(type='negative')
+    def test_update_server_of_another_tenant(self):
+        """Update name of a server that belongs to another tenant"""
+
+        server = self.create_server()
+        new_name = server['id'] + '_new'
+        self.assertRaises(exceptions.NotFound,
+                        self.alt_client.update_server, server['id'],
+                        name=new_name)
+
+    @attr(type='negative')
+    def test_update_server_name_length_exceeds_256(self):
+        """Update name of server exceed the name length limit"""
+
+        server = self.create_server()
+        new_name = 'a' * 256
+        self.assertRaises(exceptions.BadRequest,
+                        self.client.update_server, server['id'], name=new_name)
+
+    @attr(type='negative')
+    def test_delete_non_existent_server(self):
+        """Delete a non existent server"""
+
+        self.assertRaises(exceptions.NotFound, self.client.delete_server,
+                        '999erra43')
+
+    @attr(type='negative')
+    def test_delete_a_server_of_another_tenant(self):
+        """Delete a server that belongs to another tenant"""
+
+        server = self.create_server()
+        resp, body = self.client.delete_server(server['id'])
+        self.assertEqual(resp['status'], '204')
+        self.assertRaises(exceptions.NotFound, self.alt_client.delete_server,
+                         server['id'])
+
+    @attr(type='negative')
+    def test_delete_server_pass_negative_id(self):
+        """Pass an invalid string parameter to delete server"""
+
+        self.assertRaises(exceptions.NotFound, self.client.delete_server,
+                        -1)
+
+    @attr(type='negative')
+    def test_delete_server_pass_id_exceeding_length_limit(self):
+        """Pass a server ID that exceeds length limit to delete server"""
+
+        self.assertRaises(exceptions.NotFound, self.client.delete_server,
+                          sys.maxint + 1)