commit
34911b7c8b
@ -121,6 +121,7 @@ class TaskDefinition(BaseObject):
|
||||
network_mode=None,
|
||||
volumes=None,
|
||||
tags=None,
|
||||
placement_constraints=None,
|
||||
):
|
||||
self.family = family
|
||||
self.revision = revision
|
||||
@ -137,6 +138,9 @@ class TaskDefinition(BaseObject):
|
||||
self.network_mode = "bridge"
|
||||
else:
|
||||
self.network_mode = network_mode
|
||||
self.placement_constraints = (
|
||||
placement_constraints if placement_constraints is not None else []
|
||||
)
|
||||
|
||||
@property
|
||||
def response_object(self):
|
||||
@ -558,7 +562,13 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
||||
|
||||
def register_task_definition(
|
||||
self, family, container_definitions, volumes=None, network_mode=None, tags=None
|
||||
self,
|
||||
family,
|
||||
container_definitions,
|
||||
volumes=None,
|
||||
network_mode=None,
|
||||
tags=None,
|
||||
placement_constraints=None,
|
||||
):
|
||||
if family in self.task_definitions:
|
||||
last_id = self._get_last_task_definition_revision_id(family)
|
||||
@ -574,6 +584,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
volumes=volumes,
|
||||
network_mode=network_mode,
|
||||
tags=tags,
|
||||
placement_constraints=placement_constraints,
|
||||
)
|
||||
self.task_definitions[family][revision] = task_definition
|
||||
|
||||
|
@ -63,12 +63,14 @@ class EC2ContainerServiceResponse(BaseResponse):
|
||||
volumes = self._get_param("volumes")
|
||||
tags = self._get_param("tags")
|
||||
network_mode = self._get_param("networkMode")
|
||||
placement_constraints = self._get_param("placementConstraints")
|
||||
task_definition = self.ecs_backend.register_task_definition(
|
||||
family,
|
||||
container_definitions,
|
||||
volumes=volumes,
|
||||
network_mode=network_mode,
|
||||
tags=tags,
|
||||
placement_constraints=placement_constraints,
|
||||
)
|
||||
return json.dumps({"taskDefinition": task_definition.response_object})
|
||||
|
||||
|
@ -137,8 +137,13 @@ def parse_key_name(pth):
|
||||
|
||||
|
||||
def is_delete_keys(request, path, bucket_name):
|
||||
return path == "/?delete" or (
|
||||
path == "/" and getattr(request, "query_string", "") == "delete"
|
||||
# GOlang sends a request as url/?delete= (treating it as a normal key=value, even if the value is empty)
|
||||
# Python sends a request as url/?delete (treating it as a flag)
|
||||
# https://github.com/spulec/moto/issues/2937
|
||||
return (
|
||||
path == "/?delete"
|
||||
or path == "/?delete="
|
||||
or (path == "/" and getattr(request, "query_string", "") == "delete")
|
||||
)
|
||||
|
||||
|
||||
|
@ -230,7 +230,7 @@ class Queue(BaseModel):
|
||||
"FifoQueue": "false",
|
||||
"KmsDataKeyReusePeriodSeconds": 300, # five minutes
|
||||
"KmsMasterKeyId": None,
|
||||
"MaximumMessageSize": int(64 << 10),
|
||||
"MaximumMessageSize": int(64 << 12),
|
||||
"MessageRetentionPeriod": 86400 * 4, # four days
|
||||
"Policy": None,
|
||||
"ReceiveMessageWaitTimeSeconds": 0,
|
||||
|
@ -285,6 +285,9 @@ class SQSResponse(BaseResponse):
|
||||
"MessageAttributes": message_attributes,
|
||||
}
|
||||
|
||||
if entries == {}:
|
||||
raise EmptyBatchRequest()
|
||||
|
||||
messages = self.sqs_backend.send_message_batch(queue_name, entries)
|
||||
|
||||
template = self.response_template(SEND_MESSAGE_BATCH_RESPONSE)
|
||||
|
@ -4946,3 +4946,86 @@ def test_multiple_updates():
|
||||
"id": {"S": "1"},
|
||||
}
|
||||
assert result == expected_result
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_update_item_atomic_counter():
|
||||
table = "table_t"
|
||||
ddb_mock = boto3.client("dynamodb", region_name="eu-west-3")
|
||||
ddb_mock.create_table(
|
||||
TableName=table,
|
||||
KeySchema=[{"AttributeName": "t_id", "KeyType": "HASH"}],
|
||||
AttributeDefinitions=[{"AttributeName": "t_id", "AttributeType": "S"}],
|
||||
BillingMode="PAY_PER_REQUEST",
|
||||
)
|
||||
|
||||
key = {"t_id": {"S": "item1"}}
|
||||
|
||||
ddb_mock.put_item(
|
||||
TableName=table,
|
||||
Item={"t_id": {"S": "item1"}, "n_i": {"N": "5"}, "n_f": {"N": "5.3"}},
|
||||
)
|
||||
|
||||
ddb_mock.update_item(
|
||||
TableName=table,
|
||||
Key=key,
|
||||
UpdateExpression="set n_i = n_i + :inc1, n_f = n_f + :inc2",
|
||||
ExpressionAttributeValues={":inc1": {"N": "1.2"}, ":inc2": {"N": "0.05"}},
|
||||
)
|
||||
updated_item = ddb_mock.get_item(TableName=table, Key=key)["Item"]
|
||||
updated_item["n_i"]["N"].should.equal("6.2")
|
||||
updated_item["n_f"]["N"].should.equal("5.35")
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
def test_update_item_atomic_counter_return_values():
|
||||
table = "table_t"
|
||||
ddb_mock = boto3.client("dynamodb", region_name="eu-west-3")
|
||||
ddb_mock.create_table(
|
||||
TableName=table,
|
||||
KeySchema=[{"AttributeName": "t_id", "KeyType": "HASH"}],
|
||||
AttributeDefinitions=[{"AttributeName": "t_id", "AttributeType": "S"}],
|
||||
BillingMode="PAY_PER_REQUEST",
|
||||
)
|
||||
|
||||
key = {"t_id": {"S": "item1"}}
|
||||
|
||||
ddb_mock.put_item(TableName=table, Item={"t_id": {"S": "item1"}, "v": {"N": "5"}})
|
||||
|
||||
response = ddb_mock.update_item(
|
||||
TableName=table,
|
||||
Key=key,
|
||||
UpdateExpression="set v = v + :inc",
|
||||
ExpressionAttributeValues={":inc": {"N": "1"}},
|
||||
ReturnValues="UPDATED_OLD",
|
||||
)
|
||||
assert (
|
||||
"v" in response["Attributes"]
|
||||
), "v has been updated, and should be returned here"
|
||||
response["Attributes"]["v"]["N"].should.equal("5")
|
||||
|
||||
# second update
|
||||
response = ddb_mock.update_item(
|
||||
TableName=table,
|
||||
Key=key,
|
||||
UpdateExpression="set v = v + :inc",
|
||||
ExpressionAttributeValues={":inc": {"N": "1"}},
|
||||
ReturnValues="UPDATED_OLD",
|
||||
)
|
||||
assert (
|
||||
"v" in response["Attributes"]
|
||||
), "v has been updated, and should be returned here"
|
||||
response["Attributes"]["v"]["N"].should.equal("6")
|
||||
|
||||
# third update
|
||||
response = ddb_mock.update_item(
|
||||
TableName=table,
|
||||
Key=key,
|
||||
UpdateExpression="set v = v + :inc",
|
||||
ExpressionAttributeValues={":inc": {"N": "1"}},
|
||||
ReturnValues="UPDATED_NEW",
|
||||
)
|
||||
assert (
|
||||
"v" in response["Attributes"]
|
||||
), "v has been updated, and should be returned here"
|
||||
response["Attributes"]["v"]["N"].should.equal("8")
|
||||
|
@ -2604,3 +2604,36 @@ def test_ecs_service_untag_resource_multiple_tags():
|
||||
resourceArn=response["service"]["serviceArn"]
|
||||
)
|
||||
response["tags"].should.equal([{"key": "hello", "value": "world"}])
|
||||
|
||||
|
||||
@mock_ecs
|
||||
def test_ecs_task_definition_placement_constraints():
|
||||
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"},
|
||||
}
|
||||
],
|
||||
networkMode="bridge",
|
||||
tags=[
|
||||
{"key": "createdBy", "value": "moto-unittest"},
|
||||
{"key": "foo", "value": "bar"},
|
||||
],
|
||||
placementConstraints=[
|
||||
{"type": "memberOf", "expression": "attribute:ecs.instance-type =~ t2.*"}
|
||||
],
|
||||
)
|
||||
type(response["taskDefinition"]["placementConstraints"]).should.be(list)
|
||||
response["taskDefinition"]["placementConstraints"].should.equal(
|
||||
[{"type": "memberOf", "expression": "attribute:ecs.instance-type =~ t2.*"}]
|
||||
)
|
||||
|
@ -3765,7 +3765,7 @@ def test_paths_with_leading_slashes_work():
|
||||
|
||||
@mock_s3
|
||||
def test_root_dir_with_empty_name_works():
|
||||
if os.environ.get("TEST_SERVER_MODE", "false").lower() == "true":
|
||||
if settings.TEST_SERVER_MODE:
|
||||
raise SkipTest("Does not work in server mode due to error in Workzeug")
|
||||
store_and_read_back_a_key("/")
|
||||
|
||||
|
@ -384,7 +384,7 @@ def test_get_queue_attributes():
|
||||
response["Attributes"]["CreatedTimestamp"].should.be.a(six.string_types)
|
||||
response["Attributes"]["DelaySeconds"].should.equal("0")
|
||||
response["Attributes"]["LastModifiedTimestamp"].should.be.a(six.string_types)
|
||||
response["Attributes"]["MaximumMessageSize"].should.equal("65536")
|
||||
response["Attributes"]["MaximumMessageSize"].should.equal("262144")
|
||||
response["Attributes"]["MessageRetentionPeriod"].should.equal("345600")
|
||||
response["Attributes"]["QueueArn"].should.equal(
|
||||
"arn:aws:sqs:us-east-1:{}:test-queue".format(ACCOUNT_ID)
|
||||
@ -406,7 +406,7 @@ def test_get_queue_attributes():
|
||||
response["Attributes"].should.equal(
|
||||
{
|
||||
"ApproximateNumberOfMessages": "0",
|
||||
"MaximumMessageSize": "65536",
|
||||
"MaximumMessageSize": "262144",
|
||||
"QueueArn": "arn:aws:sqs:us-east-1:{}:test-queue".format(ACCOUNT_ID),
|
||||
"VisibilityTimeout": "30",
|
||||
"RedrivePolicy": json.dumps(
|
||||
@ -1147,6 +1147,21 @@ def test_send_message_batch_errors():
|
||||
)
|
||||
|
||||
|
||||
@mock_sqs
|
||||
def test_send_message_batch_with_empty_list():
|
||||
client = boto3.client("sqs", region_name="us-east-1")
|
||||
|
||||
response = client.create_queue(QueueName="test-queue")
|
||||
queue_url = response["QueueUrl"]
|
||||
|
||||
client.send_message_batch.when.called_with(
|
||||
QueueUrl=queue_url, Entries=[]
|
||||
).should.throw(
|
||||
ClientError,
|
||||
"There should be at least one SendMessageBatchRequestEntry in the request.",
|
||||
)
|
||||
|
||||
|
||||
@mock_sqs
|
||||
def test_batch_change_message_visibility():
|
||||
if os.environ.get("TEST_SERVER_MODE", "false").lower() == "true":
|
||||
|
Loading…
Reference in New Issue
Block a user