Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
84210f6011
@ -1240,14 +1240,14 @@
|
||||
- [ ] create_commit
|
||||
- [ ] create_pull_request
|
||||
- [ ] create_pull_request_approval_rule
|
||||
- [ ] create_repository
|
||||
- [X] create_repository
|
||||
- [ ] create_unreferenced_merge_commit
|
||||
- [ ] delete_approval_rule_template
|
||||
- [ ] delete_branch
|
||||
- [ ] delete_comment_content
|
||||
- [ ] delete_file
|
||||
- [ ] delete_pull_request_approval_rule
|
||||
- [ ] delete_repository
|
||||
- [X] delete_repository
|
||||
- [ ] describe_merge_conflicts
|
||||
- [ ] describe_pull_request_events
|
||||
- [ ] disassociate_approval_rule_template_from_repository
|
||||
@ -1268,7 +1268,7 @@
|
||||
- [ ] get_pull_request
|
||||
- [ ] get_pull_request_approval_states
|
||||
- [ ] get_pull_request_override_state
|
||||
- [ ] get_repository
|
||||
- [X] get_repository
|
||||
- [ ] get_repository_triggers
|
||||
- [ ] list_approval_rule_templates
|
||||
- [ ] list_associated_approval_rule_templates_for_repository
|
||||
@ -1374,7 +1374,7 @@
|
||||
- [ ] update_profiling_group
|
||||
|
||||
## codepipeline
|
||||
13% implemented
|
||||
22% implemented
|
||||
- [ ] acknowledge_job
|
||||
- [ ] acknowledge_third_party_job
|
||||
- [ ] create_custom_action_type
|
||||
@ -1394,7 +1394,7 @@
|
||||
- [ ] list_action_types
|
||||
- [ ] list_pipeline_executions
|
||||
- [X] list_pipelines
|
||||
- [ ] list_tags_for_resource
|
||||
- [X] list_tags_for_resource
|
||||
- [ ] list_webhooks
|
||||
- [ ] poll_for_jobs
|
||||
- [ ] poll_for_third_party_jobs
|
||||
@ -1408,8 +1408,8 @@
|
||||
- [ ] register_webhook_with_third_party
|
||||
- [ ] retry_stage_execution
|
||||
- [ ] start_pipeline_execution
|
||||
- [ ] tag_resource
|
||||
- [ ] untag_resource
|
||||
- [X] tag_resource
|
||||
- [X] untag_resource
|
||||
- [X] update_pipeline
|
||||
|
||||
## codestar
|
||||
@ -2694,7 +2694,7 @@
|
||||
|
||||
## ec2-instance-connect
|
||||
0% implemented
|
||||
- [ ] send_ssh_public_key
|
||||
- [x] send_ssh_public_key
|
||||
|
||||
## ecr
|
||||
27% implemented
|
||||
@ -3763,7 +3763,7 @@
|
||||
- [X] list_signing_certificates
|
||||
- [ ] list_ssh_public_keys
|
||||
- [X] list_user_policies
|
||||
- [ ] list_user_tags
|
||||
- [X] list_user_tags
|
||||
- [X] list_users
|
||||
- [X] list_virtual_mfa_devices
|
||||
- [X] put_group_policy
|
||||
|
26
README.md
26
README.md
@ -283,14 +283,14 @@ def test_describe_instances_allowed():
|
||||
]
|
||||
}
|
||||
access_key = ...
|
||||
# create access key for an IAM user/assumed role that has the policy above.
|
||||
# create access key for an IAM user/assumed role that has the policy above.
|
||||
# this part should call __exactly__ 4 AWS actions, so that authentication and authorization starts exactly after this
|
||||
|
||||
|
||||
client = boto3.client('ec2', region_name='us-east-1',
|
||||
aws_access_key_id=access_key['AccessKeyId'],
|
||||
aws_secret_access_key=access_key['SecretAccessKey'])
|
||||
|
||||
# if the IAM principal whose access key is used, does not have the permission to describe instances, this will fail
|
||||
|
||||
# if the IAM principal whose access key is used, does not have the permission to describe instances, this will fail
|
||||
instances = client.describe_instances()['Reservations'][0]['Instances']
|
||||
assert len(instances) == 0
|
||||
```
|
||||
@ -310,16 +310,16 @@ You need to ensure that the mocks are actually in place. Changes made to recent
|
||||
have altered some of the mock behavior. In short, you need to ensure that you _always_ do the following:
|
||||
|
||||
1. Ensure that your tests have dummy environment variables set up:
|
||||
|
||||
|
||||
export AWS_ACCESS_KEY_ID='testing'
|
||||
export AWS_SECRET_ACCESS_KEY='testing'
|
||||
export AWS_SECURITY_TOKEN='testing'
|
||||
export AWS_SESSION_TOKEN='testing'
|
||||
|
||||
1. __VERY IMPORTANT__: ensure that you have your mocks set up __BEFORE__ your `boto3` client is established.
|
||||
|
||||
1. __VERY IMPORTANT__: ensure that you have your mocks set up __BEFORE__ your `boto3` client is established.
|
||||
This can typically happen if you import a module that has a `boto3` client instantiated outside of a function.
|
||||
See the pesky imports section below on how to work around this.
|
||||
|
||||
|
||||
### Example on usage?
|
||||
If you are a user of [pytest](https://pytest.org/en/latest/), you can leverage [pytest fixtures](https://pytest.org/en/latest/fixture.html#fixture)
|
||||
to help set up your mocks and other AWS resources that you would need.
|
||||
@ -354,7 +354,7 @@ def cloudwatch(aws_credentials):
|
||||
... etc.
|
||||
```
|
||||
|
||||
In the code sample above, all of the AWS/mocked fixtures take in a parameter of `aws_credentials`,
|
||||
In the code sample above, all of the AWS/mocked fixtures take in a parameter of `aws_credentials`,
|
||||
which sets the proper fake environment variables. The fake environment variables are used so that `botocore` doesn't try to locate real
|
||||
credentials on your system.
|
||||
|
||||
@ -364,7 +364,7 @@ def test_create_bucket(s3):
|
||||
# s3 is a fixture defined above that yields a boto3 s3 client.
|
||||
# Feel free to instantiate another boto3 S3 client -- Keep note of the region though.
|
||||
s3.create_bucket(Bucket="somebucket")
|
||||
|
||||
|
||||
result = s3.list_buckets()
|
||||
assert len(result['Buckets']) == 1
|
||||
assert result['Buckets'][0]['Name'] == 'somebucket'
|
||||
@ -373,7 +373,7 @@ def test_create_bucket(s3):
|
||||
### What about those pesky imports?
|
||||
Recall earlier, it was mentioned that mocks should be established __BEFORE__ the clients are set up. One way
|
||||
to avoid import issues is to make use of local Python imports -- i.e. import the module inside of the unit
|
||||
test you want to run vs. importing at the top of the file.
|
||||
test you want to run vs. importing at the top of the file.
|
||||
|
||||
Example:
|
||||
```python
|
||||
@ -381,12 +381,12 @@ def test_something(s3):
|
||||
from some.package.that.does.something.with.s3 import some_func # <-- Local import for unit test
|
||||
# ^^ Importing here ensures that the mock has been established.
|
||||
|
||||
sume_func() # The mock has been established from the "s3" pytest fixture, so this function that uses
|
||||
some_func() # The mock has been established from the "s3" pytest fixture, so this function that uses
|
||||
# a package-level S3 client will properly use the mock and not reach out to AWS.
|
||||
```
|
||||
|
||||
### Other caveats
|
||||
For Tox, Travis CI, and other build systems, you might need to also perform a `touch ~/.aws/credentials`
|
||||
For Tox, Travis CI, and other build systems, you might need to also perform a `touch ~/.aws/credentials`
|
||||
command before running the tests. As long as that file is present (empty preferably) and the environment
|
||||
variables above are set, you should be good to go.
|
||||
|
||||
|
@ -76,7 +76,7 @@ Currently implemented Services:
|
||||
+---------------------------+-----------------------+------------------------------------+
|
||||
| Logs | @mock_logs | basic endpoints done |
|
||||
+---------------------------+-----------------------+------------------------------------+
|
||||
| Organizations | @mock_organizations | some core edpoints done |
|
||||
| Organizations | @mock_organizations | some core endpoints done |
|
||||
+---------------------------+-----------------------+------------------------------------+
|
||||
| Polly | @mock_polly | all endpoints done |
|
||||
+---------------------------+-----------------------+------------------------------------+
|
||||
|
@ -9,6 +9,7 @@ from .batch import mock_batch # noqa
|
||||
from .cloudformation import mock_cloudformation # noqa
|
||||
from .cloudformation import mock_cloudformation_deprecated # noqa
|
||||
from .cloudwatch import mock_cloudwatch, mock_cloudwatch_deprecated # noqa
|
||||
from .codecommit import mock_codecommit # noqa
|
||||
from .codepipeline import mock_codepipeline # noqa
|
||||
from .cognitoidentity import mock_cognitoidentity # noqa
|
||||
from .cognitoidentity import mock_cognitoidentity_deprecated # noqa
|
||||
@ -21,6 +22,7 @@ from .dynamodb import mock_dynamodb, mock_dynamodb_deprecated # noqa
|
||||
from .dynamodb2 import mock_dynamodb2, mock_dynamodb2_deprecated # noqa
|
||||
from .dynamodbstreams import mock_dynamodbstreams # noqa
|
||||
from .ec2 import mock_ec2, mock_ec2_deprecated # noqa
|
||||
from .ec2_instance_connect import mock_ec2_instance_connect # noqa
|
||||
from .ecr import mock_ecr, mock_ecr_deprecated # noqa
|
||||
from .ecs import mock_ecs, mock_ecs_deprecated # noqa
|
||||
from .elb import mock_elb, mock_elb_deprecated # noqa
|
||||
|
@ -847,3 +847,11 @@ class APIGatewayBackend(BaseBackend):
|
||||
apigateway_backends = {}
|
||||
for region_name in Session().get_available_regions("apigateway"):
|
||||
apigateway_backends[region_name] = APIGatewayBackend(region_name)
|
||||
for region_name in Session().get_available_regions(
|
||||
"apigateway", partition_name="aws-us-gov"
|
||||
):
|
||||
apigateway_backends[region_name] = APIGatewayBackend(region_name)
|
||||
for region_name in Session().get_available_regions(
|
||||
"apigateway", partition_name="aws-cn"
|
||||
):
|
||||
apigateway_backends[region_name] = APIGatewayBackend(region_name)
|
||||
|
@ -1,7 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
import time
|
||||
|
||||
import boto3
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
from moto.core import ACCOUNT_ID
|
||||
@ -77,5 +78,9 @@ class AthenaBackend(BaseBackend):
|
||||
|
||||
|
||||
athena_backends = {}
|
||||
for region in boto3.Session().get_available_regions("athena"):
|
||||
for region in Session().get_available_regions("athena"):
|
||||
athena_backends[region] = AthenaBackend(region)
|
||||
for region in Session().get_available_regions("athena", partition_name="aws-us-gov"):
|
||||
athena_backends[region] = AthenaBackend(region)
|
||||
for region in Session().get_available_regions("athena", partition_name="aws-cn"):
|
||||
athena_backends[region] = AthenaBackend(region)
|
||||
|
@ -23,7 +23,8 @@ import traceback
|
||||
import weakref
|
||||
import requests.adapters
|
||||
|
||||
import boto.awslambda
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.exceptions import RESTError
|
||||
from moto.iam.models import iam_backend
|
||||
@ -52,9 +53,6 @@ try:
|
||||
except ImportError:
|
||||
from backports.tempfile import TemporaryDirectory
|
||||
|
||||
# The lambci container is returning a special escape character for the "RequestID" fields. Unicode 033:
|
||||
# _stderr_regex = re.compile(r"START|END|REPORT RequestId: .*")
|
||||
_stderr_regex = re.compile(r"\033\[\d+.*")
|
||||
_orig_adapter_send = requests.adapters.HTTPAdapter.send
|
||||
docker_3 = docker.__version__[0] >= "3"
|
||||
|
||||
@ -384,7 +382,7 @@ class LambdaFunction(BaseModel):
|
||||
try:
|
||||
# TODO: I believe we can keep the container running and feed events as needed
|
||||
# also need to hook it up to the other services so it can make kws/s3 etc calls
|
||||
# Should get invoke_id /RequestId from invovation
|
||||
# Should get invoke_id /RequestId from invocation
|
||||
env_vars = {
|
||||
"AWS_LAMBDA_FUNCTION_TIMEOUT": self.timeout,
|
||||
"AWS_LAMBDA_FUNCTION_NAME": self.function_name,
|
||||
@ -452,14 +450,9 @@ class LambdaFunction(BaseModel):
|
||||
if exit_code != 0:
|
||||
raise Exception("lambda invoke failed output: {}".format(output))
|
||||
|
||||
# strip out RequestId lines (TODO: This will return an additional '\n' in the response)
|
||||
output = os.linesep.join(
|
||||
[
|
||||
line
|
||||
for line in self.convert(output).splitlines()
|
||||
if not _stderr_regex.match(line)
|
||||
]
|
||||
)
|
||||
# We only care about the response from the lambda
|
||||
# Which is the last line of the output, according to https://github.com/lambci/docker-lambda/issues/25
|
||||
output = output.splitlines()[-1]
|
||||
return output, False
|
||||
except BaseException as e:
|
||||
traceback.print_exc()
|
||||
@ -1043,10 +1036,10 @@ def do_validate_s3():
|
||||
return os.environ.get("VALIDATE_LAMBDA_S3", "") in ["", "1", "true"]
|
||||
|
||||
|
||||
# Handle us forgotten regions, unless Lambda truly only runs out of US and
|
||||
lambda_backends = {
|
||||
_region.name: LambdaBackend(_region.name) for _region in boto.awslambda.regions()
|
||||
}
|
||||
|
||||
lambda_backends["ap-southeast-2"] = LambdaBackend("ap-southeast-2")
|
||||
lambda_backends["us-gov-west-1"] = LambdaBackend("us-gov-west-1")
|
||||
lambda_backends = {}
|
||||
for region in Session().get_available_regions("lambda"):
|
||||
lambda_backends[region] = LambdaBackend(region)
|
||||
for region in Session().get_available_regions("lambda", partition_name="aws-us-gov"):
|
||||
lambda_backends[region] = LambdaBackend(region)
|
||||
for region in Session().get_available_regions("lambda", partition_name="aws-cn"):
|
||||
lambda_backends[region] = LambdaBackend(region)
|
||||
|
@ -8,6 +8,7 @@ from moto.awslambda import lambda_backends
|
||||
from moto.batch import batch_backends
|
||||
from moto.cloudformation import cloudformation_backends
|
||||
from moto.cloudwatch import cloudwatch_backends
|
||||
from moto.codecommit import codecommit_backends
|
||||
from moto.codepipeline import codepipeline_backends
|
||||
from moto.cognitoidentity import cognitoidentity_backends
|
||||
from moto.cognitoidp import cognitoidp_backends
|
||||
@ -19,6 +20,7 @@ from moto.dynamodb import dynamodb_backends
|
||||
from moto.dynamodb2 import dynamodb_backends2
|
||||
from moto.dynamodbstreams import dynamodbstreams_backends
|
||||
from moto.ec2 import ec2_backends
|
||||
from moto.ec2_instance_connect import ec2_instance_connect_backends
|
||||
from moto.ecr import ecr_backends
|
||||
from moto.ecs import ecs_backends
|
||||
from moto.elb import elb_backends
|
||||
@ -61,6 +63,7 @@ BACKENDS = {
|
||||
"batch": batch_backends,
|
||||
"cloudformation": cloudformation_backends,
|
||||
"cloudwatch": cloudwatch_backends,
|
||||
"codecommit": codecommit_backends,
|
||||
"codepipeline": codepipeline_backends,
|
||||
"cognito-identity": cognitoidentity_backends,
|
||||
"cognito-idp": cognitoidp_backends,
|
||||
@ -71,6 +74,7 @@ BACKENDS = {
|
||||
"dynamodb2": dynamodb_backends2,
|
||||
"dynamodbstreams": dynamodbstreams_backends,
|
||||
"ec2": ec2_backends,
|
||||
"ec2_instance_connect": ec2_instance_connect_backends,
|
||||
"ecr": ecr_backends,
|
||||
"ecs": ecs_backends,
|
||||
"elb": elb_backends,
|
||||
|
@ -1,5 +1,4 @@
|
||||
from __future__ import unicode_literals
|
||||
import boto3
|
||||
import re
|
||||
import requests.adapters
|
||||
from itertools import cycle
|
||||
@ -12,6 +11,8 @@ import docker
|
||||
import functools
|
||||
import threading
|
||||
import dateutil.parser
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.iam import iam_backends
|
||||
from moto.ec2 import ec2_backends
|
||||
@ -1317,7 +1318,10 @@ class BatchBackend(BaseBackend):
|
||||
job.terminate(reason)
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("batch")
|
||||
batch_backends = {
|
||||
region: BatchBackend(region_name=region) for region in available_regions
|
||||
}
|
||||
batch_backends = {}
|
||||
for region in Session().get_available_regions("batch"):
|
||||
batch_backends[region] = BatchBackend(region)
|
||||
for region in Session().get_available_regions("batch", partition_name="aws-us-gov"):
|
||||
batch_backends[region] = BatchBackend(region)
|
||||
for region in Session().get_available_regions("batch", partition_name="aws-cn"):
|
||||
batch_backends[region] = BatchBackend(region)
|
||||
|
@ -4,7 +4,8 @@ import json
|
||||
import yaml
|
||||
import uuid
|
||||
|
||||
import boto.cloudformation
|
||||
from boto3 import Session
|
||||
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
@ -717,5 +718,13 @@ class CloudFormationBackend(BaseBackend):
|
||||
|
||||
|
||||
cloudformation_backends = {}
|
||||
for region in boto.cloudformation.regions():
|
||||
cloudformation_backends[region.name] = CloudFormationBackend()
|
||||
for region in Session().get_available_regions("cloudformation"):
|
||||
cloudformation_backends[region] = CloudFormationBackend()
|
||||
for region in Session().get_available_regions(
|
||||
"cloudformation", partition_name="aws-us-gov"
|
||||
):
|
||||
cloudformation_backends[region] = CloudFormationBackend()
|
||||
for region in Session().get_available_regions(
|
||||
"cloudformation", partition_name="aws-cn"
|
||||
):
|
||||
cloudformation_backends[region] = CloudFormationBackend()
|
||||
|
@ -1,8 +1,10 @@
|
||||
import json
|
||||
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.exceptions import RESTError
|
||||
import boto.ec2.cloudwatch
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.tz import tzutc
|
||||
from uuid import uuid4
|
||||
@ -431,5 +433,11 @@ class LogGroup(BaseModel):
|
||||
|
||||
|
||||
cloudwatch_backends = {}
|
||||
for region in boto.ec2.cloudwatch.regions():
|
||||
cloudwatch_backends[region.name] = CloudWatchBackend()
|
||||
for region in Session().get_available_regions("cloudwatch"):
|
||||
cloudwatch_backends[region] = CloudWatchBackend()
|
||||
for region in Session().get_available_regions(
|
||||
"cloudwatch", partition_name="aws-us-gov"
|
||||
):
|
||||
cloudwatch_backends[region] = CloudWatchBackend()
|
||||
for region in Session().get_available_regions("cloudwatch", partition_name="aws-cn"):
|
||||
cloudwatch_backends[region] = CloudWatchBackend()
|
||||
|
4
moto/codecommit/__init__.py
Normal file
4
moto/codecommit/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from .models import codecommit_backends
|
||||
from ..core.models import base_decorator
|
||||
|
||||
mock_codecommit = base_decorator(codecommit_backends)
|
35
moto/codecommit/exceptions.py
Normal file
35
moto/codecommit/exceptions.py
Normal file
@ -0,0 +1,35 @@
|
||||
from moto.core.exceptions import JsonRESTError
|
||||
|
||||
|
||||
class RepositoryNameExistsException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, repository_name):
|
||||
super(RepositoryNameExistsException, self).__init__(
|
||||
"RepositoryNameExistsException",
|
||||
"Repository named {0} already exists".format(repository_name),
|
||||
)
|
||||
|
||||
|
||||
class RepositoryDoesNotExistException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, repository_name):
|
||||
super(RepositoryDoesNotExistException, self).__init__(
|
||||
"RepositoryDoesNotExistException",
|
||||
"{0} does not exist".format(repository_name),
|
||||
)
|
||||
|
||||
|
||||
class InvalidRepositoryNameException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self):
|
||||
super(InvalidRepositoryNameException, self).__init__(
|
||||
"InvalidRepositoryNameException",
|
||||
"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. ",
|
||||
)
|
69
moto/codecommit/models.py
Normal file
69
moto/codecommit/models.py
Normal file
@ -0,0 +1,69 @@
|
||||
from boto3 import Session
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
||||
from datetime import datetime
|
||||
from moto.iam.models import ACCOUNT_ID
|
||||
from .exceptions import RepositoryDoesNotExistException, RepositoryNameExistsException
|
||||
import uuid
|
||||
|
||||
|
||||
class CodeCommit(BaseModel):
|
||||
def __init__(self, region, repository_description, repository_name):
|
||||
current_date = iso_8601_datetime_with_milliseconds(datetime.utcnow())
|
||||
self.repository_metadata = dict()
|
||||
self.repository_metadata["repositoryName"] = repository_name
|
||||
self.repository_metadata[
|
||||
"cloneUrlSsh"
|
||||
] = "ssh://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
region, repository_name
|
||||
)
|
||||
self.repository_metadata[
|
||||
"cloneUrlHttp"
|
||||
] = "https://git-codecommit.{0}.amazonaws.com/v1/repos/{1}".format(
|
||||
region, repository_name
|
||||
)
|
||||
self.repository_metadata["creationDate"] = current_date
|
||||
self.repository_metadata["lastModifiedDate"] = current_date
|
||||
self.repository_metadata["repositoryDescription"] = repository_description
|
||||
self.repository_metadata["repositoryId"] = str(uuid.uuid4())
|
||||
self.repository_metadata["Arn"] = "arn:aws:codecommit:{0}:{1}:{2}".format(
|
||||
region, ACCOUNT_ID, repository_name
|
||||
)
|
||||
self.repository_metadata["accountId"] = ACCOUNT_ID
|
||||
|
||||
|
||||
class CodeCommitBackend(BaseBackend):
|
||||
def __init__(self):
|
||||
self.repositories = {}
|
||||
|
||||
def create_repository(self, region, repository_name, repository_description):
|
||||
repository = self.repositories.get(repository_name)
|
||||
if repository:
|
||||
raise RepositoryNameExistsException(repository_name)
|
||||
|
||||
self.repositories[repository_name] = CodeCommit(
|
||||
region, repository_description, repository_name
|
||||
)
|
||||
|
||||
return self.repositories[repository_name].repository_metadata
|
||||
|
||||
def get_repository(self, repository_name):
|
||||
repository = self.repositories.get(repository_name)
|
||||
if not repository:
|
||||
raise RepositoryDoesNotExistException(repository_name)
|
||||
|
||||
return repository.repository_metadata
|
||||
|
||||
def delete_repository(self, repository_name):
|
||||
repository = self.repositories.get(repository_name)
|
||||
|
||||
if repository:
|
||||
self.repositories.pop(repository_name)
|
||||
return repository.repository_metadata.get("repositoryId")
|
||||
|
||||
return None
|
||||
|
||||
|
||||
codecommit_backends = {}
|
||||
for region in Session().get_available_regions("codecommit"):
|
||||
codecommit_backends[region] = CodeCommitBackend()
|
57
moto/codecommit/responses.py
Normal file
57
moto/codecommit/responses.py
Normal file
@ -0,0 +1,57 @@
|
||||
import json
|
||||
import re
|
||||
|
||||
from moto.core.responses import BaseResponse
|
||||
from .models import codecommit_backends
|
||||
from .exceptions import InvalidRepositoryNameException
|
||||
|
||||
|
||||
def _is_repository_name_valid(repository_name):
|
||||
name_regex = re.compile(r"[\w\.-]+")
|
||||
result = name_regex.split(repository_name)
|
||||
if len(result) > 0:
|
||||
for match in result:
|
||||
if len(match) > 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class CodeCommitResponse(BaseResponse):
|
||||
@property
|
||||
def codecommit_backend(self):
|
||||
return codecommit_backends[self.region]
|
||||
|
||||
def create_repository(self):
|
||||
if not _is_repository_name_valid(self._get_param("repositoryName")):
|
||||
raise InvalidRepositoryNameException()
|
||||
|
||||
repository_metadata = self.codecommit_backend.create_repository(
|
||||
self.region,
|
||||
self._get_param("repositoryName"),
|
||||
self._get_param("repositoryDescription"),
|
||||
)
|
||||
|
||||
return json.dumps({"repositoryMetadata": repository_metadata})
|
||||
|
||||
def get_repository(self):
|
||||
if not _is_repository_name_valid(self._get_param("repositoryName")):
|
||||
raise InvalidRepositoryNameException()
|
||||
|
||||
repository_metadata = self.codecommit_backend.get_repository(
|
||||
self._get_param("repositoryName")
|
||||
)
|
||||
|
||||
return json.dumps({"repositoryMetadata": repository_metadata})
|
||||
|
||||
def delete_repository(self):
|
||||
if not _is_repository_name_valid(self._get_param("repositoryName")):
|
||||
raise InvalidRepositoryNameException()
|
||||
|
||||
repository_id = self.codecommit_backend.delete_repository(
|
||||
self._get_param("repositoryName")
|
||||
)
|
||||
|
||||
if repository_id:
|
||||
return json.dumps({"repositoryId": repository_id})
|
||||
|
||||
return json.dumps({})
|
6
moto/codecommit/urls.py
Normal file
6
moto/codecommit/urls.py
Normal file
@ -0,0 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
from .responses import CodeCommitResponse
|
||||
|
||||
url_bases = ["https?://codecommit.(.+).amazonaws.com"]
|
||||
|
||||
url_paths = {"{0}/$": CodeCommitResponse.dispatch}
|
@ -26,3 +26,19 @@ class ResourceNotFoundException(JsonRESTError):
|
||||
super(ResourceNotFoundException, self).__init__(
|
||||
"ResourceNotFoundException", message
|
||||
)
|
||||
|
||||
|
||||
class InvalidTagsException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, message):
|
||||
super(InvalidTagsException, self).__init__("InvalidTagsException", message)
|
||||
|
||||
|
||||
class TooManyTagsException(JsonRESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, arn):
|
||||
super(TooManyTagsException, self).__init__(
|
||||
"TooManyTagsException", "Tag limit exceeded for resource [{}].".format(arn)
|
||||
)
|
||||
|
@ -12,6 +12,8 @@ from moto.codepipeline.exceptions import (
|
||||
InvalidStructureException,
|
||||
PipelineNotFoundException,
|
||||
ResourceNotFoundException,
|
||||
InvalidTagsException,
|
||||
TooManyTagsException,
|
||||
)
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
@ -54,6 +56,18 @@ class CodePipeline(BaseModel):
|
||||
|
||||
return pipeline
|
||||
|
||||
def validate_tags(self, tags):
|
||||
for tag in tags:
|
||||
if tag["key"].startswith("aws:"):
|
||||
raise InvalidTagsException(
|
||||
"Not allowed to modify system tags. "
|
||||
"System tags start with 'aws:'. "
|
||||
"msg=[Caller is an end user and not allowed to mutate system tags]"
|
||||
)
|
||||
|
||||
if (len(self.tags) + len(tags)) > 50:
|
||||
raise TooManyTagsException(self._arn)
|
||||
|
||||
|
||||
class CodePipelineBackend(BaseBackend):
|
||||
def __init__(self):
|
||||
@ -93,10 +107,12 @@ class CodePipelineBackend(BaseBackend):
|
||||
self.pipelines[pipeline["name"]] = CodePipeline(region, pipeline)
|
||||
|
||||
if tags:
|
||||
self.pipelines[pipeline["name"]].validate_tags(tags)
|
||||
|
||||
new_tags = {tag["key"]: tag["value"] for tag in tags}
|
||||
self.pipelines[pipeline["name"]].tags.update(new_tags)
|
||||
|
||||
return pipeline, tags
|
||||
return pipeline, sorted(tags, key=lambda i: i["key"])
|
||||
|
||||
def get_pipeline(self, name):
|
||||
codepipeline = self.pipelines.get(name)
|
||||
@ -145,7 +161,58 @@ class CodePipelineBackend(BaseBackend):
|
||||
def delete_pipeline(self, name):
|
||||
self.pipelines.pop(name, None)
|
||||
|
||||
def list_tags_for_resource(self, arn):
|
||||
name = arn.split(":")[-1]
|
||||
pipeline = self.pipelines.get(name)
|
||||
|
||||
if not pipeline:
|
||||
raise ResourceNotFoundException(
|
||||
"The account with id '{0}' does not include a pipeline with the name '{1}'".format(
|
||||
ACCOUNT_ID, name
|
||||
)
|
||||
)
|
||||
|
||||
tags = [{"key": key, "value": value} for key, value in pipeline.tags.items()]
|
||||
|
||||
return sorted(tags, key=lambda i: i["key"])
|
||||
|
||||
def tag_resource(self, arn, tags):
|
||||
name = arn.split(":")[-1]
|
||||
pipeline = self.pipelines.get(name)
|
||||
|
||||
if not pipeline:
|
||||
raise ResourceNotFoundException(
|
||||
"The account with id '{0}' does not include a pipeline with the name '{1}'".format(
|
||||
ACCOUNT_ID, name
|
||||
)
|
||||
)
|
||||
|
||||
pipeline.validate_tags(tags)
|
||||
|
||||
for tag in tags:
|
||||
pipeline.tags.update({tag["key"]: tag["value"]})
|
||||
|
||||
def untag_resource(self, arn, tag_keys):
|
||||
name = arn.split(":")[-1]
|
||||
pipeline = self.pipelines.get(name)
|
||||
|
||||
if not pipeline:
|
||||
raise ResourceNotFoundException(
|
||||
"The account with id '{0}' does not include a pipeline with the name '{1}'".format(
|
||||
ACCOUNT_ID, name
|
||||
)
|
||||
)
|
||||
|
||||
for key in tag_keys:
|
||||
pipeline.tags.pop(key, None)
|
||||
|
||||
|
||||
codepipeline_backends = {}
|
||||
for region in Session().get_available_regions("codepipeline"):
|
||||
codepipeline_backends[region] = CodePipelineBackend()
|
||||
for region in Session().get_available_regions(
|
||||
"codepipeline", partition_name="aws-us-gov"
|
||||
):
|
||||
codepipeline_backends[region] = CodePipelineBackend()
|
||||
for region in Session().get_available_regions("codepipeline", partition_name="aws-cn"):
|
||||
codepipeline_backends[region] = CodePipelineBackend()
|
||||
|
@ -39,3 +39,24 @@ class CodePipelineResponse(BaseResponse):
|
||||
self.codepipeline_backend.delete_pipeline(self._get_param("name"))
|
||||
|
||||
return ""
|
||||
|
||||
def list_tags_for_resource(self):
|
||||
tags = self.codepipeline_backend.list_tags_for_resource(
|
||||
self._get_param("resourceArn")
|
||||
)
|
||||
|
||||
return json.dumps({"tags": tags})
|
||||
|
||||
def tag_resource(self):
|
||||
self.codepipeline_backend.tag_resource(
|
||||
self._get_param("resourceArn"), self._get_param("tags")
|
||||
)
|
||||
|
||||
return ""
|
||||
|
||||
def untag_resource(self):
|
||||
self.codepipeline_backend.untag_resource(
|
||||
self._get_param("resourceArn"), self._get_param("tagKeys")
|
||||
)
|
||||
|
||||
return ""
|
||||
|
@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
||||
import datetime
|
||||
import json
|
||||
|
||||
import boto.cognito.identity
|
||||
from boto3 import Session
|
||||
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
@ -136,5 +136,13 @@ class CognitoIdentityBackend(BaseBackend):
|
||||
|
||||
|
||||
cognitoidentity_backends = {}
|
||||
for region in boto.cognito.identity.regions():
|
||||
cognitoidentity_backends[region.name] = CognitoIdentityBackend(region.name)
|
||||
for region in Session().get_available_regions("cognito-identity"):
|
||||
cognitoidentity_backends[region] = CognitoIdentityBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"cognito-identity", partition_name="aws-us-gov"
|
||||
):
|
||||
cognitoidentity_backends[region] = CognitoIdentityBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"cognito-identity", partition_name="aws-cn"
|
||||
):
|
||||
cognitoidentity_backends[region] = CognitoIdentityBackend(region)
|
||||
|
@ -9,7 +9,7 @@ import os
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import boto.cognito.identity
|
||||
from boto3 import Session
|
||||
from jose import jws
|
||||
|
||||
from moto.compat import OrderedDict
|
||||
@ -108,7 +108,9 @@ class CognitoIdpUserPool(BaseModel):
|
||||
|
||||
return user_pool_json
|
||||
|
||||
def create_jwt(self, client_id, username, expires_in=60 * 60, extra_data={}):
|
||||
def create_jwt(
|
||||
self, client_id, username, token_use, expires_in=60 * 60, extra_data={}
|
||||
):
|
||||
now = int(time.time())
|
||||
payload = {
|
||||
"iss": "https://cognito-idp.{}.amazonaws.com/{}".format(
|
||||
@ -116,7 +118,7 @@ class CognitoIdpUserPool(BaseModel):
|
||||
),
|
||||
"sub": self.users[username].id,
|
||||
"aud": client_id,
|
||||
"token_use": "id",
|
||||
"token_use": token_use,
|
||||
"auth_time": now,
|
||||
"exp": now + expires_in,
|
||||
}
|
||||
@ -125,7 +127,10 @@ class CognitoIdpUserPool(BaseModel):
|
||||
return jws.sign(payload, self.json_web_key, algorithm="RS256"), expires_in
|
||||
|
||||
def create_id_token(self, client_id, username):
|
||||
id_token, expires_in = self.create_jwt(client_id, username)
|
||||
extra_data = self.get_user_extra_data_by_client_id(client_id, username)
|
||||
id_token, expires_in = self.create_jwt(
|
||||
client_id, username, "id", extra_data=extra_data
|
||||
)
|
||||
self.id_tokens[id_token] = (client_id, username)
|
||||
return id_token, expires_in
|
||||
|
||||
@ -135,10 +140,7 @@ class CognitoIdpUserPool(BaseModel):
|
||||
return refresh_token
|
||||
|
||||
def create_access_token(self, client_id, username):
|
||||
extra_data = self.get_user_extra_data_by_client_id(client_id, username)
|
||||
access_token, expires_in = self.create_jwt(
|
||||
client_id, username, extra_data=extra_data
|
||||
)
|
||||
access_token, expires_in = self.create_jwt(client_id, username, "access")
|
||||
self.access_tokens[access_token] = (client_id, username)
|
||||
return access_token, expires_in
|
||||
|
||||
@ -749,8 +751,14 @@ class CognitoIdpBackend(BaseBackend):
|
||||
|
||||
|
||||
cognitoidp_backends = {}
|
||||
for region in boto.cognito.identity.regions():
|
||||
cognitoidp_backends[region.name] = CognitoIdpBackend(region.name)
|
||||
for region in Session().get_available_regions("cognito-idp"):
|
||||
cognitoidp_backends[region] = CognitoIdpBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"cognito-idp", partition_name="aws-us-gov"
|
||||
):
|
||||
cognitoidp_backends[region] = CognitoIdpBackend(region)
|
||||
for region in Session().get_available_regions("cognito-idp", partition_name="aws-cn"):
|
||||
cognitoidp_backends[region] = CognitoIdpBackend(region)
|
||||
|
||||
|
||||
# Hack to help moto-server process requests on localhost, where the region isn't
|
||||
|
@ -1084,6 +1084,9 @@ class ConfigBackend(BaseBackend):
|
||||
|
||||
|
||||
config_backends = {}
|
||||
boto3_session = Session()
|
||||
for region in boto3_session.get_available_regions("config"):
|
||||
for region in Session().get_available_regions("config"):
|
||||
config_backends[region] = ConfigBackend()
|
||||
for region in Session().get_available_regions("config", partition_name="aws-us-gov"):
|
||||
config_backends[region] = ConfigBackend()
|
||||
for region in Session().get_available_regions("config", partition_name="aws-cn"):
|
||||
config_backends[region] = ConfigBackend()
|
||||
|
@ -1,7 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
import boto.datapipeline
|
||||
from boto3 import Session
|
||||
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from .utils import get_random_pipeline_id, remove_capitalization_of_dict_keys
|
||||
@ -142,5 +143,11 @@ class DataPipelineBackend(BaseBackend):
|
||||
|
||||
|
||||
datapipeline_backends = {}
|
||||
for region in boto.datapipeline.regions():
|
||||
datapipeline_backends[region.name] = DataPipelineBackend()
|
||||
for region in Session().get_available_regions("datapipeline"):
|
||||
datapipeline_backends[region] = DataPipelineBackend()
|
||||
for region in Session().get_available_regions(
|
||||
"datapipeline", partition_name="aws-us-gov"
|
||||
):
|
||||
datapipeline_backends[region] = DataPipelineBackend()
|
||||
for region in Session().get_available_regions("datapipeline", partition_name="aws-cn"):
|
||||
datapipeline_backends[region] = DataPipelineBackend(region)
|
||||
|
@ -1,4 +1,5 @@
|
||||
import boto3
|
||||
from boto3 import Session
|
||||
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
@ -226,5 +227,9 @@ class DataSyncBackend(BaseBackend):
|
||||
|
||||
|
||||
datasync_backends = {}
|
||||
for region in boto3.Session().get_available_regions("datasync"):
|
||||
datasync_backends[region] = DataSyncBackend(region_name=region)
|
||||
for region in Session().get_available_regions("datasync"):
|
||||
datasync_backends[region] = DataSyncBackend(region)
|
||||
for region in Session().get_available_regions("datasync", partition_name="aws-us-gov"):
|
||||
datasync_backends[region] = DataSyncBackend(region)
|
||||
for region in Session().get_available_regions("datasync", partition_name="aws-cn"):
|
||||
datasync_backends[region] = DataSyncBackend(region)
|
||||
|
@ -977,10 +977,8 @@ class OpLessThan(Op):
|
||||
lhs = self.lhs.expr(item)
|
||||
rhs = self.rhs.expr(item)
|
||||
# In python3 None is not a valid comparator when using < or > so must be handled specially
|
||||
if lhs and rhs:
|
||||
if lhs is not None and rhs is not None:
|
||||
return lhs < rhs
|
||||
elif lhs is None and rhs:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@ -992,10 +990,8 @@ class OpGreaterThan(Op):
|
||||
lhs = self.lhs.expr(item)
|
||||
rhs = self.rhs.expr(item)
|
||||
# In python3 None is not a valid comparator when using < or > so must be handled specially
|
||||
if lhs and rhs:
|
||||
if lhs is not None and rhs is not None:
|
||||
return lhs > rhs
|
||||
elif lhs and rhs is None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@ -1025,10 +1021,8 @@ class OpLessThanOrEqual(Op):
|
||||
lhs = self.lhs.expr(item)
|
||||
rhs = self.rhs.expr(item)
|
||||
# In python3 None is not a valid comparator when using < or > so must be handled specially
|
||||
if lhs and rhs:
|
||||
if lhs is not None and rhs is not None:
|
||||
return lhs <= rhs
|
||||
elif lhs is None and rhs or lhs is None and rhs is None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@ -1040,10 +1034,8 @@ class OpGreaterThanOrEqual(Op):
|
||||
lhs = self.lhs.expr(item)
|
||||
rhs = self.rhs.expr(item)
|
||||
# In python3 None is not a valid comparator when using < or > so must be handled specially
|
||||
if lhs and rhs:
|
||||
if lhs is not None and rhs is not None:
|
||||
return lhs >= rhs
|
||||
elif lhs and rhs is None or lhs is None and rhs is None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
@ -8,7 +8,7 @@ import re
|
||||
import uuid
|
||||
import six
|
||||
|
||||
import boto3
|
||||
from boto3 import Session
|
||||
from botocore.exceptions import ParamValidationError
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
@ -457,7 +457,7 @@ class Item(BaseModel):
|
||||
)
|
||||
if not old_list.is_list():
|
||||
raise ParamValidationError
|
||||
old_list.value.extend(new_value["L"])
|
||||
old_list.value.extend([DynamoType(v) for v in new_value["L"]])
|
||||
value = old_list
|
||||
return value
|
||||
|
||||
@ -586,7 +586,9 @@ class StreamRecord(BaseModel):
|
||||
self.record["dynamodb"]["OldImage"] = old_a
|
||||
|
||||
# This is a substantial overestimate but it's the easiest to do now
|
||||
self.record["dynamodb"]["SizeBytes"] = len(json.dumps(self.record["dynamodb"]))
|
||||
self.record["dynamodb"]["SizeBytes"] = len(
|
||||
dynamo_json_dump(self.record["dynamodb"])
|
||||
)
|
||||
|
||||
def to_json(self):
|
||||
return self.record
|
||||
@ -1484,7 +1486,10 @@ class DynamoDBBackend(BaseBackend):
|
||||
return table.ttl
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("dynamodb")
|
||||
dynamodb_backends = {
|
||||
region: DynamoDBBackend(region_name=region) for region in available_regions
|
||||
}
|
||||
dynamodb_backends = {}
|
||||
for region in Session().get_available_regions("dynamodb"):
|
||||
dynamodb_backends[region] = DynamoDBBackend(region)
|
||||
for region in Session().get_available_regions("dynamodb", partition_name="aws-us-gov"):
|
||||
dynamodb_backends[region] = DynamoDBBackend(region)
|
||||
for region in Session().get_available_regions("dynamodb", partition_name="aws-cn"):
|
||||
dynamodb_backends[region] = DynamoDBBackend(region)
|
||||
|
@ -2,9 +2,10 @@ from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import json
|
||||
import boto3
|
||||
import base64
|
||||
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.dynamodb2.models import dynamodb_backends
|
||||
|
||||
@ -139,7 +140,14 @@ class DynamoDBStreamsBackend(BaseBackend):
|
||||
return json.dumps(shard_iterator.get(limit))
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("dynamodbstreams")
|
||||
dynamodbstreams_backends = {
|
||||
region: DynamoDBStreamsBackend(region=region) for region in available_regions
|
||||
}
|
||||
dynamodbstreams_backends = {}
|
||||
for region in Session().get_available_regions("dynamodbstreams"):
|
||||
dynamodbstreams_backends[region] = DynamoDBStreamsBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"dynamodbstreams", partition_name="aws-us-gov"
|
||||
):
|
||||
dynamodbstreams_backends[region] = DynamoDBStreamsBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"dynamodbstreams", partition_name="aws-cn"
|
||||
):
|
||||
dynamodbstreams_backends[region] = DynamoDBStreamsBackend(region)
|
||||
|
@ -8,9 +8,9 @@ import os
|
||||
import re
|
||||
import six
|
||||
import warnings
|
||||
from pkg_resources import resource_filename
|
||||
|
||||
import boto.ec2
|
||||
from boto3 import Session
|
||||
from pkg_resources import resource_filename
|
||||
|
||||
from collections import defaultdict
|
||||
import weakref
|
||||
@ -1473,7 +1473,13 @@ class Zone(object):
|
||||
|
||||
|
||||
class RegionsAndZonesBackend(object):
|
||||
regions = [Region(ri.name, ri.endpoint) for ri in boto.ec2.regions()]
|
||||
regions = []
|
||||
for region in Session().get_available_regions("ec2"):
|
||||
regions.append(Region(region, "ec2.{}.amazonaws.com".format(region)))
|
||||
for region in Session().get_available_regions("ec2", partition_name="aws-us-gov"):
|
||||
regions.append(Region(region, "ec2.{}.amazonaws.com".format(region)))
|
||||
for region in Session().get_available_regions("ec2", partition_name="aws-cn"):
|
||||
regions.append(Region(region, "ec2.{}.amazonaws.com.cn".format(region)))
|
||||
|
||||
zones = {
|
||||
"ap-south-1": [
|
||||
@ -1536,6 +1542,11 @@ class RegionsAndZonesBackend(object):
|
||||
zone_id="apne1-az2",
|
||||
),
|
||||
],
|
||||
"ap-east-1": [
|
||||
Zone(region_name="ap-east-1", name="ap-east-1a", zone_id="ape1-az1"),
|
||||
Zone(region_name="ap-east-1", name="ap-east-1b", zone_id="ape1-az2"),
|
||||
Zone(region_name="ap-east-1", name="ap-east-1c", zone_id="ape1-az3"),
|
||||
],
|
||||
"sa-east-1": [
|
||||
Zone(region_name="sa-east-1", name="sa-east-1a", zone_id="sae1-az1"),
|
||||
Zone(region_name="sa-east-1", name="sa-east-1c", zone_id="sae1-az3"),
|
||||
@ -1605,10 +1616,32 @@ class RegionsAndZonesBackend(object):
|
||||
Zone(region_name="us-west-2", name="us-west-2b", zone_id="usw2-az1"),
|
||||
Zone(region_name="us-west-2", name="us-west-2c", zone_id="usw2-az3"),
|
||||
],
|
||||
"me-south-1": [
|
||||
Zone(region_name="me-south-1", name="me-south-1a", zone_id="mes1-az1"),
|
||||
Zone(region_name="me-south-1", name="me-south-1b", zone_id="mes1-az2"),
|
||||
Zone(region_name="me-south-1", name="me-south-1c", zone_id="mes1-az3"),
|
||||
],
|
||||
"cn-north-1": [
|
||||
Zone(region_name="cn-north-1", name="cn-north-1a", zone_id="cnn1-az1"),
|
||||
Zone(region_name="cn-north-1", name="cn-north-1b", zone_id="cnn1-az2"),
|
||||
],
|
||||
"cn-northwest-1": [
|
||||
Zone(
|
||||
region_name="cn-northwest-1",
|
||||
name="cn-northwest-1a",
|
||||
zone_id="cnnw1-az1",
|
||||
),
|
||||
Zone(
|
||||
region_name="cn-northwest-1",
|
||||
name="cn-northwest-1b",
|
||||
zone_id="cnnw1-az2",
|
||||
),
|
||||
Zone(
|
||||
region_name="cn-northwest-1",
|
||||
name="cn-northwest-1c",
|
||||
zone_id="cnnw1-az3",
|
||||
),
|
||||
],
|
||||
"us-gov-west-1": [
|
||||
Zone(
|
||||
region_name="us-gov-west-1", name="us-gov-west-1a", zone_id="usgw1-az1"
|
||||
@ -1620,6 +1653,17 @@ class RegionsAndZonesBackend(object):
|
||||
region_name="us-gov-west-1", name="us-gov-west-1c", zone_id="usgw1-az3"
|
||||
),
|
||||
],
|
||||
"us-gov-east-1": [
|
||||
Zone(
|
||||
region_name="us-gov-east-1", name="us-gov-east-1a", zone_id="usge1-az1"
|
||||
),
|
||||
Zone(
|
||||
region_name="us-gov-east-1", name="us-gov-east-1b", zone_id="usge1-az2"
|
||||
),
|
||||
Zone(
|
||||
region_name="us-gov-east-1", name="us-gov-east-1c", zone_id="usge1-az3"
|
||||
),
|
||||
],
|
||||
}
|
||||
|
||||
def describe_regions(self, region_names=[]):
|
||||
|
@ -104,7 +104,7 @@ class SecurityGroups(BaseResponse):
|
||||
if self.is_not_dryrun("GrantSecurityGroupIngress"):
|
||||
for args in self._process_rules_from_querystring():
|
||||
self.ec2_backend.authorize_security_group_ingress(*args)
|
||||
return AUTHORIZE_SECURITY_GROUP_INGRESS_REPONSE
|
||||
return AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE
|
||||
|
||||
def create_security_group(self):
|
||||
name = self._get_param("GroupName")
|
||||
@ -158,7 +158,7 @@ class SecurityGroups(BaseResponse):
|
||||
if self.is_not_dryrun("RevokeSecurityGroupIngress"):
|
||||
for args in self._process_rules_from_querystring():
|
||||
self.ec2_backend.revoke_security_group_ingress(*args)
|
||||
return REVOKE_SECURITY_GROUP_INGRESS_REPONSE
|
||||
return REVOKE_SECURITY_GROUP_INGRESS_RESPONSE
|
||||
|
||||
|
||||
CREATE_SECURITY_GROUP_RESPONSE = """<CreateSecurityGroupResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
@ -265,12 +265,12 @@ DESCRIBE_SECURITY_GROUPS_RESPONSE = (
|
||||
</DescribeSecurityGroupsResponse>"""
|
||||
)
|
||||
|
||||
AUTHORIZE_SECURITY_GROUP_INGRESS_REPONSE = """<AuthorizeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
AUTHORIZE_SECURITY_GROUP_INGRESS_RESPONSE = """<AuthorizeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
|
||||
<return>true</return>
|
||||
</AuthorizeSecurityGroupIngressResponse>"""
|
||||
|
||||
REVOKE_SECURITY_GROUP_INGRESS_REPONSE = """<RevokeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
REVOKE_SECURITY_GROUP_INGRESS_RESPONSE = """<RevokeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||
<requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
|
||||
<return>true</return>
|
||||
</RevokeSecurityGroupIngressResponse>"""
|
||||
|
@ -2,6 +2,6 @@ from __future__ import unicode_literals
|
||||
from .responses import EC2Response
|
||||
|
||||
|
||||
url_bases = ["https?://ec2.(.+).amazonaws.com(|.cn)"]
|
||||
url_bases = ["https?://ec2\.(.+)\.amazonaws\.com(|\.cn)"]
|
||||
|
||||
url_paths = {"{0}/": EC2Response.dispatch}
|
||||
|
4
moto/ec2_instance_connect/__init__.py
Normal file
4
moto/ec2_instance_connect/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from ..core.models import base_decorator
|
||||
from .models import ec2_instance_connect_backends
|
||||
|
||||
mock_ec2_instance_connect = base_decorator(ec2_instance_connect_backends)
|
11
moto/ec2_instance_connect/models.py
Normal file
11
moto/ec2_instance_connect/models.py
Normal file
@ -0,0 +1,11 @@
|
||||
import boto
|
||||
from moto.core import BaseBackend
|
||||
|
||||
|
||||
class Ec2InstanceConnectBackend(BaseBackend):
|
||||
pass
|
||||
|
||||
|
||||
ec2_instance_connect_backends = {}
|
||||
for region in boto.ec2.regions():
|
||||
ec2_instance_connect_backends[region.name] = Ec2InstanceConnectBackend()
|
9
moto/ec2_instance_connect/responses.py
Normal file
9
moto/ec2_instance_connect/responses.py
Normal file
@ -0,0 +1,9 @@
|
||||
import json
|
||||
from moto.core.responses import BaseResponse
|
||||
|
||||
|
||||
class Ec2InstanceConnectResponse(BaseResponse):
|
||||
def send_ssh_public_key(self):
|
||||
return json.dumps(
|
||||
{"RequestId": "example-2a47-4c91-9700-e37e85162cb6", "Success": True}
|
||||
)
|
6
moto/ec2_instance_connect/urls.py
Normal file
6
moto/ec2_instance_connect/urls.py
Normal file
@ -0,0 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
from .responses import Ec2InstanceConnectResponse
|
||||
|
||||
url_bases = ["https?://ec2-instance-connect\.(.+)\.amazonaws\.com"]
|
||||
|
||||
url_paths = {"{0}/$": Ec2InstanceConnectResponse.dispatch}
|
@ -3,9 +3,10 @@ import re
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from random import random, randint
|
||||
import boto3
|
||||
|
||||
import pytz
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core.exceptions import JsonRESTError
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import unix_time
|
||||
@ -117,6 +118,7 @@ class TaskDefinition(BaseObject):
|
||||
revision,
|
||||
container_definitions,
|
||||
region_name,
|
||||
network_mode=None,
|
||||
volumes=None,
|
||||
tags=None,
|
||||
):
|
||||
@ -131,6 +133,10 @@ class TaskDefinition(BaseObject):
|
||||
self.volumes = []
|
||||
else:
|
||||
self.volumes = volumes
|
||||
if network_mode is None:
|
||||
self.network_mode = "bridge"
|
||||
else:
|
||||
self.network_mode = network_mode
|
||||
|
||||
@property
|
||||
def response_object(self):
|
||||
@ -552,7 +558,7 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
raise Exception("{0} is not a cluster".format(cluster_name))
|
||||
|
||||
def register_task_definition(
|
||||
self, family, container_definitions, volumes, tags=None
|
||||
self, family, container_definitions, volumes=None, network_mode=None, tags=None
|
||||
):
|
||||
if family in self.task_definitions:
|
||||
last_id = self._get_last_task_definition_revision_id(family)
|
||||
@ -561,7 +567,13 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
self.task_definitions[family] = {}
|
||||
revision = 1
|
||||
task_definition = TaskDefinition(
|
||||
family, revision, container_definitions, self.region_name, volumes, tags
|
||||
family,
|
||||
revision,
|
||||
container_definitions,
|
||||
self.region_name,
|
||||
volumes=volumes,
|
||||
network_mode=network_mode,
|
||||
tags=tags,
|
||||
)
|
||||
self.task_definitions[family][revision] = task_definition
|
||||
|
||||
@ -1302,7 +1314,10 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("ecs")
|
||||
ecs_backends = {
|
||||
region: EC2ContainerServiceBackend(region) for region in available_regions
|
||||
}
|
||||
ecs_backends = {}
|
||||
for region in Session().get_available_regions("ecs"):
|
||||
ecs_backends[region] = EC2ContainerServiceBackend(region)
|
||||
for region in Session().get_available_regions("ecs", partition_name="aws-us-gov"):
|
||||
ecs_backends[region] = EC2ContainerServiceBackend(region)
|
||||
for region in Session().get_available_regions("ecs", partition_name="aws-cn"):
|
||||
ecs_backends[region] = EC2ContainerServiceBackend(region)
|
||||
|
@ -62,8 +62,13 @@ class EC2ContainerServiceResponse(BaseResponse):
|
||||
container_definitions = self._get_param("containerDefinitions")
|
||||
volumes = self._get_param("volumes")
|
||||
tags = self._get_param("tags")
|
||||
network_mode = self._get_param("networkMode")
|
||||
task_definition = self.ecs_backend.register_task_definition(
|
||||
family, container_definitions, volumes, tags
|
||||
family,
|
||||
container_definitions,
|
||||
volumes=volumes,
|
||||
network_mode=network_mode,
|
||||
tags=tags,
|
||||
)
|
||||
return json.dumps({"taskDefinition": task_definition.response_object})
|
||||
|
||||
|
@ -2,8 +2,8 @@ from __future__ import unicode_literals
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
import boto.emr
|
||||
import pytz
|
||||
from boto3 import Session
|
||||
from dateutil.parser import parse as dtparse
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.emr.exceptions import EmrError
|
||||
@ -460,5 +460,9 @@ class ElasticMapReduceBackend(BaseBackend):
|
||||
|
||||
|
||||
emr_backends = {}
|
||||
for region in boto.emr.regions():
|
||||
emr_backends[region.name] = ElasticMapReduceBackend(region.name)
|
||||
for region in Session().get_available_regions("emr"):
|
||||
emr_backends[region] = ElasticMapReduceBackend(region)
|
||||
for region in Session().get_available_regions("emr", partition_name="aws-us-gov"):
|
||||
emr_backends[region] = ElasticMapReduceBackend(region)
|
||||
for region in Session().get_available_regions("emr", partition_name="aws-cn"):
|
||||
emr_backends[region] = ElasticMapReduceBackend(region)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import boto3
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core.exceptions import JsonRESTError
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
@ -362,5 +362,10 @@ class EventsBackend(BaseBackend):
|
||||
self.event_buses.pop(name, None)
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("events")
|
||||
events_backends = {region: EventsBackend(region) for region in available_regions}
|
||||
events_backends = {}
|
||||
for region in Session().get_available_regions("events"):
|
||||
events_backends[region] = EventsBackend(region)
|
||||
for region in Session().get_available_regions("events", partition_name="aws-us-gov"):
|
||||
events_backends[region] = EventsBackend(region)
|
||||
for region in Session().get_available_regions("events", partition_name="aws-cn"):
|
||||
events_backends[region] = EventsBackend(region)
|
||||
|
@ -4,8 +4,8 @@ import hashlib
|
||||
|
||||
import datetime
|
||||
|
||||
from boto3 import Session
|
||||
|
||||
import boto.glacier
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
from .utils import get_job_id
|
||||
@ -221,5 +221,9 @@ class GlacierBackend(BaseBackend):
|
||||
|
||||
|
||||
glacier_backends = {}
|
||||
for region in boto.glacier.regions():
|
||||
glacier_backends[region.name] = GlacierBackend(region)
|
||||
for region in Session().get_available_regions("glacier"):
|
||||
glacier_backends[region] = GlacierBackend(region)
|
||||
for region in Session().get_available_regions("glacier", partition_name="aws-us-gov"):
|
||||
glacier_backends[region] = GlacierBackend(region)
|
||||
for region in Session().get_available_regions("glacier", partition_name="aws-cn"):
|
||||
glacier_backends[region] = GlacierBackend(region)
|
||||
|
@ -543,7 +543,7 @@ class Group(BaseModel):
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
def __init__(self, name, path=None):
|
||||
def __init__(self, name, path=None, tags=None):
|
||||
self.name = name
|
||||
self.id = random_resource_id()
|
||||
self.path = path if path else "/"
|
||||
@ -556,6 +556,7 @@ class User(BaseModel):
|
||||
self.password = None
|
||||
self.password_reset_required = False
|
||||
self.signing_certificates = {}
|
||||
self.tags = tags
|
||||
|
||||
@property
|
||||
def arn(self):
|
||||
@ -1421,13 +1422,13 @@ class IAMBackend(BaseBackend):
|
||||
"The group with name {0} cannot be found.".format(group_name)
|
||||
)
|
||||
|
||||
def create_user(self, user_name, path="/"):
|
||||
def create_user(self, user_name, path="/", tags=None):
|
||||
if user_name in self.users:
|
||||
raise IAMConflictException(
|
||||
"EntityAlreadyExists", "User {0} already exists".format(user_name)
|
||||
)
|
||||
|
||||
user = User(user_name, path)
|
||||
user = User(user_name, path, tags)
|
||||
self.users[user_name] = user
|
||||
return user
|
||||
|
||||
@ -1583,6 +1584,10 @@ class IAMBackend(BaseBackend):
|
||||
user = self.get_user(user_name)
|
||||
return user.policies.keys()
|
||||
|
||||
def list_user_tags(self, user_name):
|
||||
user = self.get_user(user_name)
|
||||
return user.tags
|
||||
|
||||
def put_user_policy(self, user_name, policy_name, policy_json):
|
||||
user = self.get_user(user_name)
|
||||
|
||||
|
@ -440,8 +440,8 @@ class IamResponse(BaseResponse):
|
||||
def create_user(self):
|
||||
user_name = self._get_param("UserName")
|
||||
path = self._get_param("Path")
|
||||
|
||||
user = iam_backend.create_user(user_name, path)
|
||||
tags = self._get_multi_param("Tags.member")
|
||||
user = iam_backend.create_user(user_name, path, tags)
|
||||
template = self.response_template(USER_TEMPLATE)
|
||||
return template.render(action="Create", user=user)
|
||||
|
||||
@ -538,6 +538,12 @@ class IamResponse(BaseResponse):
|
||||
template = self.response_template(LIST_USER_POLICIES_TEMPLATE)
|
||||
return template.render(policies=policies)
|
||||
|
||||
def list_user_tags(self):
|
||||
user_name = self._get_param("UserName")
|
||||
tags = iam_backend.list_user_tags(user_name)
|
||||
template = self.response_template(LIST_USER_TAGS_TEMPLATE)
|
||||
return template.render(user_tags=tags or [])
|
||||
|
||||
def put_user_policy(self):
|
||||
user_name = self._get_param("UserName")
|
||||
policy_name = self._get_param("PolicyName")
|
||||
@ -1699,6 +1705,23 @@ LIST_USER_POLICIES_TEMPLATE = """<ListUserPoliciesResponse>
|
||||
</ResponseMetadata>
|
||||
</ListUserPoliciesResponse>"""
|
||||
|
||||
LIST_USER_TAGS_TEMPLATE = """<ListUserTagsResponse>
|
||||
<ListUserTagsResult>
|
||||
<Tags>
|
||||
{% for tag in user_tags %}
|
||||
<item>
|
||||
<Key>{{ tag.Key }}</Key>
|
||||
<Value>{{ tag.Value }}</Value>
|
||||
</item>
|
||||
{% endfor %}
|
||||
</Tags>
|
||||
<IsTruncated>false</IsTruncated>
|
||||
</ListUserTagsResult>
|
||||
<ResponseMetadata>
|
||||
<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
|
||||
</ResponseMetadata>
|
||||
</ListUserTagsResponse>"""
|
||||
|
||||
CREATE_ACCESS_KEY_TEMPLATE = """<CreateAccessKeyResponse>
|
||||
<CreateAccessKeyResult>
|
||||
<AccessKey>
|
||||
|
@ -9,7 +9,7 @@ import uuid
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime
|
||||
|
||||
import boto3
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from .exceptions import (
|
||||
@ -1160,5 +1160,10 @@ class IoTBackend(BaseBackend):
|
||||
return job_executions, next_token
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("iot")
|
||||
iot_backends = {region: IoTBackend(region) for region in available_regions}
|
||||
iot_backends = {}
|
||||
for region in Session().get_available_regions("iot"):
|
||||
iot_backends[region] = IoTBackend(region)
|
||||
for region in Session().get_available_regions("iot", partition_name="aws-us-gov"):
|
||||
iot_backends[region] = IoTBackend(region)
|
||||
for region in Session().get_available_regions("iot", partition_name="aws-cn"):
|
||||
iot_backends[region] = IoTBackend(region)
|
||||
|
@ -1,8 +1,9 @@
|
||||
from __future__ import unicode_literals
|
||||
import json
|
||||
import time
|
||||
import boto3
|
||||
import jsondiff
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.iot import iot_backends
|
||||
from .exceptions import (
|
||||
@ -205,5 +206,10 @@ class IoTDataPlaneBackend(BaseBackend):
|
||||
return None
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("iot-data")
|
||||
iotdata_backends = {region: IoTDataPlaneBackend(region) for region in available_regions}
|
||||
iotdata_backends = {}
|
||||
for region in Session().get_available_regions("iot-data"):
|
||||
iotdata_backends[region] = IoTDataPlaneBackend(region)
|
||||
for region in Session().get_available_regions("iot-data", partition_name="aws-us-gov"):
|
||||
iotdata_backends[region] = IoTDataPlaneBackend(region)
|
||||
for region in Session().get_available_regions("iot-data", partition_name="aws-cn"):
|
||||
iotdata_backends[region] = IoTDataPlaneBackend(region)
|
||||
|
@ -2,7 +2,6 @@ from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
import time
|
||||
import boto.kinesis
|
||||
import re
|
||||
import six
|
||||
import itertools
|
||||
@ -10,6 +9,8 @@ import itertools
|
||||
from operator import attrgetter
|
||||
from hashlib import md5
|
||||
|
||||
from boto3 import Session
|
||||
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import unix_time
|
||||
@ -530,5 +531,9 @@ class KinesisBackend(BaseBackend):
|
||||
|
||||
|
||||
kinesis_backends = {}
|
||||
for region in boto.kinesis.regions():
|
||||
kinesis_backends[region.name] = KinesisBackend()
|
||||
for region in Session().get_available_regions("kinesis"):
|
||||
kinesis_backends[region] = KinesisBackend()
|
||||
for region in Session().get_available_regions("kinesis", partition_name="aws-us-gov"):
|
||||
kinesis_backends[region] = KinesisBackend()
|
||||
for region in Session().get_available_regions("kinesis", partition_name="aws-cn"):
|
||||
kinesis_backends[region] = KinesisBackend()
|
||||
|
@ -4,7 +4,7 @@ import os
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import boto.kms
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core.utils import iso_8601_datetime_without_milliseconds
|
||||
@ -284,5 +284,9 @@ class KmsBackend(BaseBackend):
|
||||
|
||||
|
||||
kms_backends = {}
|
||||
for region in boto.kms.regions():
|
||||
kms_backends[region.name] = KmsBackend()
|
||||
for region in Session().get_available_regions("kms"):
|
||||
kms_backends[region] = KmsBackend()
|
||||
for region in Session().get_available_regions("kms", partition_name="aws-us-gov"):
|
||||
kms_backends[region] = KmsBackend()
|
||||
for region in Session().get_available_regions("kms", partition_name="aws-cn"):
|
||||
kms_backends[region] = KmsBackend()
|
||||
|
@ -1,5 +1,6 @@
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend
|
||||
import boto.logs
|
||||
from moto.core.utils import unix_time_millis
|
||||
from .exceptions import (
|
||||
ResourceNotFoundException,
|
||||
@ -558,6 +559,10 @@ class LogsBackend(BaseBackend):
|
||||
log_group.untag(tags)
|
||||
|
||||
|
||||
logs_backends = {
|
||||
region.name: LogsBackend(region.name) for region in boto.logs.regions()
|
||||
}
|
||||
logs_backends = {}
|
||||
for region in Session().get_available_regions("logs"):
|
||||
logs_backends[region] = LogsBackend(region)
|
||||
for region in Session().get_available_regions("logs", partition_name="aws-us-gov"):
|
||||
logs_backends[region] = LogsBackend(region)
|
||||
for region in Session().get_available_regions("logs", partition_name="aws-cn"):
|
||||
logs_backends[region] = LogsBackend(region)
|
||||
|
@ -2,7 +2,8 @@ from __future__ import unicode_literals
|
||||
from xml.etree import ElementTree as ET
|
||||
import datetime
|
||||
|
||||
import boto3
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
from .resources import VOICE_DATA
|
||||
@ -113,7 +114,10 @@ class PollyBackend(BaseBackend):
|
||||
self._lexicons[name] = lexicon
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("polly")
|
||||
polly_backends = {
|
||||
region: PollyBackend(region_name=region) for region in available_regions
|
||||
}
|
||||
polly_backends = {}
|
||||
for region in Session().get_available_regions("polly"):
|
||||
polly_backends[region] = PollyBackend(region)
|
||||
for region in Session().get_available_regions("polly", partition_name="aws-us-gov"):
|
||||
polly_backends[region] = PollyBackend(region)
|
||||
for region in Session().get_available_regions("polly", partition_name="aws-cn"):
|
||||
polly_backends[region] = PollyBackend(region)
|
||||
|
@ -5,7 +5,7 @@ import datetime
|
||||
import os
|
||||
|
||||
from collections import defaultdict
|
||||
import boto.rds2
|
||||
from boto3 import Session
|
||||
from jinja2 import Template
|
||||
from re import compile as re_compile
|
||||
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
|
||||
@ -1501,6 +1501,10 @@ class DBParameterGroup(object):
|
||||
return db_parameter_group
|
||||
|
||||
|
||||
rds2_backends = dict(
|
||||
(region.name, RDS2Backend(region.name)) for region in boto.rds2.regions()
|
||||
)
|
||||
rds2_backends = {}
|
||||
for region in Session().get_available_regions("rds"):
|
||||
rds2_backends[region] = RDS2Backend(region)
|
||||
for region in Session().get_available_regions("rds", partition_name="aws-us-gov"):
|
||||
rds2_backends[region] = RDS2Backend(region)
|
||||
for region in Session().get_available_regions("rds", partition_name="aws-cn"):
|
||||
rds2_backends[region] = RDS2Backend(region)
|
||||
|
@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
||||
import copy
|
||||
import datetime
|
||||
|
||||
import boto.redshift
|
||||
from boto3 import Session
|
||||
from botocore.exceptions import ClientError
|
||||
from moto.compat import OrderedDict
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
@ -897,7 +897,9 @@ class RedshiftBackend(BaseBackend):
|
||||
|
||||
|
||||
redshift_backends = {}
|
||||
for region in boto.redshift.regions():
|
||||
redshift_backends[region.name] = RedshiftBackend(
|
||||
ec2_backends[region.name], region.name
|
||||
)
|
||||
for region in Session().get_available_regions("redshift"):
|
||||
redshift_backends[region] = RedshiftBackend(ec2_backends[region], region)
|
||||
for region in Session().get_available_regions("redshift", partition_name="aws-us-gov"):
|
||||
redshift_backends[region] = RedshiftBackend(ec2_backends[region], region)
|
||||
for region in Session().get_available_regions("redshift", partition_name="aws-cn"):
|
||||
redshift_backends[region] = RedshiftBackend(ec2_backends[region], region)
|
||||
|
@ -1,10 +1,11 @@
|
||||
from __future__ import unicode_literals
|
||||
from builtins import str
|
||||
|
||||
import boto3
|
||||
import json
|
||||
import re
|
||||
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.core import ACCOUNT_ID
|
||||
from .exceptions import BadRequestException
|
||||
@ -350,7 +351,14 @@ class ResourceGroupsBackend(BaseBackend):
|
||||
return self.groups.by_name[group_name]
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("resource-groups")
|
||||
resourcegroups_backends = {
|
||||
region: ResourceGroupsBackend(region_name=region) for region in available_regions
|
||||
}
|
||||
resourcegroups_backends = {}
|
||||
for region in Session().get_available_regions("resource-groups"):
|
||||
resourcegroups_backends[region] = ResourceGroupsBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"resource-groups", partition_name="aws-us-gov"
|
||||
):
|
||||
resourcegroups_backends[region] = ResourceGroupsBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"resource-groups", partition_name="aws-cn"
|
||||
):
|
||||
resourcegroups_backends[region] = ResourceGroupsBackend(region)
|
||||
|
@ -1,7 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
import uuid
|
||||
import boto3
|
||||
import six
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend
|
||||
from moto.core.exceptions import RESTError
|
||||
|
||||
@ -636,9 +637,14 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend):
|
||||
# return failed_resources_map
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions(
|
||||
"resourcegroupstaggingapi"
|
||||
)
|
||||
resourcegroupstaggingapi_backends = {
|
||||
region: ResourceGroupsTaggingAPIBackend(region) for region in available_regions
|
||||
}
|
||||
resourcegroupstaggingapi_backends = {}
|
||||
for region in Session().get_available_regions("resourcegroupstaggingapi"):
|
||||
resourcegroupstaggingapi_backends[region] = ResourceGroupsTaggingAPIBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"resourcegroupstaggingapi", partition_name="aws-us-gov"
|
||||
):
|
||||
resourcegroupstaggingapi_backends[region] = ResourceGroupsTaggingAPIBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"resourcegroupstaggingapi", partition_name="aws-cn"
|
||||
):
|
||||
resourcegroupstaggingapi_backends[region] = ResourceGroupsTaggingAPIBackend(region)
|
||||
|
@ -271,6 +271,7 @@ LIST_RRSET_RESPONSE = """<ListResourceRecordSetsResponse xmlns="https://route53.
|
||||
{{ record_set.to_xml() }}
|
||||
{% endfor %}
|
||||
</ResourceRecordSets>
|
||||
<IsTruncated>false</IsTruncated>
|
||||
</ListResourceRecordSetsResponse>"""
|
||||
|
||||
CHANGE_RRSET_RESPONSE = """<ChangeResourceRecordSetsResponse xmlns="https://route53.amazonaws.com/doc/2012-12-12/">
|
||||
|
@ -1482,7 +1482,7 @@ S3_ALL_BUCKETS = """<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2
|
||||
{% for bucket in buckets %}
|
||||
<Bucket>
|
||||
<Name>{{ bucket.name }}</Name>
|
||||
<CreationDate>{{ bucket.creation_date }}</CreationDate>
|
||||
<CreationDate>{{ bucket.creation_date.isoformat() }}</CreationDate>
|
||||
</Bucket>
|
||||
{% endfor %}
|
||||
</Buckets>
|
||||
@ -1491,7 +1491,9 @@ S3_ALL_BUCKETS = """<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2
|
||||
S3_BUCKET_GET_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
||||
<Name>{{ bucket.name }}</Name>
|
||||
{% if prefix != None %}
|
||||
<Prefix>{{ prefix }}</Prefix>
|
||||
{% endif %}
|
||||
<MaxKeys>{{ max_keys }}</MaxKeys>
|
||||
<Delimiter>{{ delimiter }}</Delimiter>
|
||||
<IsTruncated>{{ is_truncated }}</IsTruncated>
|
||||
@ -1523,7 +1525,9 @@ S3_BUCKET_GET_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
S3_BUCKET_GET_RESPONSE_V2 = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
||||
<Name>{{ bucket.name }}</Name>
|
||||
{% if prefix != None %}
|
||||
<Prefix>{{ prefix }}</Prefix>
|
||||
{% endif %}
|
||||
<MaxKeys>{{ max_keys }}</MaxKeys>
|
||||
<KeyCount>{{ key_count }}</KeyCount>
|
||||
{% if delimiter %}
|
||||
@ -1684,7 +1688,9 @@ S3_BUCKET_GET_VERSIONING = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
S3_BUCKET_GET_VERSIONS = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ListVersionsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01">
|
||||
<Name>{{ bucket.name }}</Name>
|
||||
{% if prefix != None %}
|
||||
<Prefix>{{ prefix }}</Prefix>
|
||||
{% endif %}
|
||||
<KeyMarker>{{ key_marker }}</KeyMarker>
|
||||
<MaxKeys>{{ max_keys }}</MaxKeys>
|
||||
<IsTruncated>{{ is_truncated }}</IsTruncated>
|
||||
@ -1863,7 +1869,6 @@ S3_MULTIPART_LIST_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ID>75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a</ID>
|
||||
<DisplayName>webfile</DisplayName>
|
||||
</Owner>
|
||||
<StorageClass>STANDARD</StorageClass>
|
||||
<PartNumberMarker>1</PartNumberMarker>
|
||||
<NextPartNumberMarker>{{ count }}</NextPartNumberMarker>
|
||||
<MaxParts>{{ count }}</MaxParts>
|
||||
|
@ -6,7 +6,7 @@ import json
|
||||
import uuid
|
||||
import datetime
|
||||
|
||||
import boto3
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from .exceptions import (
|
||||
@ -491,7 +491,14 @@ class SecretsManagerBackend(BaseBackend):
|
||||
)
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("secretsmanager")
|
||||
secretsmanager_backends = {
|
||||
region: SecretsManagerBackend(region_name=region) for region in available_regions
|
||||
}
|
||||
secretsmanager_backends = {}
|
||||
for region in Session().get_available_regions("secretsmanager"):
|
||||
secretsmanager_backends[region] = SecretsManagerBackend(region_name=region)
|
||||
for region in Session().get_available_regions(
|
||||
"secretsmanager", partition_name="aws-us-gov"
|
||||
):
|
||||
secretsmanager_backends[region] = SecretsManagerBackend(region_name=region)
|
||||
for region in Session().get_available_regions(
|
||||
"secretsmanager", partition_name="aws-cn"
|
||||
):
|
||||
secretsmanager_backends[region] = SecretsManagerBackend(region_name=region)
|
||||
|
@ -397,10 +397,6 @@ class SNSBackend(BaseBackend):
|
||||
return self._get_values_nexttoken(self.topics, next_token)
|
||||
|
||||
def delete_topic(self, arn):
|
||||
topic = self.get_topic(arn)
|
||||
subscriptions = self._get_topic_subscriptions(topic)
|
||||
for sub in subscriptions:
|
||||
self.unsubscribe(sub.arn)
|
||||
self.topics.pop(arn)
|
||||
|
||||
def get_topic(self, arn):
|
||||
@ -466,7 +462,7 @@ class SNSBackend(BaseBackend):
|
||||
return None
|
||||
|
||||
def unsubscribe(self, subscription_arn):
|
||||
self.subscriptions.pop(subscription_arn)
|
||||
self.subscriptions.pop(subscription_arn, None)
|
||||
|
||||
def list_subscriptions(self, topic_arn=None, next_token=None):
|
||||
if topic_arn:
|
||||
@ -707,6 +703,10 @@ class SNSBackend(BaseBackend):
|
||||
sns_backends = {}
|
||||
for region in Session().get_available_regions("sns"):
|
||||
sns_backends[region] = SNSBackend(region)
|
||||
for region in Session().get_available_regions("sns", partition_name="aws-us-gov"):
|
||||
sns_backends[region] = SNSBackend(region)
|
||||
for region in Session().get_available_regions("sns", partition_name="aws-cn"):
|
||||
sns_backends[region] = SNSBackend(region)
|
||||
|
||||
|
||||
DEFAULT_EFFECTIVE_DELIVERY_POLICY = {
|
||||
|
@ -8,7 +8,7 @@ import six
|
||||
import struct
|
||||
from xml.sax.saxutils import escape
|
||||
|
||||
import boto.sqs
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core.exceptions import RESTError
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
@ -183,6 +183,7 @@ class Queue(BaseModel):
|
||||
"MaximumMessageSize",
|
||||
"MessageRetentionPeriod",
|
||||
"QueueArn",
|
||||
"RedrivePolicy",
|
||||
"ReceiveMessageWaitTimeSeconds",
|
||||
"VisibilityTimeout",
|
||||
]
|
||||
@ -857,5 +858,9 @@ class SQSBackend(BaseBackend):
|
||||
|
||||
|
||||
sqs_backends = {}
|
||||
for region in boto.sqs.regions():
|
||||
sqs_backends[region.name] = SQSBackend(region.name)
|
||||
for region in Session().get_available_regions("sqs"):
|
||||
sqs_backends[region] = SQSBackend(region)
|
||||
for region in Session().get_available_regions("sqs", partition_name="aws-us-gov"):
|
||||
sqs_backends[region] = SQSBackend(region)
|
||||
for region in Session().get_available_regions("sqs", partition_name="aws-cn"):
|
||||
sqs_backends[region] = SQSBackend(region)
|
||||
|
@ -1,6 +1,8 @@
|
||||
import boto
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend
|
||||
from moto.core.utils import iso_8601_datetime_without_milliseconds
|
||||
from moto.sts.models import ACCOUNT_ID
|
||||
@ -280,7 +282,12 @@ class StepFunctionBackend(BaseBackend):
|
||||
return ACCOUNT_ID
|
||||
|
||||
|
||||
stepfunction_backends = {
|
||||
_region.name: StepFunctionBackend(_region.name)
|
||||
for _region in boto.awslambda.regions()
|
||||
}
|
||||
stepfunction_backends = {}
|
||||
for region in Session().get_available_regions("stepfunctions"):
|
||||
stepfunction_backends[region] = StepFunctionBackend(region)
|
||||
for region in Session().get_available_regions(
|
||||
"stepfunctions", partition_name="aws-us-gov"
|
||||
):
|
||||
stepfunction_backends[region] = StepFunctionBackend(region)
|
||||
for region in Session().get_available_regions("stepfunctions", partition_name="aws-cn"):
|
||||
stepfunction_backends[region] = StepFunctionBackend(region)
|
||||
|
@ -1,6 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import boto.swf
|
||||
from boto3 import Session
|
||||
|
||||
from moto.core import BaseBackend
|
||||
|
||||
@ -418,5 +418,9 @@ class SWFBackend(BaseBackend):
|
||||
|
||||
|
||||
swf_backends = {}
|
||||
for region in boto.swf.regions():
|
||||
swf_backends[region.name] = SWFBackend(region.name)
|
||||
for region in Session().get_available_regions("swf"):
|
||||
swf_backends[region] = SWFBackend(region)
|
||||
for region in Session().get_available_regions("swf", partition_name="aws-us-gov"):
|
||||
swf_backends[region] = SWFBackend(region)
|
||||
for region in Session().get_available_regions("swf", partition_name="aws-cn"):
|
||||
swf_backends[region] = SWFBackend(region)
|
||||
|
@ -20,8 +20,8 @@ import jinja2
|
||||
from prompt_toolkit import (
|
||||
prompt
|
||||
)
|
||||
from prompt_toolkit.contrib.completers import WordCompleter
|
||||
from prompt_toolkit.shortcuts import print_tokens
|
||||
from prompt_toolkit.completion import WordCompleter
|
||||
from prompt_toolkit.shortcuts import print_formatted_text
|
||||
|
||||
from botocore import xform_name
|
||||
from botocore.session import Session
|
||||
@ -149,12 +149,12 @@ def append_mock_dict_to_backends_py(service):
|
||||
with open(path) as f:
|
||||
lines = [_.replace('\n', '') for _ in f.readlines()]
|
||||
|
||||
if any(_ for _ in lines if re.match(".*'{}': {}_backends.*".format(service, service), _)):
|
||||
if any(_ for _ in lines if re.match(".*\"{}\": {}_backends.*".format(service, service), _)):
|
||||
return
|
||||
filtered_lines = [_ for _ in lines if re.match(".*'.*':.*_backends.*", _)]
|
||||
filtered_lines = [_ for _ in lines if re.match(".*\".*\":.*_backends.*", _)]
|
||||
last_elem_line_index = lines.index(filtered_lines[-1])
|
||||
|
||||
new_line = " '{}': {}_backends,".format(service, get_escaped_service(service))
|
||||
new_line = " \"{}\": {}_backends,".format(service, get_escaped_service(service))
|
||||
prev_line = lines[last_elem_line_index]
|
||||
if not prev_line.endswith('{') and not prev_line.endswith(','):
|
||||
lines[last_elem_line_index] += ','
|
||||
|
@ -1,5 +1,5 @@
|
||||
from __future__ import unicode_literals
|
||||
import boto3
|
||||
from boto3 import Session
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
|
||||
|
||||
@ -16,5 +16,10 @@ class {{ service_class }}Backend(BaseBackend):
|
||||
# add methods from here
|
||||
|
||||
|
||||
available_regions = boto3.session.Session().get_available_regions("{{ service }}")
|
||||
{{ escaped_service }}_backends = {region: {{ service_class }}Backend(region) for region in available_regions}
|
||||
{{ escaped_service }}_backends = {}
|
||||
for region in Session().get_available_regions("{{ service }}"):
|
||||
{{ escaped_service }}_backends[region] = {{ service_class }}Backend()
|
||||
for region in Session().get_available_regions("{{ service }}", partition_name="aws-us-gov"):
|
||||
{{ escaped_service }}_backends[region] = {{ service_class }}Backend()
|
||||
for region in Session().get_available_regions("{{ service }}", partition_name="aws-cn"):
|
||||
{{ escaped_service }}_backends[region] = {{ service_class }}Backend()
|
||||
|
2
setup.py
2
setup.py
@ -43,7 +43,7 @@ install_requires = [
|
||||
"python-jose<4.0.0",
|
||||
"mock",
|
||||
"docker>=2.5.1",
|
||||
"jsondiff==1.1.2",
|
||||
"jsondiff>=1.1.2",
|
||||
"aws-xray-sdk!=0.96,>=0.93",
|
||||
"responses>=0.9.0",
|
||||
"idna<2.9,>=2.5",
|
||||
|
@ -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,
|
||||
}
|
||||
],
|
||||
|
@ -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
|
||||
|
222
tests/test_codecommit/test_codecommit.py
Normal file
222
tests/test_codecommit/test_codecommit.py
Normal 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. "
|
||||
)
|
@ -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"}],
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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"])
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"]
|
||||
]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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():
|
||||
|
@ -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():
|
||||
|
@ -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}
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user