Merge "port some server tests into nova v3 part1"
diff --git a/tempest/api/compute/v3/servers/test_create_server.py b/tempest/api/compute/v3/servers/test_create_server.py
new file mode 100644
index 0000000..24ade96
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_create_server.py
@@ -0,0 +1,130 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import base64
+
+import netaddr
+import testtools
+
+from tempest.api import compute
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest.common.utils.linux.remote_client import RemoteClient
+import tempest.config
+from tempest.test import attr
+
+
+class ServersTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+    run_ssh = tempest.config.TempestConfig().compute.run_ssh
+    disk_config = 'AUTO'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServersTestJSON, cls).setUpClass()
+        cls.meta = {'hello': 'world'}
+        cls.accessIPv4 = '1.1.1.1'
+        cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2'
+        cls.name = data_utils.rand_name('server')
+        file_contents = 'This is a test file.'
+        personality = [{'path': '/test.txt',
+                       'contents': base64.b64encode(file_contents)}]
+        cls.client = cls.servers_client
+        cli_resp = cls.create_test_server(name=cls.name,
+                                          meta=cls.meta,
+                                          accessIPv4=cls.accessIPv4,
+                                          accessIPv6=cls.accessIPv6,
+                                          personality=personality,
+                                          disk_config=cls.disk_config)
+        cls.resp, cls.server_initial = cli_resp
+        cls.password = cls.server_initial['adminPass']
+        cls.client.wait_for_server_status(cls.server_initial['id'], 'ACTIVE')
+        resp, cls.server = cls.client.get_server(cls.server_initial['id'])
+
+    @attr(type='smoke')
+    def test_create_server_response(self):
+        # Check that the required fields are returned with values
+        self.assertEqual(202, self.resp.status)
+        self.assertTrue(self.server_initial['id'] is not None)
+        self.assertTrue(self.server_initial['adminPass'] is not None)
+
+    @attr(type='smoke')
+    def test_verify_server_details(self):
+        # Verify the specified server attributes are set correctly
+        self.assertEqual(self.accessIPv4, self.server['accessIPv4'])
+        # NOTE(maurosr): See http://tools.ietf.org/html/rfc5952 (section 4)
+        # Here we compare directly with the canonicalized format.
+        self.assertEqual(self.server['accessIPv6'],
+                         str(netaddr.IPAddress(self.accessIPv6)))
+        self.assertEqual(self.name, self.server['name'])
+        self.assertEqual(self.image_ref, self.server['image']['id'])
+        self.assertEqual(self.flavor_ref, self.server['flavor']['id'])
+        self.assertEqual(self.meta, self.server['metadata'])
+
+    @attr(type='smoke')
+    def test_list_servers(self):
+        # The created server should be in the list of all servers
+        resp, body = self.client.list_servers()
+        servers = body['servers']
+        found = any([i for i in servers if i['id'] == self.server['id']])
+        self.assertTrue(found)
+
+    @attr(type='smoke')
+    def test_list_servers_with_detail(self):
+        # The created server should be in the detailed list of all servers
+        resp, body = self.client.list_servers_with_detail()
+        servers = body['servers']
+        found = any([i for i in servers if i['id'] == self.server['id']])
+        self.assertTrue(found)
+
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @attr(type='gate')
+    def test_can_log_into_created_server(self):
+        # Check that the user can authenticate with the generated password
+        linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+        self.assertTrue(linux_client.can_authenticate())
+
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @attr(type='gate')
+    def test_verify_created_server_vcpus(self):
+        # Verify that the number of vcpus reported by the instance matches
+        # the amount stated by the flavor
+        resp, flavor = self.flavors_client.get_flavor_details(self.flavor_ref)
+        linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+        self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
+
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @attr(type='gate')
+    def test_host_name_is_same_as_server_name(self):
+        # Verify the instance host name is the same as the server name
+        linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+        self.assertTrue(linux_client.hostname_equals_servername(self.name))
+
+
+class ServersTestManualDisk(ServersTestJSON):
+    disk_config = 'MANUAL'
+
+    @classmethod
+    def setUpClass(cls):
+        if not compute.DISK_CONFIG_ENABLED:
+            msg = "DiskConfig extension not enabled."
+            raise cls.skipException(msg)
+        super(ServersTestManualDisk, cls).setUpClass()
+
+
+class ServersTestXML(ServersTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_multiple_create.py b/tempest/api/compute/v3/servers/test_multiple_create.py
new file mode 100644
index 0000000..080bd1a
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_multiple_create.py
@@ -0,0 +1,95 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class MultipleCreateTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+    _name = 'multiple-create-test'
+
+    def _generate_name(self):
+        return data_utils.rand_name(self._name)
+
+    def _create_multiple_servers(self, name=None, wait_until=None, **kwargs):
+        """
+        This is the right way to create_multiple servers and manage to get the
+        created servers into the servers list to be cleaned up after all.
+        """
+        kwargs['name'] = kwargs.get('name', self._generate_name())
+        resp, body = self.create_test_server(**kwargs)
+
+        return resp, body
+
+    @attr(type='gate')
+    def test_multiple_create(self):
+        resp, body = self._create_multiple_servers(wait_until='ACTIVE',
+                                                   min_count=1,
+                                                   max_count=2)
+        # NOTE(maurosr): do status response check and also make sure that
+        # reservation_id is not in the response body when the request send
+        # contains return_reservation_id=False
+        self.assertEqual('202', resp['status'])
+        self.assertNotIn('reservation_id', body)
+
+    @attr(type=['negative', 'gate'])
+    def test_min_count_less_than_one(self):
+        invalid_min_count = 0
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=invalid_min_count)
+
+    @attr(type=['negative', 'gate'])
+    def test_min_count_non_integer(self):
+        invalid_min_count = 2.5
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=invalid_min_count)
+
+    @attr(type=['negative', 'gate'])
+    def test_max_count_less_than_one(self):
+        invalid_max_count = 0
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          max_count=invalid_max_count)
+
+    @attr(type=['negative', 'gate'])
+    def test_max_count_non_integer(self):
+        invalid_max_count = 2.5
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          max_count=invalid_max_count)
+
+    @attr(type=['negative', 'gate'])
+    def test_max_count_less_than_min_count(self):
+        min_count = 3
+        max_count = 2
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=min_count,
+                          max_count=max_count)
+
+    @attr(type='gate')
+    def test_multiple_create_with_reservation_return(self):
+        resp, body = self._create_multiple_servers(wait_until='ACTIVE',
+                                                   min_count=1,
+                                                   max_count=2,
+                                                   return_reservation_id=True)
+        self.assertEqual(resp['status'], '202')
+        self.assertIn('reservation_id', body)
+
+
+class MultipleCreateTestXML(MultipleCreateTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_servers.py b/tempest/api/compute/v3/servers/test_servers.py
new file mode 100644
index 0000000..d72476d
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_servers.py
@@ -0,0 +1,133 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest.test import attr
+
+
+class ServersTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServersTestJSON, cls).setUpClass()
+        cls.client = cls.servers_client
+
+    def tearDown(self):
+        self.clear_servers()
+        super(ServersTestJSON, self).tearDown()
+
+    @attr(type='gate')
+    def test_create_server_with_admin_password(self):
+        # If an admin password is provided on server creation, the server's
+        # root password should be set to that password.
+        resp, server = self.create_test_server(adminPass='testpassword')
+
+        # Verify the password is set correctly in the response
+        self.assertEqual('testpassword', server['adminPass'])
+
+    @attr(type='gate')
+    def test_create_with_existing_server_name(self):
+        # Creating a server with a name that already exists is allowed
+
+        # TODO(sdague): clear out try, we do cleanup one layer up
+        server_name = data_utils.rand_name('server')
+        resp, server = self.create_test_server(name=server_name,
+                                               wait_until='ACTIVE')
+        id1 = server['id']
+        resp, server = self.create_test_server(name=server_name,
+                                               wait_until='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)
+
+    @attr(type='gate')
+    def test_create_specify_keypair(self):
+        # Specify a keypair while creating a server
+
+        key_name = data_utils.rand_name('key')
+        resp, keypair = self.keypairs_client.create_keypair(key_name)
+        resp, body = self.keypairs_client.list_keypairs()
+        resp, server = self.create_test_server(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'])
+
+    @attr(type='gate')
+    def test_update_server_name(self):
+        # The server name should be changed to the the provided value
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+
+        # Update the server with a new name
+        resp, server = self.client.update_server(server['id'],
+                                                 name='newname')
+        self.assertEqual(200, resp.status)
+        self.client.wait_for_server_status(server['id'], 'ACTIVE')
+
+        # Verify the name of the server has changed
+        resp, server = self.client.get_server(server['id'])
+        self.assertEqual('newname', server['name'])
+
+    @attr(type='gate')
+    def test_update_access_server_address(self):
+        # The server's access addresses should reflect the provided values
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+
+        # Update the IPv4 and IPv6 access addresses
+        resp, body = self.client.update_server(server['id'],
+                                               accessIPv4='1.1.1.1',
+                                               accessIPv6='::babe:202:202')
+        self.assertEqual(200, resp.status)
+        self.client.wait_for_server_status(server['id'], 'ACTIVE')
+
+        # Verify the access addresses have been updated
+        resp, server = self.client.get_server(server['id'])
+        self.assertEqual('1.1.1.1', server['accessIPv4'])
+        self.assertEqual('::babe:202:202', server['accessIPv6'])
+
+    @attr(type='gate')
+    def test_delete_server_while_in_building_state(self):
+        # Delete a server while it's VM state is Building
+        resp, server = self.create_test_server(wait_until='BUILD')
+        resp, _ = self.client.delete_server(server['id'])
+        self.assertEqual('204', resp['status'])
+
+    @attr(type='gate')
+    def test_delete_active_server(self):
+        # Delete a server while it's VM state is Active
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+        resp, _ = self.client.delete_server(server['id'])
+        self.assertEqual('204', resp['status'])
+
+    @attr(type='gate')
+    def test_create_server_with_ipv6_addr_only(self):
+        # Create a server without an IPv4 address(only IPv6 address).
+        resp, server = self.create_test_server(accessIPv6='2001:2001::3')
+        self.assertEqual('202', resp['status'])
+        self.client.wait_for_server_status(server['id'], 'ACTIVE')
+        resp, server = self.client.get_server(server['id'])
+        self.assertEqual('2001:2001::3', server['accessIPv6'])
+
+
+class ServersTestXML(ServersTestJSON):
+    _interface = 'xml'