diff --git a/appveyor.yml b/appveyor.yml index 5bd7850166..3d77f8d7ee 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -61,18 +61,8 @@ for: - "pylint --rcfile .pylintrc samcli" # There are some functional tests that are currently broken due to not being updated with changed code or still running with node4.3 runtimes # We need to update those but this allows us to at least runs the ones we currently have working - - "pytest tests/functional/commands/validate tests/functional/commands/cli/test_global_config.py" + - "pytest -n 4 tests/functional/commands/validate tests/functional/commands/cli/test_global_config.py" - # 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: @@ -128,11 +118,11 @@ for: - "pylint --rcfile .pylintrc samcli" # There are some functional tests that are currently broken due to not being updated with changed code or still running with node4.3 runtimes # We need to update those but this allows us to at least runs the ones we currently have working - - "pytest tests/functional/commands/validate tests/functional/commands/cli/test_global_config.py" + - "pytest -n 4 tests/functional/commands/validate tests/functional/commands/cli/test_global_config.py" # Runs only in Linux - sh: "pytest -vv tests/integration" - - sh: "pytest -vv -n 4 tests/regression" + - sh: "pytest -vv tests/regression" - sh: "/tmp/black --check setup.py tests samcli scripts" # Set JAVA_HOME to java11 @@ -142,13 +132,3 @@ for: # 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 - - sh: "venv/Scripts/activate" - - sh: "pytest -n 4 -vv tests/smoke" diff --git a/tests/integration/buildcmd/test_build_cmd.py b/tests/integration/buildcmd/test_build_cmd.py index 4f44590ab7..13e37aebb5 100644 --- a/tests/integration/buildcmd/test_build_cmd.py +++ b/tests/integration/buildcmd/test_build_cmd.py @@ -1,10 +1,11 @@ import sys import os -import subprocess import logging from unittest import skipIf from pathlib import Path from parameterized import parameterized +from subprocess import Popen, PIPE, TimeoutExpired + import pytest from .build_integ_base import BuildIntegBase @@ -13,6 +14,8 @@ LOG = logging.getLogger(__name__) +TIMEOUT = 300 + @skipIf( ((IS_WINDOWS and RUNNING_ON_CI) and not CI_OVERRIDE), @@ -31,6 +34,7 @@ class TestBuildCommand_PythonFunctions(BuildIntegBase): FUNCTION_LOGICAL_ID = "Function" + @pytest.mark.flaky(reruns=3) @parameterized.expand( [ ("python2.7", False), @@ -48,8 +52,12 @@ def test_with_default_requirements(self, runtime, use_container): cmdlist = self.get_command_list(use_container=use_container, parameter_overrides=overrides) LOG.info("Running Command: {}", cmdlist) - process = subprocess.Popen(cmdlist, cwd=self.working_dir) - process.wait() + process = Popen(cmdlist, cwd=self.working_dir) + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise self._verify_built_artifact( self.default_build_dir, self.FUNCTION_LOGICAL_ID, self.EXPECTED_FILES_PROJECT_MANIFEST @@ -98,15 +106,20 @@ def _get_python_version(self): "Skip build tests on windows when running in CI unless overridden", ) class TestBuildCommand_ErrorCases(BuildIntegBase): + @pytest.mark.flaky(reruns=3) def test_unsupported_runtime(self): overrides = {"Runtime": "unsupportedpython", "CodeUri": "Python"} cmdlist = self.get_command_list(parameter_overrides=overrides) LOG.info("Running Command: {}", cmdlist) - process = subprocess.Popen(cmdlist, cwd=self.working_dir, stdout=subprocess.PIPE) - process.wait() - - process_stdout = b"".join(process.stdout.readlines()).strip().decode("utf-8") + process = Popen(cmdlist, cwd=self.working_dir, stdout=PIPE) + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip().decode("utf-8") self.assertEqual(1, process.returncode) self.assertIn("Build Failed", process_stdout) @@ -124,6 +137,7 @@ class TestBuildCommand_NodeFunctions(BuildIntegBase): FUNCTION_LOGICAL_ID = "Function" + @pytest.mark.flaky(reruns=3) @parameterized.expand( [ ("nodejs6.10", False), @@ -141,8 +155,12 @@ def test_with_default_package_json(self, runtime, use_container): cmdlist = self.get_command_list(use_container=use_container, parameter_overrides=overrides) LOG.info("Running Command: {}", cmdlist) - process = subprocess.Popen(cmdlist, cwd=self.working_dir) - process.wait() + process = Popen(cmdlist, cwd=self.working_dir) + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise self._verify_built_artifact( self.default_build_dir, @@ -198,11 +216,11 @@ class TestBuildCommand_RubyFunctions(BuildIntegBase): FUNCTION_LOGICAL_ID = "Function" @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") @parameterized.expand([("ruby2.5")]) def test_building_ruby_in_container(self, runtime): self._test_with_default_gemfile(runtime, "use_container") + @pytest.mark.flaky(reruns=3) @parameterized.expand([("ruby2.5")]) def test_building_ruby_in_process(self, runtime): self._test_with_default_gemfile(runtime, False) @@ -212,8 +230,12 @@ def _test_with_default_gemfile(self, runtime, use_container): cmdlist = self.get_command_list(use_container=use_container, parameter_overrides=overrides) LOG.info("Running Command: {}".format(cmdlist)) - process = subprocess.Popen(cmdlist, cwd=self.working_dir) - process.wait() + process = Popen(cmdlist, cwd=self.working_dir) + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise self._verify_built_artifact( self.default_build_dir, @@ -283,7 +305,6 @@ class TestBuildCommand_Java(BuildIntegBase): UNIX_LINE_ENDING = b"\n" @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") @parameterized.expand( [ ("java8", USING_GRADLE_PATH, EXPECTED_FILES_PROJECT_MANIFEST_GRADLE), @@ -301,6 +322,7 @@ class TestBuildCommand_Java(BuildIntegBase): def test_building_java_in_container(self, runtime, code_path, expected_files): self._test_with_building_java(runtime, code_path, expected_files, "use_container") + @pytest.mark.flaky(reruns=3) @parameterized.expand( [ ("java8", USING_GRADLE_PATH, EXPECTED_FILES_PROJECT_MANIFEST_GRADLE), @@ -313,6 +335,7 @@ def test_building_java_in_container(self, runtime, code_path, expected_files): def test_building_java8_in_process(self, runtime, code_path, expected_files): self._test_with_building_java(runtime, code_path, expected_files, False) + @pytest.mark.flaky(reruns=3) @parameterized.expand( [ ("java11", USING_GRADLE_PATH, EXPECTED_FILES_PROJECT_MANIFEST_GRADLE), @@ -333,8 +356,12 @@ def _test_with_building_java(self, runtime, code_path, expected_files, use_conta self._change_to_unix_line_ending(os.path.join(self.test_data_path, self.USING_GRADLEW_PATH, "gradlew")) LOG.info("Running Command: {}".format(cmdlist)) - process = subprocess.Popen(cmdlist, cwd=self.working_dir) - process.wait() + process = Popen(cmdlist, cwd=self.working_dir) + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise self._verify_built_artifact( self.default_build_dir, self.FUNCTION_LOGICAL_ID, expected_files, self.EXPECTED_DEPENDENCIES @@ -408,6 +435,7 @@ class TestBuildCommand_Dotnet_cli_package(BuildIntegBase): "HelloWorld.dll", } + @pytest.mark.flaky(reruns=3) @parameterized.expand( [ ("dotnetcore2.0", "Dotnetcore2.0", None), @@ -431,8 +459,12 @@ def test_with_dotnetcore(self, runtime, code_uri, mode): if mode: newenv["SAM_BUILD_MODE"] = mode - process = subprocess.Popen(cmdlist, cwd=self.working_dir, env=newenv) - process.wait() + process = Popen(cmdlist, cwd=self.working_dir, env=newenv) + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise self._verify_built_artifact( self.default_build_dir, self.FUNCTION_LOGICAL_ID, self.EXPECTED_FILES_PROJECT_MANIFEST @@ -455,6 +487,7 @@ def test_with_dotnetcore(self, runtime, code_uri, mode): self.verify_docker_container_cleanedup(runtime) + @pytest.mark.flaky(reruns=3) @parameterized.expand([("dotnetcore2.0", "Dotnetcore2.0"), ("dotnetcore2.1", "Dotnetcore2.1")]) def test_must_fail_with_container(self, runtime, code_uri): use_container = True @@ -466,8 +499,12 @@ def test_must_fail_with_container(self, runtime, code_uri): cmdlist = self.get_command_list(use_container=use_container, parameter_overrides=overrides) LOG.info("Running Command: {}".format(cmdlist)) - process = subprocess.Popen(cmdlist, cwd=self.working_dir) - process.wait() + process = Popen(cmdlist, cwd=self.working_dir) + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise # Must error out, because container builds are not supported self.assertEqual(process.returncode, 1) @@ -507,16 +544,18 @@ class TestBuildCommand_SingleFunctionBuilds(BuildIntegBase): "requirements.txt", } + @pytest.mark.flaky(reruns=3) def test_function_not_found(self): overrides = {"Runtime": "python3.7", "CodeUri": "Python", "Handler": "main.handler"} cmdlist = self.get_command_list(parameter_overrides=overrides, function_identifier="FunctionNotInTemplate") - process = subprocess.Popen(cmdlist, cwd=self.working_dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = process.communicate() + process = Popen(cmdlist, cwd=self.working_dir, stderr=PIPE) + _, stderr = process.communicate(timeout=TIMEOUT) self.assertEqual(process.returncode, 1) self.assertIn("FunctionNotInTemplate not found", str(stderr.decode("utf8"))) + @pytest.mark.flaky(reruns=3) @parameterized.expand( [ ("python3.7", False, "FunctionOne"), @@ -532,8 +571,12 @@ def test_build_single_function(self, runtime, use_container, function_identifier ) LOG.info("Running Command: {}", cmdlist) - process = subprocess.Popen(cmdlist, cwd=self.working_dir) - process.wait() + process = Popen(cmdlist, cwd=self.working_dir) + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise self._verify_built_artifact(self.default_build_dir, function_identifier, self.EXPECTED_FILES_PROJECT_MANIFEST) diff --git a/tests/integration/local/invoke/test_integrations_cli.py b/tests/integration/local/invoke/test_integrations_cli.py index f9c6d66587..d0ebb4a9b2 100644 --- a/tests/integration/local/invoke/test_integrations_cli.py +++ b/tests/integration/local/invoke/test_integrations_cli.py @@ -6,7 +6,7 @@ from unittest import skipIf from nose_parameterized import parameterized -from subprocess import Popen, PIPE +from subprocess import Popen, PIPE, TimeoutExpired from timeit import default_timer as timer import pytest import docker @@ -21,59 +21,75 @@ from pathlib import Path +TIMEOUT = 300 + class TestSamPython36HelloWorldIntegration(InvokeIntegBase): template = Path("template.yml") @pytest.mark.flaky(reruns=3) - @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 ) process = Popen(command_list, stdout=PIPE) - return_code = process.wait() + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - self.assertEqual(return_code, 0) + self.assertEqual(process.returncode, 0) @pytest.mark.flaky(reruns=3) - @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) process = Popen(command_list, stdout=PIPE) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() self.assertEqual(process_stdout.decode("utf-8"), '"Hello World in a different dir"') @pytest.mark.flaky(reruns=3) - @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 ) process = Popen(command_list, stdout=PIPE) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() self.assertEqual(process_stdout.decode("utf-8"), '"Hello world"') @pytest.mark.flaky(reruns=3) - @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 ) process = Popen(command_list, stdout=PIPE) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() self.assertEqual(process_stdout.decode("utf-8"), '"Hello world"') @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") @parameterized.expand( [("TimeoutFunction"), ("TimeoutFunctionWithParameter"), ("TimeoutFunctionWithStringParameter")] ) @@ -84,18 +100,23 @@ def test_invoke_with_timeout_set(self, function_name): start = timer() process = Popen(command_list, stdout=PIPE) - return_code = process.wait() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + end = timer() wall_clock_cli_duration = end - start - process_stdout = b"".join(process.stdout.readlines()).strip() + process_stdout = stdout.strip() # validate the time of the cli (timeout is set to 5s) self.assertGreater(wall_clock_cli_duration, 5) self.assertLess(wall_clock_cli_duration, 20) - self.assertEqual(return_code, 0) + self.assertEqual(process.returncode, 0) self.assertEqual( process_stdout.decode("utf-8"), "", @@ -103,7 +124,6 @@ def test_invoke_with_timeout_set(self, function_name): ) @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_env_vars(self): command_list = self.get_command_list( "EchoCustomEnvVarFunction", @@ -113,53 +133,66 @@ def test_invoke_with_env_vars(self): ) process = Popen(command_list, stdout=PIPE) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + process_stdout = stdout.strip() self.assertEqual(process_stdout.decode("utf-8"), '"MyVar"') @pytest.mark.flaky(reruns=3) - @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 ) process = Popen(command_list, stdout=PIPE, stderr=PIPE) - process.wait() + try: + stdout, stderr = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - process_stdout = b"".join(process.stdout.readlines()).strip() - process_stderr = b"".join(process.stderr.readlines()).strip() + process_stdout = stdout.strip() + process_stderr = stderr.strip() 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.flaky(reruns=3) - @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 ) process = Popen(command_list, stderr=PIPE) - process.wait() + try: + _, stderr = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - process_stderr = b"".join(process.stderr.readlines()).strip() + process_stderr = stderr.strip() self.assertIn("Docker Lambda is writing to stderr", process_stderr.decode("utf-8")) @pytest.mark.flaky(reruns=3) - @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) process = Popen(command_list, stdout=PIPE) - return_code = process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() - self.assertEqual(return_code, 0) + self.assertEqual(process.returncode, 0) self.assertEqual("{}", process_stdout.decode("utf-8")) @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_env_using_parameters(self): command_list = self.get_command_list( "EchoEnvWithParameters", @@ -169,8 +202,13 @@ def test_invoke_with_env_using_parameters(self): ) process = Popen(command_list, stdout=PIPE) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() environ = json.loads(process_stdout.decode("utf-8")) self.assertEqual(environ["Region"], "us-east-1") @@ -187,7 +225,6 @@ def test_invoke_with_env_using_parameters(self): self.assertEqual(environ["MyRuntimeVersion"], "v0") @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_env_using_parameters_with_custom_region(self): custom_region = "my-custom-region" @@ -196,14 +233,18 @@ def test_invoke_with_env_using_parameters_with_custom_region(self): ) process = Popen(command_list, stdout=PIPE) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() environ = json.loads(process_stdout.decode("utf-8")) self.assertEqual(environ["Region"], custom_region) @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_env_with_aws_creds(self): custom_region = "my-custom-region" key = "key" @@ -222,8 +263,13 @@ def test_invoke_with_env_with_aws_creds(self): env["AWS_SESSION_TOKEN"] = session process = Popen(command_list, stdout=PIPE, env=env) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() environ = json.loads(process_stdout.decode("utf-8")) self.assertEqual(environ["AWS_DEFAULT_REGION"], custom_region) @@ -233,7 +279,6 @@ def test_invoke_with_env_with_aws_creds(self): self.assertEqual(environ["AWS_SESSION_TOKEN"], session) @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") def test_invoke_with_docker_network_of_host(self): command_list = self.get_command_list( "HelloWorldServerlessFunction", @@ -243,12 +288,15 @@ def test_invoke_with_docker_network_of_host(self): ) process = Popen(command_list, stdout=PIPE) - return_code = process.wait() + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - self.assertEqual(return_code, 0) + self.assertEqual(process.returncode, 0) @pytest.mark.flaky(reruns=3) - @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( @@ -259,13 +307,17 @@ def test_invoke_with_docker_network_of_host_in_env_var(self): env["SAM_DOCKER_NETWORK"] = "non-existing-network" process = Popen(command_list, stderr=PIPE, env=env) - process.wait() - process_stderr = b"".join(process.stderr.readlines()).strip() + try: + _, stderr = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stderr = stderr.strip() self.assertIn('Not Found ("network non-existing-network not found")', process_stderr.decode("utf-8")) @pytest.mark.flaky(reruns=3) - @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) @@ -274,13 +326,18 @@ def test_sam_template_file_env_var_set(self): env["SAM_TEMPLATE_FILE"] = str(self.test_data_path.joinpath("invoke", "sam-template.yaml")) process = Popen(command_list, stdout=PIPE, env=env) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() self.assertEqual(process_stdout.decode("utf-8"), '"Hello world"') @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") + @pytest.mark.timeout(timeout=TIMEOUT, method="thread") def test_skip_pull_image_in_env_var(self): docker.from_env().api.pull("lambci/lambda:python3.6") @@ -292,8 +349,13 @@ def test_skip_pull_image_in_env_var(self): env["SAM_SKIP_PULL_IMAGE"] = "True" process = Popen(command_list, stderr=PIPE, env=env) - process.wait() - process_stderr = b"".join(process.stderr.readlines()).strip() + try: + _, stderr = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stderr = stderr.strip() self.assertIn("Requested to skip pulling images", process_stderr.decode("utf-8")) @@ -307,7 +369,6 @@ def tearDown(self): shutil.rmtree(self.config_dir, ignore_errors=True) @pytest.mark.flaky(reruns=3) - @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) @@ -331,8 +392,13 @@ def test_existing_env_variables_precedence_over_profiles(self): env["AWS_SHARED_CREDENTIALS_FILE"] = custom_cred process = Popen(command_list, stdout=PIPE, env=env) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() environ = json.loads(process_stdout.decode("utf-8")) # Environment variables we explicitly set take priority over profiles. @@ -343,7 +409,6 @@ def test_existing_env_variables_precedence_over_profiles(self): self.assertEqual(environ["AWS_SESSION_TOKEN"], "priority_secret_token") @pytest.mark.flaky(reruns=3) - @pytest.mark.timeout(timeout=300, method="thread") def test_default_profile_with_custom_configs(self): profile = "default" custom_config = self._create_config_file(profile) @@ -365,8 +430,13 @@ def test_default_profile_with_custom_configs(self): env["AWS_SHARED_CREDENTIALS_FILE"] = custom_cred process = Popen(command_list, stdout=PIPE, env=env) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() environ = json.loads(process_stdout.decode("utf-8")) self.assertEqual(environ["AWS_DEFAULT_REGION"], "us-west-1") @@ -376,7 +446,6 @@ def test_default_profile_with_custom_configs(self): self.assertEqual(environ["AWS_SESSION_TOKEN"], "sessiontoken") @pytest.mark.flaky(reruns=3) - @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") @@ -397,8 +466,13 @@ def test_custom_profile_with_custom_configs(self): env["AWS_SHARED_CREDENTIALS_FILE"] = custom_cred process = Popen(command_list, stdout=PIPE, env=env) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + + process_stdout = stdout.strip() environ = json.loads(process_stdout.decode("utf-8")) self.assertEqual(environ["AWS_DEFAULT_REGION"], "us-west-1") @@ -408,7 +482,6 @@ def test_custom_profile_with_custom_configs(self): self.assertEqual(environ["AWS_SESSION_TOKEN"], "sessiontoken") @pytest.mark.flaky(reruns=3) - @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 @@ -434,8 +507,12 @@ def test_custom_profile_through_envrionment_variables(self): env["AWS_PROFILE"] = "custom" process = Popen(command_list, stdout=PIPE, env=env) - process.wait() - process_stdout = b"".join(process.stdout.readlines()).strip() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise + process_stdout = stdout.strip() environ = json.loads(process_stdout.decode("utf-8")) self.assertEqual(environ["AWS_DEFAULT_REGION"], "us-west-1") @@ -523,9 +600,13 @@ def test_reference_of_layer_version(self, function_logical_id): ) process = Popen(command_list, stdout=PIPE) - process.wait() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - process_stdout = b"".join(process.stdout.readlines()).strip() + process_stdout = stdout.strip() expected_output = '"This is a Layer Ping from simple_python"' @@ -543,9 +624,13 @@ def test_download_one_layer(self, function_logical_id): ) process = Popen(command_list, stdout=PIPE) - process.wait() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - process_stdout = b"".join(process.stdout.readlines()[-1:]).strip() + process_stdout = stdout.split(os.linesep)[-1:].strip() expected_output = '"Layer1"' self.assertEqual(process_stdout.decode("utf-8"), expected_output) @@ -565,9 +650,13 @@ def test_publish_changed_download_layer(self, function_logical_id): ) process = Popen(command_list, stdout=PIPE) - process.wait() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - process_stdout = b"".join(process.stdout.readlines()[-1:]).strip() + process_stdout = stdout.split(os.linesep).strip() expected_output = '"Layer1"' self.assertEqual(process_stdout.decode("utf-8"), expected_output) @@ -586,9 +675,13 @@ def test_publish_changed_download_layer(self, function_logical_id): ) process = Popen(command_list, stdout=PIPE) - process.wait() + try: + stdout, _ = process.communicate() + except TimeoutExpired: + process.kill() + raise - process_stdout = b"".join(process.stdout.readlines()[-1:]).strip() + process_stdout = stdout.split(os.linesep).strip() expected_output = '"Changed_Layer_1"' self.assertEqual(process_stdout.decode("utf-8"), expected_output) @@ -606,11 +699,15 @@ def test_download_two_layers(self, function_logical_id): ) process = Popen(command_list, stdout=PIPE) - process.wait() + try: + stdout, _ = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - stdout = process.stdout.readlines() + stdout = stdout - process_stdout = b"".join(stdout[-1:]).strip() + process_stdout = stdout.split(os.linesep).strip() expected_output = '"Layer2"' self.assertEqual(process_stdout.decode("utf-8"), expected_output) @@ -627,7 +724,11 @@ def test_caching_two_layers(self): ) process = Popen(command_list, stdout=PIPE) - process.wait() + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise self.assertEqual(2, len(os.listdir(str(self.layer_cache)))) @@ -645,7 +746,11 @@ def test_caching_two_layers_with_layer_cache_env_set(self): env["SAM_LAYER_CACHE_BASEDIR"] = str(self.layer_cache) process = Popen(command_list, stdout=PIPE, env=env) - process.wait() + try: + process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise self.assertEqual(2, len(os.listdir(str(self.layer_cache)))) @@ -680,9 +785,13 @@ def test_layer_does_not_exist(self): ) process = Popen(command_list, stderr=PIPE) - process.wait() + try: + _, stderr = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - process_stderr = b"".join(process.stderr.readlines()).strip() + process_stderr = stderr.strip() error_output = process_stderr.decode("utf-8") expected_error_output = "{} was not found.".format(non_existent_layer_arn) @@ -699,9 +808,13 @@ def test_account_does_not_exist_for_layer(self): ) process = Popen(command_list, stderr=PIPE) - process.wait() + try: + _, stderr = process.communicate(timeout=TIMEOUT) + except TimeoutExpired: + process.kill() + raise - process_stderr = b"".join(process.stderr.readlines()).strip() + process_stderr = stderr.strip() error_output = process_stderr.decode("utf-8") expected_error_output = (