diff --git a/appveyor-windows-build-dotnet.yml b/appveyor-windows-build-dotnet.yml new file mode 100644 index 0000000000..22aec59923 --- /dev/null +++ b/appveyor-windows-build-dotnet.yml @@ -0,0 +1,71 @@ +version: 1.0.{build} +image: Windows Server 2019 +build: off + +# Change the clone folder to somewhere in "D:\" because this is shared by default with Docker. We need this to mount folders. +clone_folder: D:\source + +environment: + AWS_DEFAULT_REGION: us-east-1 + SAM_CLI_DEV: 1 + APPVEYOR_CI_OVERRIDE: 1 + + # In Windows, tempdir is usually in C:\. But in AppVeyor only D:\ is shared in Docker. + # Therefore change TEMPDIR it to D: for invoke tests to work. Python uses $TMPDIR envvar + # to find root of tempdir + TMPDIR: D:\tmp + TEMP: D:\tmp + TMP: D:\tmp + + # MSI Installers only use Py3.6.6. It is sufficient to test with this version here. + PYTHON_HOME: "C:\\Python36-x64" + PYTHON_SCRIPTS: "C:\\Python36-x64\\Scripts" + PYTHON_EXE: "C:\\Python36-x64\\python.exe" + PYTHON_VERSION: '3.6.8' + PYTHON_ARCH: '64' + HOME: 'C:\Users\appveyor' + HOMEDRIVE: 'C:' + HOMEPATH: 'C:\Users\appveyor' + +init: + # Uncomment this for RDP + - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - ps: gcim Win32_Processor | % { "$($_.NumberOfLogicalProcessors) logical CPUs" } + - ps: gcim Win32_OperatingSystem | % { "$([int]($_.TotalVisibleMemorySize/1mb)) Gb" } + + +install: + + # Make sure the temp directory exists for Python to use. + - ps: "mkdir -Force D:\\tmp" + - "SET PATH=%PYTHON_HOME%;%PATH%" + - "echo %PYTHON_HOME%" + - "echo %PATH%" + - "python --version" + + # Upgrade setuptools, wheel and virtualenv + - "python -m pip install --upgrade setuptools wheel virtualenv" + + # Create new virtual environment with chosen python version and activate it + - "python -m virtualenv venv" + - "venv\\Scripts\\activate" + - "python --version" + + # Actually install SAM CLI's dependencies + - "pip install -e \".[dev]\"" + + # Switch to Docker Linux containers + - ps: Switch-DockerLinux + + # Echo final Path + - "echo %PATH%" + +test_script: + # Reactivate virtualenv before running tests + - "venv\\Scripts\\activate" + - "docker system prune -a -f" + - "pytest -vv tests/integration/buildcmd/test_build_cmd.py -k TestBuildCommand_Dotnet_cli_package" + +# Uncomment for RDP +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/appveyor-windows-build-java.yml b/appveyor-windows-build-java.yml new file mode 100644 index 0000000000..ab3b93b399 --- /dev/null +++ b/appveyor-windows-build-java.yml @@ -0,0 +1,90 @@ +version: 1.0.{build} +image: Windows Server 2019 +build: off + +# Change the clone folder to somewhere in "D:\" because this is shared by default with Docker. We need this to mount folders. +clone_folder: D:\source + +environment: + AWS_DEFAULT_REGION: us-east-1 + SAM_CLI_DEV: 1 + APPVEYOR_CI_OVERRIDE: 1 + + # In Windows, tempdir is usually in C:\. But in AppVeyor only D:\ is shared in Docker. + # Therefore change TEMPDIR it to D: for invoke tests to work. Python uses $TMPDIR envvar + # to find root of tempdir + TMPDIR: D:\tmp + TEMP: D:\tmp + TMP: D:\tmp + + # MSI Installers only use Py3.6.6. It is sufficient to test with this version here. + PYTHON_HOME: "C:\\Python36-x64" + PYTHON_SCRIPTS: "C:\\Python36-x64\\Scripts" + PYTHON_EXE: "C:\\Python36-x64\\python.exe" + PYTHON_VERSION: '3.6.8' + PYTHON_ARCH: '64' + HOME: 'C:\Users\appveyor' + HOMEDRIVE: 'C:' + HOMEPATH: 'C:\Users\appveyor' + + matrix: + - optional_gate: true + +matrix: + allow_failures: + - optional_gate: true + +init: + # Uncomment this for RDP + - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - ps: gcim Win32_Processor | % { "$($_.NumberOfLogicalProcessors) logical CPUs" } + - ps: gcim Win32_OperatingSystem | % { "$([int]($_.TotalVisibleMemorySize/1mb)) Gb" } + + +install: + + # Make sure the temp directory exists for Python to use. + - ps: "mkdir -Force D:\\tmp" + - "SET PATH=%PYTHON_HOME%;%PATH%" + - "echo %PYTHON_HOME%" + - "echo %PATH%" + - "python --version" + + # Upgrade setuptools, wheel and virtualenv + - "python -m pip install --upgrade setuptools wheel virtualenv" + + # Create new virtual environment with chosen python version and activate it + - "python -m virtualenv venv" + - "venv\\Scripts\\activate" + - "python --version" + + # Actually install SAM CLI's dependencies + - "pip install -e \".[dev]\"" + + # setup Java, Maven and Gradle + - "refreshenv" + - "choco install jdk8 -y --force" + - "refreshenv" + - "choco install maven -y --force" + - "refreshenv" + - "choco install gradle -y --force" + - "refreshenv" + - "java -version" + - "gradle -v" + - "mvn --version" + + # Switch to Docker Linux containers + - ps: Switch-DockerLinux + + # Echo final Path + - "echo %PATH%" + +test_script: + # Reactivate virtualenv before running tests + - "venv\\Scripts\\activate" + - "docker system prune -a -f" + - "pytest -vv tests/integration/buildcmd/test_build_cmd.py -k TestBuildCommand_Java" + +# Uncomment for RDP +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/appveyor-windows-build-nodejs.yml b/appveyor-windows-build-nodejs.yml new file mode 100644 index 0000000000..bfbdd76833 --- /dev/null +++ b/appveyor-windows-build-nodejs.yml @@ -0,0 +1,77 @@ +version: 1.0.{build} +image: Windows Server 2019 +build: off + +# Change the clone folder to somewhere in "D:\" because this is shared by default with Docker. We need this to mount folders. +clone_folder: D:\source + +environment: + AWS_DEFAULT_REGION: us-east-1 + SAM_CLI_DEV: 1 + APPVEYOR_CI_OVERRIDE: 1 + + # In Windows, tempdir is usually in C:\. But in AppVeyor only D:\ is shared in Docker. + # Therefore change TEMPDIR it to D: for invoke tests to work. Python uses $TMPDIR envvar + # to find root of tempdir + TMPDIR: D:\tmp + TEMP: D:\tmp + TMP: D:\tmp + + # MSI Installers only use Py3.6.6. It is sufficient to test with this version here. + PYTHON_HOME: "C:\\Python36-x64" + PYTHON_SCRIPTS: "C:\\Python36-x64\\Scripts" + PYTHON_EXE: "C:\\Python36-x64\\python.exe" + PYTHON_VERSION: '3.6.8' + PYTHON_ARCH: '64' + HOME: 'C:\Users\appveyor' + HOMEDRIVE: 'C:' + HOMEPATH: 'C:\Users\appveyor' + +init: + # Uncomment this for RDP + - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - ps: gcim Win32_Processor | % { "$($_.NumberOfLogicalProcessors) logical CPUs" } + - ps: gcim Win32_OperatingSystem | % { "$([int]($_.TotalVisibleMemorySize/1mb)) Gb" } + + +install: + + # Make sure the temp directory exists for Python to use. + - ps: "mkdir -Force D:\\tmp" + - "SET PATH=%PYTHON_HOME%;%PATH%" + - "echo %PYTHON_HOME%" + - "echo %PATH%" + - "python --version" + + # Upgrade setuptools, wheel and virtualenv + - "python -m pip install --upgrade setuptools wheel virtualenv" + + # Create new virtual environment with chosen python version and activate it + - "python -m virtualenv venv" + - "venv\\Scripts\\activate" + - "python --version" + + # Actually install SAM CLI's dependencies + - "pip install -e \".[dev]\"" + + + # To run Nodejs workflow integ tests + - "choco install nodejs-lts -y --force" + - "refreshenv" + + + # Switch to Docker Linux containers + - ps: Switch-DockerLinux + + # Echo final Path + - "echo %PATH%" + +test_script: + # Reactivate virtualenv before running tests + - "venv\\Scripts\\activate" + - "docker system prune -a -f" + - "pytest -vv tests/integration/buildcmd/test_build_cmd.py -k TestBuildCommand_NodeFunctions" + +# Uncomment for RDP +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/appveyor-windows-build-python.yml b/appveyor-windows-build-python.yml new file mode 100644 index 0000000000..a20d9b06ce --- /dev/null +++ b/appveyor-windows-build-python.yml @@ -0,0 +1,72 @@ +version: 1.0.{build} +image: Windows Server 2019 +build: off + +# Change the clone folder to somewhere in "D:\" because this is shared by default with Docker. We need this to mount folders. +clone_folder: D:\source + +environment: + AWS_DEFAULT_REGION: us-east-1 + SAM_CLI_DEV: 1 + APPVEYOR_CI_OVERRIDE: 1 + + # In Windows, tempdir is usually in C:\. But in AppVeyor only D:\ is shared in Docker. + # Therefore change TEMPDIR it to D: for invoke tests to work. Python uses $TMPDIR envvar + # to find root of tempdir + TMPDIR: D:\tmp + TEMP: D:\tmp + TMP: D:\tmp + + # MSI Installers only use Py3.6.6. It is sufficient to test with this version here. + PYTHON_HOME: "C:\\Python36-x64" + PYTHON_SCRIPTS: "C:\\Python36-x64\\Scripts" + PYTHON_EXE: "C:\\Python36-x64\\python.exe" + PYTHON_VERSION: '3.6.8' + PYTHON_ARCH: '64' + HOME: 'C:\Users\appveyor' + HOMEDRIVE: 'C:' + HOMEPATH: 'C:\Users\appveyor' + +init: + # Uncomment this for RDP + - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - ps: gcim Win32_Processor | % { "$($_.NumberOfLogicalProcessors) logical CPUs" } + - ps: gcim Win32_OperatingSystem | % { "$([int]($_.TotalVisibleMemorySize/1mb)) Gb" } + + +install: + + # Make sure the temp directory exists for Python to use. + - ps: "mkdir -Force D:\\tmp" + - "SET PATH=%PYTHON_HOME%;%PATH%" + - "echo %PYTHON_HOME%" + - "echo %PATH%" + - "python --version" + + # Upgrade setuptools, wheel and virtualenv + - "python -m pip install --upgrade setuptools wheel virtualenv" + + # Create new virtual environment with chosen python version and activate it + - "python -m virtualenv venv" + - "venv\\Scripts\\activate" + - "python --version" + + # Actually install SAM CLI's dependencies + - "pip install -e \".[dev]\"" + # Switch to Docker Linux containers + - ps: Switch-DockerLinux + + # Echo final Path + - "echo %PATH%" + +test_script: + # Reactivate virtualenv before running tests + - "venv\\Scripts\\activate" + - "docker system prune -a -f" + - "pytest -vv tests/integration/buildcmd/test_build_cmd.py -k TestBuildCommand_PythonFunctions" + - "pytest -vv tests/integration/buildcmd/test_build_cmd.py -k TestBuildCommand_SingleFunctionBuilds" + - "pytest -vv tests/integration/buildcmd/test_build_cmd.py -k TestBuildCommand_ErrorCases" + +# Uncomment for RDP +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/appveyor-windows-build-ruby.yml b/appveyor-windows-build-ruby.yml new file mode 100644 index 0000000000..18bbf966ec --- /dev/null +++ b/appveyor-windows-build-ruby.yml @@ -0,0 +1,88 @@ +version: 1.0.{build} +image: Windows Server 2019 +build: off + +# Change the clone folder to somewhere in "D:\" because this is shared by default with Docker. We need this to mount folders. +clone_folder: D:\source + +environment: + AWS_DEFAULT_REGION: us-east-1 + SAM_CLI_DEV: 1 + APPVEYOR_CI_OVERRIDE: 1 + + # In Windows, tempdir is usually in C:\. But in AppVeyor only D:\ is shared in Docker. + # Therefore change TEMPDIR it to D: for invoke tests to work. Python uses $TMPDIR envvar + # to find root of tempdir + TMPDIR: D:\tmp + TEMP: D:\tmp + TMP: D:\tmp + + # MSI Installers only use Py3.6.6. It is sufficient to test with this version here. + PYTHON_HOME: "C:\\Python36-x64" + PYTHON_SCRIPTS: "C:\\Python36-x64\\Scripts" + PYTHON_EXE: "C:\\Python36-x64\\python.exe" + PYTHON_VERSION: '3.6.8' + PYTHON_ARCH: '64' + HOME: 'C:\Users\appveyor' + HOMEDRIVE: 'C:' + HOMEPATH: 'C:\Users\appveyor' + + matrix: + - optional_gate: true + +matrix: + allow_failures: + - optional_gate: true + +init: + # Uncomment this for RDP + - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - ps: gcim Win32_Processor | % { "$($_.NumberOfLogicalProcessors) logical CPUs" } + - ps: gcim Win32_OperatingSystem | % { "$([int]($_.TotalVisibleMemorySize/1mb)) Gb" } + + +install: + + # Make sure the temp directory exists for Python to use. + - ps: "mkdir -Force D:\\tmp" + - "SET PATH=%PYTHON_HOME%;%PATH%" + - "echo %PYTHON_HOME%" + - "echo %PATH%" + - "python --version" + + # Upgrade setuptools, wheel and virtualenv + - "python -m pip install --upgrade setuptools wheel virtualenv" + + # Create new virtual environment with chosen python version and activate it + - "python -m virtualenv venv" + - "venv\\Scripts\\activate" + - "python --version" + + # Actually install SAM CLI's dependencies + - "pip install -e \".[dev]\"" + + # setup Ruby + - "choco install ruby --version 2.5.3.1 --force -y" + - "refreshenv" + - "ruby --version" + - "gem --version" + - "gem install bundler -v 2.0.2" + - "refreshenv" + - "bundler --version" + - "echo %PATH%" + + # Switch to Docker Linux containers + - ps: Switch-DockerLinux + + # Echo final Path + - "echo %PATH%" + +test_script: + # Reactivate virtualenv before running tests + - "venv\\Scripts\\activate" + - "docker system prune -a -f" + - "pytest -vv tests/integration/buildcmd/test_build_cmd.py -k TestBuildCommand_RubyFunctions" + +# Uncomment for RDP +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/appveyor-windows.yml b/appveyor-windows.yml index 2aca76c3ff..3243f006a6 100644 --- a/appveyor-windows.yml +++ b/appveyor-windows.yml @@ -40,6 +40,8 @@ install: # Make sure the temp directory exists for Python to use. - ps: "mkdir -Force D:\\tmp" + - "SET PATH=%PYTHON_HOME%;%PATH%" + - "echo %PYTHON_HOME%" - "echo %PATH%" - "python --version" @@ -47,42 +49,13 @@ install: - "python -m pip install --upgrade setuptools wheel virtualenv" # Create new virtual environment with chosen python version and activate it - - "rm -rf venv" - - "dir C:\\Python36-x64" - - "virtualenv -p %PYTHON_EXE% venv" + - "python -m virtualenv venv" - "venv\\Scripts\\activate" - - "python -c \"import sys; print(sys.executable)\"" - "python --version" # Actually install SAM CLI's dependencies - "pip install -e \".[dev]\"" - - # To run Nodejs workflow integ tests - - "choco install nodejs-lts -y --force" - - "refreshenv" - # setup Ruby - - "choco install ruby --version 2.5.3.1 --force -y" - - "refreshenv" - - "ruby --version" - - "gem --version" - - "gem install bundler -v 2.0.2" - - "refreshenv" - - "bundler --version" - - "echo %PATH%" - - # setup Java, Maven and Gradle - - "refreshenv" - - "choco install jdk8 -y --force" - - "refreshenv" - - "choco install maven -y --force" - - "refreshenv" - - "choco install gradle -y --force" - - "refreshenv" - - "java -version" - - "gradle -v" - - "mvn --version" - # Switch to Docker Linux containers - ps: Switch-DockerLinux diff --git a/appveyor.yml b/appveyor.yml index 39378826fb..29b928b054 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,10 +9,6 @@ environment: matrix: - - PYTHON_HOME: "C:\\Python27-x64" - PYTHON_VERSION: '2.7.16' - PYTHON_ARCH: '32' - - PYTHON_HOME: "C:\\Python36-x64" PYTHON_VERSION: '3.6.8' PYTHON_ARCH: '64' @@ -29,18 +25,45 @@ for: - image: Visual Studio 2017 install: + - "SET PATH=%PYTHON_HOME%;%PATH%" + - "echo %PYTHON_HOME%" + - "echo %PATH%" + - "python --version" # Upgrade setuptools, wheel and virtualenv - "python -m pip install --upgrade setuptools wheel virtualenv" # Create new virtual environment and activate it - "rm -rf venv" - "python -m virtualenv venv" - - "venv/Scripts/activate" + - "venv\\Scripts\\activate" + + build_script: + # Activate virtualenv again on windows + - "venv\\Scripts\\activate" + - "python -c \"import sys; print(sys.executable)\"" + - "pip install -e \".[dev]\"" + + test_script: + # Activate virtualenv again on windows + - "venv\\Scripts\\activate" + - "pytest --cov samcli --cov-report term-missing --cov-fail-under 95 tests/unit" + - "pylint --rcfile .pylintrc samcli" + + # Runs only in Linux + - sh: "pytest -vv tests/integration" + - sh: "/tmp/black --check setup.py tests samcli scripts" + - sh: "python scripts/check-isolated-needs-update.py" + # Smoke tests run in parallel - it runs on both Linux & Windows + # Presence of the RUN_SMOKE envvar will run the smoke tests + # Note: temporarily removing as with current dependencies we require syslog on windows + # which is not present on stdlib. + # - ps: "If ($env:RUN_SMOKE) {pytest -n 4 -vv tests/smoke}" - matrix: only: - image: Ubuntu + install: - sh: "JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64" - sh: "PATH=$JAVA_HOME/bin:$PATH" @@ -57,30 +80,30 @@ for: - sh: "wget -O /tmp/black https://github.com/python/black/releases/download/19.3b0/black" - sh: "chmod +x /tmp/black" - sh: "/tmp/black --version" + + build_script: + - "python -c \"import sys; print(sys.executable)\"" + - "pip install -e \".[dev]\"" + + test_script: + - "pytest --cov samcli --cov-report term-missing --cov-fail-under 95 tests/unit" + - "pylint --rcfile .pylintrc samcli" + + # Runs only in Linux + - sh: "pytest -vv tests/integration" + - sh: "/tmp/black --check setup.py tests samcli scripts" + - sh: "python scripts/check-isolated-needs-update.py" + + # Smoke tests run in parallel - it runs on both Linux & Windows + # Presence of the RUN_SMOKE envvar will run the smoke tests + - ps: "If ($env:RUN_SMOKE) {pytest -n 4 -vv tests/smoke}" - matrix: only: - ONLY_SMOKE: 1 + test_script: # Smoke tests run in parallel - - "pytest -n 4 -vv tests/smoke" - -build_script: - - "python -c \"import sys; print(sys.executable)\"" - - # Actually install SAM CLI's dependencies - - "pip install -e \".[dev]\"" - -test_script: - - "pytest --cov samcli --cov-report term-missing --cov-fail-under 95 tests/unit" - - "pylint --rcfile .pylintrc samcli" - - # Runs only in Linux - - sh: "pytest -vv tests/integration" - - sh: "/tmp/black --check setup.py tests samcli scripts" - - sh: "python scripts/check-isolated-needs-update.py" - - # Smoke tests run in parallel - it runs on both Linux & Windows - # Presence of the RUN_SMOKE envvar will run the smoke tests - - ps: "If ($env:RUN_SMOKE) {pytest -n 4 -vv tests/smoke}" + - sh: "venv/Scripts/activate" + - sh: "pytest -n 4 -vv tests/smoke" diff --git a/requirements/base.txt b/requirements/base.txt index a43a664dbe..39a0699fdf 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -6,11 +6,11 @@ Flask~=1.0.2 boto3~=1.9, >=1.9.56 PyYAML~=5.1 cookiecutter~=1.6.0 -aws-sam-translator==1.14.0 +aws-sam-translator==1.15.1 docker~=4.0 dateparser~=0.7 python-dateutil~=2.6 pathlib2~=2.3.2; python_version<"3.4" requests==2.22.0 serverlessrepo==0.1.9 -aws_lambda_builders==0.4.0 +aws_lambda_builders==0.5.0 diff --git a/requirements/dev.txt b/requirements/dev.txt index 8f4e1fdc32..029324c901 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,17 +1,20 @@ coverage==4.3.4 -tox==2.2.1 pytest-cov==2.4.0 # astroid > 2.0.4 is not compatible with pylint1.7 astroid>=1.5.8,<2.1.0 pylint==1.7.2 # Test requirements -pytest==3.1.0 -py==1.4.33 +pytest==3.6.0 +py==1.5.1 +pluggy==0.6.0 mock==2.0.0 parameterized==0.6.1 pathlib2==2.3.2; python_version<"3.4" futures==3.2.0; python_version<"3.2.3" # Py3.2 backport backports.tempfile==1.0 -pytest-xdist==1.20.0 \ No newline at end of file +pytest-xdist==1.20.0 +pytest-forked==1.0.2 +pytest-timeout==1.3.3 +pytest-rerunfailures==5.0 diff --git a/requirements/isolated.txt b/requirements/isolated.txt index 1440a6db13..0dbc04bb8e 100644 --- a/requirements/isolated.txt +++ b/requirements/isolated.txt @@ -1,7 +1,7 @@ arrow==0.15.2 attrs==19.1.0 -aws-lambda-builders==0.4.0 -aws-sam-translator==1.14.0 +aws-lambda-builders==0.5.0 +aws-sam-translator==1.15.1 binaryornot==0.4.4 boto3==1.9.228 botocore==1.12.228 @@ -10,8 +10,8 @@ chardet==3.0.4 chevron==0.13.1 Click==7.0 cookiecutter==1.6.0 -dateparser==0.7.1 -docker==4.0.2 +dateparser==0.7.2 +docker==4.1.0 docutils==0.15.2 Flask==1.0.4 future==0.17.1 diff --git a/samcli/__init__.py b/samcli/__init__.py index 823cc30cb7..6ae52e67dd 100644 --- a/samcli/__init__.py +++ b/samcli/__init__.py @@ -2,4 +2,4 @@ SAM CLI version """ -__version__ = "0.22.0" +__version__ = "0.23.0" diff --git a/samcli/cli/command.py b/samcli/cli/command.py index b09f0f5071..e7fca789ce 100644 --- a/samcli/cli/command.py +++ b/samcli/cli/command.py @@ -25,9 +25,9 @@ ] DEPRECATION_NOTICE = ( - "Warning : AWS SAM CLI will no longer support " - "installations on Python 2.7 starting on October 1st, 2019." - " Install AWS SAM CLI via https://docs.aws.amazon.com/serverless-application-model/" + "Deprecated : AWS SAM CLI no longer supports " + "installations on Python 2.7. " + "Install AWS SAM CLI via https://docs.aws.amazon.com/serverless-application-model/" "latest/developerguide/serverless-sam-cli-install.html for continued support with new versions. \n" ) @@ -70,7 +70,7 @@ def __init__(self, cmd_packages=None, *args, **kwargs): self._commands = BaseCommand._set_commands(cmd_packages) if sys.version_info.major == 2: - click.secho(DEPRECATION_NOTICE, fg="yellow", err=True) + click.secho(DEPRECATION_NOTICE, fg="red", err=True) @staticmethod def _set_commands(package_names): diff --git a/samcli/commands/build/command.py b/samcli/commands/build/command.py index d7549a0074..b6f9c67f9f 100644 --- a/samcli/commands/build/command.py +++ b/samcli/commands/build/command.py @@ -6,18 +6,12 @@ import logging import click -from samcli.commands.exceptions import UserException -from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options from samcli.commands._utils.options import template_option_without_build, docker_common_options, \ parameter_override_option -from samcli.commands.build.build_context import BuildContext -from samcli.lib.build.app_builder import ApplicationBuilder, BuildError, UnsupportedBuilderLibraryVersionError, \ - ContainerBuildNotSupported -from samcli.lib.build.workflow_config import UnsupportedRuntimeException -from samcli.local.lambdafn.exceptions import FunctionNotFound -from samcli.commands._utils.template import move_template +from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options from samcli.lib.telemetry.metrics import track_command + LOG = logging.getLogger(__name__) DEFAULT_BUILD_DIR = os.path.join(".aws-sam", "build") @@ -105,7 +99,7 @@ def cli(ctx, skip_pull_image, parameter_overrides, mode) # pragma: no cover -def do_cli(function_identifier, # pylint: disable=too-many-locals +def do_cli(function_identifier, # pylint: disable=too-many-locals, too-many-statements template, base_dir, build_dir, @@ -120,6 +114,15 @@ def do_cli(function_identifier, # pylint: disable=too-many-locals Implementation of the ``cli`` method """ + from samcli.commands.exceptions import UserException + + from samcli.commands.build.build_context import BuildContext + from samcli.lib.build.app_builder import ApplicationBuilder, BuildError, UnsupportedBuilderLibraryVersionError, \ + ContainerBuildNotSupported + from samcli.lib.build.workflow_config import UnsupportedRuntimeException + from samcli.local.lambdafn.exceptions import FunctionNotFound + from samcli.commands._utils.template import move_template + LOG.debug("'build' command is called") if use_container: diff --git a/samcli/commands/init/__init__.py b/samcli/commands/init/__init__.py index 9164ddeb90..613b624ee1 100644 --- a/samcli/commands/init/__init__.py +++ b/samcli/commands/init/__init__.py @@ -7,12 +7,8 @@ import click from samcli.cli.main import pass_context, common_options -from samcli.commands.exceptions import UserException -from samcli.local.common.runtime_template import INIT_RUNTIMES, SUPPORTED_DEP_MANAGERS, DEFAULT_RUNTIME -from samcli.local.init import generate_project -from samcli.local.init.exceptions import GenerateProjectFailedError from samcli.lib.telemetry.metrics import track_command - +from samcli.local.common.runtime_template import INIT_RUNTIMES, SUPPORTED_DEP_MANAGERS, DEFAULT_RUNTIME LOG = logging.getLogger(__name__) @@ -95,6 +91,10 @@ def do_cli(ctx, location, runtime, dependency_manager, output_dir, name, no_inpu """ Implementation of the ``cli`` method, just separated out for unit testing purposes """ + from samcli.commands.exceptions import UserException + from samcli.local.init import generate_project + from samcli.local.init.exceptions import GenerateProjectFailedError + LOG.debug("Init command") click.secho("[+] Initializing project structure...", fg="green") diff --git a/samcli/commands/local/invoke/cli.py b/samcli/commands/local/invoke/cli.py index d059e66ee2..95b97f27b8 100644 --- a/samcli/commands/local/invoke/cli.py +++ b/samcli/commands/local/invoke/cli.py @@ -7,14 +7,6 @@ from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options from samcli.commands.local.cli_common.options import invoke_common_options -from samcli.commands.exceptions import UserException -from samcli.commands.local.lib.exceptions import InvalidLayerReference -from samcli.commands.local.cli_common.invoke_context import InvokeContext -from samcli.local.lambdafn.exceptions import FunctionNotFound -from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException -from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError -from samcli.local.docker.manager import DockerImagePullFailedException -from samcli.local.docker.lambda_debug_entrypoint import DebuggingNotSupported from samcli.lib.telemetry.metrics import track_command @@ -113,6 +105,15 @@ def do_cli( # pylint: disable=R0914 Implementation of the ``cli`` method, just separated out for unit testing purposes """ + from samcli.commands.exceptions import UserException + from samcli.commands.local.lib.exceptions import InvalidLayerReference + from samcli.commands.local.cli_common.invoke_context import InvokeContext + from samcli.local.lambdafn.exceptions import FunctionNotFound + from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException + from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError + from samcli.local.docker.manager import DockerImagePullFailedException + from samcli.local.docker.lambda_debug_entrypoint import DebuggingNotSupported + LOG.debug("local invoke command is called") if no_event and event != STDIN_FILE_NAME: diff --git a/samcli/commands/local/start_api/cli.py b/samcli/commands/local/start_api/cli.py index a967ec1a3b..8063101359 100644 --- a/samcli/commands/local/start_api/cli.py +++ b/samcli/commands/local/start_api/cli.py @@ -7,13 +7,6 @@ from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options from samcli.commands.local.cli_common.options import invoke_common_options, service_common_options -from samcli.commands.local.cli_common.invoke_context import InvokeContext -from samcli.commands.local.lib.exceptions import NoApisDefined, InvalidLayerReference -from samcli.commands.exceptions import UserException -from samcli.commands.local.lib.local_api_service import LocalApiService -from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException -from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError -from samcli.local.docker.lambda_debug_entrypoint import DebuggingNotSupported from samcli.lib.telemetry.metrics import track_command @@ -114,6 +107,14 @@ def do_cli( # pylint: disable=R0914 Implementation of the ``cli`` method, just separated out for unit testing purposes """ + from samcli.commands.local.cli_common.invoke_context import InvokeContext + from samcli.commands.local.lib.exceptions import NoApisDefined, InvalidLayerReference + from samcli.commands.exceptions import UserException + from samcli.commands.local.lib.local_api_service import LocalApiService + from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException + from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError + from samcli.local.docker.lambda_debug_entrypoint import DebuggingNotSupported + LOG.debug("local start-api command is called") # Pass all inputs to setup necessary context to invoke function locally. diff --git a/samcli/commands/local/start_lambda/cli.py b/samcli/commands/local/start_lambda/cli.py index 96dc14c6e2..0004df846b 100644 --- a/samcli/commands/local/start_lambda/cli.py +++ b/samcli/commands/local/start_lambda/cli.py @@ -7,13 +7,6 @@ from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options from samcli.commands.local.cli_common.options import invoke_common_options, service_common_options -from samcli.commands.local.cli_common.invoke_context import InvokeContext -from samcli.commands.local.cli_common.user_exceptions import UserException -from samcli.commands.local.lib.exceptions import InvalidLayerReference -from samcli.commands.local.lib.local_lambda_service import LocalLambdaService -from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException -from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError -from samcli.local.docker.lambda_debug_entrypoint import DebuggingNotSupported from samcli.lib.telemetry.metrics import track_command @@ -123,6 +116,14 @@ def do_cli( # pylint: disable=R0914 Implementation of the ``cli`` method, just separated out for unit testing purposes """ + from samcli.commands.local.cli_common.invoke_context import InvokeContext + from samcli.commands.local.cli_common.user_exceptions import UserException + from samcli.commands.local.lib.exceptions import InvalidLayerReference + from samcli.commands.local.lib.local_lambda_service import LocalLambdaService + from samcli.commands.validate.lib.exceptions import InvalidSamDocumentException + from samcli.commands.local.lib.exceptions import OverridesNotWellDefinedError + from samcli.local.docker.lambda_debug_entrypoint import DebuggingNotSupported + LOG.debug("local start_lambda command is called") # Pass all inputs to setup necessary context to invoke function locally. diff --git a/samcli/commands/logs/command.py b/samcli/commands/logs/command.py index 3bdb90b18d..f6b479cb46 100644 --- a/samcli/commands/logs/command.py +++ b/samcli/commands/logs/command.py @@ -7,7 +7,6 @@ from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options from samcli.lib.telemetry.metrics import track_command -from .logs_context import LogsCommandContext LOG = logging.getLogger(__name__) @@ -84,6 +83,7 @@ def do_cli(function_name, stack_name, filter_pattern, tailing, start_time, end_t """ Implementation of the ``cli`` method """ + from .logs_context import LogsCommandContext LOG.debug("'logs' command is called") diff --git a/samcli/commands/publish/command.py b/samcli/commands/publish/command.py index 5a42c2ce5d..d2817a2277 100644 --- a/samcli/commands/publish/command.py +++ b/samcli/commands/publish/command.py @@ -5,16 +5,12 @@ import click import boto3 -from serverlessrepo import publish_application -from serverlessrepo.publish import CREATE_APPLICATION -from serverlessrepo.parser import METADATA, SERVERLESS_REPO_APPLICATION -from serverlessrepo.exceptions import ServerlessRepoError, InvalidS3UriError from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options from samcli.commands._utils.options import template_common_option from samcli.commands._utils.template import get_template_data -from samcli.commands.exceptions import UserException from samcli.lib.telemetry.metrics import track_command +from serverlessrepo.publish import CREATE_APPLICATION LOG = logging.getLogger(__name__) @@ -58,6 +54,13 @@ def cli(ctx, template, semantic_version): def do_cli(ctx, template, semantic_version): """Publish the application based on command line inputs.""" + + from serverlessrepo import publish_application + from serverlessrepo.parser import METADATA, SERVERLESS_REPO_APPLICATION + from serverlessrepo.exceptions import ServerlessRepoError, InvalidS3UriError + + from samcli.commands.exceptions import UserException + try: template_data = get_template_data(template) except ValueError as ex: diff --git a/samcli/commands/validate/validate.py b/samcli/commands/validate/validate.py index ffbb8d946b..cdc9d7db71 100644 --- a/samcli/commands/validate/validate.py +++ b/samcli/commands/validate/validate.py @@ -6,16 +6,10 @@ import boto3 from botocore.exceptions import NoCredentialsError import click -from samtranslator.translator.managed_policy_translator import ManagedPolicyLoader -from samcli.commands.exceptions import UserException from samcli.cli.main import pass_context, common_options as cli_framework_options, aws_creds_options from samcli.commands._utils.options import template_option_without_build -from samcli.commands.local.cli_common.user_exceptions import InvalidSamTemplateException, SamTemplateNotFoundException -from samcli.yamlhelper import yaml_parse from samcli.lib.telemetry.metrics import track_command -from .lib.exceptions import InvalidSamDocumentException -from .lib.sam_template_validator import SamTemplateValidator @click.command("validate", short_help="Validate an AWS SAM template.") @@ -35,6 +29,12 @@ def do_cli(ctx, template): """ Implementation of the ``cli`` method, just separated out for unit testing purposes """ + from samtranslator.translator.managed_policy_translator import ManagedPolicyLoader + + from samcli.commands.exceptions import UserException + from samcli.commands.local.cli_common.user_exceptions import InvalidSamTemplateException + from .lib.exceptions import InvalidSamDocumentException + from .lib.sam_template_validator import SamTemplateValidator sam_template = _read_sam_file(template) @@ -54,12 +54,16 @@ def do_cli(ctx, template): def _read_sam_file(template): """ - Reads the file (json and yaml supported) provided and returns the dictionary representation of the file. + Reads the file (json and yaml supported) provided and returns the dictionary representation of the file. - :param str template: Path to the template file - :return dict: Dictionary representing the SAM Template - :raises: SamTemplateNotFoundException when the template file does not exist + :param str template: Path to the template file + :return dict: Dictionary representing the SAM Template + :raises: SamTemplateNotFoundException when the template file does not exist """ + + from samcli.commands.local.cli_common.user_exceptions import SamTemplateNotFoundException + from samcli.yamlhelper import yaml_parse + if not os.path.exists(template): click.secho("SAM Template Not Found", bg="red") raise SamTemplateNotFoundException("Template at {} is not found".format(template)) diff --git a/samcli/lib/intrinsic_resolver/intrinsic_property_resolver.py b/samcli/lib/intrinsic_resolver/intrinsic_property_resolver.py index f9a7720ca4..0e99e90914 100644 --- a/samcli/lib/intrinsic_resolver/intrinsic_property_resolver.py +++ b/samcli/lib/intrinsic_resolver/intrinsic_property_resolver.py @@ -22,6 +22,7 @@ verify_all_list_intrinsic_type, ) from samcli.lib.intrinsic_resolver.invalid_intrinsic_exception import InvalidIntrinsicException, InvalidSymbolException +from samcli.commands._utils.template import get_template_data LOG = logging.getLogger(__name__) @@ -562,7 +563,9 @@ def handle_fn_transform(self, intrinsic_value, ignore_errors): ) location = self.intrinsic_property_resolver(parameters.get("Location"), ignore_errors) - return location + location_data = get_template_data(location) + + return location_data def handle_fn_import_value(self, intrinsic_value, ignore_errors): """ diff --git a/tests/functional/commands/validate/lib/models/all_policy_templates.yaml b/tests/functional/commands/validate/lib/models/all_policy_templates.yaml index 2cca6996f8..47509c70ea 100644 --- a/tests/functional/commands/validate/lib/models/all_policy_templates.yaml +++ b/tests/functional/commands/validate/lib/models/all_policy_templates.yaml @@ -98,8 +98,7 @@ Resources: - CloudWatchDashboardPolicy: {} - - RekognitionFacesPolicy: - CollectionId: collection + - RekognitionFacesPolicy: {} - RekognitionLabelsPolicy: {} @@ -146,3 +145,9 @@ Resources: - StepFunctionsExecutionPolicy: StateMachineName: name + + - CodeCommitCrudPolicy: + RepositoryName: name + + - CodeCommitReadPolicy: + RepositoryName: name diff --git a/tests/functional/commands/validate/lib/models/api_request_model.yaml b/tests/functional/commands/validate/lib/models/api_request_model.yaml index b7b8ed768a..6acb575750 100644 --- a/tests/functional/commands/validate/lib/models/api_request_model.yaml +++ b/tests/functional/commands/validate/lib/models/api_request_model.yaml @@ -25,4 +25,4 @@ Resources: type: object properties: username: - type: string + type: string \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/api_request_model_openapi_3.yaml b/tests/functional/commands/validate/lib/models/api_request_model_openapi_3.yaml index 0394ca5153..38c2224504 100644 --- a/tests/functional/commands/validate/lib/models/api_request_model_openapi_3.yaml +++ b/tests/functional/commands/validate/lib/models/api_request_model_openapi_3.yaml @@ -33,7 +33,7 @@ Resources: Type: AWS::Serverless::Api Properties: StageName: Prod - OpenApiVersion: '3.0.1' + OpenApiVersion: 3.0 Models: User: type: object diff --git a/tests/functional/commands/validate/lib/models/api_with_apikey_default_override.yaml b/tests/functional/commands/validate/lib/models/api_with_apikey_default_override.yaml new file mode 100644 index 0000000000..53a94e3b62 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_apikey_default_override.yaml @@ -0,0 +1,51 @@ +Resources: + MyApiWithAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + ApiKeyRequired: true + + MyFunctionWithApiKeyRequiredDefault: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequiredDefault: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAuth + Path: /ApiKeyDefault + Method: get + MyFunctionWithApiKeyRequiredTrue: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequiredTrue: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAuth + Path: /ApiKeyTrue + Method: get + Auth: + ApiKeyRequired: true + MyFunctionWithApiKeyRequiredFalse: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequiredFalse: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAuth + Path: /ApiKeyFalse + Method: get + Auth: + ApiKeyRequired: false diff --git a/tests/functional/commands/validate/lib/models/api_with_apikey_required.yaml b/tests/functional/commands/validate/lib/models/api_with_apikey_required.yaml new file mode 100644 index 0000000000..e5c562c916 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_apikey_required.yaml @@ -0,0 +1,21 @@ +Resources: + MyApiWithoutAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + + MyFunctionWithApiKeyRequired: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequired: + Type: Api + Properties: + RestApiId: !Ref MyApiWithoutAuth + Path: /ApiKeyRequiredTrue + Method: get + Auth: + ApiKeyRequired: true diff --git a/tests/functional/commands/validate/lib/models/api_with_apikey_required_openapi_3.yaml b/tests/functional/commands/validate/lib/models/api_with_apikey_required_openapi_3.yaml new file mode 100644 index 0000000000..95d7727c58 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_apikey_required_openapi_3.yaml @@ -0,0 +1,22 @@ +Resources: + MyApiWithoutAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + OpenApiVersion: '3.0.1' + + MyFunctionWithApiKeyRequired: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithApiKeyRequired: + Type: Api + Properties: + RestApiId: !Ref MyApiWithoutAuth + Path: /ApiKeyRequiredTrue + Method: get + Auth: + ApiKeyRequired: true diff --git a/tests/functional/commands/validate/lib/models/api_with_auth_all_maximum.yaml b/tests/functional/commands/validate/lib/models/api_with_auth_all_maximum.yaml index 89c94fdc7e..e3dbd397b3 100644 --- a/tests/functional/commands/validate/lib/models/api_with_auth_all_maximum.yaml +++ b/tests/functional/commands/validate/lib/models/api_with_auth_all_maximum.yaml @@ -5,6 +5,7 @@ Resources: StageName: Prod Auth: DefaultAuthorizer: MyCognitoAuth + ApiKeyRequired: true Authorizers: MyCognitoAuth: UserPoolArn: arn:aws:1 diff --git a/tests/functional/commands/validate/lib/models/api_with_auth_all_maximum_openapi_3.yaml b/tests/functional/commands/validate/lib/models/api_with_auth_all_maximum_openapi_3.yaml index 8cab3cd48c..bb236464fe 100644 --- a/tests/functional/commands/validate/lib/models/api_with_auth_all_maximum_openapi_3.yaml +++ b/tests/functional/commands/validate/lib/models/api_with_auth_all_maximum_openapi_3.yaml @@ -6,6 +6,7 @@ Resources: OpenApiVersion: '3.0.1' Auth: DefaultAuthorizer: MyCognitoAuth + ApiKeyRequired: true Authorizers: MyCognitoAuth: UserPoolArn: arn:aws:1 diff --git a/tests/functional/commands/validate/lib/models/api_with_aws_account_blacklist.yaml b/tests/functional/commands/validate/lib/models/api_with_aws_account_blacklist.yaml new file mode 100644 index 0000000000..7d64715887 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_aws_account_blacklist.yaml @@ -0,0 +1,25 @@ +Globals: + Api: + Auth: + ResourcePolicy: + AwsAccountBlacklist: ['12345'] +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs8.10 + Events: + Api: + Type: Api + Properties: + Method: Put + Path: /get diff --git a/tests/functional/commands/validate/lib/models/api_with_aws_account_whitelist.yaml b/tests/functional/commands/validate/lib/models/api_with_aws_account_whitelist.yaml new file mode 100644 index 0000000000..09c57d5e0d --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_aws_account_whitelist.yaml @@ -0,0 +1,28 @@ +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs8.10 + Events: + Api: + Type: Api + Properties: + Auth: + ResourcePolicy: + AwsAccountWhitelist: [ + "12345" + ] + AwsAccountBlacklist: [ + "67890" + ] + Method: Put + Path: /get diff --git a/tests/functional/commands/validate/lib/models/api_with_aws_iam_auth_overrides.yaml b/tests/functional/commands/validate/lib/models/api_with_aws_iam_auth_overrides.yaml index f9cd47765a..5ce61f7924 100644 --- a/tests/functional/commands/validate/lib/models/api_with_aws_iam_auth_overrides.yaml +++ b/tests/functional/commands/validate/lib/models/api_with_aws_iam_auth_overrides.yaml @@ -1,4 +1,11 @@ Resources: + MyApiWithAwsIamAuthNoCallerCredentials: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + DefaultAuthorizer: AWS_IAM + InvokeRole: NONE MyApiWithAwsIamAuth: Type: "AWS::Serverless::Api" Properties: @@ -84,3 +91,64 @@ Resources: Auth: Authorizer: AWS_IAM InvokeRole: arn:aws:iam::456::role/something-else + MyFunctionNONEInvokeRole: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + API3: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuth + Method: get + Path: /MyFunctionNONEInvokeRole + Auth: + Authorizer: AWS_IAM + InvokeRole: NONE + MyFunctionNullInvokeRole: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + API3: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuth + Method: get + Path: /MyFunctionNullInvokeRole + Auth: + Authorizer: AWS_IAM + InvokeRole: null + MyFunctionCallerCredentialsOverride: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + API3: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuthNoCallerCredentials + Method: get + Path: / + Auth: + Authorizer: AWS_IAM + InvokeRole: CALLER_CREDENTIALS + MyFunctionNoCallerCredentials: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + API3: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuthNoCallerCredentials + Method: post + Path: / diff --git a/tests/functional/commands/validate/lib/models/api_with_default_aws_iam_auth_and_no_auth_route.yaml b/tests/functional/commands/validate/lib/models/api_with_default_aws_iam_auth_and_no_auth_route.yaml new file mode 100644 index 0000000000..f777d20087 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_default_aws_iam_auth_and_no_auth_route.yaml @@ -0,0 +1,29 @@ +Resources: + MyApiWithAwsIamAuth: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Auth: + DefaultAuthorizer: AWS_IAM + + MyFunctionWithAwsIamAuth: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs8.10 + Events: + MyApiWithAwsIamAuth: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuth + Path: / + Method: post + MyApiWithNoAuth: + Type: Api + Properties: + RestApiId: !Ref MyApiWithAwsIamAuth + Path: / + Method: get + Auth: + Authorizer: 'NONE' diff --git a/tests/functional/commands/validate/lib/models/api_with_incompatible_stage_name.yaml b/tests/functional/commands/validate/lib/models/api_with_incompatible_stage_name.yaml new file mode 100644 index 0000000000..e6905c3cfa --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_incompatible_stage_name.yaml @@ -0,0 +1,56 @@ +Resources: + HyphenFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + RestApiId: HyphenApi + Path: / + Method: get + RequestModel: + Model: User + Required: true + + HyphenApi: + Type: AWS::Serverless::Api + Properties: + StageName: hoge-fuga + Models: + User: + type: object + properties: + username: + type: string + + UnderscoreFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + RestApiId: UnderscoreApi + Path: / + Method: get + RequestModel: + Model: User + Required: true + + UnderscoreApi: + Type: AWS::Serverless::Api + Properties: + StageName: hoge_fuga + Models: + User: + type: object + properties: + username: + type: string \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/api_with_ip_range_blacklist.yaml b/tests/functional/commands/validate/lib/models/api_with_ip_range_blacklist.yaml new file mode 100644 index 0000000000..1e68425bce --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_ip_range_blacklist.yaml @@ -0,0 +1,26 @@ +Globals: + Api: + Auth: + ResourcePolicy: + IpRangeBlacklist: ['1.2.3.4'] + AwsAccountWhitelist: ['12345'] +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs8.10 + Events: + Api: + Type: Api + Properties: + Method: Put + Path: /get diff --git a/tests/functional/commands/validate/lib/models/api_with_ip_range_whitelist.yaml b/tests/functional/commands/validate/lib/models/api_with_ip_range_whitelist.yaml new file mode 100644 index 0000000000..508fe7bf22 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_ip_range_whitelist.yaml @@ -0,0 +1,26 @@ +Globals: + Api: + Auth: + ResourcePolicy: + IpRangeWhitelist: ['1.2.3.4'] + IpRangeBlacklist: ['1.2.3.4'] +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs8.10 + Events: + Api: + Type: Api + Properties: + Method: Put + Path: /get diff --git a/tests/functional/commands/validate/lib/models/api_with_open_api_version.yaml b/tests/functional/commands/validate/lib/models/api_with_open_api_version.yaml index dd91b26c9c..33d8c9e1ce 100644 --- a/tests/functional/commands/validate/lib/models/api_with_open_api_version.yaml +++ b/tests/functional/commands/validate/lib/models/api_with_open_api_version.yaml @@ -1,6 +1,6 @@ Globals: Api: - OpenApiVersion: '3.0.1' + OpenApiVersion: 3.0.1 Cors: '*' Resources: diff --git a/tests/functional/commands/validate/lib/models/api_with_path_parameters.yaml b/tests/functional/commands/validate/lib/models/api_with_path_parameters.yaml new file mode 100644 index 0000000000..4e1b751051 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_path_parameters.yaml @@ -0,0 +1,20 @@ +Resources: + HtmlFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + RestApiId: HtmlApi + Path: /{prameter}/resources + Method: get + + HtmlApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionUri: s3://sam-demo-bucket/webpage_swagger.json diff --git a/tests/functional/commands/validate/lib/models/api_with_resource_policy.yaml b/tests/functional/commands/validate/lib/models/api_with_resource_policy.yaml new file mode 100644 index 0000000000..becb35be9d --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_resource_policy.yaml @@ -0,0 +1,41 @@ +Resources: + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + Auth: + ResourcePolicy: + CustomStatements: { + Action: 'execute-api:Invoke', + Resource: ['execute-api:/*/*/*'] + } + ExplicitApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + RestApiId: + Ref: ExplicitApi + Path: /one + Method: get + PostHtml: + Type: Api + Properties: + RestApiId: + Ref: ExplicitApi + Path: /two + Method: post + PutHtml: + Type: Api + Properties: + RestApiId: + Ref: ExplicitApi + Path: /three + Method: put + + \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/api_with_resource_policy_global.yaml b/tests/functional/commands/validate/lib/models/api_with_resource_policy_global.yaml new file mode 100644 index 0000000000..acc834b916 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_resource_policy_global.yaml @@ -0,0 +1,59 @@ +Parameters: + StageName: + Type: String + Default: MyOwnStage +Globals: + Api: + Auth: + ResourcePolicy: + CustomStatements: [{ + Action: 'execute-api:Invoke', + Resource: ['execute-api:/*/*/*'] + }, + { + Action: 'execute-api:blah', + Resource: ['execute-api:/*/*/*'] + } + ] + IpRangeWhitelist: [ '1.2.3.4' ] +Resources: + ExplicitApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + RestApiId: + Ref: ExplicitApi + Path: / + Method: get + + ExplicitApi: + Type: AWS::Serverless::Api + Properties: + StageName: !Ref StageName + DefinitionBody: + swagger: 2.0 + info: + version: '1.0' + title: !Ref AWS::StackName + paths: + "/": + get: + x-amazon-apigateway-integration: + httpMethod: POST + type: aws_proxy + uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ExplicitApiFunction.Arn}/invocations + responses: {} + x-amazon-apigateway-policy: + Version: '2012-10-17' + Statement: + Action: 'sts:AssumeRole' + Effect: Allow + Principal: + Service: 'lambda.amazonaws.com' + diff --git a/tests/functional/commands/validate/lib/models/api_with_resource_policy_global_implicit.yaml b/tests/functional/commands/validate/lib/models/api_with_resource_policy_global_implicit.yaml new file mode 100644 index 0000000000..5ec9536e4b --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_resource_policy_global_implicit.yaml @@ -0,0 +1,26 @@ +Globals: + Api: + Auth: + ResourcePolicy: + CustomStatements: [{ + Action: 'execute-api:Invoke', + Resource: ['execute-api:/*/*/*'] + }, + { + Action: 'execute-api:blah', + Resource: ['execute-api:/*/*/*'] + }] +Resources: + MinimalFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip + Handler: hello.handler + Runtime: python2.7 + Events: + AddItem: + Type: Api + Properties: + Path: /add + Method: post + diff --git a/tests/functional/commands/validate/lib/models/api_with_source_vpc_blacklist.yaml b/tests/functional/commands/validate/lib/models/api_with_source_vpc_blacklist.yaml new file mode 100644 index 0000000000..f8b4e00a5d --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_source_vpc_blacklist.yaml @@ -0,0 +1,26 @@ +Globals: + Api: + Auth: + ResourcePolicy: + SourceVpcBlacklist: ['vpce-3456'] +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs8.10 + Events: + Api: + Type: Api + Properties: + Method: Put + Path: /get + diff --git a/tests/functional/commands/validate/lib/models/api_with_source_vpc_whitelist.yaml b/tests/functional/commands/validate/lib/models/api_with_source_vpc_whitelist.yaml new file mode 100644 index 0000000000..0c81b17f46 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_source_vpc_whitelist.yaml @@ -0,0 +1,38 @@ +Globals: + Api: + Auth: + ResourcePolicy: + SourceVpcWhitelist: ['vpc-1234'] + SourceVpcBlacklist: ['vpce-5678'] + +Resources: + MyFunction: + Type: AWS::Serverless::Function + Properties: + InlineCode: | + exports.handler = async (event) => { + const response = { + statusCode: 200, + body: JSON.stringify('Hello from Lambda!'), + }; + return response; + }; + Handler: index.handler + Runtime: nodejs8.10 + Events: + Api: + Type: Api + Properties: + Method: Put + Path: /get + Fetch: + Type: Api + Properties: + Method: Post + Path: /fetch + + MyApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + diff --git a/tests/functional/commands/validate/lib/models/api_with_stage_tags.yaml b/tests/functional/commands/validate/lib/models/api_with_stage_tags.yaml new file mode 100644 index 0000000000..83473e1163 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/api_with_stage_tags.yaml @@ -0,0 +1,16 @@ +Parameters: + TagValueParam: + Type: String + Default: value + +Resources: + MyApiWithStageTags: + Type: "AWS::Serverless::Api" + Properties: + StageName: Prod + Tags: + TagKey1: TagValue1 + TagKey2: "" + TagKey3: + Ref: TagValueParam + TagKey4: "123" diff --git a/tests/functional/commands/validate/lib/models/cloudwatchevent_schedule_properties.yaml b/tests/functional/commands/validate/lib/models/cloudwatchevent_schedule_properties.yaml new file mode 100644 index 0000000000..72a6120347 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/cloudwatchevent_schedule_properties.yaml @@ -0,0 +1,30 @@ +Resources: + ScheduledFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip?versionId=3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO + Handler: hello.handler + Runtime: python2.7 + Events: + Schedule: + Type: Schedule + Properties: + Schedule: 'rate(1 minute)' + Name: test-schedule + Description: Test Schedule + Enabled: True + + TriggeredFunction: + Type: 'AWS::Serverless::Function' + Properties: + CodeUri: s3://sam-demo-bucket/hello.zip?versionId=3Tcgv52_0GaDvhDva4YciYeqRyPnpIcO + Handler: hello.handler + Runtime: python2.7 + Events: + OnTerminate: + Type: CloudWatchEvent + Properties: + Pattern: + detail: + state: + - terminated diff --git a/tests/functional/commands/validate/lib/models/cognito_userpool_with_event.yaml b/tests/functional/commands/validate/lib/models/cognito_userpool_with_event.yaml new file mode 100644 index 0000000000..bcd6b474ff --- /dev/null +++ b/tests/functional/commands/validate/lib/models/cognito_userpool_with_event.yaml @@ -0,0 +1,25 @@ +Resources: + UserPool: + Type: AWS::Cognito::UserPool + Properties: + LambdaConfig: + PreAuthentication: "Test" + ImplicitApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + OneTrigger: + Type: Cognito + Properties: + UserPool: + Ref: UserPool + Trigger: PreSignUp + TwoTrigger: + Type: Cognito + Properties: + UserPool: + Ref: UserPool + Trigger: [Test1, Test2] \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/function_with_batch_window.yaml b/tests/functional/commands/validate/lib/models/function_with_batch_window.yaml new file mode 100644 index 0000000000..606734458b --- /dev/null +++ b/tests/functional/commands/validate/lib/models/function_with_batch_window.yaml @@ -0,0 +1,69 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: EventSourceMapping example with MaximumBatchingWindowInSeconds property + +Parameters: + MyBatchingWindowParam: + Type: Number + Default: 45 + Description: parameter for batching window in seconds + +Resources: + MyFunctionForBatchingExample: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + InlineCode: | + + exports.handler = async (event) => { + return { + statusCode: 200, + body: JSON.stringify(event), + headers: {} + } + } + Runtime: nodejs8.10 + Events: + Stream: + Type: Kinesis + Properties: + Stream: !GetAtt KinesisStream.Arn + MaximumBatchingWindowInSeconds: 20 + StartingPosition: LATEST + StreamEvent: + Type: Kinesis + Properties: + Stream: !GetAtt KinesisStream1.Arn + MaximumBatchingWindowInSeconds: !Ref MyBatchingWindowParam + StartingPosition: LATEST + DynamoDBStreamEvent: + Type: DynamoDB + Properties: + Stream: !GetAtt DynamoDBTable.StreamArn + BatchSize: 100 + MaximumBatchingWindowInSeconds: !Ref MyBatchingWindowParam + StartingPosition: TRIM_HORIZON + + KinesisStream: + Type: AWS::Kinesis::Stream + Properties: + ShardCount: 1 + + KinesisStream1: + Type: AWS::Kinesis::Stream + Properties: + ShardCount: 1 + DynamoDBTable: + Type: AWS::DynamoDB::Table + Properties: + AttributeDefinitions: + - AttributeName: id + AttributeType: S + KeySchema: + - AttributeName: id + KeyType: HASH + ProvisionedThroughput: + ReadCapacityUnits: 5 + WriteCapacityUnits: 5 + StreamSpecification: + StreamViewType: NEW_IMAGE \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/function_with_conditional_managed_policy.yaml b/tests/functional/commands/validate/lib/models/function_with_conditional_managed_policy.yaml new file mode 100644 index 0000000000..6bfed9d071 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/function_with_conditional_managed_policy.yaml @@ -0,0 +1,17 @@ +Conditions: + DummyCondition: + !Equals ["", ""] + +Resources: + FunctionWithConditionalPolicy: + Type: AWS::Serverless::Function + Properties: + Description: A function that has Fn::If in the policies property + Handler: hello.handler + Runtime: python2.7 + CodeUri: s3://sam-demo-bucket/hello.zip + Policies: + - !If + - DummyCondition + - !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess + - !Sub arn:${AWS::Partition}:iam::aws:policy/ReadOnlyAccess \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/function_with_conditional_managed_policy_and_ref_no_value.yaml b/tests/functional/commands/validate/lib/models/function_with_conditional_managed_policy_and_ref_no_value.yaml new file mode 100644 index 0000000000..62f9528016 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/function_with_conditional_managed_policy_and_ref_no_value.yaml @@ -0,0 +1,17 @@ +Conditions: + DummyCondition: + !Equals ["", ""] + +Resources: + FunctionWithConditionalPolicy: + Type: AWS::Serverless::Function + Properties: + Description: A function that has Fn::If in the policies property + Handler: hello.handler + Runtime: python2.7 + CodeUri: s3://sam-demo-bucket/hello.zip + Policies: + - !If + - DummyCondition + - !Sub arn:${AWS::Partition}:iam::aws:policy/AdministratorAccess + - !Ref "AWS::NoValue" \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/function_with_conditional_policy_template.yaml b/tests/functional/commands/validate/lib/models/function_with_conditional_policy_template.yaml new file mode 100644 index 0000000000..4b7a0b8fe9 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/function_with_conditional_policy_template.yaml @@ -0,0 +1,19 @@ +Conditions: + DummyCondition: + !Equals ["", ""] + +Resources: + FunctionWithConditionalPolicy: + Type: AWS::Serverless::Function + Properties: + Description: A function that has Fn::If in the policies property + Handler: hello.handler + Runtime: python2.7 + CodeUri: s3://sam-demo-bucket/hello.zip + Policies: + - !If + - DummyCondition + - AWSSecretsManagerGetSecretValuePolicy: + SecretArn: "Dummy Secret Arn" + - AWSSecretsManagerRotationPolicy: + FunctionName: "Dummy Function Name" \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/function_with_conditional_policy_template_and_ref_no_value.yaml b/tests/functional/commands/validate/lib/models/function_with_conditional_policy_template_and_ref_no_value.yaml new file mode 100644 index 0000000000..432b4db2ab --- /dev/null +++ b/tests/functional/commands/validate/lib/models/function_with_conditional_policy_template_and_ref_no_value.yaml @@ -0,0 +1,18 @@ +Conditions: + DummyCondition: + !Equals ["", ""] + +Resources: + FunctionWithConditionalPolicy: + Type: AWS::Serverless::Function + Properties: + Description: A function that has Fn::If in the policies property + Handler: hello.handler + Runtime: python2.7 + CodeUri: s3://sam-demo-bucket/hello.zip + Policies: + - !If + - DummyCondition + - AWSSecretsManagerGetSecretValuePolicy: + SecretArn: "Dummy Secret Arn" + - !Ref "AWS::NoValue" \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/function_with_request_parameters.yaml b/tests/functional/commands/validate/lib/models/function_with_request_parameters.yaml new file mode 100644 index 0000000000..ebc89f8937 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/function_with_request_parameters.yaml @@ -0,0 +1,40 @@ +Resources: + + Api: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + + ApiParameterFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + RestApiId: Api + Path: / + Method: get + RequestParameters: + - method.request.header.Authorization: + Required: true + Caching: true + + NoApiParameterFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/member_portal.zip + Handler: index.gethtml + Runtime: nodejs4.3 + Events: + GetHtml: + Type: Api + Properties: + Path: / + Method: get + RequestParameters: + - method.request.querystring.type + - method.request.path.id diff --git a/tests/functional/commands/validate/lib/models/function_with_sns_event_source_all_parameters.yaml b/tests/functional/commands/validate/lib/models/function_with_sns_event_source_all_parameters.yaml index a745b2f9c8..65711e7330 100644 --- a/tests/functional/commands/validate/lib/models/function_with_sns_event_source_all_parameters.yaml +++ b/tests/functional/commands/validate/lib/models/function_with_sns_event_source_all_parameters.yaml @@ -11,6 +11,7 @@ Resources: Type: SNS Properties: Topic: topicArn + Region: region FilterPolicy: store: - example_corp diff --git a/tests/functional/commands/validate/lib/models/globals_for_api.yaml b/tests/functional/commands/validate/lib/models/globals_for_api.yaml index 5d3a956322..92aca3703e 100644 --- a/tests/functional/commands/validate/lib/models/globals_for_api.yaml +++ b/tests/functional/commands/validate/lib/models/globals_for_api.yaml @@ -8,6 +8,7 @@ Globals: Authorizers: MyCognitoAuth: UserPoolArn: !GetAtt MyUserPool.Arn + ApiKeyRequired: true Variables: SomeVar: Value diff --git a/tests/functional/commands/validate/lib/models/implicit_api_with_auth_and_conditions_max.yaml b/tests/functional/commands/validate/lib/models/implicit_api_with_auth_and_conditions_max.yaml index 61d2751a21..3c0ac05049 100644 --- a/tests/functional/commands/validate/lib/models/implicit_api_with_auth_and_conditions_max.yaml +++ b/tests/functional/commands/validate/lib/models/implicit_api_with_auth_and_conditions_max.yaml @@ -161,4 +161,6 @@ Resources: Type: Api Properties: Path: /users - Method: put \ No newline at end of file + Method: put + Auth: + ApiKeyRequired: true \ No newline at end of file diff --git a/tests/functional/commands/validate/lib/models/sns_sqs.yaml b/tests/functional/commands/validate/lib/models/sns_sqs.yaml new file mode 100644 index 0000000000..06f262fec5 --- /dev/null +++ b/tests/functional/commands/validate/lib/models/sns_sqs.yaml @@ -0,0 +1,23 @@ +Resources: + SaveNotificationFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/notifications.zip + Handler: index.save_notification + Runtime: nodejs8.10 + Events: + NotificationTopic: + Type: SNS + Properties: + Topic: !Ref Notifications + SqsSubscription: true + FilterPolicy: + store: + - example_corp + price_usd: + - numeric: + - ">=" + - 100 + + Notifications: + Type: AWS::SNS::Topic diff --git a/tests/functional/commands/validate/lib/test_sam_template_validator.py b/tests/functional/commands/validate/lib/test_sam_template_validator.py index f24cd6f7e9..f421a0d4ec 100644 --- a/tests/functional/commands/validate/lib/test_sam_template_validator.py +++ b/tests/functional/commands/validate/lib/test_sam_template_validator.py @@ -19,12 +19,17 @@ class TestValidate(TestCase): ("tests/functional/commands/validate/lib/models/api_request_model.yaml"), ("tests/functional/commands/validate/lib/models/api_request_model_openapi_3.yaml"), ("tests/functional/commands/validate/lib/models/api_with_access_log_setting.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_apikey_default_override.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_apikey_required.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_apikey_required_openapi_3.yaml"), ("tests/functional/commands/validate/lib/models/api_with_auth_all_maximum.yaml"), ("tests/functional/commands/validate/lib/models/api_with_auth_all_maximum_openapi_3.yaml"), ("tests/functional/commands/validate/lib/models/api_with_auth_all_minimum.yaml"), ("tests/functional/commands/validate/lib/models/api_with_auth_all_minimum_openapi.yaml"), ("tests/functional/commands/validate/lib/models/api_with_auth_and_conditions_all_max.yaml"), ("tests/functional/commands/validate/lib/models/api_with_auth_no_default.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_aws_account_blacklist.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_aws_account_whitelist.yaml"), ("tests/functional/commands/validate/lib/models/api_with_aws_iam_auth_overrides.yaml"), ("tests/functional/commands/validate/lib/models/api_with_binary_media_types.yaml"), ("tests/functional/commands/validate/lib/models/api_with_binary_media_types_definition_body.yaml"), @@ -41,26 +46,40 @@ class TestValidate(TestCase): ("tests/functional/commands/validate/lib/models/api_with_cors_no_definitionbody.yaml"), ("tests/functional/commands/validate/lib/models/api_with_cors_openapi_3.yaml"), ("tests/functional/commands/validate/lib/models/api_with_default_aws_iam_auth.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_default_aws_iam_auth_and_no_auth_route.yaml"), ("tests/functional/commands/validate/lib/models/api_with_gateway_responses.yaml"), ("tests/functional/commands/validate/lib/models/api_with_gateway_responses_all.yaml"), ("tests/functional/commands/validate/lib/models/api_with_gateway_responses_all_openapi_3.yaml"), ("tests/functional/commands/validate/lib/models/api_with_gateway_responses_implicit.yaml"), ("tests/functional/commands/validate/lib/models/api_with_gateway_responses_minimal.yaml"), ("tests/functional/commands/validate/lib/models/api_with_gateway_responses_string_status_code.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_incompatible_stage_name.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_ip_range_blacklist.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_ip_range_whitelist.yaml"), ("tests/functional/commands/validate/lib/models/api_with_method_aws_iam_auth.yaml"), ("tests/functional/commands/validate/lib/models/api_with_method_settings.yaml"), ("tests/functional/commands/validate/lib/models/api_with_minimum_compression_size.yaml"), ("tests/functional/commands/validate/lib/models/api_with_open_api_version.yaml"), ("tests/functional/commands/validate/lib/models/api_with_open_api_version_2.yaml"), ("tests/functional/commands/validate/lib/models/api_with_openapi_definition_body_no_flag.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_path_parameters.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_resource_policy.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_resource_policy_global.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_resource_policy_global_implicit.yaml"), ("tests/functional/commands/validate/lib/models/api_with_resource_refs.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_source_vpc_blacklist.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_source_vpc_whitelist.yaml"), + ("tests/functional/commands/validate/lib/models/api_with_stage_tags.yaml"), ("tests/functional/commands/validate/lib/models/api_with_swagger_and_openapi_with_auth.yaml"), ("tests/functional/commands/validate/lib/models/api_with_xray_tracing.yaml"), + ("tests/functional/commands/validate/lib/models/basic_function.yaml"), ("tests/functional/commands/validate/lib/models/basic_function_with_tags.yaml"), ("tests/functional/commands/validate/lib/models/basic_layer.yaml"), ("tests/functional/commands/validate/lib/models/cloudwatch_logs_with_ref.yaml"), ("tests/functional/commands/validate/lib/models/cloudwatchevent.yaml"), + ("tests/functional/commands/validate/lib/models/cloudwatchevent_schedule_properties.yaml"), ("tests/functional/commands/validate/lib/models/cloudwatchlog.yaml"), + ("tests/functional/commands/validate/lib/models/cognito_userpool_with_event.yaml"), ("tests/functional/commands/validate/lib/models/depends_on.yaml"), ("tests/functional/commands/validate/lib/models/explicit_api.yaml"), ("tests/functional/commands/validate/lib/models/explicit_api_openapi_3.yaml"), @@ -71,7 +90,16 @@ class TestValidate(TestCase): ("tests/functional/commands/validate/lib/models/function_with_alias.yaml"), ("tests/functional/commands/validate/lib/models/function_with_alias_and_event_sources.yaml"), ("tests/functional/commands/validate/lib/models/function_with_alias_intrinsics.yaml"), + ("tests/functional/commands/validate/lib/models/function_with_batch_window.yaml"), ("tests/functional/commands/validate/lib/models/function_with_condition.yaml"), + ("tests/functional/commands/validate/lib/models/function_with_conditional_managed_policy.yaml"), + ( + "tests/functional/commands/validate/lib/models/function_with_conditional_managed_policy_and_ref_no_value.yaml" + ), + ("tests/functional/commands/validate/lib/models/function_with_conditional_policy_template.yaml"), + ( + "tests/functional/commands/validate/lib/models/function_with_conditional_policy_template_and_ref_no_value.yaml" + ), ("tests/functional/commands/validate/lib/models/function_with_custom_codedeploy_deployment_preference.yaml"), ( "tests/functional/commands/validate/lib/models/function_with_custom_conditional_codedeploy_deployment_preference.yaml" @@ -91,6 +119,7 @@ class TestValidate(TestCase): ("tests/functional/commands/validate/lib/models/function_with_many_layers.yaml"), ("tests/functional/commands/validate/lib/models/function_with_permissions_boundary.yaml"), ("tests/functional/commands/validate/lib/models/function_with_policy_templates.yaml"), + ("tests/functional/commands/validate/lib/models/function_with_request_parameters.yaml"), ("tests/functional/commands/validate/lib/models/function_with_resource_refs.yaml"), ("tests/functional/commands/validate/lib/models/function_with_sns_event_source_all_parameters.yaml"), ("tests/functional/commands/validate/lib/models/global_handle_path_level_parameter.yaml"), @@ -124,10 +153,17 @@ class TestValidate(TestCase): ("tests/functional/commands/validate/lib/models/simpletable_with_sse.yaml"), ("tests/functional/commands/validate/lib/models/sns.yaml"), ("tests/functional/commands/validate/lib/models/sns_existing_other_subscription.yaml"), + ("tests/functional/commands/validate/lib/models/sns_sqs.yaml"), ("tests/functional/commands/validate/lib/models/sns_topic_outside_template.yaml"), ("tests/functional/commands/validate/lib/models/sqs.yaml"), ("tests/functional/commands/validate/lib/models/streams.yaml"), ("tests/functional/commands/validate/lib/models/unsupported_resources.yaml"), + ( + "tests/functional/commands/validate/lib/models/function_with_custom_conditional_codedeploy_deployment_preference.yaml" + ), + ( + "tests/functional/commands/validate/lib/models/function_with_deployment_preference_multiple_combinations.yaml" + ), ] def test_valid_template(self): diff --git a/tests/integration/buildcmd/test_build_cmd.py b/tests/integration/buildcmd/test_build_cmd.py index cf075b96af..fef5a26dea 100644 --- a/tests/integration/buildcmd/test_build_cmd.py +++ b/tests/integration/buildcmd/test_build_cmd.py @@ -11,13 +11,16 @@ from parameterized import parameterized from .build_integ_base import BuildIntegBase -from tests.testing_utils import IS_WINDOWS, RUNNING_ON_CI +from tests.testing_utils import IS_WINDOWS, RUNNING_ON_CI, CI_OVERRIDE LOG = logging.getLogger(__name__) -@skipIf(IS_WINDOWS and RUNNING_ON_CI, "Skip build tests on windows when running in CI") +@skipIf( + ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), + "Skip build tests on windows when running in CI unless overridden", +) class TestBuildCommand_PythonFunctions(BuildIntegBase): EXPECTED_FILES_GLOBAL_MANIFEST = set() @@ -100,7 +103,10 @@ def _get_python_version(self): return "python{}.{}".format(sys.version_info.major, sys.version_info.minor) -@skipIf(IS_WINDOWS and RUNNING_ON_CI, "Skip build tests on windows when running in CI") +@skipIf( + ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), + "Skip build tests on windows when running in CI unless overridden", +) class TestBuildCommand_ErrorCases(BuildIntegBase): def test_unsupported_runtime(self): overrides = {"Runtime": "unsupportedpython", "CodeUri": "Python"} @@ -116,7 +122,10 @@ def test_unsupported_runtime(self): self.assertIn("Build Failed", process_stdout) -@skipIf(IS_WINDOWS and RUNNING_ON_CI, "Skip build tests on windows when running in CI") +@skipIf( + ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), + "Skip build tests on windows when running in CI unless overridden", +) class TestBuildCommand_NodeFunctions(BuildIntegBase): EXPECTED_FILES_GLOBAL_MANIFEST = set() @@ -184,12 +193,15 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files, self.assertEqual(actual_files, expected_modules) -@skipIf(IS_WINDOWS and RUNNING_ON_CI, "Skip build tests on windows when running in CI") +@skipIf( + ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), + "Skip build tests on windows when running in CI unless overridden", +) class TestBuildCommand_RubyFunctions(BuildIntegBase): EXPECTED_FILES_GLOBAL_MANIFEST = set() EXPECTED_FILES_PROJECT_MANIFEST = {"app.rb"} - EXPECTED_RUBY_GEM = "httparty" + EXPECTED_RUBY_GEM = "aws-record" FUNCTION_LOGICAL_ID = "Function" @@ -251,7 +263,10 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files, self.assertTrue(any([True if self.EXPECTED_RUBY_GEM in gem else False for gem in os.listdir(str(gem_path))])) -@skipIf(IS_WINDOWS and RUNNING_ON_CI, "Skip build tests on windows when running in CI") +@skipIf( + ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), + "Skip build tests on windows when running in CI unless overridden", +) class TestBuildCommand_Java(BuildIntegBase): EXPECTED_FILES_PROJECT_MANIFEST_GRADLE = {"aws", "lib", "META-INF"} @@ -340,7 +355,10 @@ def _change_to_unix_line_ending(self, path): open_file.write(content) -@skipIf(IS_WINDOWS and RUNNING_ON_CI, "Skip build tests on windows when running in CI") +@skipIf( + ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), + "Skip build tests on windows when running in CI unless overridden", +) class TestBuildCommand_Dotnet_cli_package(BuildIntegBase): FUNCTION_LOGICAL_ID = "Function" @@ -438,7 +456,10 @@ def _verify_built_artifact(self, build_dir, function_logical_id, expected_files) self.assertEqual(actual_files, expected_files) -@skipIf(IS_WINDOWS and RUNNING_ON_CI, "Skip build tests on windows when running in CI") +@skipIf( + ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), + "Skip build tests on windows when running in CI unless overridden", +) class TestBuildCommand_SingleFunctionBuilds(BuildIntegBase): template = "many-functions-template.yaml" diff --git a/tests/integration/local/invoke/runtimes/test_with_runtime_zips.py b/tests/integration/local/invoke/runtimes/test_with_runtime_zips.py index e37f0fd402..0f1290c711 100644 --- a/tests/integration/local/invoke/runtimes/test_with_runtime_zips.py +++ b/tests/integration/local/invoke/runtimes/test_with_runtime_zips.py @@ -5,6 +5,7 @@ from subprocess import Popen, PIPE from nose_parameterized import parameterized, param +import pytest from tests.integration.local.invoke.invoke_integ_base import InvokeIntegBase @@ -30,6 +31,7 @@ def setUp(self): def tearDown(self): os.remove(self.events_file_path) + @pytest.mark.timeout(timeout=300, method="thread") @parameterized.expand([param("Go1xFunction"), param("Java8Function")]) def test_runtime_zip(self, function_name): command_list = self.get_command_list( @@ -43,6 +45,7 @@ def test_runtime_zip(self, function_name): process_stdout = b"".join(process.stdout.readlines()).strip() self.assertEqual(process_stdout.decode("utf-8"), '"Hello World"') + @pytest.mark.timeout(timeout=300, method="thread") def test_custom_provided_runtime(self): command_list = self.get_command_list( "CustomBashFunction", template_path=self.template_path, event_path=self.events_file_path diff --git a/tests/integration/local/invoke/test_integrations_cli.py b/tests/integration/local/invoke/test_integrations_cli.py index 737a926df9..2042e5cf95 100644 --- a/tests/integration/local/invoke/test_integrations_cli.py +++ b/tests/integration/local/invoke/test_integrations_cli.py @@ -8,7 +8,7 @@ from nose_parameterized import parameterized from subprocess import Popen, PIPE from timeit import default_timer as timer - +import pytest import docker from tests.integration.local.invoke.layer_utils import LayerUtils @@ -28,6 +28,7 @@ class TestSamPython36HelloWorldIntegration(InvokeIntegBase): template = Path("template.yml") + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_returncode_is_zero(self): command_list = self.get_command_list( "HelloWorldServerlessFunction", template_path=self.template_path, event_path=self.event_path @@ -38,6 +39,7 @@ def test_invoke_returncode_is_zero(self): self.assertEqual(return_code, 0) + @pytest.mark.timeout(timeout=300, method="thread") def test_function_with_metadata(self): command_list = self.get_command_list("FunctionWithMetadata", template_path=self.template_path, no_event=True) @@ -47,6 +49,7 @@ def test_function_with_metadata(self): self.assertEqual(process_stdout.decode("utf-8"), '"Hello World in a different dir"') + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_returns_execpted_results(self): command_list = self.get_command_list( "HelloWorldServerlessFunction", template_path=self.template_path, event_path=self.event_path @@ -57,6 +60,7 @@ def test_invoke_returns_execpted_results(self): process_stdout = b"".join(process.stdout.readlines()).strip() self.assertEqual(process_stdout.decode("utf-8"), '"Hello world"') + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_of_lambda_function(self): command_list = self.get_command_list( "HelloWorldLambdaFunction", template_path=self.template_path, event_path=self.event_path @@ -67,6 +71,7 @@ def test_invoke_of_lambda_function(self): process_stdout = b"".join(process.stdout.readlines()).strip() self.assertEqual(process_stdout.decode("utf-8"), '"Hello world"') + @pytest.mark.timeout(timeout=300, method="thread") @parameterized.expand([("TimeoutFunction"), ("TimeoutFunctionWithParameter")]) def test_invoke_with_timeout_set(self, function_name): command_list = self.get_command_list( @@ -93,6 +98,7 @@ def test_invoke_with_timeout_set(self, function_name): msg="The return statement in the LambdaFunction " "should never return leading to an empty string", ) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_env_vars(self): command_list = self.get_command_list( "EchoCustomEnvVarFunction", @@ -106,6 +112,7 @@ def test_invoke_with_env_vars(self): process_stdout = b"".join(process.stdout.readlines()).strip() self.assertEqual(process_stdout.decode("utf-8"), '"MyVar"') + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_when_function_writes_stdout(self): command_list = self.get_command_list( "WriteToStdoutFunction", template_path=self.template_path, event_path=self.event_path @@ -120,6 +127,7 @@ def test_invoke_when_function_writes_stdout(self): self.assertIn("Docker Lambda is writing to stdout", process_stderr.decode("utf-8")) self.assertIn("wrote to stdout", process_stdout.decode("utf-8")) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_when_function_writes_stderr(self): command_list = self.get_command_list( "WriteToStderrFunction", template_path=self.template_path, event_path=self.event_path @@ -132,6 +140,7 @@ def test_invoke_when_function_writes_stderr(self): self.assertIn("Docker Lambda is writing to stderr", process_stderr.decode("utf-8")) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_returns_expected_result_when_no_event_given(self): command_list = self.get_command_list("EchoEventFunction", template_path=self.template_path) command_list.append("--no-event") @@ -142,6 +151,7 @@ def test_invoke_returns_expected_result_when_no_event_given(self): self.assertEqual(return_code, 0) self.assertEqual("{}", process_stdout.decode("utf-8")) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_raises_exception_with_noargs_and_event(self): command_list = self.get_command_list( "HelloWorldLambdaFunction", template_path=self.template_path, event_path=self.event_path @@ -154,6 +164,7 @@ def test_invoke_raises_exception_with_noargs_and_event(self): error_output = process_stderr.decode("utf-8") self.assertIn("no_event and event cannot be used together. Please provide only one.", error_output) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_env_using_parameters(self): command_list = self.get_command_list( "EchoEnvWithParameters", @@ -180,6 +191,7 @@ def test_invoke_with_env_using_parameters(self): self.assertEqual(environ["Timeout"], "100") self.assertEqual(environ["MyRuntimeVersion"], "v0") + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_env_using_parameters_with_custom_region(self): custom_region = "my-custom-region" @@ -194,6 +206,7 @@ def test_invoke_with_env_using_parameters_with_custom_region(self): self.assertEqual(environ["Region"], custom_region) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_env_with_aws_creds(self): custom_region = "my-custom-region" key = "key" @@ -222,6 +235,7 @@ def test_invoke_with_env_with_aws_creds(self): self.assertEqual(environ["AWS_SECRET_ACCESS_KEY"], secret) self.assertEqual(environ["AWS_SESSION_TOKEN"], session) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_docker_network_of_host(self): command_list = self.get_command_list( "HelloWorldServerlessFunction", @@ -235,6 +249,7 @@ def test_invoke_with_docker_network_of_host(self): self.assertEqual(return_code, 0) + @pytest.mark.timeout(timeout=300, method="thread") @skipIf(IS_WINDOWS, "The test hangs on Windows due to trying to attach to a non-existing network") def test_invoke_with_docker_network_of_host_in_env_var(self): command_list = self.get_command_list( @@ -250,6 +265,7 @@ def test_invoke_with_docker_network_of_host_in_env_var(self): self.assertIn('Not Found ("network non-existing-network not found")', process_stderr.decode("utf-8")) + @pytest.mark.timeout(timeout=300, method="thread") def test_sam_template_file_env_var_set(self): command_list = self.get_command_list("HelloWorldFunctionInNonDefaultTemplate", event_path=self.event_path) @@ -263,6 +279,7 @@ def test_sam_template_file_env_var_set(self): self.assertEqual(process_stdout.decode("utf-8"), '"Hello world"') + @pytest.mark.timeout(timeout=300, method="thread") def test_skip_pull_image_in_env_var(self): docker.from_env().api.pull("lambci/lambda:python3.6") @@ -288,6 +305,7 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.config_dir, ignore_errors=True) + @pytest.mark.timeout(timeout=300, method="thread") def test_existing_env_variables_precedence_over_profiles(self): profile = "default" custom_config = self._create_config_file(profile) @@ -322,6 +340,7 @@ def test_existing_env_variables_precedence_over_profiles(self): self.assertEqual(environ["AWS_SECRET_ACCESS_KEY"], "priority_secret_key_id") self.assertEqual(environ["AWS_SESSION_TOKEN"], "priority_secret_token") + @pytest.mark.timeout(timeout=300, method="thread") def test_default_profile_with_custom_configs(self): profile = "default" custom_config = self._create_config_file(profile) @@ -353,6 +372,7 @@ def test_default_profile_with_custom_configs(self): self.assertEqual(environ["AWS_SECRET_ACCESS_KEY"], "shhhhhthisisasecret") self.assertEqual(environ["AWS_SESSION_TOKEN"], "sessiontoken") + @pytest.mark.timeout(timeout=300, method="thread") def test_custom_profile_with_custom_configs(self): custom_config = self._create_config_file("custom") custom_cred = self._create_cred_file("custom") @@ -383,6 +403,7 @@ def test_custom_profile_with_custom_configs(self): self.assertEqual(environ["AWS_SECRET_ACCESS_KEY"], "shhhhhthisisasecret") self.assertEqual(environ["AWS_SESSION_TOKEN"], "sessiontoken") + @pytest.mark.timeout(timeout=300, method="thread") def test_custom_profile_through_envrionment_variables(self): # When using a custom profile in a custom location, you need both the config # and credential file otherwise we fail to find a region or the profile (depending diff --git a/tests/integration/local/start_api/test_start_api.py b/tests/integration/local/start_api/test_start_api.py index 08a68ed70c..deba58b4f9 100644 --- a/tests/integration/local/start_api/test_start_api.py +++ b/tests/integration/local/start_api/test_start_api.py @@ -2,6 +2,8 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from time import time +import pytest + from samcli.local.apigw.local_apigw_service import Route from .start_api_integ_base import StartApiIntegBaseClass @@ -17,6 +19,8 @@ class TestParallelRequests(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_same_endpoint(self): """ Send two requests to the same path at the same time. This is to ensure we can handle @@ -41,6 +45,8 @@ def test_same_endpoint(self): self.assertEqual(result.status_code, 200) self.assertEqual(result.json(), {"message": "HelloWorld! I just slept and waking up."}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_different_endpoints(self): """ Send two requests to different paths at the same time. This is to ensure we can handle @@ -79,24 +85,32 @@ class TestServiceErrorResponses(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_invalid_http_verb_for_endpoint(self): - response = requests.get(self.url + "/id") + response = requests.get(self.url + "/id", timeout=300) self.assertEqual(response.status_code, 403) self.assertEqual(response.json(), {"message": "Missing Authentication Token"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_invalid_response_from_lambda(self): - response = requests.get(self.url + "/invalidresponsereturned") + response = requests.get(self.url + "/invalidresponsereturned", timeout=300) self.assertEqual(response.status_code, 502) self.assertEqual(response.json(), {"message": "Internal server error"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_invalid_json_response_from_lambda(self): - response = requests.get(self.url + "/invalidresponsehash") + response = requests.get(self.url + "/invalidresponsehash", timeout=300) self.assertEqual(response.status_code, 502) self.assertEqual(response.json(), {"message": "Internal server error"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_request_timeout(self): pass @@ -114,69 +128,85 @@ def setUp(self): def test_static_directory(self): pass + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_calling_proxy_endpoint(self): - response = requests.get(self.url + "/proxypath/this/is/some/path") + response = requests.get(self.url + "/proxypath/this/is/some/path", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_get_call_with_path_setup_with_any_implicit_api(self): """ Get Request to a path that was defined as ANY in SAM through AWS::Serverless::Function Events """ - response = requests.get(self.url + "/anyandall") + response = requests.get(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_post_call_with_path_setup_with_any_implicit_api(self): """ Post Request to a path that was defined as ANY in SAM through AWS::Serverless::Function Events """ - response = requests.post(self.url + "/anyandall", json={}) + response = requests.post(self.url + "/anyandall", json={}, timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_put_call_with_path_setup_with_any_implicit_api(self): """ Put Request to a path that was defined as ANY in SAM through AWS::Serverless::Function Events """ - response = requests.put(self.url + "/anyandall", json={}) + response = requests.put(self.url + "/anyandall", json={}, timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_head_call_with_path_setup_with_any_implicit_api(self): """ Head Request to a path that was defined as ANY in SAM through AWS::Serverless::Function Events """ - response = requests.head(self.url + "/anyandall") + response = requests.head(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_delete_call_with_path_setup_with_any_implicit_api(self): """ Delete Request to a path that was defined as ANY in SAM through AWS::Serverless::Function Events """ - response = requests.delete(self.url + "/anyandall") + response = requests.delete(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_options_call_with_path_setup_with_any_implicit_api(self): """ Options Request to a path that was defined as ANY in SAM through AWS::Serverless::Function Events """ - response = requests.options(self.url + "/anyandall") + response = requests.options(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_patch_call_with_path_setup_with_any_implicit_api(self): """ Patch Request to a path that was defined as ANY in SAM through AWS::Serverless::Function Events """ - response = requests.patch(self.url + "/anyandall") + response = requests.patch(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) @@ -189,105 +219,129 @@ class TestStartApiWithSwaggerApis(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_get_call_with_path_setup_with_any_swagger(self): """ Get Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.get(self.url + "/anyandall") + response = requests.get(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_post_call_with_path_setup_with_any_swagger(self): """ Post Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.post(self.url + "/anyandall", json={}) + response = requests.post(self.url + "/anyandall", json={}, timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_put_call_with_path_setup_with_any_swagger(self): """ Put Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.put(self.url + "/anyandall", json={}) + response = requests.put(self.url + "/anyandall", json={}, timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_head_call_with_path_setup_with_any_swagger(self): """ Head Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.head(self.url + "/anyandall") + response = requests.head(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_delete_call_with_path_setup_with_any_swagger(self): """ Delete Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.delete(self.url + "/anyandall") + response = requests.delete(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_options_call_with_path_setup_with_any_swagger(self): """ Options Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.options(self.url + "/anyandall") + response = requests.options(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_patch_call_with_path_setup_with_any_swagger(self): """ Patch Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.patch(self.url + "/anyandall") + response = requests.patch(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_function_not_defined_in_template(self): - response = requests.get(self.url + "/nofunctionfound") + response = requests.get(self.url + "/nofunctionfound", timeout=300) self.assertEqual(response.status_code, 502) self.assertEqual(response.json(), {"message": "No function defined for resource method"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_function_with_no_api_event_is_reachable(self): - response = requests.get(self.url + "/functionwithnoapievent") + response = requests.get(self.url + "/functionwithnoapievent", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_lambda_function_resource_is_reachable(self): - response = requests.get(self.url + "/nonserverlessfunction") + response = requests.get(self.url + "/nonserverlessfunction", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_binary_request(self): """ This tests that the service can accept and invoke a lambda when given binary data in a request """ input_data = self.get_binary_data(self.binary_data_file) response = requests.post( - self.url + "/echobase64eventbody", headers={"Content-Type": "image/gif"}, data=input_data + self.url + "/echobase64eventbody", headers={"Content-Type": "image/gif"}, data=input_data, timeout=300 ) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "image/gif") self.assertEqual(response.content, input_data) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_binary_response(self): """ Binary data is returned correctly """ expected = self.get_binary_data(self.binary_data_file) - response = requests.get(self.url + "/base64response") + response = requests.get(self.url + "/base64response", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "image/gif") @@ -301,99 +355,121 @@ class TestStartApiWithSwaggerRestApis(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_get_call_with_path_setup_with_any_swagger(self): """ Get Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.get(self.url + "/anyandall") + response = requests.get(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_post_call_with_path_setup_with_any_swagger(self): """ Post Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.post(self.url + "/anyandall", json={}) + response = requests.post(self.url + "/anyandall", json={}, timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_put_call_with_path_setup_with_any_swagger(self): """ Put Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.put(self.url + "/anyandall", json={}) + response = requests.put(self.url + "/anyandall", json={}, timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_head_call_with_path_setup_with_any_swagger(self): """ Head Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.head(self.url + "/anyandall") + response = requests.head(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_delete_call_with_path_setup_with_any_swagger(self): """ Delete Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.delete(self.url + "/anyandall") + response = requests.delete(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_options_call_with_path_setup_with_any_swagger(self): """ Options Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.options(self.url + "/anyandall") + response = requests.options(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_patch_call_with_path_setup_with_any_swagger(self): """ Patch Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.patch(self.url + "/anyandall") + response = requests.patch(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_function_not_defined_in_template(self): - response = requests.get(self.url + "/nofunctionfound") + response = requests.get(self.url + "/nofunctionfound", timeout=300) self.assertEqual(response.status_code, 502) self.assertEqual(response.json(), {"message": "No function defined for resource method"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_lambda_function_resource_is_reachable(self): - response = requests.get(self.url + "/nonserverlessfunction") + response = requests.get(self.url + "/nonserverlessfunction", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_binary_request(self): """ This tests that the service can accept and invoke a lambda when given binary data in a request """ input_data = self.get_binary_data(self.binary_data_file) response = requests.post( - self.url + "/echobase64eventbody", headers={"Content-Type": "image/gif"}, data=input_data + self.url + "/echobase64eventbody", headers={"Content-Type": "image/gif"}, data=input_data, timeout=300 ) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "image/gif") self.assertEqual(response.content, input_data) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_binary_response(self): """ Binary data is returned correctly """ expected = self.get_binary_data(self.binary_data_file) - response = requests.get(self.url + "/base64response") + response = requests.get(self.url + "/base64response", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "image/gif") @@ -411,83 +487,103 @@ class TestServiceResponses(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_multiple_headers_response(self): - response = requests.get(self.url + "/multipleheaders") + response = requests.get(self.url + "/multipleheaders", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "text/plain") self.assertEqual(response.headers.get("MyCustomHeader"), "Value1, Value2") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_multiple_headers_overrides_headers_response(self): - response = requests.get(self.url + "/multipleheadersoverridesheaders") + response = requests.get(self.url + "/multipleheadersoverridesheaders", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "text/plain") self.assertEqual(response.headers.get("MyCustomHeader"), "Value1, Value2, Custom") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_binary_response(self): """ Binary data is returned correctly """ expected = self.get_binary_data(self.binary_data_file) - response = requests.get(self.url + "/base64response") + response = requests.get(self.url + "/base64response", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "image/gif") self.assertEqual(response.content, expected) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_default_header_content_type(self): """ Test that if no ContentType is given the default is "application/json" """ - response = requests.get(self.url + "/onlysetstatuscode") + response = requests.get(self.url + "/onlysetstatuscode", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.content.decode("utf-8"), "no data") self.assertEqual(response.headers.get("Content-Type"), "application/json") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_default_status_code(self): """ Test that if no status_code is given, the status code is 200 :return: """ - response = requests.get(self.url + "/onlysetbody") + response = requests.get(self.url + "/onlysetbody", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_string_status_code(self): """ Test that an integer-string can be returned as the status code """ - response = requests.get(self.url + "/stringstatuscode") + response = requests.get(self.url + "/stringstatuscode", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_default_body(self): """ Test that if no body is given, the response is 'no data' """ - response = requests.get(self.url + "/onlysetstatuscode") + response = requests.get(self.url + "/onlysetstatuscode", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.content.decode("utf-8"), "no data") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_function_writing_to_stdout(self): - response = requests.get(self.url + "/writetostdout") + response = requests.get(self.url + "/writetostdout", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_function_writing_to_stderr(self): - response = requests.get(self.url + "/writetostderr") + response = requests.get(self.url + "/writetostderr", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_integer_body(self): - response = requests.get(self.url + "/echo_integer_body") + response = requests.get(self.url + "/echo_integer_body", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.content.decode("utf-8"), "42") @@ -504,25 +600,32 @@ class TestServiceRequests(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_binary_request(self): """ This tests that the service can accept and invoke a lambda when given binary data in a request """ input_data = self.get_binary_data(self.binary_data_file) response = requests.post( - self.url + "/echobase64eventbody", headers={"Content-Type": "image/gif"}, data=input_data + self.url + "/echobase64eventbody", headers={"Content-Type": "image/gif"}, data=input_data, timeout=300 ) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "image/gif") self.assertEqual(response.content, input_data) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_request_with_form_data(self): """ Form-encoded data should be put into the Event to Lambda """ response = requests.post( - self.url + "/echoeventbody", headers={"Content-Type": "application/x-www-form-urlencoded"}, data="key=value" + self.url + "/echoeventbody", + headers={"Content-Type": "application/x-www-form-urlencoded"}, + data="key=value", + timeout=300, ) self.assertEqual(response.status_code, 200) @@ -532,8 +635,10 @@ def test_request_with_form_data(self): self.assertEqual(response_data.get("headers").get("Content-Type"), "application/x-www-form-urlencoded") self.assertEqual(response_data.get("body"), "key=value") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_request_to_an_endpoint_with_two_different_handlers(self): - response = requests.get(self.url + "/echoeventbody") + response = requests.get(self.url + "/echoeventbody", timeout=300) self.assertEqual(response.status_code, 200) @@ -541,9 +646,13 @@ def test_request_to_an_endpoint_with_two_different_handlers(self): self.assertEqual(response_data.get("handler"), "echo_event_handler_2") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_request_with_multi_value_headers(self): response = requests.get( - self.url + "/echoeventbody", headers={"Content-Type": "application/x-www-form-urlencoded, image/gif"} + self.url + "/echoeventbody", + headers={"Content-Type": "application/x-www-form-urlencoded, image/gif"}, + timeout=300, ) self.assertEqual(response.status_code, 200) @@ -555,11 +664,13 @@ def test_request_with_multi_value_headers(self): response_data.get("headers").get("Content-Type"), "application/x-www-form-urlencoded, image/gif" ) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_request_with_query_params(self): """ Query params given should be put into the Event to Lambda """ - response = requests.get(self.url + "/id/4", params={"key": "value"}) + response = requests.get(self.url + "/id/4", params={"key": "value"}, timeout=300) self.assertEqual(response.status_code, 200) @@ -568,11 +679,13 @@ def test_request_with_query_params(self): self.assertEqual(response_data.get("queryStringParameters"), {"key": "value"}) self.assertEqual(response_data.get("multiValueQueryStringParameters"), {"key": ["value"]}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_request_with_list_of_query_params(self): """ Query params given should be put into the Event to Lambda """ - response = requests.get(self.url + "/id/4", params={"key": ["value", "value2"]}) + response = requests.get(self.url + "/id/4", params={"key": ["value", "value2"]}, timeout=300) self.assertEqual(response.status_code, 200) @@ -581,11 +694,13 @@ def test_request_with_list_of_query_params(self): self.assertEqual(response_data.get("queryStringParameters"), {"key": "value2"}) self.assertEqual(response_data.get("multiValueQueryStringParameters"), {"key": ["value", "value2"]}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_request_with_path_params(self): """ Path Parameters given should be put into the Event to Lambda """ - response = requests.get(self.url + "/id/4") + response = requests.get(self.url + "/id/4", timeout=300) self.assertEqual(response.status_code, 200) @@ -593,11 +708,13 @@ def test_request_with_path_params(self): self.assertEqual(response_data.get("pathParameters"), {"id": "4"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_request_with_many_path_params(self): """ Path Parameters given should be put into the Event to Lambda """ - response = requests.get(self.url + "/id/4/user/jacob") + response = requests.get(self.url + "/id/4/user/jacob", timeout=300) self.assertEqual(response.status_code, 200) @@ -605,11 +722,13 @@ def test_request_with_many_path_params(self): self.assertEqual(response_data.get("pathParameters"), {"id": "4", "user": "jacob"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_forward_headers_are_added_to_event(self): """ Test the Forwarding Headers exist in the Api Event to Lambda """ - response = requests.get(self.url + "/id/4") + response = requests.get(self.url + "/id/4", timeout=300) response_data = response.json() @@ -629,8 +748,10 @@ class TestStartApiWithStage(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_default_stage_name(self): - response = requests.get(self.url + "/echoeventbody") + response = requests.get(self.url + "/echoeventbody", timeout=300) self.assertEqual(response.status_code, 200) @@ -638,8 +759,10 @@ def test_default_stage_name(self): self.assertEqual(response_data.get("requestContext", {}).get("stage"), "Prod") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_global_stage_variables(self): - response = requests.get(self.url + "/echoeventbody") + response = requests.get(self.url + "/echoeventbody", timeout=300) self.assertEqual(response.status_code, 200) @@ -658,16 +781,20 @@ class TestStartApiWithStageAndSwagger(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_swagger_stage_name(self): - response = requests.get(self.url + "/echoeventbody") + response = requests.get(self.url + "/echoeventbody", timeout=300) self.assertEqual(response.status_code, 200) response_data = response.json() self.assertEqual(response_data.get("requestContext", {}).get("stage"), "dev") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_swagger_stage_variable(self): - response = requests.get(self.url + "/echoeventbody") + response = requests.get(self.url + "/echoeventbody", timeout=300) self.assertEqual(response.status_code, 200) @@ -686,11 +813,13 @@ class TestServiceCorsSwaggerRequests(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_cors_swagger_options(self): """ This tests that the Cors are added to option requests in the swagger template """ - response = requests.options(self.url + "/echobase64eventbody") + response = requests.options(self.url + "/echobase64eventbody", timeout=300) self.assertEqual(response.status_code, 200) @@ -710,11 +839,13 @@ class TestServiceCorsGlobalRequests(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_cors_global(self): """ This tests that the Cors are added to options requests when the global property is set """ - response = requests.options(self.url + "/echobase64eventbody") + response = requests.options(self.url + "/echobase64eventbody", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Access-Control-Allow-Origin"), "*") @@ -722,11 +853,13 @@ def test_cors_global(self): self.assertEqual(response.headers.get("Access-Control-Allow-Methods"), ",".join(sorted(Route.ANY_HTTP_METHODS))) self.assertEqual(response.headers.get("Access-Control-Max-Age"), None) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_cors_global_get(self): """ This tests that the Cors are added to post requests when the global property is set """ - response = requests.get(self.url + "/onlysetstatuscode") + response = requests.get(self.url + "/onlysetstatuscode", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.content.decode("utf-8"), "no data") @@ -747,16 +880,20 @@ class TestStartApiWithCloudFormationStage(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_default_stage_name(self): - response = requests.get(self.url + "/echoeventbody") + response = requests.get(self.url + "/echoeventbody", timeout=300) self.assertEqual(response.status_code, 200) response_data = response.json() self.assertEqual(response_data.get("requestContext", {}).get("stage"), "Dev") + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_global_stage_variables(self): - response = requests.get(self.url + "/echoeventbody") + response = requests.get(self.url + "/echoeventbody", timeout=300) self.assertEqual(response.status_code, 200) @@ -772,109 +909,133 @@ class TestStartApiWithMethodsAndResources(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_get_call_with_path_setup_with_any_swagger(self): """ Get Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.get(self.url + "/root/anyandall") + response = requests.get(self.url + "/root/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_post_call_with_path_setup_with_any_swagger(self): """ Post Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.post(self.url + "/root/anyandall", json={}) + response = requests.post(self.url + "/root/anyandall", json={}, timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_put_call_with_path_setup_with_any_swagger(self): """ Put Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.put(self.url + "/root/anyandall", json={}) + response = requests.put(self.url + "/root/anyandall", json={}, timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_head_call_with_path_setup_with_any_swagger(self): """ Head Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.head(self.url + "/root/anyandall") + response = requests.head(self.url + "/root/anyandall", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_delete_call_with_path_setup_with_any_swagger(self): """ Delete Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.delete(self.url + "/root/anyandall") + response = requests.delete(self.url + "/root/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_options_call_with_path_setup_with_any_swagger(self): """ Options Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.options(self.url + "/root/anyandall") + response = requests.options(self.url + "/root/anyandall", timeout=300) self.assertEqual(response.status_code, 200) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_patch_call_with_path_setup_with_any_swagger(self): """ Patch Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.patch(self.url + "/root/anyandall") + response = requests.patch(self.url + "/root/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_function_not_defined_in_template(self): - response = requests.get(self.url + "/root/nofunctionfound") + response = requests.get(self.url + "/root/nofunctionfound", timeout=300) self.assertEqual(response.status_code, 502) self.assertEqual(response.json(), {"message": "No function defined for resource method"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_lambda_function_resource_is_reachable(self): - response = requests.get(self.url + "/root/nonserverlessfunction") + response = requests.get(self.url + "/root/nonserverlessfunction", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_binary_request(self): """ This tests that the service can accept and invoke a lambda when given binary data in a request """ input_data = self.get_binary_data(self.binary_data_file) response = requests.post( - self.url + "/root/echobase64eventbody", headers={"Content-Type": "image/gif"}, data=input_data + self.url + "/root/echobase64eventbody", headers={"Content-Type": "image/gif"}, data=input_data, timeout=300 ) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "image/gif") self.assertEqual(response.content, input_data) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_binary_response(self): """ Binary data is returned correctly """ expected = self.get_binary_data(self.binary_data_file) - response = requests.get(self.url + "/root/base64response") + response = requests.get(self.url + "/root/base64response", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.headers.get("Content-Type"), "image/gif") self.assertEqual(response.content, expected) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_proxy_response(self): """ Binary data is returned correctly """ - response = requests.get(self.url + "/root/v1/test") + response = requests.get(self.url + "/root/v1/test", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) @@ -886,11 +1047,13 @@ class TestCDKApiGateway(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_get_with_cdk(self): """ Get Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.get(self.url + "/hello-world") + response = requests.get(self.url + "/hello-world", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) @@ -902,11 +1065,28 @@ class TestServerlessApiGateway(StartApiIntegBaseClass): def setUp(self): self.url = "http://127.0.0.1:{}".format(self.port) + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") def test_get_with_serverless(self): """ Get Request to a path that was defined as ANY in SAM through Swagger """ - response = requests.get(self.url + "/hello-world") + response = requests.get(self.url + "/hello-world", timeout=300) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), {"hello": "world"}) + + +class TestSwaggerIncludedFromSeparateFile(StartApiIntegBaseClass): + template_path = "/testdata/start_api/template-with-included-swagger.yaml" + + def setUp(self): + self.url = "http://127.0.0.1:{}".format(self.port) + + @pytest.mark.flaky(reruns=3) + @pytest.mark.timeout(timeout=600, method="thread") + def test_swagger_was_tranformed_and_api_is_reachable(self): + response = requests.patch(self.url + "/anyandall", timeout=300) self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"hello": "world"}) diff --git a/tests/integration/local/start_lambda/test_start_lambda.py b/tests/integration/local/start_lambda/test_start_lambda.py index daae71ffd6..d2cee30f90 100644 --- a/tests/integration/local/start_lambda/test_start_lambda.py +++ b/tests/integration/local/start_lambda/test_start_lambda.py @@ -1,6 +1,8 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from time import time +import pytest + import boto3 from botocore import UNSIGNED from botocore.config import Config @@ -23,6 +25,7 @@ def setUp(self): config=Config(signature_version=UNSIGNED, read_timeout=120, retries={"max_attempts": 0}), ) + @pytest.mark.timeout(timeout=300, method="thread") def test_same_endpoint(self): """ Send two requests to the same path at the same time. This is to ensure we can handle @@ -61,6 +64,7 @@ def setUp(self): config=Config(signature_version=UNSIGNED, read_timeout=120, retries={"max_attempts": 0}), ) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_non_json_data(self): expected_error_message = ( "An error occurred (InvalidRequestContent) when calling the Invoke operation: " @@ -72,6 +76,7 @@ def test_invoke_with_non_json_data(self): self.assertEqual(str(error.exception), expected_error_message) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_log_type_not_None(self): expected_error_message = ( "An error occurred (NotImplemented) when calling the Invoke operation: " @@ -83,6 +88,7 @@ def test_invoke_with_log_type_not_None(self): self.assertEqual(str(error.exception), expected_error_message) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_invocation_type_not_RequestResponse(self): expected_error_message = ( "An error occurred (NotImplemented) when calling the Invoke operation: " @@ -109,6 +115,7 @@ def setUp(self): config=Config(signature_version=UNSIGNED, read_timeout=120, retries={"max_attempts": 0}), ) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_data(self): response = self.lambda_client.invoke(FunctionName="EchoEventFunction", Payload='"This is json data"') @@ -116,6 +123,7 @@ def test_invoke_with_data(self): self.assertIsNone(response.get("FunctionError")) self.assertEqual(response.get("StatusCode"), 200) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_no_data(self): response = self.lambda_client.invoke(FunctionName="EchoEventFunction") @@ -123,6 +131,7 @@ def test_invoke_with_no_data(self): self.assertIsNone(response.get("FunctionError")) self.assertEqual(response.get("StatusCode"), 200) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_log_type_None(self): response = self.lambda_client.invoke(FunctionName="EchoEventFunction", LogType="None") @@ -130,6 +139,7 @@ def test_invoke_with_log_type_None(self): self.assertIsNone(response.get("FunctionError")) self.assertEqual(response.get("StatusCode"), 200) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_invocation_type_RequestResponse(self): response = self.lambda_client.invoke(FunctionName="EchoEventFunction", InvocationType="RequestResponse") @@ -137,6 +147,7 @@ def test_invoke_with_invocation_type_RequestResponse(self): self.assertIsNone(response.get("FunctionError")) self.assertEqual(response.get("StatusCode"), 200) + @pytest.mark.timeout(timeout=300, method="thread") def test_lambda_function_raised_error(self): response = self.lambda_client.invoke(FunctionName="RaiseExceptionFunction", InvocationType="RequestResponse") @@ -150,6 +161,7 @@ def test_lambda_function_raised_error(self): self.assertEqual(response.get("FunctionError"), "Unhandled") self.assertEqual(response.get("StatusCode"), 200) + @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_function_timeout(self): """ This behavior does not match the actually Lambda Service. For functions that timeout, data returned like the diff --git a/tests/integration/testdata/buildcmd/Ruby/Gemfile b/tests/integration/testdata/buildcmd/Ruby/Gemfile index e214f5af12..72fa463686 100644 --- a/tests/integration/testdata/buildcmd/Ruby/Gemfile +++ b/tests/integration/testdata/buildcmd/Ruby/Gemfile @@ -1,3 +1,3 @@ source "https://rubygems.org" -gem "httparty" \ No newline at end of file +gem "aws-record", "~> 2" diff --git a/tests/integration/testdata/invoke/layers/layer-template.yml b/tests/integration/testdata/invoke/layers/layer-template.yml index e494d42c6f..fcd125e20e 100644 --- a/tests/integration/testdata/invoke/layers/layer-template.yml +++ b/tests/integration/testdata/invoke/layers/layer-template.yml @@ -27,6 +27,7 @@ Resources: Handler: layer-main.one_layer_hanlder Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: LayerOneArn @@ -37,6 +38,7 @@ Resources: Handler: layer-main.one_layer_hanlder Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: ChangedLayerArn @@ -46,6 +48,7 @@ Resources: Handler: layer-main.custom_layer_handler Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: MyCustomServerlessLayer @@ -55,6 +58,7 @@ Resources: Handler: layer-main.custom_layer_handler Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: MyCustomLambdaLayer @@ -64,6 +68,7 @@ Resources: Handler: layer-main.one_layer_hanlder Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: LayerOneArn - Ref: LayerTwoArn @@ -75,6 +80,7 @@ Resources: Handler: layer-main.one_layer_hanlder Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: LayerOneArn @@ -84,6 +90,7 @@ Resources: Handler: layer-main.one_layer_hanlder Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: ChangedLayerArn # @@ -93,6 +100,7 @@ Resources: Handler: layer-main.custom_layer_handler Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: MyCustomServerlessLayer @@ -102,6 +110,7 @@ Resources: Handler: layer-main.custom_layer_handler Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: MyCustomLambdaLayer @@ -111,6 +120,7 @@ Resources: Handler: layer-main.one_layer_hanlder Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: LayerOneArn - Ref: LayerTwoArn @@ -121,6 +131,7 @@ Resources: Handler: layer-main.handler Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - Ref: NonExistentLayerArn @@ -130,6 +141,7 @@ Resources: Handler: layer-main.handler Runtime: python3.6 CodeUri: . + Timeout: 20 Layers: - arn:aws:lambda:us-west-2:111111111101:layer:layerDoesNotExist:1 diff --git a/tests/integration/testdata/invoke/template.yml b/tests/integration/testdata/invoke/template.yml index 3a3d1c51d9..fcb5493e74 100644 --- a/tests/integration/testdata/invoke/template.yml +++ b/tests/integration/testdata/invoke/template.yml @@ -24,6 +24,7 @@ Resources: Properties: Handler: main.handler Runtime: python3.6 + Timeout: 600 TimeoutFunction: Type: AWS::Serverless::Function @@ -39,7 +40,7 @@ Resources: Handler: main.sleep_handler Runtime: python3.6 CodeUri: . - Timeout: 15 + Timeout: 600 EchoCustomEnvVarFunction: Type: AWS::Serverless::Function @@ -50,6 +51,7 @@ Resources: Environment: Variables: CustomEnvVar: "MyVar" + Timeout: 600 WriteToStderrFunction: Type: AWS::Serverless::Function @@ -57,6 +59,7 @@ Resources: Handler: main.write_to_stderr Runtime: python3.6 CodeUri: . + Timeout: 600 WriteToStdoutFunction: Type: AWS::Serverless::Function @@ -64,6 +67,7 @@ Resources: Handler: main.write_to_stdout Runtime: python3.6 CodeUri: . + Timeout: 600 EchoEventFunction: Type: AWS::Serverless::Function @@ -71,6 +75,7 @@ Resources: Handler: main.echo_event Runtime: python3.6 CodeUri: . + Timeout: 600 RaiseExceptionFunction: Type: AWS::Serverless::Function @@ -78,6 +83,7 @@ Resources: Handler: main.raise_exception Runtime: python3.6 CodeUri: . + Timeout: 600 TimeoutFunctionWithParameter: Type: AWS::Serverless::Function @@ -93,6 +99,7 @@ Resources: Properties: Runtime: python3.6 Handler: main.echo_hello_world + Timeout: 600 Metadata: aws:asset:property: CodeUri aws:asset:path: ./different_code_location @@ -103,6 +110,7 @@ Resources: Handler: main.env_var_echo_hanler Runtime: python3.6 CodeUri: . + Timeout: 600 Environment: Variables: Region: !Ref "AWS::Region" diff --git a/tests/integration/testdata/start_api/cdk-sample-output.yaml b/tests/integration/testdata/start_api/cdk-sample-output.yaml index 203ed94906..4a727401e5 100644 --- a/tests/integration/testdata/start_api/cdk-sample-output.yaml +++ b/tests/integration/testdata/start_api/cdk-sample-output.yaml @@ -26,6 +26,7 @@ Resources: Code: '.' Handler: main.handler Runtime: python3.6 + Timeout: 600 HelloHandlerApiPermissionANYAC4E141E: Type: AWS::Lambda::Permission diff --git a/tests/integration/testdata/start_api/methods-resources-api-template.yaml b/tests/integration/testdata/start_api/methods-resources-api-template.yaml index 9c9fc662a4..70b1fc6e74 100644 --- a/tests/integration/testdata/start_api/methods-resources-api-template.yaml +++ b/tests/integration/testdata/start_api/methods-resources-api-template.yaml @@ -6,12 +6,14 @@ Resources: Code: "." Handler: main.base64_response Runtime: python3.6 + Timeout: 600 Type: AWS::Lambda::Function EchoBase64EventBodyFunction: Properties: Code: "." Handler: main.echo_base64_event_body Runtime: python3.6 + Timeout: 600 Type: AWS::Lambda::Function Dev: @@ -27,6 +29,7 @@ Resources: Code: "." Handler: main.handler Runtime: python3.6 + Timeout: 600 Type: AWS::Lambda::Function TestApi: diff --git a/tests/integration/testdata/start_api/serverless-sample-output.yaml b/tests/integration/testdata/start_api/serverless-sample-output.yaml index e181ab7de2..04f48ef94a 100644 --- a/tests/integration/testdata/start_api/serverless-sample-output.yaml +++ b/tests/integration/testdata/start_api/serverless-sample-output.yaml @@ -60,6 +60,7 @@ Resources: FunctionName: serverless-hello-world-dev-helloWorld Handler: main.handler MemorySize: 1024 + Timeout: 600 Role: Fn::GetAtt: - IamRoleLambdaExecution diff --git a/tests/integration/testdata/start_api/swagger-rest-api-template.yaml b/tests/integration/testdata/start_api/swagger-rest-api-template.yaml index 5e7be3a95e..e28aec0f7b 100644 --- a/tests/integration/testdata/start_api/swagger-rest-api-template.yaml +++ b/tests/integration/testdata/start_api/swagger-rest-api-template.yaml @@ -6,18 +6,21 @@ Resources: Code: "." Handler: main.base64_response Runtime: python3.6 + Timeout: 0 Type: AWS::Lambda::Function EchoBase64EventBodyFunction: Properties: Code: "." Handler: main.echo_base64_event_body Runtime: python3.6 + Timeout: 0 Type: AWS::Lambda::Function EchoEventBodyFunction: Properties: Code: "." Handler: main.echo_event_handler Runtime: python3.6 + Timeout: 0 Type: AWS::Lambda::Function MyApi: Properties: @@ -86,4 +89,5 @@ Resources: Code: "." Handler: main.handler Runtime: python3.6 + Timeout: 600 Type: AWS::Lambda::Function diff --git a/tests/integration/testdata/start_api/swagger-template.yaml b/tests/integration/testdata/start_api/swagger-template.yaml index 4073fbd032..d3f417739f 100644 --- a/tests/integration/testdata/start_api/swagger-template.yaml +++ b/tests/integration/testdata/start_api/swagger-template.yaml @@ -89,6 +89,7 @@ Resources: Handler: main.handler Runtime: python3.6 CodeUri: . + Timeout: 600 Events: GetApi: Type: Api @@ -104,6 +105,7 @@ Resources: Handler: main.handler Runtime: python3.6 CodeUri: . + Timeout: 600 MyNonServerlessLambdaFunction: Type: AWS::Lambda::Function @@ -111,6 +113,7 @@ Resources: Handler: main.handler Runtime: python3.6 CodeUri: . + Timeout: 600 Base64ResponseFunction: Type: AWS::Serverless::Function @@ -118,6 +121,7 @@ Resources: Handler: main.base64_response Runtime: python3.6 CodeUri: . + Timeout: 600 EchoBase64EventBodyFunction: Type: AWS::Serverless::Function @@ -125,6 +129,7 @@ Resources: Handler: main.echo_base64_event_body Runtime: python3.6 CodeUri: . + Timeout: 600 EchoEventHandlerFunction: Type: AWS::Serverless::Function @@ -132,6 +137,7 @@ Resources: Handler: main.echo_event_handler Runtime: python3.6 CodeUri: . + Timeout: 600 Events: GetApi: Type: Api diff --git a/tests/integration/testdata/start_api/swagger.yaml b/tests/integration/testdata/start_api/swagger.yaml new file mode 100644 index 0000000000..7638bec54e --- /dev/null +++ b/tests/integration/testdata/start_api/swagger.yaml @@ -0,0 +1,13 @@ +swagger: "2.0" +info: + title: + Ref: AWS::StackName +paths: + "/anyandall": + x-amazon-apigateway-any-method: + x-amazon-apigateway-integration: + httpMethod: POST + type: aws_proxy + uri: + Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}/invocations + responses: {} \ No newline at end of file diff --git a/tests/integration/testdata/start_api/template-with-included-swagger.yaml b/tests/integration/testdata/start_api/template-with-included-swagger.yaml new file mode 100644 index 0000000000..b9f32907eb --- /dev/null +++ b/tests/integration/testdata/start_api/template-with-included-swagger.yaml @@ -0,0 +1,33 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 + +Globals: + Api: + BinaryMediaTypes: + # These are equivalent to image/gif and image/png when deployed + - image~1png + +Resources: + MyApi: + Type: AWS::Serverless::Api + Properties: + StageName: dev + Variables: + VarName: varValue + Cors: + AllowOrigin: "'*''" + AllowMethods: "'GET'" + AllowHeaders: "'origin, x-requested-with'" + MaxAge: "'510'" + DefinitionBody: + Fn::Transform: + Name: AWS::Include + Parameters: + Location: ./swagger.yaml + + MyLambdaFunction: + Type: AWS::Serverless::Function + Properties: + Handler: main.handler + Runtime: python3.6 + CodeUri: . diff --git a/tests/integration/testdata/start_api/template.yaml b/tests/integration/testdata/start_api/template.yaml index 73b6bff06b..ef2eae07a6 100644 --- a/tests/integration/testdata/start_api/template.yaml +++ b/tests/integration/testdata/start_api/template.yaml @@ -17,6 +17,7 @@ Resources: Handler: main.handler Runtime: python3.6 CodeUri: . + Timeout: 600 Events: IdBasePath: Type: Api @@ -42,6 +43,7 @@ Resources: Handler: main.echo_event_handler Runtime: python3.6 CodeUri: . + Timeout: 600 Events: PathWithPathParams: Type: Api @@ -66,6 +68,7 @@ Resources: Properties: Handler: main.echo_event_handler_2 Runtime: python3.6 + Timeout: 600 CodeUri: . Events: EchoEventBodyPath: @@ -80,6 +83,7 @@ Resources: Handler: main.echo_integer_body Runtime: python3.6 CodeUri: . + Timeout: 600 Events: EchoEventBodyPath: Type: Api @@ -93,6 +97,7 @@ Resources: Handler: main.content_type_setter_handler Runtime: python3.6 CodeUri: . + Timeout: 600 Events: ContentTypeSetter: Type: Api @@ -106,6 +111,7 @@ Resources: Handler: main.only_set_status_code_handler Runtime: python3.6 CodeUri: . + Timeout: 600 Events: OnlySetStatusCodePath: Type: Api @@ -119,6 +125,7 @@ Resources: Handler: main.only_set_body_handler Runtime: python3.6 CodeUri: . + Timeout: 600 Events: OnlySetBodyPath: Type: Api @@ -132,6 +139,7 @@ Resources: Handler: main.string_status_code_handler Runtime: python3.6 CodeUri: . + Timeout: 600 Events: StringStatusCodePath: Type: Api @@ -173,6 +181,7 @@ Resources: Handler: main.write_to_stderr Runtime: python3.6 CodeUri: . + Timeout: 600 Events: WriteToStderrPath: Type: Api @@ -186,6 +195,7 @@ Resources: Handler: main.write_to_stdout Runtime: python3.6 CodeUri: . + Timeout: 600 Events: WriteToStdoutPath: Type: Api @@ -199,6 +209,7 @@ Resources: Handler: main.invalid_response_returned Runtime: python3.6 CodeUri: . + Timeout: 600 Events: InvalidResponseReturned: Type: Api @@ -212,6 +223,7 @@ Resources: Handler: main.invalid_hash_response Runtime: python3.6 CodeUri: . + Timeout: 600 Events: InvalidResponseReturned: Type: Api @@ -225,6 +237,7 @@ Resources: Handler: main.base64_response Runtime: python3.6 CodeUri: . + Timeout: 600 Events: Base64ResponsePath: Type: Api @@ -238,6 +251,7 @@ Resources: Handler: main.echo_base64_event_body Runtime: python3.6 CodeUri: . + Timeout: 600 Events: EchoBase64EventBodyPath: Type: Api @@ -251,6 +265,7 @@ Resources: Handler: main.multiple_headers Runtime: python3.6 CodeUri: . + Timeout: 600 Events: IdBasePath: Type: Api @@ -264,6 +279,7 @@ Resources: Handler: main.multiple_headers_overrides_headers Runtime: python3.6 CodeUri: . + Timeout: 600 Events: IdBasePath: Type: Api diff --git a/tests/testing_utils.py b/tests/testing_utils.py index ce0b3fc0ff..293e6e9676 100644 --- a/tests/testing_utils.py +++ b/tests/testing_utils.py @@ -4,3 +4,4 @@ IS_WINDOWS = platform.system().lower() == "windows" RUNNING_ON_CI = os.environ.get("APPVEYOR", False) RUNNING_TEST_FOR_MASTER_ON_CI = os.environ.get("APPVEYOR_REPO_BRANCH", "master") != "master" +CI_OVERRIDE = os.environ.get("APPVEYOR_CI_OVERRIDE", False) diff --git a/tests/unit/commands/buildcmd/test_command.py b/tests/unit/commands/buildcmd/test_command.py index f8008238a3..b609ad0402 100644 --- a/tests/unit/commands/buildcmd/test_command.py +++ b/tests/unit/commands/buildcmd/test_command.py @@ -13,9 +13,9 @@ class TestDoCli(TestCase): - @patch("samcli.commands.build.command.BuildContext") - @patch("samcli.commands.build.command.ApplicationBuilder") - @patch("samcli.commands.build.command.move_template") + @patch("samcli.commands.build.build_context.BuildContext") + @patch("samcli.lib.build.app_builder.ApplicationBuilder") + @patch("samcli.commands._utils.template.move_template") @patch("samcli.commands.build.command.os") def test_must_succeed_build(self, os_mock, move_template_mock, ApplicationBuilderMock, BuildContextMock): @@ -63,8 +63,8 @@ def test_must_succeed_build(self, os_mock, move_template_mock, ApplicationBuilde (UnsupportedBuilderLibraryVersionError(container_name="name", error_msg="msg"),), ] ) - @patch("samcli.commands.build.command.BuildContext") - @patch("samcli.commands.build.command.ApplicationBuilder") + @patch("samcli.commands.build.build_context.BuildContext") + @patch("samcli.lib.build.app_builder.ApplicationBuilder") def test_must_catch_known_exceptions(self, exception, ApplicationBuilderMock, BuildContextMock): ctx_mock = Mock() @@ -91,8 +91,8 @@ def test_must_catch_known_exceptions(self, exception, ApplicationBuilderMock, Bu self.assertEqual(str(ctx.exception), str(exception)) - @patch("samcli.commands.build.command.BuildContext") - @patch("samcli.commands.build.command.ApplicationBuilder") + @patch("samcli.commands.build.build_context.BuildContext") + @patch("samcli.lib.build.app_builder.ApplicationBuilder") def test_must_catch_function_not_found_exception(self, ApplicationBuilderMock, BuildContextMock): ctx_mock = Mock() BuildContextMock.return_value.__enter__ = Mock() diff --git a/tests/unit/commands/init/test_cli.py b/tests/unit/commands/init/test_cli.py index 8d15a2c274..4034d5b10d 100644 --- a/tests/unit/commands/init/test_cli.py +++ b/tests/unit/commands/init/test_cli.py @@ -16,7 +16,7 @@ def setUp(self): self.name = "testing project" self.no_input = False - @patch("samcli.commands.init.generate_project") + @patch("samcli.local.init.generate_project") def test_init_cli(self, generate_project_patch): # GIVEN generate_project successfully created a project # WHEN a project name has been passed @@ -35,7 +35,7 @@ def test_init_cli(self, generate_project_patch): self.location, self.runtime, self.dependency_manager, self.output_dir, self.name, self.no_input ) - @patch("samcli.commands.init.generate_project") + @patch("samcli.local.init.generate_project") def test_init_cli_generate_project_fails(self, generate_project_patch): # GIVEN generate_project fails to create a project diff --git a/tests/unit/commands/local/invoke/test_cli.py b/tests/unit/commands/local/invoke/test_cli.py index 99fb85dba4..a15448833b 100644 --- a/tests/unit/commands/local/invoke/test_cli.py +++ b/tests/unit/commands/local/invoke/test_cli.py @@ -39,7 +39,7 @@ def setUp(self): self.region_name = "region" self.profile = "profile" - @patch("samcli.commands.local.invoke.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_cli_must_setup_context_and_invoke(self, get_event_mock, InvokeContextMock): event_data = "data" @@ -95,7 +95,7 @@ def test_cli_must_setup_context_and_invoke(self, get_event_mock, InvokeContextMo ) get_event_mock.assert_called_with(self.eventfile) - @patch("samcli.commands.local.invoke.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_cli_must_invoke_with_no_event(self, get_event_mock, InvokeContextMock): self.no_event = True @@ -149,7 +149,7 @@ def test_cli_must_invoke_with_no_event(self, get_event_mock, InvokeContextMock): ) get_event_mock.assert_not_called() - @patch("samcli.commands.local.invoke.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_no_event_and_event(self, get_event_mock, InvokeContextMock): self.no_event = True @@ -188,7 +188,7 @@ def test_must_raise_user_exception_on_no_event_and_event(self, get_event_mock, I param(DockerImagePullFailedException("Failed to pull image"), "Failed to pull image"), ] ) - @patch("samcli.commands.local.invoke.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_function_not_found( self, side_effect_exception, expected_exectpion_message, get_event_mock, InvokeContextMock @@ -240,7 +240,7 @@ def test_must_raise_user_exception_on_function_not_found( (DebuggingNotSupported("Debugging not supported"), "Debugging not supported"), ] ) - @patch("samcli.commands.local.invoke.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_invalid_sam_template( self, exeception_to_raise, execption_message, get_event_mock, InvokeContextMock @@ -278,7 +278,7 @@ def test_must_raise_user_exception_on_invalid_sam_template( msg = str(ex_ctx.exception) self.assertEqual(msg, execption_message) - @patch("samcli.commands.local.invoke.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") @patch("samcli.commands.local.invoke.cli._get_event") def test_must_raise_user_exception_on_invalid_env_vars(self, get_event_mock, InvokeContextMock): event_data = "data" diff --git a/tests/unit/commands/local/start_api/test_cli.py b/tests/unit/commands/local/start_api/test_cli.py index c697092975..b9d514e434 100644 --- a/tests/unit/commands/local/start_api/test_cli.py +++ b/tests/unit/commands/local/start_api/test_cli.py @@ -40,8 +40,8 @@ def setUp(self): self.port = 123 self.static_dir = "staticdir" - @patch("samcli.commands.local.start_api.cli.InvokeContext") - @patch("samcli.commands.local.start_api.cli.LocalApiService") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") + @patch("samcli.commands.local.lib.local_api_service.LocalApiService") def test_cli_must_setup_context_and_start_service(self, local_api_service_mock, invoke_context_mock): # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() @@ -76,8 +76,8 @@ def test_cli_must_setup_context_and_start_service(self, local_api_service_mock, service_mock.start.assert_called_with() - @patch("samcli.commands.local.start_api.cli.InvokeContext") - @patch("samcli.commands.local.start_api.cli.LocalApiService") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") + @patch("samcli.commands.local.lib.local_api_service.LocalApiService") def test_must_raise_if_no_api_defined(self, local_api_service_mock, invoke_context_mock): # Mock the __enter__ method to return a object inside a context manager @@ -105,7 +105,7 @@ def test_must_raise_if_no_api_defined(self, local_api_service_mock, invoke_conte (DebuggingNotSupported("Debugging not supported"), "Debugging not supported"), ] ) - @patch("samcli.commands.local.start_api.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_sam_template( self, exeception_to_raise, execption_message, invoke_context_mock ): @@ -119,7 +119,7 @@ def test_must_raise_user_exception_on_invalid_sam_template( expected = execption_message self.assertEqual(msg, expected) - @patch("samcli.commands.local.start_api.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_env_vars(self, invoke_context_mock): invoke_context_mock.side_effect = OverridesNotWellDefinedError("bad env vars") diff --git a/tests/unit/commands/local/start_lambda/test_cli.py b/tests/unit/commands/local/start_lambda/test_cli.py index 54f6496775..91e46689ce 100644 --- a/tests/unit/commands/local/start_lambda/test_cli.py +++ b/tests/unit/commands/local/start_lambda/test_cli.py @@ -35,8 +35,8 @@ def setUp(self): self.host = "host" self.port = 123 - @patch("samcli.commands.local.start_lambda.cli.InvokeContext") - @patch("samcli.commands.local.start_lambda.cli.LocalLambdaService") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") + @patch("samcli.commands.local.lib.local_lambda_service.LocalLambdaService") def test_cli_must_setup_context_and_start_service(self, local_lambda_service_mock, invoke_context_mock): # Mock the __enter__ method to return a object inside a context manager context_mock = Mock() @@ -79,7 +79,7 @@ def test_cli_must_setup_context_and_start_service(self, local_lambda_service_moc (DebuggingNotSupported("Debugging not supported"), "Debugging not supported"), ] ) - @patch("samcli.commands.local.start_lambda.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_sam_template( self, exeception_to_raise, execption_message, invoke_context_mock ): @@ -92,7 +92,7 @@ def test_must_raise_user_exception_on_invalid_sam_template( expected = execption_message self.assertEqual(msg, expected) - @patch("samcli.commands.local.start_lambda.cli.InvokeContext") + @patch("samcli.commands.local.cli_common.invoke_context.InvokeContext") def test_must_raise_user_exception_on_invalid_env_vars(self, invoke_context_mock): invoke_context_mock.side_effect = OverridesNotWellDefinedError("bad env vars") diff --git a/tests/unit/commands/logs/test_command.py b/tests/unit/commands/logs/test_command.py index aacd8c313b..a1938a141c 100644 --- a/tests/unit/commands/logs/test_command.py +++ b/tests/unit/commands/logs/test_command.py @@ -14,7 +14,7 @@ def setUp(self): self.end_time = "end" @patch("samcli.commands.logs.command.click") - @patch("samcli.commands.logs.command.LogsCommandContext") + @patch("samcli.commands.logs.logs_context.LogsCommandContext") def test_without_tail(self, LogsCommandContextMock, click_mock): tailing = False events_iterable = [1, 2, 3] @@ -48,7 +48,7 @@ def test_without_tail(self, LogsCommandContextMock, click_mock): click_mock.echo.assert_has_calls([call(v, nl=False) for v in formatted_events]) @patch("samcli.commands.logs.command.click") - @patch("samcli.commands.logs.command.LogsCommandContext") + @patch("samcli.commands.logs.logs_context.LogsCommandContext") def test_with_tailing(self, LogsCommandContextMock, click_mock): tailing = True events_iterable = [1, 2, 3] diff --git a/tests/unit/commands/publish/test_command.py b/tests/unit/commands/publish/test_command.py index 892e49c848..743ac4e4fc 100644 --- a/tests/unit/commands/publish/test_command.py +++ b/tests/unit/commands/publish/test_command.py @@ -34,7 +34,7 @@ def test_must_raise_if_value_error(self, click_mock, get_template_data_mock): click_mock.secho.assert_called_with("Publish Failed", fg="red") @patch("samcli.commands.publish.command.get_template_data", Mock(return_value={})) - @patch("samcli.commands.publish.command.publish_application") + @patch("serverlessrepo.publish_application") @patch("samcli.commands.publish.command.click") def test_must_raise_if_serverlessrepo_error(self, click_mock, publish_application_mock): publish_application_mock.side_effect = ServerlessRepoError() @@ -44,7 +44,7 @@ def test_must_raise_if_serverlessrepo_error(self, click_mock, publish_applicatio click_mock.secho.assert_called_with("Publish Failed", fg="red") @patch("samcli.commands.publish.command.get_template_data", Mock(return_value={})) - @patch("samcli.commands.publish.command.publish_application") + @patch("serverlessrepo.publish_application") @patch("samcli.commands.publish.command.click") def test_must_raise_if_invalid_S3_uri_error(self, click_mock, publish_application_mock): publish_application_mock.side_effect = InvalidS3UriError(message="") @@ -56,7 +56,7 @@ def test_must_raise_if_invalid_S3_uri_error(self, click_mock, publish_applicatio click_mock.secho.assert_called_with("Publish Failed", fg="red") @patch("samcli.commands.publish.command.get_template_data", Mock(return_value={})) - @patch("samcli.commands.publish.command.publish_application") + @patch("serverlessrepo.publish_application") @patch("samcli.commands.publish.command.click") def test_must_succeed_to_create_application(self, click_mock, publish_application_mock): publish_application_mock.return_value = { @@ -78,7 +78,7 @@ def test_must_succeed_to_create_application(self, click_mock, publish_applicatio ) @patch("samcli.commands.publish.command.get_template_data", Mock(return_value={})) - @patch("samcli.commands.publish.command.publish_application") + @patch("serverlessrepo.publish_application") @patch("samcli.commands.publish.command.click") def test_must_succeed_to_update_application(self, click_mock, publish_application_mock): publish_application_mock.return_value = { @@ -100,7 +100,7 @@ def test_must_succeed_to_update_application(self, click_mock, publish_applicatio ) @patch("samcli.commands.publish.command.get_template_data", Mock(return_value={})) - @patch("samcli.commands.publish.command.publish_application") + @patch("serverlessrepo.publish_application") @patch("samcli.commands.publish.command.boto3") @patch("samcli.commands.publish.command.click") def test_print_console_link_if_context_region_not_set(self, click_mock, boto3_mock, publish_application_mock): @@ -120,7 +120,7 @@ def test_print_console_link_if_context_region_not_set(self, click_mock, boto3_mo click_mock.secho.assert_called_with(expected_link, fg="yellow") @patch("samcli.commands.publish.command.get_template_data") - @patch("samcli.commands.publish.command.publish_application") + @patch("serverlessrepo.publish_application") def test_must_use_template_semantic_version(self, publish_application_mock, get_template_data_mock): template_data = {METADATA: {SERVERLESS_REPO_APPLICATION: {SEMANTIC_VERSION: "0.1"}}} get_template_data_mock.return_value = template_data @@ -129,7 +129,7 @@ def test_must_use_template_semantic_version(self, publish_application_mock, get_ publish_application_mock.assert_called_with(template_data) @patch("samcli.commands.publish.command.get_template_data") - @patch("samcli.commands.publish.command.publish_application") + @patch("serverlessrepo.publish_application") def test_must_override_template_semantic_version(self, publish_application_mock, get_template_data_mock): template_data = {METADATA: {SERVERLESS_REPO_APPLICATION: {SEMANTIC_VERSION: "0.1"}}} get_template_data_mock.return_value = template_data diff --git a/tests/unit/commands/validate/test_cli.py b/tests/unit/commands/validate/test_cli.py index 452dbbdc1b..156a614619 100644 --- a/tests/unit/commands/validate/test_cli.py +++ b/tests/unit/commands/validate/test_cli.py @@ -20,7 +20,7 @@ def test_file_not_found(self, path_exists_patch, click_patch): with self.assertRaises(SamTemplateNotFoundException): _read_sam_file(template_path) - @patch("samcli.commands.validate.validate.yaml_parse") + @patch("samcli.yamlhelper.yaml_parse") @patch("samcli.commands.validate.validate.click") @patch("samcli.commands.validate.validate.os.path.exists") def test_file_parsed(self, path_exists_patch, click_patch, yaml_parse_patch): @@ -34,7 +34,7 @@ def test_file_parsed(self, path_exists_patch, click_patch, yaml_parse_patch): self.assertEqual(actual_template, {"a": "b"}) - @patch("samcli.commands.validate.validate.SamTemplateValidator") + @patch("samcli.commands.validate.lib.sam_template_validator.SamTemplateValidator") @patch("samcli.commands.validate.validate.click") @patch("samcli.commands.validate.validate._read_sam_file") def test_template_fails_validation(self, read_sam_file_patch, click_patch, template_valiadator): @@ -48,7 +48,7 @@ def test_template_fails_validation(self, read_sam_file_patch, click_patch, templ with self.assertRaises(InvalidSamTemplateException): do_cli(ctx=None, template=template_path) - @patch("samcli.commands.validate.validate.SamTemplateValidator") + @patch("samcli.commands.validate.lib.sam_template_validator.SamTemplateValidator") @patch("samcli.commands.validate.validate.click") @patch("samcli.commands.validate.validate._read_sam_file") def test_no_credentials_provided(self, read_sam_file_patch, click_patch, template_valiadator): @@ -62,7 +62,7 @@ def test_no_credentials_provided(self, read_sam_file_patch, click_patch, templat with self.assertRaises(UserException): do_cli(ctx=None, template=template_path) - @patch("samcli.commands.validate.validate.SamTemplateValidator") + @patch("samcli.commands.validate.lib.sam_template_validator.SamTemplateValidator") @patch("samcli.commands.validate.validate.click") @patch("samcli.commands.validate.validate._read_sam_file") def test_template_passes_validation(self, read_sam_file_patch, click_patch, template_valiadator): diff --git a/tests/unit/lib/intrinsic_resolver/test_intrinsic_resolver.py b/tests/unit/lib/intrinsic_resolver/test_intrinsic_resolver.py index 991fa1cb20..0c80e84eab 100644 --- a/tests/unit/lib/intrinsic_resolver/test_intrinsic_resolver.py +++ b/tests/unit/lib/intrinsic_resolver/test_intrinsic_resolver.py @@ -8,6 +8,8 @@ from pathlib2 import Path from unittest import TestCase +from mock import patch + from parameterized import parameterized from samcli.lib.intrinsic_resolver.intrinsic_property_resolver import IntrinsicResolver @@ -302,9 +304,12 @@ def setUp(self): template={}, symbol_resolver=IntrinsicsSymbolTable(logical_id_translator=logical_id_translator) ) - def test_basic_fn_transform(self): + @patch("samcli.lib.intrinsic_resolver.intrinsic_property_resolver.get_template_data") + def test_basic_fn_transform(self, get_template_data_patch): intrinsic = {"Fn::Transform": {"Name": "AWS::Include", "Parameters": {"Location": "test"}}} + get_template_data_patch.return_value = {"data": "test"} self.resolver.intrinsic_property_resolver(intrinsic, True) + get_template_data_patch.assert_called_once_with("test") def test_fn_transform_unsupported_macro(self): intrinsic = {"Fn::Transform": {"Name": "UNKNOWN", "Parameters": {"Location": "test"}}}