blob: 8d689866564e65d2c67a7ed0e2ccf01b4be146d0 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Jay Pipes13b479b2012-06-11 14:52:27 -04002# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
David Kranzcf0040c2012-06-26 09:46:56 -040016import time
Jay Pipesf38eaac2012-06-21 13:37:35 -040017
Doug Hellmann583ce2c2015-03-11 14:55:46 +000018from oslo_log import log as logging
Matthew Treinish01472ff2015-02-20 17:26:52 -050019from tempest_lib import exceptions as lib_exc
20
Joseph Lanouxb3e1f872015-01-30 11:13:07 +000021from tempest.common import compute
Fei Long Wangd39431f2015-05-14 11:30:48 +120022from tempest.common.utils import data_utils
Ken'ichi Ohmichi8b9c7802015-07-08 05:57:37 +000023from tempest.common import waiters
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000024from tempest import config
David Kranz33138312013-09-24 17:09:32 -040025from tempest import exceptions
Attila Fazekasdc216422013-01-29 15:12:14 +010026import tempest.test
Jay Pipesf38eaac2012-06-21 13:37:35 -040027
Matthew Treinishb0a78fc2014-01-29 16:49:12 +000028CONF = config.CONF
Tiago Melloeda03b52012-08-22 23:47:29 -030029
Jay Pipesf38eaac2012-06-21 13:37:35 -040030LOG = logging.getLogger(__name__)
Daryl Walleckc7251962012-03-12 17:26:54 -050031
32
Attila Fazekasdc216422013-01-29 15:12:14 +010033class BaseComputeTest(tempest.test.BaseTestCase):
Sean Daguef237ccb2013-01-04 15:19:14 -050034 """Base test case class for all Compute API tests."""
Daryl Walleckc7251962012-03-12 17:26:54 -050035
Ken'ichi Ohmichi9f5adf82014-12-12 04:01:32 +000036 _api_version = 2
Attila Fazekas430dae32013-10-17 15:19:32 +020037 force_tenant_isolation = False
Chris Yeoh8a79b9d2013-01-18 19:32:47 +103038
Andrea Frittolib21de6c2015-02-06 20:12:38 +000039 # TODO(andreaf) We should care also for the alt_manager here
40 # but only once client lazy load in the manager is done
41 credentials = ['primary']
42
Jay Pipesf38eaac2012-06-21 13:37:35 -040043 @classmethod
Emily Hugenbruche7991d92014-12-12 16:53:36 +000044 def skip_checks(cls):
45 super(BaseComputeTest, cls).skip_checks()
Matthew Treinishf8ff3582015-08-25 12:41:56 -040046 if not CONF.service_available.nova:
47 raise cls.skipException("Nova is not available")
Emily Hugenbruche7991d92014-12-12 16:53:36 +000048 if cls._api_version != 2:
49 msg = ("Unexpected API version is specified (%s)" %
50 cls._api_version)
51 raise exceptions.InvalidConfiguration(message=msg)
Jay Pipesf38eaac2012-06-21 13:37:35 -040052
Emily Hugenbruche7991d92014-12-12 16:53:36 +000053 @classmethod
54 def setup_credentials(cls):
55 cls.set_network_resources()
56 super(BaseComputeTest, cls).setup_credentials()
Daryl Walleckc7251962012-03-12 17:26:54 -050057
Emily Hugenbruche7991d92014-12-12 16:53:36 +000058 @classmethod
59 def setup_clients(cls):
60 super(BaseComputeTest, cls).setup_clients()
61 cls.servers_client = cls.os.servers_client
Ken'ichi Ohmichi7ca54b82015-07-07 01:10:26 +000062 cls.server_groups_client = cls.os.server_groups_client
Emily Hugenbruche7991d92014-12-12 16:53:36 +000063 cls.flavors_client = cls.os.flavors_client
64 cls.images_client = cls.os.images_client
65 cls.extensions_client = cls.os.extensions_client
Ken'ichi Ohmichi03af1c52015-07-13 00:28:05 +000066 cls.floating_ip_pools_client = cls.os.floating_ip_pools_client
Emily Hugenbruche7991d92014-12-12 16:53:36 +000067 cls.floating_ips_client = cls.os.floating_ips_client
68 cls.keypairs_client = cls.os.keypairs_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +000069 cls.security_group_rules_client = cls.os.security_group_rules_client
Emily Hugenbruche7991d92014-12-12 16:53:36 +000070 cls.security_groups_client = cls.os.security_groups_client
71 cls.quotas_client = cls.os.quotas_client
72 # NOTE(mriedem): os-quota-class-sets is v2 API only
73 cls.quota_classes_client = cls.os.quota_classes_client
74 # NOTE(mriedem): os-networks is v2 API only
75 cls.networks_client = cls.os.networks_client
76 cls.limits_client = cls.os.limits_client
77 cls.volumes_extensions_client = cls.os.volumes_extensions_client
Gaozexub9c9d6e2015-09-10 17:08:04 +080078 cls.snapshots_extensions_client = cls.os.snapshots_extensions_client
Emily Hugenbruche7991d92014-12-12 16:53:36 +000079 cls.interfaces_client = cls.os.interfaces_client
80 cls.fixed_ips_client = cls.os.fixed_ips_client
81 cls.availability_zone_client = cls.os.availability_zone_client
82 cls.agents_client = cls.os.agents_client
83 cls.aggregates_client = cls.os.aggregates_client
84 cls.services_client = cls.os.services_client
85 cls.instance_usages_audit_log_client = (
86 cls.os.instance_usages_audit_log_client)
87 cls.hypervisor_client = cls.os.hypervisor_client
88 cls.certificates_client = cls.os.certificates_client
89 cls.migrations_client = cls.os.migrations_client
90 cls.security_group_default_rules_client = (
91 cls.os.security_group_default_rules_client)
Ken'ichi Ohmichi2b6012b2015-09-03 01:56:19 +000092 cls.versions_client = cls.os.compute_versions_client
Emily Hugenbruche7991d92014-12-12 16:53:36 +000093
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030094 if CONF.volume_feature_enabled.api_v1:
95 cls.volumes_client = cls.os.volumes_client
96 else:
97 cls.volumes_client = cls.os.volumes_v2_client
98
Emily Hugenbruche7991d92014-12-12 16:53:36 +000099 @classmethod
100 def resource_setup(cls):
101 super(BaseComputeTest, cls).resource_setup()
Matthew Treinishb0a78fc2014-01-29 16:49:12 +0000102 cls.build_interval = CONF.compute.build_interval
103 cls.build_timeout = CONF.compute.build_timeout
104 cls.ssh_user = CONF.compute.ssh_user
105 cls.image_ref = CONF.compute.image_ref
106 cls.image_ref_alt = CONF.compute.image_ref_alt
107 cls.flavor_ref = CONF.compute.flavor_ref
108 cls.flavor_ref_alt = CONF.compute.flavor_ref_alt
109 cls.image_ssh_user = CONF.compute.image_ssh_user
110 cls.image_ssh_password = CONF.compute.image_ssh_password
Jay Pipesf38eaac2012-06-21 13:37:35 -0400111 cls.servers = []
Sean Dagued62bf1c2013-06-05 14:36:25 -0400112 cls.images = []
Zhi Kun Liu02e7a7b2014-01-08 16:08:32 +0800113 cls.security_groups = []
Abhijeet.Jain87dd4452014-04-23 15:51:23 +0530114 cls.server_groups = []
Matthew Treinishf7fca6a2013-12-09 16:27:23 +0000115
Emily Hugenbruche7991d92014-12-12 16:53:36 +0000116 @classmethod
117 def resource_cleanup(cls):
118 cls.clear_images()
119 cls.clear_servers()
120 cls.clear_security_groups()
121 cls.clear_server_groups()
122 super(BaseComputeTest, cls).resource_cleanup()
Ken'ichi Ohmichi543a5d42014-05-02 08:44:15 +0900123
Matthew Treinishf7fca6a2013-12-09 16:27:23 +0000124 @classmethod
Jay Pipes444c3e62012-10-04 19:26:35 -0400125 def clear_servers(cls):
Salvatore1422a9a2014-10-08 15:53:25 +0200126 LOG.debug('Clearing servers: %s', ','.join(
127 server['id'] for server in cls.servers))
Jay Pipes444c3e62012-10-04 19:26:35 -0400128 for server in cls.servers:
Dan Smith74e7bcb2012-08-21 09:18:26 -0700129 try:
130 cls.servers_client.delete_server(server['id'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900131 except lib_exc.NotFound:
Joe Gordon0c335792014-09-23 12:36:11 -0700132 # Something else already cleaned up the server, nothing to be
133 # worried about
Dan Smith74e7bcb2012-08-21 09:18:26 -0700134 pass
Joe Gordon0c335792014-09-23 12:36:11 -0700135 except Exception:
136 LOG.exception('Deleting server %s failed' % server['id'])
Dan Smith74e7bcb2012-08-21 09:18:26 -0700137
Jay Pipes444c3e62012-10-04 19:26:35 -0400138 for server in cls.servers:
Dan Smith74e7bcb2012-08-21 09:18:26 -0700139 try:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000140 waiters.wait_for_server_termination(cls.servers_client,
141 server['id'])
Dan Smith74e7bcb2012-08-21 09:18:26 -0700142 except Exception:
Joe Gordon0c335792014-09-23 12:36:11 -0700143 LOG.exception('Waiting for deletion of server %s failed'
144 % server['id'])
Dan Smith74e7bcb2012-08-21 09:18:26 -0700145
146 @classmethod
Attila Fazekas305e65b2013-10-29 13:23:07 +0100147 def server_check_teardown(cls):
148 """Checks is the shared server clean enough for subsequent test.
149 Method will delete the server when it's dirty.
150 The setUp method is responsible for creating a new server.
151 Exceptions raised in tearDown class are fails the test case,
152 This method supposed to use only by tierDown methods, when
153 the shared server_id is stored in the server_id of the class.
154 """
155 if getattr(cls, 'server_id', None) is not None:
156 try:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000157 waiters.wait_for_server_status(cls.servers_client,
158 cls.server_id, 'ACTIVE')
Attila Fazekas305e65b2013-10-29 13:23:07 +0100159 except Exception as exc:
160 LOG.exception(exc)
161 cls.servers_client.delete_server(cls.server_id)
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000162 waiters.wait_for_server_termination(cls.servers_client,
163 cls.server_id)
Attila Fazekas305e65b2013-10-29 13:23:07 +0100164 cls.server_id = None
165 raise
166
167 @classmethod
Sean Dagued62bf1c2013-06-05 14:36:25 -0400168 def clear_images(cls):
Salvatore1422a9a2014-10-08 15:53:25 +0200169 LOG.debug('Clearing images: %s', ','.join(cls.images))
Sean Dagued62bf1c2013-06-05 14:36:25 -0400170 for image_id in cls.images:
171 try:
172 cls.images_client.delete_image(image_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900173 except lib_exc.NotFound:
David Kranz33138312013-09-24 17:09:32 -0400174 # The image may have already been deleted which is OK.
175 pass
Yair Frieda039f872014-01-02 12:11:10 +0200176 except Exception:
177 LOG.exception('Exception raised deleting image %s' % image_id)
Sean Dagued62bf1c2013-06-05 14:36:25 -0400178
179 @classmethod
Zhi Kun Liu02e7a7b2014-01-08 16:08:32 +0800180 def clear_security_groups(cls):
Salvatore1422a9a2014-10-08 15:53:25 +0200181 LOG.debug('Clearing security groups: %s', ','.join(
182 str(sg['id']) for sg in cls.security_groups))
Zhi Kun Liu02e7a7b2014-01-08 16:08:32 +0800183 for sg in cls.security_groups:
184 try:
David Kranz9964b4e2015-02-06 15:45:29 -0500185 cls.security_groups_client.delete_security_group(sg['id'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900186 except lib_exc.NotFound:
Zhi Kun Liu02e7a7b2014-01-08 16:08:32 +0800187 # The security group may have already been deleted which is OK.
188 pass
189 except Exception as exc:
190 LOG.info('Exception raised deleting security group %s',
191 sg['id'])
192 LOG.exception(exc)
Zhi Kun Liu02e7a7b2014-01-08 16:08:32 +0800193
194 @classmethod
Abhijeet.Jain87dd4452014-04-23 15:51:23 +0530195 def clear_server_groups(cls):
Salvatore1422a9a2014-10-08 15:53:25 +0200196 LOG.debug('Clearing server groups: %s', ','.join(cls.server_groups))
Abhijeet.Jain87dd4452014-04-23 15:51:23 +0530197 for server_group_id in cls.server_groups:
198 try:
Ken'ichi Ohmichi7ca54b82015-07-07 01:10:26 +0000199 cls.server_groups_client.delete_server_group(server_group_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900200 except lib_exc.NotFound:
Abhijeet.Jain87dd4452014-04-23 15:51:23 +0530201 # The server-group may have already been deleted which is OK.
202 pass
203 except Exception:
204 LOG.exception('Exception raised deleting server-group %s',
205 server_group_id)
206
207 @classmethod
Joseph Lanouxb3e1f872015-01-30 11:13:07 +0000208 def create_test_server(cls, validatable=False, **kwargs):
209 """Wrapper utility that returns a test server.
Rohit Karajgidc300b22012-05-04 08:11:00 -0700210
Joseph Lanouxb3e1f872015-01-30 11:13:07 +0000211 This wrapper utility calls the common create test server and
212 returns a test server. The purpose of this wrapper is to minimize
213 the impact on the code of the tests already using this
214 function.
215 """
216 tenant_network = cls.get_tenant_network()
217 body, servers = compute.create_test_server(
218 cls.os,
219 validatable,
220 validation_resources=cls.validation_resources,
221 tenant_network=tenant_network,
222 **kwargs)
Ken'ichi Ohmichi51c8c262013-12-21 03:30:37 +0900223
224 cls.servers.extend(servers)
Sean Dague9b669e32012-12-13 18:40:08 -0500225
David Kranz0fb14292015-02-11 15:55:20 -0500226 return body
Sean Dague9b669e32012-12-13 18:40:08 -0500227
Zhi Kun Liu02e7a7b2014-01-08 16:08:32 +0800228 @classmethod
229 def create_security_group(cls, name=None, description=None):
230 if name is None:
231 name = data_utils.rand_name(cls.__name__ + "-securitygroup")
232 if description is None:
Ken'ichi Ohmichi4937f562015-03-23 00:15:01 +0000233 description = data_utils.rand_name('description')
ghanshyamb610b772015-08-24 17:29:38 +0900234 body = cls.security_groups_client.create_security_group(
235 name=name, description=description)['security_group']
Zhi Kun Liu02e7a7b2014-01-08 16:08:32 +0800236 cls.security_groups.append(body)
237
David Kranz9964b4e2015-02-06 15:45:29 -0500238 return body
Zhi Kun Liu02e7a7b2014-01-08 16:08:32 +0800239
Abhijeet.Jain87dd4452014-04-23 15:51:23 +0530240 @classmethod
Ghanshyam2a180b82014-06-16 13:54:22 +0900241 def create_test_server_group(cls, name="", policy=None):
Abhijeet.Jain87dd4452014-04-23 15:51:23 +0530242 if not name:
243 name = data_utils.rand_name(cls.__name__ + "-Server-Group")
Ghanshyam2a180b82014-06-16 13:54:22 +0900244 if policy is None:
Abhijeet.Jain87dd4452014-04-23 15:51:23 +0530245 policy = ['affinity']
ghanshyam2dc13452015-08-24 17:39:25 +0900246 body = (cls.server_groups_client.create_server_group(name, policy)
247 ['server_group'])
David Kranzda5d4ec2014-06-24 16:04:57 -0400248 cls.server_groups.append(body['id'])
David Kranzae99b9a2015-02-16 13:37:01 -0500249 return body
Abhijeet.Jain87dd4452014-04-23 15:51:23 +0530250
David Kranzcf0040c2012-06-26 09:46:56 -0400251 def wait_for(self, condition):
Sean Daguef237ccb2013-01-04 15:19:14 -0500252 """Repeatedly calls condition() until a timeout."""
David Kranzcf0040c2012-06-26 09:46:56 -0400253 start_time = int(time.time())
254 while True:
255 try:
256 condition()
Matthew Treinish05d9fb92012-12-07 16:14:05 -0500257 except Exception:
David Kranzcf0040c2012-06-26 09:46:56 -0400258 pass
259 else:
260 return
261 if int(time.time()) - start_time >= self.build_timeout:
262 condition()
263 return
264 time.sleep(self.build_interval)
Jay Pipesf38eaac2012-06-21 13:37:35 -0400265
Matt Riedemann807d0562014-01-27 12:03:10 -0800266 @staticmethod
267 def _delete_volume(volumes_client, volume_id):
268 """Deletes the given volume and waits for it to be gone."""
269 try:
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000270 volumes_client.delete_volume(volume_id)
Matt Riedemann807d0562014-01-27 12:03:10 -0800271 # TODO(mriedem): We should move the wait_for_resource_deletion
272 # into the delete_volume method as a convenience to the caller.
273 volumes_client.wait_for_resource_deletion(volume_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900274 except lib_exc.NotFound:
Matt Riedemann807d0562014-01-27 12:03:10 -0800275 LOG.warn("Unable to delete volume '%s' since it was not found. "
276 "Maybe it was already deleted?" % volume_id)
277
Attila Fazekas423834d2014-03-14 17:33:13 +0100278 @classmethod
279 def prepare_instance_network(cls):
Joseph Lanouxffe09dd2015-03-18 16:45:33 +0000280 if (CONF.validation.auth_method != 'disabled' and
281 CONF.validation.connect_method == 'floating'):
Attila Fazekas423834d2014-03-14 17:33:13 +0100282 cls.set_network_resources(network=True, subnet=True, router=True,
283 dhcp=True)
284
ivan-zhu8f992be2013-07-31 14:56:58 +0800285 @classmethod
286 def create_image_from_server(cls, server_id, **kwargs):
287 """Wrapper utility that returns an image created from the server."""
Masayuki Igawa259c1132013-10-31 17:48:44 +0900288 name = data_utils.rand_name(cls.__name__ + "-image")
ivan-zhu8f992be2013-07-31 14:56:58 +0800289 if 'name' in kwargs:
290 name = kwargs.pop('name')
291
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000292 image = cls.images_client.create_image(server_id, name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500293 image_id = data_utils.parse_image_id(image.response['location'])
ivan-zhu8f992be2013-07-31 14:56:58 +0800294 cls.images.append(image_id)
295
296 if 'wait_until' in kwargs:
Ken'ichi Ohmichi8b9c7802015-07-08 05:57:37 +0000297 waiters.wait_for_image_status(cls.images_client,
298 image_id, kwargs['wait_until'])
ghanshyam1756e0b2015-08-18 19:19:05 +0900299 image = cls.images_client.show_image(image_id)['image']
ivan-zhu8f992be2013-07-31 14:56:58 +0800300
Bob Ball621e4602013-12-06 19:53:43 +0000301 if kwargs['wait_until'] == 'ACTIVE':
302 if kwargs.get('wait_for_server', True):
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000303 waiters.wait_for_server_status(cls.servers_client,
304 server_id, 'ACTIVE')
David Kranza5299eb2015-01-15 17:24:05 -0500305 return image
ivan-zhu8f992be2013-07-31 14:56:58 +0800306
307 @classmethod
Joseph Lanouxffe09dd2015-03-18 16:45:33 +0000308 def rebuild_server(cls, server_id, validatable=False, **kwargs):
ivan-zhu8f992be2013-07-31 14:56:58 +0800309 # Destroy an existing server and creates a new one
Matthew Treinish2cd19a42013-12-02 21:54:42 +0000310 if server_id:
311 try:
312 cls.servers_client.delete_server(server_id)
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000313 waiters.wait_for_server_termination(cls.servers_client,
314 server_id)
Yair Frieda039f872014-01-02 12:11:10 +0200315 except Exception:
316 LOG.exception('Failed to delete server %s' % server_id)
Joseph Lanouxffe09dd2015-03-18 16:45:33 +0000317
318 server = cls.create_test_server(
319 validatable,
320 wait_until='ACTIVE',
321 **kwargs)
Ken'ichi Ohmichi9f5adf82014-12-12 04:01:32 +0000322 cls.password = server['adminPass']
Matthew Treinish2cd19a42013-12-02 21:54:42 +0000323 return server['id']
ivan-zhu8f992be2013-07-31 14:56:58 +0800324
Matt Riedemann5dc594c2014-01-27 11:40:28 -0800325 @classmethod
Jesse Keating613b4982015-05-04 15:05:19 -0700326 def delete_server(cls, server_id):
327 """Deletes an existing server and waits for it to be gone."""
328 try:
329 cls.servers_client.delete_server(server_id)
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000330 waiters.wait_for_server_termination(cls.servers_client,
331 server_id)
Jesse Keating613b4982015-05-04 15:05:19 -0700332 except Exception:
333 LOG.exception('Failed to delete server %s' % server_id)
334
335 @classmethod
Matt Riedemann5dc594c2014-01-27 11:40:28 -0800336 def delete_volume(cls, volume_id):
337 """Deletes the given volume and waits for it to be gone."""
Ken'ichi Ohmichi9f5adf82014-12-12 04:01:32 +0000338 cls._delete_volume(cls.volumes_extensions_client, volume_id)
Ken'ichi Ohmichi543a5d42014-05-02 08:44:15 +0900339
Joseph Lanouxffe09dd2015-03-18 16:45:33 +0000340 @classmethod
341 def get_server_ip(cls, server):
342 """Get the server fixed or floating IP.
343
344 For the floating IP, the address created by the validation resources
345 is returned.
346 For the fixed IP, the server is returned and the current mechanism of
347 address extraction in the remote_client is followed.
348 """
349 if CONF.validation.connect_method == 'floating':
350 ip_or_server = cls.validation_resources['floating_ip']['ip']
351 elif CONF.validation.connect_method == 'fixed':
352 ip_or_server = server
353 return ip_or_server
354
Ken'ichi Ohmichi543a5d42014-05-02 08:44:15 +0900355
356class BaseV2ComputeTest(BaseComputeTest):
357 _api_version = 2
Matt Riedemann5dc594c2014-01-27 11:40:28 -0800358
ivan-zhuf2b00502013-10-18 10:06:52 +0800359
Ken'ichi Ohmichibcefa3d2014-05-09 08:14:05 +0900360class BaseComputeAdminTest(BaseComputeTest):
361 """Base test case class for Compute Admin API tests."""
ivan-zhuf2b00502013-10-18 10:06:52 +0800362
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000363 credentials = ['primary', 'admin']
Emily Hugenbruche7991d92014-12-12 16:53:36 +0000364
365 @classmethod
366 def setup_clients(cls):
367 super(BaseComputeAdminTest, cls).setup_clients()
Ken'ichi Ohmichi9f5adf82014-12-12 04:01:32 +0000368 cls.availability_zone_admin_client = (
369 cls.os_adm.availability_zone_client)
ivan-zhu8f992be2013-07-31 14:56:58 +0800370
Ken'ichi Ohmichibcefa3d2014-05-09 08:14:05 +0900371
372class BaseV2ComputeAdminTest(BaseComputeAdminTest):
373 """Base test case class for Compute Admin V2 API tests."""
374 _api_version = 2