commit
e750e3ace0
@ -35,9 +35,10 @@ install:
|
||||
if [ "$TEST_SERVER_MODE" = "true" ]; then
|
||||
python wait_for.py
|
||||
fi
|
||||
before_script:
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == "3.7" ]]; then make lint; fi
|
||||
script:
|
||||
- make test-only
|
||||
- if [[ $TRAVIS_PYTHON_VERSION == "3.7" ]]; then make lint; fi
|
||||
after_success:
|
||||
- coveralls
|
||||
before_deploy:
|
||||
|
@ -31,7 +31,6 @@ Moto Changelog
|
||||
* delete_configuration_aggregator()
|
||||
* describe_aggregation_authorizations()
|
||||
* describe_configuration_aggregators()
|
||||
* describe_identity_pool()
|
||||
* get_resource_config_history()
|
||||
* list_aggregate_discovered_resources() (For S3)
|
||||
* list_discovered_resources() (For S3)
|
||||
@ -39,6 +38,7 @@ Moto Changelog
|
||||
* put_configuration_aggregator()
|
||||
* Cognito
|
||||
* assume_role_with_web_identity()
|
||||
* describe_identity_pool()
|
||||
* get_open_id_token()
|
||||
* update_user_pool_domain()
|
||||
* DataSync:
|
||||
|
@ -2718,12 +2718,12 @@
|
||||
- [ ] upgrade_elasticsearch_domain
|
||||
|
||||
## events
|
||||
48% implemented
|
||||
58% implemented
|
||||
- [ ] activate_event_source
|
||||
- [ ] create_event_bus
|
||||
- [X] create_event_bus
|
||||
- [ ] create_partner_event_source
|
||||
- [ ] deactivate_event_source
|
||||
- [ ] delete_event_bus
|
||||
- [X] delete_event_bus
|
||||
- [ ] delete_partner_event_source
|
||||
- [X] delete_rule
|
||||
- [X] describe_event_bus
|
||||
@ -2732,7 +2732,7 @@
|
||||
- [X] describe_rule
|
||||
- [X] disable_rule
|
||||
- [X] enable_rule
|
||||
- [ ] list_event_buses
|
||||
- [X] list_event_buses
|
||||
- [ ] list_event_sources
|
||||
- [ ] list_partner_event_source_accounts
|
||||
- [ ] list_partner_event_sources
|
||||
@ -3977,46 +3977,46 @@
|
||||
- [ ] update_resource
|
||||
|
||||
## lambda
|
||||
0% implemented
|
||||
41% implemented
|
||||
- [ ] add_layer_version_permission
|
||||
- [ ] add_permission
|
||||
- [ ] create_alias
|
||||
- [ ] create_event_source_mapping
|
||||
- [ ] create_function
|
||||
- [X] create_event_source_mapping
|
||||
- [X] create_function
|
||||
- [ ] delete_alias
|
||||
- [ ] delete_event_source_mapping
|
||||
- [ ] delete_function
|
||||
- [X] delete_event_source_mapping
|
||||
- [X] delete_function
|
||||
- [ ] delete_function_concurrency
|
||||
- [ ] delete_layer_version
|
||||
- [ ] get_account_settings
|
||||
- [ ] get_alias
|
||||
- [ ] get_event_source_mapping
|
||||
- [ ] get_function
|
||||
- [X] get_event_source_mapping
|
||||
- [X] get_function
|
||||
- [ ] get_function_configuration
|
||||
- [ ] get_layer_version
|
||||
- [ ] get_layer_version_by_arn
|
||||
- [ ] get_layer_version_policy
|
||||
- [ ] get_policy
|
||||
- [ ] invoke
|
||||
- [X] invoke
|
||||
- [ ] invoke_async
|
||||
- [ ] list_aliases
|
||||
- [ ] list_event_source_mappings
|
||||
- [ ] list_functions
|
||||
- [X] list_event_source_mappings
|
||||
- [X] list_functions
|
||||
- [ ] list_layer_versions
|
||||
- [ ] list_layers
|
||||
- [ ] list_tags
|
||||
- [ ] list_versions_by_function
|
||||
- [X] list_tags
|
||||
- [X] list_versions_by_function
|
||||
- [ ] publish_layer_version
|
||||
- [ ] publish_version
|
||||
- [ ] put_function_concurrency
|
||||
- [ ] remove_layer_version_permission
|
||||
- [ ] remove_permission
|
||||
- [ ] tag_resource
|
||||
- [ ] untag_resource
|
||||
- [X] tag_resource
|
||||
- [X] untag_resource
|
||||
- [ ] update_alias
|
||||
- [ ] update_event_source_mapping
|
||||
- [ ] update_function_code
|
||||
- [ ] update_function_configuration
|
||||
- [X] update_event_source_mapping
|
||||
- [X] update_function_code
|
||||
- [X] update_function_configuration
|
||||
|
||||
## lex-models
|
||||
0% implemented
|
||||
@ -4723,7 +4723,7 @@
|
||||
- [ ] update_server_engine_attributes
|
||||
|
||||
## organizations
|
||||
41% implemented
|
||||
43% implemented
|
||||
- [ ] accept_handshake
|
||||
- [X] attach_policy
|
||||
- [ ] cancel_handshake
|
||||
@ -4737,7 +4737,7 @@
|
||||
- [ ] delete_organizational_unit
|
||||
- [ ] delete_policy
|
||||
- [X] describe_account
|
||||
- [ ] describe_create_account_status
|
||||
- [X] describe_create_account_status
|
||||
- [ ] describe_handshake
|
||||
- [X] describe_organization
|
||||
- [X] describe_organizational_unit
|
||||
|
@ -979,6 +979,32 @@ class LambdaBackend(BaseBackend):
|
||||
def add_policy(self, function_name, policy):
|
||||
self.get_function(function_name).policy = policy
|
||||
|
||||
def update_function_code(self, function_name, qualifier, body):
|
||||
fn = self.get_function(function_name, qualifier)
|
||||
|
||||
if fn:
|
||||
if body.get("Publish", False):
|
||||
fn = self.publish_function(function_name)
|
||||
|
||||
config = fn.update_function_code(body)
|
||||
return config
|
||||
else:
|
||||
return None
|
||||
|
||||
def update_function_configuration(self, function_name, qualifier, body):
|
||||
fn = self.get_function(function_name, qualifier)
|
||||
|
||||
return fn.update_configuration(body) if fn else None
|
||||
|
||||
def invoke(self, function_name, qualifier, body, headers, response_headers):
|
||||
fn = self.get_function(function_name, qualifier)
|
||||
if fn:
|
||||
payload = fn.invoke(body, headers, response_headers)
|
||||
response_headers["Content-Length"] = str(len(payload))
|
||||
return response_headers, payload
|
||||
else:
|
||||
return response_headers, None
|
||||
|
||||
|
||||
def do_validate_s3():
|
||||
return os.environ.get("VALIDATE_LAMBDA_S3", "") in ["", "1", "true"]
|
||||
|
@ -168,10 +168,10 @@ class LambdaResponse(BaseResponse):
|
||||
function_name = self.path.rsplit("/", 2)[-2]
|
||||
qualifier = self._get_param("qualifier")
|
||||
|
||||
fn = self.lambda_backend.get_function(function_name, qualifier)
|
||||
if fn:
|
||||
payload = fn.invoke(self.body, self.headers, response_headers)
|
||||
response_headers["Content-Length"] = str(len(payload))
|
||||
response_header, payload = self.lambda_backend.invoke(
|
||||
function_name, qualifier, self.body, self.headers, response_headers
|
||||
)
|
||||
if payload:
|
||||
return 202, response_headers, payload
|
||||
else:
|
||||
return 404, response_headers, "{}"
|
||||
@ -337,26 +337,23 @@ class LambdaResponse(BaseResponse):
|
||||
def _put_configuration(self, request):
|
||||
function_name = self.path.rsplit("/", 2)[-2]
|
||||
qualifier = self._get_param("Qualifier", None)
|
||||
resp = self.lambda_backend.update_function_configuration(
|
||||
function_name, qualifier, body=self.json_body
|
||||
)
|
||||
|
||||
fn = self.lambda_backend.get_function(function_name, qualifier)
|
||||
|
||||
if fn:
|
||||
config = fn.update_configuration(self.json_body)
|
||||
return 200, {}, json.dumps(config)
|
||||
if resp:
|
||||
return 200, {}, json.dumps(resp)
|
||||
else:
|
||||
return 404, {}, "{}"
|
||||
|
||||
def _put_code(self):
|
||||
function_name = self.path.rsplit("/", 2)[-2]
|
||||
qualifier = self._get_param("Qualifier", None)
|
||||
resp = self.lambda_backend.update_function_code(
|
||||
function_name, qualifier, body=self.json_body
|
||||
)
|
||||
|
||||
fn = self.lambda_backend.get_function(function_name, qualifier)
|
||||
|
||||
if fn:
|
||||
if self.json_body.get("Publish", False):
|
||||
fn = self.lambda_backend.publish_function(function_name)
|
||||
|
||||
config = fn.update_function_code(self.json_body)
|
||||
return 200, {}, json.dumps(config)
|
||||
if resp:
|
||||
return 200, {}, json.dumps(resp)
|
||||
else:
|
||||
return 404, {}, "{}"
|
||||
|
@ -27,12 +27,14 @@ class Task(BaseModel):
|
||||
name,
|
||||
region_name,
|
||||
arn_counter=0,
|
||||
metadata=None,
|
||||
):
|
||||
self.source_location_arn = source_location_arn
|
||||
self.destination_location_arn = destination_location_arn
|
||||
self.name = name
|
||||
self.metadata = metadata
|
||||
# For simplicity Tasks are either available or running
|
||||
self.status = "AVAILABLE"
|
||||
self.name = name
|
||||
self.current_task_execution_arn = None
|
||||
# Generate ARN
|
||||
self.arn = "arn:aws:datasync:{0}:111222333444:task/task-{1}".format(
|
||||
@ -129,7 +131,27 @@ class DataSyncBackend(BaseBackend):
|
||||
self.locations[location.arn] = location
|
||||
return location.arn
|
||||
|
||||
def create_task(self, source_location_arn, destination_location_arn, name):
|
||||
def _get_location(self, location_arn, typ):
|
||||
if location_arn not in self.locations:
|
||||
raise InvalidRequestException(
|
||||
"Location {0} is not found.".format(location_arn)
|
||||
)
|
||||
location = self.locations[location_arn]
|
||||
if location.typ != typ:
|
||||
raise InvalidRequestException(
|
||||
"Invalid Location type: {0}".format(location.typ)
|
||||
)
|
||||
return location
|
||||
|
||||
def delete_location(self, location_arn):
|
||||
if location_arn in self.locations:
|
||||
del self.locations[location_arn]
|
||||
else:
|
||||
raise InvalidRequestException
|
||||
|
||||
def create_task(
|
||||
self, source_location_arn, destination_location_arn, name, metadata=None
|
||||
):
|
||||
if source_location_arn not in self.locations:
|
||||
raise InvalidRequestException(
|
||||
"Location {0} not found.".format(source_location_arn)
|
||||
@ -145,10 +167,33 @@ class DataSyncBackend(BaseBackend):
|
||||
name,
|
||||
region_name=self.region_name,
|
||||
arn_counter=self.arn_counter,
|
||||
metadata=metadata,
|
||||
)
|
||||
self.tasks[task.arn] = task
|
||||
return task.arn
|
||||
|
||||
def _get_task(self, task_arn):
|
||||
if task_arn in self.tasks:
|
||||
return self.tasks[task_arn]
|
||||
else:
|
||||
raise InvalidRequestException
|
||||
|
||||
def update_task(self, task_arn, name, metadata):
|
||||
if task_arn in self.tasks:
|
||||
task = self.tasks[task_arn]
|
||||
task.name = name
|
||||
task.metadata = metadata
|
||||
else:
|
||||
raise InvalidRequestException(
|
||||
"Sync task {0} is not found.".format(task_arn)
|
||||
)
|
||||
|
||||
def delete_task(self, task_arn):
|
||||
if task_arn in self.tasks:
|
||||
del self.tasks[task_arn]
|
||||
else:
|
||||
raise InvalidRequestException
|
||||
|
||||
def start_task_execution(self, task_arn):
|
||||
self.arn_counter = self.arn_counter + 1
|
||||
if task_arn in self.tasks:
|
||||
@ -161,12 +206,19 @@ class DataSyncBackend(BaseBackend):
|
||||
return task_execution.arn
|
||||
raise InvalidRequestException("Invalid request.")
|
||||
|
||||
def _get_task_execution(self, task_execution_arn):
|
||||
if task_execution_arn in self.task_executions:
|
||||
return self.task_executions[task_execution_arn]
|
||||
else:
|
||||
raise InvalidRequestException
|
||||
|
||||
def cancel_task_execution(self, task_execution_arn):
|
||||
if task_execution_arn in self.task_executions:
|
||||
task_execution = self.task_executions[task_execution_arn]
|
||||
task_execution.cancel()
|
||||
task_arn = task_execution.task_arn
|
||||
self.tasks[task_arn].current_task_execution_arn = None
|
||||
self.tasks[task_arn].status = "AVAILABLE"
|
||||
return
|
||||
raise InvalidRequestException(
|
||||
"Sync task {0} is not found.".format(task_execution_arn)
|
||||
|
@ -2,7 +2,6 @@ import json
|
||||
|
||||
from moto.core.responses import BaseResponse
|
||||
|
||||
from .exceptions import InvalidRequestException
|
||||
from .models import datasync_backends
|
||||
|
||||
|
||||
@ -18,17 +17,7 @@ class DataSyncResponse(BaseResponse):
|
||||
return json.dumps({"Locations": locations})
|
||||
|
||||
def _get_location(self, location_arn, typ):
|
||||
location_arn = self._get_param("LocationArn")
|
||||
if location_arn not in self.datasync_backend.locations:
|
||||
raise InvalidRequestException(
|
||||
"Location {0} is not found.".format(location_arn)
|
||||
)
|
||||
location = self.datasync_backend.locations[location_arn]
|
||||
if location.typ != typ:
|
||||
raise InvalidRequestException(
|
||||
"Invalid Location type: {0}".format(location.typ)
|
||||
)
|
||||
return location
|
||||
return self.datasync_backend._get_location(location_arn, typ)
|
||||
|
||||
def create_location_s3(self):
|
||||
# s3://bucket_name/folder/
|
||||
@ -86,16 +75,40 @@ class DataSyncResponse(BaseResponse):
|
||||
}
|
||||
)
|
||||
|
||||
def delete_location(self):
|
||||
location_arn = self._get_param("LocationArn")
|
||||
self.datasync_backend.delete_location(location_arn)
|
||||
return json.dumps({})
|
||||
|
||||
def create_task(self):
|
||||
destination_location_arn = self._get_param("DestinationLocationArn")
|
||||
source_location_arn = self._get_param("SourceLocationArn")
|
||||
name = self._get_param("Name")
|
||||
|
||||
metadata = {
|
||||
"CloudWatchLogGroupArn": self._get_param("CloudWatchLogGroupArn"),
|
||||
"Options": self._get_param("Options"),
|
||||
"Excludes": self._get_param("Excludes"),
|
||||
"Tags": self._get_param("Tags"),
|
||||
}
|
||||
arn = self.datasync_backend.create_task(
|
||||
source_location_arn, destination_location_arn, name
|
||||
source_location_arn, destination_location_arn, name, metadata=metadata
|
||||
)
|
||||
return json.dumps({"TaskArn": arn})
|
||||
|
||||
def update_task(self):
|
||||
task_arn = self._get_param("TaskArn")
|
||||
self.datasync_backend.update_task(
|
||||
task_arn,
|
||||
name=self._get_param("Name"),
|
||||
metadata={
|
||||
"CloudWatchLogGroupArn": self._get_param("CloudWatchLogGroupArn"),
|
||||
"Options": self._get_param("Options"),
|
||||
"Excludes": self._get_param("Excludes"),
|
||||
"Tags": self._get_param("Tags"),
|
||||
},
|
||||
)
|
||||
return json.dumps({})
|
||||
|
||||
def list_tasks(self):
|
||||
tasks = list()
|
||||
for arn, task in self.datasync_backend.tasks.items():
|
||||
@ -104,29 +117,32 @@ class DataSyncResponse(BaseResponse):
|
||||
)
|
||||
return json.dumps({"Tasks": tasks})
|
||||
|
||||
def delete_task(self):
|
||||
task_arn = self._get_param("TaskArn")
|
||||
self.datasync_backend.delete_task(task_arn)
|
||||
return json.dumps({})
|
||||
|
||||
def describe_task(self):
|
||||
task_arn = self._get_param("TaskArn")
|
||||
if task_arn in self.datasync_backend.tasks:
|
||||
task = self.datasync_backend.tasks[task_arn]
|
||||
return json.dumps(
|
||||
{
|
||||
"TaskArn": task.arn,
|
||||
"Name": task.name,
|
||||
"CurrentTaskExecutionArn": task.current_task_execution_arn,
|
||||
"Status": task.status,
|
||||
"SourceLocationArn": task.source_location_arn,
|
||||
"DestinationLocationArn": task.destination_location_arn,
|
||||
}
|
||||
)
|
||||
raise InvalidRequestException
|
||||
task = self.datasync_backend._get_task(task_arn)
|
||||
return json.dumps(
|
||||
{
|
||||
"TaskArn": task.arn,
|
||||
"Status": task.status,
|
||||
"Name": task.name,
|
||||
"CurrentTaskExecutionArn": task.current_task_execution_arn,
|
||||
"SourceLocationArn": task.source_location_arn,
|
||||
"DestinationLocationArn": task.destination_location_arn,
|
||||
"CloudWatchLogGroupArn": task.metadata["CloudWatchLogGroupArn"],
|
||||
"Options": task.metadata["Options"],
|
||||
"Excludes": task.metadata["Excludes"],
|
||||
}
|
||||
)
|
||||
|
||||
def start_task_execution(self):
|
||||
task_arn = self._get_param("TaskArn")
|
||||
if task_arn in self.datasync_backend.tasks:
|
||||
arn = self.datasync_backend.start_task_execution(task_arn)
|
||||
if arn:
|
||||
return json.dumps({"TaskExecutionArn": arn})
|
||||
raise InvalidRequestException("Invalid request.")
|
||||
arn = self.datasync_backend.start_task_execution(task_arn)
|
||||
return json.dumps({"TaskExecutionArn": arn})
|
||||
|
||||
def cancel_task_execution(self):
|
||||
task_execution_arn = self._get_param("TaskExecutionArn")
|
||||
@ -135,21 +151,12 @@ class DataSyncResponse(BaseResponse):
|
||||
|
||||
def describe_task_execution(self):
|
||||
task_execution_arn = self._get_param("TaskExecutionArn")
|
||||
|
||||
if task_execution_arn in self.datasync_backend.task_executions:
|
||||
task_execution = self.datasync_backend.task_executions[task_execution_arn]
|
||||
if task_execution:
|
||||
result = json.dumps(
|
||||
{
|
||||
"TaskExecutionArn": task_execution.arn,
|
||||
"Status": task_execution.status,
|
||||
}
|
||||
)
|
||||
if task_execution.status == "SUCCESS":
|
||||
self.datasync_backend.tasks[
|
||||
task_execution.task_arn
|
||||
].status = "AVAILABLE"
|
||||
# Simulate task being executed
|
||||
task_execution.iterate_status()
|
||||
return result
|
||||
raise InvalidRequestException
|
||||
task_execution = self.datasync_backend._get_task_execution(task_execution_arn)
|
||||
result = json.dumps(
|
||||
{"TaskExecutionArn": task_execution.arn, "Status": task_execution.status,}
|
||||
)
|
||||
if task_execution.status == "SUCCESS":
|
||||
self.datasync_backend.tasks[task_execution.task_arn].status = "AVAILABLE"
|
||||
# Simulate task being executed
|
||||
task_execution.iterate_status()
|
||||
return result
|
||||
|
@ -77,6 +77,7 @@ class DynamoType(object):
|
||||
attr, list_index = attribute_is_list(attr)
|
||||
if not key:
|
||||
# {'S': value} ==> {'S': new_value}
|
||||
self.type = new_value.type
|
||||
self.value = new_value.value
|
||||
else:
|
||||
if attr not in self.value: # nonexistingattribute
|
||||
|
@ -214,6 +214,7 @@ class NetworkInterface(TaggedEC2Resource):
|
||||
ec2_backend,
|
||||
subnet,
|
||||
private_ip_address,
|
||||
private_ip_addresses=None,
|
||||
device_index=0,
|
||||
public_ip_auto_assign=True,
|
||||
group_ids=None,
|
||||
@ -223,6 +224,7 @@ class NetworkInterface(TaggedEC2Resource):
|
||||
self.id = random_eni_id()
|
||||
self.device_index = device_index
|
||||
self.private_ip_address = private_ip_address or random_private_ip()
|
||||
self.private_ip_addresses = private_ip_addresses
|
||||
self.subnet = subnet
|
||||
self.instance = None
|
||||
self.attachment_id = None
|
||||
@ -341,12 +343,19 @@ class NetworkInterfaceBackend(object):
|
||||
super(NetworkInterfaceBackend, self).__init__()
|
||||
|
||||
def create_network_interface(
|
||||
self, subnet, private_ip_address, group_ids=None, description=None, **kwargs
|
||||
self,
|
||||
subnet,
|
||||
private_ip_address,
|
||||
private_ip_addresses=None,
|
||||
group_ids=None,
|
||||
description=None,
|
||||
**kwargs
|
||||
):
|
||||
eni = NetworkInterface(
|
||||
self,
|
||||
subnet,
|
||||
private_ip_address,
|
||||
private_ip_addresses,
|
||||
group_ids=group_ids,
|
||||
description=description,
|
||||
**kwargs
|
||||
@ -2819,6 +2828,9 @@ class Subnet(TaggedEC2Resource):
|
||||
self.vpc_id = vpc_id
|
||||
self.cidr_block = cidr_block
|
||||
self.cidr = ipaddress.IPv4Network(six.text_type(self.cidr_block), strict=False)
|
||||
self._available_ip_addresses = (
|
||||
ipaddress.IPv4Network(six.text_type(self.cidr_block)).num_addresses - 5
|
||||
)
|
||||
self._availability_zone = availability_zone
|
||||
self.default_for_az = default_for_az
|
||||
self.map_public_ip_on_launch = map_public_ip_on_launch
|
||||
@ -2854,6 +2866,21 @@ class Subnet(TaggedEC2Resource):
|
||||
|
||||
return subnet
|
||||
|
||||
@property
|
||||
def available_ip_addresses(self):
|
||||
enis = [
|
||||
eni
|
||||
for eni in self.ec2_backend.get_all_network_interfaces()
|
||||
if eni.subnet.id == self.id
|
||||
]
|
||||
addresses_taken = [
|
||||
eni.private_ip_address for eni in enis if eni.private_ip_address
|
||||
]
|
||||
for eni in enis:
|
||||
if eni.private_ip_addresses:
|
||||
addresses_taken.extend(eni.private_ip_addresses)
|
||||
return str(self._available_ip_addresses - len(addresses_taken))
|
||||
|
||||
@property
|
||||
def availability_zone(self):
|
||||
return self._availability_zone.name
|
||||
|
@ -7,12 +7,13 @@ class ElasticNetworkInterfaces(BaseResponse):
|
||||
def create_network_interface(self):
|
||||
subnet_id = self._get_param("SubnetId")
|
||||
private_ip_address = self._get_param("PrivateIpAddress")
|
||||
private_ip_addresses = self._get_multi_param("PrivateIpAddresses")
|
||||
groups = self._get_multi_param("SecurityGroupId")
|
||||
subnet = self.ec2_backend.get_subnet(subnet_id)
|
||||
description = self._get_param("Description")
|
||||
if self.is_not_dryrun("CreateNetworkInterface"):
|
||||
eni = self.ec2_backend.create_network_interface(
|
||||
subnet, private_ip_address, groups, description
|
||||
subnet, private_ip_address, private_ip_addresses, groups, description
|
||||
)
|
||||
template = self.response_template(CREATE_NETWORK_INTERFACE_RESPONSE)
|
||||
return template.render(eni=eni)
|
||||
|
@ -53,7 +53,7 @@ CREATE_SUBNET_RESPONSE = """
|
||||
<state>pending</state>
|
||||
<vpcId>{{ subnet.vpc_id }}</vpcId>
|
||||
<cidrBlock>{{ subnet.cidr_block }}</cidrBlock>
|
||||
<availableIpAddressCount>251</availableIpAddressCount>
|
||||
<availableIpAddressCount>{{ subnet.available_ip_addresses }}</availableIpAddressCount>
|
||||
<availabilityZone>{{ subnet._availability_zone.name }}</availabilityZone>
|
||||
<availabilityZoneId>{{ subnet._availability_zone.zone_id }}</availabilityZoneId>
|
||||
<defaultForAz>{{ subnet.default_for_az }}</defaultForAz>
|
||||
@ -81,7 +81,7 @@ DESCRIBE_SUBNETS_RESPONSE = """
|
||||
<state>available</state>
|
||||
<vpcId>{{ subnet.vpc_id }}</vpcId>
|
||||
<cidrBlock>{{ subnet.cidr_block }}</cidrBlock>
|
||||
<availableIpAddressCount>251</availableIpAddressCount>
|
||||
<availableIpAddressCount>{{ subnet.available_ip_addresses }}</availableIpAddressCount>
|
||||
<availabilityZone>{{ subnet._availability_zone.name }}</availabilityZone>
|
||||
<availabilityZoneId>{{ subnet._availability_zone.zone_id }}</availabilityZoneId>
|
||||
<defaultForAz>{{ subnet.default_for_az }}</defaultForAz>
|
||||
|
@ -5,6 +5,7 @@ import boto3
|
||||
|
||||
from moto.core.exceptions import JsonRESTError
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.sts.models import ACCOUNT_ID
|
||||
|
||||
|
||||
class Rule(BaseModel):
|
||||
@ -54,6 +55,42 @@ class Rule(BaseModel):
|
||||
self.targets.pop(index)
|
||||
|
||||
|
||||
class EventBus(BaseModel):
|
||||
def __init__(self, region_name, name):
|
||||
self.region = region_name
|
||||
self.name = name
|
||||
|
||||
self._permissions = {}
|
||||
|
||||
@property
|
||||
def arn(self):
|
||||
return "arn:aws:events:{region}:{account_id}:event-bus/{name}".format(
|
||||
region=self.region, account_id=ACCOUNT_ID, name=self.name
|
||||
)
|
||||
|
||||
@property
|
||||
def policy(self):
|
||||
if not len(self._permissions):
|
||||
return None
|
||||
|
||||
policy = {"Version": "2012-10-17", "Statement": []}
|
||||
|
||||
for sid, permission in self._permissions.items():
|
||||
policy["Statement"].append(
|
||||
{
|
||||
"Sid": sid,
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::{}:root".format(permission["Principal"])
|
||||
},
|
||||
"Action": permission["Action"],
|
||||
"Resource": self.arn,
|
||||
}
|
||||
)
|
||||
|
||||
return json.dumps(policy)
|
||||
|
||||
|
||||
class EventsBackend(BaseBackend):
|
||||
ACCOUNT_ID = re.compile(r"^(\d{1,12}|\*)$")
|
||||
STATEMENT_ID = re.compile(r"^[a-zA-Z0-9-_]{1,64}$")
|
||||
@ -65,13 +102,19 @@ class EventsBackend(BaseBackend):
|
||||
self.rules_order = []
|
||||
self.next_tokens = {}
|
||||
self.region_name = region_name
|
||||
self.permissions = {}
|
||||
self.event_buses = {}
|
||||
self.event_sources = {}
|
||||
|
||||
self._add_default_event_bus()
|
||||
|
||||
def reset(self):
|
||||
region_name = self.region_name
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
def _add_default_event_bus(self):
|
||||
self.event_buses["default"] = EventBus(self.region_name, "default")
|
||||
|
||||
def _get_rule_by_index(self, i):
|
||||
return self.rules.get(self.rules_order[i])
|
||||
|
||||
@ -221,9 +264,17 @@ class EventsBackend(BaseBackend):
|
||||
def test_event_pattern(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def put_permission(self, action, principal, statement_id):
|
||||
def put_permission(self, event_bus_name, action, principal, statement_id):
|
||||
if not event_bus_name:
|
||||
event_bus_name = "default"
|
||||
|
||||
event_bus = self.describe_event_bus(event_bus_name)
|
||||
|
||||
if action is None or action != "events:PutEvents":
|
||||
raise JsonRESTError("InvalidParameterValue", "Action must be PutEvents")
|
||||
raise JsonRESTError(
|
||||
"ValidationException",
|
||||
"Provided value in parameter 'action' is not supported.",
|
||||
)
|
||||
|
||||
if principal is None or self.ACCOUNT_ID.match(principal) is None:
|
||||
raise JsonRESTError(
|
||||
@ -235,34 +286,81 @@ class EventsBackend(BaseBackend):
|
||||
"InvalidParameterValue", "StatementId must match ^[a-zA-Z0-9-_]{1,64}$"
|
||||
)
|
||||
|
||||
self.permissions[statement_id] = {"action": action, "principal": principal}
|
||||
event_bus._permissions[statement_id] = {
|
||||
"Action": action,
|
||||
"Principal": principal,
|
||||
}
|
||||
|
||||
def remove_permission(self, statement_id):
|
||||
try:
|
||||
del self.permissions[statement_id]
|
||||
except KeyError:
|
||||
raise JsonRESTError("ResourceNotFoundException", "StatementId not found")
|
||||
def remove_permission(self, event_bus_name, statement_id):
|
||||
if not event_bus_name:
|
||||
event_bus_name = "default"
|
||||
|
||||
def describe_event_bus(self):
|
||||
arn = "arn:aws:events:{0}:000000000000:event-bus/default".format(
|
||||
self.region_name
|
||||
)
|
||||
statements = []
|
||||
for statement_id, data in self.permissions.items():
|
||||
statements.append(
|
||||
{
|
||||
"Sid": statement_id,
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "arn:aws:iam::{0}:root".format(data["principal"])
|
||||
},
|
||||
"Action": data["action"],
|
||||
"Resource": arn,
|
||||
}
|
||||
event_bus = self.describe_event_bus(event_bus_name)
|
||||
|
||||
if not len(event_bus._permissions):
|
||||
raise JsonRESTError(
|
||||
"ResourceNotFoundException", "EventBus does not have a policy."
|
||||
)
|
||||
policy = {"Version": "2012-10-17", "Statement": statements}
|
||||
policy_json = json.dumps(policy)
|
||||
return {"Policy": policy_json, "Name": "default", "Arn": arn}
|
||||
|
||||
if not event_bus._permissions.pop(statement_id, None):
|
||||
raise JsonRESTError(
|
||||
"ResourceNotFoundException",
|
||||
"Statement with the provided id does not exist.",
|
||||
)
|
||||
|
||||
def describe_event_bus(self, name):
|
||||
if not name:
|
||||
name = "default"
|
||||
|
||||
event_bus = self.event_buses.get(name)
|
||||
|
||||
if not event_bus:
|
||||
raise JsonRESTError(
|
||||
"ResourceNotFoundException",
|
||||
"Event bus {} does not exist.".format(name),
|
||||
)
|
||||
|
||||
return event_bus
|
||||
|
||||
def create_event_bus(self, name, event_source_name):
|
||||
if name in self.event_buses:
|
||||
raise JsonRESTError(
|
||||
"ResourceAlreadyExistsException",
|
||||
"Event bus {} already exists.".format(name),
|
||||
)
|
||||
|
||||
if not event_source_name and "/" in name:
|
||||
raise JsonRESTError(
|
||||
"ValidationException", "Event bus name must not contain '/'."
|
||||
)
|
||||
|
||||
if event_source_name and event_source_name not in self.event_sources:
|
||||
raise JsonRESTError(
|
||||
"ResourceNotFoundException",
|
||||
"Event source {} does not exist.".format(event_source_name),
|
||||
)
|
||||
|
||||
self.event_buses[name] = EventBus(self.region_name, name)
|
||||
|
||||
return self.event_buses[name]
|
||||
|
||||
def list_event_buses(self, name_prefix):
|
||||
if name_prefix:
|
||||
return [
|
||||
event_bus
|
||||
for event_bus in self.event_buses.values()
|
||||
if event_bus.name.startswith(name_prefix)
|
||||
]
|
||||
|
||||
return list(self.event_buses.values())
|
||||
|
||||
def delete_event_bus(self, name):
|
||||
if name == "default":
|
||||
raise JsonRESTError(
|
||||
"ValidationException", "Cannot delete event bus default."
|
||||
)
|
||||
|
||||
self.event_buses.pop(name, None)
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("events")
|
||||
|
@ -238,20 +238,68 @@ class EventsHandler(BaseResponse):
|
||||
pass
|
||||
|
||||
def put_permission(self):
|
||||
event_bus_name = self._get_param("EventBusName")
|
||||
action = self._get_param("Action")
|
||||
principal = self._get_param("Principal")
|
||||
statement_id = self._get_param("StatementId")
|
||||
|
||||
self.events_backend.put_permission(action, principal, statement_id)
|
||||
self.events_backend.put_permission(
|
||||
event_bus_name, action, principal, statement_id
|
||||
)
|
||||
|
||||
return ""
|
||||
|
||||
def remove_permission(self):
|
||||
event_bus_name = self._get_param("EventBusName")
|
||||
statement_id = self._get_param("StatementId")
|
||||
|
||||
self.events_backend.remove_permission(statement_id)
|
||||
self.events_backend.remove_permission(event_bus_name, statement_id)
|
||||
|
||||
return ""
|
||||
|
||||
def describe_event_bus(self):
|
||||
return json.dumps(self.events_backend.describe_event_bus())
|
||||
name = self._get_param("Name")
|
||||
|
||||
event_bus = self.events_backend.describe_event_bus(name)
|
||||
response = {
|
||||
"Name": event_bus.name,
|
||||
"Arn": event_bus.arn,
|
||||
}
|
||||
|
||||
if event_bus.policy:
|
||||
response["Policy"] = event_bus.policy
|
||||
|
||||
return json.dumps(response), self.response_headers
|
||||
|
||||
def create_event_bus(self):
|
||||
name = self._get_param("Name")
|
||||
event_source_name = self._get_param("EventSourceName")
|
||||
|
||||
event_bus = self.events_backend.create_event_bus(name, event_source_name)
|
||||
|
||||
return json.dumps({"EventBusArn": event_bus.arn}), self.response_headers
|
||||
|
||||
def list_event_buses(self):
|
||||
name_prefix = self._get_param("NamePrefix")
|
||||
# ToDo: add 'NextToken' & 'Limit' parameters
|
||||
|
||||
response = []
|
||||
for event_bus in self.events_backend.list_event_buses(name_prefix):
|
||||
event_bus_response = {
|
||||
"Name": event_bus.name,
|
||||
"Arn": event_bus.arn,
|
||||
}
|
||||
|
||||
if event_bus.policy:
|
||||
event_bus_response["Policy"] = event_bus.policy
|
||||
|
||||
response.append(event_bus_response)
|
||||
|
||||
return json.dumps({"EventBuses": response}), self.response_headers
|
||||
|
||||
def delete_event_bus(self):
|
||||
name = self._get_param("Name")
|
||||
|
||||
self.events_backend.delete_event_bus(name)
|
||||
|
||||
return "", self.response_headers
|
||||
|
@ -818,6 +818,12 @@ class IAMBackend(BaseBackend):
|
||||
policy = ManagedPolicy(
|
||||
policy_name, description=description, document=policy_document, path=path
|
||||
)
|
||||
if policy.arn in self.managed_policies:
|
||||
raise EntityAlreadyExists(
|
||||
"A policy called {} already exists. Duplicate names are not allowed.".format(
|
||||
policy_name
|
||||
)
|
||||
)
|
||||
self.managed_policies[policy.arn] = policy
|
||||
return policy
|
||||
|
||||
@ -1227,6 +1233,14 @@ class IAMBackend(BaseBackend):
|
||||
group = self.get_group(group_name)
|
||||
return group.get_policy(policy_name)
|
||||
|
||||
def delete_group(self, group_name):
|
||||
try:
|
||||
del self.groups[group_name]
|
||||
except KeyError:
|
||||
raise IAMNotFoundException(
|
||||
"The group with name {0} cannot be found.".format(group_name)
|
||||
)
|
||||
|
||||
def create_user(self, user_name, path="/"):
|
||||
if user_name in self.users:
|
||||
raise IAMConflictException(
|
||||
|
@ -428,6 +428,12 @@ class IamResponse(BaseResponse):
|
||||
template = self.response_template(GET_GROUP_POLICY_TEMPLATE)
|
||||
return template.render(name="GetGroupPolicyResponse", **policy_result)
|
||||
|
||||
def delete_group(self):
|
||||
group_name = self._get_param("GroupName")
|
||||
iam_backend.delete_group(group_name)
|
||||
template = self.response_template(GENERIC_EMPTY_TEMPLATE)
|
||||
return template.render(name="DeleteGroup")
|
||||
|
||||
def create_user(self):
|
||||
user_name = self._get_param("UserName")
|
||||
path = self._get_param("Path")
|
||||
|
@ -269,10 +269,32 @@ class OrganizationsBackend(BaseBackend):
|
||||
)
|
||||
return account
|
||||
|
||||
def get_account_by_attr(self, attr, value):
|
||||
account = next(
|
||||
(
|
||||
account
|
||||
for account in self.accounts
|
||||
if hasattr(account, attr) and getattr(account, attr) == value
|
||||
),
|
||||
None,
|
||||
)
|
||||
if account is None:
|
||||
raise RESTError(
|
||||
"AccountNotFoundException",
|
||||
"You specified an account that doesn't exist.",
|
||||
)
|
||||
return account
|
||||
|
||||
def describe_account(self, **kwargs):
|
||||
account = self.get_account_by_id(kwargs["AccountId"])
|
||||
return account.describe()
|
||||
|
||||
def describe_create_account_status(self, **kwargs):
|
||||
account = self.get_account_by_attr(
|
||||
"create_account_status_id", kwargs["CreateAccountRequestId"]
|
||||
)
|
||||
return account.create_account_status
|
||||
|
||||
def list_accounts(self):
|
||||
return dict(
|
||||
Accounts=[account.describe()["Account"] for account in self.accounts]
|
||||
|
@ -65,6 +65,13 @@ class OrganizationsResponse(BaseResponse):
|
||||
self.organizations_backend.describe_account(**self.request_params)
|
||||
)
|
||||
|
||||
def describe_create_account_status(self):
|
||||
return json.dumps(
|
||||
self.organizations_backend.describe_create_account_status(
|
||||
**self.request_params
|
||||
)
|
||||
)
|
||||
|
||||
def list_accounts(self):
|
||||
return json.dumps(self.organizations_backend.list_accounts())
|
||||
|
||||
|
@ -14,23 +14,21 @@ class ResourceNotFoundException(SecretsManagerClientError):
|
||||
)
|
||||
|
||||
|
||||
# Using specialised exception due to the use of a non-ASCII character
|
||||
class SecretNotFoundException(SecretsManagerClientError):
|
||||
def __init__(self):
|
||||
self.code = 404
|
||||
super(SecretNotFoundException, self).__init__(
|
||||
"ResourceNotFoundException",
|
||||
message="Secrets Manager can\u2019t find the specified secret.",
|
||||
message="Secrets Manager can't find the specified secret.",
|
||||
)
|
||||
|
||||
|
||||
# Using specialised exception due to the use of a non-ASCII character
|
||||
class SecretHasNoValueException(SecretsManagerClientError):
|
||||
def __init__(self, version_stage):
|
||||
self.code = 404
|
||||
super(SecretHasNoValueException, self).__init__(
|
||||
"ResourceNotFoundException",
|
||||
message="Secrets Manager can\u2019t find the specified secret "
|
||||
message="Secrets Manager can't find the specified secret "
|
||||
"value for staging label: {}".format(version_stage),
|
||||
)
|
||||
|
||||
|
@ -7,16 +7,18 @@ import boto3
|
||||
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
alternative_service_names = {'lambda': 'awslambda'}
|
||||
|
||||
|
||||
def get_moto_implementation(service_name):
|
||||
service_name_standardized = service_name.replace("-", "") if "-" in service_name else service_name
|
||||
if not hasattr(moto, service_name_standardized):
|
||||
service_name = service_name.replace("-", "") if "-" in service_name else service_name
|
||||
alt_service_name = alternative_service_names[service_name] if service_name in alternative_service_names else service_name
|
||||
if not hasattr(moto, alt_service_name):
|
||||
return None
|
||||
module = getattr(moto, service_name_standardized)
|
||||
module = getattr(moto, alt_service_name)
|
||||
if module is None:
|
||||
return None
|
||||
mock = getattr(module, "mock_{}".format(service_name_standardized))
|
||||
mock = getattr(module, "mock_{}".format(service_name))
|
||||
if mock is None:
|
||||
return None
|
||||
backends = list(mock().backends.values())
|
||||
|
@ -402,10 +402,10 @@ def test_s3_access_denied_with_denying_attached_group_policy():
|
||||
"Statement": [{"Effect": "Deny", "Action": "s3:List*", "Resource": "*"}],
|
||||
}
|
||||
access_key = create_user_with_access_key_and_attached_policy(
|
||||
user_name, attached_policy_document
|
||||
user_name, attached_policy_document, policy_name="policy1"
|
||||
)
|
||||
create_group_with_attached_policy_and_add_user(
|
||||
user_name, group_attached_policy_document
|
||||
user_name, group_attached_policy_document, policy_name="policy2"
|
||||
)
|
||||
client = boto3.client(
|
||||
"s3",
|
||||
@ -476,10 +476,16 @@ def test_access_denied_with_many_irrelevant_policies():
|
||||
"Statement": [{"Effect": "Deny", "Action": "lambda:*", "Resource": "*"}],
|
||||
}
|
||||
access_key = create_user_with_access_key_and_multiple_policies(
|
||||
user_name, inline_policy_document, attached_policy_document
|
||||
user_name,
|
||||
inline_policy_document,
|
||||
attached_policy_document,
|
||||
attached_policy_name="policy1",
|
||||
)
|
||||
create_group_with_multiple_policies_and_add_user(
|
||||
user_name, group_inline_policy_document, group_attached_policy_document
|
||||
user_name,
|
||||
group_inline_policy_document,
|
||||
group_attached_policy_document,
|
||||
attached_policy_name="policy2",
|
||||
)
|
||||
client = boto3.client(
|
||||
"ec2",
|
||||
|
@ -127,6 +127,22 @@ def test_list_locations():
|
||||
assert response["Locations"][2]["LocationUri"] == "s3://my_bucket/dir"
|
||||
|
||||
|
||||
@mock_datasync
|
||||
def test_delete_location():
|
||||
client = boto3.client("datasync", region_name="us-east-1")
|
||||
locations = create_locations(client, create_smb=True)
|
||||
response = client.list_locations()
|
||||
assert len(response["Locations"]) == 1
|
||||
location_arn = locations["smb_arn"]
|
||||
|
||||
response = client.delete_location(LocationArn=location_arn)
|
||||
response = client.list_locations()
|
||||
assert len(response["Locations"]) == 0
|
||||
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.delete_location(LocationArn=location_arn)
|
||||
|
||||
|
||||
@mock_datasync
|
||||
def test_create_task():
|
||||
client = boto3.client("datasync", region_name="us-east-1")
|
||||
@ -208,6 +224,72 @@ def test_describe_task_not_exist():
|
||||
client.describe_task(TaskArn="abc")
|
||||
|
||||
|
||||
@mock_datasync
|
||||
def test_update_task():
|
||||
client = boto3.client("datasync", region_name="us-east-1")
|
||||
locations = create_locations(client, create_s3=True, create_smb=True)
|
||||
|
||||
initial_name = "Initial_Name"
|
||||
updated_name = "Updated_Name"
|
||||
initial_options = {
|
||||
"VerifyMode": "NONE",
|
||||
"Atime": "BEST_EFFORT",
|
||||
"Mtime": "PRESERVE",
|
||||
}
|
||||
updated_options = {
|
||||
"VerifyMode": "POINT_IN_TIME_CONSISTENT",
|
||||
"Atime": "BEST_EFFORT",
|
||||
"Mtime": "PRESERVE",
|
||||
}
|
||||
response = client.create_task(
|
||||
SourceLocationArn=locations["smb_arn"],
|
||||
DestinationLocationArn=locations["s3_arn"],
|
||||
Name=initial_name,
|
||||
Options=initial_options,
|
||||
)
|
||||
task_arn = response["TaskArn"]
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["TaskArn"] == task_arn
|
||||
assert response["Name"] == initial_name
|
||||
assert response["Options"] == initial_options
|
||||
|
||||
response = client.update_task(
|
||||
TaskArn=task_arn, Name=updated_name, Options=updated_options
|
||||
)
|
||||
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["TaskArn"] == task_arn
|
||||
assert response["Name"] == updated_name
|
||||
assert response["Options"] == updated_options
|
||||
|
||||
with assert_raises(ClientError) as e:
|
||||
client.update_task(TaskArn="doesnt_exist")
|
||||
|
||||
|
||||
@mock_datasync
|
||||
def test_delete_task():
|
||||
client = boto3.client("datasync", region_name="us-east-1")
|
||||
locations = create_locations(client, create_s3=True, create_smb=True)
|
||||
|
||||
response = client.create_task(
|
||||
SourceLocationArn=locations["smb_arn"],
|
||||
DestinationLocationArn=locations["s3_arn"],
|
||||
Name="task_name",
|
||||
)
|
||||
|
||||
response = client.list_tasks()
|
||||
assert len(response["Tasks"]) == 1
|
||||
task_arn = response["Tasks"][0]["TaskArn"]
|
||||
assert task_arn is not None
|
||||
|
||||
response = client.delete_task(TaskArn=task_arn)
|
||||
response = client.list_tasks()
|
||||
assert len(response["Tasks"]) == 0
|
||||
|
||||
with assert_raises(ClientError) as e:
|
||||
response = client.delete_task(TaskArn=task_arn)
|
||||
|
||||
|
||||
@mock_datasync
|
||||
def test_start_task_execution():
|
||||
client = boto3.client("datasync", region_name="us-east-1")
|
||||
@ -261,6 +343,8 @@ def test_describe_task_execution():
|
||||
Name="task_name",
|
||||
)
|
||||
task_arn = response["TaskArn"]
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["Status"] == "AVAILABLE"
|
||||
|
||||
response = client.start_task_execution(TaskArn=task_arn)
|
||||
task_execution_arn = response["TaskExecutionArn"]
|
||||
@ -270,26 +354,38 @@ def test_describe_task_execution():
|
||||
response = client.describe_task_execution(TaskExecutionArn=task_execution_arn)
|
||||
assert response["TaskExecutionArn"] == task_execution_arn
|
||||
assert response["Status"] == "INITIALIZING"
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["Status"] == "RUNNING"
|
||||
|
||||
response = client.describe_task_execution(TaskExecutionArn=task_execution_arn)
|
||||
assert response["TaskExecutionArn"] == task_execution_arn
|
||||
assert response["Status"] == "PREPARING"
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["Status"] == "RUNNING"
|
||||
|
||||
response = client.describe_task_execution(TaskExecutionArn=task_execution_arn)
|
||||
assert response["TaskExecutionArn"] == task_execution_arn
|
||||
assert response["Status"] == "TRANSFERRING"
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["Status"] == "RUNNING"
|
||||
|
||||
response = client.describe_task_execution(TaskExecutionArn=task_execution_arn)
|
||||
assert response["TaskExecutionArn"] == task_execution_arn
|
||||
assert response["Status"] == "VERIFYING"
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["Status"] == "RUNNING"
|
||||
|
||||
response = client.describe_task_execution(TaskExecutionArn=task_execution_arn)
|
||||
assert response["TaskExecutionArn"] == task_execution_arn
|
||||
assert response["Status"] == "SUCCESS"
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["Status"] == "AVAILABLE"
|
||||
|
||||
response = client.describe_task_execution(TaskExecutionArn=task_execution_arn)
|
||||
assert response["TaskExecutionArn"] == task_execution_arn
|
||||
assert response["Status"] == "SUCCESS"
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["Status"] == "AVAILABLE"
|
||||
|
||||
|
||||
@mock_datasync
|
||||
@ -317,11 +413,13 @@ def test_cancel_task_execution():
|
||||
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert response["CurrentTaskExecutionArn"] == task_execution_arn
|
||||
assert response["Status"] == "RUNNING"
|
||||
|
||||
response = client.cancel_task_execution(TaskExecutionArn=task_execution_arn)
|
||||
|
||||
response = client.describe_task(TaskArn=task_arn)
|
||||
assert "CurrentTaskExecutionArn" not in response
|
||||
assert response["Status"] == "AVAILABLE"
|
||||
|
||||
response = client.describe_task_execution(TaskExecutionArn=task_execution_arn)
|
||||
assert response["Status"] == "ERROR"
|
||||
|
@ -3319,3 +3319,66 @@ def _create_user_table():
|
||||
TableName="users", Item={"username": {"S": "user3"}, "foo": {"S": "bar"}}
|
||||
)
|
||||
return client
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_update_item_if_original_value_is_none():
|
||||
dynamo = boto3.resource("dynamodb", region_name="eu-central-1")
|
||||
dynamo.create_table(
|
||||
AttributeDefinitions=[{"AttributeName": "job_id", "AttributeType": "S"}],
|
||||
TableName="origin-rbu-dev",
|
||||
KeySchema=[{"AttributeName": "job_id", "KeyType": "HASH"}],
|
||||
ProvisionedThroughput={"ReadCapacityUnits": 1, "WriteCapacityUnits": 1},
|
||||
)
|
||||
table = dynamo.Table("origin-rbu-dev")
|
||||
table.put_item(Item={"job_id": "a", "job_name": None})
|
||||
table.update_item(
|
||||
Key={"job_id": "a"},
|
||||
UpdateExpression="SET job_name = :output",
|
||||
ExpressionAttributeValues={":output": "updated",},
|
||||
)
|
||||
table.scan()["Items"][0]["job_name"].should.equal("updated")
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_update_nested_item_if_original_value_is_none():
|
||||
dynamo = boto3.resource("dynamodb", region_name="eu-central-1")
|
||||
dynamo.create_table(
|
||||
AttributeDefinitions=[{"AttributeName": "job_id", "AttributeType": "S"}],
|
||||
TableName="origin-rbu-dev",
|
||||
KeySchema=[{"AttributeName": "job_id", "KeyType": "HASH"}],
|
||||
ProvisionedThroughput={"ReadCapacityUnits": 1, "WriteCapacityUnits": 1},
|
||||
)
|
||||
table = dynamo.Table("origin-rbu-dev")
|
||||
table.put_item(Item={"job_id": "a", "job_details": {"job_name": None}})
|
||||
table.update_item(
|
||||
Key={"job_id": "a"},
|
||||
UpdateExpression="SET job_details.job_name = :output",
|
||||
ExpressionAttributeValues={":output": "updated",},
|
||||
)
|
||||
table.scan()["Items"][0]["job_details"]["job_name"].should.equal("updated")
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_allow_update_to_item_with_different_type():
|
||||
dynamo = boto3.resource("dynamodb", region_name="eu-central-1")
|
||||
dynamo.create_table(
|
||||
AttributeDefinitions=[{"AttributeName": "job_id", "AttributeType": "S"}],
|
||||
TableName="origin-rbu-dev",
|
||||
KeySchema=[{"AttributeName": "job_id", "KeyType": "HASH"}],
|
||||
ProvisionedThroughput={"ReadCapacityUnits": 1, "WriteCapacityUnits": 1},
|
||||
)
|
||||
table = dynamo.Table("origin-rbu-dev")
|
||||
table.put_item(Item={"job_id": "a", "job_details": {"job_name": {"nested": "yes"}}})
|
||||
table.put_item(Item={"job_id": "b", "job_details": {"job_name": {"nested": "yes"}}})
|
||||
table.update_item(
|
||||
Key={"job_id": "a"},
|
||||
UpdateExpression="SET job_details.job_name = :output",
|
||||
ExpressionAttributeValues={":output": "updated"},
|
||||
)
|
||||
table.get_item(Key={"job_id": "a"})["Item"]["job_details"][
|
||||
"job_name"
|
||||
].should.be.equal("updated")
|
||||
table.get_item(Key={"job_id": "b"})["Item"]["job_details"][
|
||||
"job_name"
|
||||
].should.be.equal({"nested": "yes"})
|
||||
|
@ -11,6 +11,7 @@ from boto.exception import EC2ResponseError
|
||||
from botocore.exceptions import ParamValidationError, ClientError
|
||||
import json
|
||||
import sure # noqa
|
||||
import random
|
||||
|
||||
from moto import mock_cloudformation_deprecated, mock_ec2, mock_ec2_deprecated
|
||||
|
||||
@ -474,3 +475,127 @@ def test_create_subnets_with_overlapping_cidr_blocks():
|
||||
subnet_cidr_block
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_available_ip_addresses_in_subnet():
|
||||
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")
|
||||
cidr_range_addresses = [
|
||||
("10.0.0.0/16", 65531),
|
||||
("10.0.0.0/17", 32763),
|
||||
("10.0.0.0/18", 16379),
|
||||
("10.0.0.0/19", 8187),
|
||||
("10.0.0.0/20", 4091),
|
||||
("10.0.0.0/21", 2043),
|
||||
("10.0.0.0/22", 1019),
|
||||
("10.0.0.0/23", 507),
|
||||
("10.0.0.0/24", 251),
|
||||
("10.0.0.0/25", 123),
|
||||
("10.0.0.0/26", 59),
|
||||
("10.0.0.0/27", 27),
|
||||
("10.0.0.0/28", 11),
|
||||
]
|
||||
for (cidr, expected_count) in cidr_range_addresses:
|
||||
validate_subnet_details(client, vpc, cidr, expected_count)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_available_ip_addresses_in_subnet_with_enis():
|
||||
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")
|
||||
# Verify behaviour for various CIDR ranges (...)
|
||||
# Don't try to assign ENIs to /27 and /28, as there are not a lot of IP addresses to go around
|
||||
cidr_range_addresses = [
|
||||
("10.0.0.0/16", 65531),
|
||||
("10.0.0.0/17", 32763),
|
||||
("10.0.0.0/18", 16379),
|
||||
("10.0.0.0/19", 8187),
|
||||
("10.0.0.0/20", 4091),
|
||||
("10.0.0.0/21", 2043),
|
||||
("10.0.0.0/22", 1019),
|
||||
("10.0.0.0/23", 507),
|
||||
("10.0.0.0/24", 251),
|
||||
("10.0.0.0/25", 123),
|
||||
("10.0.0.0/26", 59),
|
||||
]
|
||||
for (cidr, expected_count) in cidr_range_addresses:
|
||||
validate_subnet_details_after_creating_eni(client, vpc, cidr, expected_count)
|
||||
|
||||
|
||||
def validate_subnet_details(client, vpc, cidr, expected_ip_address_count):
|
||||
subnet = client.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock=cidr, AvailabilityZone="us-west-1b"
|
||||
)["Subnet"]
|
||||
subnet["AvailableIpAddressCount"].should.equal(expected_ip_address_count)
|
||||
client.delete_subnet(SubnetId=subnet["SubnetId"])
|
||||
|
||||
|
||||
def validate_subnet_details_after_creating_eni(
|
||||
client, vpc, cidr, expected_ip_address_count
|
||||
):
|
||||
subnet = client.create_subnet(
|
||||
VpcId=vpc.id, CidrBlock=cidr, AvailabilityZone="us-west-1b"
|
||||
)["Subnet"]
|
||||
# Create a random number of Elastic Network Interfaces
|
||||
nr_of_eni_to_create = random.randint(0, 5)
|
||||
ip_addresses_assigned = 0
|
||||
enis_created = []
|
||||
for i in range(0, nr_of_eni_to_create):
|
||||
# Create a random number of IP addresses per ENI
|
||||
nr_of_ip_addresses = random.randint(1, 5)
|
||||
if nr_of_ip_addresses == 1:
|
||||
# Pick the first available IP address (First 4 are reserved by AWS)
|
||||
private_address = "10.0.0." + str(ip_addresses_assigned + 4)
|
||||
eni = client.create_network_interface(
|
||||
SubnetId=subnet["SubnetId"], PrivateIpAddress=private_address
|
||||
)["NetworkInterface"]
|
||||
enis_created.append(eni)
|
||||
ip_addresses_assigned = ip_addresses_assigned + 1
|
||||
else:
|
||||
# Assign a list of IP addresses
|
||||
private_addresses = [
|
||||
"10.0.0." + str(4 + ip_addresses_assigned + i)
|
||||
for i in range(0, nr_of_ip_addresses)
|
||||
]
|
||||
eni = client.create_network_interface(
|
||||
SubnetId=subnet["SubnetId"],
|
||||
PrivateIpAddresses=[
|
||||
{"PrivateIpAddress": address} for address in private_addresses
|
||||
],
|
||||
)["NetworkInterface"]
|
||||
enis_created.append(eni)
|
||||
ip_addresses_assigned = ip_addresses_assigned + nr_of_ip_addresses + 1 #
|
||||
# Verify that the nr of available IP addresses takes these ENIs into account
|
||||
updated_subnet = client.describe_subnets(SubnetIds=[subnet["SubnetId"]])["Subnets"][
|
||||
0
|
||||
]
|
||||
private_addresses = [
|
||||
eni["PrivateIpAddress"] for eni in enis_created if eni["PrivateIpAddress"]
|
||||
]
|
||||
for eni in enis_created:
|
||||
private_addresses.extend(
|
||||
[address["PrivateIpAddress"] for address in eni["PrivateIpAddresses"]]
|
||||
)
|
||||
error_msg = (
|
||||
"Nr of IP addresses for Subnet with CIDR {0} is incorrect. Expected: {1}, Actual: {2}. "
|
||||
"Addresses: {3}"
|
||||
)
|
||||
with sure.ensure(
|
||||
error_msg,
|
||||
cidr,
|
||||
str(expected_ip_address_count),
|
||||
updated_subnet["AvailableIpAddressCount"],
|
||||
str(private_addresses),
|
||||
):
|
||||
updated_subnet["AvailableIpAddressCount"].should.equal(
|
||||
expected_ip_address_count - ip_addresses_assigned
|
||||
)
|
||||
# Clean up, as we have to create a few more subnets that shouldn't interfere with each other
|
||||
for eni in enis_created:
|
||||
client.delete_network_interface(NetworkInterfaceId=eni["NetworkInterfaceId"])
|
||||
client.delete_subnet(SubnetId=subnet["SubnetId"])
|
||||
|
@ -1,6 +1,7 @@
|
||||
import random
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from moto.events import mock_events
|
||||
from botocore.exceptions import ClientError
|
||||
@ -204,6 +205,53 @@ def test_permissions():
|
||||
assert resp_policy["Statement"][0]["Sid"] == "Account1"
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_put_permission_errors():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
client.create_event_bus(Name="test-bus")
|
||||
|
||||
client.put_permission.when.called_with(
|
||||
EventBusName="non-existing",
|
||||
Action="events:PutEvents",
|
||||
Principal="111111111111",
|
||||
StatementId="test",
|
||||
).should.throw(ClientError, "Event bus non-existing does not exist.")
|
||||
|
||||
client.put_permission.when.called_with(
|
||||
EventBusName="test-bus",
|
||||
Action="events:PutPermission",
|
||||
Principal="111111111111",
|
||||
StatementId="test",
|
||||
).should.throw(
|
||||
ClientError, "Provided value in parameter 'action' is not supported."
|
||||
)
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_remove_permission_errors():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
client.create_event_bus(Name="test-bus")
|
||||
|
||||
client.remove_permission.when.called_with(
|
||||
EventBusName="non-existing", StatementId="test"
|
||||
).should.throw(ClientError, "Event bus non-existing does not exist.")
|
||||
|
||||
client.remove_permission.when.called_with(
|
||||
EventBusName="test-bus", StatementId="test"
|
||||
).should.throw(ClientError, "EventBus does not have a policy.")
|
||||
|
||||
client.put_permission(
|
||||
EventBusName="test-bus",
|
||||
Action="events:PutEvents",
|
||||
Principal="111111111111",
|
||||
StatementId="test",
|
||||
)
|
||||
|
||||
client.remove_permission.when.called_with(
|
||||
EventBusName="test-bus", StatementId="non-existing"
|
||||
).should.throw(ClientError, "Statement with the provided id does not exist.")
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_put_events():
|
||||
client = boto3.client("events", "eu-central-1")
|
||||
@ -220,3 +268,177 @@ def test_put_events():
|
||||
|
||||
with assert_raises(ClientError):
|
||||
client.put_events(Entries=[event] * 20)
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_create_event_bus():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
response = client.create_event_bus(Name="test-bus")
|
||||
|
||||
response["EventBusArn"].should.equal(
|
||||
"arn:aws:events:us-east-1:123456789012:event-bus/test-bus"
|
||||
)
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_create_event_bus_errors():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
client.create_event_bus(Name="test-bus")
|
||||
|
||||
client.create_event_bus.when.called_with(Name="test-bus").should.throw(
|
||||
ClientError, "Event bus test-bus already exists."
|
||||
)
|
||||
|
||||
# the 'default' name is already used for the account's default event bus.
|
||||
client.create_event_bus.when.called_with(Name="default").should.throw(
|
||||
ClientError, "Event bus default already exists."
|
||||
)
|
||||
|
||||
# non partner event buses can't contain the '/' character
|
||||
client.create_event_bus.when.called_with(Name="test/test-bus").should.throw(
|
||||
ClientError, "Event bus name must not contain '/'."
|
||||
)
|
||||
|
||||
client.create_event_bus.when.called_with(
|
||||
Name="aws.partner/test/test-bus", EventSourceName="aws.partner/test/test-bus"
|
||||
).should.throw(
|
||||
ClientError, "Event source aws.partner/test/test-bus does not exist."
|
||||
)
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_describe_event_bus():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
|
||||
response = client.describe_event_bus()
|
||||
|
||||
response["Name"].should.equal("default")
|
||||
response["Arn"].should.equal(
|
||||
"arn:aws:events:us-east-1:123456789012:event-bus/default"
|
||||
)
|
||||
response.should_not.have.key("Policy")
|
||||
|
||||
client.create_event_bus(Name="test-bus")
|
||||
client.put_permission(
|
||||
EventBusName="test-bus",
|
||||
Action="events:PutEvents",
|
||||
Principal="111111111111",
|
||||
StatementId="test",
|
||||
)
|
||||
|
||||
response = client.describe_event_bus(Name="test-bus")
|
||||
|
||||
response["Name"].should.equal("test-bus")
|
||||
response["Arn"].should.equal(
|
||||
"arn:aws:events:us-east-1:123456789012:event-bus/test-bus"
|
||||
)
|
||||
json.loads(response["Policy"]).should.equal(
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "test",
|
||||
"Effect": "Allow",
|
||||
"Principal": {"AWS": "arn:aws:iam::111111111111:root"},
|
||||
"Action": "events:PutEvents",
|
||||
"Resource": "arn:aws:events:us-east-1:123456789012:event-bus/test-bus",
|
||||
}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_describe_event_bus_errors():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
|
||||
client.describe_event_bus.when.called_with(Name="non-existing").should.throw(
|
||||
ClientError, "Event bus non-existing does not exist."
|
||||
)
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_list_event_buses():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
client.create_event_bus(Name="test-bus-1")
|
||||
client.create_event_bus(Name="test-bus-2")
|
||||
client.create_event_bus(Name="other-bus-1")
|
||||
client.create_event_bus(Name="other-bus-2")
|
||||
|
||||
response = client.list_event_buses()
|
||||
|
||||
response["EventBuses"].should.have.length_of(5)
|
||||
sorted(response["EventBuses"], key=lambda i: i["Name"]).should.equal(
|
||||
[
|
||||
{
|
||||
"Name": "default",
|
||||
"Arn": "arn:aws:events:us-east-1:123456789012:event-bus/default",
|
||||
},
|
||||
{
|
||||
"Name": "other-bus-1",
|
||||
"Arn": "arn:aws:events:us-east-1:123456789012:event-bus/other-bus-1",
|
||||
},
|
||||
{
|
||||
"Name": "other-bus-2",
|
||||
"Arn": "arn:aws:events:us-east-1:123456789012:event-bus/other-bus-2",
|
||||
},
|
||||
{
|
||||
"Name": "test-bus-1",
|
||||
"Arn": "arn:aws:events:us-east-1:123456789012:event-bus/test-bus-1",
|
||||
},
|
||||
{
|
||||
"Name": "test-bus-2",
|
||||
"Arn": "arn:aws:events:us-east-1:123456789012:event-bus/test-bus-2",
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
response = client.list_event_buses(NamePrefix="other-bus")
|
||||
|
||||
response["EventBuses"].should.have.length_of(2)
|
||||
sorted(response["EventBuses"], key=lambda i: i["Name"]).should.equal(
|
||||
[
|
||||
{
|
||||
"Name": "other-bus-1",
|
||||
"Arn": "arn:aws:events:us-east-1:123456789012:event-bus/other-bus-1",
|
||||
},
|
||||
{
|
||||
"Name": "other-bus-2",
|
||||
"Arn": "arn:aws:events:us-east-1:123456789012:event-bus/other-bus-2",
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_delete_event_bus():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
client.create_event_bus(Name="test-bus")
|
||||
|
||||
response = client.list_event_buses()
|
||||
response["EventBuses"].should.have.length_of(2)
|
||||
|
||||
client.delete_event_bus(Name="test-bus")
|
||||
|
||||
response = client.list_event_buses()
|
||||
response["EventBuses"].should.have.length_of(1)
|
||||
response["EventBuses"].should.equal(
|
||||
[
|
||||
{
|
||||
"Name": "default",
|
||||
"Arn": "arn:aws:events:us-east-1:123456789012:event-bus/default",
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
# deleting non existing event bus should be successful
|
||||
client.delete_event_bus(Name="non-existing")
|
||||
|
||||
|
||||
@mock_events
|
||||
def test_delete_event_bus_errors():
|
||||
client = boto3.client("events", "us-east-1")
|
||||
|
||||
client.delete_event_bus.when.called_with(Name="default").should.throw(
|
||||
ClientError, "Cannot delete event bus default."
|
||||
)
|
||||
|
@ -408,6 +408,21 @@ def test_create_policy():
|
||||
)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_create_policy_already_exists():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
response = conn.create_policy(
|
||||
PolicyName="TestCreatePolicy", PolicyDocument=MOCK_POLICY
|
||||
)
|
||||
with assert_raises(conn.exceptions.EntityAlreadyExistsException) as ex:
|
||||
response = conn.create_policy(
|
||||
PolicyName="TestCreatePolicy", PolicyDocument=MOCK_POLICY
|
||||
)
|
||||
ex.exception.response["Error"]["Code"].should.equal("EntityAlreadyExists")
|
||||
ex.exception.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(409)
|
||||
ex.exception.response["Error"]["Message"].should.contain("TestCreatePolicy")
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_delete_policy():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
|
@ -8,6 +8,7 @@ import sure # noqa
|
||||
|
||||
from nose.tools import assert_raises
|
||||
from boto.exception import BotoServerError
|
||||
from botocore.exceptions import ClientError
|
||||
from moto import mock_iam, mock_iam_deprecated
|
||||
|
||||
MOCK_POLICY = """
|
||||
@ -182,3 +183,25 @@ def test_list_group_policies():
|
||||
conn.list_group_policies(GroupName="my-group")["PolicyNames"].should.equal(
|
||||
["my-policy"]
|
||||
)
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_delete_group():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
conn.create_group(GroupName="my-group")
|
||||
groups = conn.list_groups()
|
||||
assert groups["Groups"][0]["GroupName"] == "my-group"
|
||||
assert len(groups["Groups"]) == 1
|
||||
conn.delete_group(GroupName="my-group")
|
||||
conn.list_groups()["Groups"].should.be.empty
|
||||
|
||||
|
||||
@mock_iam
|
||||
def test_delete_unknown_group():
|
||||
conn = boto3.client("iam", region_name="us-east-1")
|
||||
with assert_raises(ClientError) as err:
|
||||
conn.delete_group(GroupName="unknown-group")
|
||||
err.exception.response["Error"]["Code"].should.equal("NoSuchEntity")
|
||||
err.exception.response["Error"]["Message"].should.equal(
|
||||
"The group with name unknown-group cannot be found."
|
||||
)
|
||||
|
@ -159,6 +159,17 @@ def test_create_account():
|
||||
create_status["AccountName"].should.equal(mockname)
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_describe_create_account_status():
|
||||
client = boto3.client("organizations", region_name="us-east-1")
|
||||
client.create_organization(FeatureSet="ALL")["Organization"]
|
||||
request_id = client.create_account(AccountName=mockname, Email=mockemail)[
|
||||
"CreateAccountStatus"
|
||||
]["Id"]
|
||||
response = client.describe_create_account_status(CreateAccountRequestId=request_id)
|
||||
validate_create_account_status(response["CreateAccountStatus"])
|
||||
|
||||
|
||||
@mock_organizations
|
||||
def test_describe_account():
|
||||
client = boto3.client("organizations", region_name="us-east-1")
|
||||
|
@ -45,7 +45,7 @@ def test_get_secret_that_does_not_exist():
|
||||
result = conn.get_secret_value(SecretId="i-dont-exist")
|
||||
|
||||
assert_equal(
|
||||
"Secrets Manager can\u2019t find the specified secret.",
|
||||
"Secrets Manager can't find the specified secret.",
|
||||
cm.exception.response["Error"]["Message"],
|
||||
)
|
||||
|
||||
@ -61,7 +61,7 @@ def test_get_secret_that_does_not_match():
|
||||
result = conn.get_secret_value(SecretId="i-dont-match")
|
||||
|
||||
assert_equal(
|
||||
"Secrets Manager can\u2019t find the specified secret.",
|
||||
"Secrets Manager can't find the specified secret.",
|
||||
cm.exception.response["Error"]["Message"],
|
||||
)
|
||||
|
||||
@ -88,7 +88,7 @@ def test_get_secret_that_has_no_value():
|
||||
result = conn.get_secret_value(SecretId="java-util-test-password")
|
||||
|
||||
assert_equal(
|
||||
"Secrets Manager can\u2019t find the specified secret value for staging label: AWSCURRENT",
|
||||
"Secrets Manager can't find the specified secret value for staging label: AWSCURRENT",
|
||||
cm.exception.response["Error"]["Message"],
|
||||
)
|
||||
|
||||
|
@ -48,9 +48,7 @@ def test_get_secret_that_does_not_exist():
|
||||
headers={"X-Amz-Target": "secretsmanager.GetSecretValue"},
|
||||
)
|
||||
json_data = json.loads(get_secret.data.decode("utf-8"))
|
||||
assert (
|
||||
json_data["message"] == "Secrets Manager can\u2019t find the specified secret."
|
||||
)
|
||||
assert json_data["message"] == "Secrets Manager can't find the specified secret."
|
||||
assert json_data["__type"] == "ResourceNotFoundException"
|
||||
|
||||
|
||||
@ -70,9 +68,7 @@ def test_get_secret_that_does_not_match():
|
||||
headers={"X-Amz-Target": "secretsmanager.GetSecretValue"},
|
||||
)
|
||||
json_data = json.loads(get_secret.data.decode("utf-8"))
|
||||
assert (
|
||||
json_data["message"] == "Secrets Manager can\u2019t find the specified secret."
|
||||
)
|
||||
assert json_data["message"] == "Secrets Manager can't find the specified secret."
|
||||
assert json_data["__type"] == "ResourceNotFoundException"
|
||||
|
||||
|
||||
@ -95,7 +91,7 @@ def test_get_secret_that_has_no_value():
|
||||
json_data = json.loads(get_secret.data.decode("utf-8"))
|
||||
assert (
|
||||
json_data["message"]
|
||||
== "Secrets Manager can\u2019t find the specified secret value for staging label: AWSCURRENT"
|
||||
== "Secrets Manager can't find the specified secret value for staging label: AWSCURRENT"
|
||||
)
|
||||
assert json_data["__type"] == "ResourceNotFoundException"
|
||||
|
||||
@ -178,9 +174,7 @@ def test_describe_secret_that_does_not_exist():
|
||||
)
|
||||
|
||||
json_data = json.loads(describe_secret.data.decode("utf-8"))
|
||||
assert (
|
||||
json_data["message"] == "Secrets Manager can\u2019t find the specified secret."
|
||||
)
|
||||
assert json_data["message"] == "Secrets Manager can't find the specified secret."
|
||||
assert json_data["__type"] == "ResourceNotFoundException"
|
||||
|
||||
|
||||
@ -202,9 +196,7 @@ def test_describe_secret_that_does_not_match():
|
||||
)
|
||||
|
||||
json_data = json.loads(describe_secret.data.decode("utf-8"))
|
||||
assert (
|
||||
json_data["message"] == "Secrets Manager can\u2019t find the specified secret."
|
||||
)
|
||||
assert json_data["message"] == "Secrets Manager can't find the specified secret."
|
||||
assert json_data["__type"] == "ResourceNotFoundException"
|
||||
|
||||
|
||||
@ -306,9 +298,7 @@ def test_rotate_secret_that_does_not_exist():
|
||||
)
|
||||
|
||||
json_data = json.loads(rotate_secret.data.decode("utf-8"))
|
||||
assert (
|
||||
json_data["message"] == "Secrets Manager can\u2019t find the specified secret."
|
||||
)
|
||||
assert json_data["message"] == "Secrets Manager can't find the specified secret."
|
||||
assert json_data["__type"] == "ResourceNotFoundException"
|
||||
|
||||
|
||||
@ -330,9 +320,7 @@ def test_rotate_secret_that_does_not_match():
|
||||
)
|
||||
|
||||
json_data = json.loads(rotate_secret.data.decode("utf-8"))
|
||||
assert (
|
||||
json_data["message"] == "Secrets Manager can\u2019t find the specified secret."
|
||||
)
|
||||
assert json_data["message"] == "Secrets Manager can't find the specified secret."
|
||||
assert json_data["__type"] == "ResourceNotFoundException"
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user