Skip to content

Commit 37a7bd1

Browse files
committed
tests: add unit, functional and integration tests
Why is this change necessary? * Tests to ensure that the makefile based approach for provided runtimes works.
1 parent da5ec4b commit 37a7bd1

File tree

16 files changed

+327
-66
lines changed

16 files changed

+327
-66
lines changed

.appveyor.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ for:
7070
# setup Gradle
7171
- "choco install gradle"
7272

73+
# setup make
74+
- "choco install make"
75+
7376
# Echo final Path
7477
- "echo %PATH%"
7578

aws_lambda_builders/workflows/provided_make/actions.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,15 @@ def execute(self):
5252
:raises lambda_builders.actions.ActionFailedError: when Make Build fails.
5353
"""
5454

55-
# Create the Artifacts Directory if it doesnt exist.
55+
# Create the Artifacts Directory if it doesnt exist.
5656
if not self.osutils.exists(self.artifacts_dir):
5757
self.osutils.makedirs(self.artifacts_dir)
5858

5959
try:
60-
self.subprocess_make.run([f"build-{self.build_logical_id}"], env={"ARTIFACTS_DIR": self.artifacts_dir}, cwd=self.scratch_dir)
60+
self.subprocess_make.run(
61+
["build-{logical_id}".format(logical_id=self.build_logical_id)],
62+
env={"ARTIFACTS_DIR": self.artifacts_dir},
63+
cwd=self.scratch_dir,
64+
)
6165
except MakeExecutionError as ex:
6266
raise ActionFailedError(str(ex))

aws_lambda_builders/workflows/provided_make/make.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __init__(self, osutils, make_exe=None):
4646

4747
self.make_exe = make_exe
4848

49-
def run(self, args, env, cwd=None):
49+
def run(self, args, env=None, cwd=None):
5050

5151
"""
5252
Runs the action.
@@ -55,7 +55,7 @@ def run(self, args, env, cwd=None):
5555
:param args: Command line arguments to pass to Make
5656
5757
:type args: dict
58-
:param env : Environment variables dictionary to be passed into subprocess
58+
:param env : environment variables dictionary to be passed into subprocess
5959
6060
:type cwd: str
6161
:param cwd: Directory where to execute the command (defaults to current dir)
@@ -80,7 +80,9 @@ def run(self, args, env, cwd=None):
8080

8181
LOG.debug("executing Make: %s", invoke_make)
8282

83-
p = self.osutils.popen(invoke_make, stdout=self.osutils.pipe, stderr=self.osutils.pipe, cwd=cwd, env=env)
83+
p = self.osutils.popen(
84+
invoke_make, stdout=self.osutils.pipe, stderr=self.osutils.pipe, cwd=cwd, env=env if env else {}
85+
)
8486

8587
out, err = p.communicate()
8688

aws_lambda_builders/workflows/provided_make/make_resolver.py

Lines changed: 0 additions & 22 deletions
This file was deleted.

aws_lambda_builders/workflows/provided_make/utils.py

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@
44

55
import os
66
import platform
7-
import tarfile
87
import subprocess
9-
import shutil
10-
11-
from aws_lambda_builders.utils import which
128

139

1410
class OSUtils(object):
@@ -18,21 +14,8 @@ class OSUtils(object):
1814
unit test actions in memory
1915
"""
2016

21-
def copy_file(self, file_path, destination_path):
22-
return shutil.copy2(file_path, destination_path)
23-
24-
def extract_tarfile(self, tarfile_path, unpack_dir):
25-
with tarfile.open(tarfile_path, "r:*") as tar:
26-
tar.extractall(unpack_dir)
27-
28-
def file_exists(self, filename):
29-
return os.path.isfile(filename)
30-
31-
def joinpath(self, *args):
32-
return os.path.join(*args)
33-
34-
def exists(self, path):
35-
return os.path.exists(path)
17+
def exists(self, p):
18+
return os.path.exists(p)
3619

3720
def makedirs(self, path):
3821
return os.makedirs(path)
@@ -45,17 +28,5 @@ def popen(self, command, stdout=None, stderr=None, env=None, cwd=None):
4528
def pipe(self):
4629
return subprocess.PIPE
4730

48-
def dirname(self, path):
49-
return os.path.dirname(path)
50-
51-
def remove_file(self, filename):
52-
return os.remove(filename)
53-
54-
def abspath(self, path):
55-
return os.path.abspath(path)
56-
5731
def is_windows(self):
5832
return platform.system().lower() == "windows"
59-
60-
def which(self, executable, executable_search_paths=None):
61-
return which(executable, executable_search_paths=executable_search_paths)

aws_lambda_builders/workflows/provided_make/workflow.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
"""
44
from aws_lambda_builders.workflow import BaseWorkflow, Capability
55
from aws_lambda_builders.actions import CopySourceAction
6+
from aws_lambda_builders.path_resolver import PathResolver
67
from .actions import ProvidedMakeAction
7-
from .make_resolver import MakeResolver
88
from .utils import OSUtils
99
from .make import SubProcessMake
1010

@@ -32,17 +32,18 @@ def __init__(self, source_dir, artifacts_dir, scratch_dir, manifest_path, runtim
3232
options = kwargs.get("options") or {}
3333
build_logical_id = options.get("build_logical_id", None)
3434

35-
subprocess_make = SubProcessMake(make_exe=self.binaries['make'].binary_path, osutils=self.os_utils)
35+
subprocess_make = SubProcessMake(make_exe=self.binaries["make"].binary_path, osutils=self.os_utils)
3636

3737
make_action = ProvidedMakeAction(
3838
artifacts_dir,
39-
scratch_dir, manifest_path, osutils=osutils, subprocess_make=subprocess_make, build_logical_id=build_logical_id
39+
scratch_dir,
40+
manifest_path,
41+
osutils=self.os_utils,
42+
subprocess_make=subprocess_make,
43+
build_logical_id=build_logical_id,
4044
)
4145

42-
self.actions = [
43-
CopySourceAction(source_dir, scratch_dir, excludes=self.EXCLUDED_FILES),
44-
make_action
45-
]
46+
self.actions = [CopySourceAction(source_dir, scratch_dir, excludes=self.EXCLUDED_FILES), make_action]
4647

4748
def get_resolvers(self):
48-
return [MakeResolver(executable_search_paths=self.executable_search_paths)]
49+
return [PathResolver(runtime="provided", binary="make", executable_search_paths=self.executable_search_paths)]

tests/functional/workflows/provided_make/__init__.py

Whitespace-only changes.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import os
2+
import sys
3+
4+
from unittest import TestCase
5+
6+
from aws_lambda_builders.workflows.provided_make import utils
7+
8+
9+
class TestOSUtils(TestCase):
10+
def setUp(self):
11+
12+
self.osutils = utils.OSUtils()
13+
14+
def test_popen_runs_a_process_and_returns_outcome(self):
15+
16+
cwd_py = os.path.join(os.path.dirname(__file__), "..", "..", "testdata", "cwd.py")
17+
18+
p = self.osutils.popen([sys.executable, cwd_py], stdout=self.osutils.pipe, stderr=self.osutils.pipe)
19+
20+
out, err = p.communicate()
21+
22+
self.assertEqual(p.returncode, 0)
23+
24+
self.assertEqual(out.decode("utf8").strip(), os.getcwd())
25+
26+
def test_popen_can_accept_cwd_and_env(self):
27+
28+
testdata_dir = os.path.join(os.path.dirname(__file__), "..", "..", "testdata")
29+
30+
p = self.osutils.popen(
31+
[sys.executable, "cwd.py"],
32+
stdout=self.osutils.pipe,
33+
stderr=self.osutils.pipe,
34+
env=os.environ.copy().update({"SOME_ENV": "SOME_VALUE"}),
35+
cwd=testdata_dir,
36+
)
37+
38+
out, err = p.communicate()
39+
40+
self.assertEqual(p.returncode, 0)
41+
42+
self.assertEqual(out.decode("utf8").strip(), os.path.abspath(testdata_dir))
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import os
2+
import shutil
3+
import sys
4+
import tempfile
5+
from unittest import TestCase
6+
7+
from aws_lambda_builders.builder import LambdaBuilder
8+
from aws_lambda_builders.exceptions import WorkflowFailedError
9+
10+
11+
class TestProvidedMakeWorkflow(TestCase):
12+
"""
13+
Verifies that `provided_make` workflow works by building a Lambda that requires Numpy
14+
"""
15+
16+
TEST_DATA_FOLDER = os.path.join(os.path.dirname(__file__), "testdata", "makefile-present")
17+
18+
def setUp(self):
19+
self.source_dir = self.TEST_DATA_FOLDER
20+
self.artifacts_dir = tempfile.mkdtemp()
21+
self.scratch_dir = tempfile.mkdtemp()
22+
23+
self.manifest_path_valid = os.path.join(self.TEST_DATA_FOLDER, "Makefile")
24+
25+
self.test_data_files = {"__init__.py", "main.py", "requirements-requests.txt"}
26+
27+
self.builder = LambdaBuilder(language="provided", dependency_manager=None, application_framework=None)
28+
self.runtime = "provided"
29+
30+
def tearDown(self):
31+
shutil.rmtree(self.artifacts_dir)
32+
shutil.rmtree(self.scratch_dir)
33+
34+
def test_must_build_python_project_through_makefile(self):
35+
self.builder.build(
36+
self.source_dir,
37+
self.artifacts_dir,
38+
self.scratch_dir,
39+
self.manifest_path_valid,
40+
runtime=self.runtime,
41+
options={"build_logical_id": "HelloWorldFunction"},
42+
)
43+
dependencies_installed = {
44+
"chardet",
45+
"urllib3",
46+
"idna",
47+
"urllib3-1.25.8.dist-info",
48+
"chardet-3.0.4.dist-info",
49+
"certifi-2020.4.5.1.dist-info",
50+
"certifi",
51+
"idna-2.9.dist-info",
52+
"requests",
53+
"requests-2.23.0.dist-info",
54+
}
55+
56+
expected_files = self.test_data_files.union(dependencies_installed)
57+
output_files = set(os.listdir(self.artifacts_dir))
58+
self.assertEquals(expected_files, output_files)
59+
60+
def test_must_build_python_project_through_makefile_unknown_target(self):
61+
with self.assertRaises(WorkflowFailedError):
62+
self.builder.build(
63+
self.source_dir,
64+
self.artifacts_dir,
65+
self.scratch_dir,
66+
self.manifest_path_valid,
67+
runtime=self.runtime,
68+
options={"build_logical_id": "HelloWorldFunction2"},
69+
)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
build-HelloWorldFunction:
2+
cp -r *.py $(ARTIFACTS_DIR)
3+
cp -r requirements-requests.txt $(ARTIFACTS_DIR)
4+
python -m pip install -r requirements-requests.txt -t $(ARTIFACTS_DIR)
5+
rm -rf $(ARTIFACTS_DIR)/bin

tests/integration/workflows/provided_make/testdata/makefile-present/__init__.py

Whitespace-only changes.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import requests
2+
3+
4+
def lambda_handler(event, context):
5+
# Just return the requests version.
6+
return "{}".format(requests.__version__)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
requests==2.23.0
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from unittest import TestCase
2+
from mock import patch
3+
4+
from aws_lambda_builders.actions import ActionFailedError
5+
from aws_lambda_builders.workflows.provided_make.actions import ProvidedMakeAction
6+
from aws_lambda_builders.workflows.provided_make.make import MakeExecutionError
7+
8+
9+
class TestProvidedMakeAction(TestCase):
10+
@patch("aws_lambda_builders.workflows.provided_make.utils.OSUtils")
11+
@patch("aws_lambda_builders.workflows.provided_make.make.SubProcessMake")
12+
def test_call_makefile_target(self, OSUtilMock, SubprocessMakeMock):
13+
osutils = OSUtilMock.return_value
14+
subprocess_make = SubprocessMakeMock.return_value
15+
16+
action = ProvidedMakeAction(
17+
"artifacts",
18+
"scratch_dir",
19+
"manifest",
20+
osutils=osutils,
21+
subprocess_make=subprocess_make,
22+
build_logical_id="logical_id",
23+
)
24+
25+
osutils.dirname.side_effect = lambda value: "/dir:{}".format(value)
26+
osutils.abspath.side_effect = lambda value: "/abs:{}".format(value)
27+
osutils.joinpath.side_effect = lambda a, b: "{}/{}".format(a, b)
28+
29+
action.execute()
30+
31+
subprocess_make.run.assert_called_with(
32+
["build-logical_id"], env={"ARTIFACTS_DIR": "artifacts"}, cwd="scratch_dir"
33+
)
34+
35+
@patch("aws_lambda_builders.workflows.provided_make.utils.OSUtils")
36+
@patch("aws_lambda_builders.workflows.provided_make.make.SubProcessMake")
37+
def test_makefile_target_fails(self, OSUtilMock, SubprocessMakeMock):
38+
osutils = OSUtilMock.return_value
39+
subprocess_make = SubprocessMakeMock.return_value
40+
41+
action = ProvidedMakeAction(
42+
"artifacts",
43+
"scratch_dir",
44+
"manifest",
45+
osutils=osutils,
46+
subprocess_make=subprocess_make,
47+
build_logical_id="logical_id",
48+
)
49+
50+
osutils.dirname.side_effect = lambda value: "/dir:{}".format(value)
51+
osutils.abspath.side_effect = lambda value: "/abs:{}".format(value)
52+
osutils.joinpath.side_effect = lambda a, b: "{}/{}".format(a, b)
53+
54+
subprocess_make.run.side_effect = [MakeExecutionError(message="failure")]
55+
56+
with self.assertRaises(ActionFailedError):
57+
action.execute()
58+
59+
subprocess_make.run.assert_called_with(
60+
["build-logical_id"], env={"ARTIFACTS_DIR": "artifacts"}, cwd="scratch_dir"
61+
)

0 commit comments

Comments
 (0)