コード例 #1
0
 def setUp(self):
     self.container_manager = Mock()
     self.builder = ApplicationBuilder(Mock(),
                                       "/build/dir",
                                       "/base/dir",
                                       container_manager=self.container_manager)
     self.builder._parse_builder_response = Mock()
コード例 #2
0
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(), "builddir", "basedir")

        self.template_dict = {
            "Resources": {
                "MyFunction1": {
                    "Type": "AWS::Serverless::Function",
                    "Properties": {
                        "CodeUri": "oldvalue"
                    }
                },
                "MyFunction2": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {
                        "Code": "oldvalue"
                    }
                },
                "OtherResource": {
                    "Type": "AWS::Lambda::Version",
                    "Properties": {
                        "CodeUri": "something"
                    }
                }
            }
        }
コード例 #3
0
    def test_should_run_build_for_only_unique_builds(self, persist_mock,
                                                     read_mock, osutils_mock):
        build_function_mock = Mock()

        # create 3 function resources where 2 of them would have same codeuri, runtime and metadata
        function1_1 = generate_function("function1_1")
        function1_2 = generate_function("function1_2")
        function2 = generate_function("function2", runtime="different_runtime")
        resources_to_build_collector = ResourcesToBuildCollector()
        resources_to_build_collector.add_functions(
            [function1_1, function1_2, function2])

        build_dir = "builddir"

        # instantiate the builder and run build method
        builder = ApplicationBuilder(resources_to_build_collector, "builddir",
                                     "basedir", "cachedir")
        builder._build_function = build_function_mock
        build_function_mock.side_effect = [
            os.path.join(build_dir, function1_1.name),
            os.path.join(build_dir, function1_2.name),
            os.path.join(build_dir, function1_2.name),
        ]

        result = builder.build()

        # result should contain all 3 functions as expected
        self.assertEqual(
            result,
            {
                function1_1.name: os.path.join(build_dir, function1_1.name),
                function1_2.name: os.path.join(build_dir, function1_2.name),
                function2.name: os.path.join(build_dir, function1_2.name),
            },
        )

        # actual build should only be called twice since only 2 of the functions have unique build
        build_function_mock.assert_has_calls(
            [
                call(
                    function1_1.name,
                    function1_1.codeuri,
                    ZIP,
                    function1_1.runtime,
                    function1_1.handler,
                    ANY,
                    function1_1.metadata,
                ),
                call(
                    function2.name,
                    function2.codeuri,
                    ZIP,
                    function2.runtime,
                    function2.handler,
                    ANY,
                    function2.metadata,
                ),
            ],
            any_order=True,
        )
コード例 #4
0
 def setUp(self):
     self.layer1 = Mock()
     self.layer2 = Mock()
     self.container_manager = Mock()
     resources_to_build_collector = ResourcesToBuildCollector()
     resources_to_build_collector.add_layers([self.layer1, self.layer2])
     self.builder = ApplicationBuilder(resources_to_build_collector, "builddir", "basedir")
コード例 #5
0
class TestApplicationBuilder_build_function(TestCase):
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(), "/build/dir", "/base/dir")

    @patch("samcli.lib.build.app_builder._get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_process(self, osutils_mock,
                                   get_workflow_config_mock):
        function_name = "function_name"
        codeuri = "path/to/source"
        runtime = "runtime"
        scratch_dir = "scratch"
        config_mock = get_workflow_config_mock.return_value = Mock()
        config_mock.manifest_name = "manifest_name"

        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(
            return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        self.builder._build_function_in_process = Mock()

        code_dir = "/base/dir/path/to/source"
        artifacts_dir = "/build/dir/function_name"
        manifest_path = os.path.join(code_dir, config_mock.manifest_name)

        self.builder._build_function(function_name, codeuri, runtime)

        self.builder._build_function_in_process.assert_called_with(
            config_mock, code_dir, artifacts_dir, scratch_dir, manifest_path,
            runtime)

    @patch("samcli.lib.build.app_builder._get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_container(self, osutils_mock,
                                     get_workflow_config_mock):
        function_name = "function_name"
        codeuri = "path/to/source"
        runtime = "runtime"
        scratch_dir = "scratch"
        config_mock = get_workflow_config_mock.return_value = Mock()
        config_mock.manifest_name = "manifest_name"

        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(
            return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        self.builder._build_function_on_container = Mock()

        code_dir = "/base/dir/path/to/source"
        artifacts_dir = "/build/dir/function_name"
        manifest_path = os.path.join(code_dir, config_mock.manifest_name)

        # Settting the container manager will make us use the container
        self.builder._container_manager = Mock()
        self.builder._build_function(function_name, codeuri, runtime)

        self.builder._build_function_on_container.assert_called_with(
            config_mock, code_dir, artifacts_dir, scratch_dir, manifest_path,
            runtime)
コード例 #6
0
ファイル: command.py プロジェクト: winsome/aws-sam-cli
def do_cli(
        template,  # pylint: disable=too-many-locals
        base_dir,
        build_dir,
        clean,
        use_container,
        manifest_path,
        docker_network,
        skip_pull_image,
        parameter_overrides):
    """
    Implementation of the ``cli`` method
    """

    LOG.debug("'build' command is called")

    if use_container:
        LOG.info("Starting Build inside a container")

    with BuildContext(template,
                      base_dir,
                      build_dir,
                      clean=clean,
                      manifest_path=manifest_path,
                      use_container=use_container,
                      parameter_overrides=parameter_overrides,
                      docker_network=docker_network,
                      skip_pull_image=skip_pull_image) as ctx:

        builder = ApplicationBuilder(
            ctx.function_provider,
            ctx.build_dir,
            ctx.base_dir,
            manifest_path_override=ctx.manifest_path_override,
            container_manager=ctx.container_manager)
        try:
            artifacts = builder.build()
            modified_template = builder.update_template(
                ctx.template_dict, ctx.original_template_path, artifacts)

            move_template(ctx.original_template_path, ctx.output_template_path,
                          modified_template)

            click.secho("\nBuild Succeeded", fg="green")

            msg = gen_success_msg(
                os.path.relpath(ctx.build_dir),
                os.path.relpath(ctx.output_template_path),
                os.path.abspath(
                    ctx.build_dir) == os.path.abspath(DEFAULT_BUILD_DIR))

            click.secho(msg, fg="yellow")

        except (UnsupportedRuntimeException, BuildError,
                UnsupportedBuilderLibraryVersionError) as ex:
            click.secho("Build Failed", fg="red")
            raise UserException(str(ex))
コード例 #7
0
    def setUp(self):
        self.func1 = Mock()
        self.func2 = Mock()
        self.layer1 = Mock()
        self.layer2 = Mock()

        resources_to_build_collector = ResourcesToBuildCollector()
        resources_to_build_collector.add_functions([self.func1, self.func2])
        resources_to_build_collector.add_layers([self.layer1, self.layer2])
        self.builder = ApplicationBuilder(resources_to_build_collector, "builddir", "basedir")
コード例 #8
0
ファイル: command.py プロジェクト: Frameio/aws-sam-cli
def do_cli(template,  # pylint: disable=too-many-locals
           base_dir,
           build_dir,
           clean,
           use_container,
           manifest_path,
           docker_network,
           skip_pull_image,
           parameter_overrides):
    """
    Implementation of the ``cli`` method
    """

    LOG.debug("'build' command is called")

    if use_container:
        LOG.info("Starting Build inside a container")

    with BuildContext(template,
                      base_dir,
                      build_dir,
                      clean=clean,
                      manifest_path=manifest_path,
                      use_container=use_container,
                      parameter_overrides=parameter_overrides,
                      docker_network=docker_network,
                      skip_pull_image=skip_pull_image) as ctx:

        builder = ApplicationBuilder(ctx.function_provider,
                                     ctx.build_dir,
                                     ctx.base_dir,
                                     manifest_path_override=ctx.manifest_path_override,
                                     container_manager=ctx.container_manager
                                     )
        try:
            artifacts = builder.build()
            modified_template = builder.update_template(ctx.template_dict,
                                                        ctx.original_template_path,
                                                        artifacts)

            move_template(ctx.original_template_path,
                          ctx.output_template_path,
                          modified_template)

            click.secho("\nBuild Succeeded", fg="green")

            msg = gen_success_msg(os.path.relpath(ctx.build_dir),
                                  os.path.relpath(ctx.output_template_path),
                                  os.path.abspath(ctx.build_dir) == os.path.abspath(DEFAULT_BUILD_DIR))

            click.secho(msg, fg="yellow")

        except (UnsupportedRuntimeException, BuildError, UnsupportedBuilderLibraryVersionError) as ex:
            click.secho("Build Failed", fg="red")
            raise UserException(str(ex))
コード例 #9
0
class TestApplicationBuilder_update_template(TestCase):
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(), "builddir", "basedir", "cachedir")

        self.template_dict = {
            "Resources": {
                "MyFunction1": {"Type": "AWS::Serverless::Function", "Properties": {"CodeUri": "oldvalue"}},
                "MyFunction2": {"Type": "AWS::Lambda::Function", "Properties": {"Code": "oldvalue"}},
                "GlueResource": {"Type": "AWS::Glue::Job", "Properties": {"Command": {"ScriptLocation": "something"}}},
                "OtherResource": {"Type": "AWS::Lambda::Version", "Properties": {"CodeUri": "something"}},
                "MyImageFunction1": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {"PackageType": "Image"},
                    "Metadata": {"Dockerfile": "Dockerfile", "DockerContext": "DockerContext", "DockerTag": "Tag"},
                },
            }
        }

    def test_must_update_resources_with_build_artifacts(self):
        self.maxDiff = None
        original_template_path = "/path/to/tempate.txt"
        built_artifacts = {
            "MyFunction1": "/path/to/build/MyFunction1",
            "MyFunction2": "/path/to/build/MyFunction2",
            "MyImageFunction1": "myimagefunction1:Tag",
        }

        expected_result = {
            "Resources": {
                "MyFunction1": {
                    "Type": "AWS::Serverless::Function",
                    "Properties": {"CodeUri": os.path.join("build", "MyFunction1")},
                },
                "MyFunction2": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {"Code": os.path.join("build", "MyFunction2")},
                },
                "GlueResource": {"Type": "AWS::Glue::Job", "Properties": {"Command": {"ScriptLocation": "something"}}},
                "OtherResource": {"Type": "AWS::Lambda::Version", "Properties": {"CodeUri": "something"}},
                "MyImageFunction1": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {"Code": "myimagefunction1:Tag", "PackageType": IMAGE},
                    "Metadata": {"Dockerfile": "Dockerfile", "DockerContext": "DockerContext", "DockerTag": "Tag"},
                },
            }
        }

        actual = self.builder.update_template(self.template_dict, original_template_path, built_artifacts)
        self.assertEqual(actual, expected_result)

    def test_must_skip_if_no_artifacts(self):
        built_artifacts = {}
        actual = self.builder.update_template(self.template_dict, "/foo/bar/template.txt", built_artifacts)

        self.assertEqual(actual, self.template_dict)
コード例 #10
0
 def setUp(self):
     self.stream_mock = Mock()
     self.docker_client_mock = Mock()
     self.builder = ApplicationBuilder(
         Mock(),
         "/build/dir",
         "/base/dir",
         "/cached/dir",
         stream_writer=self.stream_mock,
         docker_client=self.docker_client_mock,
     )
コード例 #11
0
    def test_parallel_run_should_pick_parallel_strategy(self, mock_parallel_build_strategy_class):
        mock_parallel_build_strategy = Mock()
        mock_parallel_build_strategy_class.return_value = mock_parallel_build_strategy

        build_graph_mock = Mock()
        get_build_graph_mock = Mock(return_value=build_graph_mock)

        builder = ApplicationBuilder(Mock(), "builddir", "basedir", "cachedir", parallel=True)
        builder._get_build_graph = get_build_graph_mock

        result = builder.build()

        mock_parallel_build_strategy.build.assert_called_once()
        self.assertEqual(result, mock_parallel_build_strategy.build())
コード例 #12
0
class TestApplicationBuilder_build_function_in_process(TestCase):
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(),
                                          "/build/dir",
                                          "/base/dir",
                                          "/cache/dir",
                                          mode="mode")

    @patch("samcli.lib.build.app_builder.LambdaBuilder")
    def test_must_use_lambda_builder(self, lambda_builder_mock):
        config_mock = Mock()
        builder_instance_mock = lambda_builder_mock.return_value = Mock()

        result = self.builder._build_function_in_process(
            config_mock, "source_dir", "artifacts_dir", "scratch_dir",
            "manifest_path", "runtime", None)
        self.assertEqual(result, "artifacts_dir")

        lambda_builder_mock.assert_called_with(
            language=config_mock.language,
            dependency_manager=config_mock.dependency_manager,
            application_framework=config_mock.application_framework,
        )

        builder_instance_mock.build.assert_called_with(
            "source_dir",
            "artifacts_dir",
            "scratch_dir",
            "manifest_path",
            runtime="runtime",
            executable_search_paths=config_mock.executable_search_paths,
            mode="mode",
            options=None,
        )

    @patch("samcli.lib.build.app_builder.LambdaBuilder")
    def test_must_raise_on_error(self, lambda_builder_mock):
        config_mock = Mock()
        builder_instance_mock = lambda_builder_mock.return_value = Mock()
        builder_instance_mock.build.side_effect = LambdaBuilderError()
        self.builder._get_build_options = Mock(return_value=None)

        with self.assertRaises(BuildError):
            self.builder._build_function_in_process(config_mock, "source_dir",
                                                    "artifacts_dir",
                                                    "scratch_dir",
                                                    "manifest_path", "runtime",
                                                    None)
コード例 #13
0
class TestApplicationBuilder_build(TestCase):

    def setUp(self):
        self.mock_func_provider = Mock()
        self.builder = ApplicationBuilder(self.mock_func_provider,
                                          "builddir",
                                          "basedir")

    def test_must_iterate_on_functions(self):
        func1 = Mock()
        func2 = Mock()
        build_function_mock = Mock()

        self.mock_func_provider.get_all.return_value = [func1, func2]
        self.builder._build_function = build_function_mock

        result = self.builder.build()

        self.assertEquals(result, {
            func1.name: build_function_mock.return_value,
            func2.name: build_function_mock.return_value,
        })

        build_function_mock.assert_has_calls([
            call(func1.name, func1.codeuri, func1.runtime),
            call(func2.name, func2.codeuri, func2.runtime),
        ], any_order=False)
コード例 #14
0
 def setUp(self):
     self.container_manager = Mock()
     self.builder = ApplicationBuilder(Mock(),
                                       "/build/dir",
                                       "/base/dir",
                                       container_manager=self.container_manager)
     self.builder._parse_builder_response = Mock()
コード例 #15
0
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(), "builddir", "basedir", "cachedir")

        self.template_dict = {
            "Resources": {
                "MyFunction1": {"Type": "AWS::Serverless::Function", "Properties": {"CodeUri": "oldvalue"}},
                "MyFunction2": {"Type": "AWS::Lambda::Function", "Properties": {"Code": "oldvalue"}},
                "GlueResource": {"Type": "AWS::Glue::Job", "Properties": {"Command": {"ScriptLocation": "something"}}},
                "OtherResource": {"Type": "AWS::Lambda::Version", "Properties": {"CodeUri": "something"}},
                "MyImageFunction1": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {"PackageType": "Image"},
                    "Metadata": {"Dockerfile": "Dockerfile", "DockerContext": "DockerContext", "DockerTag": "Tag"},
                },
            }
        }
コード例 #16
0
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(),
                                          "builddir",
                                          "basedir")

        self.template_dict = {
            "Resources": {
                "MyFunction1": {
                    "Type": "AWS::Serverless::Function",
                    "Properties": {
                        "CodeUri": "oldvalue"
                    }
                },
                "MyFunction2": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {
                        "Code": "oldvalue"
                    }
                },
                "OtherResource": {
                    "Type": "AWS::Lambda::Version",
                    "Properties": {
                        "CodeUri": "something"
                    }
                }
            }
        }
コード例 #17
0
class TestApplicationBuilder_build(TestCase):
    def setUp(self):
        self.mock_func_provider = Mock()
        self.builder = ApplicationBuilder(self.mock_func_provider, "builddir",
                                          "basedir")

    def test_must_iterate_on_functions(self):
        func1 = Mock()
        func2 = Mock()
        build_function_mock = Mock()

        self.mock_func_provider.get_all.return_value = [func1, func2]
        self.builder._build_function = build_function_mock

        result = self.builder.build()

        self.assertEquals(
            result, {
                func1.name: build_function_mock.return_value,
                func2.name: build_function_mock.return_value,
            })

        build_function_mock.assert_has_calls([
            call(func1.name, func1.codeuri, func1.runtime),
            call(func2.name, func2.codeuri, func2.runtime),
        ],
                                             any_order=False)
コード例 #18
0
class TestApplicationBuilder_build(TestCase):
    def setUp(self):
        self.func1 = Mock()
        self.func2 = Mock()
        self.builder = ApplicationBuilder([self.func1, self.func2], "builddir",
                                          "basedir")

    def test_must_iterate_on_functions(self):
        build_function_mock = Mock()

        self.builder._build_function = build_function_mock

        result = self.builder.build()

        self.assertEqual(
            result,
            {
                self.func1.name: build_function_mock.return_value,
                self.func2.name: build_function_mock.return_value
            },
        )

        build_function_mock.assert_has_calls(
            [
                call(self.func1.name, self.func1.codeuri, self.func1.runtime,
                     self.func1.handler),
                call(self.func2.name, self.func2.codeuri, self.func2.runtime,
                     self.func2.handler),
            ],
            any_order=False,
        )
コード例 #19
0
class TestApplicationBuilder_update_template_windows(TestCase):
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(), "builddir", "basedir")

        self.template_dict = {
            "Resources": {
                "MyFunction1": {"Type": "AWS::Serverless::Function", "Properties": {"CodeUri": "oldvalue"}},
                "MyFunction2": {"Type": "AWS::Lambda::Function", "Properties": {"Code": "oldvalue"}},
                "GlueResource": {"Type": "AWS::Glue::Job", "Properties": {"Command": {"ScriptLocation": "something"}}},
                "OtherResource": {"Type": "AWS::Lambda::Version", "Properties": {"CodeUri": "something"}},
            }
        }

        # Force os.path to be ntpath instead of posixpath on unix systems
        import ntpath

        self.saved_os_path_module = sys.modules["os.path"]
        os.path = sys.modules["ntpath"]

    def test_must_write_absolute_path_for_different_drives(self):
        def mock_new(cls, *args, **kwargs):
            cls = WindowsPath
            self = cls._from_parts(args, init=False)
            self._init()
            return self

        def mock_resolve(self):
            return self

        with patch("pathlib.Path.__new__", new=mock_new):
            with patch("pathlib.Path.resolve", new=mock_resolve):
                original_template_path = "C:\\path\\to\\template.txt"
                function_1_path = "D:\\path\\to\\build\\MyFunction1"
                function_2_path = "C:\\path2\\to\\build\\MyFunction2"
                built_artifacts = {"MyFunction1": function_1_path, "MyFunction2": function_2_path}

                expected_result = {
                    "Resources": {
                        "MyFunction1": {
                            "Type": "AWS::Serverless::Function",
                            "Properties": {"CodeUri": function_1_path},
                        },
                        "MyFunction2": {
                            "Type": "AWS::Lambda::Function",
                            "Properties": {"Code": "..\\..\\path2\\to\\build\\MyFunction2"},
                        },
                        "GlueResource": {
                            "Type": "AWS::Glue::Job",
                            "Properties": {"Command": {"ScriptLocation": "something"}},
                        },
                        "OtherResource": {"Type": "AWS::Lambda::Version", "Properties": {"CodeUri": "something"}},
                    }
                }

                actual = self.builder.update_template(self.template_dict, original_template_path, built_artifacts)
                self.assertEqual(actual, expected_result)

    def tearDown(self):
        os.path = self.saved_os_path_module
コード例 #20
0
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(), "builddir", "basedir")

        self.template_dict = {
            "Resources": {
                "MyFunction1": {"Type": "AWS::Serverless::Function", "Properties": {"CodeUri": "oldvalue"}},
                "MyFunction2": {"Type": "AWS::Lambda::Function", "Properties": {"Code": "oldvalue"}},
                "GlueResource": {"Type": "AWS::Glue::Job", "Properties": {"Command": {"ScriptLocation": "something"}}},
                "OtherResource": {"Type": "AWS::Lambda::Version", "Properties": {"CodeUri": "something"}},
            }
        }

        # Force os.path to be ntpath instead of posixpath on unix systems
        import ntpath

        self.saved_os_path_module = sys.modules["os.path"]
        os.path = sys.modules["ntpath"]
コード例 #21
0
class TestApplicationBuilder_build_function_in_process(TestCase):

    def setUp(self):
        self.builder = ApplicationBuilder(Mock(),
                                          "/build/dir",
                                          "/base/dir")

    @patch("samcli.lib.build.app_builder.LambdaBuilder")
    def test_must_use_lambda_builder(self, lambda_builder_mock):
        config_mock = Mock()
        builder_instance_mock = lambda_builder_mock.return_value = Mock()

        result = self.builder._build_function_in_process(config_mock,
                                                         "source_dir",
                                                         "artifacts_dir",
                                                         "scratch_dir",
                                                         "manifest_path",
                                                         "runtime")
        self.assertEquals(result, "artifacts_dir")

        lambda_builder_mock.assert_called_with(language=config_mock.language,
                                               dependency_manager=config_mock.dependency_manager,
                                               application_framework=config_mock.application_framework)

        builder_instance_mock.build.assert_called_with("source_dir",
                                                       "artifacts_dir",
                                                       "scratch_dir",
                                                       "manifest_path",
                                                       runtime="runtime",
                                                       executable_search_paths=config_mock.executable_search_paths)

    @patch("samcli.lib.build.app_builder.LambdaBuilder")
    def test_must_raise_on_error(self, lambda_builder_mock):
        config_mock = Mock()
        builder_instance_mock = lambda_builder_mock.return_value = Mock()
        builder_instance_mock.build.side_effect = LambdaBuilderError()
        self.builder._get_build_options = Mock(return_value=None)

        with self.assertRaises(BuildError):
            self.builder._build_function_in_process(config_mock,
                                                    "source_dir",
                                                    "artifacts_dir",
                                                    "scratch_dir",
                                                    "manifest_path",
                                                    "runtime")
コード例 #22
0
class TestApplicationBuilder_update_template(TestCase):
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(), "builddir", "basedir")

        self.template_dict = {
            "Resources": {
                "MyFunction1": {"Type": "AWS::Serverless::Function", "Properties": {"CodeUri": "oldvalue"}},
                "MyFunction2": {"Type": "AWS::Lambda::Function", "Properties": {"Code": "oldvalue"}},
                "GlueResource": {"Type": "AWS::Glue::Job", "Properties": {"Command": {"ScriptLocation": "something"}}},
                "OtherResource": {"Type": "AWS::Lambda::Version", "Properties": {"CodeUri": "something"}},
            }
        }

    def test_must_write_relative_build_artifacts_path(self):
        original_template_path = "/path/to/tempate.txt"
        built_artifacts = {"MyFunction1": "/path/to/build/MyFunction1", "MyFunction2": "/path/to/build/MyFunction2"}

        expected_result = {
            "Resources": {
                "MyFunction1": {
                    "Type": "AWS::Serverless::Function",
                    "Properties": {"CodeUri": os.path.join("build", "MyFunction1")},
                },
                "MyFunction2": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {"Code": os.path.join("build", "MyFunction2")},
                },
                "GlueResource": {"Type": "AWS::Glue::Job", "Properties": {"Command": {"ScriptLocation": "something"}}},
                "OtherResource": {"Type": "AWS::Lambda::Version", "Properties": {"CodeUri": "something"}},
            }
        }

        actual = self.builder.update_template(self.template_dict, original_template_path, built_artifacts)
        self.assertEqual(actual, expected_result)

    def test_must_skip_if_no_artifacts(self):
        built_artifacts = {}
        actual = self.builder.update_template(self.template_dict, "/foo/bar/template.txt", built_artifacts)

        self.assertEqual(actual, self.template_dict)
コード例 #23
0
    def setUp(self):
        self.func1 = Mock()
        self.func1.packagetype = ZIP
        self.func1.name = "function_name1"
        self.func2 = Mock()
        self.func2.packagetype = ZIP
        self.func2.name = "function_name2"
        self.imageFunc1 = Mock()
        self.imageFunc1.name = "function_name3"

        self.layer1 = Mock()
        self.layer2 = Mock()

        self.imageFunc1.packagetype = IMAGE
        self.layer1.build_method = "build_method"
        self.layer2.build_method = "build_method"

        resources_to_build_collector = ResourcesToBuildCollector()
        resources_to_build_collector.add_functions(
            [self.func1, self.func2, self.imageFunc1])
        resources_to_build_collector.add_layers([self.layer1, self.layer2])
        self.builder = ApplicationBuilder(resources_to_build_collector,
                                          "builddir", "basedir", "cachedir")
コード例 #24
0
class TestApplicationBuilder_build(TestCase):
    def setUp(self):
        self.func1 = Mock()
        self.func2 = Mock()
        self.layer1 = Mock()
        self.layer2 = Mock()

        resources_to_build_collector = ResourcesToBuildCollector()
        resources_to_build_collector.add_functions([self.func1, self.func2])
        resources_to_build_collector.add_layers([self.layer1, self.layer2])
        self.builder = ApplicationBuilder(resources_to_build_collector,
                                          "builddir", "basedir")

    def test_must_iterate_on_functions_and_layers(self):
        build_function_mock = Mock()
        build_layer_mock = Mock()

        self.builder._build_function = build_function_mock
        self.builder._build_layer = build_layer_mock

        result = self.builder.build()

        self.assertEqual(
            result,
            {
                self.func1.name: build_function_mock.return_value,
                self.func2.name: build_function_mock.return_value,
                self.layer1.name: build_layer_mock.return_value,
                self.layer2.name: build_layer_mock.return_value,
            },
        )

        build_function_mock.assert_has_calls(
            [
                call(self.func1.name, self.func1.codeuri, self.func1.runtime,
                     self.func1.handler),
                call(self.func2.name, self.func2.codeuri, self.func2.runtime,
                     self.func2.handler),
            ],
            any_order=False,
        )
コード例 #25
0
class TestApplicationBuilder_build_lambda_image_function(TestCase):
    def setUp(self):
        self.stream_mock = Mock()
        self.docker_client_mock = Mock()
        self.builder = ApplicationBuilder(
            Mock(),
            "/build/dir",
            "/base/dir",
            "/cached/dir",
            stream_writer=self.stream_mock,
            docker_client=self.docker_client_mock,
        )

    def test_docker_build_raises_docker_unavailable(self):
        with self.assertRaises(DockerConnectionError):
            metadata = {
                "Dockerfile": "Dockerfile",
                "DockerContext": "context",
                "DockerTag": "Tag",
                "DockerBuildArgs": {
                    "a": "b"
                },
            }

            self.docker_client_mock.ping.side_effect = docker.errors.APIError(
                message="Mock Error")

            self.builder._build_lambda_image("Name", metadata)

    def test_docker_build_raises_DockerBuildFailed_when_error_in_buildlog_stream(
            self):
        with self.assertRaises(DockerBuildFailed):
            metadata = {
                "Dockerfile": "Dockerfile",
                "DockerContext": "context",
                "DockerTag": "Tag",
                "DockerBuildArgs": {
                    "a": "b"
                },
            }

            self.docker_client_mock.api.build.return_value = [{
                "error":
                "Function building failed"
            }]

            self.builder._build_lambda_image("Name", metadata)

    def test_dockerfile_not_in_dockercontext(self):
        with self.assertRaises(DockerfileOutSideOfContext):
            metadata = {
                "Dockerfile": "Dockerfile",
                "DockerContext": "context",
                "DockerTag": "Tag",
                "DockerBuildArgs": {
                    "a": "b"
                },
            }

            response_mock = Mock()
            response_mock.status_code = 500
            error_mock = Mock()
            error_mock.side_effect = docker.errors.APIError(
                "Bad Request",
                response=response_mock,
                explanation="Cannot locate specified Dockerfile")
            self.builder._stream_lambda_image_build_logs = error_mock
            self.docker_client_mock.api.build.return_value = []

            self.builder._build_lambda_image("Name", metadata)

    def test_error_rerasises(self):
        with self.assertRaises(docker.errors.APIError):
            metadata = {
                "Dockerfile": "Dockerfile",
                "DockerContext": "context",
                "DockerTag": "Tag",
                "DockerBuildArgs": {
                    "a": "b"
                },
            }
            error_mock = Mock()
            error_mock.side_effect = docker.errors.APIError(
                "Bad Request", explanation="Some explanation")
            self.builder._stream_lambda_image_build_logs = error_mock
            self.docker_client_mock.api.build.return_value = []

            self.builder._build_lambda_image("Name", metadata)

    def test_can_build_image_function(self):
        metadata = {
            "Dockerfile": "Dockerfile",
            "DockerContext": "context",
            "DockerTag": "Tag",
            "DockerBuildArgs": {
                "a": "b"
            },
        }

        self.docker_client_mock.api.build.return_value = []

        result = self.builder._build_lambda_image("Name", metadata)

        self.assertEqual(result, "name:Tag")

    def test_can_build_image_function_without_tag(self):
        metadata = {
            "Dockerfile": "Dockerfile",
            "DockerContext": "context",
            "DockerBuildArgs": {
                "a": "b"
            }
        }

        self.docker_client_mock.api.build.return_value = []
        result = self.builder._build_lambda_image("Name", metadata)

        self.assertEqual(result, "name:latest")

    @patch("samcli.lib.build.app_builder.os")
    def test_can_build_image_function_under_debug(self, mock_os):
        mock_os.environ.get.return_value = "debug"
        metadata = {
            "Dockerfile": "Dockerfile",
            "DockerContext": "context",
            "DockerTag": "Tag",
            "DockerBuildArgs": {
                "a": "b"
            },
        }

        self.docker_client_mock.api.build.return_value = []

        result = self.builder._build_lambda_image("Name", metadata)

        self.assertEqual(result, "name:Tag-debug")
        self.builder._build_lambda_image("Name", metadata)
        self.assertEqual(
            self.docker_client_mock.api.build.call_args,
            # NOTE (sriram-mv): path set to ANY to handle platform differences.
            call(
                path=ANY,
                dockerfile="Dockerfile",
                tag="name:Tag-debug",
                buildargs={
                    "a": "b",
                    "SAM_BUILD_MODE": "debug"
                },
                decode=True,
            ),
        )
コード例 #26
0
class TestApplicationBuilderForLayerBuild(TestCase):
    def setUp(self):
        self.layer1 = Mock()
        self.layer2 = Mock()
        self.container_manager = Mock()
        resources_to_build_collector = ResourcesToBuildCollector()
        resources_to_build_collector.add_layers([self.layer1, self.layer2])
        self.builder = ApplicationBuilder(resources_to_build_collector,
                                          "builddir", "basedir", "cachedir")

    @patch("samcli.lib.build.app_builder.get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    @patch("samcli.lib.build.app_builder.get_layer_subfolder")
    def test_must_build_layer_in_process(self, get_layer_subfolder_mock,
                                         osutils_mock,
                                         get_workflow_config_mock):
        get_layer_subfolder_mock.return_value = "python"
        config_mock = Mock()
        config_mock.manifest_name = "manifest_name"

        scratch_dir = "scratch"
        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(
            return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        get_workflow_config_mock.return_value = config_mock
        build_function_in_process_mock = Mock()

        self.builder._build_function_in_process = build_function_in_process_mock
        self.builder._build_layer("layer_name", "code_uri", "python3.8",
                                  ["python3.8"])

        build_function_in_process_mock.assert_called_once()
        args, _ = build_function_in_process_mock.call_args_list[0]
        self._validate_build_args(args, config_mock)

    @patch("samcli.lib.build.app_builder.get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    @patch("samcli.lib.build.app_builder.get_layer_subfolder")
    def test_must_build_layer_in_container(self, get_layer_subfolder_mock,
                                           osutils_mock,
                                           get_workflow_config_mock):
        self.builder._container_manager = self.container_manager
        get_layer_subfolder_mock.return_value = "python"
        config_mock = Mock()
        config_mock.manifest_name = "manifest_name"

        scratch_dir = "scratch"
        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(
            return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        get_workflow_config_mock.return_value = config_mock
        build_function_on_container_mock = Mock()

        self.builder._build_function_on_container = build_function_on_container_mock
        self.builder._build_layer("layer_name", "code_uri", "python3.8",
                                  ["python3.8"])

        build_function_on_container_mock.assert_called_once()
        args, _ = build_function_on_container_mock.call_args_list[0]
        self._validate_build_args(args, config_mock)

    def _validate_build_args(self, args, config_mock):
        self.assertEqual(config_mock, args[0])
        self.assertTrue(args[1].endswith("code_uri"))
        self.assertTrue(args[2].endswith("python"))
        self.assertEqual("scratch", args[3])
        self.assertTrue(args[4].endswith("manifest_name"))
        self.assertEqual("python3.8", args[5])
コード例 #27
0
class TestApplicationBuilder_build(TestCase):
    def setUp(self):
        self.func1 = Mock()
        self.func1.packagetype = ZIP
        self.func1.name = "function_name1"
        self.func2 = Mock()
        self.func2.packagetype = ZIP
        self.func2.name = "function_name2"
        self.imageFunc1 = Mock()
        self.imageFunc1.name = "function_name3"

        self.layer1 = Mock()
        self.layer2 = Mock()

        self.imageFunc1.packagetype = IMAGE
        self.layer1.build_method = "build_method"
        self.layer2.build_method = "build_method"

        resources_to_build_collector = ResourcesToBuildCollector()
        resources_to_build_collector.add_functions(
            [self.func1, self.func2, self.imageFunc1])
        resources_to_build_collector.add_layers([self.layer1, self.layer2])
        self.builder = ApplicationBuilder(resources_to_build_collector,
                                          "builddir", "basedir", "cachedir")

    @patch("samcli.lib.build.build_graph.BuildGraph._write")
    def test_must_iterate_on_functions_and_layers(self, persist_mock):
        build_function_mock = Mock()
        build_image_function_mock = Mock()
        build_image_function_mock_return = Mock()
        build_layer_mock = Mock()

        def build_layer_return(layer_name, layer_codeuri, layer_build_method,
                               layer_compatible_runtimes):
            return f"{layer_name}_location"

        build_layer_mock.side_effect = build_layer_return

        self.builder._build_function = build_function_mock
        self.builder._build_lambda_image = build_image_function_mock
        self.builder._build_layer = build_layer_mock

        build_function_mock.side_effect = [
            os.path.join("builddir", self.func1.name),
            os.path.join("builddir", self.func2.name),
            build_image_function_mock_return,
        ]

        result = self.builder.build()
        self.maxDiff = None

        self.assertEqual(
            result,
            {
                self.func1.name: os.path.join("builddir", self.func1.name),
                self.func2.name: os.path.join("builddir", self.func2.name),
                self.imageFunc1.name: build_image_function_mock_return,
                self.layer1.name: f"{self.layer1.name}_location",
                self.layer2.name: f"{self.layer2.name}_location",
            },
        )

        build_function_mock.assert_has_calls(
            [
                call(
                    self.func1.name,
                    self.func1.codeuri,
                    ZIP,
                    self.func1.runtime,
                    self.func1.handler,
                    ANY,
                    self.func1.metadata,
                ),
                call(
                    self.func2.name,
                    self.func2.codeuri,
                    ZIP,
                    self.func2.runtime,
                    self.func2.handler,
                    ANY,
                    self.func2.metadata,
                ),
                call(
                    self.imageFunc1.name,
                    self.imageFunc1.codeuri,
                    IMAGE,
                    self.imageFunc1.runtime,
                    self.imageFunc1.handler,
                    ANY,
                    self.imageFunc1.metadata,
                ),
            ],
            any_order=False,
        )

        build_layer_mock.assert_has_calls([
            call(self.layer1.name, self.layer1.codeuri,
                 self.layer1.build_method, self.layer1.compatible_runtimes),
            call(self.layer2.name, self.layer2.codeuri,
                 self.layer2.build_method, self.layer2.compatible_runtimes),
        ])

    @patch("samcli.lib.build.build_graph.BuildGraph._write")
    def test_should_generate_build_graph(self, persist_mock):
        build_graph = self.builder._get_build_graph()

        self.assertTrue(len(build_graph.get_function_build_definitions()), 2)

        all_functions_in_build_graph = []
        for build_definition in build_graph.get_function_build_definitions():
            for function in build_definition.functions:
                all_functions_in_build_graph.append(function)

        self.assertTrue(self.func1 in all_functions_in_build_graph)
        self.assertTrue(self.func2 in all_functions_in_build_graph)

    @patch("samcli.lib.build.build_graph.BuildGraph._write")
    @patch("samcli.lib.build.build_graph.BuildGraph._read")
    @patch("samcli.lib.build.build_strategy.osutils")
    def test_should_run_build_for_only_unique_builds(self, persist_mock,
                                                     read_mock, osutils_mock):
        build_function_mock = Mock()

        # create 3 function resources where 2 of them would have same codeuri, runtime and metadata
        function1_1 = generate_function("function1_1")
        function1_2 = generate_function("function1_2")
        function2 = generate_function("function2", runtime="different_runtime")
        resources_to_build_collector = ResourcesToBuildCollector()
        resources_to_build_collector.add_functions(
            [function1_1, function1_2, function2])

        build_dir = "builddir"

        # instantiate the builder and run build method
        builder = ApplicationBuilder(resources_to_build_collector, "builddir",
                                     "basedir", "cachedir")
        builder._build_function = build_function_mock
        build_function_mock.side_effect = [
            os.path.join(build_dir, function1_1.name),
            os.path.join(build_dir, function1_2.name),
            os.path.join(build_dir, function1_2.name),
        ]

        result = builder.build()

        # result should contain all 3 functions as expected
        self.assertEqual(
            result,
            {
                function1_1.name: os.path.join(build_dir, function1_1.name),
                function1_2.name: os.path.join(build_dir, function1_2.name),
                function2.name: os.path.join(build_dir, function1_2.name),
            },
        )

        # actual build should only be called twice since only 2 of the functions have unique build
        build_function_mock.assert_has_calls(
            [
                call(
                    function1_1.name,
                    function1_1.codeuri,
                    ZIP,
                    function1_1.runtime,
                    function1_1.handler,
                    ANY,
                    function1_1.metadata,
                ),
                call(
                    function2.name,
                    function2.codeuri,
                    ZIP,
                    function2.runtime,
                    function2.handler,
                    ANY,
                    function2.metadata,
                ),
            ],
            any_order=True,
        )

    @patch("samcli.lib.build.app_builder.DefaultBuildStrategy")
    def test_default_run_should_pick_default_strategy(
            self, mock_default_build_strategy_class):
        mock_default_build_strategy = Mock()
        mock_default_build_strategy_class.return_value = mock_default_build_strategy

        build_graph_mock = Mock()
        get_build_graph_mock = Mock(return_value=build_graph_mock)

        builder = ApplicationBuilder(Mock(), "builddir", "basedir", "cachedir")
        builder._get_build_graph = get_build_graph_mock

        result = builder.build()

        mock_default_build_strategy.build.assert_called_once()
        self.assertEqual(result, mock_default_build_strategy.build())

    @patch("samcli.lib.build.app_builder.CachedBuildStrategy")
    def test_cached_run_should_pick_cached_strategy(
            self, mock_cached_build_strategy_class):
        mock_cached_build_strategy = Mock()
        mock_cached_build_strategy_class.return_value = mock_cached_build_strategy

        build_graph_mock = Mock()
        get_build_graph_mock = Mock(return_value=build_graph_mock)

        builder = ApplicationBuilder(Mock(),
                                     "builddir",
                                     "basedir",
                                     "cachedir",
                                     cached=True)
        builder._get_build_graph = get_build_graph_mock

        result = builder.build()

        mock_cached_build_strategy.build.assert_called_once()
        self.assertEqual(result, mock_cached_build_strategy.build())

    @patch("samcli.lib.build.app_builder.ParallelBuildStrategy")
    def test_parallel_run_should_pick_parallel_strategy(
            self, mock_parallel_build_strategy_class):
        mock_parallel_build_strategy = Mock()
        mock_parallel_build_strategy_class.return_value = mock_parallel_build_strategy

        build_graph_mock = Mock()
        get_build_graph_mock = Mock(return_value=build_graph_mock)

        builder = ApplicationBuilder(Mock(),
                                     "builddir",
                                     "basedir",
                                     "cachedir",
                                     parallel=True)
        builder._get_build_graph = get_build_graph_mock

        result = builder.build()

        mock_parallel_build_strategy.build.assert_called_once()
        self.assertEqual(result, mock_parallel_build_strategy.build())

    @patch("samcli.lib.build.app_builder.ParallelBuildStrategy")
    @patch("samcli.lib.build.app_builder.CachedBuildStrategy")
    def test_parallel_and_cached_run_should_pick_parallel_with_cached_strategy(
            self, mock_cached_build_strategy_class,
            mock_parallel_build_strategy_class):
        mock_parallel_build_strategy = Mock()
        mock_parallel_build_strategy_class.return_value = mock_parallel_build_strategy

        mock_cached_build_strategy = Mock()
        mock_cached_build_strategy_class.return_value = mock_cached_build_strategy

        build_graph_mock = Mock()
        get_build_graph_mock = Mock(return_value=build_graph_mock)

        builder = ApplicationBuilder(Mock(),
                                     "builddir",
                                     "basedir",
                                     "cachedir",
                                     parallel=True)
        builder._get_build_graph = get_build_graph_mock

        result = builder.build()

        mock_parallel_build_strategy.build.assert_called_once()
        self.assertEqual(result, mock_parallel_build_strategy.build())
コード例 #28
0
 def setUp(self):
     self.builder = ApplicationBuilder(Mock(),
                                       "/build/dir",
                                       "/base/dir")
コード例 #29
0
 def setUp(self):
     self.builder = ApplicationBuilder(Mock(),
                                       "/build/dir",
                                       "/base/dir",
                                       "/cache/dir",
                                       mode="mode")
コード例 #30
0
 def setUp(self):
     self.builder = ApplicationBuilder(Mock(), "/build/dir", "/base/dir",
                                       "cachedir")
コード例 #31
0
 def setUp(self):
     self.mock_func_provider = Mock()
     self.builder = ApplicationBuilder(self.mock_func_provider, "builddir",
                                       "basedir")
コード例 #32
0
class TestApplicationBuilder_update_template(TestCase):

    def setUp(self):
        self.builder = ApplicationBuilder(Mock(),
                                          "builddir",
                                          "basedir")

        self.template_dict = {
            "Resources": {
                "MyFunction1": {
                    "Type": "AWS::Serverless::Function",
                    "Properties": {
                        "CodeUri": "oldvalue"
                    }
                },
                "MyFunction2": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {
                        "Code": "oldvalue"
                    }
                },
                "OtherResource": {
                    "Type": "AWS::Lambda::Version",
                    "Properties": {
                        "CodeUri": "something"
                    }
                }
            }
        }

    def test_must_write_relative_build_artifacts_path(self):
        original_template_path = "/path/to/tempate.txt"
        built_artifacts = {
            "MyFunction1": "/path/to/build/MyFunction1",
            "MyFunction2": "/path/to/build/MyFunction2"
        }

        expected_result = {
            "Resources": {
                "MyFunction1": {
                    "Type": "AWS::Serverless::Function",
                    "Properties": {
                        "CodeUri": os.path.join("build", "MyFunction1")
                    }
                },
                "MyFunction2": {
                    "Type": "AWS::Lambda::Function",
                    "Properties": {
                        "Code": os.path.join("build", "MyFunction2")
                    }
                },
                "OtherResource": {
                    "Type": "AWS::Lambda::Version",
                    "Properties": {
                        "CodeUri": "something"
                    }
                }
            }
        }

        actual = self.builder.update_template(self.template_dict, original_template_path, built_artifacts)
        self.assertEquals(actual, expected_result)

    def test_must_skip_if_no_artifacts(self):

        built_artifacts = {}
        actual = self.builder.update_template(self.template_dict, "/foo/bar/template.txt", built_artifacts)

        self.assertEquals(actual, self.template_dict)
コード例 #33
0
 def setUp(self):
     self.image_name = "name"
     self.builder = ApplicationBuilder(Mock(),
                                       "/build/dir",
                                       "/base/dir")
コード例 #34
0
class TestApplicationBuilder_parse_builder_response(TestCase):

    def setUp(self):
        self.image_name = "name"
        self.builder = ApplicationBuilder(Mock(),
                                          "/build/dir",
                                          "/base/dir")

    def test_must_parse_json(self):
        data = {"valid": "json"}

        result = self.builder._parse_builder_response(json.dumps(data), self.image_name)
        self.assertEquals(result, data)

    def test_must_fail_on_invalid_json(self):
        data = "{invalid: json}"

        with self.assertRaises(ValueError):
            self.builder._parse_builder_response(data, self.image_name)

    def test_must_raise_on_user_error(self):
        msg = "invalid params"
        data = {"error": {"code": 488, "message": msg}}

        with self.assertRaises(BuildError) as ctx:
            self.builder._parse_builder_response(json.dumps(data), self.image_name)

        self.assertEquals(str(ctx.exception), msg)

    def test_must_raise_on_version_mismatch(self):
        msg = "invalid params"
        data = {"error": {"code": 505, "message": msg}}

        with self.assertRaises(UnsupportedBuilderLibraryVersionError) as ctx:
            self.builder._parse_builder_response(json.dumps(data), self.image_name)

        expected = str(UnsupportedBuilderLibraryVersionError(self.image_name, msg))
        self.assertEquals(str(ctx.exception), expected)

    def test_must_raise_on_method_not_found(self):
        msg = "invalid method"
        data = {"error": {"code": -32601, "message": msg}}

        with self.assertRaises(UnsupportedBuilderLibraryVersionError) as ctx:
            self.builder._parse_builder_response(json.dumps(data), self.image_name)

        expected = str(UnsupportedBuilderLibraryVersionError(self.image_name, msg))
        self.assertEquals(str(ctx.exception), expected)

    def test_must_raise_on_all_other_codes(self):
        msg = "builder crashed"
        data = {"error": {"code": 1, "message": msg}}

        with self.assertRaises(ValueError) as ctx:
            self.builder._parse_builder_response(json.dumps(data), self.image_name)

        self.assertEquals(str(ctx.exception), msg)
コード例 #35
0
class TestApplicationBuilder_build_function(TestCase):

    def setUp(self):
        self.builder = ApplicationBuilder(Mock(),
                                          "/build/dir",
                                          "/base/dir")

    @patch("samcli.lib.build.app_builder.get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_process(self, osutils_mock, get_workflow_config_mock):
        function_name = "function_name"
        codeuri = "path/to/source"
        runtime = "runtime"
        scratch_dir = "scratch"
        config_mock = get_workflow_config_mock.return_value = Mock()
        config_mock.manifest_name = "manifest_name"

        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        self.builder._build_function_in_process = Mock()

        code_dir = "/base/dir/path/to/source"
        artifacts_dir = "/build/dir/function_name"
        manifest_path = os.path.join(code_dir, config_mock.manifest_name)

        self.builder._build_function(function_name, codeuri, runtime)

        self.builder._build_function_in_process.assert_called_with(config_mock,
                                                                   code_dir,
                                                                   artifacts_dir,
                                                                   scratch_dir,
                                                                   manifest_path,
                                                                   runtime)

    @patch("samcli.lib.build.app_builder.get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_container(self, osutils_mock, get_workflow_config_mock):
        function_name = "function_name"
        codeuri = "path/to/source"
        runtime = "runtime"
        scratch_dir = "scratch"
        config_mock = get_workflow_config_mock.return_value = Mock()
        config_mock.manifest_name = "manifest_name"

        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        self.builder._build_function_on_container = Mock()

        code_dir = "/base/dir/path/to/source"
        artifacts_dir = "/build/dir/function_name"
        manifest_path = os.path.join(code_dir, config_mock.manifest_name)

        # Settting the container manager will make us use the container
        self.builder._container_manager = Mock()
        self.builder._build_function(function_name, codeuri, runtime)

        self.builder._build_function_on_container.assert_called_with(config_mock,
                                                                     code_dir,
                                                                     artifacts_dir,
                                                                     scratch_dir,
                                                                     manifest_path,
                                                                     runtime)
コード例 #36
0
class TestApplicationBuilder_build_function_on_container(TestCase):

    def setUp(self):
        self.container_manager = Mock()
        self.builder = ApplicationBuilder(Mock(),
                                          "/build/dir",
                                          "/base/dir",
                                          container_manager=self.container_manager)
        self.builder._parse_builder_response = Mock()

    @patch("samcli.lib.build.app_builder.LambdaBuildContainer")
    @patch("samcli.lib.build.app_builder.lambda_builders_protocol_version")
    @patch("samcli.lib.build.app_builder.LOG")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_container(self, osutils_mock, LOGMock, protocol_version_mock, LambdaBuildContainerMock):
        config = Mock()
        log_level = LOGMock.getEffectiveLevel.return_value = 'foo'
        stdout_data = "container stdout response data"
        response = {
            "result": {
                "artifacts_dir": "/some/dir"
            }

        }

        def mock_wait_for_logs(stdout, stderr):
            stdout.write(stdout_data.encode('utf-8'))

        # Wire all mocks correctly
        container_mock = LambdaBuildContainerMock.return_value = Mock()
        container_mock.wait_for_logs = mock_wait_for_logs
        self.builder._parse_builder_response.return_value = response

        result = self.builder._build_function_on_container(config,
                                                           "source_dir",
                                                           "artifacts_dir",
                                                           "scratch_dir",
                                                           "manifest_path",
                                                           "runtime")
        self.assertEquals(result, "artifacts_dir")

        LambdaBuildContainerMock.assert_called_once_with(protocol_version_mock,
                                                         config.language,
                                                         config.dependency_manager,
                                                         config.application_framework,
                                                         "source_dir",
                                                         "manifest_path",
                                                         "runtime",
                                                         log_level=log_level,
                                                         optimizations=None,
                                                         options=None,
                                                         executable_search_paths=config.executable_search_paths)

        self.container_manager.run.assert_called_with(container_mock)
        self.builder._parse_builder_response.assert_called_once_with(stdout_data, container_mock.image)
        container_mock.copy.assert_called_with(response["result"]["artifacts_dir"] + "/.",
                                               "artifacts_dir")
        self.container_manager.stop.assert_called_with(container_mock)

    @patch("samcli.lib.build.app_builder.LambdaBuildContainer")
    def test_must_raise_on_unsupported_container(self, LambdaBuildContainerMock):
        config = Mock()

        container_mock = LambdaBuildContainerMock.return_value = Mock()
        container_mock.image = "image name"
        container_mock.executable_name = "myexecutable"

        self.container_manager.run.side_effect = docker.errors.APIError("Bad Request: 'lambda-builders' "
                                                                        "executable file not found in $PATH")

        with self.assertRaises(UnsupportedBuilderLibraryVersionError) as ctx:
            self.builder._build_function_on_container(config,
                                                      "source_dir",
                                                      "artifacts_dir",
                                                      "scratch_dir",
                                                      "manifest_path",
                                                      "runtime")

        msg = "You are running an outdated version of Docker container 'image name' that is not compatible with" \
              "this version of SAM CLI. Please upgrade to continue to continue with build. " \
              "Reason: 'myexecutable executable not found in container'"

        self.assertEquals(str(ctx.exception), msg)
        self.container_manager.stop.assert_called_with(container_mock)
コード例 #37
0
class TestApplicationBuilder_build_function(TestCase):
    def setUp(self):
        self.builder = ApplicationBuilder(Mock(), "/build/dir", "/base/dir",
                                          "cachedir")

    @patch("samcli.lib.build.app_builder.get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_process(self, osutils_mock,
                                   get_workflow_config_mock):
        function_name = "function_name"
        codeuri = "path/to/source"
        packagetype = ZIP
        runtime = "runtime"
        scratch_dir = "scratch"
        handler = "handler.handle"
        config_mock = get_workflow_config_mock.return_value = Mock()
        config_mock.manifest_name = "manifest_name"

        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(
            return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        self.builder._build_function_in_process = Mock()

        code_dir = str(Path("/base/dir/path/to/source").resolve())
        artifacts_dir = str(Path("/build/dir/function_name"))
        manifest_path = str(
            Path(os.path.join(code_dir, config_mock.manifest_name)).resolve())

        self.builder._build_function(function_name, codeuri, ZIP, runtime,
                                     handler, artifacts_dir)

        self.builder._build_function_in_process.assert_called_with(
            config_mock, code_dir, artifacts_dir, scratch_dir, manifest_path,
            runtime, None)

    @patch("samcli.lib.build.app_builder.get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_process_with_metadata(self, osutils_mock,
                                                 get_workflow_config_mock):
        function_name = "function_name"
        codeuri = "path/to/source"
        runtime = "runtime"
        packagetype = ZIP
        scratch_dir = "scratch"
        handler = "handler.handle"
        config_mock = get_workflow_config_mock.return_value = Mock()
        config_mock.manifest_name = "manifest_name"

        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(
            return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        self.builder._build_function_in_process = Mock()

        code_dir = str(Path("/base/dir/path/to/source").resolve())
        artifacts_dir = str(Path("/build/dir/function_name"))
        manifest_path = str(
            Path(os.path.join(code_dir, config_mock.manifest_name)).resolve())

        self.builder._build_function(function_name,
                                     codeuri,
                                     packagetype,
                                     runtime,
                                     handler,
                                     artifacts_dir,
                                     metadata={"BuildMethod": "Workflow"})

        get_workflow_config_mock.assert_called_with(
            runtime,
            code_dir,
            self.builder._base_dir,
            specified_workflow="Workflow")

        self.builder._build_function_in_process.assert_called_with(
            config_mock, code_dir, artifacts_dir, scratch_dir, manifest_path,
            runtime, None)

    @patch("samcli.lib.build.app_builder.get_workflow_config")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_container(self, osutils_mock,
                                     get_workflow_config_mock):
        function_name = "function_name"
        codeuri = "path/to/source"
        runtime = "runtime"
        packagetype = ZIP
        scratch_dir = "scratch"
        handler = "handler.handle"
        config_mock = get_workflow_config_mock.return_value = Mock()
        config_mock.manifest_name = "manifest_name"

        osutils_mock.mkdir_temp.return_value.__enter__ = Mock(
            return_value=scratch_dir)
        osutils_mock.mkdir_temp.return_value.__exit__ = Mock()

        self.builder._build_function_on_container = Mock()

        code_dir = str(Path("/base/dir/path/to/source").resolve())
        artifacts_dir = str(Path("/build/dir/function_name"))
        manifest_path = str(
            Path(os.path.join(code_dir, config_mock.manifest_name)).resolve())

        # Settting the container manager will make us use the container
        self.builder._container_manager = Mock()
        self.builder._build_function(function_name, codeuri, packagetype,
                                     runtime, handler, artifacts_dir)

        self.builder._build_function_on_container.assert_called_with(
            config_mock, code_dir, artifacts_dir, scratch_dir, manifest_path,
            runtime, None)
コード例 #38
0
class TestApplicationBuilder_parse_builder_response(TestCase):
    def setUp(self):
        self.image_name = "name"
        self.builder = ApplicationBuilder(Mock(), "/build/dir", "/base/dir",
                                          "/cache/dir")

    def test_must_parse_json(self):
        data = {"valid": "json"}

        result = self.builder._parse_builder_response(json.dumps(data),
                                                      self.image_name)
        self.assertEqual(result, data)

    def test_must_fail_on_invalid_json(self):
        data = "{invalid: json}"

        with self.assertRaises(ValueError):
            self.builder._parse_builder_response(data, self.image_name)

    def test_must_raise_on_user_error(self):
        msg = "invalid params"
        data = {"error": {"code": 488, "message": msg}}

        with self.assertRaises(BuildInsideContainerError) as ctx:
            self.builder._parse_builder_response(json.dumps(data),
                                                 self.image_name)

        self.assertEqual(str(ctx.exception), msg)

    def test_must_raise_on_version_mismatch(self):
        msg = "invalid params"
        data = {"error": {"code": 505, "message": msg}}

        with self.assertRaises(UnsupportedBuilderLibraryVersionError) as ctx:
            self.builder._parse_builder_response(json.dumps(data),
                                                 self.image_name)

        expected = str(
            UnsupportedBuilderLibraryVersionError(self.image_name, msg))
        self.assertEqual(str(ctx.exception), expected)

    def test_must_raise_on_method_not_found(self):
        msg = "invalid method"
        data = {"error": {"code": -32601, "message": msg}}

        with self.assertRaises(UnsupportedBuilderLibraryVersionError) as ctx:
            self.builder._parse_builder_response(json.dumps(data),
                                                 self.image_name)

        expected = str(
            UnsupportedBuilderLibraryVersionError(self.image_name, msg))
        self.assertEqual(str(ctx.exception), expected)

    def test_must_raise_on_all_other_codes(self):
        msg = "builder crashed"
        data = {"error": {"code": 1, "message": msg}}

        with self.assertRaises(ValueError) as ctx:
            self.builder._parse_builder_response(json.dumps(data),
                                                 self.image_name)

        self.assertEqual(str(ctx.exception), msg)
コード例 #39
0
 def setUp(self):
     self.image_name = "name"
     self.builder = ApplicationBuilder(Mock(), "/build/dir", "/base/dir",
                                       "/cache/dir")
コード例 #40
0
ファイル: command.py プロジェクト: uu64/aws-sam-cli
def do_cli(  # pylint: disable=too-many-locals, too-many-statements
    function_identifier: Optional[str],
    template: str,
    base_dir: Optional[str],
    build_dir: str,
    cache_dir: str,
    clean: bool,
    use_container: bool,
    cached: bool,
    parallel: bool,
    manifest_path: Optional[str],
    docker_network: Optional[str],
    skip_pull_image: bool,
    parameter_overrides: Dict,
    mode: Optional[str],
    container_env_var: Optional[Tuple[str]],
    container_env_var_file: Optional[str],
    build_image: Optional[Tuple[str]],
) -> None:
    """
    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
    from samcli.lib.build.build_graph import InvalidBuildGraphException

    LOG.debug("'build' command is called")
    if cached:
        LOG.info("Starting Build use cache")
    if use_container:
        LOG.info("Starting Build inside a container")

    processed_env_vars = _process_env_var(container_env_var)
    processed_build_images = _process_image_options(build_image)

    with BuildContext(
            function_identifier,
            template,
            base_dir,
            build_dir,
            cache_dir,
            cached,
            clean=clean,
            manifest_path=manifest_path,
            use_container=use_container,
            parameter_overrides=parameter_overrides,
            docker_network=docker_network,
            skip_pull_image=skip_pull_image,
            mode=mode,
            container_env_var=processed_env_vars,
            container_env_var_file=container_env_var_file,
            build_images=processed_build_images,
    ) as ctx:
        try:
            builder = ApplicationBuilder(
                ctx.resources_to_build,
                ctx.build_dir,
                ctx.base_dir,
                ctx.cache_dir,
                ctx.cached,
                ctx.is_building_specific_resource,
                manifest_path_override=ctx.manifest_path_override,
                container_manager=ctx.container_manager,
                mode=ctx.mode,
                parallel=parallel,
                container_env_var=processed_env_vars,
                container_env_var_file=container_env_var_file,
                build_images=processed_build_images,
            )
        except FunctionNotFound as ex:
            raise UserException(str(ex),
                                wrapped_from=ex.__class__.__name__) from ex

        try:
            artifacts = builder.build()

            stack_output_template_path_by_stack_path = {
                stack.stack_path: stack.get_output_template_path(ctx.build_dir)
                for stack in ctx.stacks
            }
            for stack in ctx.stacks:
                modified_template = builder.update_template(
                    stack,
                    artifacts,
                    stack_output_template_path_by_stack_path,
                )
                move_template(stack.location,
                              stack.get_output_template_path(ctx.build_dir),
                              modified_template)

            click.secho("\nBuild Succeeded", fg="green")

            # try to use relpath so the command is easier to understand, however,
            # under Windows, when SAM and (build_dir or output_template_path) are
            # on different drive, relpath() fails.
            root_stack = SamLocalStackProvider.find_root_stack(ctx.stacks)
            out_template_path = root_stack.get_output_template_path(
                ctx.build_dir)
            try:
                build_dir_in_success_message = os.path.relpath(ctx.build_dir)
                output_template_path_in_success_message = os.path.relpath(
                    out_template_path)
            except ValueError:
                LOG.debug(
                    "Failed to retrieve relpath - using the specified path as-is instead"
                )
                build_dir_in_success_message = ctx.build_dir
                output_template_path_in_success_message = out_template_path

            msg = gen_success_msg(
                build_dir_in_success_message,
                output_template_path_in_success_message,
                os.path.abspath(
                    ctx.build_dir) == os.path.abspath(DEFAULT_BUILD_DIR),
            )

            click.secho(msg, fg="yellow")

        except (
                UnsupportedRuntimeException,
                BuildError,
                BuildInsideContainerError,
                UnsupportedBuilderLibraryVersionError,
                ContainerBuildNotSupported,
                InvalidBuildGraphException,
        ) as ex:
            click.secho("\nBuild Failed", fg="red")

            # Some Exceptions have a deeper wrapped exception that needs to be surfaced
            # from deeper than just one level down.
            deep_wrap = getattr(ex, "wrapped_from", None)
            wrapped_from = deep_wrap if deep_wrap else ex.__class__.__name__
            raise UserException(str(ex), wrapped_from=wrapped_from) from ex
コード例 #41
0
class TestApplicationBuilder_build_function_on_container(TestCase):
    def setUp(self):
        self.container_manager = Mock()
        self.builder = ApplicationBuilder(
            Mock(),
            "/build/dir",
            "/base/dir",
            "/cache/dir",
            container_manager=self.container_manager,
            mode="mode")
        self.builder._parse_builder_response = Mock()

    @patch("samcli.lib.build.app_builder.LambdaBuildContainer")
    @patch("samcli.lib.build.app_builder.lambda_builders_protocol_version")
    @patch("samcli.lib.build.app_builder.LOG")
    @patch("samcli.lib.build.app_builder.osutils")
    def test_must_build_in_container(self, osutils_mock, LOGMock,
                                     protocol_version_mock,
                                     LambdaBuildContainerMock):
        config = Mock()
        log_level = LOGMock.getEffectiveLevel.return_value = "foo"
        stdout_data = "container stdout response data"
        response = {"result": {"artifacts_dir": "/some/dir"}}

        def mock_wait_for_logs(stdout, stderr):
            stdout.write(stdout_data.encode("utf-8"))

        # Wire all mocks correctly
        container_mock = LambdaBuildContainerMock.return_value = Mock()
        container_mock.wait_for_logs = mock_wait_for_logs
        self.builder._parse_builder_response.return_value = response

        result = self.builder._build_function_on_container(
            config, "source_dir", "artifacts_dir", "scratch_dir",
            "manifest_path", "runtime", None)
        self.assertEqual(result, "artifacts_dir")

        LambdaBuildContainerMock.assert_called_once_with(
            protocol_version_mock,
            config.language,
            config.dependency_manager,
            config.application_framework,
            "source_dir",
            "manifest_path",
            "runtime",
            log_level=log_level,
            optimizations=None,
            options=None,
            executable_search_paths=config.executable_search_paths,
            mode="mode",
        )

        self.container_manager.run.assert_called_with(container_mock)
        self.builder._parse_builder_response.assert_called_once_with(
            stdout_data, container_mock.image)
        container_mock.copy.assert_called_with(
            response["result"]["artifacts_dir"] + "/.", "artifacts_dir")
        self.container_manager.stop.assert_called_with(container_mock)

    @patch("samcli.lib.build.app_builder.LambdaBuildContainer")
    def test_must_raise_on_unsupported_container(self,
                                                 LambdaBuildContainerMock):
        config = Mock()

        container_mock = LambdaBuildContainerMock.return_value = Mock()
        container_mock.image = "image name"
        container_mock.executable_name = "myexecutable"

        self.container_manager.run.side_effect = docker.errors.APIError(
            "Bad Request: 'lambda-builders' "
            "executable file not found in $PATH")

        with self.assertRaises(UnsupportedBuilderLibraryVersionError) as ctx:
            self.builder._build_function_on_container(config, "source_dir",
                                                      "artifacts_dir",
                                                      "scratch_dir",
                                                      "manifest_path",
                                                      "runtime", {})

        msg = (
            "You are running an outdated version of Docker container 'image name' that is not compatible with"
            "this version of SAM CLI. Please upgrade to continue to continue with build. "
            "Reason: 'myexecutable executable not found in container'")

        self.assertEqual(str(ctx.exception), msg)
        self.container_manager.stop.assert_called_with(container_mock)

    def test_must_raise_on_docker_not_running(self):
        config = Mock()

        self.container_manager.is_docker_reachable = False

        with self.assertRaises(BuildInsideContainerError) as ctx:
            self.builder._build_function_on_container(config, "source_dir",
                                                      "artifacts_dir",
                                                      "scratch_dir",
                                                      "manifest_path",
                                                      "runtime", {})

        self.assertEqual(
            str(ctx.exception),
            "Docker is unreachable. Docker needs to be running to build inside a container."
        )

    @patch("samcli.lib.build.app_builder.supports_build_in_container")
    def test_must_raise_on_unsupported_container_build(
            self, supports_build_in_container_mock):
        config = Mock()

        reason = "my reason"
        supports_build_in_container_mock.return_value = (False, reason)

        with self.assertRaises(ContainerBuildNotSupported) as ctx:
            self.builder._build_function_on_container(config, "source_dir",
                                                      "artifacts_dir",
                                                      "scratch_dir",
                                                      "manifest_path",
                                                      "runtime", {})

        self.assertEqual(str(ctx.exception), reason)
コード例 #42
0
 def setUp(self):
     self.mock_func_provider = Mock()
     self.builder = ApplicationBuilder(self.mock_func_provider,
                                       "builddir",
                                       "basedir")