def setUp(self): # create a build graph with 2 function definitions and 2 layer definitions self.build_graph = BuildGraph("build_dir") self.function1_1 = Mock() self.function1_1.inlinecode = None self.function1_2 = Mock() self.function1_2.inlinecode = None self.function2 = Mock() self.function2.inlinecode = None self.function_build_definition1 = FunctionBuildDefinition( "runtime", "codeuri", ZIP, {}) self.function_build_definition1.functions = [ self.function1_1, self.function1_2 ] self.function_build_definition2 = FunctionBuildDefinition( "runtime2", "codeuri", ZIP, {}) self.function_build_definition1.functions = [self.function2] self.build_graph.put_function_build_definition( self.function_build_definition1, Mock(packagetype=ZIP)) self.build_graph.put_function_build_definition( self.function_build_definition2, Mock(packagetype=ZIP)) self.layer_build_definition1 = LayerBuildDefinition( "layer1", "codeuri", "build_method", []) self.layer_build_definition2 = LayerBuildDefinition( "layer2", "codeuri", "build_method", []) self.build_graph.put_layer_build_definition( self.layer_build_definition1, Mock()) self.build_graph.put_layer_build_definition( self.layer_build_definition2, Mock())
def test_if_cached_invalid_with_no_cached_folder(self, build_layer_mock, build_function_mock, copytree_mock): with osutils.mkdir_temp() as temp_base_dir: build_dir = Path(temp_base_dir, ".aws-sam", "build") build_dir.mkdir(parents=True) cache_dir = Path(temp_base_dir, ".aws-sam", "cache") cache_dir.mkdir(parents=True) build_function_mock.return_value = { "HelloWorldPython": "artifact1", "HelloWorldPython2": "artifact2" } build_layer_mock.return_value = {"SumLayer": "artifact3"} build_graph_path = Path(build_dir.parent, "build.toml") build_graph_path.write_text( CachedBuildStrategyTest.BUILD_GRAPH_CONTENTS) build_graph = BuildGraph(str(build_dir)) cached_build_strategy = CachedBuildStrategy( build_graph, DefaultBuildStrategy, temp_base_dir, build_dir, cache_dir, True) cached_build_strategy.build_single_function_definition( build_graph.get_function_build_definitions()[0]) cached_build_strategy.build_single_layer_definition( build_graph.get_layer_build_definitions()[0]) build_function_mock.assert_called_once() build_layer_mock.assert_called_once() self.assertEqual(copytree_mock.call_count, 2)
def test_functions_should_be_added_existing_build_graph(self): with osutils.mkdir_temp() as temp_base_dir: build_dir = Path(temp_base_dir, ".aws-sam", "build") build_dir.mkdir(parents=True) build_graph_path = Path(build_dir.parent, "build.toml") build_graph_path.write_text(TestBuildGraph.BUILD_GRAPH_CONTENTS) build_graph = BuildGraph(str(build_dir)) build_definition1 = BuildDefinition(TestBuildGraph.RUNTIME, TestBuildGraph.CODEURI, TestBuildGraph.METADATA) function1 = generate_function(runtime=TestBuildGraph.RUNTIME, codeuri=TestBuildGraph.CODEURI, metadata=TestBuildGraph.METADATA) build_graph.put_build_definition(build_definition1, function1) self.assertTrue(len(build_graph.get_build_definitions()), 1) for build_definition in build_graph.get_build_definitions(): self.assertTrue(len(build_definition.functions), 1) self.assertTrue(build_definition.functions[0], function1) self.assertEqual(build_definition.uuid, TestBuildGraph.UUID) build_definition2 = BuildDefinition("another_runtime", "another_codeuri", None) function2 = generate_function(name="another_function") build_graph.put_build_definition(build_definition2, function2) self.assertTrue(len(build_graph.get_build_definitions()), 2)
def test_should_read_existing_build_graph(self): with osutils.mkdir_temp() as temp_base_dir: build_dir = Path(temp_base_dir, ".aws-sam", "build") build_dir.mkdir(parents=True) build_graph_path = Path(build_dir.parent, "build.toml") build_graph_path.write_text(TestBuildGraph.BUILD_GRAPH_CONTENTS) build_graph = BuildGraph(str(build_dir)) for build_definition in build_graph.get_build_definitions(): self.assertEqual(build_definition.codeuri, TestBuildGraph.CODEURI) self.assertEqual(build_definition.runtime, TestBuildGraph.RUNTIME) self.assertEqual(build_definition.metadata, TestBuildGraph.METADATA)
def _get_build_graph(self): """ Converts list of functions and layers into a build graph, where we can iterate on each unique build and trigger build :return: BuildGraph, which represents list of unique build definitions """ build_graph = BuildGraph(self._build_dir) functions = self._resources_to_build.functions layers = self._resources_to_build.layers for function in functions: function_build_details = FunctionBuildDefinition( function.runtime, function.codeuri, function.packagetype, function.metadata) build_graph.put_function_build_definition(function_build_details, function) for layer in layers: layer_build_details = LayerBuildDefinition( layer.name, layer.codeuri, layer.build_method, layer.compatible_runtimes) build_graph.put_layer_build_definition(layer_build_details, layer) build_graph.clean_redundant_definitions_and_update( not self._is_building_specific_resource) return build_graph
def test_if_cached_valid_when_build_single_function_definition( self, dir_checksum_mock, exists_mock, copytree_mock): pass with osutils.mkdir_temp() as temp_base_dir: build_dir = Path(temp_base_dir, ".aws-sam", "build") build_dir.mkdir(parents=True) cache_dir = Path(temp_base_dir, ".aws-sam", "cache") cache_dir.mkdir(parents=True) exists_mock.return_value = True dir_checksum_mock.return_value = CachedBuildStrategyTest.SOURCE_MD5 build_graph_path = Path(build_dir.parent, "build.toml") build_graph_path.write_text( CachedBuildStrategyTest.BUILD_GRAPH_CONTENTS) build_graph = BuildGraph(str(build_dir)) cached_build_strategy = CachedBuildStrategy( build_graph, DefaultBuildStrategy, temp_base_dir, build_dir, cache_dir, True) func1 = Mock() func1.name = "func1_name" func2 = Mock() func2.name = "func2_name" build_definition = build_graph.get_function_build_definitions()[0] layer_definition = build_graph.get_layer_build_definitions()[0] build_graph.put_function_build_definition(build_definition, func1) build_graph.put_function_build_definition(build_definition, func2) layer = Mock() layer.name = "layer_name" build_graph.put_layer_build_definition(layer_definition, layer) cached_build_strategy.build_single_function_definition( build_definition) cached_build_strategy.build_single_layer_definition( layer_definition) self.assertEqual(copytree_mock.call_count, 3)
class BuildStrategyBaseTest(TestCase): def setUp(self): # create a build graph with 2 function definitions and 2 layer definitions self.build_graph = BuildGraph("build_dir") self.function1_1 = Mock() self.function1_2 = Mock() self.function2 = Mock() self.function_build_definition1 = FunctionBuildDefinition( "runtime", "codeuri", {}) self.function_build_definition1.functions = [ self.function1_1, self.function1_2 ] self.function_build_definition2 = FunctionBuildDefinition( "runtime2", "codeuri", {}) self.function_build_definition1.functions = [self.function2] self.build_graph.put_function_build_definition( self.function_build_definition1, Mock()) self.build_graph.put_function_build_definition( self.function_build_definition2, Mock()) self.layer_build_definition1 = LayerBuildDefinition( "layer1", "codeuri", "build_method", []) self.layer_build_definition2 = LayerBuildDefinition( "layer2", "codeuri", "build_method", []) self.build_graph.put_layer_build_definition( self.layer_build_definition1, Mock()) self.build_graph.put_layer_build_definition( self.layer_build_definition2, Mock())
def test_should_instantiate_first_time(self): with osutils.mkdir_temp() as temp_base_dir: build_dir = Path(temp_base_dir, ".aws-sam", "build") build_dir.mkdir(parents=True) build_graph1 = BuildGraph(str(build_dir.resolve())) build_graph1.clean_redundant_functions_and_update(True) build_graph2 = BuildGraph(str(build_dir.resolve())) self.assertEqual(build_graph1.get_build_definitions(), build_graph2.get_build_definitions())
def _build_layers(self, build_graph: BuildGraph) -> Dict[str, str]: """ Iterates through build graph and runs each unique build and copies outcome to the corresponding layer folder """ layer_build_results = {} for layer_definition in build_graph.get_layer_build_definitions(): layer_build_results.update(self.build_single_layer_definition(layer_definition)) return layer_build_results
def _build_functions(self, build_graph: BuildGraph) -> Dict[str, str]: """ Iterates through build graph and runs each unique build and copies outcome to the corresponding function folder """ function_build_results = {} for build_definition in build_graph.get_function_build_definitions(): function_build_results.update(self.build_single_function_definition(build_definition)) return function_build_results
class BuildStrategyBaseTest(TestCase): def setUp(self): # create a build graph with 2 function definitions and 2 layer definitions self.build_graph = BuildGraph("build_dir") self.function1_1 = Mock() self.function1_1.inlinecode = None self.function1_1.get_build_dir = Mock() self.function1_1.full_path = Mock() self.function1_2 = Mock() self.function1_2.inlinecode = None self.function1_2.get_build_dir = Mock() self.function1_2.full_path = Mock() self.function2 = Mock() self.function2.inlinecode = None self.function2.get_build_dir = Mock() self.function2.full_path = Mock() self.function_build_definition1 = FunctionBuildDefinition( "runtime", "codeuri", ZIP, {}) self.function_build_definition2 = FunctionBuildDefinition( "runtime2", "codeuri", ZIP, {}) self.build_graph.put_function_build_definition( self.function_build_definition1, self.function1_1) self.build_graph.put_function_build_definition( self.function_build_definition1, self.function1_2) self.build_graph.put_function_build_definition( self.function_build_definition2, self.function2) self.layer1 = Mock() self.layer2 = Mock() self.layer_build_definition1 = LayerBuildDefinition( "layer1", "codeuri", "build_method", []) self.layer_build_definition2 = LayerBuildDefinition( "layer2", "codeuri", "build_method", []) self.build_graph.put_layer_build_definition( self.layer_build_definition1, self.layer1) self.build_graph.put_layer_build_definition( self.layer_build_definition2, self.layer2)
def test_redundant_cached_should_be_clean(self): with osutils.mkdir_temp() as temp_base_dir: build_dir = Path(temp_base_dir, ".aws-sam", "build") build_dir.mkdir(parents=True) build_graph = BuildGraph(str(build_dir.resolve())) cache_dir = Path(temp_base_dir, ".aws-sam", "cache") cache_dir.mkdir(parents=True) redundant_cache_folder = Path(cache_dir, "redundant") redundant_cache_folder.mkdir(parents=True) cached_build_strategy = CachedBuildStrategy(build_graph, Mock(), temp_base_dir, build_dir, cache_dir, True) cached_build_strategy._clean_redundant_cached() self.assertTrue(not redundant_cache_folder.exists())
def _get_build_graph(self, inline_env_vars: Optional[Dict] = None, env_vars_file: Optional[str] = None) -> BuildGraph: """ Converts list of functions and layers into a build graph, where we can iterate on each unique build and trigger build :return: BuildGraph, which represents list of unique build definitions """ build_graph = BuildGraph(self._build_dir) functions = self._resources_to_build.functions layers = self._resources_to_build.layers file_env_vars = {} if env_vars_file: try: with open(env_vars_file, "r", encoding="utf-8") as fp: file_env_vars = json.load(fp) except Exception as ex: raise IOError( "Could not read environment variables overrides from file {}: {}" .format(env_vars_file, str(ex))) from ex for function in functions: container_env_vars = self._make_env_vars(function, file_env_vars, inline_env_vars) function_build_details = FunctionBuildDefinition( function.runtime, function.codeuri, function.packagetype, function.metadata, env_vars=container_env_vars) build_graph.put_function_build_definition(function_build_details, function) for layer in layers: container_env_vars = self._make_env_vars(layer, file_env_vars, inline_env_vars) layer_build_details = LayerBuildDefinition( layer.name, layer.codeuri, layer.build_method, layer.compatible_runtimes, env_vars=container_env_vars) build_graph.put_layer_build_definition(layer_build_details, layer) build_graph.clean_redundant_definitions_and_update( not self._is_building_specific_resource) return build_graph
def _get_build_graph(self): """ Converts list of functions into a build graph, where we can iterate on each unique build and trigger build :return: BuildGraph, which represents list of unique build definitions """ build_graph = BuildGraph(self._build_dir) functions = self._resources_to_build.functions for function in functions: build_details = BuildDefinition(function.runtime, function.codeuri, function.metadata) build_graph.put_build_definition(build_details, function) build_graph.clean_redundant_functions_and_update(not self._is_building_specific_resource) return build_graph
def test_should_instantiate_first_time_and_update(self): with osutils.mkdir_temp() as temp_base_dir: build_dir = Path(temp_base_dir, ".aws-sam", "build") build_dir.mkdir(parents=True) # create a build graph and persist it build_graph1 = BuildGraph(str(build_dir)) build_definition1 = BuildDefinition(TestBuildGraph.RUNTIME, TestBuildGraph.CODEURI, TestBuildGraph.METADATA) function1 = generate_function(runtime=TestBuildGraph.RUNTIME, codeuri=TestBuildGraph.CODEURI, metadata=TestBuildGraph.METADATA) build_graph1.put_build_definition(build_definition1, function1) build_graph1.clean_redundant_functions_and_update(True) # read previously persisted graph and compare build_graph2 = BuildGraph(str(build_dir)) self.assertEqual(len(build_graph1.get_build_definitions()), len(build_graph2.get_build_definitions())) self.assertEqual( list(build_graph1.get_build_definitions())[0], list(build_graph2.get_build_definitions())[0])