Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
5a9c921d97
132 changed files with 33915 additions and 9581 deletions
|
|
@ -74,6 +74,31 @@ def test_list_certificates():
|
|||
resp['CertificateSummaryList'][0]['DomainName'].should.equal(SERVER_COMMON_NAME)
|
||||
|
||||
|
||||
@mock_acm
|
||||
def test_list_certificates_by_status():
|
||||
client = boto3.client('acm', region_name='eu-central-1')
|
||||
issued_arn = _import_cert(client)
|
||||
pending_arn = client.request_certificate(DomainName='google.com')['CertificateArn']
|
||||
|
||||
resp = client.list_certificates()
|
||||
len(resp['CertificateSummaryList']).should.equal(2)
|
||||
resp = client.list_certificates(CertificateStatuses=['EXPIRED', 'INACTIVE'])
|
||||
len(resp['CertificateSummaryList']).should.equal(0)
|
||||
resp = client.list_certificates(CertificateStatuses=['PENDING_VALIDATION'])
|
||||
len(resp['CertificateSummaryList']).should.equal(1)
|
||||
resp['CertificateSummaryList'][0]['CertificateArn'].should.equal(pending_arn)
|
||||
|
||||
resp = client.list_certificates(CertificateStatuses=['ISSUED'])
|
||||
len(resp['CertificateSummaryList']).should.equal(1)
|
||||
resp['CertificateSummaryList'][0]['CertificateArn'].should.equal(issued_arn)
|
||||
resp = client.list_certificates(CertificateStatuses=['ISSUED', 'PENDING_VALIDATION'])
|
||||
len(resp['CertificateSummaryList']).should.equal(2)
|
||||
arns = {cert['CertificateArn'] for cert in resp['CertificateSummaryList']}
|
||||
arns.should.contain(issued_arn)
|
||||
arns.should.contain(pending_arn)
|
||||
|
||||
|
||||
|
||||
@mock_acm
|
||||
def test_get_invalid_certificate():
|
||||
client = boto3.client('acm', region_name='eu-central-1')
|
||||
|
|
@ -291,6 +316,7 @@ def test_request_certificate():
|
|||
)
|
||||
resp.should.contain('CertificateArn')
|
||||
arn = resp['CertificateArn']
|
||||
arn.should.match(r"arn:aws:acm:eu-central-1:\d{12}:certificate/")
|
||||
|
||||
resp = client.request_certificate(
|
||||
DomainName='google.com',
|
||||
|
|
|
|||
|
|
@ -988,13 +988,30 @@ def test_api_keys():
|
|||
apikey['name'].should.equal(apikey_name)
|
||||
len(apikey['value']).should.equal(40)
|
||||
|
||||
apikey_name = 'TESTKEY3'
|
||||
payload = {'name': apikey_name }
|
||||
response = client.create_api_key(**payload)
|
||||
apikey_id = response['id']
|
||||
|
||||
patch_operations = [
|
||||
{'op': 'replace', 'path': '/name', 'value': 'TESTKEY3_CHANGE'},
|
||||
{'op': 'replace', 'path': '/customerId', 'value': '12345'},
|
||||
{'op': 'replace', 'path': '/description', 'value': 'APIKEY UPDATE TEST'},
|
||||
{'op': 'replace', 'path': '/enabled', 'value': 'false'},
|
||||
]
|
||||
response = client.update_api_key(apiKey=apikey_id, patchOperations=patch_operations)
|
||||
response['name'].should.equal('TESTKEY3_CHANGE')
|
||||
response['customerId'].should.equal('12345')
|
||||
response['description'].should.equal('APIKEY UPDATE TEST')
|
||||
response['enabled'].should.equal(False)
|
||||
|
||||
response = client.get_api_keys()
|
||||
len(response['items']).should.equal(2)
|
||||
len(response['items']).should.equal(3)
|
||||
|
||||
client.delete_api_key(apiKey=apikey_id)
|
||||
|
||||
response = client.get_api_keys()
|
||||
len(response['items']).should.equal(1)
|
||||
len(response['items']).should.equal(2)
|
||||
|
||||
@mock_apigateway
|
||||
def test_usage_plans():
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@ from boto.ec2.autoscale.group import AutoScalingGroup
|
|||
from boto.ec2.autoscale import Tag
|
||||
import boto.ec2.elb
|
||||
import sure # noqa
|
||||
from botocore.exceptions import ClientError
|
||||
from nose.tools import assert_raises
|
||||
|
||||
from moto import mock_autoscaling, mock_ec2_deprecated, mock_elb_deprecated, mock_elb, mock_autoscaling_deprecated, mock_ec2
|
||||
from tests.helpers import requires_boto_gte
|
||||
|
||||
from utils import setup_networking, setup_networking_deprecated
|
||||
from utils import setup_networking, setup_networking_deprecated, setup_instance_with_networking
|
||||
|
||||
|
||||
@mock_autoscaling_deprecated
|
||||
|
|
@ -724,6 +726,67 @@ def test_create_autoscaling_group_boto3():
|
|||
response['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
def test_create_autoscaling_group_from_instance():
|
||||
autoscaling_group_name = 'test_asg'
|
||||
image_id = 'ami-0cc293023f983ed53'
|
||||
instance_type = 't2.micro'
|
||||
|
||||
mocked_instance_with_networking = setup_instance_with_networking(image_id, instance_type)
|
||||
client = boto3.client('autoscaling', region_name='us-east-1')
|
||||
response = client.create_auto_scaling_group(
|
||||
AutoScalingGroupName=autoscaling_group_name,
|
||||
InstanceId=mocked_instance_with_networking['instance'],
|
||||
MinSize=1,
|
||||
MaxSize=3,
|
||||
DesiredCapacity=2,
|
||||
Tags=[
|
||||
{'ResourceId': 'test_asg',
|
||||
'ResourceType': 'auto-scaling-group',
|
||||
'Key': 'propogated-tag-key',
|
||||
'Value': 'propogate-tag-value',
|
||||
'PropagateAtLaunch': True
|
||||
},
|
||||
{'ResourceId': 'test_asg',
|
||||
'ResourceType': 'auto-scaling-group',
|
||||
'Key': 'not-propogated-tag-key',
|
||||
'Value': 'not-propogate-tag-value',
|
||||
'PropagateAtLaunch': False
|
||||
}],
|
||||
VPCZoneIdentifier=mocked_instance_with_networking['subnet1'],
|
||||
NewInstancesProtectedFromScaleIn=False,
|
||||
)
|
||||
response['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
|
||||
|
||||
describe_launch_configurations_response = client.describe_launch_configurations()
|
||||
describe_launch_configurations_response['LaunchConfigurations'].should.have.length_of(1)
|
||||
launch_configuration_from_instance = describe_launch_configurations_response['LaunchConfigurations'][0]
|
||||
launch_configuration_from_instance['LaunchConfigurationName'].should.equal('test_asg')
|
||||
launch_configuration_from_instance['ImageId'].should.equal(image_id)
|
||||
launch_configuration_from_instance['InstanceType'].should.equal(instance_type)
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
def test_create_autoscaling_group_from_invalid_instance_id():
|
||||
invalid_instance_id = 'invalid_instance'
|
||||
|
||||
mocked_networking = setup_networking()
|
||||
client = boto3.client('autoscaling', region_name='us-east-1')
|
||||
with assert_raises(ClientError) as ex:
|
||||
client.create_auto_scaling_group(
|
||||
AutoScalingGroupName='test_asg',
|
||||
InstanceId=invalid_instance_id,
|
||||
MinSize=9,
|
||||
MaxSize=15,
|
||||
DesiredCapacity=12,
|
||||
VPCZoneIdentifier=mocked_networking['subnet1'],
|
||||
NewInstancesProtectedFromScaleIn=False,
|
||||
)
|
||||
ex.exception.response['ResponseMetadata']['HTTPStatusCode'].should.equal(400)
|
||||
ex.exception.response['Error']['Code'].should.equal('ValidationError')
|
||||
ex.exception.response['Error']['Message'].should.equal('Instance [{0}] is invalid.'.format(invalid_instance_id))
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
def test_describe_autoscaling_groups_boto3():
|
||||
mocked_networking = setup_networking()
|
||||
|
|
@ -823,6 +886,62 @@ def test_update_autoscaling_group_boto3():
|
|||
group['NewInstancesProtectedFromScaleIn'].should.equal(False)
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
def test_update_autoscaling_group_min_size_desired_capacity_change():
|
||||
mocked_networking = setup_networking()
|
||||
client = boto3.client('autoscaling', region_name='us-east-1')
|
||||
|
||||
client.create_launch_configuration(
|
||||
LaunchConfigurationName='test_launch_configuration'
|
||||
)
|
||||
client.create_auto_scaling_group(
|
||||
AutoScalingGroupName='test_asg',
|
||||
LaunchConfigurationName='test_launch_configuration',
|
||||
MinSize=2,
|
||||
MaxSize=20,
|
||||
DesiredCapacity=3,
|
||||
VPCZoneIdentifier=mocked_networking['subnet1'],
|
||||
)
|
||||
client.update_auto_scaling_group(
|
||||
AutoScalingGroupName='test_asg',
|
||||
MinSize=5,
|
||||
)
|
||||
response = client.describe_auto_scaling_groups(
|
||||
AutoScalingGroupNames=['test_asg'])
|
||||
group = response['AutoScalingGroups'][0]
|
||||
group['DesiredCapacity'].should.equal(5)
|
||||
group['MinSize'].should.equal(5)
|
||||
group['Instances'].should.have.length_of(5)
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
def test_update_autoscaling_group_max_size_desired_capacity_change():
|
||||
mocked_networking = setup_networking()
|
||||
client = boto3.client('autoscaling', region_name='us-east-1')
|
||||
|
||||
client.create_launch_configuration(
|
||||
LaunchConfigurationName='test_launch_configuration'
|
||||
)
|
||||
client.create_auto_scaling_group(
|
||||
AutoScalingGroupName='test_asg',
|
||||
LaunchConfigurationName='test_launch_configuration',
|
||||
MinSize=2,
|
||||
MaxSize=20,
|
||||
DesiredCapacity=10,
|
||||
VPCZoneIdentifier=mocked_networking['subnet1'],
|
||||
)
|
||||
client.update_auto_scaling_group(
|
||||
AutoScalingGroupName='test_asg',
|
||||
MaxSize=5,
|
||||
)
|
||||
response = client.describe_auto_scaling_groups(
|
||||
AutoScalingGroupNames=['test_asg'])
|
||||
group = response['AutoScalingGroups'][0]
|
||||
group['DesiredCapacity'].should.equal(5)
|
||||
group['MaxSize'].should.equal(5)
|
||||
group['Instances'].should.have.length_of(5)
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
def test_autoscaling_taqs_update_boto3():
|
||||
mocked_networking = setup_networking()
|
||||
|
|
@ -1269,3 +1388,36 @@ def test_set_desired_capacity_down_boto3():
|
|||
instance_ids = {instance['InstanceId'] for instance in group['Instances']}
|
||||
set(protected).should.equal(instance_ids)
|
||||
set(unprotected).should_not.be.within(instance_ids) # only unprotected killed
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
@mock_ec2
|
||||
def test_terminate_instance_in_autoscaling_group():
|
||||
mocked_networking = setup_networking()
|
||||
client = boto3.client('autoscaling', region_name='us-east-1')
|
||||
_ = client.create_launch_configuration(
|
||||
LaunchConfigurationName='test_launch_configuration'
|
||||
)
|
||||
_ = client.create_auto_scaling_group(
|
||||
AutoScalingGroupName='test_asg',
|
||||
LaunchConfigurationName='test_launch_configuration',
|
||||
MinSize=1,
|
||||
MaxSize=20,
|
||||
VPCZoneIdentifier=mocked_networking['subnet1'],
|
||||
NewInstancesProtectedFromScaleIn=False
|
||||
)
|
||||
|
||||
response = client.describe_auto_scaling_groups(AutoScalingGroupNames=['test_asg'])
|
||||
original_instance_id = next(
|
||||
instance['InstanceId']
|
||||
for instance in response['AutoScalingGroups'][0]['Instances']
|
||||
)
|
||||
ec2_client = boto3.client('ec2', region_name='us-east-1')
|
||||
ec2_client.terminate_instances(InstanceIds=[original_instance_id])
|
||||
|
||||
response = client.describe_auto_scaling_groups(AutoScalingGroupNames=['test_asg'])
|
||||
replaced_instance_id = next(
|
||||
instance['InstanceId']
|
||||
for instance in response['AutoScalingGroups'][0]['Instances']
|
||||
)
|
||||
replaced_instance_id.should_not.equal(original_instance_id)
|
||||
|
|
|
|||
|
|
@ -31,3 +31,18 @@ def setup_networking_deprecated():
|
|||
"10.11.2.0/24",
|
||||
availability_zone='us-east-1b')
|
||||
return {'vpc': vpc.id, 'subnet1': subnet1.id, 'subnet2': subnet2.id}
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def setup_instance_with_networking(image_id, instance_type):
|
||||
mock_data = setup_networking()
|
||||
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||
instances = ec2.create_instances(
|
||||
ImageId=image_id,
|
||||
InstanceType=instance_type,
|
||||
MaxCount=1,
|
||||
MinCount=1,
|
||||
SubnetId=mock_data['subnet1']
|
||||
)
|
||||
mock_data['instance'] = instances[0].id
|
||||
return mock_data
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import base64
|
||||
import uuid
|
||||
import botocore.client
|
||||
import boto3
|
||||
import hashlib
|
||||
|
|
@ -11,11 +12,12 @@ import zipfile
|
|||
import sure # noqa
|
||||
|
||||
from freezegun import freeze_time
|
||||
from moto import mock_lambda, mock_s3, mock_ec2, mock_sns, mock_logs, settings
|
||||
from moto import mock_lambda, mock_s3, mock_ec2, mock_sns, mock_logs, settings, mock_sqs
|
||||
from nose.tools import assert_raises
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
_lambda_region = 'us-west-2'
|
||||
boto3.setup_default_session(region_name=_lambda_region)
|
||||
|
||||
|
||||
def _process_lambda(func_str):
|
||||
|
|
@ -59,6 +61,13 @@ def lambda_handler(event, context):
|
|||
"""
|
||||
return _process_lambda(pfunc)
|
||||
|
||||
def get_test_zip_file4():
|
||||
pfunc = """
|
||||
def lambda_handler(event, context):
|
||||
raise Exception('I failed!')
|
||||
"""
|
||||
return _process_lambda(pfunc)
|
||||
|
||||
|
||||
@mock_lambda
|
||||
def test_list_functions():
|
||||
|
|
@ -933,3 +942,306 @@ def test_list_versions_by_function_for_nonexistent_function():
|
|||
versions = conn.list_versions_by_function(FunctionName='testFunction')
|
||||
|
||||
assert len(versions['Versions']) == 0
|
||||
|
||||
|
||||
@mock_logs
|
||||
@mock_lambda
|
||||
@mock_sqs
|
||||
def test_create_event_source_mapping():
|
||||
sqs = boto3.resource('sqs')
|
||||
queue = sqs.create_queue(QueueName="test-sqs-queue1")
|
||||
|
||||
conn = boto3.client('lambda')
|
||||
func = conn.create_function(
|
||||
FunctionName='testFunction',
|
||||
Runtime='python2.7',
|
||||
Role='test-iam-role',
|
||||
Handler='lambda_function.lambda_handler',
|
||||
Code={
|
||||
'ZipFile': get_test_zip_file3(),
|
||||
},
|
||||
Description='test lambda function',
|
||||
Timeout=3,
|
||||
MemorySize=128,
|
||||
Publish=True,
|
||||
)
|
||||
|
||||
response = conn.create_event_source_mapping(
|
||||
EventSourceArn=queue.attributes['QueueArn'],
|
||||
FunctionName=func['FunctionArn'],
|
||||
)
|
||||
|
||||
assert response['EventSourceArn'] == queue.attributes['QueueArn']
|
||||
assert response['FunctionArn'] == func['FunctionArn']
|
||||
assert response['State'] == 'Enabled'
|
||||
|
||||
|
||||
@mock_logs
|
||||
@mock_lambda
|
||||
@mock_sqs
|
||||
def test_invoke_function_from_sqs():
|
||||
logs_conn = boto3.client("logs")
|
||||
sqs = boto3.resource('sqs')
|
||||
queue = sqs.create_queue(QueueName="test-sqs-queue1")
|
||||
|
||||
conn = boto3.client('lambda')
|
||||
func = conn.create_function(
|
||||
FunctionName='testFunction',
|
||||
Runtime='python2.7',
|
||||
Role='test-iam-role',
|
||||
Handler='lambda_function.lambda_handler',
|
||||
Code={
|
||||
'ZipFile': get_test_zip_file3(),
|
||||
},
|
||||
Description='test lambda function',
|
||||
Timeout=3,
|
||||
MemorySize=128,
|
||||
Publish=True,
|
||||
)
|
||||
|
||||
response = conn.create_event_source_mapping(
|
||||
EventSourceArn=queue.attributes['QueueArn'],
|
||||
FunctionName=func['FunctionArn'],
|
||||
)
|
||||
|
||||
assert response['EventSourceArn'] == queue.attributes['QueueArn']
|
||||
assert response['State'] == 'Enabled'
|
||||
|
||||
sqs_client = boto3.client('sqs')
|
||||
sqs_client.send_message(QueueUrl=queue.url, MessageBody='test')
|
||||
start = time.time()
|
||||
while (time.time() - start) < 30:
|
||||
result = logs_conn.describe_log_streams(logGroupName='/aws/lambda/testFunction')
|
||||
log_streams = result.get('logStreams')
|
||||
if not log_streams:
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
assert len(log_streams) == 1
|
||||
result = logs_conn.get_log_events(logGroupName='/aws/lambda/testFunction', logStreamName=log_streams[0]['logStreamName'])
|
||||
for event in result.get('events'):
|
||||
if event['message'] == 'get_test_zip_file3 success':
|
||||
return
|
||||
time.sleep(1)
|
||||
|
||||
assert False, "Test Failed"
|
||||
|
||||
|
||||
@mock_logs
|
||||
@mock_lambda
|
||||
@mock_sqs
|
||||
def test_invoke_function_from_sqs_exception():
|
||||
logs_conn = boto3.client("logs")
|
||||
sqs = boto3.resource('sqs')
|
||||
queue = sqs.create_queue(QueueName="test-sqs-queue1")
|
||||
|
||||
conn = boto3.client('lambda')
|
||||
func = conn.create_function(
|
||||
FunctionName='testFunction',
|
||||
Runtime='python2.7',
|
||||
Role='test-iam-role',
|
||||
Handler='lambda_function.lambda_handler',
|
||||
Code={
|
||||
'ZipFile': get_test_zip_file4(),
|
||||
},
|
||||
Description='test lambda function',
|
||||
Timeout=3,
|
||||
MemorySize=128,
|
||||
Publish=True,
|
||||
)
|
||||
|
||||
response = conn.create_event_source_mapping(
|
||||
EventSourceArn=queue.attributes['QueueArn'],
|
||||
FunctionName=func['FunctionArn'],
|
||||
)
|
||||
|
||||
assert response['EventSourceArn'] == queue.attributes['QueueArn']
|
||||
assert response['State'] == 'Enabled'
|
||||
|
||||
entries = []
|
||||
for i in range(3):
|
||||
body = {
|
||||
"uuid": str(uuid.uuid4()),
|
||||
"test": "test_{}".format(i),
|
||||
}
|
||||
entry = {
|
||||
'Id': str(i),
|
||||
'MessageBody': json.dumps(body)
|
||||
}
|
||||
entries.append(entry)
|
||||
|
||||
queue.send_messages(Entries=entries)
|
||||
|
||||
start = time.time()
|
||||
while (time.time() - start) < 30:
|
||||
result = logs_conn.describe_log_streams(logGroupName='/aws/lambda/testFunction')
|
||||
log_streams = result.get('logStreams')
|
||||
if not log_streams:
|
||||
time.sleep(1)
|
||||
continue
|
||||
assert len(log_streams) >= 1
|
||||
|
||||
result = logs_conn.get_log_events(logGroupName='/aws/lambda/testFunction', logStreamName=log_streams[0]['logStreamName'])
|
||||
for event in result.get('events'):
|
||||
if 'I failed!' in event['message']:
|
||||
messages = queue.receive_messages(MaxNumberOfMessages=10)
|
||||
# Verify messages are still visible and unprocessed
|
||||
assert len(messages) is 3
|
||||
return
|
||||
time.sleep(1)
|
||||
|
||||
assert False, "Test Failed"
|
||||
|
||||
|
||||
@mock_logs
|
||||
@mock_lambda
|
||||
@mock_sqs
|
||||
def test_list_event_source_mappings():
|
||||
sqs = boto3.resource('sqs')
|
||||
queue = sqs.create_queue(QueueName="test-sqs-queue1")
|
||||
|
||||
conn = boto3.client('lambda')
|
||||
func = conn.create_function(
|
||||
FunctionName='testFunction',
|
||||
Runtime='python2.7',
|
||||
Role='test-iam-role',
|
||||
Handler='lambda_function.lambda_handler',
|
||||
Code={
|
||||
'ZipFile': get_test_zip_file3(),
|
||||
},
|
||||
Description='test lambda function',
|
||||
Timeout=3,
|
||||
MemorySize=128,
|
||||
Publish=True,
|
||||
)
|
||||
response = conn.create_event_source_mapping(
|
||||
EventSourceArn=queue.attributes['QueueArn'],
|
||||
FunctionName=func['FunctionArn'],
|
||||
)
|
||||
mappings = conn.list_event_source_mappings(EventSourceArn='123')
|
||||
assert len(mappings['EventSourceMappings']) == 0
|
||||
|
||||
mappings = conn.list_event_source_mappings(EventSourceArn=queue.attributes['QueueArn'])
|
||||
assert len(mappings['EventSourceMappings']) == 1
|
||||
assert mappings['EventSourceMappings'][0]['UUID'] == response['UUID']
|
||||
assert mappings['EventSourceMappings'][0]['FunctionArn'] == func['FunctionArn']
|
||||
|
||||
|
||||
@mock_lambda
|
||||
@mock_sqs
|
||||
def test_get_event_source_mapping():
|
||||
sqs = boto3.resource('sqs')
|
||||
queue = sqs.create_queue(QueueName="test-sqs-queue1")
|
||||
|
||||
conn = boto3.client('lambda')
|
||||
func = conn.create_function(
|
||||
FunctionName='testFunction',
|
||||
Runtime='python2.7',
|
||||
Role='test-iam-role',
|
||||
Handler='lambda_function.lambda_handler',
|
||||
Code={
|
||||
'ZipFile': get_test_zip_file3(),
|
||||
},
|
||||
Description='test lambda function',
|
||||
Timeout=3,
|
||||
MemorySize=128,
|
||||
Publish=True,
|
||||
)
|
||||
response = conn.create_event_source_mapping(
|
||||
EventSourceArn=queue.attributes['QueueArn'],
|
||||
FunctionName=func['FunctionArn'],
|
||||
)
|
||||
mapping = conn.get_event_source_mapping(UUID=response['UUID'])
|
||||
assert mapping['UUID'] == response['UUID']
|
||||
assert mapping['FunctionArn'] == func['FunctionArn']
|
||||
|
||||
conn.get_event_source_mapping.when.called_with(UUID='1')\
|
||||
.should.throw(botocore.client.ClientError)
|
||||
|
||||
|
||||
@mock_lambda
|
||||
@mock_sqs
|
||||
def test_update_event_source_mapping():
|
||||
sqs = boto3.resource('sqs')
|
||||
queue = sqs.create_queue(QueueName="test-sqs-queue1")
|
||||
|
||||
conn = boto3.client('lambda')
|
||||
func1 = conn.create_function(
|
||||
FunctionName='testFunction',
|
||||
Runtime='python2.7',
|
||||
Role='test-iam-role',
|
||||
Handler='lambda_function.lambda_handler',
|
||||
Code={
|
||||
'ZipFile': get_test_zip_file3(),
|
||||
},
|
||||
Description='test lambda function',
|
||||
Timeout=3,
|
||||
MemorySize=128,
|
||||
Publish=True,
|
||||
)
|
||||
func2 = conn.create_function(
|
||||
FunctionName='testFunction2',
|
||||
Runtime='python2.7',
|
||||
Role='test-iam-role',
|
||||
Handler='lambda_function.lambda_handler',
|
||||
Code={
|
||||
'ZipFile': get_test_zip_file3(),
|
||||
},
|
||||
Description='test lambda function',
|
||||
Timeout=3,
|
||||
MemorySize=128,
|
||||
Publish=True,
|
||||
)
|
||||
response = conn.create_event_source_mapping(
|
||||
EventSourceArn=queue.attributes['QueueArn'],
|
||||
FunctionName=func1['FunctionArn'],
|
||||
)
|
||||
assert response['FunctionArn'] == func1['FunctionArn']
|
||||
assert response['BatchSize'] == 10
|
||||
assert response['State'] == 'Enabled'
|
||||
|
||||
mapping = conn.update_event_source_mapping(
|
||||
UUID=response['UUID'],
|
||||
Enabled=False,
|
||||
BatchSize=15,
|
||||
FunctionName='testFunction2'
|
||||
|
||||
)
|
||||
assert mapping['UUID'] == response['UUID']
|
||||
assert mapping['FunctionArn'] == func2['FunctionArn']
|
||||
assert mapping['State'] == 'Disabled'
|
||||
|
||||
|
||||
@mock_lambda
|
||||
@mock_sqs
|
||||
def test_delete_event_source_mapping():
|
||||
sqs = boto3.resource('sqs')
|
||||
queue = sqs.create_queue(QueueName="test-sqs-queue1")
|
||||
|
||||
conn = boto3.client('lambda')
|
||||
func1 = conn.create_function(
|
||||
FunctionName='testFunction',
|
||||
Runtime='python2.7',
|
||||
Role='test-iam-role',
|
||||
Handler='lambda_function.lambda_handler',
|
||||
Code={
|
||||
'ZipFile': get_test_zip_file3(),
|
||||
},
|
||||
Description='test lambda function',
|
||||
Timeout=3,
|
||||
MemorySize=128,
|
||||
Publish=True,
|
||||
)
|
||||
response = conn.create_event_source_mapping(
|
||||
EventSourceArn=queue.attributes['QueueArn'],
|
||||
FunctionName=func1['FunctionArn'],
|
||||
)
|
||||
assert response['FunctionArn'] == func1['FunctionArn']
|
||||
assert response['BatchSize'] == 10
|
||||
assert response['State'] == 'Enabled'
|
||||
|
||||
response = conn.delete_event_source_mapping(UUID=response['UUID'])
|
||||
|
||||
assert response['State'] == 'Deleting'
|
||||
conn.get_event_source_mapping.when.called_with(UUID=response['UUID'])\
|
||||
.should.throw(botocore.client.ClientError)
|
||||
|
|
|
|||
|
|
@ -642,6 +642,87 @@ def test_describe_task_definition():
|
|||
len(resp['jobDefinitions']).should.equal(3)
|
||||
|
||||
|
||||
@mock_logs
|
||||
@mock_ec2
|
||||
@mock_ecs
|
||||
@mock_iam
|
||||
@mock_batch
|
||||
def test_submit_job_by_name():
|
||||
ec2_client, iam_client, ecs_client, logs_client, batch_client = _get_clients()
|
||||
vpc_id, subnet_id, sg_id, iam_arn = _setup(ec2_client, iam_client)
|
||||
|
||||
compute_name = 'test_compute_env'
|
||||
resp = batch_client.create_compute_environment(
|
||||
computeEnvironmentName=compute_name,
|
||||
type='UNMANAGED',
|
||||
state='ENABLED',
|
||||
serviceRole=iam_arn
|
||||
)
|
||||
arn = resp['computeEnvironmentArn']
|
||||
|
||||
resp = batch_client.create_job_queue(
|
||||
jobQueueName='test_job_queue',
|
||||
state='ENABLED',
|
||||
priority=123,
|
||||
computeEnvironmentOrder=[
|
||||
{
|
||||
'order': 123,
|
||||
'computeEnvironment': arn
|
||||
},
|
||||
]
|
||||
)
|
||||
queue_arn = resp['jobQueueArn']
|
||||
|
||||
job_definition_name = 'sleep10'
|
||||
|
||||
batch_client.register_job_definition(
|
||||
jobDefinitionName=job_definition_name,
|
||||
type='container',
|
||||
containerProperties={
|
||||
'image': 'busybox',
|
||||
'vcpus': 1,
|
||||
'memory': 128,
|
||||
'command': ['sleep', '10']
|
||||
}
|
||||
)
|
||||
batch_client.register_job_definition(
|
||||
jobDefinitionName=job_definition_name,
|
||||
type='container',
|
||||
containerProperties={
|
||||
'image': 'busybox',
|
||||
'vcpus': 1,
|
||||
'memory': 256,
|
||||
'command': ['sleep', '10']
|
||||
}
|
||||
)
|
||||
resp = batch_client.register_job_definition(
|
||||
jobDefinitionName=job_definition_name,
|
||||
type='container',
|
||||
containerProperties={
|
||||
'image': 'busybox',
|
||||
'vcpus': 1,
|
||||
'memory': 512,
|
||||
'command': ['sleep', '10']
|
||||
}
|
||||
)
|
||||
job_definition_arn = resp['jobDefinitionArn']
|
||||
|
||||
resp = batch_client.submit_job(
|
||||
jobName='test1',
|
||||
jobQueue=queue_arn,
|
||||
jobDefinition=job_definition_name
|
||||
)
|
||||
job_id = resp['jobId']
|
||||
|
||||
resp_jobs = batch_client.describe_jobs(jobs=[job_id])
|
||||
|
||||
# batch_client.terminate_job(jobId=job_id)
|
||||
|
||||
len(resp_jobs['jobs']).should.equal(1)
|
||||
resp_jobs['jobs'][0]['jobId'].should.equal(job_id)
|
||||
resp_jobs['jobs'][0]['jobQueue'].should.equal(queue_arn)
|
||||
resp_jobs['jobs'][0]['jobDefinition'].should.equal(job_definition_arn)
|
||||
|
||||
# SLOW TESTS
|
||||
@expected_failure
|
||||
@mock_logs
|
||||
|
|
|
|||
|
|
@ -593,9 +593,11 @@ def test_create_stack_lambda_and_dynamodb():
|
|||
}
|
||||
},
|
||||
"func1version": {
|
||||
"Type": "AWS::Lambda::LambdaVersion",
|
||||
"Properties" : {
|
||||
"Version": "v1.2.3"
|
||||
"Type": "AWS::Lambda::Version",
|
||||
"Properties": {
|
||||
"FunctionName": {
|
||||
"Ref": "func1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tab1": {
|
||||
|
|
@ -618,8 +620,10 @@ def test_create_stack_lambda_and_dynamodb():
|
|||
},
|
||||
"func1mapping": {
|
||||
"Type": "AWS::Lambda::EventSourceMapping",
|
||||
"Properties" : {
|
||||
"FunctionName": "v1.2.3",
|
||||
"Properties": {
|
||||
"FunctionName": {
|
||||
"Ref": "func1"
|
||||
},
|
||||
"EventSourceArn": "arn:aws:dynamodb:region:XXXXXX:table/tab1/stream/2000T00:00:00.000",
|
||||
"StartingPosition": "0",
|
||||
"BatchSize": 100,
|
||||
|
|
|
|||
|
|
@ -1,85 +1,97 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import boto3
|
||||
|
||||
from moto import mock_cognitoidentity
|
||||
import sure # noqa
|
||||
|
||||
from moto.cognitoidentity.utils import get_random_identity_id
|
||||
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_create_identity_pool():
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
|
||||
result = conn.create_identity_pool(IdentityPoolName='TestPool',
|
||||
AllowUnauthenticatedIdentities=False,
|
||||
SupportedLoginProviders={'graph.facebook.com': '123456789012345'},
|
||||
DeveloperProviderName='devname',
|
||||
OpenIdConnectProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db'],
|
||||
CognitoIdentityProviders=[
|
||||
{
|
||||
'ProviderName': 'testprovider',
|
||||
'ClientId': 'CLIENT12345',
|
||||
'ServerSideTokenCheck': True
|
||||
},
|
||||
],
|
||||
SamlProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db'])
|
||||
assert result['IdentityPoolId'] != ''
|
||||
|
||||
|
||||
# testing a helper function
|
||||
def test_get_random_identity_id():
|
||||
assert len(get_random_identity_id('us-west-2')) > 0
|
||||
assert len(get_random_identity_id('us-west-2').split(':')[1]) == 19
|
||||
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_id():
|
||||
# These two do NOT work in server mode. They just don't return the data from the model.
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_id(AccountId='someaccount',
|
||||
IdentityPoolId='us-west-2:12345',
|
||||
Logins={
|
||||
'someurl': '12345'
|
||||
})
|
||||
print(result)
|
||||
assert result.get('IdentityId', "").startswith('us-west-2') or result.get('ResponseMetadata').get('HTTPStatusCode') == 200
|
||||
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_credentials_for_identity():
|
||||
# These two do NOT work in server mode. They just don't return the data from the model.
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_credentials_for_identity(IdentityId='12345')
|
||||
|
||||
assert result.get('Expiration', 0) > 0 or result.get('ResponseMetadata').get('HTTPStatusCode') == 200
|
||||
assert result.get('IdentityId') == '12345' or result.get('ResponseMetadata').get('HTTPStatusCode') == 200
|
||||
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_open_id_token_for_developer_identity():
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_open_id_token_for_developer_identity(
|
||||
IdentityPoolId='us-west-2:12345',
|
||||
IdentityId='12345',
|
||||
Logins={
|
||||
'someurl': '12345'
|
||||
},
|
||||
TokenDuration=123
|
||||
)
|
||||
assert len(result['Token'])
|
||||
assert result['IdentityId'] == '12345'
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_open_id_token_for_developer_identity_when_no_explicit_identity_id():
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_open_id_token_for_developer_identity(
|
||||
IdentityPoolId='us-west-2:12345',
|
||||
Logins={
|
||||
'someurl': '12345'
|
||||
},
|
||||
TokenDuration=123
|
||||
)
|
||||
assert len(result['Token']) > 0
|
||||
assert len(result['IdentityId']) > 0
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import boto3
|
||||
|
||||
from moto import mock_cognitoidentity
|
||||
import sure # noqa
|
||||
|
||||
from moto.cognitoidentity.utils import get_random_identity_id
|
||||
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_create_identity_pool():
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
|
||||
result = conn.create_identity_pool(IdentityPoolName='TestPool',
|
||||
AllowUnauthenticatedIdentities=False,
|
||||
SupportedLoginProviders={'graph.facebook.com': '123456789012345'},
|
||||
DeveloperProviderName='devname',
|
||||
OpenIdConnectProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db'],
|
||||
CognitoIdentityProviders=[
|
||||
{
|
||||
'ProviderName': 'testprovider',
|
||||
'ClientId': 'CLIENT12345',
|
||||
'ServerSideTokenCheck': True
|
||||
},
|
||||
],
|
||||
SamlProviderARNs=['arn:aws:rds:eu-west-2:123456789012:db:mysql-db'])
|
||||
assert result['IdentityPoolId'] != ''
|
||||
|
||||
|
||||
# testing a helper function
|
||||
def test_get_random_identity_id():
|
||||
assert len(get_random_identity_id('us-west-2')) > 0
|
||||
assert len(get_random_identity_id('us-west-2').split(':')[1]) == 19
|
||||
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_id():
|
||||
# These two do NOT work in server mode. They just don't return the data from the model.
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_id(AccountId='someaccount',
|
||||
IdentityPoolId='us-west-2:12345',
|
||||
Logins={
|
||||
'someurl': '12345'
|
||||
})
|
||||
print(result)
|
||||
assert result.get('IdentityId', "").startswith('us-west-2') or result.get('ResponseMetadata').get('HTTPStatusCode') == 200
|
||||
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_credentials_for_identity():
|
||||
# These two do NOT work in server mode. They just don't return the data from the model.
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_credentials_for_identity(IdentityId='12345')
|
||||
|
||||
assert result.get('Expiration', 0) > 0 or result.get('ResponseMetadata').get('HTTPStatusCode') == 200
|
||||
assert result.get('IdentityId') == '12345' or result.get('ResponseMetadata').get('HTTPStatusCode') == 200
|
||||
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_open_id_token_for_developer_identity():
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_open_id_token_for_developer_identity(
|
||||
IdentityPoolId='us-west-2:12345',
|
||||
IdentityId='12345',
|
||||
Logins={
|
||||
'someurl': '12345'
|
||||
},
|
||||
TokenDuration=123
|
||||
)
|
||||
assert len(result['Token']) > 0
|
||||
assert result['IdentityId'] == '12345'
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_open_id_token_for_developer_identity_when_no_explicit_identity_id():
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_open_id_token_for_developer_identity(
|
||||
IdentityPoolId='us-west-2:12345',
|
||||
Logins={
|
||||
'someurl': '12345'
|
||||
},
|
||||
TokenDuration=123
|
||||
)
|
||||
assert len(result['Token']) > 0
|
||||
assert len(result['IdentityId']) > 0
|
||||
|
||||
@mock_cognitoidentity
|
||||
def test_get_open_id_token():
|
||||
conn = boto3.client('cognito-identity', 'us-west-2')
|
||||
result = conn.get_open_id_token(
|
||||
IdentityId='12345',
|
||||
Logins={
|
||||
'someurl': '12345'
|
||||
}
|
||||
)
|
||||
assert len(result['Token']) > 0
|
||||
assert result['IdentityId'] == '12345'
|
||||
|
|
|
|||
|
|
@ -133,6 +133,22 @@ def test_create_user_pool_domain():
|
|||
result["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||
|
||||
|
||||
@mock_cognitoidp
|
||||
def test_create_user_pool_domain_custom_domain_config():
|
||||
conn = boto3.client("cognito-idp", "us-west-2")
|
||||
|
||||
domain = str(uuid.uuid4())
|
||||
custom_domain_config = {
|
||||
"CertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/123456789012",
|
||||
}
|
||||
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||
result = conn.create_user_pool_domain(
|
||||
UserPoolId=user_pool_id, Domain=domain, CustomDomainConfig=custom_domain_config
|
||||
)
|
||||
result["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||
result["CloudFrontDomain"].should.equal("e2c343b3293ee505.cloudfront.net")
|
||||
|
||||
|
||||
@mock_cognitoidp
|
||||
def test_describe_user_pool_domain():
|
||||
conn = boto3.client("cognito-idp", "us-west-2")
|
||||
|
|
@ -162,6 +178,23 @@ def test_delete_user_pool_domain():
|
|||
result["DomainDescription"].keys().should.have.length_of(0)
|
||||
|
||||
|
||||
@mock_cognitoidp
|
||||
def test_update_user_pool_domain():
|
||||
conn = boto3.client("cognito-idp", "us-west-2")
|
||||
|
||||
domain = str(uuid.uuid4())
|
||||
custom_domain_config = {
|
||||
"CertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/123456789012",
|
||||
}
|
||||
user_pool_id = conn.create_user_pool(PoolName=str(uuid.uuid4()))["UserPool"]["Id"]
|
||||
conn.create_user_pool_domain(UserPoolId=user_pool_id, Domain=domain)
|
||||
result = conn.update_user_pool_domain(
|
||||
UserPoolId=user_pool_id, Domain=domain, CustomDomainConfig=custom_domain_config
|
||||
)
|
||||
result["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||
result["CloudFrontDomain"].should.equal("e2c343b3293ee505.cloudfront.net")
|
||||
|
||||
|
||||
@mock_cognitoidp
|
||||
def test_create_user_pool_client():
|
||||
conn = boto3.client("cognito-idp", "us-west-2")
|
||||
|
|
|
|||
|
|
@ -123,6 +123,526 @@ def test_put_configuration_recorder():
|
|||
assert "maximum number of configuration recorders: 1 is reached." in ce.exception.response['Error']['Message']
|
||||
|
||||
|
||||
@mock_config
|
||||
def test_put_configuration_aggregator():
|
||||
client = boto3.client('config', region_name='us-west-2')
|
||||
|
||||
# With too many aggregation sources:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
'111111111111',
|
||||
'222222222222'
|
||||
],
|
||||
'AwsRegions': [
|
||||
'us-east-1',
|
||||
'us-west-2'
|
||||
]
|
||||
},
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
'111111111111',
|
||||
'222222222222'
|
||||
],
|
||||
'AwsRegions': [
|
||||
'us-east-1',
|
||||
'us-west-2'
|
||||
]
|
||||
}
|
||||
]
|
||||
)
|
||||
assert 'Member must have length less than or equal to 1' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# With an invalid region config (no regions defined):
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
'111111111111',
|
||||
'222222222222'
|
||||
],
|
||||
'AllAwsRegions': False
|
||||
}
|
||||
]
|
||||
)
|
||||
assert 'Your request does not specify any regions' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidParameterValueException'
|
||||
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
OrganizationAggregationSource={
|
||||
'RoleArn': 'arn:aws:iam::012345678910:role/SomeRole'
|
||||
}
|
||||
)
|
||||
assert 'Your request does not specify any regions' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidParameterValueException'
|
||||
|
||||
# With both region flags defined:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
'111111111111',
|
||||
'222222222222'
|
||||
],
|
||||
'AwsRegions': [
|
||||
'us-east-1',
|
||||
'us-west-2'
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
]
|
||||
)
|
||||
assert 'You must choose one of these options' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidParameterValueException'
|
||||
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
OrganizationAggregationSource={
|
||||
'RoleArn': 'arn:aws:iam::012345678910:role/SomeRole',
|
||||
'AwsRegions': [
|
||||
'us-east-1',
|
||||
'us-west-2'
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
)
|
||||
assert 'You must choose one of these options' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidParameterValueException'
|
||||
|
||||
# Name too long:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='a' * 257,
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
]
|
||||
)
|
||||
assert 'configurationAggregatorName' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# Too many tags (>50):
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
],
|
||||
Tags=[{'Key': '{}'.format(x), 'Value': '{}'.format(x)} for x in range(0, 51)]
|
||||
)
|
||||
assert 'Member must have length less than or equal to 50' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# Tag key is too big (>128 chars):
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
],
|
||||
Tags=[{'Key': 'a' * 129, 'Value': 'a'}]
|
||||
)
|
||||
assert 'Member must have length less than or equal to 128' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# Tag value is too big (>256 chars):
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
],
|
||||
Tags=[{'Key': 'tag', 'Value': 'a' * 257}]
|
||||
)
|
||||
assert 'Member must have length less than or equal to 256' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# Duplicate Tags:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
],
|
||||
Tags=[{'Key': 'a', 'Value': 'a'}, {'Key': 'a', 'Value': 'a'}]
|
||||
)
|
||||
assert 'Duplicate tag keys found.' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidInput'
|
||||
|
||||
# Invalid characters in the tag key:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
],
|
||||
Tags=[{'Key': '!', 'Value': 'a'}]
|
||||
)
|
||||
assert 'Member must satisfy regular expression pattern:' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# If it contains both the AccountAggregationSources and the OrganizationAggregationSource
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': False
|
||||
}
|
||||
],
|
||||
OrganizationAggregationSource={
|
||||
'RoleArn': 'arn:aws:iam::012345678910:role/SomeRole',
|
||||
'AllAwsRegions': False
|
||||
}
|
||||
)
|
||||
assert 'AccountAggregationSource and the OrganizationAggregationSource' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidParameterValueException'
|
||||
|
||||
# If it contains neither:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
)
|
||||
assert 'AccountAggregationSource or the OrganizationAggregationSource' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidParameterValueException'
|
||||
|
||||
# Just make one:
|
||||
account_aggregation_source = {
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
'111111111111',
|
||||
'222222222222'
|
||||
],
|
||||
'AwsRegions': [
|
||||
'us-east-1',
|
||||
'us-west-2'
|
||||
],
|
||||
'AllAwsRegions': False
|
||||
}
|
||||
|
||||
result = client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[account_aggregation_source],
|
||||
)
|
||||
assert result['ConfigurationAggregator']['ConfigurationAggregatorName'] == 'testing'
|
||||
assert result['ConfigurationAggregator']['AccountAggregationSources'] == [account_aggregation_source]
|
||||
assert 'arn:aws:config:us-west-2:123456789012:config-aggregator/config-aggregator-' in \
|
||||
result['ConfigurationAggregator']['ConfigurationAggregatorArn']
|
||||
assert result['ConfigurationAggregator']['CreationTime'] == result['ConfigurationAggregator']['LastUpdatedTime']
|
||||
|
||||
# Update the existing one:
|
||||
original_arn = result['ConfigurationAggregator']['ConfigurationAggregatorArn']
|
||||
account_aggregation_source.pop('AwsRegions')
|
||||
account_aggregation_source['AllAwsRegions'] = True
|
||||
result = client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[account_aggregation_source]
|
||||
)
|
||||
|
||||
assert result['ConfigurationAggregator']['ConfigurationAggregatorName'] == 'testing'
|
||||
assert result['ConfigurationAggregator']['AccountAggregationSources'] == [account_aggregation_source]
|
||||
assert result['ConfigurationAggregator']['ConfigurationAggregatorArn'] == original_arn
|
||||
|
||||
# Make an org one:
|
||||
result = client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testingOrg',
|
||||
OrganizationAggregationSource={
|
||||
'RoleArn': 'arn:aws:iam::012345678910:role/SomeRole',
|
||||
'AwsRegions': ['us-east-1', 'us-west-2']
|
||||
}
|
||||
)
|
||||
|
||||
assert result['ConfigurationAggregator']['ConfigurationAggregatorName'] == 'testingOrg'
|
||||
assert result['ConfigurationAggregator']['OrganizationAggregationSource'] == {
|
||||
'RoleArn': 'arn:aws:iam::012345678910:role/SomeRole',
|
||||
'AwsRegions': [
|
||||
'us-east-1',
|
||||
'us-west-2'
|
||||
],
|
||||
'AllAwsRegions': False
|
||||
}
|
||||
|
||||
|
||||
@mock_config
|
||||
def test_describe_configuration_aggregators():
|
||||
client = boto3.client('config', region_name='us-west-2')
|
||||
|
||||
# Without any config aggregators:
|
||||
assert not client.describe_configuration_aggregators()['ConfigurationAggregators']
|
||||
|
||||
# Make 10 config aggregators:
|
||||
for x in range(0, 10):
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing{}'.format(x),
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
# Describe with an incorrect name:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.describe_configuration_aggregators(ConfigurationAggregatorNames=['DoesNotExist'])
|
||||
assert 'The configuration aggregator does not exist.' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationAggregatorException'
|
||||
|
||||
# Error describe with more than 1 item in the list:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.describe_configuration_aggregators(ConfigurationAggregatorNames=['testing0', 'DoesNotExist'])
|
||||
assert 'At least one of the configuration aggregators does not exist.' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationAggregatorException'
|
||||
|
||||
# Get the normal list:
|
||||
result = client.describe_configuration_aggregators()
|
||||
assert not result.get('NextToken')
|
||||
assert len(result['ConfigurationAggregators']) == 10
|
||||
|
||||
# Test filtered list:
|
||||
agg_names = ['testing0', 'testing1', 'testing2']
|
||||
result = client.describe_configuration_aggregators(ConfigurationAggregatorNames=agg_names)
|
||||
assert not result.get('NextToken')
|
||||
assert len(result['ConfigurationAggregators']) == 3
|
||||
assert [agg['ConfigurationAggregatorName'] for agg in result['ConfigurationAggregators']] == agg_names
|
||||
|
||||
# Test Pagination:
|
||||
result = client.describe_configuration_aggregators(Limit=4)
|
||||
assert len(result['ConfigurationAggregators']) == 4
|
||||
assert result['NextToken'] == 'testing4'
|
||||
assert [agg['ConfigurationAggregatorName'] for agg in result['ConfigurationAggregators']] == \
|
||||
['testing{}'.format(x) for x in range(0, 4)]
|
||||
result = client.describe_configuration_aggregators(Limit=4, NextToken='testing4')
|
||||
assert len(result['ConfigurationAggregators']) == 4
|
||||
assert result['NextToken'] == 'testing8'
|
||||
assert [agg['ConfigurationAggregatorName'] for agg in result['ConfigurationAggregators']] == \
|
||||
['testing{}'.format(x) for x in range(4, 8)]
|
||||
result = client.describe_configuration_aggregators(Limit=4, NextToken='testing8')
|
||||
assert len(result['ConfigurationAggregators']) == 2
|
||||
assert not result.get('NextToken')
|
||||
assert [agg['ConfigurationAggregatorName'] for agg in result['ConfigurationAggregators']] == \
|
||||
['testing{}'.format(x) for x in range(8, 10)]
|
||||
|
||||
# Test Pagination with Filtering:
|
||||
result = client.describe_configuration_aggregators(ConfigurationAggregatorNames=['testing2', 'testing4'], Limit=1)
|
||||
assert len(result['ConfigurationAggregators']) == 1
|
||||
assert result['NextToken'] == 'testing4'
|
||||
assert result['ConfigurationAggregators'][0]['ConfigurationAggregatorName'] == 'testing2'
|
||||
result = client.describe_configuration_aggregators(ConfigurationAggregatorNames=['testing2', 'testing4'], Limit=1, NextToken='testing4')
|
||||
assert not result.get('NextToken')
|
||||
assert result['ConfigurationAggregators'][0]['ConfigurationAggregatorName'] == 'testing4'
|
||||
|
||||
# Test with an invalid filter:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.describe_configuration_aggregators(NextToken='WRONG')
|
||||
assert 'The nextToken provided is invalid' == ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidNextTokenException'
|
||||
|
||||
|
||||
@mock_config
|
||||
def test_put_aggregation_authorization():
|
||||
client = boto3.client('config', region_name='us-west-2')
|
||||
|
||||
# Too many tags (>50):
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_aggregation_authorization(
|
||||
AuthorizedAccountId='012345678910',
|
||||
AuthorizedAwsRegion='us-west-2',
|
||||
Tags=[{'Key': '{}'.format(x), 'Value': '{}'.format(x)} for x in range(0, 51)]
|
||||
)
|
||||
assert 'Member must have length less than or equal to 50' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# Tag key is too big (>128 chars):
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_aggregation_authorization(
|
||||
AuthorizedAccountId='012345678910',
|
||||
AuthorizedAwsRegion='us-west-2',
|
||||
Tags=[{'Key': 'a' * 129, 'Value': 'a'}]
|
||||
)
|
||||
assert 'Member must have length less than or equal to 128' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# Tag value is too big (>256 chars):
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_aggregation_authorization(
|
||||
AuthorizedAccountId='012345678910',
|
||||
AuthorizedAwsRegion='us-west-2',
|
||||
Tags=[{'Key': 'tag', 'Value': 'a' * 257}]
|
||||
)
|
||||
assert 'Member must have length less than or equal to 256' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# Duplicate Tags:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_aggregation_authorization(
|
||||
AuthorizedAccountId='012345678910',
|
||||
AuthorizedAwsRegion='us-west-2',
|
||||
Tags=[{'Key': 'a', 'Value': 'a'}, {'Key': 'a', 'Value': 'a'}]
|
||||
)
|
||||
assert 'Duplicate tag keys found.' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidInput'
|
||||
|
||||
# Invalid characters in the tag key:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.put_aggregation_authorization(
|
||||
AuthorizedAccountId='012345678910',
|
||||
AuthorizedAwsRegion='us-west-2',
|
||||
Tags=[{'Key': '!', 'Value': 'a'}]
|
||||
)
|
||||
assert 'Member must satisfy regular expression pattern:' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'ValidationException'
|
||||
|
||||
# Put a normal one there:
|
||||
result = client.put_aggregation_authorization(AuthorizedAccountId='012345678910', AuthorizedAwsRegion='us-east-1',
|
||||
Tags=[{'Key': 'tag', 'Value': 'a'}])
|
||||
|
||||
assert result['AggregationAuthorization']['AggregationAuthorizationArn'] == 'arn:aws:config:us-west-2:123456789012:' \
|
||||
'aggregation-authorization/012345678910/us-east-1'
|
||||
assert result['AggregationAuthorization']['AuthorizedAccountId'] == '012345678910'
|
||||
assert result['AggregationAuthorization']['AuthorizedAwsRegion'] == 'us-east-1'
|
||||
assert isinstance(result['AggregationAuthorization']['CreationTime'], datetime)
|
||||
|
||||
creation_date = result['AggregationAuthorization']['CreationTime']
|
||||
|
||||
# And again:
|
||||
result = client.put_aggregation_authorization(AuthorizedAccountId='012345678910', AuthorizedAwsRegion='us-east-1')
|
||||
assert result['AggregationAuthorization']['AggregationAuthorizationArn'] == 'arn:aws:config:us-west-2:123456789012:' \
|
||||
'aggregation-authorization/012345678910/us-east-1'
|
||||
assert result['AggregationAuthorization']['AuthorizedAccountId'] == '012345678910'
|
||||
assert result['AggregationAuthorization']['AuthorizedAwsRegion'] == 'us-east-1'
|
||||
assert result['AggregationAuthorization']['CreationTime'] == creation_date
|
||||
|
||||
|
||||
@mock_config
|
||||
def test_describe_aggregation_authorizations():
|
||||
client = boto3.client('config', region_name='us-west-2')
|
||||
|
||||
# With no aggregation authorizations:
|
||||
assert not client.describe_aggregation_authorizations()['AggregationAuthorizations']
|
||||
|
||||
# Make 10 account authorizations:
|
||||
for i in range(0, 10):
|
||||
client.put_aggregation_authorization(AuthorizedAccountId='{}'.format(str(i) * 12), AuthorizedAwsRegion='us-west-2')
|
||||
|
||||
result = client.describe_aggregation_authorizations()
|
||||
assert len(result['AggregationAuthorizations']) == 10
|
||||
assert not result.get('NextToken')
|
||||
for i in range(0, 10):
|
||||
assert result['AggregationAuthorizations'][i]['AuthorizedAccountId'] == str(i) * 12
|
||||
|
||||
# Test Pagination:
|
||||
result = client.describe_aggregation_authorizations(Limit=4)
|
||||
assert len(result['AggregationAuthorizations']) == 4
|
||||
assert result['NextToken'] == ('4' * 12) + '/us-west-2'
|
||||
assert [auth['AuthorizedAccountId'] for auth in result['AggregationAuthorizations']] == ['{}'.format(str(x) * 12) for x in range(0, 4)]
|
||||
|
||||
result = client.describe_aggregation_authorizations(Limit=4, NextToken=('4' * 12) + '/us-west-2')
|
||||
assert len(result['AggregationAuthorizations']) == 4
|
||||
assert result['NextToken'] == ('8' * 12) + '/us-west-2'
|
||||
assert [auth['AuthorizedAccountId'] for auth in result['AggregationAuthorizations']] == ['{}'.format(str(x) * 12) for x in range(4, 8)]
|
||||
|
||||
result = client.describe_aggregation_authorizations(Limit=4, NextToken=('8' * 12) + '/us-west-2')
|
||||
assert len(result['AggregationAuthorizations']) == 2
|
||||
assert not result.get('NextToken')
|
||||
assert [auth['AuthorizedAccountId'] for auth in result['AggregationAuthorizations']] == ['{}'.format(str(x) * 12) for x in range(8, 10)]
|
||||
|
||||
# Test with an invalid filter:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.describe_aggregation_authorizations(NextToken='WRONG')
|
||||
assert 'The nextToken provided is invalid' == ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'InvalidNextTokenException'
|
||||
|
||||
|
||||
@mock_config
|
||||
def test_delete_aggregation_authorization():
|
||||
client = boto3.client('config', region_name='us-west-2')
|
||||
|
||||
client.put_aggregation_authorization(AuthorizedAccountId='012345678910', AuthorizedAwsRegion='us-west-2')
|
||||
|
||||
# Delete it:
|
||||
client.delete_aggregation_authorization(AuthorizedAccountId='012345678910', AuthorizedAwsRegion='us-west-2')
|
||||
|
||||
# Verify that none are there:
|
||||
assert not client.describe_aggregation_authorizations()['AggregationAuthorizations']
|
||||
|
||||
# Try it again -- nothing should happen:
|
||||
client.delete_aggregation_authorization(AuthorizedAccountId='012345678910', AuthorizedAwsRegion='us-west-2')
|
||||
|
||||
|
||||
@mock_config
|
||||
def test_delete_configuration_aggregator():
|
||||
client = boto3.client('config', region_name='us-west-2')
|
||||
client.put_configuration_aggregator(
|
||||
ConfigurationAggregatorName='testing',
|
||||
AccountAggregationSources=[
|
||||
{
|
||||
'AccountIds': [
|
||||
'012345678910',
|
||||
],
|
||||
'AllAwsRegions': True
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
client.delete_configuration_aggregator(ConfigurationAggregatorName='testing')
|
||||
|
||||
# And again to confirm that it's deleted:
|
||||
with assert_raises(ClientError) as ce:
|
||||
client.delete_configuration_aggregator(ConfigurationAggregatorName='testing')
|
||||
assert 'The configuration aggregator does not exist.' in ce.exception.response['Error']['Message']
|
||||
assert ce.exception.response['Error']['Code'] == 'NoSuchConfigurationAggregatorException'
|
||||
|
||||
|
||||
@mock_config
|
||||
def test_describe_configurations():
|
||||
client = boto3.client('config', region_name='us-west-2')
|
||||
|
|
|
|||
|
|
@ -38,12 +38,6 @@ def test_domain_dispatched():
|
|||
keys[0].should.equal('EmailResponse.dispatch')
|
||||
|
||||
|
||||
def test_domain_without_matches():
|
||||
dispatcher = DomainDispatcherApplication(create_backend_app)
|
||||
dispatcher.get_application.when.called_with(
|
||||
{"HTTP_HOST": "not-matching-anything.com"}).should.throw(RuntimeError)
|
||||
|
||||
|
||||
def test_domain_dispatched_with_service():
|
||||
# If we pass a particular service, always return that.
|
||||
dispatcher = DomainDispatcherApplication(create_backend_app, service="s3")
|
||||
|
|
|
|||
|
|
@ -452,6 +452,90 @@ def test_basic_projection_expressions():
|
|||
assert 'body' in results['Items'][1]
|
||||
assert 'forum_name' in results['Items'][1]
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_basic_projection_expressions_using_scan():
|
||||
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
|
||||
|
||||
# Create the DynamoDB table.
|
||||
table = dynamodb.create_table(
|
||||
TableName='users',
|
||||
KeySchema=[
|
||||
{
|
||||
'AttributeName': 'forum_name',
|
||||
'KeyType': 'HASH'
|
||||
},
|
||||
{
|
||||
'AttributeName': 'subject',
|
||||
'KeyType': 'RANGE'
|
||||
},
|
||||
],
|
||||
AttributeDefinitions=[
|
||||
{
|
||||
'AttributeName': 'forum_name',
|
||||
'AttributeType': 'S'
|
||||
},
|
||||
{
|
||||
'AttributeName': 'subject',
|
||||
'AttributeType': 'S'
|
||||
},
|
||||
],
|
||||
ProvisionedThroughput={
|
||||
'ReadCapacityUnits': 5,
|
||||
'WriteCapacityUnits': 5
|
||||
}
|
||||
)
|
||||
table = dynamodb.Table('users')
|
||||
|
||||
table.put_item(Item={
|
||||
'forum_name': 'the-key',
|
||||
'subject': '123',
|
||||
'body': 'some test message'
|
||||
})
|
||||
|
||||
table.put_item(Item={
|
||||
'forum_name': 'not-the-key',
|
||||
'subject': '123',
|
||||
'body': 'some other test message'
|
||||
})
|
||||
# Test a scan returning all items
|
||||
results = table.scan(
|
||||
FilterExpression=Key('forum_name').eq(
|
||||
'the-key'),
|
||||
ProjectionExpression='body, subject'
|
||||
)
|
||||
|
||||
assert 'body' in results['Items'][0]
|
||||
assert results['Items'][0]['body'] == 'some test message'
|
||||
assert 'subject' in results['Items'][0]
|
||||
|
||||
table.put_item(Item={
|
||||
'forum_name': 'the-key',
|
||||
'subject': '1234',
|
||||
'body': 'yet another test message'
|
||||
})
|
||||
|
||||
results = table.scan(
|
||||
FilterExpression=Key('forum_name').eq(
|
||||
'the-key'),
|
||||
ProjectionExpression='body'
|
||||
)
|
||||
|
||||
assert 'body' in results['Items'][0]
|
||||
assert 'subject' not in results['Items'][0]
|
||||
assert 'forum_name' not in results['Items'][0]
|
||||
assert 'body' in results['Items'][1]
|
||||
assert 'subject' not in results['Items'][1]
|
||||
assert 'forum_name' not in results['Items'][1]
|
||||
|
||||
# The projection expression should not remove data from storage
|
||||
results = table.query(
|
||||
KeyConditionExpression=Key('forum_name').eq(
|
||||
'the-key'),
|
||||
)
|
||||
assert 'subject' in results['Items'][0]
|
||||
assert 'body' in results['Items'][1]
|
||||
assert 'forum_name' in results['Items'][1]
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_basic_projection_expressions_with_attr_expression_names():
|
||||
|
|
@ -519,6 +603,84 @@ def test_basic_projection_expressions_with_attr_expression_names():
|
|||
assert 'attachment' in results['Items'][0]
|
||||
assert results['Items'][0]['attachment'] == 'something'
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_basic_projection_expressions_using_scan_with_attr_expression_names():
|
||||
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
|
||||
|
||||
# Create the DynamoDB table.
|
||||
table = dynamodb.create_table(
|
||||
TableName='users',
|
||||
KeySchema=[
|
||||
{
|
||||
'AttributeName': 'forum_name',
|
||||
'KeyType': 'HASH'
|
||||
},
|
||||
{
|
||||
'AttributeName': 'subject',
|
||||
'KeyType': 'RANGE'
|
||||
},
|
||||
],
|
||||
AttributeDefinitions=[
|
||||
{
|
||||
'AttributeName': 'forum_name',
|
||||
'AttributeType': 'S'
|
||||
},
|
||||
{
|
||||
'AttributeName': 'subject',
|
||||
'AttributeType': 'S'
|
||||
},
|
||||
],
|
||||
ProvisionedThroughput={
|
||||
'ReadCapacityUnits': 5,
|
||||
'WriteCapacityUnits': 5
|
||||
}
|
||||
)
|
||||
table = dynamodb.Table('users')
|
||||
|
||||
table.put_item(Item={
|
||||
'forum_name': 'the-key',
|
||||
'subject': '123',
|
||||
'body': 'some test message',
|
||||
'attachment': 'something'
|
||||
})
|
||||
|
||||
table.put_item(Item={
|
||||
'forum_name': 'not-the-key',
|
||||
'subject': '123',
|
||||
'body': 'some other test message',
|
||||
'attachment': 'something'
|
||||
})
|
||||
# Test a scan returning all items
|
||||
|
||||
results = table.scan(
|
||||
FilterExpression=Key('forum_name').eq(
|
||||
'the-key'),
|
||||
ProjectionExpression='#rl, #rt, subject',
|
||||
ExpressionAttributeNames={
|
||||
'#rl': 'body',
|
||||
'#rt': 'attachment'
|
||||
},
|
||||
)
|
||||
|
||||
assert 'body' in results['Items'][0]
|
||||
assert 'attachment' in results['Items'][0]
|
||||
assert 'subject' in results['Items'][0]
|
||||
assert 'form_name' not in results['Items'][0]
|
||||
|
||||
# Test without a FilterExpression
|
||||
results = table.scan(
|
||||
ProjectionExpression='#rl, #rt, subject',
|
||||
ExpressionAttributeNames={
|
||||
'#rl': 'body',
|
||||
'#rt': 'attachment'
|
||||
},
|
||||
)
|
||||
|
||||
assert 'body' in results['Items'][0]
|
||||
assert 'attachment' in results['Items'][0]
|
||||
assert 'subject' in results['Items'][0]
|
||||
assert 'form_name' not in results['Items'][0]
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_put_item_returns_consumed_capacity():
|
||||
|
|
@ -676,44 +838,47 @@ def test_filter_expression():
|
|||
filter_expr.expr(row1).should.be(True)
|
||||
|
||||
# NOT test 2
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('NOT (Id = :v0)', {}, {':v0': {'N': 8}})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('NOT (Id = :v0)', {}, {':v0': {'N': '8'}})
|
||||
filter_expr.expr(row1).should.be(False) # Id = 8 so should be false
|
||||
|
||||
# AND test
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id > :v0 AND Subs < :v1', {}, {':v0': {'N': 5}, ':v1': {'N': 7}})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id > :v0 AND Subs < :v1', {}, {':v0': {'N': '5'}, ':v1': {'N': '7'}})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
filter_expr.expr(row2).should.be(False)
|
||||
|
||||
# OR test
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id = :v0 OR Id=:v1', {}, {':v0': {'N': 5}, ':v1': {'N': 8}})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id = :v0 OR Id=:v1', {}, {':v0': {'N': '5'}, ':v1': {'N': '8'}})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
|
||||
# BETWEEN test
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id BETWEEN :v0 AND :v1', {}, {':v0': {'N': 5}, ':v1': {'N': 10}})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id BETWEEN :v0 AND :v1', {}, {':v0': {'N': '5'}, ':v1': {'N': '10'}})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
|
||||
# PAREN test
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id = :v0 AND (Subs = :v0 OR Subs = :v1)', {}, {':v0': {'N': 8}, ':v1': {'N': 5}})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id = :v0 AND (Subs = :v0 OR Subs = :v1)', {}, {':v0': {'N': '8'}, ':v1': {'N': '5'}})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
|
||||
# IN test
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id IN :v0', {}, {':v0': {'NS': [7, 8, 9]}})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('Id IN (:v0, :v1, :v2)', {}, {
|
||||
':v0': {'N': '7'},
|
||||
':v1': {'N': '8'},
|
||||
':v2': {'N': '9'}})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
|
||||
# attribute function tests (with extra spaces)
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('attribute_exists(Id) AND attribute_not_exists (User)', {}, {})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('attribute_type(Id, N)', {}, {})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('attribute_type(Id, :v0)', {}, {':v0': {'S': 'N'}})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
|
||||
# beginswith function test
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('begins_with(Desc, Some)', {}, {})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('begins_with(Desc, :v0)', {}, {':v0': {'S': 'Some'}})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
filter_expr.expr(row2).should.be(False)
|
||||
|
||||
# contains function test
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('contains(KV, test1)', {}, {})
|
||||
filter_expr = moto.dynamodb2.comparisons.get_filter_expression('contains(KV, :v0)', {}, {':v0': {'S': 'test1'}})
|
||||
filter_expr.expr(row1).should.be(True)
|
||||
filter_expr.expr(row2).should.be(False)
|
||||
|
||||
|
|
@ -754,14 +919,26 @@ def test_query_filter():
|
|||
TableName='test1',
|
||||
Item={
|
||||
'client': {'S': 'client1'},
|
||||
'app': {'S': 'app1'}
|
||||
'app': {'S': 'app1'},
|
||||
'nested': {'M': {
|
||||
'version': {'S': 'version1'},
|
||||
'contents': {'L': [
|
||||
{'S': 'value1'}, {'S': 'value2'},
|
||||
]},
|
||||
}},
|
||||
}
|
||||
)
|
||||
client.put_item(
|
||||
TableName='test1',
|
||||
Item={
|
||||
'client': {'S': 'client1'},
|
||||
'app': {'S': 'app2'}
|
||||
'app': {'S': 'app2'},
|
||||
'nested': {'M': {
|
||||
'version': {'S': 'version2'},
|
||||
'contents': {'L': [
|
||||
{'S': 'value1'}, {'S': 'value2'},
|
||||
]},
|
||||
}},
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -783,6 +960,18 @@ def test_query_filter():
|
|||
)
|
||||
assert response['Count'] == 2
|
||||
|
||||
response = table.query(
|
||||
KeyConditionExpression=Key('client').eq('client1'),
|
||||
FilterExpression=Attr('nested.version').contains('version')
|
||||
)
|
||||
assert response['Count'] == 2
|
||||
|
||||
response = table.query(
|
||||
KeyConditionExpression=Key('client').eq('client1'),
|
||||
FilterExpression=Attr('nested.contents[0]').eq('value1')
|
||||
)
|
||||
assert response['Count'] == 2
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_scan_filter():
|
||||
|
|
@ -1061,7 +1250,7 @@ def test_delete_item():
|
|||
with assert_raises(ClientError) as ex:
|
||||
table.delete_item(Key={'client': 'client1', 'app': 'app1'},
|
||||
ReturnValues='ALL_NEW')
|
||||
|
||||
|
||||
# Test deletion and returning old value
|
||||
response = table.delete_item(Key={'client': 'client1', 'app': 'app1'}, ReturnValues='ALL_OLD')
|
||||
response['Attributes'].should.contain('client')
|
||||
|
|
@ -1153,6 +1342,46 @@ def test_query_missing_expr_names():
|
|||
resp['Items'][0]['client']['S'].should.equal('test2')
|
||||
|
||||
|
||||
# https://github.com/spulec/moto/issues/2328
|
||||
@mock_dynamodb2
|
||||
def test_update_item_with_list():
|
||||
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
|
||||
|
||||
# Create the DynamoDB table.
|
||||
dynamodb.create_table(
|
||||
TableName='Table',
|
||||
KeySchema=[
|
||||
{
|
||||
'AttributeName': 'key',
|
||||
'KeyType': 'HASH'
|
||||
}
|
||||
],
|
||||
AttributeDefinitions=[
|
||||
{
|
||||
'AttributeName': 'key',
|
||||
'AttributeType': 'S'
|
||||
},
|
||||
],
|
||||
ProvisionedThroughput={
|
||||
'ReadCapacityUnits': 1,
|
||||
'WriteCapacityUnits': 1
|
||||
}
|
||||
)
|
||||
table = dynamodb.Table('Table')
|
||||
table.update_item(
|
||||
Key={'key': 'the-key'},
|
||||
AttributeUpdates={
|
||||
'list': {'Value': [1, 2], 'Action': 'PUT'}
|
||||
}
|
||||
)
|
||||
|
||||
resp = table.get_item(Key={'key': 'the-key'})
|
||||
resp['Item'].should.equal({
|
||||
'key': 'the-key',
|
||||
'list': [1, 2]
|
||||
})
|
||||
|
||||
|
||||
# https://github.com/spulec/moto/issues/1342
|
||||
@mock_dynamodb2
|
||||
def test_update_item_on_map():
|
||||
|
|
@ -1364,7 +1593,7 @@ def test_put_return_attributes():
|
|||
ReturnValues='NONE'
|
||||
)
|
||||
assert 'Attributes' not in r
|
||||
|
||||
|
||||
r = dynamodb.put_item(
|
||||
TableName='moto-test',
|
||||
Item={'id': {'S': 'foo'}, 'col1': {'S': 'val2'}},
|
||||
|
|
@ -1381,7 +1610,7 @@ def test_put_return_attributes():
|
|||
ex.exception.response['Error']['Code'].should.equal('ValidationException')
|
||||
ex.exception.response['ResponseMetadata']['HTTPStatusCode'].should.equal(400)
|
||||
ex.exception.response['Error']['Message'].should.equal('Return values set to invalid value')
|
||||
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_query_global_secondary_index_when_created_via_update_table_resource():
|
||||
|
|
@ -1489,7 +1718,7 @@ def test_dynamodb_streams_1():
|
|||
'StreamViewType': 'NEW_AND_OLD_IMAGES'
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
assert 'StreamSpecification' in resp['TableDescription']
|
||||
assert resp['TableDescription']['StreamSpecification'] == {
|
||||
'StreamEnabled': True,
|
||||
|
|
@ -1497,11 +1726,11 @@ def test_dynamodb_streams_1():
|
|||
}
|
||||
assert 'LatestStreamLabel' in resp['TableDescription']
|
||||
assert 'LatestStreamArn' in resp['TableDescription']
|
||||
|
||||
|
||||
resp = conn.delete_table(TableName='test-streams')
|
||||
|
||||
assert 'StreamSpecification' in resp['TableDescription']
|
||||
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_dynamodb_streams_2():
|
||||
|
|
@ -1532,11 +1761,10 @@ def test_dynamodb_streams_2():
|
|||
assert 'LatestStreamLabel' in resp['TableDescription']
|
||||
assert 'LatestStreamArn' in resp['TableDescription']
|
||||
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_condition_expressions():
|
||||
client = boto3.client('dynamodb', region_name='us-east-1')
|
||||
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
|
||||
|
||||
# Create the DynamoDB table.
|
||||
client.create_table(
|
||||
|
|
@ -1589,6 +1817,57 @@ def test_condition_expressions():
|
|||
}
|
||||
)
|
||||
|
||||
client.put_item(
|
||||
TableName='test1',
|
||||
Item={
|
||||
'client': {'S': 'client1'},
|
||||
'app': {'S': 'app1'},
|
||||
'match': {'S': 'match'},
|
||||
'existing': {'S': 'existing'},
|
||||
},
|
||||
ConditionExpression='attribute_exists(#nonexistent) OR attribute_exists(#existing)',
|
||||
ExpressionAttributeNames={
|
||||
'#nonexistent': 'nope',
|
||||
'#existing': 'existing'
|
||||
}
|
||||
)
|
||||
|
||||
client.put_item(
|
||||
TableName='test1',
|
||||
Item={
|
||||
'client': {'S': 'client1'},
|
||||
'app': {'S': 'app1'},
|
||||
'match': {'S': 'match'},
|
||||
'existing': {'S': 'existing'},
|
||||
},
|
||||
ConditionExpression='#client BETWEEN :a AND :z',
|
||||
ExpressionAttributeNames={
|
||||
'#client': 'client',
|
||||
},
|
||||
ExpressionAttributeValues={
|
||||
':a': {'S': 'a'},
|
||||
':z': {'S': 'z'},
|
||||
}
|
||||
)
|
||||
|
||||
client.put_item(
|
||||
TableName='test1',
|
||||
Item={
|
||||
'client': {'S': 'client1'},
|
||||
'app': {'S': 'app1'},
|
||||
'match': {'S': 'match'},
|
||||
'existing': {'S': 'existing'},
|
||||
},
|
||||
ConditionExpression='#client IN (:client1, :client2)',
|
||||
ExpressionAttributeNames={
|
||||
'#client': 'client',
|
||||
},
|
||||
ExpressionAttributeValues={
|
||||
':client1': {'S': 'client1'},
|
||||
':client2': {'S': 'client2'},
|
||||
}
|
||||
)
|
||||
|
||||
with assert_raises(client.exceptions.ConditionalCheckFailedException):
|
||||
client.put_item(
|
||||
TableName='test1',
|
||||
|
|
@ -1641,6 +1920,119 @@ def test_condition_expressions():
|
|||
}
|
||||
)
|
||||
|
||||
# Make sure update_item honors ConditionExpression as well
|
||||
client.update_item(
|
||||
TableName='test1',
|
||||
Key={
|
||||
'client': {'S': 'client1'},
|
||||
'app': {'S': 'app1'},
|
||||
},
|
||||
UpdateExpression='set #match=:match',
|
||||
ConditionExpression='attribute_exists(#existing)',
|
||||
ExpressionAttributeNames={
|
||||
'#existing': 'existing',
|
||||
'#match': 'match',
|
||||
},
|
||||
ExpressionAttributeValues={
|
||||
':match': {'S': 'match'}
|
||||
}
|
||||
)
|
||||
|
||||
with assert_raises(client.exceptions.ConditionalCheckFailedException):
|
||||
client.update_item(
|
||||
TableName='test1',
|
||||
Key={
|
||||
'client': { 'S': 'client1'},
|
||||
'app': { 'S': 'app1'},
|
||||
},
|
||||
UpdateExpression='set #match=:match',
|
||||
ConditionExpression='attribute_not_exists(#existing)',
|
||||
ExpressionAttributeValues={
|
||||
':match': {'S': 'match'}
|
||||
},
|
||||
ExpressionAttributeNames={
|
||||
'#existing': 'existing',
|
||||
'#match': 'match',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_condition_expression__attr_doesnt_exist():
|
||||
client = boto3.client('dynamodb', region_name='us-east-1')
|
||||
|
||||
client.create_table(
|
||||
TableName='test',
|
||||
KeySchema=[{'AttributeName': 'forum_name', 'KeyType': 'HASH'}],
|
||||
AttributeDefinitions=[
|
||||
{'AttributeName': 'forum_name', 'AttributeType': 'S'},
|
||||
],
|
||||
ProvisionedThroughput={'ReadCapacityUnits': 1, 'WriteCapacityUnits': 1},
|
||||
)
|
||||
|
||||
client.put_item(
|
||||
TableName='test',
|
||||
Item={
|
||||
'forum_name': {'S': 'foo'},
|
||||
'ttl': {'N': 'bar'},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def update_if_attr_doesnt_exist():
|
||||
# Test nonexistent top-level attribute.
|
||||
client.update_item(
|
||||
TableName='test',
|
||||
Key={
|
||||
'forum_name': {'S': 'the-key'},
|
||||
'subject': {'S': 'the-subject'},
|
||||
},
|
||||
UpdateExpression='set #new_state=:new_state, #ttl=:ttl',
|
||||
ConditionExpression='attribute_not_exists(#new_state)',
|
||||
ExpressionAttributeNames={'#new_state': 'foobar', '#ttl': 'ttl'},
|
||||
ExpressionAttributeValues={
|
||||
':new_state': {'S': 'some-value'},
|
||||
':ttl': {'N': '12345.67'},
|
||||
},
|
||||
ReturnValues='ALL_NEW',
|
||||
)
|
||||
|
||||
update_if_attr_doesnt_exist()
|
||||
|
||||
# Second time should fail
|
||||
with assert_raises(client.exceptions.ConditionalCheckFailedException):
|
||||
update_if_attr_doesnt_exist()
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_condition_expression__or_order():
|
||||
client = boto3.client('dynamodb', region_name='us-east-1')
|
||||
|
||||
client.create_table(
|
||||
TableName='test',
|
||||
KeySchema=[{'AttributeName': 'forum_name', 'KeyType': 'HASH'}],
|
||||
AttributeDefinitions=[
|
||||
{'AttributeName': 'forum_name', 'AttributeType': 'S'},
|
||||
],
|
||||
ProvisionedThroughput={'ReadCapacityUnits': 1, 'WriteCapacityUnits': 1},
|
||||
)
|
||||
|
||||
# ensure that the RHS of the OR expression is not evaluated if the LHS
|
||||
# returns true (as it would result an error)
|
||||
client.update_item(
|
||||
TableName='test',
|
||||
Key={
|
||||
'forum_name': {'S': 'the-key'},
|
||||
},
|
||||
UpdateExpression='set #ttl=:ttl',
|
||||
ConditionExpression='attribute_not_exists(#ttl) OR #ttl <= :old_ttl',
|
||||
ExpressionAttributeNames={'#ttl': 'ttl'},
|
||||
ExpressionAttributeValues={
|
||||
':ttl': {'N': '6'},
|
||||
':old_ttl': {'N': '5'},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_query_gsi_with_range_key():
|
||||
|
|
@ -1749,3 +2141,55 @@ def test_scan_by_non_exists_index():
|
|||
ex.exception.response['Error']['Message'].should.equal(
|
||||
'The table does not have the specified index: non_exists_index'
|
||||
)
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_batch_items_returns_all():
|
||||
dynamodb = _create_user_table()
|
||||
returned_items = dynamodb.batch_get_item(RequestItems={
|
||||
'users': {
|
||||
'Keys': [{
|
||||
'username': {'S': 'user0'}
|
||||
}, {
|
||||
'username': {'S': 'user1'}
|
||||
}, {
|
||||
'username': {'S': 'user2'}
|
||||
}, {
|
||||
'username': {'S': 'user3'}
|
||||
}],
|
||||
'ConsistentRead': True
|
||||
}
|
||||
})['Responses']['users']
|
||||
assert len(returned_items) == 3
|
||||
assert [item['username']['S'] for item in returned_items] == ['user1', 'user2', 'user3']
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_batch_items_should_throw_exception_for_duplicate_request():
|
||||
client = _create_user_table()
|
||||
with assert_raises(ClientError) as ex:
|
||||
client.batch_get_item(RequestItems={
|
||||
'users': {
|
||||
'Keys': [{
|
||||
'username': {'S': 'user0'}
|
||||
}, {
|
||||
'username': {'S': 'user0'}
|
||||
}],
|
||||
'ConsistentRead': True
|
||||
}})
|
||||
ex.exception.response['Error']['Code'].should.equal('ValidationException')
|
||||
ex.exception.response['Error']['Message'].should.equal('Provided list of item keys contains duplicates')
|
||||
|
||||
|
||||
def _create_user_table():
|
||||
client = boto3.client('dynamodb', region_name='us-east-1')
|
||||
client.create_table(
|
||||
TableName='users',
|
||||
KeySchema=[{'AttributeName': 'username', 'KeyType': 'HASH'}],
|
||||
AttributeDefinitions=[{'AttributeName': 'username', 'AttributeType': 'S'}],
|
||||
ProvisionedThroughput={'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5}
|
||||
)
|
||||
client.put_item(TableName='users', Item={'username': {'S': 'user1'}, 'foo': {'S': 'bar'}})
|
||||
client.put_item(TableName='users', Item={'username': {'S': 'user2'}, 'foo': {'S': 'bar'}})
|
||||
client.put_item(TableName='users', Item={'username': {'S': 'user3'}, 'foo': {'S': 'bar'}})
|
||||
return client
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from nose.tools import assert_raises
|
|||
import sure # noqa
|
||||
|
||||
from moto import mock_ec2_deprecated, mock_ec2
|
||||
from moto.ec2.models import AMIS
|
||||
from moto.ec2.models import AMIS, OWNER_ID
|
||||
from tests.helpers import requires_boto_gte
|
||||
|
||||
|
||||
|
|
@ -152,6 +152,29 @@ def test_ami_copy():
|
|||
cm.exception.request_id.should_not.be.none
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_copy_image_changes_owner_id():
|
||||
conn = boto3.client('ec2', region_name='us-east-1')
|
||||
|
||||
# this source AMI ID is from moto/ec2/resources/amis.json
|
||||
source_ami_id = "ami-03cf127a"
|
||||
|
||||
# confirm the source ami owner id is different from the default owner id.
|
||||
# if they're ever the same it means this test is invalid.
|
||||
check_resp = conn.describe_images(ImageIds=[source_ami_id])
|
||||
check_resp["Images"][0]["OwnerId"].should_not.equal(OWNER_ID)
|
||||
|
||||
copy_resp = conn.copy_image(
|
||||
SourceImageId=source_ami_id,
|
||||
Name="new-image",
|
||||
Description="a copy of an image",
|
||||
SourceRegion="us-east-1")
|
||||
|
||||
describe_resp = conn.describe_images(Owners=["self"])
|
||||
describe_resp["Images"][0]["OwnerId"].should.equal(OWNER_ID)
|
||||
describe_resp["Images"][0]["ImageId"].should.equal(copy_resp["ImageId"])
|
||||
|
||||
|
||||
@mock_ec2_deprecated
|
||||
def test_ami_tagging():
|
||||
conn = boto.connect_vpc('the_key', 'the_secret')
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from freezegun import freeze_time
|
|||
import sure # noqa
|
||||
|
||||
from moto import mock_ec2_deprecated, mock_ec2
|
||||
from moto.ec2.models import OWNER_ID
|
||||
|
||||
|
||||
@mock_ec2_deprecated
|
||||
|
|
@ -395,7 +396,7 @@ def test_snapshot_filters():
|
|||
).should.equal({snapshot3.id})
|
||||
|
||||
snapshots_by_owner_id = conn.get_all_snapshots(
|
||||
filters={'owner-id': '123456789012'})
|
||||
filters={'owner-id': OWNER_ID})
|
||||
set([snap.id for snap in snapshots_by_owner_id]
|
||||
).should.equal({snapshot1.id, snapshot2.id, snapshot3.id})
|
||||
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ def test_elastic_network_interfaces_filtering():
|
|||
subnet.id, groups=[security_group1.id, security_group2.id])
|
||||
eni2 = conn.create_network_interface(
|
||||
subnet.id, groups=[security_group1.id])
|
||||
eni3 = conn.create_network_interface(subnet.id)
|
||||
eni3 = conn.create_network_interface(subnet.id, description='test description')
|
||||
|
||||
all_enis = conn.get_all_network_interfaces()
|
||||
all_enis.should.have.length_of(3)
|
||||
|
|
@ -189,6 +189,12 @@ def test_elastic_network_interfaces_filtering():
|
|||
enis_by_group.should.have.length_of(1)
|
||||
set([eni.id for eni in enis_by_group]).should.equal(set([eni1.id]))
|
||||
|
||||
# Filter by Description
|
||||
enis_by_description = conn.get_all_network_interfaces(
|
||||
filters={'description': eni3.description })
|
||||
enis_by_description.should.have.length_of(1)
|
||||
enis_by_description[0].description.should.equal(eni3.description)
|
||||
|
||||
# Unsupported filter
|
||||
conn.get_all_network_interfaces.when.called_with(
|
||||
filters={'not-implemented-filter': 'foobar'}).should.throw(NotImplementedError)
|
||||
|
|
@ -343,6 +349,106 @@ def test_elastic_network_interfaces_get_by_subnet_id():
|
|||
enis.should.have.length_of(0)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_elastic_network_interfaces_get_by_description():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-2')
|
||||
ec2_client = boto3.client('ec2', region_name='us-west-2')
|
||||
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
subnet = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock='10.0.0.0/24', AvailabilityZone='us-west-2a')
|
||||
|
||||
eni1 = ec2.create_network_interface(
|
||||
SubnetId=subnet.id, PrivateIpAddress='10.0.10.5', Description='test interface')
|
||||
|
||||
# The status of the new interface should be 'available'
|
||||
waiter = ec2_client.get_waiter('network_interface_available')
|
||||
waiter.wait(NetworkInterfaceIds=[eni1.id])
|
||||
|
||||
filters = [{'Name': 'description', 'Values': [eni1.description]}]
|
||||
enis = list(ec2.network_interfaces.filter(Filters=filters))
|
||||
enis.should.have.length_of(1)
|
||||
|
||||
filters = [{'Name': 'description', 'Values': ['bad description']}]
|
||||
enis = list(ec2.network_interfaces.filter(Filters=filters))
|
||||
enis.should.have.length_of(0)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_elastic_network_interfaces_describe_network_interfaces_with_filter():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-2')
|
||||
ec2_client = boto3.client('ec2', region_name='us-west-2')
|
||||
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
subnet = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock='10.0.0.0/24', AvailabilityZone='us-west-2a')
|
||||
|
||||
eni1 = ec2.create_network_interface(
|
||||
SubnetId=subnet.id, PrivateIpAddress='10.0.10.5', Description='test interface')
|
||||
|
||||
# The status of the new interface should be 'available'
|
||||
waiter = ec2_client.get_waiter('network_interface_available')
|
||||
waiter.wait(NetworkInterfaceIds=[eni1.id])
|
||||
|
||||
# Filter by network-interface-id
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'network-interface-id', 'Values': [eni1.id]}])
|
||||
response['NetworkInterfaces'].should.have.length_of(1)
|
||||
response['NetworkInterfaces'][0]['NetworkInterfaceId'].should.equal(eni1.id)
|
||||
response['NetworkInterfaces'][0]['PrivateIpAddress'].should.equal(eni1.private_ip_address)
|
||||
response['NetworkInterfaces'][0]['Description'].should.equal(eni1.description)
|
||||
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'network-interface-id', 'Values': ['bad-id']}])
|
||||
response['NetworkInterfaces'].should.have.length_of(0)
|
||||
|
||||
# Filter by private-ip-address
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'private-ip-address', 'Values': [eni1.private_ip_address]}])
|
||||
response['NetworkInterfaces'].should.have.length_of(1)
|
||||
response['NetworkInterfaces'][0]['NetworkInterfaceId'].should.equal(eni1.id)
|
||||
response['NetworkInterfaces'][0]['PrivateIpAddress'].should.equal(eni1.private_ip_address)
|
||||
response['NetworkInterfaces'][0]['Description'].should.equal(eni1.description)
|
||||
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'private-ip-address', 'Values': ['11.11.11.11']}])
|
||||
response['NetworkInterfaces'].should.have.length_of(0)
|
||||
|
||||
# Filter by sunet-id
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'subnet-id', 'Values': [eni1.subnet.id]}])
|
||||
response['NetworkInterfaces'].should.have.length_of(1)
|
||||
response['NetworkInterfaces'][0]['NetworkInterfaceId'].should.equal(eni1.id)
|
||||
response['NetworkInterfaces'][0]['PrivateIpAddress'].should.equal(eni1.private_ip_address)
|
||||
response['NetworkInterfaces'][0]['Description'].should.equal(eni1.description)
|
||||
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'subnet-id', 'Values': ['sn-bad-id']}])
|
||||
response['NetworkInterfaces'].should.have.length_of(0)
|
||||
|
||||
# Filter by description
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'description', 'Values': [eni1.description]}])
|
||||
response['NetworkInterfaces'].should.have.length_of(1)
|
||||
response['NetworkInterfaces'][0]['NetworkInterfaceId'].should.equal(eni1.id)
|
||||
response['NetworkInterfaces'][0]['PrivateIpAddress'].should.equal(eni1.private_ip_address)
|
||||
response['NetworkInterfaces'][0]['Description'].should.equal(eni1.description)
|
||||
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'description', 'Values': ['bad description']}])
|
||||
response['NetworkInterfaces'].should.have.length_of(0)
|
||||
|
||||
# Filter by multiple filters
|
||||
response = ec2_client.describe_network_interfaces(
|
||||
Filters=[{'Name': 'private-ip-address', 'Values': [eni1.private_ip_address]},
|
||||
{'Name': 'network-interface-id', 'Values': [eni1.id]},
|
||||
{'Name': 'subnet-id', 'Values': [eni1.subnet.id]}])
|
||||
response['NetworkInterfaces'].should.have.length_of(1)
|
||||
response['NetworkInterfaces'][0]['NetworkInterfaceId'].should.equal(eni1.id)
|
||||
response['NetworkInterfaces'][0]['PrivateIpAddress'].should.equal(eni1.private_ip_address)
|
||||
response['NetworkInterfaces'][0]['Description'].should.equal(eni1.description)
|
||||
|
||||
|
||||
@mock_ec2_deprecated
|
||||
@mock_cloudformation_deprecated
|
||||
def test_elastic_network_interfaces_cloudformation():
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
from __future__ import unicode_literals
|
||||
# Ensure 'assert_raises' context manager support for Python 2.6
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
import tests.backport_assert_raises
|
||||
from nose.tools import assert_raises
|
||||
|
||||
|
|
@ -679,8 +681,8 @@ def test_modify_instance_attribute_security_groups():
|
|||
reservation = conn.run_instances('ami-1234abcd')
|
||||
instance = reservation.instances[0]
|
||||
|
||||
sg_id = 'sg-1234abcd'
|
||||
sg_id2 = 'sg-abcd4321'
|
||||
sg_id = conn.create_security_group('test security group', 'this is a test security group').id
|
||||
sg_id2 = conn.create_security_group('test security group 2', 'this is a test security group 2').id
|
||||
|
||||
with assert_raises(EC2ResponseError) as ex:
|
||||
instance.modify_attribute("groupSet", [sg_id, sg_id2], dry_run=True)
|
||||
|
|
@ -1255,6 +1257,7 @@ def test_create_instance_ebs_optimized():
|
|||
instance.load()
|
||||
instance.ebs_optimized.should.be(False)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_run_multiple_instances_in_same_command():
|
||||
instance_count = 4
|
||||
|
|
@ -1269,3 +1272,37 @@ def test_run_multiple_instances_in_same_command():
|
|||
instances = reservations[0]['Instances']
|
||||
for i in range(0, instance_count):
|
||||
instances[i]['AmiLaunchIndex'].should.be(i)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_describe_instance_attribute():
|
||||
client = boto3.client('ec2', region_name='us-east-1')
|
||||
security_group_id = client.create_security_group(
|
||||
GroupName='test security group', Description='this is a test security group')['GroupId']
|
||||
client.run_instances(ImageId='ami-1234abcd',
|
||||
MinCount=1,
|
||||
MaxCount=1,
|
||||
SecurityGroupIds=[security_group_id])
|
||||
instance_id = client.describe_instances()['Reservations'][0]['Instances'][0]['InstanceId']
|
||||
|
||||
valid_instance_attributes = ['instanceType', 'kernel', 'ramdisk', 'userData', 'disableApiTermination', 'instanceInitiatedShutdownBehavior', 'rootDeviceName', 'blockDeviceMapping', 'productCodes', 'sourceDestCheck', 'groupSet', 'ebsOptimized', 'sriovNetSupport']
|
||||
|
||||
for valid_instance_attribute in valid_instance_attributes:
|
||||
response = client.describe_instance_attribute(InstanceId=instance_id, Attribute=valid_instance_attribute)
|
||||
if valid_instance_attribute == "groupSet":
|
||||
response.should.have.key("Groups")
|
||||
response["Groups"].should.have.length_of(1)
|
||||
response["Groups"][0]["GroupId"].should.equal(security_group_id)
|
||||
elif valid_instance_attribute == "userData":
|
||||
response.should.have.key("UserData")
|
||||
response["UserData"].should.be.empty
|
||||
|
||||
invalid_instance_attributes = ['abc', 'Kernel', 'RamDisk', 'userdata', 'iNsTaNcEtYpE']
|
||||
|
||||
for invalid_instance_attribute in invalid_instance_attributes:
|
||||
with assert_raises(ClientError) as ex:
|
||||
client.describe_instance_attribute(InstanceId=instance_id, Attribute=invalid_instance_attribute)
|
||||
ex.exception.response['Error']['Code'].should.equal('InvalidParameterValue')
|
||||
ex.exception.response['ResponseMetadata']['HTTPStatusCode'].should.equal(400)
|
||||
message = 'Value ({invalid_instance_attribute}) for parameter attribute is invalid. Unknown attribute.'.format(invalid_instance_attribute=invalid_instance_attribute)
|
||||
ex.exception.response['Error']['Message'].should.equal(message)
|
||||
|
|
|
|||
|
|
@ -30,12 +30,12 @@ def test_new_subnet_associates_with_default_network_acl():
|
|||
conn = boto.connect_vpc('the_key', 'the secret')
|
||||
vpc = conn.get_all_vpcs()[0]
|
||||
|
||||
subnet = conn.create_subnet(vpc.id, "172.31.48.0/20")
|
||||
subnet = conn.create_subnet(vpc.id, "172.31.112.0/20")
|
||||
all_network_acls = conn.get_all_network_acls()
|
||||
all_network_acls.should.have.length_of(1)
|
||||
|
||||
acl = all_network_acls[0]
|
||||
acl.associations.should.have.length_of(4)
|
||||
acl.associations.should.have.length_of(7)
|
||||
[a.subnet_id for a in acl.associations].should.contain(subnet.id)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ def test_boto3_non_default_subnet():
|
|||
|
||||
|
||||
@mock_ec2
|
||||
def test_modify_subnet_attribute():
|
||||
def test_modify_subnet_attribute_public_ip_on_launch():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
client = boto3.client('ec2', region_name='us-west-1')
|
||||
|
||||
|
|
@ -145,6 +145,34 @@ def test_modify_subnet_attribute():
|
|||
subnet.map_public_ip_on_launch.should.be.ok
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_modify_subnet_attribute_assign_ipv6_address_on_creation():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
client = boto3.client('ec2', region_name='us-west-1')
|
||||
|
||||
# Get the default VPC
|
||||
vpc = list(ec2.vpcs.all())[0]
|
||||
|
||||
subnet = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock='172.31.112.0/20', AvailabilityZone='us-west-1a')
|
||||
|
||||
# 'map_public_ip_on_launch' is set when calling 'DescribeSubnets' action
|
||||
subnet.reload()
|
||||
|
||||
# For non default subnet, attribute value should be 'False'
|
||||
subnet.assign_ipv6_address_on_creation.shouldnt.be.ok
|
||||
|
||||
client.modify_subnet_attribute(
|
||||
SubnetId=subnet.id, AssignIpv6AddressOnCreation={'Value': False})
|
||||
subnet.reload()
|
||||
subnet.assign_ipv6_address_on_creation.shouldnt.be.ok
|
||||
|
||||
client.modify_subnet_attribute(
|
||||
SubnetId=subnet.id, AssignIpv6AddressOnCreation={'Value': True})
|
||||
subnet.reload()
|
||||
subnet.assign_ipv6_address_on_creation.should.be.ok
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_modify_subnet_attribute_validation():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
|
|
@ -291,6 +319,84 @@ def test_subnet_tags_through_cloudformation():
|
|||
subnet.tags["blah"].should.equal("baz")
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_create_subnet_response_fields():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
client = boto3.client('ec2', region_name='us-west-1')
|
||||
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
subnet = client.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock='10.0.0.0/24', AvailabilityZone='us-west-1a')['Subnet']
|
||||
|
||||
subnet.should.have.key('AvailabilityZone')
|
||||
subnet.should.have.key('AvailabilityZoneId')
|
||||
subnet.should.have.key('AvailableIpAddressCount')
|
||||
subnet.should.have.key('CidrBlock')
|
||||
subnet.should.have.key('State')
|
||||
subnet.should.have.key('SubnetId')
|
||||
subnet.should.have.key('VpcId')
|
||||
subnet.shouldnt.have.key('Tags')
|
||||
subnet.should.have.key('DefaultForAz').which.should.equal(False)
|
||||
subnet.should.have.key('MapPublicIpOnLaunch').which.should.equal(False)
|
||||
subnet.should.have.key('OwnerId')
|
||||
subnet.should.have.key('AssignIpv6AddressOnCreation').which.should.equal(False)
|
||||
|
||||
subnet_arn = "arn:aws:ec2:{region}:{owner_id}:subnet/{subnet_id}".format(region=subnet['AvailabilityZone'][0:-1],
|
||||
owner_id=subnet['OwnerId'],
|
||||
subnet_id=subnet['SubnetId'])
|
||||
subnet.should.have.key('SubnetArn').which.should.equal(subnet_arn)
|
||||
subnet.should.have.key('Ipv6CidrBlockAssociationSet').which.should.equal([])
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_describe_subnet_response_fields():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
client = boto3.client('ec2', region_name='us-west-1')
|
||||
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
subnet_object = ec2.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock='10.0.0.0/24', AvailabilityZone='us-west-1a')
|
||||
|
||||
subnets = client.describe_subnets(SubnetIds=[subnet_object.id])['Subnets']
|
||||
subnets.should.have.length_of(1)
|
||||
subnet = subnets[0]
|
||||
|
||||
subnet.should.have.key('AvailabilityZone')
|
||||
subnet.should.have.key('AvailabilityZoneId')
|
||||
subnet.should.have.key('AvailableIpAddressCount')
|
||||
subnet.should.have.key('CidrBlock')
|
||||
subnet.should.have.key('State')
|
||||
subnet.should.have.key('SubnetId')
|
||||
subnet.should.have.key('VpcId')
|
||||
subnet.shouldnt.have.key('Tags')
|
||||
subnet.should.have.key('DefaultForAz').which.should.equal(False)
|
||||
subnet.should.have.key('MapPublicIpOnLaunch').which.should.equal(False)
|
||||
subnet.should.have.key('OwnerId')
|
||||
subnet.should.have.key('AssignIpv6AddressOnCreation').which.should.equal(False)
|
||||
|
||||
subnet_arn = "arn:aws:ec2:{region}:{owner_id}:subnet/{subnet_id}".format(region=subnet['AvailabilityZone'][0:-1],
|
||||
owner_id=subnet['OwnerId'],
|
||||
subnet_id=subnet['SubnetId'])
|
||||
subnet.should.have.key('SubnetArn').which.should.equal(subnet_arn)
|
||||
subnet.should.have.key('Ipv6CidrBlockAssociationSet').which.should.equal([])
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_create_subnet_with_invalid_availability_zone():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
client = boto3.client('ec2', region_name='us-west-1')
|
||||
|
||||
vpc = ec2.create_vpc(CidrBlock='10.0.0.0/16')
|
||||
|
||||
subnet_availability_zone = 'asfasfas'
|
||||
with assert_raises(ClientError) as ex:
|
||||
subnet = client.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock='10.0.0.0/24', AvailabilityZone=subnet_availability_zone)
|
||||
assert str(ex.exception).startswith(
|
||||
"An error occurred (InvalidParameterValue) when calling the CreateSubnet "
|
||||
"operation: Value ({}) for parameter availabilityZone is invalid. Subnets can currently only be created in the following availability zones: ".format(subnet_availability_zone))
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_create_subnet_with_invalid_cidr_range():
|
||||
ec2 = boto3.resource('ec2', region_name='us-west-1')
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,4 +1,5 @@
|
|||
from __future__ import unicode_literals
|
||||
from datetime import datetime
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
|
|
@ -94,6 +95,10 @@ def test_register_task_definition():
|
|||
}],
|
||||
'logConfiguration': {'logDriver': 'json-file'}
|
||||
}
|
||||
],
|
||||
tags=[
|
||||
{'key': 'createdBy', 'value': 'moto-unittest'},
|
||||
{'key': 'foo', 'value': 'bar'},
|
||||
]
|
||||
)
|
||||
type(response['taskDefinition']).should.be(dict)
|
||||
|
|
@ -473,6 +478,8 @@ def test_describe_services():
|
|||
response['services'][0]['deployments'][0]['pendingCount'].should.equal(2)
|
||||
response['services'][0]['deployments'][0]['runningCount'].should.equal(0)
|
||||
response['services'][0]['deployments'][0]['status'].should.equal('PRIMARY')
|
||||
(datetime.now() - response['services'][0]['deployments'][0]["createdAt"].replace(tzinfo=None)).seconds.should.be.within(0, 10)
|
||||
(datetime.now() - response['services'][0]['deployments'][0]["updatedAt"].replace(tzinfo=None)).seconds.should.be.within(0, 10)
|
||||
|
||||
|
||||
@mock_ecs
|
||||
|
|
@ -2304,3 +2311,52 @@ def test_create_service_load_balancing():
|
|||
response['service']['status'].should.equal('ACTIVE')
|
||||
response['service']['taskDefinition'].should.equal(
|
||||
'arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1')
|
||||
|
||||
|
||||
@mock_ecs
|
||||
def test_list_tags_for_resource():
|
||||
client = boto3.client('ecs', region_name='us-east-1')
|
||||
response = client.register_task_definition(
|
||||
family='test_ecs_task',
|
||||
containerDefinitions=[
|
||||
{
|
||||
'name': 'hello_world',
|
||||
'image': 'docker/hello-world:latest',
|
||||
'cpu': 1024,
|
||||
'memory': 400,
|
||||
'essential': True,
|
||||
'environment': [{
|
||||
'name': 'AWS_ACCESS_KEY_ID',
|
||||
'value': 'SOME_ACCESS_KEY'
|
||||
}],
|
||||
'logConfiguration': {'logDriver': 'json-file'}
|
||||
}
|
||||
],
|
||||
tags=[
|
||||
{'key': 'createdBy', 'value': 'moto-unittest'},
|
||||
{'key': 'foo', 'value': 'bar'},
|
||||
]
|
||||
)
|
||||
type(response['taskDefinition']).should.be(dict)
|
||||
response['taskDefinition']['revision'].should.equal(1)
|
||||
response['taskDefinition']['taskDefinitionArn'].should.equal(
|
||||
'arn:aws:ecs:us-east-1:012345678910:task-definition/test_ecs_task:1')
|
||||
|
||||
task_definition_arn = response['taskDefinition']['taskDefinitionArn']
|
||||
response = client.list_tags_for_resource(resourceArn=task_definition_arn)
|
||||
|
||||
type(response['tags']).should.be(list)
|
||||
response['tags'].should.equal([
|
||||
{'key': 'createdBy', 'value': 'moto-unittest'},
|
||||
{'key': 'foo', 'value': 'bar'},
|
||||
])
|
||||
|
||||
|
||||
@mock_ecs
|
||||
def test_list_tags_for_resource_unknown():
|
||||
client = boto3.client('ecs', region_name='us-east-1')
|
||||
task_definition_arn = 'arn:aws:ecs:us-east-1:012345678910:task-definition/unknown:1'
|
||||
try:
|
||||
client.list_tags_for_resource(resourceArn=task_definition_arn)
|
||||
except ClientError as err:
|
||||
err.response['Error']['Code'].should.equal('ClientException')
|
||||
|
|
|
|||
|
|
@ -667,6 +667,91 @@ def test_register_targets():
|
|||
response.get('TargetHealthDescriptions').should.have.length_of(1)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_elbv2
|
||||
def test_stopped_instance_target():
|
||||
target_group_port = 8080
|
||||
|
||||
conn = boto3.client('elbv2', region_name='us-east-1')
|
||||
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||
|
||||
security_group = ec2.create_security_group(
|
||||
GroupName='a-security-group', Description='First One')
|
||||
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||
subnet1 = ec2.create_subnet(
|
||||
VpcId=vpc.id,
|
||||
CidrBlock='172.28.7.192/26',
|
||||
AvailabilityZone='us-east-1a')
|
||||
subnet2 = ec2.create_subnet(
|
||||
VpcId=vpc.id,
|
||||
CidrBlock='172.28.7.0/26',
|
||||
AvailabilityZone='us-east-1b')
|
||||
|
||||
conn.create_load_balancer(
|
||||
Name='my-lb',
|
||||
Subnets=[subnet1.id, subnet2.id],
|
||||
SecurityGroups=[security_group.id],
|
||||
Scheme='internal',
|
||||
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||
|
||||
response = conn.create_target_group(
|
||||
Name='a-target',
|
||||
Protocol='HTTP',
|
||||
Port=target_group_port,
|
||||
VpcId=vpc.id,
|
||||
HealthCheckProtocol='HTTP',
|
||||
HealthCheckPath='/',
|
||||
HealthCheckIntervalSeconds=5,
|
||||
HealthCheckTimeoutSeconds=5,
|
||||
HealthyThresholdCount=5,
|
||||
UnhealthyThresholdCount=2,
|
||||
Matcher={'HttpCode': '200'})
|
||||
target_group = response.get('TargetGroups')[0]
|
||||
|
||||
# No targets registered yet
|
||||
response = conn.describe_target_health(
|
||||
TargetGroupArn=target_group.get('TargetGroupArn'))
|
||||
response.get('TargetHealthDescriptions').should.have.length_of(0)
|
||||
|
||||
response = ec2.create_instances(
|
||||
ImageId='ami-1234abcd', MinCount=1, MaxCount=1)
|
||||
instance = response[0]
|
||||
|
||||
target_dict = {
|
||||
'Id': instance.id,
|
||||
'Port': 500
|
||||
}
|
||||
|
||||
response = conn.register_targets(
|
||||
TargetGroupArn=target_group.get('TargetGroupArn'),
|
||||
Targets=[target_dict])
|
||||
|
||||
response = conn.describe_target_health(
|
||||
TargetGroupArn=target_group.get('TargetGroupArn'))
|
||||
response.get('TargetHealthDescriptions').should.have.length_of(1)
|
||||
target_health_description = response.get('TargetHealthDescriptions')[0]
|
||||
|
||||
target_health_description['Target'].should.equal(target_dict)
|
||||
target_health_description['HealthCheckPort'].should.equal(str(target_group_port))
|
||||
target_health_description['TargetHealth'].should.equal({
|
||||
'State': 'healthy'
|
||||
})
|
||||
|
||||
instance.stop()
|
||||
|
||||
response = conn.describe_target_health(
|
||||
TargetGroupArn=target_group.get('TargetGroupArn'))
|
||||
response.get('TargetHealthDescriptions').should.have.length_of(1)
|
||||
target_health_description = response.get('TargetHealthDescriptions')[0]
|
||||
target_health_description['Target'].should.equal(target_dict)
|
||||
target_health_description['HealthCheckPort'].should.equal(str(target_group_port))
|
||||
target_health_description['TargetHealth'].should.equal({
|
||||
'State': 'unused',
|
||||
'Reason': 'Target.InvalidState',
|
||||
'Description': 'Target is in the stopped state'
|
||||
})
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_elbv2
|
||||
def test_target_group_attributes():
|
||||
|
|
@ -1726,3 +1811,132 @@ def test_redirect_action_listener_rule_cloudformation():
|
|||
'Port': '443', 'Protocol': 'HTTPS', 'StatusCode': 'HTTP_301',
|
||||
}
|
||||
},])
|
||||
|
||||
|
||||
@mock_elbv2
|
||||
@mock_ec2
|
||||
def test_cognito_action_listener_rule():
|
||||
conn = boto3.client('elbv2', region_name='us-east-1')
|
||||
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||
|
||||
security_group = ec2.create_security_group(
|
||||
GroupName='a-security-group', Description='First One')
|
||||
vpc = ec2.create_vpc(CidrBlock='172.28.7.0/24', InstanceTenancy='default')
|
||||
subnet1 = ec2.create_subnet(
|
||||
VpcId=vpc.id,
|
||||
CidrBlock='172.28.7.192/26',
|
||||
AvailabilityZone='us-east-1a')
|
||||
subnet2 = ec2.create_subnet(
|
||||
VpcId=vpc.id,
|
||||
CidrBlock='172.28.7.128/26',
|
||||
AvailabilityZone='us-east-1b')
|
||||
|
||||
response = conn.create_load_balancer(
|
||||
Name='my-lb',
|
||||
Subnets=[subnet1.id, subnet2.id],
|
||||
SecurityGroups=[security_group.id],
|
||||
Scheme='internal',
|
||||
Tags=[{'Key': 'key_name', 'Value': 'a_value'}])
|
||||
load_balancer_arn = response.get('LoadBalancers')[0].get('LoadBalancerArn')
|
||||
|
||||
action = {
|
||||
'Type': 'authenticate-cognito',
|
||||
'AuthenticateCognitoConfig': {
|
||||
'UserPoolArn': 'arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_ABCD1234',
|
||||
'UserPoolClientId': 'abcd1234abcd',
|
||||
'UserPoolDomain': 'testpool',
|
||||
}
|
||||
}
|
||||
response = conn.create_listener(LoadBalancerArn=load_balancer_arn,
|
||||
Protocol='HTTP',
|
||||
Port=80,
|
||||
DefaultActions=[action])
|
||||
|
||||
listener = response.get('Listeners')[0]
|
||||
listener.get('DefaultActions')[0].should.equal(action)
|
||||
listener_arn = listener.get('ListenerArn')
|
||||
|
||||
describe_rules_response = conn.describe_rules(ListenerArn=listener_arn)
|
||||
describe_rules_response['Rules'][0]['Actions'][0].should.equal(action)
|
||||
|
||||
describe_listener_response = conn.describe_listeners(ListenerArns=[listener_arn, ])
|
||||
describe_listener_actions = describe_listener_response['Listeners'][0]['DefaultActions'][0]
|
||||
describe_listener_actions.should.equal(action)
|
||||
|
||||
|
||||
@mock_elbv2
|
||||
@mock_cloudformation
|
||||
def test_cognito_action_listener_rule_cloudformation():
|
||||
cnf_conn = boto3.client('cloudformation', region_name='us-east-1')
|
||||
elbv2_client = boto3.client('elbv2', region_name='us-east-1')
|
||||
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "ECS Cluster Test CloudFormation",
|
||||
"Resources": {
|
||||
"testVPC": {
|
||||
"Type": "AWS::EC2::VPC",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/16",
|
||||
},
|
||||
},
|
||||
"subnet1": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/24",
|
||||
"VpcId": {"Ref": "testVPC"},
|
||||
"AvalabilityZone": "us-east-1b",
|
||||
},
|
||||
},
|
||||
"subnet2": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.1.0/24",
|
||||
"VpcId": {"Ref": "testVPC"},
|
||||
"AvalabilityZone": "us-east-1b",
|
||||
},
|
||||
},
|
||||
"testLb": {
|
||||
"Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
|
||||
"Properties": {
|
||||
"Name": "my-lb",
|
||||
"Subnets": [{"Ref": "subnet1"}, {"Ref": "subnet2"}],
|
||||
"Type": "application",
|
||||
"SecurityGroups": [],
|
||||
}
|
||||
},
|
||||
"testListener": {
|
||||
"Type": "AWS::ElasticLoadBalancingV2::Listener",
|
||||
"Properties": {
|
||||
"LoadBalancerArn": {"Ref": "testLb"},
|
||||
"Port": 80,
|
||||
"Protocol": "HTTP",
|
||||
"DefaultActions": [{
|
||||
"Type": "authenticate-cognito",
|
||||
"AuthenticateCognitoConfig": {
|
||||
'UserPoolArn': 'arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_ABCD1234',
|
||||
'UserPoolClientId': 'abcd1234abcd',
|
||||
'UserPoolDomain': 'testpool',
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
template_json = json.dumps(template)
|
||||
cnf_conn.create_stack(StackName="test-stack", TemplateBody=template_json)
|
||||
|
||||
describe_load_balancers_response = elbv2_client.describe_load_balancers(Names=['my-lb',])
|
||||
load_balancer_arn = describe_load_balancers_response['LoadBalancers'][0]['LoadBalancerArn']
|
||||
describe_listeners_response = elbv2_client.describe_listeners(LoadBalancerArn=load_balancer_arn)
|
||||
|
||||
describe_listeners_response['Listeners'].should.have.length_of(1)
|
||||
describe_listeners_response['Listeners'][0]['DefaultActions'].should.equal([{
|
||||
'Type': 'authenticate-cognito',
|
||||
"AuthenticateCognitoConfig": {
|
||||
'UserPoolArn': 'arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_ABCD1234',
|
||||
'UserPoolClientId': 'abcd1234abcd',
|
||||
'UserPoolDomain': 'testpool',
|
||||
}
|
||||
},])
|
||||
|
|
|
|||
|
|
@ -229,6 +229,26 @@ def test_delete_table():
|
|||
exc.exception.response['Error']['Code'].should.equal('EntityNotFoundException')
|
||||
exc.exception.response['Error']['Message'].should.match('Table myspecialtable not found')
|
||||
|
||||
@mock_glue
|
||||
def test_batch_delete_table():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
helpers.create_database(client, database_name)
|
||||
|
||||
table_name = 'myspecialtable'
|
||||
table_input = helpers.create_table_input(database_name, table_name)
|
||||
helpers.create_table(client, database_name, table_name, table_input)
|
||||
|
||||
result = client.batch_delete_table(DatabaseName=database_name, TablesToDelete=[table_name])
|
||||
result['ResponseMetadata']['HTTPStatusCode'].should.equal(200)
|
||||
|
||||
# confirm table is deleted
|
||||
with assert_raises(ClientError) as exc:
|
||||
helpers.get_table(client, database_name, table_name)
|
||||
|
||||
exc.exception.response['Error']['Code'].should.equal('EntityNotFoundException')
|
||||
exc.exception.response['Error']['Message'].should.match('Table myspecialtable not found')
|
||||
|
||||
|
||||
@mock_glue
|
||||
def test_get_partitions_empty():
|
||||
|
|
@ -310,6 +330,72 @@ def test_get_partition_not_found():
|
|||
exc.exception.response['Error']['Code'].should.equal('EntityNotFoundException')
|
||||
exc.exception.response['Error']['Message'].should.match('partition')
|
||||
|
||||
@mock_glue
|
||||
def test_batch_create_partition():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
table_name = 'myfirsttable'
|
||||
helpers.create_database(client, database_name)
|
||||
|
||||
helpers.create_table(client, database_name, table_name)
|
||||
|
||||
before = datetime.now(pytz.utc)
|
||||
|
||||
partition_inputs = []
|
||||
for i in range(0, 20):
|
||||
values = ["2018-10-{:2}".format(i)]
|
||||
part_input = helpers.create_partition_input(database_name, table_name, values=values)
|
||||
partition_inputs.append(part_input)
|
||||
|
||||
client.batch_create_partition(
|
||||
DatabaseName=database_name,
|
||||
TableName=table_name,
|
||||
PartitionInputList=partition_inputs
|
||||
)
|
||||
|
||||
after = datetime.now(pytz.utc)
|
||||
|
||||
response = client.get_partitions(DatabaseName=database_name, TableName=table_name)
|
||||
|
||||
partitions = response['Partitions']
|
||||
|
||||
partitions.should.have.length_of(20)
|
||||
|
||||
for idx, partition in enumerate(partitions):
|
||||
partition_input = partition_inputs[idx]
|
||||
|
||||
partition['TableName'].should.equal(table_name)
|
||||
partition['StorageDescriptor'].should.equal(partition_input['StorageDescriptor'])
|
||||
partition['Values'].should.equal(partition_input['Values'])
|
||||
partition['CreationTime'].should.be.greater_than(before)
|
||||
partition['CreationTime'].should.be.lower_than(after)
|
||||
|
||||
|
||||
@mock_glue
|
||||
def test_batch_create_partition_already_exist():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
table_name = 'myfirsttable'
|
||||
values = ['2018-10-01']
|
||||
helpers.create_database(client, database_name)
|
||||
|
||||
helpers.create_table(client, database_name, table_name)
|
||||
|
||||
helpers.create_partition(client, database_name, table_name, values=values)
|
||||
|
||||
partition_input = helpers.create_partition_input(database_name, table_name, values=values)
|
||||
|
||||
response = client.batch_create_partition(
|
||||
DatabaseName=database_name,
|
||||
TableName=table_name,
|
||||
PartitionInputList=[partition_input]
|
||||
)
|
||||
|
||||
response.should.have.key('Errors')
|
||||
response['Errors'].should.have.length_of(1)
|
||||
response['Errors'][0]['PartitionValues'].should.equal(values)
|
||||
response['Errors'][0]['ErrorDetail']['ErrorCode'].should.equal('AlreadyExistsException')
|
||||
|
||||
|
||||
@mock_glue
|
||||
def test_get_partition():
|
||||
|
|
@ -333,6 +419,63 @@ def test_get_partition():
|
|||
partition['Values'].should.equal(values[1])
|
||||
|
||||
|
||||
@mock_glue
|
||||
def test_batch_get_partition():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
table_name = 'myfirsttable'
|
||||
helpers.create_database(client, database_name)
|
||||
|
||||
helpers.create_table(client, database_name, table_name)
|
||||
|
||||
values = [['2018-10-01'], ['2018-09-01']]
|
||||
|
||||
helpers.create_partition(client, database_name, table_name, values=values[0])
|
||||
helpers.create_partition(client, database_name, table_name, values=values[1])
|
||||
|
||||
partitions_to_get = [
|
||||
{'Values': values[0]},
|
||||
{'Values': values[1]},
|
||||
]
|
||||
response = client.batch_get_partition(DatabaseName=database_name, TableName=table_name, PartitionsToGet=partitions_to_get)
|
||||
|
||||
partitions = response['Partitions']
|
||||
partitions.should.have.length_of(2)
|
||||
|
||||
partition = partitions[1]
|
||||
partition['TableName'].should.equal(table_name)
|
||||
partition['Values'].should.equal(values[1])
|
||||
|
||||
|
||||
@mock_glue
|
||||
def test_batch_get_partition_missing_partition():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
table_name = 'myfirsttable'
|
||||
helpers.create_database(client, database_name)
|
||||
|
||||
helpers.create_table(client, database_name, table_name)
|
||||
|
||||
values = [['2018-10-01'], ['2018-09-01'], ['2018-08-01']]
|
||||
|
||||
helpers.create_partition(client, database_name, table_name, values=values[0])
|
||||
helpers.create_partition(client, database_name, table_name, values=values[2])
|
||||
|
||||
partitions_to_get = [
|
||||
{'Values': values[0]},
|
||||
{'Values': values[1]},
|
||||
{'Values': values[2]},
|
||||
]
|
||||
response = client.batch_get_partition(DatabaseName=database_name, TableName=table_name, PartitionsToGet=partitions_to_get)
|
||||
|
||||
partitions = response['Partitions']
|
||||
partitions.should.have.length_of(2)
|
||||
|
||||
partitions[0]['Values'].should.equal(values[0])
|
||||
partitions[1]['Values'].should.equal(values[2])
|
||||
|
||||
|
||||
|
||||
@mock_glue
|
||||
def test_update_partition_not_found_moving():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
|
|
@ -445,3 +588,112 @@ def test_update_partition_move():
|
|||
|
||||
partition['TableName'].should.equal(table_name)
|
||||
partition['StorageDescriptor']['Columns'].should.equal([{'Name': 'country', 'Type': 'string'}])
|
||||
|
||||
@mock_glue
|
||||
def test_delete_partition():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
table_name = 'myfirsttable'
|
||||
values = ['2018-10-01']
|
||||
helpers.create_database(client, database_name)
|
||||
helpers.create_table(client, database_name, table_name)
|
||||
|
||||
part_input = helpers.create_partition_input(database_name, table_name, values=values)
|
||||
helpers.create_partition(client, database_name, table_name, part_input)
|
||||
|
||||
client.delete_partition(
|
||||
DatabaseName=database_name,
|
||||
TableName=table_name,
|
||||
PartitionValues=values,
|
||||
)
|
||||
|
||||
response = client.get_partitions(DatabaseName=database_name, TableName=table_name)
|
||||
partitions = response['Partitions']
|
||||
partitions.should.be.empty
|
||||
|
||||
@mock_glue
|
||||
def test_delete_partition_bad_partition():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
table_name = 'myfirsttable'
|
||||
values = ['2018-10-01']
|
||||
helpers.create_database(client, database_name)
|
||||
helpers.create_table(client, database_name, table_name)
|
||||
|
||||
with assert_raises(ClientError) as exc:
|
||||
client.delete_partition(
|
||||
DatabaseName=database_name,
|
||||
TableName=table_name,
|
||||
PartitionValues=values,
|
||||
)
|
||||
|
||||
exc.exception.response['Error']['Code'].should.equal('EntityNotFoundException')
|
||||
|
||||
@mock_glue
|
||||
def test_batch_delete_partition():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
table_name = 'myfirsttable'
|
||||
helpers.create_database(client, database_name)
|
||||
helpers.create_table(client, database_name, table_name)
|
||||
|
||||
partition_inputs = []
|
||||
for i in range(0, 20):
|
||||
values = ["2018-10-{:2}".format(i)]
|
||||
part_input = helpers.create_partition_input(database_name, table_name, values=values)
|
||||
partition_inputs.append(part_input)
|
||||
|
||||
client.batch_create_partition(
|
||||
DatabaseName=database_name,
|
||||
TableName=table_name,
|
||||
PartitionInputList=partition_inputs
|
||||
)
|
||||
|
||||
partition_values = [{"Values": p["Values"]} for p in partition_inputs]
|
||||
|
||||
response = client.batch_delete_partition(
|
||||
DatabaseName=database_name,
|
||||
TableName=table_name,
|
||||
PartitionsToDelete=partition_values,
|
||||
)
|
||||
|
||||
response.should_not.have.key('Errors')
|
||||
|
||||
@mock_glue
|
||||
def test_batch_delete_partition_with_bad_partitions():
|
||||
client = boto3.client('glue', region_name='us-east-1')
|
||||
database_name = 'myspecialdatabase'
|
||||
table_name = 'myfirsttable'
|
||||
helpers.create_database(client, database_name)
|
||||
helpers.create_table(client, database_name, table_name)
|
||||
|
||||
partition_inputs = []
|
||||
for i in range(0, 20):
|
||||
values = ["2018-10-{:2}".format(i)]
|
||||
part_input = helpers.create_partition_input(database_name, table_name, values=values)
|
||||
partition_inputs.append(part_input)
|
||||
|
||||
client.batch_create_partition(
|
||||
DatabaseName=database_name,
|
||||
TableName=table_name,
|
||||
PartitionInputList=partition_inputs
|
||||
)
|
||||
|
||||
partition_values = [{"Values": p["Values"]} for p in partition_inputs]
|
||||
|
||||
partition_values.insert(5, {"Values": ["2018-11-01"]})
|
||||
partition_values.insert(10, {"Values": ["2018-11-02"]})
|
||||
partition_values.insert(15, {"Values": ["2018-11-03"]})
|
||||
|
||||
response = client.batch_delete_partition(
|
||||
DatabaseName=database_name,
|
||||
TableName=table_name,
|
||||
PartitionsToDelete=partition_values,
|
||||
)
|
||||
|
||||
response.should.have.key('Errors')
|
||||
response['Errors'].should.have.length_of(3)
|
||||
error_partitions = map(lambda x: x['PartitionValues'], response['Errors'])
|
||||
['2018-11-01'].should.be.within(error_partitions)
|
||||
['2018-11-02'].should.be.within(error_partitions)
|
||||
['2018-11-03'].should.be.within(error_partitions)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import unicode_literals
|
||||
import base64
|
||||
import json
|
||||
|
||||
import boto
|
||||
import boto3
|
||||
|
|
@ -29,6 +30,44 @@ FyDHrtlrS80dPUQWNYHw++oACDpWO01LGLPPrGmuO/7cOdojPEd852q5gd+7W9xt
|
|||
8vUH+pBa6IBLbvBp+szli51V3TLSWcoyy4ceJNQU2vCkTLoFdS0RLd/7tQ==
|
||||
-----END CERTIFICATE-----"""
|
||||
|
||||
MOCK_POLICY = """
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement":
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:ListBucket",
|
||||
"Resource": "arn:aws:s3:::example_bucket"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
MOCK_POLICY_2 = """
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "2",
|
||||
"Statement":
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:ListBucket",
|
||||
"Resource": "arn:aws:s3:::example_bucket"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
MOCK_POLICY_3 = """
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "3",
|
||||
"Statement":
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:ListBucket",
|
||||
"Resource": "arn:aws:s3:::example_bucket"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_all_server_certs():
|
||||
|
|
@ -243,12 +282,12 @@ def test_list_instance_profiles_for_role():
|
|||
def test_list_role_policies():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_role("my-role")
|
||||
conn.put_role_policy("my-role", "test policy", "my policy")
|
||||
conn.put_role_policy("my-role", "test policy", MOCK_POLICY)
|
||||
role = conn.list_role_policies("my-role")
|
||||
role.policy_names.should.have.length_of(1)
|
||||
role.policy_names[0].should.equal("test policy")
|
||||
|
||||
conn.put_role_policy("my-role", "test policy 2", "another policy")
|
||||
conn.put_role_policy("my-role", "test policy 2", MOCK_POLICY)
|
||||
role = conn.list_role_policies("my-role")
|
||||
role.policy_names.should.have.length_of(2)
|
||||
|
||||
|
|
@ -266,12 +305,21 @@ def test_put_role_policy():
|
|||
conn = boto.connect_iam()
|
||||
conn.create_role(
|
||||
"my-role", assume_role_policy_document="some policy", path="my-path")
|
||||
conn.put_role_policy("my-role", "test policy", "my policy")
|
||||
conn.put_role_policy("my-role", "test policy", MOCK_POLICY)
|
||||
policy = conn.get_role_policy(
|
||||
"my-role", "test policy")['get_role_policy_response']['get_role_policy_result']['policy_name']
|
||||
policy.should.equal("test policy")
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_get_role_policy():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_role(
|
||||
RoleName="my-role", AssumeRolePolicyDocument="some policy", Path="my-path")
|
||||
with assert_raises(conn.exceptions.NoSuchEntityException):
|
||||
conn.get_role_policy(RoleName="my-role", PolicyName="does-not-exist")
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_update_assume_role_policy():
|
||||
conn = boto.connect_iam()
|
||||
|
|
@ -286,7 +334,7 @@ def test_create_policy():
|
|||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
response = conn.create_policy(
|
||||
PolicyName="TestCreatePolicy",
|
||||
PolicyDocument='{"some":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
response['Policy']['Arn'].should.equal("arn:aws:iam::123456789012:policy/TestCreatePolicy")
|
||||
|
||||
|
||||
|
|
@ -299,20 +347,62 @@ def test_create_policy_versions():
|
|||
PolicyDocument='{"some":"policy"}')
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreatePolicyVersion",
|
||||
PolicyDocument='{"some":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
version = conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestCreatePolicyVersion",
|
||||
PolicyDocument='{"some":"policy"}',
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
SetAsDefault=True)
|
||||
version.get('PolicyVersion').get('Document').should.equal({'some': 'policy'})
|
||||
version.get('PolicyVersion').get('Document').should.equal(json.loads(MOCK_POLICY))
|
||||
version.get('PolicyVersion').get('VersionId').should.equal("v2")
|
||||
version.get('PolicyVersion').get('IsDefaultVersion').should.be.ok
|
||||
conn.delete_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestCreatePolicyVersion",
|
||||
VersionId="v1")
|
||||
version = conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestCreatePolicyVersion",
|
||||
PolicyDocument='{"some":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
version.get('PolicyVersion').get('VersionId').should.equal("v3")
|
||||
version.get('PolicyVersion').get('IsDefaultVersion').shouldnt.be.ok
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_create_many_policy_versions():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_policy(
|
||||
PolicyName="TestCreateManyPolicyVersions",
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
for _ in range(0, 4):
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestCreateManyPolicyVersions",
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
with assert_raises(ClientError):
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestCreateManyPolicyVersions",
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_set_default_policy_version():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_policy(
|
||||
PolicyName="TestSetDefaultPolicyVersion",
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestSetDefaultPolicyVersion",
|
||||
PolicyDocument=MOCK_POLICY_2,
|
||||
SetAsDefault=True)
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestSetDefaultPolicyVersion",
|
||||
PolicyDocument=MOCK_POLICY_3,
|
||||
SetAsDefault=True)
|
||||
versions = conn.list_policy_versions(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestSetDefaultPolicyVersion")
|
||||
versions.get('Versions')[0].get('Document').should.equal(json.loads(MOCK_POLICY))
|
||||
versions.get('Versions')[0].get('IsDefaultVersion').shouldnt.be.ok
|
||||
versions.get('Versions')[1].get('Document').should.equal(json.loads(MOCK_POLICY_2))
|
||||
versions.get('Versions')[1].get('IsDefaultVersion').shouldnt.be.ok
|
||||
versions.get('Versions')[2].get('Document').should.equal(json.loads(MOCK_POLICY_3))
|
||||
versions.get('Versions')[2].get('IsDefaultVersion').should.be.ok
|
||||
|
||||
|
||||
@mock_iam
|
||||
|
|
@ -320,10 +410,21 @@ def test_get_policy():
|
|||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
response = conn.create_policy(
|
||||
PolicyName="TestGetPolicy",
|
||||
PolicyDocument='{"some":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
policy = conn.get_policy(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestGetPolicy")
|
||||
response['Policy']['Arn'].should.equal("arn:aws:iam::123456789012:policy/TestGetPolicy")
|
||||
policy['Policy']['Arn'].should.equal("arn:aws:iam::123456789012:policy/TestGetPolicy")
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_get_aws_managed_policy():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
managed_policy_arn = 'arn:aws:iam::aws:policy/IAMUserChangePassword'
|
||||
managed_policy_create_date = datetime.strptime("2016-11-15T00:25:16+00:00", "%Y-%m-%dT%H:%M:%S+00:00")
|
||||
policy = conn.get_policy(
|
||||
PolicyArn=managed_policy_arn)
|
||||
policy['Policy']['Arn'].should.equal(managed_policy_arn)
|
||||
policy['Policy']['CreateDate'].replace(tzinfo=None).should.equal(managed_policy_create_date)
|
||||
|
||||
|
||||
@mock_iam
|
||||
|
|
@ -331,10 +432,10 @@ def test_get_policy_version():
|
|||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_policy(
|
||||
PolicyName="TestGetPolicyVersion",
|
||||
PolicyDocument='{"some":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
version = conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestGetPolicyVersion",
|
||||
PolicyDocument='{"some":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
with assert_raises(ClientError):
|
||||
conn.get_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestGetPolicyVersion",
|
||||
|
|
@ -342,7 +443,40 @@ def test_get_policy_version():
|
|||
retrieved = conn.get_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestGetPolicyVersion",
|
||||
VersionId=version.get('PolicyVersion').get('VersionId'))
|
||||
retrieved.get('PolicyVersion').get('Document').should.equal({'some': 'policy'})
|
||||
retrieved.get('PolicyVersion').get('Document').should.equal(json.loads(MOCK_POLICY))
|
||||
retrieved.get('PolicyVersion').get('IsDefaultVersion').shouldnt.be.ok
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_get_aws_managed_policy_version():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
managed_policy_arn = 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
|
||||
managed_policy_version_create_date = datetime.strptime("2015-04-09T15:03:43+00:00", "%Y-%m-%dT%H:%M:%S+00:00")
|
||||
with assert_raises(ClientError):
|
||||
conn.get_policy_version(
|
||||
PolicyArn=managed_policy_arn,
|
||||
VersionId='v2-does-not-exist')
|
||||
retrieved = conn.get_policy_version(
|
||||
PolicyArn=managed_policy_arn,
|
||||
VersionId="v1")
|
||||
retrieved['PolicyVersion']['CreateDate'].replace(tzinfo=None).should.equal(managed_policy_version_create_date)
|
||||
retrieved['PolicyVersion']['Document'].should.be.an(dict)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_get_aws_managed_policy_v4_version():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
managed_policy_arn = 'arn:aws:iam::aws:policy/job-function/SystemAdministrator'
|
||||
managed_policy_version_create_date = datetime.strptime("2018-10-08T21:33:45+00:00", "%Y-%m-%dT%H:%M:%S+00:00")
|
||||
with assert_raises(ClientError):
|
||||
conn.get_policy_version(
|
||||
PolicyArn=managed_policy_arn,
|
||||
VersionId='v2-does-not-exist')
|
||||
retrieved = conn.get_policy_version(
|
||||
PolicyArn=managed_policy_arn,
|
||||
VersionId="v4")
|
||||
retrieved['PolicyVersion']['CreateDate'].replace(tzinfo=None).should.equal(managed_policy_version_create_date)
|
||||
retrieved['PolicyVersion']['Document'].should.be.an(dict)
|
||||
|
||||
|
||||
@mock_iam
|
||||
|
|
@ -353,22 +487,24 @@ def test_list_policy_versions():
|
|||
PolicyArn="arn:aws:iam::123456789012:policy/TestListPolicyVersions")
|
||||
conn.create_policy(
|
||||
PolicyName="TestListPolicyVersions",
|
||||
PolicyDocument='{"first":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
versions = conn.list_policy_versions(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestListPolicyVersions")
|
||||
versions.get('Versions')[0].get('VersionId').should.equal('v1')
|
||||
versions.get('Versions')[0].get('IsDefaultVersion').should.be.ok
|
||||
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestListPolicyVersions",
|
||||
PolicyDocument='{"second":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY_2)
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestListPolicyVersions",
|
||||
PolicyDocument='{"third":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY_3)
|
||||
versions = conn.list_policy_versions(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestListPolicyVersions")
|
||||
print(versions.get('Versions'))
|
||||
versions.get('Versions')[1].get('Document').should.equal({'second': 'policy'})
|
||||
versions.get('Versions')[2].get('Document').should.equal({'third': 'policy'})
|
||||
versions.get('Versions')[1].get('Document').should.equal(json.loads(MOCK_POLICY_2))
|
||||
versions.get('Versions')[1].get('IsDefaultVersion').shouldnt.be.ok
|
||||
versions.get('Versions')[2].get('Document').should.equal(json.loads(MOCK_POLICY_3))
|
||||
versions.get('Versions')[2].get('IsDefaultVersion').shouldnt.be.ok
|
||||
|
||||
|
||||
@mock_iam
|
||||
|
|
@ -376,10 +512,10 @@ def test_delete_policy_version():
|
|||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_policy(
|
||||
PolicyName="TestDeletePolicyVersion",
|
||||
PolicyDocument='{"first":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestDeletePolicyVersion",
|
||||
PolicyDocument='{"second":"policy"}')
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
with assert_raises(ClientError):
|
||||
conn.delete_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestDeletePolicyVersion",
|
||||
|
|
@ -392,6 +528,21 @@ def test_delete_policy_version():
|
|||
len(versions.get('Versions')).should.equal(1)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_delete_default_policy_version():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_policy(
|
||||
PolicyName="TestDeletePolicyVersion",
|
||||
PolicyDocument=MOCK_POLICY)
|
||||
conn.create_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestDeletePolicyVersion",
|
||||
PolicyDocument=MOCK_POLICY_2)
|
||||
with assert_raises(ClientError):
|
||||
conn.delete_policy_version(
|
||||
PolicyArn="arn:aws:iam::123456789012:policy/TestDeletePolicyVersion",
|
||||
VersionId='v1')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_create_user():
|
||||
conn = boto.connect_iam()
|
||||
|
|
@ -446,22 +597,20 @@ def test_list_users():
|
|||
@mock_iam()
|
||||
def test_user_policies():
|
||||
policy_name = 'UserManagedPolicy'
|
||||
policy_document = "{'mypolicy': 'test'}"
|
||||
user_name = 'my-user'
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_user(UserName=user_name)
|
||||
conn.put_user_policy(
|
||||
UserName=user_name,
|
||||
PolicyName=policy_name,
|
||||
PolicyDocument=policy_document
|
||||
PolicyDocument=MOCK_POLICY
|
||||
)
|
||||
|
||||
policy_doc = conn.get_user_policy(
|
||||
UserName=user_name,
|
||||
PolicyName=policy_name
|
||||
)
|
||||
test = policy_document in policy_doc['PolicyDocument']
|
||||
test.should.equal(True)
|
||||
policy_doc['PolicyDocument'].should.equal(json.loads(MOCK_POLICY))
|
||||
|
||||
policies = conn.list_user_policies(UserName=user_name)
|
||||
len(policies['PolicyNames']).should.equal(1)
|
||||
|
|
@ -497,13 +646,17 @@ def test_delete_login_profile():
|
|||
conn.delete_login_profile('my-user')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
@mock_iam()
|
||||
def test_create_access_key():
|
||||
conn = boto.connect_iam()
|
||||
with assert_raises(BotoServerError):
|
||||
conn.create_access_key('my-user')
|
||||
conn.create_user('my-user')
|
||||
conn.create_access_key('my-user')
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
with assert_raises(ClientError):
|
||||
conn.create_access_key(UserName='my-user')
|
||||
conn.create_user(UserName='my-user')
|
||||
access_key = conn.create_access_key(UserName='my-user')["AccessKey"]
|
||||
(datetime.utcnow() - access_key["CreateDate"].replace(tzinfo=None)).seconds.should.be.within(0, 10)
|
||||
access_key["AccessKeyId"].should.have.length_of(20)
|
||||
access_key["SecretAccessKey"].should.have.length_of(40)
|
||||
assert access_key["AccessKeyId"].startswith("AKIA")
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
|
|
@ -622,7 +775,7 @@ def test_managed_policy():
|
|||
conn = boto.connect_iam()
|
||||
|
||||
conn.create_policy(policy_name='UserManagedPolicy',
|
||||
policy_document={'mypolicy': 'test'},
|
||||
policy_document=MOCK_POLICY,
|
||||
path='/mypolicy/',
|
||||
description='my user managed policy')
|
||||
|
||||
|
|
@ -723,7 +876,7 @@ def test_attach_detach_user_policy():
|
|||
|
||||
policy_name = 'UserAttachedPolicy'
|
||||
policy = iam.create_policy(PolicyName=policy_name,
|
||||
PolicyDocument='{"mypolicy": "test"}',
|
||||
PolicyDocument=MOCK_POLICY,
|
||||
Path='/mypolicy/',
|
||||
Description='my user attached policy')
|
||||
|
||||
|
|
@ -779,7 +932,6 @@ def test_get_access_key_last_used():
|
|||
|
||||
@mock_iam
|
||||
def test_get_account_authorization_details():
|
||||
import json
|
||||
test_policy = json.dumps({
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
|
|
@ -792,7 +944,8 @@ def test_get_account_authorization_details():
|
|||
})
|
||||
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_role(RoleName="my-role", AssumeRolePolicyDocument="some policy", Path="/my-path/")
|
||||
boundary = 'arn:aws:iam::123456789012:policy/boundary'
|
||||
conn.create_role(RoleName="my-role", AssumeRolePolicyDocument="some policy", Path="/my-path/", Description='testing', PermissionsBoundary=boundary)
|
||||
conn.create_user(Path='/', UserName='testUser')
|
||||
conn.create_group(Path='/', GroupName='testGroup')
|
||||
conn.create_policy(
|
||||
|
|
@ -833,6 +986,11 @@ def test_get_account_authorization_details():
|
|||
assert len(result['GroupDetailList']) == 0
|
||||
assert len(result['Policies']) == 0
|
||||
assert len(result['RoleDetailList'][0]['InstanceProfileList']) == 1
|
||||
assert result['RoleDetailList'][0]['InstanceProfileList'][0]['Roles'][0]['Description'] == 'testing'
|
||||
assert result['RoleDetailList'][0]['InstanceProfileList'][0]['Roles'][0]['PermissionsBoundary'] == {
|
||||
'PermissionsBoundaryType': 'PermissionsBoundaryPolicy',
|
||||
'PermissionsBoundaryArn': 'arn:aws:iam::123456789012:policy/boundary'
|
||||
}
|
||||
assert len(result['RoleDetailList'][0]['Tags']) == 2
|
||||
assert len(result['RoleDetailList'][0]['RolePolicyList']) == 1
|
||||
assert len(result['RoleDetailList'][0]['AttachedManagedPolicies']) == 1
|
||||
|
|
@ -999,6 +1157,79 @@ def test_delete_saml_provider():
|
|||
assert not resp['Certificates']
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_role_with_tags():
|
||||
"""Tests both the tag_role and get_role_tags capability"""
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_role(RoleName="my-role", AssumeRolePolicyDocument="{}", Tags=[
|
||||
{
|
||||
'Key': 'somekey',
|
||||
'Value': 'somevalue'
|
||||
},
|
||||
{
|
||||
'Key': 'someotherkey',
|
||||
'Value': 'someothervalue'
|
||||
}
|
||||
], Description='testing')
|
||||
|
||||
# Get role:
|
||||
role = conn.get_role(RoleName='my-role')['Role']
|
||||
assert len(role['Tags']) == 2
|
||||
assert role['Tags'][0]['Key'] == 'somekey'
|
||||
assert role['Tags'][0]['Value'] == 'somevalue'
|
||||
assert role['Tags'][1]['Key'] == 'someotherkey'
|
||||
assert role['Tags'][1]['Value'] == 'someothervalue'
|
||||
assert role['Description'] == 'testing'
|
||||
|
||||
# Empty is good:
|
||||
conn.create_role(RoleName="my-role2", AssumeRolePolicyDocument="{}", Tags=[
|
||||
{
|
||||
'Key': 'somekey',
|
||||
'Value': ''
|
||||
}
|
||||
])
|
||||
tags = conn.list_role_tags(RoleName='my-role2')
|
||||
assert len(tags['Tags']) == 1
|
||||
assert tags['Tags'][0]['Key'] == 'somekey'
|
||||
assert tags['Tags'][0]['Value'] == ''
|
||||
|
||||
# Test creating tags with invalid values:
|
||||
# With more than 50 tags:
|
||||
with assert_raises(ClientError) as ce:
|
||||
too_many_tags = list(map(lambda x: {'Key': str(x), 'Value': str(x)}, range(0, 51)))
|
||||
conn.create_role(RoleName="my-role3", AssumeRolePolicyDocument="{}", Tags=too_many_tags)
|
||||
assert 'failed to satisfy constraint: Member must have length less than or equal to 50.' \
|
||||
in ce.exception.response['Error']['Message']
|
||||
|
||||
# With a duplicate tag:
|
||||
with assert_raises(ClientError) as ce:
|
||||
conn.create_role(RoleName="my-role3", AssumeRolePolicyDocument="{}", Tags=[{'Key': '0', 'Value': ''}, {'Key': '0', 'Value': ''}])
|
||||
assert 'Duplicate tag keys found. Please note that Tag keys are case insensitive.' \
|
||||
in ce.exception.response['Error']['Message']
|
||||
|
||||
# Duplicate tag with different casing:
|
||||
with assert_raises(ClientError) as ce:
|
||||
conn.create_role(RoleName="my-role3", AssumeRolePolicyDocument="{}", Tags=[{'Key': 'a', 'Value': ''}, {'Key': 'A', 'Value': ''}])
|
||||
assert 'Duplicate tag keys found. Please note that Tag keys are case insensitive.' \
|
||||
in ce.exception.response['Error']['Message']
|
||||
|
||||
# With a really big key:
|
||||
with assert_raises(ClientError) as ce:
|
||||
conn.create_role(RoleName="my-role3", AssumeRolePolicyDocument="{}", Tags=[{'Key': '0' * 129, 'Value': ''}])
|
||||
assert 'Member must have length less than or equal to 128.' in ce.exception.response['Error']['Message']
|
||||
|
||||
# With a really big value:
|
||||
with assert_raises(ClientError) as ce:
|
||||
conn.create_role(RoleName="my-role3", AssumeRolePolicyDocument="{}", Tags=[{'Key': '0', 'Value': '0' * 257}])
|
||||
assert 'Member must have length less than or equal to 256.' in ce.exception.response['Error']['Message']
|
||||
|
||||
# With an invalid character:
|
||||
with assert_raises(ClientError) as ce:
|
||||
conn.create_role(RoleName="my-role3", AssumeRolePolicyDocument="{}", Tags=[{'Key': 'NOWAY!', 'Value': ''}])
|
||||
assert 'Member must satisfy regular expression pattern: [\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]+' \
|
||||
in ce.exception.response['Error']['Message']
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_tag_role():
|
||||
"""Tests both the tag_role and get_role_tags capability"""
|
||||
|
|
@ -1186,6 +1417,7 @@ def test_update_role_description():
|
|||
|
||||
assert response['Role']['RoleName'] == 'my-role'
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_update_role():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
|
|
@ -1197,6 +1429,7 @@ def test_update_role():
|
|||
response = conn.update_role_description(RoleName="my-role", Description="test")
|
||||
assert response['Role']['RoleName'] == 'my-role'
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_update_role():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
|
|
@ -1211,7 +1444,6 @@ def test_update_role():
|
|||
|
||||
@mock_iam()
|
||||
def test_list_entities_for_policy():
|
||||
import json
|
||||
test_policy = json.dumps({
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
|
|
@ -1292,6 +1524,8 @@ def test_create_role_no_path():
|
|||
resp = conn.create_role(RoleName='my-role', AssumeRolePolicyDocument='some policy', Description='test')
|
||||
resp.get('Role').get('Arn').should.equal('arn:aws:iam::123456789012:role/my-role')
|
||||
resp.get('Role').should_not.have.key('PermissionsBoundary')
|
||||
resp.get('Role').get('Description').should.equal('test')
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_create_role_with_permissions_boundary():
|
||||
|
|
@ -1303,6 +1537,7 @@ def test_create_role_with_permissions_boundary():
|
|||
'PermissionsBoundaryArn': boundary
|
||||
}
|
||||
resp.get('Role').get('PermissionsBoundary').should.equal(expected)
|
||||
resp.get('Role').get('Description').should.equal('test')
|
||||
|
||||
invalid_boundary_arn = 'arn:aws:iam::123456789:not_a_boundary'
|
||||
with assert_raises(ClientError):
|
||||
|
|
|
|||
|
|
@ -1,155 +1,167 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import boto
|
||||
import boto3
|
||||
import sure # noqa
|
||||
|
||||
from nose.tools import assert_raises
|
||||
from boto.exception import BotoServerError
|
||||
from moto import mock_iam, mock_iam_deprecated
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_create_group():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.create_group('my-group')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_group():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
conn.get_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.get_group('not-group')
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_get_group_current():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_group(GroupName='my-group')
|
||||
result = conn.get_group(GroupName='my-group')
|
||||
|
||||
assert result['Group']['Path'] == '/'
|
||||
assert result['Group']['GroupName'] == 'my-group'
|
||||
assert isinstance(result['Group']['CreateDate'], datetime)
|
||||
assert result['Group']['GroupId']
|
||||
assert result['Group']['Arn'] == 'arn:aws:iam::123456789012:group/my-group'
|
||||
assert not result['Users']
|
||||
|
||||
# Make a group with a different path:
|
||||
other_group = conn.create_group(GroupName='my-other-group', Path='some/location')
|
||||
assert other_group['Group']['Path'] == 'some/location'
|
||||
assert other_group['Group']['Arn'] == 'arn:aws:iam::123456789012:group/some/location/my-other-group'
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_all_groups():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group1')
|
||||
conn.create_group('my-group2')
|
||||
groups = conn.get_all_groups()['list_groups_response'][
|
||||
'list_groups_result']['groups']
|
||||
groups.should.have.length_of(2)
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_add_user_to_group():
|
||||
conn = boto.connect_iam()
|
||||
with assert_raises(BotoServerError):
|
||||
conn.add_user_to_group('my-group', 'my-user')
|
||||
conn.create_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.add_user_to_group('my-group', 'my-user')
|
||||
conn.create_user('my-user')
|
||||
conn.add_user_to_group('my-group', 'my-user')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_remove_user_from_group():
|
||||
conn = boto.connect_iam()
|
||||
with assert_raises(BotoServerError):
|
||||
conn.remove_user_from_group('my-group', 'my-user')
|
||||
conn.create_group('my-group')
|
||||
conn.create_user('my-user')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.remove_user_from_group('my-group', 'my-user')
|
||||
conn.add_user_to_group('my-group', 'my-user')
|
||||
conn.remove_user_from_group('my-group', 'my-user')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_groups_for_user():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group1')
|
||||
conn.create_group('my-group2')
|
||||
conn.create_group('other-group')
|
||||
conn.create_user('my-user')
|
||||
conn.add_user_to_group('my-group1', 'my-user')
|
||||
conn.add_user_to_group('my-group2', 'my-user')
|
||||
|
||||
groups = conn.get_groups_for_user(
|
||||
'my-user')['list_groups_for_user_response']['list_groups_for_user_result']['groups']
|
||||
groups.should.have.length_of(2)
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_put_group_policy():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
conn.put_group_policy('my-group', 'my-policy', '{"some": "json"}')
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_attach_group_policies():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_group(GroupName='my-group')
|
||||
conn.list_attached_group_policies(GroupName='my-group')['AttachedPolicies'].should.be.empty
|
||||
policy_arn = 'arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforEC2Role'
|
||||
conn.list_attached_group_policies(GroupName='my-group')['AttachedPolicies'].should.be.empty
|
||||
conn.attach_group_policy(GroupName='my-group', PolicyArn=policy_arn)
|
||||
conn.list_attached_group_policies(GroupName='my-group')['AttachedPolicies'].should.equal(
|
||||
[
|
||||
{
|
||||
'PolicyName': 'AmazonElasticMapReduceforEC2Role',
|
||||
'PolicyArn': policy_arn,
|
||||
}
|
||||
])
|
||||
|
||||
conn.detach_group_policy(GroupName='my-group', PolicyArn=policy_arn)
|
||||
conn.list_attached_group_policies(GroupName='my-group')['AttachedPolicies'].should.be.empty
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_group_policy():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.get_group_policy('my-group', 'my-policy')
|
||||
|
||||
conn.put_group_policy('my-group', 'my-policy', '{"some": "json"}')
|
||||
conn.get_group_policy('my-group', 'my-policy')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_all_group_policies():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
policies = conn.get_all_group_policies('my-group')['list_group_policies_response']['list_group_policies_result']['policy_names']
|
||||
assert policies == []
|
||||
conn.put_group_policy('my-group', 'my-policy', '{"some": "json"}')
|
||||
policies = conn.get_all_group_policies('my-group')['list_group_policies_response']['list_group_policies_result']['policy_names']
|
||||
assert policies == ['my-policy']
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_list_group_policies():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_group(GroupName='my-group')
|
||||
conn.list_group_policies(GroupName='my-group')['PolicyNames'].should.be.empty
|
||||
conn.put_group_policy(GroupName='my-group', PolicyName='my-policy', PolicyDocument='{"some": "json"}')
|
||||
conn.list_group_policies(GroupName='my-group')['PolicyNames'].should.equal(['my-policy'])
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import boto
|
||||
import boto3
|
||||
import sure # noqa
|
||||
|
||||
from nose.tools import assert_raises
|
||||
from boto.exception import BotoServerError
|
||||
from moto import mock_iam, mock_iam_deprecated
|
||||
|
||||
MOCK_POLICY = """
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement":
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": "s3:ListBucket",
|
||||
"Resource": "arn:aws:s3:::example_bucket"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_create_group():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.create_group('my-group')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_group():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
conn.get_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.get_group('not-group')
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_get_group_current():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_group(GroupName='my-group')
|
||||
result = conn.get_group(GroupName='my-group')
|
||||
|
||||
assert result['Group']['Path'] == '/'
|
||||
assert result['Group']['GroupName'] == 'my-group'
|
||||
assert isinstance(result['Group']['CreateDate'], datetime)
|
||||
assert result['Group']['GroupId']
|
||||
assert result['Group']['Arn'] == 'arn:aws:iam::123456789012:group/my-group'
|
||||
assert not result['Users']
|
||||
|
||||
# Make a group with a different path:
|
||||
other_group = conn.create_group(GroupName='my-other-group', Path='some/location')
|
||||
assert other_group['Group']['Path'] == 'some/location'
|
||||
assert other_group['Group']['Arn'] == 'arn:aws:iam::123456789012:group/some/location/my-other-group'
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_all_groups():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group1')
|
||||
conn.create_group('my-group2')
|
||||
groups = conn.get_all_groups()['list_groups_response'][
|
||||
'list_groups_result']['groups']
|
||||
groups.should.have.length_of(2)
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_add_user_to_group():
|
||||
conn = boto.connect_iam()
|
||||
with assert_raises(BotoServerError):
|
||||
conn.add_user_to_group('my-group', 'my-user')
|
||||
conn.create_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.add_user_to_group('my-group', 'my-user')
|
||||
conn.create_user('my-user')
|
||||
conn.add_user_to_group('my-group', 'my-user')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_remove_user_from_group():
|
||||
conn = boto.connect_iam()
|
||||
with assert_raises(BotoServerError):
|
||||
conn.remove_user_from_group('my-group', 'my-user')
|
||||
conn.create_group('my-group')
|
||||
conn.create_user('my-user')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.remove_user_from_group('my-group', 'my-user')
|
||||
conn.add_user_to_group('my-group', 'my-user')
|
||||
conn.remove_user_from_group('my-group', 'my-user')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_groups_for_user():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group1')
|
||||
conn.create_group('my-group2')
|
||||
conn.create_group('other-group')
|
||||
conn.create_user('my-user')
|
||||
conn.add_user_to_group('my-group1', 'my-user')
|
||||
conn.add_user_to_group('my-group2', 'my-user')
|
||||
|
||||
groups = conn.get_groups_for_user(
|
||||
'my-user')['list_groups_for_user_response']['list_groups_for_user_result']['groups']
|
||||
groups.should.have.length_of(2)
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_put_group_policy():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
conn.put_group_policy('my-group', 'my-policy', MOCK_POLICY)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_attach_group_policies():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_group(GroupName='my-group')
|
||||
conn.list_attached_group_policies(GroupName='my-group')['AttachedPolicies'].should.be.empty
|
||||
policy_arn = 'arn:aws:iam::aws:policy/service-role/AmazonElasticMapReduceforEC2Role'
|
||||
conn.list_attached_group_policies(GroupName='my-group')['AttachedPolicies'].should.be.empty
|
||||
conn.attach_group_policy(GroupName='my-group', PolicyArn=policy_arn)
|
||||
conn.list_attached_group_policies(GroupName='my-group')['AttachedPolicies'].should.equal(
|
||||
[
|
||||
{
|
||||
'PolicyName': 'AmazonElasticMapReduceforEC2Role',
|
||||
'PolicyArn': policy_arn,
|
||||
}
|
||||
])
|
||||
|
||||
conn.detach_group_policy(GroupName='my-group', PolicyArn=policy_arn)
|
||||
conn.list_attached_group_policies(GroupName='my-group')['AttachedPolicies'].should.be.empty
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_group_policy():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
with assert_raises(BotoServerError):
|
||||
conn.get_group_policy('my-group', 'my-policy')
|
||||
|
||||
conn.put_group_policy('my-group', 'my-policy', MOCK_POLICY)
|
||||
conn.get_group_policy('my-group', 'my-policy')
|
||||
|
||||
|
||||
@mock_iam_deprecated()
|
||||
def test_get_all_group_policies():
|
||||
conn = boto.connect_iam()
|
||||
conn.create_group('my-group')
|
||||
policies = conn.get_all_group_policies('my-group')['list_group_policies_response']['list_group_policies_result']['policy_names']
|
||||
assert policies == []
|
||||
conn.put_group_policy('my-group', 'my-policy', MOCK_POLICY)
|
||||
policies = conn.get_all_group_policies('my-group')['list_group_policies_response']['list_group_policies_result']['policy_names']
|
||||
assert policies == ['my-policy']
|
||||
|
||||
|
||||
@mock_iam()
|
||||
def test_list_group_policies():
|
||||
conn = boto3.client('iam', region_name='us-east-1')
|
||||
conn.create_group(GroupName='my-group')
|
||||
conn.list_group_policies(GroupName='my-group')['PolicyNames'].should.be.empty
|
||||
conn.put_group_policy(GroupName='my-group', PolicyName='my-policy', PolicyDocument=MOCK_POLICY)
|
||||
conn.list_group_policies(GroupName='my-group')['PolicyNames'].should.equal(['my-policy'])
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from moto import mock_kinesis, mock_kinesis_deprecated
|
|||
def test_create_cluster():
|
||||
conn = boto.kinesis.connect_to_region("us-west-2")
|
||||
|
||||
conn.create_stream("my_stream", 2)
|
||||
conn.create_stream("my_stream", 3)
|
||||
|
||||
stream_response = conn.describe_stream("my_stream")
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ def test_create_cluster():
|
|||
stream["StreamStatus"].should.equal("ACTIVE")
|
||||
|
||||
shards = stream['Shards']
|
||||
shards.should.have.length_of(2)
|
||||
shards.should.have.length_of(3)
|
||||
|
||||
|
||||
@mock_kinesis_deprecated
|
||||
|
|
|
|||
|
|
@ -11,21 +11,29 @@ import sure # noqa
|
|||
from moto import mock_kms, mock_kms_deprecated
|
||||
from nose.tools import assert_raises
|
||||
from freezegun import freeze_time
|
||||
from datetime import date
|
||||
from datetime import datetime
|
||||
from dateutil.tz import tzutc
|
||||
|
||||
|
||||
@mock_kms_deprecated
|
||||
@mock_kms
|
||||
def test_create_key():
|
||||
conn = boto.kms.connect_to_region("us-west-2")
|
||||
conn = boto3.client('kms', region_name='us-east-1')
|
||||
with freeze_time("2015-01-01 00:00:00"):
|
||||
key = conn.create_key(policy="my policy",
|
||||
description="my key", key_usage='ENCRYPT_DECRYPT')
|
||||
key = conn.create_key(Policy="my policy",
|
||||
Description="my key",
|
||||
KeyUsage='ENCRYPT_DECRYPT',
|
||||
Tags=[
|
||||
{
|
||||
'TagKey': 'project',
|
||||
'TagValue': 'moto',
|
||||
},
|
||||
])
|
||||
|
||||
key['KeyMetadata']['Description'].should.equal("my key")
|
||||
key['KeyMetadata']['KeyUsage'].should.equal("ENCRYPT_DECRYPT")
|
||||
key['KeyMetadata']['Enabled'].should.equal(True)
|
||||
key['KeyMetadata']['CreationDate'].should.equal("1420070400")
|
||||
key['KeyMetadata']['CreationDate'].should.be.a(date)
|
||||
|
||||
|
||||
@mock_kms_deprecated
|
||||
|
|
@ -183,6 +191,7 @@ def test_decrypt():
|
|||
conn = boto.kms.connect_to_region('us-west-2')
|
||||
response = conn.decrypt('ZW5jcnlwdG1l'.encode('utf-8'))
|
||||
response['Plaintext'].should.equal(b'encryptme')
|
||||
response['KeyId'].should.equal('key_id')
|
||||
|
||||
|
||||
@mock_kms_deprecated
|
||||
|
|
|
|||
|
|
@ -162,3 +162,63 @@ def test_delete_retention_policy():
|
|||
|
||||
response = conn.delete_log_group(logGroupName=log_group_name)
|
||||
|
||||
|
||||
@mock_logs
|
||||
def test_get_log_events():
|
||||
conn = boto3.client('logs', 'us-west-2')
|
||||
log_group_name = 'test'
|
||||
log_stream_name = 'stream'
|
||||
conn.create_log_group(logGroupName=log_group_name)
|
||||
conn.create_log_stream(
|
||||
logGroupName=log_group_name,
|
||||
logStreamName=log_stream_name
|
||||
)
|
||||
|
||||
events = [{'timestamp': x, 'message': str(x)} for x in range(20)]
|
||||
|
||||
conn.put_log_events(
|
||||
logGroupName=log_group_name,
|
||||
logStreamName=log_stream_name,
|
||||
logEvents=events
|
||||
)
|
||||
|
||||
resp = conn.get_log_events(
|
||||
logGroupName=log_group_name,
|
||||
logStreamName=log_stream_name,
|
||||
limit=10)
|
||||
|
||||
resp['events'].should.have.length_of(10)
|
||||
resp.should.have.key('nextForwardToken')
|
||||
resp.should.have.key('nextBackwardToken')
|
||||
for i in range(10):
|
||||
resp['events'][i]['timestamp'].should.equal(i)
|
||||
resp['events'][i]['message'].should.equal(str(i))
|
||||
|
||||
next_token = resp['nextForwardToken']
|
||||
|
||||
resp = conn.get_log_events(
|
||||
logGroupName=log_group_name,
|
||||
logStreamName=log_stream_name,
|
||||
nextToken=next_token,
|
||||
limit=10)
|
||||
|
||||
resp['events'].should.have.length_of(10)
|
||||
resp.should.have.key('nextForwardToken')
|
||||
resp.should.have.key('nextBackwardToken')
|
||||
resp['nextForwardToken'].should.equal(next_token)
|
||||
for i in range(10):
|
||||
resp['events'][i]['timestamp'].should.equal(i+10)
|
||||
resp['events'][i]['message'].should.equal(str(i+10))
|
||||
|
||||
resp = conn.get_log_events(
|
||||
logGroupName=log_group_name,
|
||||
logStreamName=log_stream_name,
|
||||
nextToken=resp['nextBackwardToken'],
|
||||
limit=10)
|
||||
|
||||
resp['events'].should.have.length_of(10)
|
||||
resp.should.have.key('nextForwardToken')
|
||||
resp.should.have.key('nextBackwardToken')
|
||||
for i in range(10):
|
||||
resp['events'][i]['timestamp'].should.equal(i)
|
||||
resp['events'][i]['message'].should.equal(str(i))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import six
|
||||
import sure # noqa
|
||||
import datetime
|
||||
from moto.organizations import utils
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ from __future__ import unicode_literals
|
|||
import boto3
|
||||
import json
|
||||
import six
|
||||
import sure # noqa
|
||||
from botocore.exceptions import ClientError
|
||||
from nose.tools import assert_raises
|
||||
|
||||
|
|
@ -27,6 +26,25 @@ def test_create_organization():
|
|||
validate_organization(response)
|
||||
response['Organization']['FeatureSet'].should.equal('ALL')
|
||||
|
||||
response = client.list_accounts()
|
||||
len(response['Accounts']).should.equal(1)
|
||||
response['Accounts'][0]['Name'].should.equal('master')
|
||||
response['Accounts'][0]['Id'].should.equal(utils.MASTER_ACCOUNT_ID)
|
||||
response['Accounts'][0]['Email'].should.equal(utils.MASTER_ACCOUNT_EMAIL)
|
||||
|
||||
response = client.list_policies(Filter='SERVICE_CONTROL_POLICY')
|
||||
len(response['Policies']).should.equal(1)
|
||||
response['Policies'][0]['Name'].should.equal('FullAWSAccess')
|
||||
response['Policies'][0]['Id'].should.equal(utils.DEFAULT_POLICY_ID)
|
||||
response['Policies'][0]['AwsManaged'].should.equal(True)
|
||||
|
||||
response = client.list_targets_for_policy(PolicyId=utils.DEFAULT_POLICY_ID)
|
||||
len(response['Targets']).should.equal(2)
|
||||
root_ou = [t for t in response['Targets'] if t['Type'] == 'ROOT'][0]
|
||||
root_ou['Name'].should.equal('Root')
|
||||
master_account = [t for t in response['Targets'] if t['Type'] == 'ACCOUNT'][0]
|
||||
master_account['Name'].should.equal('master')
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_describe_organization():
|
||||
|
|
@ -177,11 +195,11 @@ def test_list_accounts():
|
|||
response = client.list_accounts()
|
||||
response.should.have.key('Accounts')
|
||||
accounts = response['Accounts']
|
||||
len(accounts).should.equal(5)
|
||||
len(accounts).should.equal(6)
|
||||
for account in accounts:
|
||||
validate_account(org, account)
|
||||
accounts[3]['Name'].should.equal(mockname + '3')
|
||||
accounts[2]['Email'].should.equal(mockname + '2' + '@' + mockdomain)
|
||||
accounts[4]['Name'].should.equal(mockname + '3')
|
||||
accounts[3]['Email'].should.equal(mockname + '2' + '@' + mockdomain)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
|
|
@ -291,8 +309,10 @@ def test_list_children():
|
|||
response02 = client.list_children(ParentId=root_id, ChildType='ORGANIZATIONAL_UNIT')
|
||||
response03 = client.list_children(ParentId=ou01_id, ChildType='ACCOUNT')
|
||||
response04 = client.list_children(ParentId=ou01_id, ChildType='ORGANIZATIONAL_UNIT')
|
||||
response01['Children'][0]['Id'].should.equal(account01_id)
|
||||
response01['Children'][0]['Id'].should.equal(utils.MASTER_ACCOUNT_ID)
|
||||
response01['Children'][0]['Type'].should.equal('ACCOUNT')
|
||||
response01['Children'][1]['Id'].should.equal(account01_id)
|
||||
response01['Children'][1]['Type'].should.equal('ACCOUNT')
|
||||
response02['Children'][0]['Id'].should.equal(ou01_id)
|
||||
response02['Children'][0]['Type'].should.equal('ORGANIZATIONAL_UNIT')
|
||||
response03['Children'][0]['Id'].should.equal(account02_id)
|
||||
|
|
@ -591,4 +611,3 @@ def test_list_targets_for_policy_exception():
|
|||
ex.operation_name.should.equal('ListTargetsForPolicy')
|
||||
ex.response['Error']['Code'].should.equal('400')
|
||||
ex.response['Error']['Message'].should.contain('InvalidInputException')
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ def test_create_database():
|
|||
MasterUsername='root',
|
||||
MasterUserPassword='hunter2',
|
||||
Port=1234,
|
||||
DBSecurityGroups=["my_sg"])
|
||||
DBSecurityGroups=["my_sg"],
|
||||
VpcSecurityGroupIds=['sg-123456'])
|
||||
db_instance = database['DBInstance']
|
||||
db_instance['AllocatedStorage'].should.equal(10)
|
||||
db_instance['DBInstanceClass'].should.equal("db.m1.small")
|
||||
|
|
@ -34,6 +35,40 @@ def test_create_database():
|
|||
db_instance['IAMDatabaseAuthenticationEnabled'].should.equal(False)
|
||||
db_instance['DbiResourceId'].should.contain("db-")
|
||||
db_instance['CopyTagsToSnapshot'].should.equal(False)
|
||||
db_instance['InstanceCreateTime'].should.be.a("datetime.datetime")
|
||||
db_instance['VpcSecurityGroups'][0]['VpcSecurityGroupId'].should.equal('sg-123456')
|
||||
|
||||
|
||||
@mock_rds2
|
||||
def test_create_database_non_existing_option_group():
|
||||
conn = boto3.client('rds', region_name='us-west-2')
|
||||
database = conn.create_db_instance.when.called_with(
|
||||
DBInstanceIdentifier='db-master-1',
|
||||
AllocatedStorage=10,
|
||||
Engine='postgres',
|
||||
DBName='staging-postgres',
|
||||
DBInstanceClass='db.m1.small',
|
||||
OptionGroupName='non-existing').should.throw(ClientError)
|
||||
|
||||
|
||||
@mock_rds2
|
||||
def test_create_database_with_option_group():
|
||||
conn = boto3.client('rds', region_name='us-west-2')
|
||||
conn.create_option_group(OptionGroupName='my-og',
|
||||
EngineName='mysql',
|
||||
MajorEngineVersion='5.6',
|
||||
OptionGroupDescription='test option group')
|
||||
database = conn.create_db_instance(DBInstanceIdentifier='db-master-1',
|
||||
AllocatedStorage=10,
|
||||
Engine='postgres',
|
||||
DBName='staging-postgres',
|
||||
DBInstanceClass='db.m1.small',
|
||||
OptionGroupName='my-og')
|
||||
db_instance = database['DBInstance']
|
||||
db_instance['AllocatedStorage'].should.equal(10)
|
||||
db_instance['DBInstanceClass'].should.equal('db.m1.small')
|
||||
db_instance['DBName'].should.equal('staging-postgres')
|
||||
db_instance['OptionGroupMemberships'][0]['OptionGroupName'].should.equal('my-og')
|
||||
|
||||
|
||||
@mock_rds2
|
||||
|
|
@ -204,6 +239,7 @@ def test_get_databases_paginated():
|
|||
resp3 = conn.describe_db_instances(MaxRecords=100)
|
||||
resp3["DBInstances"].should.have.length_of(51)
|
||||
|
||||
|
||||
@mock_rds2
|
||||
def test_describe_non_existant_database():
|
||||
conn = boto3.client('rds', region_name='us-west-2')
|
||||
|
|
@ -226,9 +262,11 @@ def test_modify_db_instance():
|
|||
instances['DBInstances'][0]['AllocatedStorage'].should.equal(10)
|
||||
conn.modify_db_instance(DBInstanceIdentifier='db-master-1',
|
||||
AllocatedStorage=20,
|
||||
ApplyImmediately=True)
|
||||
ApplyImmediately=True,
|
||||
VpcSecurityGroupIds=['sg-123456'])
|
||||
instances = conn.describe_db_instances(DBInstanceIdentifier='db-master-1')
|
||||
instances['DBInstances'][0]['AllocatedStorage'].should.equal(20)
|
||||
instances['DBInstances'][0]['VpcSecurityGroups'][0]['VpcSecurityGroupId'].should.equal('sg-123456')
|
||||
|
||||
|
||||
@mock_rds2
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ def test_create_cluster_boto3():
|
|||
response['Cluster']['NodeType'].should.equal('ds2.xlarge')
|
||||
create_time = response['Cluster']['ClusterCreateTime']
|
||||
create_time.should.be.lower_than(datetime.datetime.now(create_time.tzinfo))
|
||||
create_time.should.be.greater_than(datetime.datetime.now(create_time.tzinfo) - datetime.timedelta(minutes=1))
|
||||
|
||||
|
||||
@mock_redshift
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ from __future__ import unicode_literals
|
|||
|
||||
import boto3
|
||||
import sure # noqa
|
||||
from moto import mock_resourcegroupstaggingapi, mock_s3, mock_ec2, mock_elbv2
|
||||
from moto import mock_ec2
|
||||
from moto import mock_elbv2
|
||||
from moto import mock_kms
|
||||
from moto import mock_resourcegroupstaggingapi
|
||||
from moto import mock_s3
|
||||
|
||||
|
||||
@mock_s3
|
||||
|
|
@ -225,10 +229,12 @@ def test_get_tag_values_ec2():
|
|||
|
||||
@mock_ec2
|
||||
@mock_elbv2
|
||||
@mock_kms
|
||||
@mock_resourcegroupstaggingapi
|
||||
def test_get_resources_elbv2():
|
||||
conn = boto3.client('elbv2', region_name='us-east-1')
|
||||
def test_get_many_resources():
|
||||
elbv2 = boto3.client('elbv2', region_name='us-east-1')
|
||||
ec2 = boto3.resource('ec2', region_name='us-east-1')
|
||||
kms = boto3.client('kms', region_name='us-east-1')
|
||||
|
||||
security_group = ec2.create_security_group(
|
||||
GroupName='a-security-group', Description='First One')
|
||||
|
|
@ -242,7 +248,7 @@ def test_get_resources_elbv2():
|
|||
CidrBlock='172.28.7.0/26',
|
||||
AvailabilityZone='us-east-1b')
|
||||
|
||||
conn.create_load_balancer(
|
||||
elbv2.create_load_balancer(
|
||||
Name='my-lb',
|
||||
Subnets=[subnet1.id, subnet2.id],
|
||||
SecurityGroups=[security_group.id],
|
||||
|
|
@ -259,13 +265,27 @@ def test_get_resources_elbv2():
|
|||
]
|
||||
)
|
||||
|
||||
conn.create_load_balancer(
|
||||
elbv2.create_load_balancer(
|
||||
Name='my-other-lb',
|
||||
Subnets=[subnet1.id, subnet2.id],
|
||||
SecurityGroups=[security_group.id],
|
||||
Scheme='internal',
|
||||
)
|
||||
|
||||
kms.create_key(
|
||||
KeyUsage='ENCRYPT_DECRYPT',
|
||||
Tags=[
|
||||
{
|
||||
'TagKey': 'key_name',
|
||||
'TagValue': 'a_value'
|
||||
},
|
||||
{
|
||||
'TagKey': 'key_2',
|
||||
'TagValue': 'val2'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
rtapi = boto3.client('resourcegroupstaggingapi', region_name='us-east-1')
|
||||
|
||||
resp = rtapi.get_resources(ResourceTypeFilters=['elasticloadbalancer:loadbalancer'])
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ def test_rrset():
|
|||
|
||||
changes = ResourceRecordSets(conn, zoneid)
|
||||
changes.add_change("DELETE", "foo.bar.testdns.aws.com", "A")
|
||||
changes.add_change("DELETE", "foo.bar.testdns.aws.com", "TXT")
|
||||
changes.commit()
|
||||
|
||||
changes = ResourceRecordSets(conn, zoneid)
|
||||
|
|
@ -123,12 +124,12 @@ def test_rrset():
|
|||
rrsets.should.have.length_of(2)
|
||||
|
||||
rrsets = conn.get_all_rrsets(
|
||||
zoneid, name="foo.bar.testdns.aws.com", type="A")
|
||||
zoneid, name="bar.foo.testdns.aws.com", type="A")
|
||||
rrsets.should.have.length_of(1)
|
||||
rrsets[0].resource_records[0].should.equal('1.2.3.4')
|
||||
rrsets[0].resource_records[0].should.equal('5.6.7.8')
|
||||
|
||||
rrsets = conn.get_all_rrsets(
|
||||
zoneid, name="bar.foo.testdns.aws.com", type="A")
|
||||
zoneid, name="foo.bar.testdns.aws.com", type="A")
|
||||
rrsets.should.have.length_of(2)
|
||||
resource_records = [rr for rr_set in rrsets for rr in rr_set.resource_records]
|
||||
resource_records.should.contain('1.2.3.4')
|
||||
|
|
@ -172,14 +173,16 @@ def test_alias_rrset():
|
|||
changes.commit()
|
||||
|
||||
rrsets = conn.get_all_rrsets(zoneid, type="A")
|
||||
rrset_records = [(rr_set.name, rr) for rr_set in rrsets for rr in rr_set.resource_records]
|
||||
rrset_records.should.have.length_of(2)
|
||||
rrset_records.should.contain(('foo.alias.testdns.aws.com.', 'foo.testdns.aws.com'))
|
||||
rrset_records.should.contain(('bar.alias.testdns.aws.com.', 'bar.testdns.aws.com'))
|
||||
rrsets[0].resource_records[0].should.equal('foo.testdns.aws.com')
|
||||
alias_targets = [rr_set.alias_dns_name for rr_set in rrsets]
|
||||
alias_targets.should.have.length_of(2)
|
||||
alias_targets.should.contain('foo.testdns.aws.com')
|
||||
alias_targets.should.contain('bar.testdns.aws.com')
|
||||
rrsets[0].alias_dns_name.should.equal('foo.testdns.aws.com')
|
||||
rrsets[0].resource_records.should.have.length_of(0)
|
||||
rrsets = conn.get_all_rrsets(zoneid, type="CNAME")
|
||||
rrsets.should.have.length_of(1)
|
||||
rrsets[0].resource_records[0].should.equal('bar.testdns.aws.com')
|
||||
rrsets[0].alias_dns_name.should.equal('bar.testdns.aws.com')
|
||||
rrsets[0].resource_records.should.have.length_of(0)
|
||||
|
||||
|
||||
@mock_route53_deprecated
|
||||
|
|
@ -582,7 +585,40 @@ def test_change_resource_record_sets_crud_valid():
|
|||
cname_record_detail['TTL'].should.equal(60)
|
||||
cname_record_detail['ResourceRecords'].should.equal([{'Value': '192.168.1.1'}])
|
||||
|
||||
# Delete record.
|
||||
# Update to add Alias.
|
||||
cname_alias_record_endpoint_payload = {
|
||||
'Comment': 'Update to Alias prod.redis.db',
|
||||
'Changes': [
|
||||
{
|
||||
'Action': 'UPSERT',
|
||||
'ResourceRecordSet': {
|
||||
'Name': 'prod.redis.db.',
|
||||
'Type': 'A',
|
||||
'TTL': 60,
|
||||
'AliasTarget': {
|
||||
'HostedZoneId': hosted_zone_id,
|
||||
'DNSName': 'prod.redis.alias.',
|
||||
'EvaluateTargetHealth': False,
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
conn.change_resource_record_sets(HostedZoneId=hosted_zone_id, ChangeBatch=cname_alias_record_endpoint_payload)
|
||||
|
||||
response = conn.list_resource_record_sets(HostedZoneId=hosted_zone_id)
|
||||
cname_alias_record_detail = response['ResourceRecordSets'][0]
|
||||
cname_alias_record_detail['Name'].should.equal('prod.redis.db.')
|
||||
cname_alias_record_detail['Type'].should.equal('A')
|
||||
cname_alias_record_detail['TTL'].should.equal(60)
|
||||
cname_alias_record_detail['AliasTarget'].should.equal({
|
||||
'HostedZoneId': hosted_zone_id,
|
||||
'DNSName': 'prod.redis.alias.',
|
||||
'EvaluateTargetHealth': False,
|
||||
})
|
||||
cname_alias_record_detail.should_not.contain('ResourceRecords')
|
||||
|
||||
# Delete record with wrong type.
|
||||
delete_payload = {
|
||||
'Comment': 'delete prod.redis.db',
|
||||
'Changes': [
|
||||
|
|
@ -597,8 +633,133 @@ def test_change_resource_record_sets_crud_valid():
|
|||
}
|
||||
conn.change_resource_record_sets(HostedZoneId=hosted_zone_id, ChangeBatch=delete_payload)
|
||||
response = conn.list_resource_record_sets(HostedZoneId=hosted_zone_id)
|
||||
len(response['ResourceRecordSets']).should.equal(1)
|
||||
|
||||
# Delete record.
|
||||
delete_payload = {
|
||||
'Comment': 'delete prod.redis.db',
|
||||
'Changes': [
|
||||
{
|
||||
'Action': 'DELETE',
|
||||
'ResourceRecordSet': {
|
||||
'Name': 'prod.redis.db',
|
||||
'Type': 'A',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
conn.change_resource_record_sets(HostedZoneId=hosted_zone_id, ChangeBatch=delete_payload)
|
||||
response = conn.list_resource_record_sets(HostedZoneId=hosted_zone_id)
|
||||
len(response['ResourceRecordSets']).should.equal(0)
|
||||
|
||||
@mock_route53
|
||||
def test_change_weighted_resource_record_sets():
|
||||
conn = boto3.client('route53', region_name='us-east-2')
|
||||
conn.create_hosted_zone(
|
||||
Name='test.vpc.internal.',
|
||||
CallerReference=str(hash('test'))
|
||||
)
|
||||
|
||||
zones = conn.list_hosted_zones_by_name(
|
||||
DNSName='test.vpc.internal.'
|
||||
)
|
||||
|
||||
hosted_zone_id = zones['HostedZones'][0]['Id']
|
||||
|
||||
#Create 2 weighted records
|
||||
conn.change_resource_record_sets(
|
||||
HostedZoneId=hosted_zone_id,
|
||||
ChangeBatch={
|
||||
'Changes': [
|
||||
{
|
||||
'Action': 'CREATE',
|
||||
'ResourceRecordSet': {
|
||||
'Name': 'test.vpc.internal',
|
||||
'Type': 'A',
|
||||
'SetIdentifier': 'test1',
|
||||
'Weight': 50,
|
||||
'AliasTarget': {
|
||||
'HostedZoneId': 'Z3AADJGX6KTTL2',
|
||||
'DNSName': 'internal-test1lb-447688172.us-east-2.elb.amazonaws.com.',
|
||||
'EvaluateTargetHealth': True
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
'Action': 'CREATE',
|
||||
'ResourceRecordSet': {
|
||||
'Name': 'test.vpc.internal',
|
||||
'Type': 'A',
|
||||
'SetIdentifier': 'test2',
|
||||
'Weight': 50,
|
||||
'AliasTarget': {
|
||||
'HostedZoneId': 'Z3AADJGX6KTTL2',
|
||||
'DNSName': 'internal-testlb2-1116641781.us-east-2.elb.amazonaws.com.',
|
||||
'EvaluateTargetHealth': True
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
response = conn.list_resource_record_sets(HostedZoneId=hosted_zone_id)
|
||||
record = response['ResourceRecordSets'][0]
|
||||
#Update the first record to have a weight of 90
|
||||
conn.change_resource_record_sets(
|
||||
HostedZoneId=hosted_zone_id,
|
||||
ChangeBatch={
|
||||
'Changes' : [
|
||||
{
|
||||
'Action' : 'UPSERT',
|
||||
'ResourceRecordSet' : {
|
||||
'Name' : record['Name'],
|
||||
'Type' : record['Type'],
|
||||
'SetIdentifier' : record['SetIdentifier'],
|
||||
'Weight' : 90,
|
||||
'AliasTarget' : {
|
||||
'HostedZoneId' : record['AliasTarget']['HostedZoneId'],
|
||||
'DNSName' : record['AliasTarget']['DNSName'],
|
||||
'EvaluateTargetHealth' : record['AliasTarget']['EvaluateTargetHealth']
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
record = response['ResourceRecordSets'][1]
|
||||
#Update the second record to have a weight of 10
|
||||
conn.change_resource_record_sets(
|
||||
HostedZoneId=hosted_zone_id,
|
||||
ChangeBatch={
|
||||
'Changes' : [
|
||||
{
|
||||
'Action' : 'UPSERT',
|
||||
'ResourceRecordSet' : {
|
||||
'Name' : record['Name'],
|
||||
'Type' : record['Type'],
|
||||
'SetIdentifier' : record['SetIdentifier'],
|
||||
'Weight' : 10,
|
||||
'AliasTarget' : {
|
||||
'HostedZoneId' : record['AliasTarget']['HostedZoneId'],
|
||||
'DNSName' : record['AliasTarget']['DNSName'],
|
||||
'EvaluateTargetHealth' : record['AliasTarget']['EvaluateTargetHealth']
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
response = conn.list_resource_record_sets(HostedZoneId=hosted_zone_id)
|
||||
for record in response['ResourceRecordSets']:
|
||||
if record['SetIdentifier'] == 'test1':
|
||||
record['Weight'].should.equal(90)
|
||||
if record['SetIdentifier'] == 'test2':
|
||||
record['Weight'].should.equal(10)
|
||||
|
||||
|
||||
@mock_route53
|
||||
def test_change_resource_record_invalid():
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ def test_delete_keys():
|
|||
|
||||
|
||||
@mock_s3_deprecated
|
||||
def test_delete_keys_with_invalid():
|
||||
def test_delete_keys_invalid():
|
||||
conn = boto.connect_s3('the_key', 'the_secret')
|
||||
bucket = conn.create_bucket('foobar')
|
||||
|
||||
|
|
@ -648,6 +648,7 @@ def test_delete_keys_with_invalid():
|
|||
Key(bucket=bucket, name='file3').set_contents_from_string('abc')
|
||||
Key(bucket=bucket, name='file4').set_contents_from_string('abc')
|
||||
|
||||
# non-existing key case
|
||||
result = bucket.delete_keys(['abc', 'file3'])
|
||||
|
||||
result.deleted.should.have.length_of(1)
|
||||
|
|
@ -656,6 +657,18 @@ def test_delete_keys_with_invalid():
|
|||
keys.should.have.length_of(3)
|
||||
keys[0].name.should.equal('file1')
|
||||
|
||||
# empty keys
|
||||
result = bucket.delete_keys([])
|
||||
|
||||
result.deleted.should.have.length_of(0)
|
||||
result.errors.should.have.length_of(0)
|
||||
|
||||
@mock_s3
|
||||
def test_boto3_delete_empty_keys_list():
|
||||
with assert_raises(ClientError) as err:
|
||||
boto3.client('s3').delete_objects(Bucket='foobar', Delete={'Objects': []})
|
||||
assert err.exception.response["Error"]["Code"] == "MalformedXML"
|
||||
|
||||
|
||||
@mock_s3_deprecated
|
||||
def test_bucket_name_with_dot():
|
||||
|
|
@ -1596,6 +1609,28 @@ def test_boto3_delete_versioned_bucket():
|
|||
|
||||
client.delete_bucket(Bucket='blah')
|
||||
|
||||
@mock_s3
|
||||
def test_boto3_get_object_if_modified_since():
|
||||
s3 = boto3.client('s3', region_name='us-east-1')
|
||||
bucket_name = "blah"
|
||||
s3.create_bucket(Bucket=bucket_name)
|
||||
|
||||
key = 'hello.txt'
|
||||
|
||||
s3.put_object(
|
||||
Bucket=bucket_name,
|
||||
Key=key,
|
||||
Body='test'
|
||||
)
|
||||
|
||||
with assert_raises(botocore.exceptions.ClientError) as err:
|
||||
s3.get_object(
|
||||
Bucket=bucket_name,
|
||||
Key=key,
|
||||
IfModifiedSince=datetime.datetime.utcnow() + datetime.timedelta(hours=1)
|
||||
)
|
||||
e = err.exception
|
||||
e.response['Error'].should.equal({'Code': '304', 'Message': 'Not Modified'})
|
||||
|
||||
@mock_s3
|
||||
def test_boto3_head_object_if_modified_since():
|
||||
|
|
@ -1649,6 +1684,42 @@ def test_boto3_multipart_etag():
|
|||
resp['ETag'].should.equal(EXPECTED_ETAG)
|
||||
|
||||
|
||||
@mock_s3
|
||||
@reduced_min_part_size
|
||||
def test_boto3_multipart_part_size():
|
||||
s3 = boto3.client('s3', region_name='us-east-1')
|
||||
s3.create_bucket(Bucket='mybucket')
|
||||
|
||||
mpu = s3.create_multipart_upload(Bucket='mybucket', Key='the-key')
|
||||
mpu_id = mpu["UploadId"]
|
||||
|
||||
parts = []
|
||||
n_parts = 10
|
||||
for i in range(1, n_parts + 1):
|
||||
part_size = REDUCED_PART_SIZE + i
|
||||
body = b'1' * part_size
|
||||
part = s3.upload_part(
|
||||
Bucket='mybucket',
|
||||
Key='the-key',
|
||||
PartNumber=i,
|
||||
UploadId=mpu_id,
|
||||
Body=body,
|
||||
ContentLength=len(body),
|
||||
)
|
||||
parts.append({"PartNumber": i, "ETag": part["ETag"]})
|
||||
|
||||
s3.complete_multipart_upload(
|
||||
Bucket='mybucket',
|
||||
Key='the-key',
|
||||
UploadId=mpu_id,
|
||||
MultipartUpload={"Parts": parts},
|
||||
)
|
||||
|
||||
for i in range(1, n_parts + 1):
|
||||
obj = s3.head_object(Bucket='mybucket', Key='the-key', PartNumber=i)
|
||||
assert obj["ContentLength"] == REDUCED_PART_SIZE + i
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_boto3_put_object_with_tagging():
|
||||
s3 = boto3.client('s3', region_name='us-east-1')
|
||||
|
|
|
|||
|
|
@ -1,106 +1,138 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import boto
|
||||
import boto3
|
||||
from boto.exception import S3CreateError, S3ResponseError
|
||||
from boto.s3.lifecycle import Lifecycle, Transition, Expiration, Rule
|
||||
|
||||
import sure # noqa
|
||||
from botocore.exceptions import ClientError
|
||||
from datetime import datetime
|
||||
from nose.tools import assert_raises
|
||||
|
||||
from moto import mock_s3_deprecated, mock_s3
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_storage_class_standard():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
# add an object to the bucket with standard storage
|
||||
|
||||
s3.put_object(Bucket="Bucket", Key="my_key", Body="my_value")
|
||||
|
||||
list_of_objects = s3.list_objects(Bucket="Bucket")
|
||||
|
||||
list_of_objects['Contents'][0]["StorageClass"].should.equal("STANDARD")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_storage_class_infrequent_access():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
# add an object to the bucket with standard storage
|
||||
|
||||
s3.put_object(Bucket="Bucket", Key="my_key_infrequent", Body="my_value_infrequent", StorageClass="STANDARD_IA")
|
||||
|
||||
D = s3.list_objects(Bucket="Bucket")
|
||||
|
||||
D['Contents'][0]["StorageClass"].should.equal("STANDARD_IA")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_storage_class_copy():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARD")
|
||||
|
||||
s3.create_bucket(Bucket="Bucket2")
|
||||
# second object is originally of storage class REDUCED_REDUNDANCY
|
||||
s3.put_object(Bucket="Bucket2", Key="Second_Object", Body="Body2")
|
||||
|
||||
s3.copy_object(CopySource = {"Bucket": "Bucket", "Key": "First_Object"}, Bucket="Bucket2", Key="Second_Object", StorageClass="ONEZONE_IA")
|
||||
|
||||
list_of_copied_objects = s3.list_objects(Bucket="Bucket2")
|
||||
|
||||
# checks that a copied object can be properly copied
|
||||
list_of_copied_objects["Contents"][0]["StorageClass"].should.equal("ONEZONE_IA")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_invalid_copied_storage_class():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARD")
|
||||
|
||||
s3.create_bucket(Bucket="Bucket2")
|
||||
s3.put_object(Bucket="Bucket2", Key="Second_Object", Body="Body2", StorageClass="REDUCED_REDUNDANCY")
|
||||
|
||||
# Try to copy an object with an invalid storage class
|
||||
with assert_raises(ClientError) as err:
|
||||
s3.copy_object(CopySource = {"Bucket": "Bucket", "Key": "First_Object"}, Bucket="Bucket2", Key="Second_Object", StorageClass="STANDARD2")
|
||||
|
||||
e = err.exception
|
||||
e.response["Error"]["Code"].should.equal("InvalidStorageClass")
|
||||
e.response["Error"]["Message"].should.equal("The storage class you specified is not valid")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_invalid_storage_class():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
# Try to add an object with an invalid storage class
|
||||
with assert_raises(ClientError) as err:
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARDD")
|
||||
|
||||
e = err.exception
|
||||
e.response["Error"]["Code"].should.equal("InvalidStorageClass")
|
||||
e.response["Error"]["Message"].should.equal("The storage class you specified is not valid")
|
||||
|
||||
@mock_s3
|
||||
def test_s3_default_storage_class():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body")
|
||||
|
||||
list_of_objects = s3.list_objects(Bucket="Bucket")
|
||||
|
||||
# tests that the default storage class is still STANDARD
|
||||
list_of_objects["Contents"][0]["StorageClass"].should.equal("STANDARD")
|
||||
|
||||
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import boto3
|
||||
|
||||
import sure # noqa
|
||||
from botocore.exceptions import ClientError
|
||||
from nose.tools import assert_raises
|
||||
|
||||
from moto import mock_s3
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_storage_class_standard():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
# add an object to the bucket with standard storage
|
||||
|
||||
s3.put_object(Bucket="Bucket", Key="my_key", Body="my_value")
|
||||
|
||||
list_of_objects = s3.list_objects(Bucket="Bucket")
|
||||
|
||||
list_of_objects['Contents'][0]["StorageClass"].should.equal("STANDARD")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_storage_class_infrequent_access():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
# add an object to the bucket with standard storage
|
||||
|
||||
s3.put_object(Bucket="Bucket", Key="my_key_infrequent", Body="my_value_infrequent", StorageClass="STANDARD_IA")
|
||||
|
||||
D = s3.list_objects(Bucket="Bucket")
|
||||
|
||||
D['Contents'][0]["StorageClass"].should.equal("STANDARD_IA")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_storage_class_intelligent_tiering():
|
||||
s3 = boto3.client("s3")
|
||||
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
s3.put_object(Bucket="Bucket", Key="my_key_infrequent", Body="my_value_infrequent", StorageClass="INTELLIGENT_TIERING")
|
||||
|
||||
objects = s3.list_objects(Bucket="Bucket")
|
||||
|
||||
objects['Contents'][0]["StorageClass"].should.equal("INTELLIGENT_TIERING")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_storage_class_copy():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARD")
|
||||
|
||||
s3.create_bucket(Bucket="Bucket2")
|
||||
# second object is originally of storage class REDUCED_REDUNDANCY
|
||||
s3.put_object(Bucket="Bucket2", Key="Second_Object", Body="Body2")
|
||||
|
||||
s3.copy_object(CopySource = {"Bucket": "Bucket", "Key": "First_Object"}, Bucket="Bucket2", Key="Second_Object", StorageClass="ONEZONE_IA")
|
||||
|
||||
list_of_copied_objects = s3.list_objects(Bucket="Bucket2")
|
||||
|
||||
# checks that a copied object can be properly copied
|
||||
list_of_copied_objects["Contents"][0]["StorageClass"].should.equal("ONEZONE_IA")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_invalid_copied_storage_class():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARD")
|
||||
|
||||
s3.create_bucket(Bucket="Bucket2")
|
||||
s3.put_object(Bucket="Bucket2", Key="Second_Object", Body="Body2", StorageClass="REDUCED_REDUNDANCY")
|
||||
|
||||
# Try to copy an object with an invalid storage class
|
||||
with assert_raises(ClientError) as err:
|
||||
s3.copy_object(CopySource = {"Bucket": "Bucket", "Key": "First_Object"}, Bucket="Bucket2", Key="Second_Object", StorageClass="STANDARD2")
|
||||
|
||||
e = err.exception
|
||||
e.response["Error"]["Code"].should.equal("InvalidStorageClass")
|
||||
e.response["Error"]["Message"].should.equal("The storage class you specified is not valid")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_invalid_storage_class():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
# Try to add an object with an invalid storage class
|
||||
with assert_raises(ClientError) as err:
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARDD")
|
||||
|
||||
e = err.exception
|
||||
e.response["Error"]["Code"].should.equal("InvalidStorageClass")
|
||||
e.response["Error"]["Message"].should.equal("The storage class you specified is not valid")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_default_storage_class():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body")
|
||||
|
||||
list_of_objects = s3.list_objects(Bucket="Bucket")
|
||||
|
||||
# tests that the default storage class is still STANDARD
|
||||
list_of_objects["Contents"][0]["StorageClass"].should.equal("STANDARD")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_copy_object_error_for_glacier_storage_class():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="GLACIER")
|
||||
|
||||
with assert_raises(ClientError) as exc:
|
||||
s3.copy_object(CopySource={"Bucket": "Bucket", "Key": "First_Object"}, Bucket="Bucket", Key="Second_Object")
|
||||
|
||||
exc.exception.response["Error"]["Code"].should.equal("ObjectNotInActiveTierError")
|
||||
|
||||
|
||||
@mock_s3
|
||||
def test_s3_copy_object_error_for_deep_archive_storage_class():
|
||||
s3 = boto3.client("s3")
|
||||
s3.create_bucket(Bucket="Bucket")
|
||||
|
||||
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="DEEP_ARCHIVE")
|
||||
|
||||
with assert_raises(ClientError) as exc:
|
||||
s3.copy_object(CopySource={"Bucket": "Bucket", "Key": "First_Object"}, Bucket="Bucket", Key="Second_Object")
|
||||
|
||||
exc.exception.response["Error"]["Code"].should.equal("ObjectNotInActiveTierError")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import unittest
|
|||
import pytz
|
||||
from datetime import datetime
|
||||
from nose.tools import assert_raises
|
||||
from six import b
|
||||
|
||||
DEFAULT_SECRET_NAME = 'test-secret'
|
||||
|
||||
|
|
@ -22,6 +23,15 @@ def test_get_secret_value():
|
|||
result = conn.get_secret_value(SecretId='java-util-test-password')
|
||||
assert result['SecretString'] == 'foosecret'
|
||||
|
||||
@mock_secretsmanager
|
||||
def test_get_secret_value_binary():
|
||||
conn = boto3.client('secretsmanager', region_name='us-west-2')
|
||||
|
||||
create_secret = conn.create_secret(Name='java-util-test-password',
|
||||
SecretBinary=b("foosecret"))
|
||||
result = conn.get_secret_value(SecretId='java-util-test-password')
|
||||
assert result['SecretBinary'] == b('foosecret')
|
||||
|
||||
@mock_secretsmanager
|
||||
def test_get_secret_that_does_not_exist():
|
||||
conn = boto3.client('secretsmanager', region_name='us-west-2')
|
||||
|
|
|
|||
|
|
@ -1,190 +1,202 @@
|
|||
from __future__ import unicode_literals
|
||||
import boto3
|
||||
import six
|
||||
import json
|
||||
|
||||
import sure # noqa
|
||||
|
||||
from botocore.exceptions import ClientError
|
||||
from moto import mock_sns
|
||||
from moto.sns.models import DEFAULT_TOPIC_POLICY, DEFAULT_EFFECTIVE_DELIVERY_POLICY, DEFAULT_PAGE_SIZE
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_create_and_delete_topic():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
for topic_name in ('some-topic', '-some-topic-', '_some-topic_', 'a' * 256):
|
||||
conn.create_topic(Name=topic_name)
|
||||
|
||||
topics_json = conn.list_topics()
|
||||
topics = topics_json["Topics"]
|
||||
topics.should.have.length_of(1)
|
||||
topics[0]['TopicArn'].should.equal(
|
||||
"arn:aws:sns:{0}:123456789012:{1}"
|
||||
.format(conn._client_config.region_name, topic_name)
|
||||
)
|
||||
|
||||
# Delete the topic
|
||||
conn.delete_topic(TopicArn=topics[0]['TopicArn'])
|
||||
|
||||
# And there should now be 0 topics
|
||||
topics_json = conn.list_topics()
|
||||
topics = topics_json["Topics"]
|
||||
topics.should.have.length_of(0)
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_should_be_indempodent():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
topic_arn = conn.create_topic(Name="some-topic")['TopicArn']
|
||||
conn.set_topic_attributes(
|
||||
TopicArn=topic_arn,
|
||||
AttributeName="DisplayName",
|
||||
AttributeValue="should_be_set"
|
||||
)
|
||||
topic_display_name = conn.get_topic_attributes(
|
||||
TopicArn=topic_arn
|
||||
)['Attributes']['DisplayName']
|
||||
topic_display_name.should.be.equal("should_be_set")
|
||||
|
||||
#recreate topic to prove indempodentcy
|
||||
topic_arn = conn.create_topic(Name="some-topic")['TopicArn']
|
||||
topic_display_name = conn.get_topic_attributes(
|
||||
TopicArn=topic_arn
|
||||
)['Attributes']['DisplayName']
|
||||
topic_display_name.should.be.equal("should_be_set")
|
||||
|
||||
@mock_sns
|
||||
def test_get_missing_topic():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
conn.get_topic_attributes.when.called_with(
|
||||
TopicArn="a-fake-arn").should.throw(ClientError)
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_must_meet_constraints():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
common_random_chars = [':', ";", "!", "@", "|", "^", "%"]
|
||||
for char in common_random_chars:
|
||||
conn.create_topic.when.called_with(
|
||||
Name="no%s_invalidchar" % char).should.throw(ClientError)
|
||||
conn.create_topic.when.called_with(
|
||||
Name="no spaces allowed").should.throw(ClientError)
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_should_be_of_certain_length():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
too_short = ""
|
||||
conn.create_topic.when.called_with(
|
||||
Name=too_short).should.throw(ClientError)
|
||||
too_long = "x" * 257
|
||||
conn.create_topic.when.called_with(
|
||||
Name=too_long).should.throw(ClientError)
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_in_multiple_regions():
|
||||
for region in ['us-west-1', 'us-west-2']:
|
||||
conn = boto3.client("sns", region_name=region)
|
||||
conn.create_topic(Name="some-topic")
|
||||
list(conn.list_topics()["Topics"]).should.have.length_of(1)
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_topic_corresponds_to_region():
|
||||
for region in ['us-east-1', 'us-west-2']:
|
||||
conn = boto3.client("sns", region_name=region)
|
||||
conn.create_topic(Name="some-topic")
|
||||
topics_json = conn.list_topics()
|
||||
topic_arn = topics_json["Topics"][0]['TopicArn']
|
||||
topic_arn.should.equal(
|
||||
"arn:aws:sns:{0}:123456789012:some-topic".format(region))
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_topic_attributes():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
conn.create_topic(Name="some-topic")
|
||||
|
||||
topics_json = conn.list_topics()
|
||||
topic_arn = topics_json["Topics"][0]['TopicArn']
|
||||
|
||||
attributes = conn.get_topic_attributes(TopicArn=topic_arn)['Attributes']
|
||||
attributes["TopicArn"].should.equal(
|
||||
"arn:aws:sns:{0}:123456789012:some-topic"
|
||||
.format(conn._client_config.region_name)
|
||||
)
|
||||
attributes["Owner"].should.equal('123456789012')
|
||||
json.loads(attributes["Policy"]).should.equal(DEFAULT_TOPIC_POLICY)
|
||||
attributes["DisplayName"].should.equal("")
|
||||
attributes["SubscriptionsPending"].should.equal('0')
|
||||
attributes["SubscriptionsConfirmed"].should.equal('0')
|
||||
attributes["SubscriptionsDeleted"].should.equal('0')
|
||||
attributes["DeliveryPolicy"].should.equal("")
|
||||
json.loads(attributes["EffectiveDeliveryPolicy"]).should.equal(
|
||||
DEFAULT_EFFECTIVE_DELIVERY_POLICY)
|
||||
|
||||
# boto can't handle prefix-mandatory strings:
|
||||
# i.e. unicode on Python 2 -- u"foobar"
|
||||
# and bytes on Python 3 -- b"foobar"
|
||||
if six.PY2:
|
||||
policy = json.dumps({b"foo": b"bar"})
|
||||
displayname = b"My display name"
|
||||
delivery = json.dumps(
|
||||
{b"http": {b"defaultHealthyRetryPolicy": {b"numRetries": 5}}})
|
||||
else:
|
||||
policy = json.dumps({u"foo": u"bar"})
|
||||
displayname = u"My display name"
|
||||
delivery = json.dumps(
|
||||
{u"http": {u"defaultHealthyRetryPolicy": {u"numRetries": 5}}})
|
||||
conn.set_topic_attributes(TopicArn=topic_arn,
|
||||
AttributeName="Policy",
|
||||
AttributeValue=policy)
|
||||
conn.set_topic_attributes(TopicArn=topic_arn,
|
||||
AttributeName="DisplayName",
|
||||
AttributeValue=displayname)
|
||||
conn.set_topic_attributes(TopicArn=topic_arn,
|
||||
AttributeName="DeliveryPolicy",
|
||||
AttributeValue=delivery)
|
||||
|
||||
attributes = conn.get_topic_attributes(TopicArn=topic_arn)['Attributes']
|
||||
attributes["Policy"].should.equal('{"foo": "bar"}')
|
||||
attributes["DisplayName"].should.equal("My display name")
|
||||
attributes["DeliveryPolicy"].should.equal(
|
||||
'{"http": {"defaultHealthyRetryPolicy": {"numRetries": 5}}}')
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_topic_paging():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
for index in range(DEFAULT_PAGE_SIZE + int(DEFAULT_PAGE_SIZE / 2)):
|
||||
conn.create_topic(Name="some-topic_" + str(index))
|
||||
|
||||
response = conn.list_topics()
|
||||
topics_list = response["Topics"]
|
||||
next_token = response["NextToken"]
|
||||
|
||||
len(topics_list).should.equal(DEFAULT_PAGE_SIZE)
|
||||
int(next_token).should.equal(DEFAULT_PAGE_SIZE)
|
||||
|
||||
response = conn.list_topics(NextToken=next_token)
|
||||
topics_list = response["Topics"]
|
||||
response.shouldnt.have("NextToken")
|
||||
|
||||
topics_list.should.have.length_of(int(DEFAULT_PAGE_SIZE / 2))
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_add_remove_permissions():
|
||||
conn = boto3.client('sns', region_name='us-east-1')
|
||||
response = conn.create_topic(Name='testpermissions')
|
||||
|
||||
conn.add_permission(
|
||||
TopicArn=response['TopicArn'],
|
||||
Label='Test1234',
|
||||
AWSAccountId=['999999999999'],
|
||||
ActionName=['AddPermission']
|
||||
)
|
||||
conn.remove_permission(
|
||||
TopicArn=response['TopicArn'],
|
||||
Label='Test1234'
|
||||
)
|
||||
from __future__ import unicode_literals
|
||||
import boto3
|
||||
import six
|
||||
import json
|
||||
|
||||
import sure # noqa
|
||||
|
||||
from botocore.exceptions import ClientError
|
||||
from moto import mock_sns
|
||||
from moto.sns.models import DEFAULT_TOPIC_POLICY, DEFAULT_EFFECTIVE_DELIVERY_POLICY, DEFAULT_PAGE_SIZE
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_create_and_delete_topic():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
for topic_name in ('some-topic', '-some-topic-', '_some-topic_', 'a' * 256):
|
||||
conn.create_topic(Name=topic_name)
|
||||
|
||||
topics_json = conn.list_topics()
|
||||
topics = topics_json["Topics"]
|
||||
topics.should.have.length_of(1)
|
||||
topics[0]['TopicArn'].should.equal(
|
||||
"arn:aws:sns:{0}:123456789012:{1}"
|
||||
.format(conn._client_config.region_name, topic_name)
|
||||
)
|
||||
|
||||
# Delete the topic
|
||||
conn.delete_topic(TopicArn=topics[0]['TopicArn'])
|
||||
|
||||
# And there should now be 0 topics
|
||||
topics_json = conn.list_topics()
|
||||
topics = topics_json["Topics"]
|
||||
topics.should.have.length_of(0)
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_with_attributes():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
conn.create_topic(Name='some-topic-with-attribute', Attributes={'DisplayName': 'test-topic'})
|
||||
topics_json = conn.list_topics()
|
||||
topic_arn = topics_json["Topics"][0]['TopicArn']
|
||||
|
||||
attributes = conn.get_topic_attributes(TopicArn=topic_arn)['Attributes']
|
||||
attributes['DisplayName'].should.equal('test-topic')
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_should_be_indempodent():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
topic_arn = conn.create_topic(Name="some-topic")['TopicArn']
|
||||
conn.set_topic_attributes(
|
||||
TopicArn=topic_arn,
|
||||
AttributeName="DisplayName",
|
||||
AttributeValue="should_be_set"
|
||||
)
|
||||
topic_display_name = conn.get_topic_attributes(
|
||||
TopicArn=topic_arn
|
||||
)['Attributes']['DisplayName']
|
||||
topic_display_name.should.be.equal("should_be_set")
|
||||
|
||||
#recreate topic to prove indempodentcy
|
||||
topic_arn = conn.create_topic(Name="some-topic")['TopicArn']
|
||||
topic_display_name = conn.get_topic_attributes(
|
||||
TopicArn=topic_arn
|
||||
)['Attributes']['DisplayName']
|
||||
topic_display_name.should.be.equal("should_be_set")
|
||||
|
||||
@mock_sns
|
||||
def test_get_missing_topic():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
conn.get_topic_attributes.when.called_with(
|
||||
TopicArn="a-fake-arn").should.throw(ClientError)
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_must_meet_constraints():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
common_random_chars = [':', ";", "!", "@", "|", "^", "%"]
|
||||
for char in common_random_chars:
|
||||
conn.create_topic.when.called_with(
|
||||
Name="no%s_invalidchar" % char).should.throw(ClientError)
|
||||
conn.create_topic.when.called_with(
|
||||
Name="no spaces allowed").should.throw(ClientError)
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_should_be_of_certain_length():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
too_short = ""
|
||||
conn.create_topic.when.called_with(
|
||||
Name=too_short).should.throw(ClientError)
|
||||
too_long = "x" * 257
|
||||
conn.create_topic.when.called_with(
|
||||
Name=too_long).should.throw(ClientError)
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_create_topic_in_multiple_regions():
|
||||
for region in ['us-west-1', 'us-west-2']:
|
||||
conn = boto3.client("sns", region_name=region)
|
||||
conn.create_topic(Name="some-topic")
|
||||
list(conn.list_topics()["Topics"]).should.have.length_of(1)
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_topic_corresponds_to_region():
|
||||
for region in ['us-east-1', 'us-west-2']:
|
||||
conn = boto3.client("sns", region_name=region)
|
||||
conn.create_topic(Name="some-topic")
|
||||
topics_json = conn.list_topics()
|
||||
topic_arn = topics_json["Topics"][0]['TopicArn']
|
||||
topic_arn.should.equal(
|
||||
"arn:aws:sns:{0}:123456789012:some-topic".format(region))
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_topic_attributes():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
conn.create_topic(Name="some-topic")
|
||||
|
||||
topics_json = conn.list_topics()
|
||||
topic_arn = topics_json["Topics"][0]['TopicArn']
|
||||
|
||||
attributes = conn.get_topic_attributes(TopicArn=topic_arn)['Attributes']
|
||||
attributes["TopicArn"].should.equal(
|
||||
"arn:aws:sns:{0}:123456789012:some-topic"
|
||||
.format(conn._client_config.region_name)
|
||||
)
|
||||
attributes["Owner"].should.equal('123456789012')
|
||||
json.loads(attributes["Policy"]).should.equal(DEFAULT_TOPIC_POLICY)
|
||||
attributes["DisplayName"].should.equal("")
|
||||
attributes["SubscriptionsPending"].should.equal('0')
|
||||
attributes["SubscriptionsConfirmed"].should.equal('0')
|
||||
attributes["SubscriptionsDeleted"].should.equal('0')
|
||||
attributes["DeliveryPolicy"].should.equal("")
|
||||
json.loads(attributes["EffectiveDeliveryPolicy"]).should.equal(
|
||||
DEFAULT_EFFECTIVE_DELIVERY_POLICY)
|
||||
|
||||
# boto can't handle prefix-mandatory strings:
|
||||
# i.e. unicode on Python 2 -- u"foobar"
|
||||
# and bytes on Python 3 -- b"foobar"
|
||||
if six.PY2:
|
||||
policy = json.dumps({b"foo": b"bar"})
|
||||
displayname = b"My display name"
|
||||
delivery = json.dumps(
|
||||
{b"http": {b"defaultHealthyRetryPolicy": {b"numRetries": 5}}})
|
||||
else:
|
||||
policy = json.dumps({u"foo": u"bar"})
|
||||
displayname = u"My display name"
|
||||
delivery = json.dumps(
|
||||
{u"http": {u"defaultHealthyRetryPolicy": {u"numRetries": 5}}})
|
||||
conn.set_topic_attributes(TopicArn=topic_arn,
|
||||
AttributeName="Policy",
|
||||
AttributeValue=policy)
|
||||
conn.set_topic_attributes(TopicArn=topic_arn,
|
||||
AttributeName="DisplayName",
|
||||
AttributeValue=displayname)
|
||||
conn.set_topic_attributes(TopicArn=topic_arn,
|
||||
AttributeName="DeliveryPolicy",
|
||||
AttributeValue=delivery)
|
||||
|
||||
attributes = conn.get_topic_attributes(TopicArn=topic_arn)['Attributes']
|
||||
attributes["Policy"].should.equal('{"foo": "bar"}')
|
||||
attributes["DisplayName"].should.equal("My display name")
|
||||
attributes["DeliveryPolicy"].should.equal(
|
||||
'{"http": {"defaultHealthyRetryPolicy": {"numRetries": 5}}}')
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_topic_paging():
|
||||
conn = boto3.client("sns", region_name="us-east-1")
|
||||
for index in range(DEFAULT_PAGE_SIZE + int(DEFAULT_PAGE_SIZE / 2)):
|
||||
conn.create_topic(Name="some-topic_" + str(index))
|
||||
|
||||
response = conn.list_topics()
|
||||
topics_list = response["Topics"]
|
||||
next_token = response["NextToken"]
|
||||
|
||||
len(topics_list).should.equal(DEFAULT_PAGE_SIZE)
|
||||
int(next_token).should.equal(DEFAULT_PAGE_SIZE)
|
||||
|
||||
response = conn.list_topics(NextToken=next_token)
|
||||
topics_list = response["Topics"]
|
||||
response.shouldnt.have("NextToken")
|
||||
|
||||
topics_list.should.have.length_of(int(DEFAULT_PAGE_SIZE / 2))
|
||||
|
||||
|
||||
@mock_sns
|
||||
def test_add_remove_permissions():
|
||||
conn = boto3.client('sns', region_name='us-east-1')
|
||||
response = conn.create_topic(Name='testpermissions')
|
||||
|
||||
conn.add_permission(
|
||||
TopicArn=response['TopicArn'],
|
||||
Label='Test1234',
|
||||
AWSAccountId=['999999999999'],
|
||||
ActionName=['AddPermission']
|
||||
)
|
||||
conn.remove_permission(
|
||||
TopicArn=response['TopicArn'],
|
||||
Label='Test1234'
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,84 +1,213 @@
|
|||
from __future__ import unicode_literals
|
||||
import json
|
||||
|
||||
import boto
|
||||
import boto3
|
||||
from freezegun import freeze_time
|
||||
import sure # noqa
|
||||
|
||||
from moto import mock_sts, mock_sts_deprecated
|
||||
|
||||
|
||||
@freeze_time("2012-01-01 12:00:00")
|
||||
@mock_sts_deprecated
|
||||
def test_get_session_token():
|
||||
conn = boto.connect_sts()
|
||||
token = conn.get_session_token(duration=123)
|
||||
|
||||
token.expiration.should.equal('2012-01-01T12:02:03.000Z')
|
||||
token.session_token.should.equal(
|
||||
"AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE")
|
||||
token.access_key.should.equal("AKIAIOSFODNN7EXAMPLE")
|
||||
token.secret_key.should.equal("wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY")
|
||||
|
||||
|
||||
@freeze_time("2012-01-01 12:00:00")
|
||||
@mock_sts_deprecated
|
||||
def test_get_federation_token():
|
||||
conn = boto.connect_sts()
|
||||
token = conn.get_federation_token(duration=123, name="Bob")
|
||||
|
||||
token.credentials.expiration.should.equal('2012-01-01T12:02:03.000Z')
|
||||
token.credentials.session_token.should.equal(
|
||||
"AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==")
|
||||
token.credentials.access_key.should.equal("AKIAIOSFODNN7EXAMPLE")
|
||||
token.credentials.secret_key.should.equal(
|
||||
"wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY")
|
||||
token.federated_user_arn.should.equal(
|
||||
"arn:aws:sts::123456789012:federated-user/Bob")
|
||||
token.federated_user_id.should.equal("123456789012:Bob")
|
||||
|
||||
|
||||
@freeze_time("2012-01-01 12:00:00")
|
||||
@mock_sts_deprecated
|
||||
def test_assume_role():
|
||||
conn = boto.connect_sts()
|
||||
|
||||
policy = json.dumps({
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Stmt13690092345534",
|
||||
"Action": [
|
||||
"S3:ListBucket"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::foobar-tester"
|
||||
]
|
||||
},
|
||||
]
|
||||
})
|
||||
s3_role = "arn:aws:iam::123456789012:role/test-role"
|
||||
role = conn.assume_role(s3_role, "session-name",
|
||||
policy, duration_seconds=123)
|
||||
|
||||
credentials = role.credentials
|
||||
credentials.expiration.should.equal('2012-01-01T12:02:03.000Z')
|
||||
credentials.session_token.should.equal(
|
||||
"BQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE")
|
||||
credentials.access_key.should.equal("AKIAIOSFODNN7EXAMPLE")
|
||||
credentials.secret_key.should.equal(
|
||||
"aJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY")
|
||||
|
||||
role.user.arn.should.equal("arn:aws:iam::123456789012:role/test-role")
|
||||
role.user.assume_role_id.should.contain("session-name")
|
||||
|
||||
|
||||
@mock_sts
|
||||
def test_get_caller_identity():
|
||||
identity = boto3.client(
|
||||
"sts", region_name='us-east-1').get_caller_identity()
|
||||
|
||||
identity['Arn'].should.equal('arn:aws:sts::123456789012:user/moto')
|
||||
identity['UserId'].should.equal('AKIAIOSFODNN7EXAMPLE')
|
||||
identity['Account'].should.equal('123456789012')
|
||||
from __future__ import unicode_literals
|
||||
import json
|
||||
|
||||
import boto
|
||||
import boto3
|
||||
from botocore.client import ClientError
|
||||
from freezegun import freeze_time
|
||||
from nose.tools import assert_raises
|
||||
import sure # noqa
|
||||
|
||||
|
||||
from moto import mock_sts, mock_sts_deprecated, mock_iam, settings
|
||||
from moto.iam.models import ACCOUNT_ID
|
||||
from moto.sts.responses import MAX_FEDERATION_TOKEN_POLICY_LENGTH
|
||||
|
||||
|
||||
@freeze_time("2012-01-01 12:00:00")
|
||||
@mock_sts_deprecated
|
||||
def test_get_session_token():
|
||||
conn = boto.connect_sts()
|
||||
token = conn.get_session_token(duration=123)
|
||||
|
||||
token.expiration.should.equal('2012-01-01T12:02:03.000Z')
|
||||
token.session_token.should.equal(
|
||||
"AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/LTo6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3zrkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtpZ3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE")
|
||||
token.access_key.should.equal("AKIAIOSFODNN7EXAMPLE")
|
||||
token.secret_key.should.equal("wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY")
|
||||
|
||||
|
||||
@freeze_time("2012-01-01 12:00:00")
|
||||
@mock_sts_deprecated
|
||||
def test_get_federation_token():
|
||||
conn = boto.connect_sts()
|
||||
token_name = "Bob"
|
||||
token = conn.get_federation_token(duration=123, name=token_name)
|
||||
|
||||
token.credentials.expiration.should.equal('2012-01-01T12:02:03.000Z')
|
||||
token.credentials.session_token.should.equal(
|
||||
"AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==")
|
||||
token.credentials.access_key.should.equal("AKIAIOSFODNN7EXAMPLE")
|
||||
token.credentials.secret_key.should.equal(
|
||||
"wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY")
|
||||
token.federated_user_arn.should.equal(
|
||||
"arn:aws:sts::{account_id}:federated-user/{token_name}".format(account_id=ACCOUNT_ID, token_name=token_name))
|
||||
token.federated_user_id.should.equal(str(ACCOUNT_ID) + ":" + token_name)
|
||||
|
||||
|
||||
@freeze_time("2012-01-01 12:00:00")
|
||||
@mock_sts
|
||||
def test_assume_role():
|
||||
client = boto3.client(
|
||||
"sts", region_name='us-east-1')
|
||||
|
||||
session_name = "session-name"
|
||||
policy = json.dumps({
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Stmt13690092345534",
|
||||
"Action": [
|
||||
"S3:ListBucket"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::foobar-tester"
|
||||
]
|
||||
},
|
||||
]
|
||||
})
|
||||
role_name = "test-role"
|
||||
s3_role = "arn:aws:iam::{account_id}:role/{role_name}".format(account_id=ACCOUNT_ID, role_name=role_name)
|
||||
assume_role_response = client.assume_role(RoleArn=s3_role, RoleSessionName=session_name,
|
||||
Policy=policy, DurationSeconds=900)
|
||||
|
||||
credentials = assume_role_response['Credentials']
|
||||
if not settings.TEST_SERVER_MODE:
|
||||
credentials['Expiration'].isoformat().should.equal('2012-01-01T12:15:00+00:00')
|
||||
credentials['SessionToken'].should.have.length_of(356)
|
||||
assert credentials['SessionToken'].startswith("FQoGZXIvYXdzE")
|
||||
credentials['AccessKeyId'].should.have.length_of(20)
|
||||
assert credentials['AccessKeyId'].startswith("ASIA")
|
||||
credentials['SecretAccessKey'].should.have.length_of(40)
|
||||
|
||||
assume_role_response['AssumedRoleUser']['Arn'].should.equal("arn:aws:sts::{account_id}:assumed-role/{role_name}/{session_name}".format(
|
||||
account_id=ACCOUNT_ID, role_name=role_name, session_name=session_name))
|
||||
assert assume_role_response['AssumedRoleUser']['AssumedRoleId'].startswith("AROA")
|
||||
assert assume_role_response['AssumedRoleUser']['AssumedRoleId'].endswith(":" + session_name)
|
||||
assume_role_response['AssumedRoleUser']['AssumedRoleId'].should.have.length_of(21 + 1 + len(session_name))
|
||||
|
||||
|
||||
@freeze_time("2012-01-01 12:00:00")
|
||||
@mock_sts_deprecated
|
||||
def test_assume_role_with_web_identity():
|
||||
conn = boto.connect_sts()
|
||||
|
||||
policy = json.dumps({
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Stmt13690092345534",
|
||||
"Action": [
|
||||
"S3:ListBucket"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": [
|
||||
"arn:aws:s3:::foobar-tester"
|
||||
]
|
||||
},
|
||||
]
|
||||
})
|
||||
role_name = "test-role"
|
||||
s3_role = "arn:aws:iam::{account_id}:role/{role_name}".format(account_id=ACCOUNT_ID, role_name=role_name)
|
||||
session_name = "session-name"
|
||||
role = conn.assume_role_with_web_identity(
|
||||
s3_role, session_name, policy, duration_seconds=123)
|
||||
|
||||
credentials = role.credentials
|
||||
credentials.expiration.should.equal('2012-01-01T12:02:03.000Z')
|
||||
credentials.session_token.should.have.length_of(356)
|
||||
assert credentials.session_token.startswith("FQoGZXIvYXdzE")
|
||||
credentials.access_key.should.have.length_of(20)
|
||||
assert credentials.access_key.startswith("ASIA")
|
||||
credentials.secret_key.should.have.length_of(40)
|
||||
|
||||
role.user.arn.should.equal("arn:aws:sts::{account_id}:assumed-role/{role_name}/{session_name}".format(
|
||||
account_id=ACCOUNT_ID, role_name=role_name, session_name=session_name))
|
||||
role.user.assume_role_id.should.contain("session-name")
|
||||
|
||||
|
||||
@mock_sts
|
||||
def test_get_caller_identity_with_default_credentials():
|
||||
identity = boto3.client(
|
||||
"sts", region_name='us-east-1').get_caller_identity()
|
||||
|
||||
identity['Arn'].should.equal('arn:aws:sts::{account_id}:user/moto'.format(account_id=ACCOUNT_ID))
|
||||
identity['UserId'].should.equal('AKIAIOSFODNN7EXAMPLE')
|
||||
identity['Account'].should.equal(str(ACCOUNT_ID))
|
||||
|
||||
|
||||
@mock_sts
|
||||
@mock_iam
|
||||
def test_get_caller_identity_with_iam_user_credentials():
|
||||
iam_client = boto3.client("iam", region_name='us-east-1')
|
||||
iam_user_name = "new-user"
|
||||
iam_user = iam_client.create_user(UserName=iam_user_name)['User']
|
||||
access_key = iam_client.create_access_key(UserName=iam_user_name)['AccessKey']
|
||||
|
||||
identity = boto3.client(
|
||||
"sts", region_name='us-east-1', aws_access_key_id=access_key['AccessKeyId'],
|
||||
aws_secret_access_key=access_key['SecretAccessKey']).get_caller_identity()
|
||||
|
||||
identity['Arn'].should.equal(iam_user['Arn'])
|
||||
identity['UserId'].should.equal(iam_user['UserId'])
|
||||
identity['Account'].should.equal(str(ACCOUNT_ID))
|
||||
|
||||
|
||||
@mock_sts
|
||||
@mock_iam
|
||||
def test_get_caller_identity_with_assumed_role_credentials():
|
||||
iam_client = boto3.client("iam", region_name='us-east-1')
|
||||
sts_client = boto3.client("sts", region_name='us-east-1')
|
||||
iam_role_name = "new-user"
|
||||
trust_policy_document = {
|
||||
"Version": "2012-10-17",
|
||||
"Statement": {
|
||||
"Effect": "Allow",
|
||||
"Principal": {"AWS": "arn:aws:iam::{account_id}:root".format(account_id=ACCOUNT_ID)},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
}
|
||||
iam_role_arn = iam_client.role_arn = iam_client.create_role(
|
||||
RoleName=iam_role_name,
|
||||
AssumeRolePolicyDocument=json.dumps(trust_policy_document)
|
||||
)['Role']['Arn']
|
||||
session_name = "new-session"
|
||||
assumed_role = sts_client.assume_role(RoleArn=iam_role_arn,
|
||||
RoleSessionName=session_name)
|
||||
access_key = assumed_role['Credentials']
|
||||
|
||||
identity = boto3.client(
|
||||
"sts", region_name='us-east-1', aws_access_key_id=access_key['AccessKeyId'],
|
||||
aws_secret_access_key=access_key['SecretAccessKey']).get_caller_identity()
|
||||
|
||||
identity['Arn'].should.equal(assumed_role['AssumedRoleUser']['Arn'])
|
||||
identity['UserId'].should.equal(assumed_role['AssumedRoleUser']['AssumedRoleId'])
|
||||
identity['Account'].should.equal(str(ACCOUNT_ID))
|
||||
|
||||
|
||||
@mock_sts
|
||||
def test_federation_token_with_too_long_policy():
|
||||
"Trying to get a federation token with a policy longer than 2048 character should fail"
|
||||
cli = boto3.client("sts", region_name='us-east-1')
|
||||
resource_tmpl = 'arn:aws:s3:::yyyy-xxxxx-cloud-default/my_default_folder/folder-name-%s/*'
|
||||
statements = []
|
||||
for num in range(30):
|
||||
statements.append(
|
||||
{
|
||||
'Effect': 'Allow',
|
||||
'Action': ['s3:*'],
|
||||
'Resource': resource_tmpl % str(num)
|
||||
}
|
||||
)
|
||||
policy = {
|
||||
'Version': '2012-10-17',
|
||||
'Statement': statements
|
||||
}
|
||||
json_policy = json.dumps(policy)
|
||||
assert len(json_policy) > MAX_FEDERATION_TOKEN_POLICY_LENGTH
|
||||
|
||||
with assert_raises(ClientError) as exc:
|
||||
cli.get_federation_token(Name='foo', DurationSeconds=3600, Policy=json_policy)
|
||||
exc.exception.response['Error']['Code'].should.equal('ValidationError')
|
||||
exc.exception.response['Error']['Message'].should.contain(
|
||||
str(MAX_FEDERATION_TOKEN_POLICY_LENGTH)
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue