Feat: added integration tests, container tag check and layer support #2780
Feat: added integration tests, container tag check and layer support #2780qingchm merged 24 commits intoaws:feat/public-ecrfrom
Conversation
jfuss
left a comment
There was a problem hiding this comment.
The logic seems generally good and I like how you adding the Container option class!
Can we make sure we have unit tests for any code we added? It looks like we don't have tests for the Container class or the additional logic you added into the app_builder. Pytest should give you lines/files that are missing coverage and you can use that as a starting place to have the lines/files you added are covered.
samcli/lib/build/app_builder.py
Outdated
| image = None | ||
| if self._build_images is not None: | ||
| if layer_name in self._build_images: | ||
| image = self._build_images[layer_name] | ||
| elif None in self._build_images: | ||
| image = self._build_images[None] | ||
| self._build_function_on_container( |
There was a problem hiding this comment.
I am slightly confused on this. Which I think is mainly due to the nesting.
A couple questions:
- Can
self._build_imagesbeNone? If so, is there a way we can safely default this to an empty dict instead? - Why are we checking if the
layer_nameis inself._build_images? - I am not familiar with the
build_imagesproperty and how it gets set. Could you describe the contents?
Something to think about for the future:
When you are writing deeply nested code, consider ways you can simplify it. There are usually ways to write the same logic with less control flows or splitting the nesting into simpler private functions. So in this case, if we could default self._build_images to an empty dict in __init__ then we safe ourselves the need to do None checks (we do this throughout the code base for this reason).
When acting on dictionaries in python, try to avoid using [] to access elements and instead use .get() method. The .get() method does the checks you want for you. So you can simplify both inner if statements by doing image = self._build_images.get(layer_name). By default, this will return None if the element (layer_name) is not in the dict.
I think I actually answered my above questions while writing the last part but will leave the in the comment to help explain my thought process/questions I would ask.
There was a problem hiding this comment.
- Yes it is defaulted to be none. Type hinting doesn't allow any parameter defaults to be {}, so no.
- self._build_images has function names and layer names as keys and image uri's as value.
- Details in feat(Public ECR): Added --build-image Options #2725, basically we take the command line argument and make a dict that stores the URI's and their related logicalId's
There was a problem hiding this comment.
+1 on using get(), this is following the previous pr's pattern, will change both to get()
There was a problem hiding this comment.
And we can set self._build_images to buildimages or {} during assignment, for sure this would be safer
| @parameterized.expand( | ||
| [ | ||
| ("use_container", None), | ||
| ("use_container", "amazon/aws-sam-cli-build-image-nodejs10.x"), |
There was a problem hiding this comment.
Can we keep the languages our integ tests use the same as others (python I think)? This helps us in keeping things up to date across all our tests.
There was a problem hiding this comment.
Sure I can change the test case to python then
|
|
||
| self.verify_docker_container_cleanedup("nodejs10.x") | ||
|
|
||
| def _verify_right_image_pulled(self, build_image, process_stderr): |
There was a problem hiding this comment.
I thought we have helper functions that do this already?
There was a problem hiding this comment.
this is checking the name of the image, I don't think we have anything similar
| self.verify_docker_container_cleanedup("nodejs10.x") | ||
|
|
||
| def _verify_right_image_pulled(self, build_image, process_stderr): | ||
| image_name = build_image if build_image is not None else "public.ecr.aws/sam/build-nodejs10.x" |
There was a problem hiding this comment.
If you really want to stay with node (which I prefer we keep all our integ tests the same language unless really testing something lang specific), we should be using the latest node.
There was a problem hiding this comment.
We have already added the support to default the tags to be latest if we don't input the tag, so this is exactly the same thing. But for the testing we can test if latest tag is included
There was a problem hiding this comment.
I am not talking about the image tag here. You are using Nodejs10.x, which is the oldest of the 2 Node versions Lambda supports. My comment is to not use the oldest and instead us the latest version of Node (or any language we us in our integ tests).
There was a problem hiding this comment.
+1, this can save us some work (or delay the work) when we deprecate node 10
| process = Popen(cmdlist, cwd=self.working_dir, stdout=PIPE, stderr=PIPE) | ||
| try: | ||
| stdout, stderr = process.communicate(timeout=TIMEOUT) | ||
| LOG.info(f"Stdout: {stdout.decode('utf-8')}") |
There was a problem hiding this comment.
Do we need this info always displayed in our test output?
Same goes for other LOG. statements, mainly those who will output logs of data (stderr and stdout).
There was a problem hiding this comment.
We do this same logging behaviour for all of our integration tests, when we run the command @jfuss
There was a problem hiding this comment.
In other build tests we do not log stdout and stderr. This comment is about removing the large outputs in our tests logs. Leaving what commands and other small information is fine, logging 30+ lines seems like overkill. If you think this info is important, then we should only output it on test failure instead of every single run.
There was a problem hiding this comment.
I guess we do but it is done through the run_command:
aws-sam-cli/tests/testing_utils.py
Line 25 in 4543732
There was a problem hiding this comment.
Because we need to do extra work that run_command does not provide, which is checking the content in the stderr
There was a problem hiding this comment.
We do support checking stderr using run_command
aws-sam-cli/tests/integration/buildcmd/test_build_cmd.py
Lines 1548 to 1551 in 4543732
There was a problem hiding this comment.
I can try something like this, trying to use the nametuple returned
There was a problem hiding this comment.
Before I had several differences between this function and run command, but seems like this run_command will return what I need
There was a problem hiding this comment.
Updated to use run_command()
| LOG.debug(Path(config_path).read_text()) | ||
| runner = CliRunner() | ||
| result = runner.invoke(cli, []) | ||
| result = runner.invoke(cli, ["--use-container"]) |
There was a problem hiding this comment.
Why are we adding --use-container to all of these? It's unclear why we need to update this.
There was a problem hiding this comment.
Because otherwise as the CliRunner doesn't see this tag, it fails the invocation and showcases the ContainerTag check error
There was a problem hiding this comment.
I might be missing something but my initial feeling is that seems wrong. Wouldn't this mean we are requiring --use-container now? The command shouldn't fail if we don't provided --use-container to the cli.
There was a problem hiding this comment.
It should now, we are going to fail any use of container related tags if we don't provide --use-container to the cli instead of ignoring them now
| import click | ||
|
|
||
|
|
||
| class Container(click.Option): |
There was a problem hiding this comment.
Should we name this something more specific like ContainerOptions? We have other Container classes and might be easier to read/understand the difference at a glance.
There was a problem hiding this comment.
Sure I will change the name
aahung
left a comment
There was a problem hiding this comment.
How does it handle if I want to specify a build image for a function in nested stack like --build-image=ChildStack.FunctionA. It will be great if we have an integ test on that
Some unit tests are already included in the previous pr. Adding additional unit tests for layer builds. As for Container class, I don't think we have tests on click_mutex class either. Are we looking to add tests for click related code? |
| process = Popen(cmdlist, cwd=self.working_dir, stdout=PIPE, stderr=PIPE) | ||
| try: | ||
| stdout, stderr = process.communicate(timeout=TIMEOUT) | ||
| LOG.info(f"Stdout: {stdout.decode('utf-8')}") |
There was a problem hiding this comment.
I guess we do but it is done through the run_command:
aws-sam-cli/tests/testing_utils.py
Line 25 in 4543732
| import click | ||
|
|
||
|
|
||
| class ContainerOptions(click.Option): |
There was a problem hiding this comment.
Do we have unit tests for this class?
There was a problem hiding this comment.
We don't, I don't see any tests related to https://github.com/aws/aws-sam-cli/blob/develop/samcli/commands/local/cli_common/click_mutex.py either, let me know your thoughts regarding testing on click.Option classes! One of the ways that I can think of testing it would be to create a mock CliRunner and verify that command fails when we provide container related tags without -u
There was a problem hiding this comment.
Just because we do not have tests for another class, doesn't mean we should not be adding tests for new code. We always want to improve the code base through adding tests. With that logic one could say, we shouldn't be adding any tests because we have a class that doesn't have tests at all.
Please add unit tests for code we add, so we have some basic checks in place on that expectation of that code.
We shouldn't need to mock a CliRunner here or verify commands (kind of out of scope of a unit tests in my opinion). What we want to verify is that the logic you added is correct. So you can mock out methods, input, etc to help in validating what you expect to happen does happen. At the very least we should have tests to cover:
if "use_container" not in opts and self.name in opts:
opt_name = self.name.replace("_", "-")
msg = f"Missing required parameter, need the --use-container flag in order to use --{opt_name} flag."
raise click.UsageError(msg)
An alternative way to do this is by creating a sub method and testing that, if mocking the rest of things becomes a pain.
There was a problem hiding this comment.
adding two branches of tests
aahung
left a comment
There was a problem hiding this comment.
Overall LGTM, left some small comments/questions
| process = Popen(cmdlist, cwd=self.working_dir, stdout=PIPE, stderr=PIPE) | ||
| try: | ||
| stdout, stderr = process.communicate(timeout=TIMEOUT) | ||
| LOG.info(f"Stdout: {stdout.decode('utf-8')}") |
There was a problem hiding this comment.
We do support checking stderr using run_command
aws-sam-cli/tests/integration/buildcmd/test_build_cmd.py
Lines 1548 to 1551 in 4543732
|
|
||
|
|
||
| @patch("samcli.commands.build.click_container.ContainerOptions") | ||
| class TestContainerOptionsSucceeds(TestCase): |
There was a problem hiding this comment.
Nit: Since this is in its own file, lets match that with our unit tests as well. This is will make it consistent with all our other tests in the repo and make it easier to know where to update tests in the future when things change.
jfuss
left a comment
There was a problem hiding this comment.
Thanks for handling all the feedback through this PR.
* feat(Public ECR): Changed Build Image Registry to Public ECR (#2708) * Changed Build Image Registry to Public ECR * Added _IMAGE_URI_PREFIX * Fixed Unit Tests * Updated Image Format * feat(Public ECR): Updated Test Image Name and Added Latest Tag Check (#2720) * Added Tests for Latest Tag * Added use_container Check for Verify Latest Tag Tests * Fixed DotNet and Go Build Tests * Added Missing use_container Check for test_build_function_and_layer * feat(Public ECR): Changed Build Image Registry to Public ECR (#2708) * Changed Build Image Registry to Public ECR * Added _IMAGE_URI_PREFIX * Fixed Unit Tests * Updated Image Format * feat(Public ECR): Updated Test Image Name and Added Latest Tag Check (#2720) * Added Tests for Latest Tag * Added use_container Check for Verify Latest Tag Tests * Fixed DotNet and Go Build Tests * Added Missing use_container Check for test_build_function_and_layer * feat(Public ECR): Added --build-image Options (#2725) * Added Latest Tag Check * Added --build-image Option * Added Unit Tests * Added Help Text and Fixed PyLint * Fixed Path Validation for Unit Tests * Updated Type Hintings * Added _parse_key_value_pair * Updated tag Handling for Image Pulls * Added Throwing Exception with Invalid Build Images * Fixed PyLint Issue * Feat: added integration tests, container tag check and layer support (#2780) * Added integration tests * Added click requirement on -u presence for container based options * Added click class that checks -u presence for container based options * Reformatting and fixing test cases * Fix for integration test failures * Added support for layers * Resolve conflict * Refactoring file location * Addressing review comments, refactoring * Reformatting logging sentence * Refactoring container check for simplicity * Clarifying test case * Added unit tests on layer builds * Improving readability * Refactoring to simplify * Removing unnecessary lines * Refactoring integration test * Shortening error message * Adjusting test behaviour * Added new unit tests * Test refactoring * Added new test class * Removed unused import * Improving help text Co-authored-by: Qingchuan Ma <69653965+qingchm@users.noreply.github.com>
* feat(Public ECR): Changed Build Image Registry to Public ECR (aws#2708) * Changed Build Image Registry to Public ECR * Added _IMAGE_URI_PREFIX * Fixed Unit Tests * Updated Image Format * feat(Public ECR): Updated Test Image Name and Added Latest Tag Check (aws#2720) * Added Tests for Latest Tag * Added use_container Check for Verify Latest Tag Tests * Fixed DotNet and Go Build Tests * Added Missing use_container Check for test_build_function_and_layer * feat(Public ECR): Changed Build Image Registry to Public ECR (aws#2708) * Changed Build Image Registry to Public ECR * Added _IMAGE_URI_PREFIX * Fixed Unit Tests * Updated Image Format * feat(Public ECR): Updated Test Image Name and Added Latest Tag Check (aws#2720) * Added Tests for Latest Tag * Added use_container Check for Verify Latest Tag Tests * Fixed DotNet and Go Build Tests * Added Missing use_container Check for test_build_function_and_layer * feat(Public ECR): Added --build-image Options (aws#2725) * Added Latest Tag Check * Added --build-image Option * Added Unit Tests * Added Help Text and Fixed PyLint * Fixed Path Validation for Unit Tests * Updated Type Hintings * Added _parse_key_value_pair * Updated tag Handling for Image Pulls * Added Throwing Exception with Invalid Build Images * Fixed PyLint Issue * Feat: added integration tests, container tag check and layer support (aws#2780) * Added integration tests * Added click requirement on -u presence for container based options * Added click class that checks -u presence for container based options * Reformatting and fixing test cases * Fix for integration test failures * Added support for layers * Resolve conflict * Refactoring file location * Addressing review comments, refactoring * Reformatting logging sentence * Refactoring container check for simplicity * Clarifying test case * Added unit tests on layer builds * Improving readability * Refactoring to simplify * Removing unnecessary lines * Refactoring integration test * Shortening error message * Adjusting test behaviour * Added new unit tests * Test refactoring * Added new test class * Removed unused import * Improving help text Co-authored-by: Qingchuan Ma <69653965+qingchm@users.noreply.github.com>
Which issue(s) does this change fix?
N.A.
Why is this change necessary?
To add integration tests for new option --build-image
How does it address the issue?
N.A.
What side effects does this change have?
N.A.
Checklist
make prpassesmake update-reproducible-reqsif dependencies were changedBy submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.