def test_layer_is_not_cached(self): download_layers = LayerDownloader("/", ".") layer_path = Mock() layer_path.exists.return_value = False self.assertFalse(download_layers._is_layer_cached(layer_path))
def test_download_all_with_force(self, download_patch): download_patch.side_effect = ['/home/layer1', '/home/layer2'] download_layers = LayerDownloader("/home", ".") acutal_results = download_layers.download_all(['layer1', 'layer2'], force=True) self.assertEquals(acutal_results, ['/home/layer1', '/home/layer2']) download_patch.assert_has_calls([call('layer1', True), call("layer2", True)])
def test_fetch_layer_uri_fails_with_no_creds(self): lambda_client_mock = Mock() lambda_client_mock.get_layer_version.side_effect = NoCredentialsError() download_layers = LayerDownloader("/", ".", lambda_client_mock) layer = Mock() layer.layer_arn = "arn" layer.version = 1 with self.assertRaises(CredentialsRequired): download_layers._fetch_layer_uri(layer=layer)
def test_fetch_layer_uri_is_successful(self): lambda_client_mock = Mock() lambda_client_mock.get_layer_version.return_value = {"Content": {"Location": "some/uri"}} download_layers = LayerDownloader("/", ".", lambda_client_mock) layer = Mock() layer.layer_arn = "arn" layer.version = 1 actual_uri = download_layers._fetch_layer_uri(layer=layer) self.assertEquals(actual_uri, "some/uri")
def test_fetch_layer_uri_fails_with_ResourceNotFoundException(self): lambda_client_mock = Mock() lambda_client_mock.get_layer_version.side_effect = ClientError( error_response={'Error': {'Code': 'ResourceNotFoundException'}}, operation_name="lambda") download_layers = LayerDownloader("/", ".", lambda_client_mock) layer = Mock() layer.layer_arn = "arn" layer.version = 1 with self.assertRaises(ResourceNotFound): download_layers._fetch_layer_uri(layer=layer)
def test_fetch_layer_uri_re_raises_client_error(self): lambda_client_mock = Mock() lambda_client_mock.get_layer_version.side_effect = ClientError( error_response={'Error': {'Code': 'Unknown'}}, operation_name="lambda") download_layers = LayerDownloader("/", ".", lambda_client_mock) layer = Mock() layer.layer_arn = "arn" layer.version = 1 with self.assertRaises(ClientError): download_layers._fetch_layer_uri(layer=layer)
def test_download_layer_that_is_cached(self, is_layer_cached_patch, create_cache_patch): is_layer_cached_patch.return_value = True download_layers = LayerDownloader("/home", ".") layer_mock = Mock() layer_mock.is_defined_within_template = False layer_mock.name = "layer1" actual = download_layers.download(layer_mock) self.assertEquals(actual.codeuri, '/home/layer1') create_cache_patch.assert_called_once_with("/home")
def test_create_cache(self, path_patch): cache_path_mock = Mock() path_patch.return_value = cache_path_mock self.assertIsNone(LayerDownloader._create_cache("./home")) path_patch.assert_called_once_with("./home") cache_path_mock.mkdir.assert_called_once_with(parents=True, exist_ok=True, mode=0o700)
def test_download_layer_that_was_template_defined(self, create_cache_patch, resolve_code_path_patch): download_layers = LayerDownloader("/home", ".") layer_mock = Mock() layer_mock.is_template_defined = True layer_mock.name = "layer1" layer_mock.codeuri = "/some/custom/path" resolve_code_path_patch.return_value = './some/custom/path' actual = download_layers.download(layer_mock) self.assertEquals(actual.codeuri, './some/custom/path') create_cache_patch.assert_not_called() resolve_code_path_patch.assert_called_once_with(".", "/some/custom/path")
def lambda_runtime(self): if not self._lambda_runtimes: layer_downloader = LayerDownloader(self._layer_cache_basedir, self.get_cwd()) 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_download_layer_that_was_template_defined(self, create_cache_patch, resolve_code_path_patch): download_layers = LayerDownloader("/home", ".") layer_mock = Mock() layer_mock.is_template_defined = True layer_mock.name = "layer1" layer_mock.codeuri = "/some/custom/path" resolve_code_path_patch.return_value = './some/custom/path' actual = download_layers.download(layer_mock) self.assertEquals(actual.codeuri, './some/custom/path') create_cache_patch.assert_not_called() resolve_code_path_patch.assert_called_once_with( ".", "/some/custom/path")
def setUp(self): self.code_dir = { "echo": nodejs_lambda(ECHO_CODE), "sleep": nodejs_lambda(SLEEP_CODE), "envvar": nodejs_lambda(GET_ENV_VAR) } self.container_manager = ContainerManager() layer_downloader = LayerDownloader("./", "./") self.lambda_image = LambdaImage(layer_downloader, False, False) self.runtime = LambdaRuntime(self.container_manager, self.lambda_image)
def make_service(function_provider, cwd): port = random_port() manager = ContainerManager() layer_downloader = LayerDownloader("./", "./") image_builder = LambdaImage(layer_downloader, False, False) local_runtime = LambdaRuntime(manager, image_builder) lambda_runner = LocalLambdaRunner(local_runtime=local_runtime, function_provider=function_provider, cwd=cwd) service = LocalLambdaInvokeService(lambda_runner, port=port, host="127.0.0.1") scheme = "http" url = "{}://127.0.0.1:{}".format(scheme, port) return service, port, url, scheme
def test_download_layer(self, is_layer_cached_patch, create_cache_patch, fetch_layer_uri_patch, unzip_from_uri_patch): is_layer_cached_patch.return_value = False download_layers = LayerDownloader("/home", ".") layer_mock = Mock() layer_mock.is_defined_within_template = False layer_mock.name = "layer1" layer_mock.arn = "arn:layer:layer1:1" layer_mock.layer_arn = "arn:layer:layer1" fetch_layer_uri_patch.return_value = "layer/uri" actual = download_layers.download(layer_mock) self.assertEquals(actual.codeuri, "/home/layer1") create_cache_patch.assert_called_once_with("/home") fetch_layer_uri_patch.assert_called_once_with(layer_mock) unzip_from_uri_patch.assert_called_once_with("layer/uri", '/home/layer1.zip', unzip_output_dir='/home/layer1', progressbar_label="Downloading arn:layer:layer1")
def test_debug_port_is_created_on_host(self): layer_downloader = LayerDownloader("./", "./") image_builder = LambdaImage(layer_downloader, False, False) container = LambdaContainer(self.runtime, self.handler, self.code_dir, self.layers, image_builder, debug_options=self.debug_context) with self._create(container): container.start() # After container is started, query the container to make sure it is bound to the right ports port_binding = self.docker_client.api.port(container.id, self.debug_port) self.assertIsNotNone(port_binding, "Container must be bound to a port on host machine") self.assertEquals(1, len(port_binding), "Only one port must be bound to the container") self.assertEquals(port_binding[0]["HostPort"], str(self.debug_port))
def test_must_invoke(self): input_event = '"some data"' expected_env_vars = { "var1": "override_value1", "var2": "shell_env_value2" } manager = ContainerManager() layer_downloader = LayerDownloader("./", "./") lambda_image = LambdaImage(layer_downloader, False, False) local_runtime = LambdaRuntime(manager, lambda_image) runner = LocalLambdaRunner(local_runtime, self.mock_function_provider, self.cwd, self.env_var_overrides, debug_context=None) # Append the real AWS credentials to the expected values. creds = runner.get_aws_creds() # default value for creds is not configured by the test. But coming from a downstream class expected_env_vars["AWS_SECRET_ACCESS_KEY"] = creds.get( "secret", "defaultsecret") expected_env_vars["AWS_ACCESS_KEY_ID"] = creds.get("key", "defaultkey") expected_env_vars["AWS_REGION"] = creds.get("region", "us-east-1") stdout_stream = io.BytesIO() stderr_stream = io.BytesIO() stdout_stream_writer = StreamWriter(stdout_stream) stderr_stream_writer = StreamWriter(stderr_stream) runner.invoke(self.function_name, input_event, stdout=stdout_stream_writer, stderr=stderr_stream_writer) # stderr is where the Lambda container runtime logs are available. It usually contains requestId, start time # etc. So it is non-zero in size self.assertGreater(len(stderr_stream.getvalue().strip()), 0, "stderr stream must contain data") # This should contain all the environment variables passed to the function actual_output = json.loads( stdout_stream.getvalue().strip().decode("utf-8")) for key, value in expected_env_vars.items(): self.assertTrue(key in actual_output, "Key '{}' must be in function output".format(key)) self.assertEqual(actual_output.get(key), value)
def test_container_is_attached_to_network(self): layer_downloader = LayerDownloader("./", "./") image_builder = LambdaImage(layer_downloader, False, False) container = LambdaContainer(self.runtime, self.handler, self.code_dir, self.layers, image_builder) with self._network_create() as network: # Ask the container to attach to the network container.network_id = network.id with self._create(container): container.start() # Now that the container has been created, it would be connected to the network # Fetch the latest information about this network from server network.reload() self.assertEquals(1, len(network.containers)) self.assertEquals(container.id, network.containers[0].id)
def test_basic_creation(self): """ A docker container must be successfully created """ layer_downloader = LayerDownloader("./", "./") image_builder = LambdaImage(layer_downloader, False, False) container = LambdaContainer(self.runtime, self.handler, self.code_dir, self.layers, image_builder) self.assertIsNone(container.id, "Container must not have ID before creation") # Create the container and verify its properties with self._create(container): self.assertIsNotNone(container.id, "Container must have an ID") # Call Docker API to make sure container indeed exists actual_container = self.docker_client.containers.get(container.id) self.assertEquals(actual_container.status, "created") self.assertTrue(self.expected_docker_image in actual_container.image.tags, "Image name of the container must be " + self.expected_docker_image)
def local_lambda_runner(self): """ Returns an instance of the runner capable of running Lambda functions locally :return samcli.commands.local.lib.local_lambda.LocalLambdaRunner: Runner configured to run Lambda functions locally """ layer_downloader = LayerDownloader(self._layer_cache_basedir, self.get_cwd()) image_builder = LambdaImage(layer_downloader, self._skip_pull_image, self._force_image_build) lambda_runtime = LambdaRuntime(self._container_manager, image_builder) return LocalLambdaRunner(local_runtime=lambda_runtime, function_provider=self._function_provider, cwd=self.get_cwd(), env_vars_values=self._env_vars_value, debug_context=self._debug_context)
def setUp(self): self.code_dir = nodejs_lambda(SLEEP_CODE) Input = namedtuple("Input", ["timeout", "sleep", "check_stdout"]) self.inputs = [ Input(sleep=1, timeout=10, check_stdout=True), Input(sleep=2, timeout=10, check_stdout=True), Input(sleep=3, timeout=10, check_stdout=True), Input(sleep=5, timeout=10, check_stdout=True), Input(sleep=8, timeout=10, check_stdout=True), Input(sleep=13, timeout=12, check_stdout=False), # Must timeout Input(sleep=21, timeout=20, check_stdout=False), # Must timeout. So stdout will be empty ] random.shuffle(self.inputs) container_manager = ContainerManager() layer_downloader = LayerDownloader("./", "./") self.lambda_image = LambdaImage(layer_downloader, False, False) self.runtime = LambdaRuntime(container_manager, self.lambda_image)
def test_function_result_is_available_in_stdout_and_logs_in_stderr(self): # This is the JSON result from Lambda function # Convert to proper binary type to be compatible with Python 2 & 3 expected_output = b'{"a":"b"}' expected_stderr = b"**This string is printed from Lambda function**" layer_downloader = LayerDownloader("./", "./") image_builder = LambdaImage(layer_downloader, False) container = LambdaContainer(self.runtime, self.handler, self.code_dir, self.layers, image_builder) stdout_stream = io.BytesIO() stderr_stream = io.BytesIO() with self._create(container): container.start() container.wait_for_logs(stdout=stdout_stream, stderr=stderr_stream) function_output = stdout_stream.getvalue() function_stderr = stderr_stream.getvalue() self.assertEquals(function_output.strip(), expected_output) self.assertIn(expected_stderr, function_stderr)
def test_initialization(self): download_layers = LayerDownloader("/some/path", ".") self.assertEquals(download_layers.layer_cache, "/some/path")
def setUp(self): self.host = "127.0.0.1" self.port = random.randint(30000, 40000) # get a random port self.url = "http://{}:{}".format(self.host, self.port) self.code_abs_path = nodejs_lambda(API_GATEWAY_ECHO_EVENT) # Let's convert this absolute path to relative path. Let the parent be the CWD, and codeuri be the folder self.cwd = os.path.dirname(self.code_abs_path) self.code_uri = os.path.relpath( self.code_abs_path, self.cwd) # Get relative path with respect to CWD # Setup a static file in the directory self.static_dir = "mystaticdir" self.static_file_name = "myfile.txt" self.static_file_content = "This is a static file" self._setup_static_file( os.path.join( self.cwd, self.static_dir), # Create static directory with in cwd self.static_file_name, self.static_file_content, ) # Create one Lambda function self.function_name = "name" self.function = provider.Function( name=self.function_name, runtime="nodejs4.3", memory=256, timeout=5, handler="index.handler", codeuri=self.code_uri, environment={}, rolearn=None, layers=[], ) self.mock_function_provider = Mock() self.mock_function_provider.get.return_value = self.function # Setup two APIs pointing to the same function routes = [ Route(path="/get", methods=["GET"], function_name=self.function_name), Route(path="/post", methods=["POST"], function_name=self.function_name), ] api = Api(routes=routes) self.api_provider_mock = Mock() self.api_provider_mock.get_all.return_value = api # Now wire up the Lambda invoker and pass it through the context self.lambda_invoke_context_mock = Mock() manager = ContainerManager() layer_downloader = LayerDownloader("./", "./") lambda_image = LambdaImage(layer_downloader, False, False) local_runtime = LambdaRuntime(manager, lambda_image) lambda_runner = LocalLambdaRunner(local_runtime, self.mock_function_provider, self.cwd, debug_context=None) self.lambda_invoke_context_mock.local_lambda_runner = lambda_runner self.lambda_invoke_context_mock.get_cwd.return_value = self.cwd