Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Stephan Huber 2020-01-23 15:37:40 +01:00
commit 84210f6011
78 changed files with 1510 additions and 618 deletions

View file

@ -706,14 +706,14 @@ def test_create_autoscaling_group_boto3():
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "propogated-tag-key",
"Value": "propogate-tag-value",
"Value": "propagate-tag-value",
"PropagateAtLaunch": True,
},
{
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "not-propogated-tag-key",
"Value": "not-propogate-tag-value",
"Value": "not-propagate-tag-value",
"PropagateAtLaunch": False,
},
],
@ -744,14 +744,14 @@ def test_create_autoscaling_group_from_instance():
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "propogated-tag-key",
"Value": "propogate-tag-value",
"Value": "propagate-tag-value",
"PropagateAtLaunch": True,
},
{
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "not-propogated-tag-key",
"Value": "not-propogate-tag-value",
"Value": "not-propagate-tag-value",
"PropagateAtLaunch": False,
},
],
@ -1062,7 +1062,7 @@ def test_detach_one_instance_decrement():
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "propogated-tag-key",
"Value": "propogate-tag-value",
"Value": "propagate-tag-value",
"PropagateAtLaunch": True,
}
],
@ -1116,7 +1116,7 @@ def test_detach_one_instance():
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "propogated-tag-key",
"Value": "propogate-tag-value",
"Value": "propagate-tag-value",
"PropagateAtLaunch": True,
}
],
@ -1169,7 +1169,7 @@ def test_attach_one_instance():
"ResourceId": "test_asg",
"ResourceType": "auto-scaling-group",
"Key": "propogated-tag-key",
"Value": "propogate-tag-value",
"Value": "propagate-tag-value",
"PropagateAtLaunch": True,
}
],

View file

@ -58,8 +58,7 @@ def lambda_handler(event, context):
volume_id = event.get('volume_id')
vol = ec2.Volume(volume_id)
print('get volume details for %s\\nVolume - %s state=%s, size=%s' % (volume_id, volume_id, vol.state, vol.size))
return event
return {{'id': vol.id, 'state': vol.state, 'size': vol.size}}
""".format(
base_url="motoserver:5000"
if settings.TEST_SERVER_MODE
@ -181,27 +180,9 @@ if settings.TEST_SERVER_MODE:
Payload=json.dumps(in_data),
)
result["StatusCode"].should.equal(202)
msg = "get volume details for %s\nVolume - %s state=%s, size=%s\n%s" % (
vol.id,
vol.id,
vol.state,
vol.size,
json.dumps(in_data).replace(
" ", ""
), # Makes the tests pass as the result is missing the whitespace
)
log_result = base64.b64decode(result["LogResult"]).decode("utf-8")
# The Docker lambda invocation will return an additional '\n', so need to replace it:
log_result = log_result.replace("\n\n", "\n")
log_result.should.equal(msg)
payload = result["Payload"].read().decode("utf-8")
# The Docker lambda invocation will return an additional '\n', so need to replace it:
payload = payload.replace("\n\n", "\n")
payload.should.equal(msg)
actual_payload = json.loads(result["Payload"].read().decode("utf-8"))
expected_payload = {"id": vol.id, "state": vol.state, "size": vol.size}
actual_payload.should.equal(expected_payload)
@mock_logs

View file

@ -0,0 +1,222 @@
import boto3
import sure # noqa
from moto import mock_codecommit
from moto.iam.models import ACCOUNT_ID
from botocore.exceptions import ClientError
from nose.tools import assert_raises
@mock_codecommit
def test_create_repository():
client = boto3.client("codecommit", region_name="eu-central-1")
response = client.create_repository(
repositoryName="repository_one", repositoryDescription="description repo one"
)
response.should_not.be.none
response["repositoryMetadata"].should_not.be.none
response["repositoryMetadata"]["creationDate"].should_not.be.none
response["repositoryMetadata"]["lastModifiedDate"].should_not.be.none
response["repositoryMetadata"]["repositoryId"].should_not.be.empty
response["repositoryMetadata"]["repositoryName"].should.equal("repository_one")
response["repositoryMetadata"]["repositoryDescription"].should.equal(
"description repo one"
)
response["repositoryMetadata"]["cloneUrlSsh"].should.equal(
"ssh://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
"eu-central-1", "repository_one"
)
)
response["repositoryMetadata"]["cloneUrlHttp"].should.equal(
"https://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
"eu-central-1", "repository_one"
)
)
response["repositoryMetadata"]["Arn"].should.equal(
"arn:aws:codecommit:{0}:{1}:{2}".format(
"eu-central-1", ACCOUNT_ID, "repository_one"
)
)
response["repositoryMetadata"]["accountId"].should.equal(ACCOUNT_ID)
@mock_codecommit
def test_create_repository_without_description():
client = boto3.client("codecommit", region_name="eu-central-1")
response = client.create_repository(repositoryName="repository_two")
response.should_not.be.none
response.get("repositoryMetadata").should_not.be.none
response.get("repositoryMetadata").get("repositoryName").should.equal(
"repository_two"
)
response.get("repositoryMetadata").get("repositoryDescription").should.be.none
response["repositoryMetadata"].should_not.be.none
response["repositoryMetadata"]["creationDate"].should_not.be.none
response["repositoryMetadata"]["lastModifiedDate"].should_not.be.none
response["repositoryMetadata"]["repositoryId"].should_not.be.empty
response["repositoryMetadata"]["cloneUrlSsh"].should.equal(
"ssh://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
"eu-central-1", "repository_two"
)
)
response["repositoryMetadata"]["cloneUrlHttp"].should.equal(
"https://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
"eu-central-1", "repository_two"
)
)
response["repositoryMetadata"]["Arn"].should.equal(
"arn:aws:codecommit:{0}:{1}:{2}".format(
"eu-central-1", ACCOUNT_ID, "repository_two"
)
)
response["repositoryMetadata"]["accountId"].should.equal(ACCOUNT_ID)
@mock_codecommit
def test_create_repository_repository_name_exists():
client = boto3.client("codecommit", region_name="eu-central-1")
client.create_repository(repositoryName="repository_two")
with assert_raises(ClientError) as e:
client.create_repository(
repositoryName="repository_two",
repositoryDescription="description repo two",
)
ex = e.exception
ex.operation_name.should.equal("CreateRepository")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("RepositoryNameExistsException")
ex.response["Error"]["Message"].should.equal(
"Repository named {0} already exists".format("repository_two")
)
@mock_codecommit
def test_create_repository_invalid_repository_name():
client = boto3.client("codecommit", region_name="eu-central-1")
with assert_raises(ClientError) as e:
client.create_repository(repositoryName="in_123_valid_@#$_characters")
ex = e.exception
ex.operation_name.should.equal("CreateRepository")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("InvalidRepositoryNameException")
ex.response["Error"]["Message"].should.equal(
"The repository name is not valid. Repository names can be any valid "
"combination of letters, numbers, "
"periods, underscores, and dashes between 1 and 100 characters in "
"length. Names are case sensitive. "
"For more information, see Limits in the AWS CodeCommit User Guide. "
)
@mock_codecommit
def test_get_repository():
client = boto3.client("codecommit", region_name="eu-central-1")
repository_name = "repository_one"
client.create_repository(
repositoryName=repository_name, repositoryDescription="description repo one"
)
response = client.get_repository(repositoryName=repository_name)
response.should_not.be.none
response.get("repositoryMetadata").should_not.be.none
response.get("repositoryMetadata").get("creationDate").should_not.be.none
response.get("repositoryMetadata").get("lastModifiedDate").should_not.be.none
response.get("repositoryMetadata").get("repositoryId").should_not.be.empty
response.get("repositoryMetadata").get("repositoryName").should.equal(
repository_name
)
response.get("repositoryMetadata").get("repositoryDescription").should.equal(
"description repo one"
)
response.get("repositoryMetadata").get("cloneUrlSsh").should.equal(
"ssh://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
"eu-central-1", "repository_one"
)
)
response.get("repositoryMetadata").get("cloneUrlHttp").should.equal(
"https://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
"eu-central-1", "repository_one"
)
)
response.get("repositoryMetadata").get("Arn").should.equal(
"arn:aws:codecommit:{0}:{1}:{2}".format(
"eu-central-1", ACCOUNT_ID, "repository_one"
)
)
response.get("repositoryMetadata").get("accountId").should.equal(ACCOUNT_ID)
client = boto3.client("codecommit", region_name="us-east-1")
with assert_raises(ClientError) as e:
client.get_repository(repositoryName=repository_name)
ex = e.exception
ex.operation_name.should.equal("GetRepository")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("RepositoryDoesNotExistException")
ex.response["Error"]["Message"].should.equal(
"{0} does not exist".format(repository_name)
)
@mock_codecommit
def test_get_repository_invalid_repository_name():
client = boto3.client("codecommit", region_name="eu-central-1")
with assert_raises(ClientError) as e:
client.get_repository(repositoryName="repository_one-@#@")
ex = e.exception
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("InvalidRepositoryNameException")
ex.response["Error"]["Message"].should.equal(
"The repository name is not valid. Repository names can be any valid "
"combination of letters, numbers, "
"periods, underscores, and dashes between 1 and 100 characters in "
"length. Names are case sensitive. "
"For more information, see Limits in the AWS CodeCommit User Guide. "
)
@mock_codecommit
def test_delete_repository():
client = boto3.client("codecommit", region_name="us-east-1")
response = client.create_repository(repositoryName="repository_one")
repository_id_create = response.get("repositoryMetadata").get("repositoryId")
response = client.delete_repository(repositoryName="repository_one")
response.get("repositoryId").should_not.be.none
repository_id_create.should.equal(response.get("repositoryId"))
response = client.delete_repository(repositoryName="unknown_repository")
response.get("repositoryId").should.be.none
@mock_codecommit
def test_delete_repository_invalid_repository_name():
client = boto3.client("codecommit", region_name="us-east-1")
with assert_raises(ClientError) as e:
client.delete_repository(repositoryName="_rep@ository_one")
ex = e.exception
ex.operation_name.should.equal("DeleteRepository")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("InvalidRepositoryNameException")
ex.response["Error"]["Message"].should.equal(
"The repository name is not valid. Repository names can be any valid "
"combination of letters, numbers, "
"periods, underscores, and dashes between 1 and 100 characters in "
"length. Names are case sensitive. "
"For more information, see Limits in the AWS CodeCommit User Guide. "
)

View file

@ -13,52 +13,7 @@ from moto import mock_codepipeline, mock_iam
def test_create_pipeline():
client = boto3.client("codepipeline", region_name="us-east-1")
response = client.create_pipeline(
pipeline={
"name": "test-pipeline",
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
},
tags=[{"key": "key", "value": "value"}],
)
response = create_basic_codepipeline(client, "test-pipeline")
response["pipeline"].should.equal(
{
@ -120,98 +75,10 @@ def test_create_pipeline():
def test_create_pipeline_errors():
client = boto3.client("codepipeline", region_name="us-east-1")
client_iam = boto3.client("iam", region_name="us-east-1")
client.create_pipeline(
pipeline={
"name": "test-pipeline",
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
}
)
create_basic_codepipeline(client, "test-pipeline")
with assert_raises(ClientError) as e:
client.create_pipeline(
pipeline={
"name": "test-pipeline",
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
}
)
create_basic_codepipeline(client, "test-pipeline")
ex = e.exception
ex.operation_name.should.equal("CreatePipeline")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
@ -348,52 +215,7 @@ def test_create_pipeline_errors():
@mock_codepipeline
def test_get_pipeline():
client = boto3.client("codepipeline", region_name="us-east-1")
client.create_pipeline(
pipeline={
"name": "test-pipeline",
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
},
tags=[{"key": "key", "value": "value"}],
)
create_basic_codepipeline(client, "test-pipeline")
response = client.get_pipeline(name="test-pipeline")
@ -474,53 +296,7 @@ def test_get_pipeline_errors():
@mock_codepipeline
def test_update_pipeline():
client = boto3.client("codepipeline", region_name="us-east-1")
role_arn = get_role_arn()
client.create_pipeline(
pipeline={
"name": "test-pipeline",
"roleArn": role_arn,
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
},
tags=[{"key": "key", "value": "value"}],
)
create_basic_codepipeline(client, "test-pipeline")
response = client.get_pipeline(name="test-pipeline")
created_time = response["metadata"]["created"]
@ -529,7 +305,7 @@ def test_update_pipeline():
response = client.update_pipeline(
pipeline={
"name": "test-pipeline",
"roleArn": role_arn,
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
@ -692,105 +468,19 @@ def test_update_pipeline_errors():
@mock_codepipeline
def test_list_pipelines():
client = boto3.client("codepipeline", region_name="us-east-1")
client.create_pipeline(
pipeline={
"name": "test-pipeline-1",
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
},
)
client.create_pipeline(
pipeline={
"name": "test-pipeline-2",
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
},
)
name_1 = "test-pipeline-1"
create_basic_codepipeline(client, name_1)
name_2 = "test-pipeline-2"
create_basic_codepipeline(client, name_2)
response = client.list_pipelines()
response["pipelines"].should.have.length_of(2)
response["pipelines"][0]["name"].should.equal("test-pipeline-1")
response["pipelines"][0]["name"].should.equal(name_1)
response["pipelines"][0]["version"].should.equal(1)
response["pipelines"][0]["created"].should.be.a(datetime)
response["pipelines"][0]["updated"].should.be.a(datetime)
response["pipelines"][1]["name"].should.equal("test-pipeline-2")
response["pipelines"][1]["name"].should.equal(name_2)
response["pipelines"][1]["version"].should.equal(1)
response["pipelines"][1]["created"].should.be.a(datetime)
response["pipelines"][1]["updated"].should.be.a(datetime)
@ -799,68 +489,172 @@ def test_list_pipelines():
@mock_codepipeline
def test_delete_pipeline():
client = boto3.client("codepipeline", region_name="us-east-1")
client.create_pipeline(
pipeline={
"name": "test-pipeline",
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
},
)
name = "test-pipeline"
create_basic_codepipeline(client, name)
client.list_pipelines()["pipelines"].should.have.length_of(1)
client.delete_pipeline(name="test-pipeline")
client.delete_pipeline(name=name)
client.list_pipelines()["pipelines"].should.have.length_of(0)
# deleting a not existing pipeline, should raise no exception
client.delete_pipeline(name="test-pipeline")
client.delete_pipeline(name=name)
@mock_codepipeline
def test_list_tags_for_resource():
client = boto3.client("codepipeline", region_name="us-east-1")
name = "test-pipeline"
create_basic_codepipeline(client, name)
response = client.list_tags_for_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name)
)
response["tags"].should.equal([{"key": "key", "value": "value"}])
@mock_codepipeline
def test_list_tags_for_resource_errors():
client = boto3.client("codepipeline", region_name="us-east-1")
with assert_raises(ClientError) as e:
client.list_tags_for_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:not-existing"
)
ex = e.exception
ex.operation_name.should.equal("ListTagsForResource")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("ResourceNotFoundException")
ex.response["Error"]["Message"].should.equal(
"The account with id '123456789012' does not include a pipeline with the name 'not-existing'"
)
@mock_codepipeline
def test_tag_resource():
client = boto3.client("codepipeline", region_name="us-east-1")
name = "test-pipeline"
create_basic_codepipeline(client, name)
client.tag_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name),
tags=[{"key": "key-2", "value": "value-2"}],
)
response = client.list_tags_for_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name)
)
response["tags"].should.equal(
[{"key": "key", "value": "value"}, {"key": "key-2", "value": "value-2"}]
)
@mock_codepipeline
def test_tag_resource_errors():
client = boto3.client("codepipeline", region_name="us-east-1")
name = "test-pipeline"
create_basic_codepipeline(client, name)
with assert_raises(ClientError) as e:
client.tag_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:not-existing",
tags=[{"key": "key-2", "value": "value-2"}],
)
ex = e.exception
ex.operation_name.should.equal("TagResource")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("ResourceNotFoundException")
ex.response["Error"]["Message"].should.equal(
"The account with id '123456789012' does not include a pipeline with the name 'not-existing'"
)
with assert_raises(ClientError) as e:
client.tag_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name),
tags=[{"key": "aws:key", "value": "value"}],
)
ex = e.exception
ex.operation_name.should.equal("TagResource")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("InvalidTagsException")
ex.response["Error"]["Message"].should.equal(
"Not allowed to modify system tags. "
"System tags start with 'aws:'. "
"msg=[Caller is an end user and not allowed to mutate system tags]"
)
with assert_raises(ClientError) as e:
client.tag_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name),
tags=[
{"key": "key-{}".format(i), "value": "value-{}".format(i)}
for i in range(50)
],
)
ex = e.exception
ex.operation_name.should.equal("TagResource")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("TooManyTagsException")
ex.response["Error"]["Message"].should.equal(
"Tag limit exceeded for resource [arn:aws:codepipeline:us-east-1:123456789012:{}].".format(
name
)
)
@mock_codepipeline
def test_untag_resource():
client = boto3.client("codepipeline", region_name="us-east-1")
name = "test-pipeline"
create_basic_codepipeline(client, name)
response = client.list_tags_for_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name)
)
response["tags"].should.equal([{"key": "key", "value": "value"}])
client.untag_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name),
tagKeys=["key"],
)
response = client.list_tags_for_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name)
)
response["tags"].should.have.length_of(0)
# removing a not existing tag should raise no exception
client.untag_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:{}".format(name),
tagKeys=["key"],
)
@mock_codepipeline
def test_untag_resource_errors():
client = boto3.client("codepipeline", region_name="us-east-1")
with assert_raises(ClientError) as e:
client.untag_resource(
resourceArn="arn:aws:codepipeline:us-east-1:123456789012:not-existing",
tagKeys=["key"],
)
ex = e.exception
ex.operation_name.should.equal("UntagResource")
ex.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
ex.response["Error"]["Code"].should.contain("ResourceNotFoundException")
ex.response["Error"]["Message"].should.equal(
"The account with id '123456789012' does not include a pipeline with the name 'not-existing'"
)
@mock_iam
def get_role_arn():
iam = boto3.client("iam", region_name="us-east-1")
client = boto3.client("iam", region_name="us-east-1")
try:
return iam.get_role(RoleName="test-role")["Role"]["Arn"]
return client.get_role(RoleName="test-role")["Role"]["Arn"]
except ClientError:
return iam.create_role(
return client.create_role(
RoleName="test-role",
AssumeRolePolicyDocument=json.dumps(
{
@ -875,3 +669,52 @@ def get_role_arn():
}
),
)["Role"]["Arn"]
def create_basic_codepipeline(client, name):
return client.create_pipeline(
pipeline={
"name": name,
"roleArn": get_role_arn(),
"artifactStore": {
"type": "S3",
"location": "codepipeline-us-east-1-123456789012",
},
"stages": [
{
"name": "Stage-1",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "S3",
"version": "1",
},
"configuration": {
"S3Bucket": "test-bucket",
"S3ObjectKey": "test-object",
},
"outputArtifacts": [{"name": "artifact"},],
},
],
},
{
"name": "Stage-2",
"actions": [
{
"name": "Action-1",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1",
},
},
],
},
],
},
tags=[{"key": "key", "value": "value"}],
)

View file

@ -1142,11 +1142,13 @@ def test_token_legitimacy():
id_claims = json.loads(jws.verify(id_token, json_web_key, "RS256"))
id_claims["iss"].should.equal(issuer)
id_claims["aud"].should.equal(client_id)
id_claims["token_use"].should.equal("id")
for k, v in outputs["additional_fields"].items():
id_claims[k].should.equal(v)
access_claims = json.loads(jws.verify(access_token, json_web_key, "RS256"))
access_claims["iss"].should.equal(issuer)
access_claims["aud"].should.equal(client_id)
for k, v in outputs["additional_fields"].items():
access_claims[k].should.equal(v)
access_claims["token_use"].should.equal("access")
@mock_cognitoidp

View file

@ -9,7 +9,7 @@ from boto3.dynamodb.conditions import Attr, Key
import sure # noqa
import requests
from moto import mock_dynamodb2, mock_dynamodb2_deprecated
from moto.dynamodb2 import dynamodb_backend2
from moto.dynamodb2 import dynamodb_backend2, dynamodb_backends2
from boto.exception import JSONResponseError
from botocore.exceptions import ClientError, ParamValidationError
from tests.helpers import requires_boto_gte
@ -350,6 +350,60 @@ def test_put_item_with_special_chars():
)
@requires_boto_gte("2.9")
@mock_dynamodb2
def test_put_item_with_streams():
name = "TestTable"
conn = boto3.client(
"dynamodb",
region_name="us-west-2",
aws_access_key_id="ak",
aws_secret_access_key="sk",
)
conn.create_table(
TableName=name,
KeySchema=[{"AttributeName": "forum_name", "KeyType": "HASH"}],
AttributeDefinitions=[{"AttributeName": "forum_name", "AttributeType": "S"}],
StreamSpecification={
"StreamEnabled": True,
"StreamViewType": "NEW_AND_OLD_IMAGES",
},
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
)
conn.put_item(
TableName=name,
Item={
"forum_name": {"S": "LOLCat Forum"},
"subject": {"S": "Check this out!"},
"Body": {"S": "http://url_to_lolcat.gif"},
"SentBy": {"S": "test"},
"Data": {"M": {"Key1": {"S": "Value1"}, "Key2": {"S": "Value2"}}},
},
)
result = conn.get_item(TableName=name, Key={"forum_name": {"S": "LOLCat Forum"}})
result["Item"].should.be.equal(
{
"forum_name": {"S": "LOLCat Forum"},
"subject": {"S": "Check this out!"},
"Body": {"S": "http://url_to_lolcat.gif"},
"SentBy": {"S": "test"},
"Data": {"M": {"Key1": {"S": "Value1"}, "Key2": {"S": "Value2"}}},
}
)
table = dynamodb_backends2["us-west-2"].get_table(name)
if not table:
# There is no way to access stream data over the API, so this part can't run in server-tests mode.
return
len(table.stream_shard.items).should.be.equal(1)
stream_record = table.stream_shard.items[0].record
stream_record["eventName"].should.be.equal("INSERT")
stream_record["dynamodb"]["SizeBytes"].should.be.equal(447)
@requires_boto_gte("2.9")
@mock_dynamodb2
def test_query_returns_consumed_capacity():
@ -1665,6 +1719,32 @@ def test_scan_filter4():
assert response["Count"] == 0
@mock_dynamodb2
def test_scan_filter_should_not_return_non_existing_attributes():
table_name = "my-table"
item = {"partitionKey": "pk-2", "my-attr": 42}
# Create table
res = boto3.resource("dynamodb", region_name="us-east-1")
res.create_table(
TableName=table_name,
KeySchema=[{"AttributeName": "partitionKey", "KeyType": "HASH"}],
AttributeDefinitions=[{"AttributeName": "partitionKey", "AttributeType": "S"}],
BillingMode="PAY_PER_REQUEST",
)
table = res.Table(table_name)
# Insert items
table.put_item(Item={"partitionKey": "pk-1"})
table.put_item(Item=item)
# Verify a few operations
# Assert we only find the item that has this attribute
table.scan(FilterExpression=Attr("my-attr").lt(43))["Items"].should.equal([item])
table.scan(FilterExpression=Attr("my-attr").lte(42))["Items"].should.equal([item])
table.scan(FilterExpression=Attr("my-attr").gte(42))["Items"].should.equal([item])
table.scan(FilterExpression=Attr("my-attr").gt(41))["Items"].should.equal([item])
# Sanity check that we can't find the item if the FE is wrong
table.scan(FilterExpression=Attr("my-attr").gt(43))["Items"].should.equal([])
@mock_dynamodb2
def test_bad_scan_filter():
client = boto3.client("dynamodb", region_name="us-east-1")
@ -2451,6 +2531,48 @@ def test_condition_expressions():
)
@mock_dynamodb2
def test_condition_expression_numerical_attribute():
dynamodb = boto3.resource("dynamodb", region_name="us-east-1")
dynamodb.create_table(
TableName="my-table",
KeySchema=[{"AttributeName": "partitionKey", "KeyType": "HASH"}],
AttributeDefinitions=[{"AttributeName": "partitionKey", "AttributeType": "S"}],
)
table = dynamodb.Table("my-table")
table.put_item(Item={"partitionKey": "pk-pos", "myAttr": 5})
table.put_item(Item={"partitionKey": "pk-neg", "myAttr": -5})
# try to update the item we put in the table using numerical condition expression
# Specifically, verify that we can compare with a zero-value
# First verify that > and >= work on positive numbers
update_numerical_con_expr(
key="pk-pos", con_expr="myAttr > :zero", res="6", table=table
)
update_numerical_con_expr(
key="pk-pos", con_expr="myAttr >= :zero", res="7", table=table
)
# Second verify that < and <= work on negative numbers
update_numerical_con_expr(
key="pk-neg", con_expr="myAttr < :zero", res="-4", table=table
)
update_numerical_con_expr(
key="pk-neg", con_expr="myAttr <= :zero", res="-3", table=table
)
def update_numerical_con_expr(key, con_expr, res, table):
table.update_item(
Key={"partitionKey": key},
UpdateExpression="ADD myAttr :one",
ExpressionAttributeValues={":zero": 0, ":one": 1},
ConditionExpression=con_expr,
)
table.get_item(Key={"partitionKey": key})["Item"]["myAttr"].should.equal(
Decimal(res)
)
@mock_dynamodb2
def test_condition_expression__attr_doesnt_exist():
client = boto3.client("dynamodb", region_name="us-east-1")
@ -3435,6 +3557,58 @@ def test_update_supports_nested_list_append_onto_another_list():
)
@mock_dynamodb2
def test_update_supports_list_append_maps():
client = boto3.client("dynamodb", region_name="us-west-1")
client.create_table(
AttributeDefinitions=[
{"AttributeName": "id", "AttributeType": "S"},
{"AttributeName": "rid", "AttributeType": "S"},
],
TableName="TestTable",
KeySchema=[
{"AttributeName": "id", "KeyType": "HASH"},
{"AttributeName": "rid", "KeyType": "RANGE"},
],
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
)
client.put_item(
TableName="TestTable",
Item={
"id": {"S": "nested_list_append"},
"rid": {"S": "range_key"},
"a": {"L": [{"M": {"b": {"S": "bar1"}}}]},
},
)
# Update item using list_append expression
client.update_item(
TableName="TestTable",
Key={"id": {"S": "nested_list_append"}, "rid": {"S": "range_key"}},
UpdateExpression="SET a = list_append(a, :i)",
ExpressionAttributeValues={":i": {"L": [{"M": {"b": {"S": "bar2"}}}]}},
)
# Verify item is appended to the existing list
result = client.query(
TableName="TestTable",
KeyConditionExpression="id = :i AND begins_with(rid, :r)",
ExpressionAttributeValues={
":i": {"S": "nested_list_append"},
":r": {"S": "range_key"},
},
)["Items"]
result.should.equal(
[
{
"a": {"L": [{"M": {"b": {"S": "bar1"}}}, {"M": {"b": {"S": "bar2"}}}]},
"rid": {"S": "range_key"},
"id": {"S": "nested_list_append"},
}
]
)
@mock_dynamodb2
def test_update_catches_invalid_list_append_operation():
client = boto3.client("dynamodb", region_name="us-east-1")

View file

@ -11,7 +11,7 @@ from moto import mock_ec2, mock_ec2_deprecated
def test_describe_regions():
conn = boto.connect_ec2("the_key", "the_secret")
regions = conn.get_all_regions()
regions.should.have.length_of(16)
len(regions).should.be.greater_than(1)
for region in regions:
region.endpoint.should.contain(region.name)
@ -32,7 +32,7 @@ def test_availability_zones():
def test_boto3_describe_regions():
ec2 = boto3.client("ec2", "us-east-1")
resp = ec2.describe_regions()
resp["Regions"].should.have.length_of(16)
len(resp["Regions"]).should.be.greater_than(1)
for rec in resp["Regions"]:
rec["Endpoint"].should.contain(rec["RegionName"])

View file

@ -3,13 +3,21 @@ import boto.ec2
import boto.ec2.autoscale
import boto.ec2.elb
import sure
from boto3 import Session
from moto import mock_ec2_deprecated, mock_autoscaling_deprecated, mock_elb_deprecated
from moto.ec2 import ec2_backends
def test_use_boto_regions():
boto_regions = {r.name for r in boto.ec2.regions()}
boto_regions = set()
for region in Session().get_available_regions("ec2"):
boto_regions.add(region)
for region in Session().get_available_regions("ec2", partition_name="aws-us-gov"):
boto_regions.add(region)
for region in Session().get_available_regions("ec2", partition_name="aws-cn"):
boto_regions.add(region)
moto_regions = set(ec2_backends)
moto_regions.should.equal(boto_regions)

View file

@ -0,0 +1,23 @@
import boto3
from moto import mock_ec2_instance_connect
pubkey = """ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQDV5+voluw2zmzqpqCAqtsyoP01TQ8Ydx1eS1yD6wUsHcPqMIqpo57YxiC8XPwrdeKQ6GG6MC3bHsgXoPypGP0LyixbiuLTU31DnnqorcHt4bWs6rQa7dK2pCCflz2fhYRt5ZjqSNsAKivIbqkH66JozN0SySIka3kEV79GdB0BicioKeEJlCwM9vvxafyzjWf/z8E0lh4ni3vkLpIVJ0t5l+Qd9QMJrT6Is0SCQPVagTYZoi8+fWDoGsBa8vyRwDjEzBl28ZplKh9tSyDkRIYszWTpmK8qHiqjLYZBfAxXjGJbEYL1iig4ZxvbYzKEiKSBi1ZMW9iWjHfZDZuxXAmB
example
"""
@mock_ec2_instance_connect
def test_send_ssh_public_key():
client = boto3.client("ec2-instance-connect", region_name="us-east-1")
fake_request_id = "example-2a47-4c91-9700-e37e85162cb6"
response = client.send_ssh_public_key(
InstanceId="i-abcdefg12345",
InstanceOSUser="ec2-user",
SSHPublicKey=pubkey,
AvailabilityZone="us-east-1a",
)
assert response["RequestId"] == fake_request_id

View file

@ -94,6 +94,7 @@ def test_register_task_definition():
"logConfiguration": {"logDriver": "json-file"},
}
],
networkMode="bridge",
tags=[
{"key": "createdBy", "value": "moto-unittest"},
{"key": "foo", "value": "bar"},
@ -124,6 +125,7 @@ def test_register_task_definition():
response["taskDefinition"]["containerDefinitions"][0]["logConfiguration"][
"logDriver"
].should.equal("json-file")
response["taskDefinition"]["networkMode"].should.equal("bridge")
@mock_ecs

View file

@ -44,7 +44,7 @@ def test_describe_job():
joboutput.should.have.key("Tier").which.should.equal("Standard")
joboutput.should.have.key("StatusCode").which.should.equal("InProgress")
joboutput.should.have.key("VaultARN").which.should.equal(
"arn:aws:glacier:RegionInfo:us-west-2:012345678901:vaults/my_vault"
"arn:aws:glacier:us-west-2:012345678901:vaults/my_vault"
)

View file

@ -1737,9 +1737,7 @@ def test_delete_saml_provider():
def test_create_role_defaults():
"""Tests default values"""
conn = boto3.client("iam", region_name="us-east-1")
conn.create_role(
RoleName="my-role", AssumeRolePolicyDocument="{}",
)
conn.create_role(RoleName="my-role", AssumeRolePolicyDocument="{}")
# Get role:
role = conn.get_role(RoleName="my-role")["Role"]
@ -2672,3 +2670,33 @@ def test_get_account_summary():
"GroupsQuota": 300,
}
)
@mock_iam()
def test_list_user_tags():
"""Tests both setting a tags on a user in create_user and list_user_tags"""
conn = boto3.client("iam", region_name="us-east-1")
conn.create_user(UserName="kenny-bania")
conn.create_user(
UserName="jackie-chiles", Tags=[{"Key": "Sue-Allen", "Value": "Oh-Henry"}]
)
conn.create_user(
UserName="cosmo",
Tags=[
{"Key": "Stan", "Value": "The Caddy"},
{"Key": "like-a", "Value": "glove"},
],
)
response = conn.list_user_tags(UserName="kenny-bania")
response["Tags"].should.equal([])
response["IsTruncated"].should_not.be.ok
response = conn.list_user_tags(UserName="jackie-chiles")
response["Tags"].should.equal([{"Key": "Sue-Allen", "Value": "Oh-Henry"}])
response["IsTruncated"].should_not.be.ok
response = conn.list_user_tags(UserName="cosmo")
response["Tags"].should.equal(
[{"Key": "Stan", "Value": "The Caddy"}, {"Key": "like-a", "Value": "glove"}]
)
response["IsTruncated"].should_not.be.ok

View file

@ -862,6 +862,8 @@ def test_list_resource_record_sets_name_type_filters():
StartRecordName=all_records[start_with][1],
)
response["IsTruncated"].should.equal(False)
returned_records = [
(record["Type"], record["Name"]) for record in response["ResourceRecordSets"]
]

View file

@ -1261,7 +1261,7 @@ def test_boto3_list_objects_truncated_response():
assert listed_object["Key"] == "one"
assert resp["MaxKeys"] == 1
assert resp["IsTruncated"] == True
assert resp["Prefix"] == "None"
assert resp.get("Prefix") is None
assert resp["Delimiter"] == "None"
assert "NextMarker" in resp
@ -1274,7 +1274,7 @@ def test_boto3_list_objects_truncated_response():
assert listed_object["Key"] == "three"
assert resp["MaxKeys"] == 1
assert resp["IsTruncated"] == True
assert resp["Prefix"] == "None"
assert resp.get("Prefix") is None
assert resp["Delimiter"] == "None"
assert "NextMarker" in resp
@ -1287,7 +1287,7 @@ def test_boto3_list_objects_truncated_response():
assert listed_object["Key"] == "two"
assert resp["MaxKeys"] == 1
assert resp["IsTruncated"] == False
assert resp["Prefix"] == "None"
assert resp.get("Prefix") is None
assert resp["Delimiter"] == "None"
assert "NextMarker" not in resp

View file

@ -54,9 +54,10 @@ def test_deleting_subscriptions_by_deleting_topic():
]["Subscriptions"]
subscriptions.should.have.length_of(1)
subscription = subscriptions[0]
subscription_arn = subscription["SubscriptionArn"]
subscription["TopicArn"].should.equal(topic_arn)
subscription["Protocol"].should.equal("http")
subscription["SubscriptionArn"].should.contain(topic_arn)
subscription_arn.should.contain(topic_arn)
subscription["Endpoint"].should.equal("http://example.com/")
# Now delete the topic
@ -67,12 +68,25 @@ def test_deleting_subscriptions_by_deleting_topic():
topics = topics_json["ListTopicsResponse"]["ListTopicsResult"]["Topics"]
topics.should.have.length_of(0)
# And there should be zero subscriptions left
# And the subscription should still be left
subscriptions = conn.get_all_subscriptions()["ListSubscriptionsResponse"][
"ListSubscriptionsResult"
]["Subscriptions"]
subscriptions.should.have.length_of(1)
subscription = subscriptions[0]
subscription["SubscriptionArn"].should.equal(subscription_arn)
# Now delete hanging subscription
conn.unsubscribe(subscription_arn)
subscriptions = conn.get_all_subscriptions()["ListSubscriptionsResponse"][
"ListSubscriptionsResult"
]["Subscriptions"]
subscriptions.should.have.length_of(0)
# Deleting it again should not result in any error
conn.unsubscribe(subscription_arn)
@mock_sns_deprecated
def test_getting_subscriptions_by_topic():

View file

@ -97,34 +97,48 @@ def test_creating_subscription():
@mock_sns
def test_deleting_subscriptions_by_deleting_topic():
conn = boto3.client("sns", region_name="us-east-1")
conn.create_topic(Name="some-topic")
response = conn.list_topics()
def test_unsubscribe_from_deleted_topic():
client = boto3.client("sns", region_name="us-east-1")
client.create_topic(Name="some-topic")
response = client.list_topics()
topic_arn = response["Topics"][0]["TopicArn"]
conn.subscribe(TopicArn=topic_arn, Protocol="http", Endpoint="http://example.com/")
client.subscribe(
TopicArn=topic_arn, Protocol="http", Endpoint="http://example.com/"
)
subscriptions = conn.list_subscriptions()["Subscriptions"]
subscriptions = client.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
subscription = subscriptions[0]
subscription_arn = subscription["SubscriptionArn"]
subscription["TopicArn"].should.equal(topic_arn)
subscription["Protocol"].should.equal("http")
subscription["SubscriptionArn"].should.contain(topic_arn)
subscription_arn.should.contain(topic_arn)
subscription["Endpoint"].should.equal("http://example.com/")
# Now delete the topic
conn.delete_topic(TopicArn=topic_arn)
client.delete_topic(TopicArn=topic_arn)
# And there should now be 0 topics
topics_json = conn.list_topics()
topics_json = client.list_topics()
topics = topics_json["Topics"]
topics.should.have.length_of(0)
# And there should be zero subscriptions left
subscriptions = conn.list_subscriptions()["Subscriptions"]
# And the subscription should still be left
subscriptions = client.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(1)
subscription = subscriptions[0]
subscription["SubscriptionArn"].should.equal(subscription_arn)
# Now delete hanging subscription
client.unsubscribe(SubscriptionArn=subscription_arn)
subscriptions = client.list_subscriptions()["Subscriptions"]
subscriptions.should.have.length_of(0)
# Deleting it again should not result in any error
client.unsubscribe(SubscriptionArn=subscription_arn)
@mock_sns
def test_getting_subscriptions_by_topic():

View file

@ -331,7 +331,20 @@ def test_delete_queue():
@mock_sqs
def test_get_queue_attributes():
client = boto3.client("sqs", region_name="us-east-1")
response = client.create_queue(QueueName="test-queue")
dlq_resp = client.create_queue(QueueName="test-dlr-queue")
dlq_arn1 = client.get_queue_attributes(QueueUrl=dlq_resp["QueueUrl"])["Attributes"][
"QueueArn"
]
response = client.create_queue(
QueueName="test-queue",
Attributes={
"RedrivePolicy": json.dumps(
{"deadLetterTargetArn": dlq_arn1, "maxReceiveCount": 2}
),
},
)
queue_url = response["QueueUrl"]
response = client.get_queue_attributes(QueueUrl=queue_url)
@ -356,6 +369,7 @@ def test_get_queue_attributes():
"ApproximateNumberOfMessages",
"MaximumMessageSize",
"QueueArn",
"RedrivePolicy",
"VisibilityTimeout",
],
)
@ -366,6 +380,9 @@ def test_get_queue_attributes():
"MaximumMessageSize": "65536",
"QueueArn": "arn:aws:sqs:us-east-1:{}:test-queue".format(ACCOUNT_ID),
"VisibilityTimeout": "30",
"RedrivePolicy": json.dumps(
{"deadLetterTargetArn": dlq_arn1, "maxReceiveCount": 2}
),
}
)