We want to default to running all tox environments under python 3, so set the basepython value in each environment. We do not want to specify a minor version number, because we do not want to have to update the file every time we upgrade python. We do not want to set the override once in testenv, because that breaks the more specific versions used in default environments like py35 and py36. Change-Id: If1575ac4d8250bec1f445de7cb0ebcb398bd4e8d Signed-off-by: Doug Hellmann <doug@doughellmann.com>
412 lines
16 KiB
Python
412 lines
16 KiB
Python
# Copyright 2015 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 six.moves import range
|
|
import time
|
|
|
|
import botocore.exceptions
|
|
from oslo_log import log
|
|
from tempest.lib.common.utils import data_utils
|
|
from tempest.lib import decorators
|
|
|
|
from ec2api_tempest_plugin import base
|
|
from ec2api_tempest_plugin import config
|
|
from ec2api_tempest_plugin.scenario import base as scenario_base
|
|
|
|
CONF = config.CONF
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
class TagsPagingTest(scenario_base.BaseScenarioTest):
|
|
|
|
# NOTE(andrey-mp): limit for tags for one resource in amazon
|
|
TAGS_COUNT = 10
|
|
|
|
@classmethod
|
|
@base.safe_setup
|
|
def setUpClass(cls):
|
|
super(TagsPagingTest, cls).setUpClass()
|
|
if 'amazon' in CONF.aws.ec2_url:
|
|
raise cls.skipException('Paging is broken in Amazon.')
|
|
|
|
def _create_volume_and_tags(self):
|
|
data = self.client.create_volume(
|
|
Size=1, AvailabilityZone=CONF.aws.aws_zone)
|
|
volume_id = data['VolumeId']
|
|
self.addResourceCleanUp(self.client.delete_volume, VolumeId=volume_id)
|
|
self.get_volume_waiter().wait_available(volume_id)
|
|
|
|
keys = list()
|
|
for dummy in range(0, self.TAGS_COUNT):
|
|
key = data_utils.rand_name('key')
|
|
value = 'aaa' if dummy < 6 else 'bbb'
|
|
data = self.client.create_tags(Resources=[volume_id],
|
|
Tags=[{'Key': key, 'Value': value}])
|
|
keys.append(key)
|
|
|
|
return volume_id, keys
|
|
|
|
@decorators.idempotent_id('8df6e612-07cd-466d-99de-9f37954a6c9a')
|
|
def test_simple_tags_paging_with_many_results(self):
|
|
volume_id = self._create_volume_and_tags()[0]
|
|
|
|
data = self.client.describe_tags(MaxResults=500,
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]}])
|
|
self.assertNotIn('NextToken', data)
|
|
self.assertNotEmpty(data['Tags'])
|
|
self.assertEqual(self.TAGS_COUNT, len(data['Tags']))
|
|
|
|
@decorators.idempotent_id('683883d5-9a94-43f2-a1eb-d193db0e44e9')
|
|
def test_simple_tags_paging_with_min_results(self):
|
|
volume_id = self._create_volume_and_tags()[0]
|
|
|
|
data = self.client.describe_tags(
|
|
MaxResults=5,
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
|
|
{'Name': 'tag-value', 'Values': ['aaa']}])
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Tags'])
|
|
|
|
@decorators.idempotent_id('1db8cc5a-d0b3-4e5f-b411-d84cfa4f21e0')
|
|
def test_tags_paging_second_page_only_with_token(self):
|
|
volume_id = self._create_volume_and_tags()[0]
|
|
|
|
data = self.client.describe_tags(
|
|
MaxResults=5,
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
|
|
{'Name': 'tag-value', 'Values': ['aaa']}])
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Tags'])
|
|
data = self.client.describe_tags(
|
|
NextToken=data['NextToken'],
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
|
|
{'Name': 'tag-value', 'Values': ['aaa']}])
|
|
self.assertNotIn('NextToken', data)
|
|
self.assertNotEmpty(data['Tags'])
|
|
|
|
@decorators.idempotent_id('a4d7b315-9616-4f9e-85b7-0f892e09a9a2')
|
|
def test_tags_paging_with_const_filter(self):
|
|
volume_id = self._create_volume_and_tags()[0]
|
|
|
|
data = self.client.describe_tags(
|
|
MaxResults=5,
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
|
|
{'Name': 'tag-value', 'Values': ['aaa']}])
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Tags'])
|
|
data = self.client.describe_tags(
|
|
MaxResults=5, NextToken=data['NextToken'],
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
|
|
{'Name': 'tag-value', 'Values': ['aaa']}])
|
|
self.assertNotIn('NextToken', data)
|
|
self.assertNotEmpty(data['Tags'])
|
|
|
|
@decorators.idempotent_id('ad4b793a-8231-4d30-8c26-43736b7b71e4')
|
|
def test_tags_paging_with_differenet_filters(self):
|
|
volume_id = self._create_volume_and_tags()[0]
|
|
|
|
data = self.client.describe_tags(
|
|
MaxResults=5,
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
|
|
{'Name': 'tag-value', 'Values': ['aaa']}])
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Tags'])
|
|
data = self.client.describe_tags(
|
|
MaxResults=5, NextToken=data['NextToken'],
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]}])
|
|
self.assertNotEmpty(data['Tags'])
|
|
self.assertLessEqual(1, len(data['Tags']))
|
|
|
|
@decorators.idempotent_id('ec6d68bb-37f3-4c5c-b4c5-000d73fbc1bf')
|
|
def test_tags_paging_with_tags_deletion(self):
|
|
volume_id, keys = self._create_volume_and_tags()
|
|
|
|
data = self.client.describe_tags(MaxResults=5,
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]}])
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Tags'])
|
|
for key in keys:
|
|
self.client.delete_tags(Resources=[volume_id], Tags=[{'Key': key}])
|
|
data = self.client.describe_tags(
|
|
MaxResults=5, NextToken=data['NextToken'],
|
|
Filters=[{'Name': 'resource-id', 'Values': [volume_id]}])
|
|
self.assertNotIn('NextToken', data)
|
|
self.assertEmpty(data['Tags'])
|
|
|
|
@decorators.idempotent_id('37eb0597-998f-4744-8462-d56e5599dcd8')
|
|
def test_invalid_max_results(self):
|
|
self.assertRaises('InvalidParameterValue',
|
|
self.client.describe_tags, MaxResults=4)
|
|
|
|
# NOTE(andrey-mp): value more than 1000 in not invalid
|
|
# but amazon returns 1000 elements
|
|
self.client.describe_tags(MaxResults=1100)
|
|
|
|
|
|
class VolumesPagingTest(scenario_base.BaseScenarioTest):
|
|
|
|
VOLUMES_COUNT = 6
|
|
|
|
@classmethod
|
|
@base.safe_setup
|
|
def setUpClass(cls):
|
|
super(VolumesPagingTest, cls).setUpClass()
|
|
if 'amazon' in CONF.aws.ec2_url:
|
|
raise cls.skipException('Paging is broken in Amazon.')
|
|
|
|
zone = CONF.aws.aws_zone
|
|
cls.ids = list()
|
|
for dummy in range(0, cls.VOLUMES_COUNT):
|
|
data = cls.client.create_volume(Size=1, AvailabilityZone=zone)
|
|
volume_id = data['VolumeId']
|
|
cls.addResourceCleanUpStatic(cls.client.delete_volume,
|
|
VolumeId=volume_id)
|
|
cls.ids.append(volume_id)
|
|
for volume_id in cls.ids:
|
|
cls.get_volume_waiter().wait_available(volume_id)
|
|
|
|
@decorators.idempotent_id('d44ea940-d9ae-42a4-b3ce-add296a1678c')
|
|
def test_simple_volumes_paging_with_many_results(self):
|
|
data = self.client.describe_volumes(MaxResults=500)
|
|
self.assertNotIn('NextToken', data)
|
|
self.assertNotEmpty(data['Volumes'])
|
|
self.assertLessEqual(self.VOLUMES_COUNT, len(data['Volumes']))
|
|
|
|
@decorators.idempotent_id('9780c871-ee90-411c-b6ec-1e2f1785926b')
|
|
def test_simple_volumes_paging_with_min_results(self):
|
|
data = self.client.describe_volumes(MaxResults=5)
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Volumes'])
|
|
|
|
@decorators.idempotent_id('692684c4-62bc-457a-899a-07cc5382c9ab')
|
|
def test_volumes_paging_second_page(self):
|
|
data = self.client.describe_volumes(MaxResults=5)
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Volumes'])
|
|
data = self.client.describe_volumes(
|
|
MaxResults=5, NextToken=data['NextToken'])
|
|
self.assertNotIn('NextToken', data)
|
|
self.assertNotEmpty(data['Volumes'])
|
|
|
|
@decorators.idempotent_id('83183fac-bb9b-4c36-8d23-84ed55c57015')
|
|
def test_invalid_paging(self):
|
|
self.assertRaises('InvalidParameterValue',
|
|
self.client.describe_volumes, MaxResults=4)
|
|
|
|
self.assertRaises('InvalidParameterCombination',
|
|
self.client.describe_volumes,
|
|
MaxResults=5, VolumeIds=[self.ids[0]])
|
|
|
|
@decorators.idempotent_id('2a777d78-9f0b-4ab0-a841-73dbaafae0dd')
|
|
def test_volumes_paging_with_filters(self):
|
|
data = self.client.describe_volumes(MaxResults=5,
|
|
Filters=[{'Name': 'volume-id', 'Values': [self.ids[0]]}])
|
|
self.assertNotEmpty(data['Volumes'])
|
|
if 'NextToken' in data:
|
|
# Amazon way
|
|
data = self.client.describe_volumes(
|
|
MaxResults=5, NextToken=data['NextToken'],
|
|
Filters=[{'Name': 'volume-id', 'Values': [self.ids[0]]}])
|
|
self.assertNotIn('NextToken', data)
|
|
self.assertEmpty(data['Volumes'])
|
|
|
|
data = self.client.describe_volumes(MaxResults=5,
|
|
Filters=[{'Name': 'volume-id', 'Values': ['vol-*']}])
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Volumes'])
|
|
data = self.client.describe_volumes(
|
|
MaxResults=5, NextToken=data['NextToken'],
|
|
Filters=[{'Name': 'volume-id', 'Values': ['vol-*']}])
|
|
self.assertNotEmpty(data['Volumes'])
|
|
|
|
|
|
class SnapshotPagingTest(scenario_base.BaseScenarioTest):
|
|
|
|
SNAPSHOTS_COUNT = 6
|
|
|
|
@classmethod
|
|
@base.safe_setup
|
|
def setUpClass(cls):
|
|
super(SnapshotPagingTest, cls).setUpClass()
|
|
if 'amazon' in CONF.aws.ec2_url:
|
|
raise cls.skipException('Paging is broken in Amazon.')
|
|
|
|
zone = CONF.aws.aws_zone
|
|
|
|
data = cls.client.create_volume(Size=1, AvailabilityZone=zone)
|
|
volume_id = data['VolumeId']
|
|
cls.addResourceCleanUpStatic(cls.client.delete_volume,
|
|
VolumeId=volume_id)
|
|
cls.get_volume_waiter().wait_available(volume_id)
|
|
|
|
def _create_snapshot():
|
|
try:
|
|
return cls.client.create_snapshot(VolumeId=volume_id)
|
|
except botocore.exceptions.ClientError as e:
|
|
code = (e.response.get('ResponseMetadata', {})
|
|
.get('HTTPStatusCode'))
|
|
if not code or code != 500:
|
|
raise
|
|
|
|
waiter = base.EC2Waiter(_create_snapshot)
|
|
cls.ids = list()
|
|
while len(cls.ids) < cls.SNAPSHOTS_COUNT:
|
|
time.sleep(10)
|
|
data = waiter.wait_for_result()
|
|
snapshot_id = data['SnapshotId']
|
|
cls.addResourceCleanUpStatic(cls.client.delete_snapshot,
|
|
SnapshotId=snapshot_id)
|
|
cls.get_snapshot_waiter().wait_available(snapshot_id,
|
|
final_set=('completed'))
|
|
cls.ids.append(snapshot_id)
|
|
|
|
@decorators.idempotent_id('f44729b1-42d7-4f18-b5e0-f8dc2a03e624')
|
|
def test_simple_snapshots_paging_with_many_results(self):
|
|
data = self.client.describe_snapshots(MaxResults=500,
|
|
OwnerIds=['self'])
|
|
self.assertNotEmpty(data['Snapshots'])
|
|
count = 0
|
|
for s in data['Snapshots']:
|
|
if s['SnapshotId'] in self.ids:
|
|
count += 1
|
|
self.assertEqual(self.SNAPSHOTS_COUNT, count)
|
|
|
|
@decorators.idempotent_id('3146c81d-84c0-4817-9318-328f92bece7f')
|
|
def test_simple_snapshots_paging_with_min_results(self):
|
|
data = self.client.describe_snapshots(MaxResults=5, OwnerIds=['self'])
|
|
self.assertIn('NextToken', data)
|
|
self.assertNotEmpty(data['Snapshots'])
|
|
|
|
@decorators.idempotent_id('fef90b60-0a46-4802-a822-98ccb58ff18c')
|
|
def test_snapshots_paging(self):
|
|
count = 0
|
|
max_results = 5
|
|
kwargs = {'MaxResults': max_results, 'OwnerIds': ['self']}
|
|
while True:
|
|
data = self.client.describe_snapshots(*[], **kwargs)
|
|
self.assertGreaterEqual(max_results, len(data['Snapshots']))
|
|
for s in data['Snapshots']:
|
|
if s['SnapshotId'] in self.ids:
|
|
count += 1
|
|
if 'NextToken' not in data:
|
|
break
|
|
kwargs['NextToken'] = data['NextToken']
|
|
|
|
self.assertEqual(self.SNAPSHOTS_COUNT, count)
|
|
|
|
@decorators.idempotent_id('8379d875-2979-4573-858f-2fd331ae992c')
|
|
def test_invalid_paging(self):
|
|
self.assertRaises('InvalidParameterValue',
|
|
self.client.describe_snapshots, MaxResults=4)
|
|
|
|
self.assertRaises('InvalidParameterCombination',
|
|
self.client.describe_snapshots,
|
|
MaxResults=5, SnapshotIds=[self.ids[0]])
|
|
|
|
|
|
class InstancePagingTest(scenario_base.BaseScenarioTest):
|
|
|
|
RESERVATIONS_COUNT = 2
|
|
INSTANCES_IN_RESERVATIONS_COUNT = 3
|
|
|
|
@classmethod
|
|
@base.safe_setup
|
|
def setUpClass(cls):
|
|
super(InstancePagingTest, cls).setUpClass()
|
|
if 'amazon' in CONF.aws.ec2_url:
|
|
raise cls.skipException('Paging is broken in Amazon.')
|
|
if not CONF.aws.image_id:
|
|
raise cls.skipException('aws image_id does not provided')
|
|
|
|
cls.ids = list()
|
|
cls.reservation_ids = list()
|
|
kwargs = {
|
|
'ImageId': CONF.aws.image_id,
|
|
'InstanceType': CONF.aws.instance_type,
|
|
'Placement': {'AvailabilityZone': CONF.aws.aws_zone},
|
|
'MinCount': cls.INSTANCES_IN_RESERVATIONS_COUNT,
|
|
'MaxCount': cls.INSTANCES_IN_RESERVATIONS_COUNT
|
|
}
|
|
for dummy in range(0, cls.RESERVATIONS_COUNT):
|
|
data = cls.client.run_instances(*[], **kwargs)
|
|
for instance in data['Instances']:
|
|
cls.ids.append(instance['InstanceId'])
|
|
cls.reservation_ids.append(data['ReservationId'])
|
|
|
|
cls.addResourceCleanUpStatic(cls.client.terminate_instances,
|
|
InstanceIds=cls.ids)
|
|
for instance_id in cls.ids:
|
|
cls.get_instance_waiter().wait_available(instance_id,
|
|
final_set=('running'))
|
|
|
|
@decorators.idempotent_id('703da498-c73f-4fd1-a2be-2feddb5292d0')
|
|
def test_simple_instances_paging_with_many_results(self):
|
|
data = self.client.describe_instances(MaxResults=500)
|
|
self.assertNotIn('NextToken', data)
|
|
self.assertNotEmpty(data['Reservations'])
|
|
rcount = 0
|
|
for r in data['Reservations']:
|
|
if r['ReservationId'] in self.reservation_ids:
|
|
rcount += 1
|
|
self.assertEqual(self.RESERVATIONS_COUNT, rcount)
|
|
count = self.RESERVATIONS_COUNT * self.INSTANCES_IN_RESERVATIONS_COUNT
|
|
instances = set()
|
|
self._collect_own_instances(data, instances)
|
|
self.assertEqual(count, len(instances))
|
|
|
|
@decorators.idempotent_id('f494a2a8-6d75-4ef4-ae15-ac4fd1269107')
|
|
def test_simple_instances_paging_with_min_results(self):
|
|
max_results = 5
|
|
data = self.client.describe_instances(MaxResults=max_results)
|
|
self.assertIn('NextToken', data)
|
|
self.assertEqual(max_results, self._count_instances(data))
|
|
|
|
@decorators.idempotent_id('429802be-d599-4732-a310-3ffe8274df54')
|
|
def test_instances_paging(self):
|
|
max_results = 5
|
|
kwargs = {'MaxResults': max_results}
|
|
instances = set()
|
|
while True:
|
|
data = self.client.describe_instances(*[], **kwargs)
|
|
self.assertGreaterEqual(max_results, self._count_instances(data))
|
|
self._collect_own_instances(data, instances)
|
|
if 'NextToken' not in data:
|
|
break
|
|
kwargs['NextToken'] = data['NextToken']
|
|
|
|
count = self.RESERVATIONS_COUNT * self.INSTANCES_IN_RESERVATIONS_COUNT
|
|
self.assertEqual(count, len(instances))
|
|
|
|
@decorators.idempotent_id('061d564d-6d3a-44a8-bec9-9dba04f6f362')
|
|
def test_invalid_paging(self):
|
|
self.assertRaises('InvalidParameterValue',
|
|
self.client.describe_instances, MaxResults=4)
|
|
|
|
self.assertRaises('InvalidParameterCombination',
|
|
self.client.describe_instances,
|
|
MaxResults=5, InstanceIds=[self.ids[0]])
|
|
|
|
def _collect_own_instances(self, data, instances):
|
|
for reservation in data['Reservations']:
|
|
for instance in reservation['Instances']:
|
|
if instance['InstanceId'] in self.ids:
|
|
instances.add(instance['InstanceId'])
|
|
|
|
def _count_instances(self, data):
|
|
count = 0
|
|
for reservation in data['Reservations']:
|
|
count += len(reservation['Instances'])
|
|
return count
|