Introduce Github Actions to replace TravisCI (#3610)

This commit is contained in:
Bert Blommers 2021-01-26 12:37:03 +00:00 committed by GitHub
parent 5a41866f71
commit 8591eda9d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 364 additions and 240 deletions

View File

@ -9,3 +9,4 @@ exclude_lines =
[run]
include = moto/*
omit = moto/packages/*
source = moto

View File

@ -1,7 +1,191 @@
name: Example Action
on: [push]
name: TestNDeploy
on:
push:
branches:
- master
pull_request:
jobs:
job1:
# Install and cache dependencies
cache:
name: Caching
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ 2.7, 3.6, 3.7, 3.8 ]
steps:
- run: echo "Test"
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Get pip cache dir
id: pip-cache-dir
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: pip cache
id: pip-cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache-dir.outputs.dir }}
key: pip-${{ matrix.python-version }}-${{ hashFiles('**/requirements-dev.txt') }}
- name: Install Linux dependencies
if: ${{ matrix.python-version == 3.8 && steps.pip-cache.outputs.cache-hit != 'true' }}
run: |
sudo apt-get install libxslt-dev libxml2-dev -y
- name: Install project dependencies
if: ${{ steps.pip-cache.outputs.cache-hit != 'true' }}
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
lint:
name: Linting
runs-on: ubuntu-latest
needs: cache
strategy:
matrix:
python-version: [3.7]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
# Retrieve the previously cached dependencies
- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: pip cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: pip-${{ matrix.python-version }}-${{ hashFiles('**/requirements-dev.txt') }}
# Still need to properly install the dependencies - it will only skip the download part
- name: Install project dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Lint with flake8
run:
make lint
test:
name: Unit test
runs-on: ubuntu-latest
needs: lint
strategy:
fail-fast: false
matrix:
python-version: [2.7, 3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: pip cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: pip-${{ matrix.python-version }}-${{ hashFiles('**/requirements-dev.txt') }}
- name: Install Linux dependencies
if: ${{ matrix.python-version == 3.8 }}
run: |
sudo apt-get install libxslt-dev libxml2-dev -y
- name: Install project dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
pip install pytest-cov
- name: Test with pytest
if: ${{ matrix.python-version != 3.7 }}
run: |
make test-only
# Only need to configure coverage once
# Pytest-cov explicitly fails in Py2 for XRay tests
- name: Test with pytest/coverage
if: ${{ matrix.python-version == 3.7 }}
run: |
make test-coverage
- name: "Upload coverage to Codecov"
if: ${{ matrix.python-version == 3.7 }}
uses: codecov/codecov-action@v1
with:
fail_ci_if_error: true
testserver:
name: Unit tests in Server Mode
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
python-version: [2.7, 3.6, 3.7, 3.8]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Start MotoServer
run: |
python setup.py sdist
docker run --rm -t --name motoserver -e TEST_SERVER_MODE=true -e AWS_SECRET_ACCESS_KEY=server_secret -e AWS_ACCESS_KEY_ID=server_key -v `pwd`:/moto -p 5000:5000 -v /var/run/docker.sock:/var/run/docker.sock python:3.7-buster /moto/travis_moto_server.sh &
python wait_for.py
- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: pip cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: pip-${{ matrix.python-version }}-${{ hashFiles('**/requirements-dev.txt') }}
- name: Install Linux dependencies
if: ${{ matrix.python-version == 3.8 }}
run: |
sudo apt-get install libxslt-dev libxml2-dev -y
- name: Install project dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Test ServerMode
env:
TEST_SERVER_MODE: ${{ true }}
run: |
make test-only
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: [test, testserver]
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
strategy:
matrix:
python-version: [3.8]
steps:
- uses: actions/checkout@v2
- name: Update project version
run: |
git fetch --unshallow
python update_version_from_git.py
- name: Build project
run: |
pip install wheel
python setup.py sdist bdist_wheel
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
password: ${{ secrets.PYPI_API_TOKEN }}

View File

@ -1,68 +0,0 @@
dist: focal
language: python
services:
- docker
python:
- 2.7
- 3.6
- 3.7
- 3.8
env:
- TEST_SERVER_MODE=false
- TEST_SERVER_MODE=true
before_install:
- export BOTO_CONFIG=/dev/null
install:
- |
python setup.py sdist
if [ "$TEST_SERVER_MODE" = "true" ]; then
if [ "$TRAVIS_PYTHON_VERSION" = "3.8" ]; then
# Python 3.8 does not provide Stretch images yet [1]
# [1] https://github.com/docker-library/python/issues/428
PYTHON_DOCKER_TAG=${TRAVIS_PYTHON_VERSION}-buster
else
PYTHON_DOCKER_TAG=${TRAVIS_PYTHON_VERSION}-stretch
fi
docker run --rm -t --name motoserver -e TEST_SERVER_MODE=true -e AWS_SECRET_ACCESS_KEY=server_secret -e AWS_ACCESS_KEY_ID=server_key -v `pwd`:/moto -p 5000:5000 -v /var/run/docker.sock:/var/run/docker.sock python:${PYTHON_DOCKER_TAG} /moto/travis_moto_server.sh &
fi
travis_retry pip install -r requirements-dev.txt
travis_retry pip install docker>=2.5.1
travis_retry pip install boto==2.45.0
travis_retry pip install boto3
travis_retry pip install dist/moto*.gz
travis_retry pip install coveralls==1.1
travis_retry pip install coverage==4.5.4
if [ "$TEST_SERVER_MODE" = "true" ]; then
python wait_for.py
fi
before_script:
- if [[ $TRAVIS_PYTHON_VERSION == "3.7" ]]; then make lint; fi
script:
- make test-only
after_success:
- coveralls
before_deploy:
- git checkout $TRAVIS_BRANCH
- git fetch --unshallow
- python update_version_from_git.py
deploy:
- provider: pypi
distributions: sdist bdist_wheel
user: spulec
password:
secure: NxnPylnTfekJmGyoufCw0lMoYRskSMJzvAIyAlJJVYKwEhmiCPOrdy5qV8i8mRZ1AkUsqU3jBZ/PD56n96clHW0E3d080UleRDj6JpyALVdeLfMqZl9kLmZ8bqakWzYq3VSJKw2zGP/L4tPGf8wTK1SUv9yl/YNDsBdCkjDverw=
on:
branch:
- master
skip_cleanup: true
skip_existing: true
# - provider: pypi
# distributions: sdist bdist_wheel
# user: spulec
# password:
# secure: NxnPylnTfekJmGyoufCw0lMoYRskSMJzvAIyAlJJVYKwEhmiCPOrdy5qV8i8mRZ1AkUsqU3jBZ/PD56n96clHW0E3d080UleRDj6JpyALVdeLfMqZl9kLmZ8bqakWzYq3VSJKw2zGP/L4tPGf8wTK1SUv9yl/YNDsBdCkjDverw=
# on:
# tags: true
# skip_existing: true

View File

@ -26,7 +26,12 @@ format:
test-only:
rm -f .coverage
rm -rf cover
@pytest -sv --cov=moto --cov-report html ./tests/ $(TEST_EXCLUDE)
pytest -sv ./tests/ $(TEST_EXCLUDE)
test-coverage:
rm -f .coverage
rm -rf cover
pytest -sv --cov=moto --cov-report xml ./tests/ $(TEST_EXCLUDE)
test: lint test-only

View File

@ -2,7 +2,7 @@
[![Join the chat at https://gitter.im/awsmoto/Lobby](https://badges.gitter.im/awsmoto/Lobby.svg)](https://gitter.im/awsmoto/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/spulec/moto.svg?branch=master)](https://travis-ci.org/spulec/moto)
[![Build Status](https://github.com/spulec/moto/workflows/TestNDeploy/badge.svg)](https://github.com/spulec/moto/actions)
[![Coverage Status](https://coveralls.io/repos/spulec/moto/badge.svg?branch=master)](https://coveralls.io/r/spulec/moto)
[![Docs](https://readthedocs.org/projects/pip/badge/?version=stable)](http://docs.getmoto.org)
![PyPI](https://img.shields.io/pypi/v/moto.svg)
@ -441,8 +441,8 @@ As a result, you need to add that entry to your host file for your tests to func
## Releases
Releases are done from travisci. Fairly closely following this:
https://docs.travis-ci.com/user/deployment/pypi/
Releases are done from Gitlab Actions. Fairly closely following this:
https://packaging.python.org/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
- Commits to `master` branch do a dev deploy to pypi.
- Commits to a tag do a real deploy to pypi.

View File

@ -4,3 +4,6 @@ universal=1
[tool:pytest]
markers =
network: marks tests which require network connection
[coverage:run]
relative_files = True

View File

@ -2523,6 +2523,16 @@ def test_create_open_id_connect_provider():
)
@pytest.mark.parametrize("url", ["example.org", "example"])
@mock_iam
def test_create_open_id_connect_provider_invalid_url(url):
client = boto3.client("iam", region_name="us-east-1")
with pytest.raises(ClientError) as e:
client.create_open_id_connect_provider(Url=url, ThumbprintList=[])
msg = e.value.response["Error"]["Message"]
msg.should.contain("Invalid Open ID Connect Provider URL")
@mock_iam
def test_create_open_id_connect_provider_errors():
client = boto3.client("iam", region_name="us-east-1")
@ -2532,49 +2542,65 @@ def test_create_open_id_connect_provider_errors():
Url="https://example.com", ThumbprintList=[]
).should.throw(ClientError, "Unknown")
client.create_open_id_connect_provider.when.called_with(
Url="example.org", ThumbprintList=[]
).should.throw(ClientError, "Invalid Open ID Connect Provider URL")
client.create_open_id_connect_provider.when.called_with(
Url="example", ThumbprintList=[]
).should.throw(ClientError, "Invalid Open ID Connect Provider URL")
@mock_iam
def test_create_open_id_connect_provider_too_many_entries():
client = boto3.client("iam", region_name="us-east-1")
client.create_open_id_connect_provider.when.called_with(
Url="http://example.org",
ThumbprintList=["a" * 40, "b" * 40, "c" * 40, "d" * 40, "e" * 40, "f" * 40,],
).should.throw(ClientError, "Thumbprint list must contain fewer than 5 entries.")
with pytest.raises(ClientError) as e:
client.create_open_id_connect_provider(
Url="http://example.org",
ThumbprintList=[
"a" * 40,
"b" * 40,
"c" * 40,
"d" * 40,
"e" * 40,
"f" * 40,
],
)
msg = e.value.response["Error"]["Message"]
msg.should.contain("Thumbprint list must contain fewer than 5 entries.")
@mock_iam
def test_create_open_id_connect_provider_quota_error():
client = boto3.client("iam", region_name="us-east-1")
too_many_client_ids = ["{}".format(i) for i in range(101)]
client.create_open_id_connect_provider.when.called_with(
Url="http://example.org", ThumbprintList=[], ClientIDList=too_many_client_ids,
).should.throw(
ClientError, "Cannot exceed quota for ClientIdsPerOpenIdConnectProvider: 100",
)
with pytest.raises(ClientError) as e:
client.create_open_id_connect_provider(
Url="http://example.org",
ThumbprintList=[],
ClientIDList=too_many_client_ids,
)
msg = e.value.response["Error"]["Message"]
msg.should.contain("Cannot exceed quota for ClientIdsPerOpenIdConnectProvider: 100")
@mock_iam
def test_create_open_id_connect_provider_multiple_errors():
client = boto3.client("iam", region_name="us-east-1")
too_long_url = "b" * 256
too_long_thumbprint = "b" * 41
too_long_client_id = "b" * 256
client.create_open_id_connect_provider.when.called_with(
Url=too_long_url,
ThumbprintList=[too_long_thumbprint],
ClientIDList=[too_long_client_id],
).should.throw(
ClientError,
"3 validation errors detected: "
'Value "{0}" at "clientIDList" failed to satisfy constraint: '
"Member must satisfy constraint: "
"[Member must have length less than or equal to 255, "
"Member must have length greater than or equal to 1]; "
'Value "{1}" at "thumbprintList" failed to satisfy constraint: '
"Member must satisfy constraint: "
"[Member must have length less than or equal to 40, "
"Member must have length greater than or equal to 40]; "
'Value "{2}" at "url" failed to satisfy constraint: '
"Member must have length less than or equal to 255".format(
[too_long_client_id], [too_long_thumbprint], too_long_url
),
)
with pytest.raises(ClientError) as e:
client.create_open_id_connect_provider(
Url=too_long_url,
ThumbprintList=[too_long_thumbprint],
ClientIDList=[too_long_client_id],
)
msg = e.value.response["Error"]["Message"]
msg.should.contain("3 validation errors detected:")
msg.should.contain('"clientIDList" failed to satisfy constraint:')
msg.should.contain("Member must have length less than or equal to 255")
msg.should.contain("Member must have length greater than or equal to 1")
msg.should.contain('"thumbprintList" failed to satisfy constraint:')
msg.should.contain("Member must have length less than or equal to 40")
msg.should.contain("Member must have length greater than or equal to 40")
msg.should.contain('"url" failed to satisfy constraint:')
msg.should.contain("Member must have length less than or equal to 255")
@mock_iam

View File

@ -831,9 +831,8 @@ def test_describe_parameters_with_parameter_filters_path():
@mock_ssm
def test_describe_parameters_invalid_parameter_filters():
def test_describe_parameters_needs_param():
client = boto3.client("ssm", region_name="us-east-1")
client.describe_parameters.when.called_with(
Filters=[{"Key": "Name", "Values": ["test"]}],
ParameterFilters=[{"Key": "Name", "Values": ["test"]}],
@ -842,145 +841,119 @@ def test_describe_parameters_invalid_parameter_filters():
"You can use either Filters or ParameterFilters in a single request.",
)
client.describe_parameters.when.called_with(ParameterFilters=[{}]).should.throw(
ParamValidationError,
'Parameter validation failed:\nMissing required parameter in ParameterFilters[0]: "Key"',
)
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "key"}]
).should.throw(
ClientError,
'1 validation error detected: Value "key" at "parameterFilters.1.member.key" failed to satisfy constraint: '
"Member must satisfy regular expression pattern: tag:.+|Name|Type|KeyId|Path|Label|Tier",
)
long_key = "tag:" + "t" * 129
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": long_key}]
).should.throw(
ClientError,
'1 validation error detected: Value "{value}" at "parameterFilters.1.member.key" failed to satisfy constraint: '
"Member must have length less than or equal to 132".format(value=long_key),
)
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Name", "Option": "over 10 chars"}]
).should.throw(
ClientError,
'1 validation error detected: Value "over 10 chars" at "parameterFilters.1.member.option" failed to satisfy constraint: '
"Member must have length less than or equal to 10",
)
many_values = ["test"] * 51
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Name", "Values": many_values}]
).should.throw(
ClientError,
'1 validation error detected: Value "{value}" at "parameterFilters.1.member.values" failed to satisfy constraint: '
"Member must have length less than or equal to 50".format(value=many_values),
)
long_value = ["t" * 1025]
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Name", "Values": long_value}]
).should.throw(
ClientError,
'1 validation error detected: Value "{value}" at "parameterFilters.1.member.values" failed to satisfy constraint: '
"[Member must have length less than or equal to 1024, Member must have length greater than or equal to 1]".format(
value=long_value
@pytest.mark.parametrize(
"filters,error_msg",
[
(
[{"Key": "key"}],
"Member must satisfy regular expression pattern: tag:.+|Name|Type|KeyId|Path|Label|Tier",
),
)
(
[{"Key": "tag:" + "t" * 129}],
"Member must have length less than or equal to 132",
),
(
[{"Key": "Name", "Option": "over 10 chars"}],
"Member must have length less than or equal to 10",
),
(
[{"Key": "Name", "Values": ["test"] * 51}],
"Member must have length less than or equal to 50",
),
(
[{"Key": "Name", "Values": ["t" * 1025]}],
"Member must have length less than or equal to 1024, Member must have length greater than or equal to 1",
),
(
[{"Key": "Name", "Option": "over 10 chars"}, {"Key": "key"}],
"2 validation errors detected:",
),
(
[{"Key": "Label"}],
"The following filter key is not valid: Label. Valid filter keys include: [Path, Name, Type, KeyId, Tier]",
),
(
[{"Key": "Name"}],
"The following filter values are missing : null for filter key Name",
),
(
[
{"Key": "Name", "Values": ["test"]},
{"Key": "Name", "Values": ["test test"]},
],
"The following filter is duplicated in the request: Name. A request can contain only one occurrence of a specific filter.",
),
(
[{"Key": "Path", "Values": ["/aws", "/ssm"]}],
'Filters for common parameters can\'t be prefixed with "aws" or "ssm" (case-insensitive).',
),
(
[{"Key": "Path", "Option": "Equals", "Values": ["test"]}],
"The following filter option is not valid: Equals. Valid options include: [Recursive, OneLevel]",
),
(
[{"Key": "Tier", "Values": ["test"]}],
"The following filter value is not valid: test. Valid values include: [Standard, Advanced, Intelligent-Tiering]",
),
(
[{"Key": "Type", "Values": ["test"]}],
"The following filter value is not valid: test. Valid values include: [String, StringList, SecureString]",
),
(
[{"Key": "Name", "Option": "option", "Values": ["test"]}],
"The following filter option is not valid: option. Valid options include: [BeginsWith, Equals].",
),
],
)
@mock_ssm
def test_describe_parameters_invalid_parameter_filters(filters, error_msg):
client = boto3.client("ssm", region_name="us-east-1")
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Name", "Option": "over 10 chars"}, {"Key": "key"}]
).should.throw(
ClientError,
"2 validation errors detected: "
'Value "over 10 chars" at "parameterFilters.1.member.option" failed to satisfy constraint: '
"Member must have length less than or equal to 10; "
'Value "key" at "parameterFilters.2.member.key" failed to satisfy constraint: '
"Member must satisfy regular expression pattern: tag:.+|Name|Type|KeyId|Path|Label|Tier",
)
with pytest.raises(ClientError) as e:
client.describe_parameters(ParameterFilters=filters)
e.value.response["Error"]["Message"].should.contain(error_msg)
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Label"}]
).should.throw(
ClientError,
"The following filter key is not valid: Label. Valid filter keys include: [Path, Name, Type, KeyId, Tier].",
)
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Name"}]
).should.throw(
ClientError,
"The following filter values are missing : null for filter key Name.",
)
@pytest.mark.parametrize("value", ["/###", "//", "test"])
@mock_ssm
def test_describe_parameters_invalid_path(value):
client = boto3.client("ssm", region_name="us-east-1")
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Name", "Values": []}]
).should.throw(
ParamValidationError,
"Invalid length for parameter ParameterFilters[0].Values, value: 0, valid range: 1-inf",
)
client.describe_parameters.when.called_with(
ParameterFilters=[
{"Key": "Name", "Values": ["test"]},
{"Key": "Name", "Values": ["test test"]},
]
).should.throw(
ClientError,
"The following filter is duplicated in the request: Name. A request can contain only one occurrence of a specific filter.",
)
for value in ["/###", "//", "test"]:
client.describe_parameters.when.called_with(
with pytest.raises(ClientError) as e:
client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Values": [value]}]
).should.throw(
ClientError,
'The parameter doesn\'t meet the parameter name requirements. The parameter name must begin with a forward slash "/". '
'It can\'t be prefixed with "aws" or "ssm" (case-insensitive). '
"It must use only letters, numbers, or the following symbols: . (period), - (hyphen), _ (underscore). "
'Special characters are not allowed. All sub-paths, if specified, must use the forward slash symbol "/". '
"Valid example: /get/parameters2-/by1./path0_.",
)
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Path", "Values": ["/aws", "/ssm"]}]
).should.throw(
ClientError,
'Filters for common parameters can\'t be prefixed with "aws" or "ssm" (case-insensitive). '
"When using global parameters, please specify within a global namespace.",
msg = e.value.response["Error"]["Message"]
msg.should.contain("The parameter doesn't meet the parameter name requirements")
msg.should.contain('The parameter name must begin with a forward slash "/".')
msg.should.contain('It can\'t be prefixed with "aws" or "ssm" (case-insensitive).')
msg.should.contain(
"It must use only letters, numbers, or the following symbols: . (period), - (hyphen), _ (underscore)."
)
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Path", "Option": "Equals", "Values": ["test"]}]
).should.throw(
ClientError,
"The following filter option is not valid: Equals. Valid options include: [Recursive, OneLevel].",
msg.should.contain(
'Special characters are not allowed. All sub-paths, if specified, must use the forward slash symbol "/".'
)
msg.should.contain("Valid example: /get/parameters2-/by1./path0_.")
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Tier", "Values": ["test"]}]
).should.throw(
ClientError,
"The following filter value is not valid: test. Valid values include: [Standard, Advanced, Intelligent-Tiering]",
)
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Type", "Values": ["test"]}]
).should.throw(
ClientError,
"The following filter value is not valid: test. Valid values include: [String, StringList, SecureString]",
)
@pytest.mark.parametrize(
"filters,error_msg",
[
([{}], 'Missing required parameter in ParameterFilters[0]: "Key"',),
(
[{"Key": "Name", "Values": []}],
"Invalid length for parameter ParameterFilters[0].Values, value: 0, valid range: 1-inf",
),
],
)
@mock_ssm
def test_describe_parameters_parameter_validation(filters, error_msg):
client = boto3.client("ssm", region_name="us-east-1")
client.describe_parameters.when.called_with(
ParameterFilters=[{"Key": "Name", "Option": "option", "Values": ["test"]}]
).should.throw(
ClientError,
"The following filter option is not valid: option. Valid options include: [BeginsWith, Equals].",
)
with pytest.raises(ParamValidationError) as e:
client.describe_parameters(ParameterFilters=filters)
e.value.kwargs["report"].should.contain(error_msg)
@mock_ssm

View File

@ -25,7 +25,7 @@ while True:
break
except EXCEPTIONS:
elapsed_s = time.time() - start_ts
if elapsed_s > 60:
if elapsed_s > 120:
raise
print(".")