class TestWarmLambdaRuntime_get_code_dir(TestCase): def setUp(self): self.manager_mock = Mock() @patch("samcli.local.lambdafn.runtime.os") def test_must_return_same_path_if_path_is_not_compressed_file(self, os_mock): lambda_image_mock = Mock() os_mock.path.isfile.return_value = False code_path = "path" self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) res = self.runtime._get_code_dir(code_path) self.assertEqual(self.runtime._temp_uncompressed_paths_to_be_cleaned, []) self.assertEqual(res, code_path) @patch("samcli.local.lambdafn.runtime._unzip_file") @patch("samcli.local.lambdafn.runtime.os") def test_must_cache_temp_uncompressed_dirs_to_be_cleared_later(self, os_mock, _unzip_file_mock): lambda_image_mock = Mock() os_mock.path.isfile.return_value = True uncompressed_dir_mock = Mock() _unzip_file_mock.return_value = uncompressed_dir_mock code_path = "path.zip" self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) res = self.runtime._get_code_dir(code_path) self.assertEqual(self.runtime._temp_uncompressed_paths_to_be_cleaned, [uncompressed_dir_mock]) self.assertEqual(res, uncompressed_dir_mock)
class TestWarmLambdaRuntime_clean_warm_containers_related_resources(TestCase): def setUp(self): self.manager_mock = Mock() lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) self.observer_mock = Mock() self.func1_container_mock = Mock() self.func2_container_mock = Mock() self.runtime._containers = { "func_name1": self.func1_container_mock, "func_name2": self.func2_container_mock, } self.runtime._observer = self.observer_mock self.runtime._observer.is_alive.return_value = True self.runtime._temp_uncompressed_paths_to_be_cleaned = ["path1", "path2"] @patch("samcli.local.lambdafn.runtime.shutil") def test_must_container_stopped_when_its_code_dir_got_changed(self, shutil_mock): self.runtime.clean_running_containers_and_related_resources() self.assertEquals( self.runtime._container_manager.stop.call_args_list, [ call(self.func1_container_mock), call(self.func2_container_mock), ], ) self.assertEquals( shutil_mock.rmtree.call_args_list, [ call("path1"), call("path2"), ], ) self.runtime._observer.stop.assert_called_once_with()
def test_must_run_container_then_wait_for_result_and_container_not_stopped( self, LambdaContainerMock, LambdaFunctionObserverMock ): event = "event" code_dir = "some code dir" stdout = "stdout" stderr = "stderr" container = Mock() timer = Mock() debug_options = Mock() debug_options.debug_function = self.name lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) # Using MagicMock to mock the context manager self.runtime._get_code_dir = MagicMock() self.runtime._get_code_dir.return_value = code_dir # Configure interrupt handler self.runtime._configure_interrupt = Mock() self.runtime._configure_interrupt.return_value = timer LambdaContainerMock.return_value = container container.is_running.return_value = False self.runtime.invoke(self.func_config, event, debug_context=debug_options, stdout=stdout, stderr=stderr) # Verify if Lambda Event data is set self.env_vars.add_lambda_event_body.assert_not_called() # Make sure env-vars get resolved self.env_vars.resolve.assert_called_with() # Make sure the context manager is called to return the code directory self.runtime._get_code_dir.assert_called_with(self.code_path) # Make sure the container is created with proper values LambdaContainerMock.assert_called_with( self.lang, self.imageuri, self.handler, self.packagetype, self.imageconfig, code_dir, self.layers, lambda_image_mock, debug_options=debug_options, env_vars=self.env_var_value, memory_mb=self.DEFAULT_MEMORY, ) # Run the container and get results self.manager_mock.run.assert_called_with(container) self.runtime._configure_interrupt.assert_called_with(self.name, self.DEFAULT_TIMEOUT, container, True) container.wait_for_result.assert_called_with(event=event, name=self.name, stdout=stdout, stderr=stderr) # Finally block timer.cancel.assert_called_with() self.manager_mock.stop.assert_not_called()
def test_must_return_same_path_if_path_is_not_compressed_file(self, os_mock): lambda_image_mock = Mock() os_mock.path.isfile.return_value = False code_path = "path" self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) res = self.runtime._get_code_dir(code_path) self.assertEqual(self.runtime._temp_uncompressed_paths_to_be_cleaned, []) self.assertEqual(res, code_path)
def test_must_cache_temp_uncompressed_dirs_to_be_cleared_later(self, os_mock, _unzip_file_mock): lambda_image_mock = Mock() os_mock.path.isfile.return_value = True uncompressed_dir_mock = Mock() _unzip_file_mock.return_value = uncompressed_dir_mock code_path = "path.zip" self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) res = self.runtime._get_code_dir(code_path) self.assertEqual(self.runtime._temp_uncompressed_paths_to_be_cleaned, [uncompressed_dir_mock]) self.assertEqual(res, uncompressed_dir_mock)
def setUp(self): self.manager_mock = Mock() lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) self.observer_mock = Mock() self.runtime._observer = self.observer_mock self.lang = "runtime" self.handler = "handler" self.imageuri = None self.imageconfig = None self.func1_name = "func1_name" self.func1_code_path = "func1_code_path" self.func2_name = "func2_name" self.func2_code_path = "func2_code_path" self.common_layer_code_path = "layer1-code-path" self.common_layer_arn = "layer1-arn" self.common_layers = [ LayerVersion(arn=self.common_layer_arn, codeuri=self.common_layer_code_path, compatible_runtimes=self.lang) ] self.func_config1 = FunctionConfig( self.func1_name, self.lang, self.handler, self.imageuri, self.imageconfig, ZIP, self.func1_code_path, self.common_layers, ) self.func_config2 = FunctionConfig( self.func2_name, self.lang, self.handler, self.imageuri, self.imageconfig, IMAGE, self.func2_code_path, self.common_layers, ) self.func1_container_mock = Mock() self.func2_container_mock = Mock() self.runtime._containers = { self.func1_name: self.func1_container_mock, self.func2_name: self.func2_container_mock, }
class TestWarmLambdaRuntime_add_function_to_observer(TestCase): def setUp(self): self.manager_mock = Mock() self.name = "name" self.lang = "runtime" self.handler = "handler" self.code_path = "code-path" self.layer1_code_path = "layer1-code-path" self.layer1_arn = "layer1-arn" self.layers = [ LayerVersion(arn=self.layer1_arn, codeuri=self.layer1_code_path, compatible_runtimes=self.lang) ] self.imageuri = None self.packagetype = ZIP self.imageconfig = None self.func_config = FunctionConfig( self.name, self.lang, self.handler, self.imageuri, self.imageconfig, self.packagetype, self.code_path, self.layers, ) @patch("samcli.local.lambdafn.runtime.FileObserver") def test_must_observe_function_code_path_and_layers_paths( self, FileObserverMock): lambda_image_mock = Mock() observer_mock = Mock() FileObserverMock.return_value = observer_mock self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) self.runtime._add_function_to_observer(self.func_config) self.assertEqual( self.runtime._observed_paths, { "code-path": [self.func_config], "layer1-code-path": [self.func_config], }, ) self.assertEqual( observer_mock.watch.call_args_list, [ call("code-path"), call("layer1-code-path"), ], ) observer_mock.start.assert_called_once_with()
def setUp(self): self.manager_mock = Mock() lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) self.observer_mock = Mock() self.func1_container_mock = Mock() self.func2_container_mock = Mock() self.runtime._containers = { "func_name1": self.func1_container_mock, "func_name2": self.func2_container_mock, } self.runtime._observer = self.observer_mock self.runtime._observer.is_alive.return_value = True self.runtime._temp_uncompressed_paths_to_be_cleaned = ["path1", "path2"]
def test_must_create_non_cached_container(self, LambdaContainerMock, LambdaFunctionObserverMock): code_dir = "some code dir" container = Mock() debug_options = Mock() debug_options.debug_function = self.name lambda_image_mock = Mock() lambda_function_observer_mock = Mock() LambdaFunctionObserverMock.return_value = lambda_function_observer_mock self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) # Using MagicMock to mock the context manager self.runtime._get_code_dir = MagicMock() self.runtime._get_code_dir.return_value = code_dir LambdaContainerMock.return_value = container self.runtime.create(self.func_config, debug_context=debug_options) # Make sure the container is created with proper values LambdaContainerMock.assert_called_with( self.lang, self.imageuri, self.handler, self.packagetype, self.imageconfig, code_dir, self.layers, lambda_image_mock, debug_options=debug_options, env_vars=self.env_var_value, memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, ) self.manager_mock.create.assert_called_with(container) # validate that the created container got cached self.assertEqual(self.runtime._containers[self.name], container) lambda_function_observer_mock.watch.assert_called_with( self.func_config) lambda_function_observer_mock.start.assert_called_with()
def lambda_runtime(self) -> LambdaRuntime: if not self._lambda_runtimes: layer_downloader = LayerDownloader(self._layer_cache_basedir, self.get_cwd(), self._stacks) image_builder = LambdaImage(layer_downloader, self._skip_pull_image, self._force_image_build) self._lambda_runtimes = { ContainersMode.WARM: WarmLambdaRuntime(self._container_manager, image_builder), ContainersMode.COLD: LambdaRuntime(self._container_manager, image_builder), } return self._lambda_runtimes[self._containers_mode]
def test_must_return_cached_container(self, LambdaContainerMock, LambdaFunctionObserverMock): code_dir = "some code dir" container = Mock() debug_options = Mock() debug_options.debug_function = self.name lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) # Using MagicMock to mock the context manager self.runtime._get_code_dir = MagicMock() self.runtime._get_code_dir.return_value = code_dir LambdaContainerMock.return_value = container self.runtime.create(self.func_config, debug_context=debug_options) result = self.runtime.create(self.func_config, debug_context=debug_options) # validate that the manager.create method got called only one time self.manager_mock.create.assert_called_once_with(container) self.assertEqual(result, container)
def test_must_observe_function_code_path_and_layers_paths( self, FileObserverMock): lambda_image_mock = Mock() observer_mock = Mock() FileObserverMock.return_value = observer_mock self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) self.runtime._add_function_to_observer(self.func_config) self.assertEqual( self.runtime._observed_paths, { "code-path": [self.func_config], "layer1-code-path": [self.func_config], }, ) self.assertEqual( observer_mock.watch.call_args_list, [ call("code-path"), call("layer1-code-path"), ], ) observer_mock.start.assert_called_once_with()
def test_must_ignore_debug_options_if_function_name_is_not_debug_function( self, LambdaContainerMock): code_dir = "some code dir" container = Mock() debug_options = Mock() debug_options.debug_function = "name2" lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) self.runtime._add_function_to_observer = Mock() # Using MagicMock to mock the context manager self.runtime._get_code_dir = MagicMock() self.runtime._get_code_dir.return_value = code_dir LambdaContainerMock.return_value = container self.runtime.create(self.func_config, debug_context=debug_options) # Make sure the container is created with proper values LambdaContainerMock.assert_called_with( self.lang, self.imageuri, self.handler, self.packagetype, self.imageconfig, code_dir, self.layers, lambda_image_mock, debug_options=None, env_vars=self.env_var_value, memory_mb=self.DEFAULT_MEMORY, ) self.manager_mock.create.assert_called_with(container) # validate that the created container got cached self.assertEqual(self.runtime._containers[self.name], container)
class TestWarmLambdaRuntime_on_code_change(TestCase): def setUp(self): self.manager_mock = Mock() lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) self.observer_mock = Mock() self.runtime._observer = self.observer_mock self.lang = "runtime" self.handler = "handler" self.imageuri = None self.imageconfig = None self.func1_name = "func1_name" self.func1_code_path = "func1_code_path" self.func2_name = "func2_name" self.func2_code_path = "func2_code_path" self.common_layer_code_path = "layer1-code-path" self.common_layer_arn = "layer1-arn" self.common_layers = [ LayerVersion(arn=self.common_layer_arn, codeuri=self.common_layer_code_path, compatible_runtimes=self.lang) ] self.func_config1 = FunctionConfig( self.func1_name, self.lang, self.handler, self.imageuri, self.imageconfig, ZIP, self.func1_code_path, self.common_layers, ) self.func_config2 = FunctionConfig( self.func2_name, self.lang, self.handler, self.imageuri, self.imageconfig, IMAGE, self.func2_code_path, self.common_layers, ) self.func1_container_mock = Mock() self.func2_container_mock = Mock() self.runtime._containers = { self.func1_name: self.func1_container_mock, self.func2_name: self.func2_container_mock, } def test_only_one_container_get_stopped_when_its_code_dir_got_changed(self): self.runtime._on_code_change([self.func_config1]) self.manager_mock.stop.assert_called_with(self.func1_container_mock) self.assertEqual( self.runtime._containers, { self.func2_name: self.func2_container_mock, }, ) self.observer_mock.unwatch.assert_called_with(self.func_config1) def test_both_containers_get_stopped_when_both_functions_got_updated(self): self.runtime._on_code_change([self.func_config1, self.func_config2]) self.assertEqual( self.manager_mock.stop.call_args_list, [ call(self.func1_container_mock), call(self.func2_container_mock), ], ) self.assertEqual(self.runtime._containers, {}) self.assertEqual( self.observer_mock.unwatch.call_args_list, [ call(self.func_config1), call(self.func_config2), ], )
class TestWarmLambdaRuntime_create(TestCase): DEFAULT_MEMORY = 128 DEFAULT_TIMEOUT = 3 def setUp(self): self.manager_mock = Mock() self.name = "name" self.lang = "runtime" self.handler = "handler" self.code_path = "code-path" self.layers = [] self.imageuri = None self.packagetype = ZIP self.imageconfig = None self.func_config = FunctionConfig( self.name, self.lang, self.handler, self.imageuri, self.imageconfig, self.packagetype, self.code_path, self.layers, ) self.env_vars = Mock() self.func_config.env_vars = self.env_vars self.env_var_value = {"a": "b"} self.env_vars.resolve.return_value = self.env_var_value @patch("samcli.local.lambdafn.runtime.LambdaFunctionObserver") @patch("samcli.local.lambdafn.runtime.LambdaContainer") def test_must_create_non_cached_container(self, LambdaContainerMock, LambdaFunctionObserverMock): code_dir = "some code dir" container = Mock() debug_options = Mock() debug_options.debug_function = self.name lambda_image_mock = Mock() lambda_function_observer_mock = Mock() LambdaFunctionObserverMock.return_value = lambda_function_observer_mock self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) # Using MagicMock to mock the context manager self.runtime._get_code_dir = MagicMock() self.runtime._get_code_dir.return_value = code_dir LambdaContainerMock.return_value = container self.runtime.create(self.func_config, debug_context=debug_options) # Make sure the container is created with proper values LambdaContainerMock.assert_called_with( self.lang, self.imageuri, self.handler, self.packagetype, self.imageconfig, code_dir, self.layers, lambda_image_mock, debug_options=debug_options, env_vars=self.env_var_value, memory_mb=self.DEFAULT_MEMORY, ) self.manager_mock.create.assert_called_with(container) # validate that the created container got cached self.assertEqual(self.runtime._containers[self.name], container) lambda_function_observer_mock.watch.assert_called_with(self.func_config) lambda_function_observer_mock.start.assert_called_with() @patch("samcli.local.lambdafn.runtime.LambdaFunctionObserver") @patch("samcli.local.lambdafn.runtime.LambdaContainer") def test_must_return_cached_container(self, LambdaContainerMock, LambdaFunctionObserverMock): code_dir = "some code dir" container = Mock() debug_options = Mock() debug_options.debug_function = self.name lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) # Using MagicMock to mock the context manager self.runtime._get_code_dir = MagicMock() self.runtime._get_code_dir.return_value = code_dir LambdaContainerMock.return_value = container self.runtime.create(self.func_config, debug_context=debug_options) result = self.runtime.create(self.func_config, debug_context=debug_options) # validate that the manager.create method got called only one time self.manager_mock.create.assert_called_once_with(container) self.assertEqual(result, container) @patch("samcli.local.lambdafn.runtime.LambdaFunctionObserver") @patch("samcli.local.lambdafn.runtime.LambdaContainer") def test_must_ignore_debug_options_if_function_name_is_not_debug_function( self, LambdaContainerMock, LambdaFunctionObserverMock ): code_dir = "some code dir" container = Mock() debug_options = Mock() debug_options.debug_function = "name2" lambda_image_mock = Mock() self.runtime = WarmLambdaRuntime(self.manager_mock, lambda_image_mock) # Using MagicMock to mock the context manager self.runtime._get_code_dir = MagicMock() self.runtime._get_code_dir.return_value = code_dir LambdaContainerMock.return_value = container self.runtime.create(self.func_config, debug_context=debug_options) # Make sure the container is created with proper values LambdaContainerMock.assert_called_with( self.lang, self.imageuri, self.handler, self.packagetype, self.imageconfig, code_dir, self.layers, lambda_image_mock, debug_options=None, env_vars=self.env_var_value, memory_mb=self.DEFAULT_MEMORY, ) self.manager_mock.create.assert_called_with(container) # validate that the created container got cached self.assertEqual(self.runtime._containers[self.name], container)