Skip to content

Commit e48f728

Browse files
committed
Move sync command integration tests to a dedicated file
Previously, the tool's command line interface was only ever intended to provide the "sync" functionality so a single "all" integration test file was reasonable. Now that additional distinct command line functionality is planned, it will be better to separate the integration tests into multiple files to make it easier for the developer to navigate the code.
1 parent 70aa399 commit e48f728

File tree

10 files changed

+92
-70
lines changed

10 files changed

+92
-70
lines changed

.prettierignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# See: https://prettier.io/docs/en/ignore.html#ignoring-files-prettierignore
22

3-
/test/testdata/test_all/golden/logs/
3+
/test/testdata/test_sync/golden/logs/

test/conftest.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Source:
2+
# https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/test-integration/test_all.py
3+
# Copyright 2021 ARDUINO SA (http://www.arduino.cc/)
4+
#
5+
# This program is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU Affero General Public License as published
7+
# by the Free Software Foundation, either version 3 of the License, or
8+
# (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU Affero General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU Affero General Public License
16+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
#
18+
# You can be released from the requirements of the above licenses by purchasing
19+
# a commercial license. Buying such a license is mandatory if you want to
20+
# modify or otherwise use the software for commercial activities involving the
21+
# Arduino software without disclosing the source code of your own applications.
22+
# To purchase a commercial license, send an email to license@arduino.cc.
23+
#
24+
import pytest
25+
import pathlib
26+
import platform
27+
import typing
28+
import invoke.context
29+
import json
30+
31+
32+
@pytest.fixture(scope="function")
33+
def run_command(pytestconfig, working_dir) -> typing.Callable[..., invoke.runners.Result]:
34+
"""Provide a wrapper around invoke's `run` API so that every test will work in the same temporary folder.
35+
36+
Useful reference:
37+
http://docs.pyinvoke.org/en/1.4/api/runners.html#invoke.runners.Result
38+
"""
39+
40+
executable_path = pathlib.Path(pytestconfig.rootdir).parent / "libraries-repository-engine"
41+
42+
def _run(
43+
cmd: list,
44+
custom_working_dir: typing.Optional[str] = None,
45+
custom_env: typing.Optional[dict] = None,
46+
) -> invoke.runners.Result:
47+
if cmd is None:
48+
cmd = []
49+
if not custom_working_dir:
50+
custom_working_dir = working_dir
51+
quoted_cmd = []
52+
for token in cmd:
53+
quoted_cmd.append(f'"{token}"')
54+
cli_full_line = '"{}" {}'.format(executable_path, " ".join(quoted_cmd))
55+
run_context = invoke.context.Context()
56+
# It might happen that we need to change directories between drives on Windows,
57+
# in that case the "/d" flag must be used otherwise directory wouldn't change
58+
cd_command = "cd"
59+
if platform.system() == "Windows":
60+
cd_command += " /d"
61+
# Context.cd() is not used since it doesn't work correctly on Windows.
62+
# It escapes spaces in the path using "\ " but it doesn't always work,
63+
# wrapping the path in quotation marks is the safest approach
64+
with run_context.prefix(f'{cd_command} "{custom_working_dir}"'):
65+
return run_context.run(
66+
command=cli_full_line,
67+
echo=False,
68+
hide=True,
69+
warn=True,
70+
env=custom_env,
71+
encoding="utf-8",
72+
)
73+
74+
return _run
75+
76+
77+
@pytest.fixture(scope="function")
78+
def working_dir(tmpdir_factory) -> str:
79+
"""Create a temporary folder for the test to run in. It will be created before running each test and deleted at the
80+
end. This way all the tests work in isolation.
81+
"""
82+
work_dir = tmpdir_factory.mktemp(basename="TestWorkingDir")
83+
yield str(work_dir)

test/test_all.py renamed to test/test_sync.py

Lines changed: 8 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
# Source:
2-
# https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/test-integration/test_all.py
31
# Copyright 2021 ARDUINO SA (http://www.arduino.cc/)
42
#
53
# This program is free software: you can redistribute it and/or modify
@@ -27,18 +25,13 @@
2725
import hashlib
2826
import json
2927
import pathlib
30-
import platform
31-
import typing
3228
import math
3329

34-
import invoke.context
35-
import pytest
36-
3730
test_data_path = pathlib.Path(__file__).resolve().parent.joinpath("testdata")
3831
size_comparison_tolerance = 0.03 # Maximum allowed archive size difference ratio
3932

4033

41-
def test_all(run_command, working_dir):
34+
def test_sync(run_command, working_dir):
4235
working_dir_path = pathlib.Path(working_dir)
4336
configuration = {
4437
"BaseDownloadUrl": "http://www.example.com/libraries/",
@@ -62,7 +55,7 @@ def test_all(run_command, working_dir):
6255
"sync",
6356
"--config-file",
6457
working_dir_path.joinpath("config.json"),
65-
test_data_path.joinpath("test_all", "repos.txt"),
58+
test_data_path.joinpath("test_sync", "repos.txt"),
6659
]
6760

6861
# Run the engine
@@ -73,12 +66,12 @@ def test_all(run_command, working_dir):
7366
check_libraries(configuration=configuration)
7467
check_logs(
7568
configuration=configuration,
76-
golden_logs_parent_path=test_data_path.joinpath("test_all", "golden", "logs", "generate"),
69+
golden_logs_parent_path=test_data_path.joinpath("test_sync", "golden", "logs", "generate"),
7770
logs_subpath=pathlib.Path("github.com", "arduino-libraries", "ArduinoCloudThing", "index.html"),
7871
)
7972
check_logs(
8073
configuration=configuration,
81-
golden_logs_parent_path=test_data_path.joinpath("test_all", "golden", "logs", "generate"),
74+
golden_logs_parent_path=test_data_path.joinpath("test_sync", "golden", "logs", "generate"),
8275
logs_subpath=pathlib.Path("github.com", "arduino-libraries", "SpacebrewYun", "index.html"),
8376
)
8477
check_db(configuration=configuration)
@@ -92,12 +85,12 @@ def test_all(run_command, working_dir):
9285
check_libraries(configuration=configuration)
9386
check_logs(
9487
configuration=configuration,
95-
golden_logs_parent_path=test_data_path.joinpath("test_all", "golden", "logs", "update"),
88+
golden_logs_parent_path=test_data_path.joinpath("test_sync", "golden", "logs", "update"),
9689
logs_subpath=pathlib.Path("github.com", "arduino-libraries", "ArduinoCloudThing", "index.html"),
9790
)
9891
check_logs(
9992
configuration=configuration,
100-
golden_logs_parent_path=test_data_path.joinpath("test_all", "golden", "logs", "update"),
93+
golden_logs_parent_path=test_data_path.joinpath("test_sync", "golden", "logs", "update"),
10194
logs_subpath=pathlib.Path("github.com", "arduino-libraries", "SpacebrewYun", "index.html"),
10295
)
10396
check_db(configuration=configuration)
@@ -190,7 +183,7 @@ def check_db(configuration):
190183
release["Log"] = "\n".join([line.rstrip() for line in release["Log"].splitlines()])
191184

192185
# Load golden db
193-
golden_db_template = test_data_path.joinpath("test_all", "golden", "db.json").read_text(encoding="utf-8")
186+
golden_db_template = test_data_path.joinpath("test_sync", "golden", "db.json").read_text(encoding="utf-8")
194187
# Fill in mutable content
195188
golden_db_string = string.Template(template=golden_db_template).substitute(
196189
base_download_url=configuration["BaseDownloadUrl"],
@@ -248,7 +241,7 @@ def check_index(configuration):
248241
release["checksum"] = checksum_placeholder
249242

250243
# Load golden index
251-
golden_library_index_template = test_data_path.joinpath("test_all", "golden", "library_index.json").read_text(
244+
golden_library_index_template = test_data_path.joinpath("test_sync", "golden", "library_index.json").read_text(
252245
encoding="utf-8"
253246
)
254247
# Fill in mutable content
@@ -319,57 +312,3 @@ def test_clean_checkout(run_command, working_dir):
319312
for release in library_index["libraries"]:
320313
# ssd1306@1.0.0 contains a .exe and so should fail validation.
321314
assert not (release["name"] == "ssd1306" and release["version"] == "1.0.0")
322-
323-
324-
@pytest.fixture(scope="function")
325-
def run_command(pytestconfig, working_dir) -> typing.Callable[..., invoke.runners.Result]:
326-
"""Provide a wrapper around invoke's `run` API so that every test will work in the same temporary folder.
327-
328-
Useful reference:
329-
http://docs.pyinvoke.org/en/1.4/api/runners.html#invoke.runners.Result
330-
"""
331-
332-
executable_path = pathlib.Path(pytestconfig.rootdir).parent / "libraries-repository-engine"
333-
334-
def _run(
335-
cmd: list,
336-
custom_working_dir: typing.Optional[str] = None,
337-
custom_env: typing.Optional[dict] = None,
338-
) -> invoke.runners.Result:
339-
if cmd is None:
340-
cmd = []
341-
if not custom_working_dir:
342-
custom_working_dir = working_dir
343-
quoted_cmd = []
344-
for token in cmd:
345-
quoted_cmd.append(f'"{token}"')
346-
cli_full_line = '"{}" {}'.format(executable_path, " ".join(quoted_cmd))
347-
run_context = invoke.context.Context()
348-
# It might happen that we need to change directories between drives on Windows,
349-
# in that case the "/d" flag must be used otherwise directory wouldn't change
350-
cd_command = "cd"
351-
if platform.system() == "Windows":
352-
cd_command += " /d"
353-
# Context.cd() is not used since it doesn't work correctly on Windows.
354-
# It escapes spaces in the path using "\ " but it doesn't always work,
355-
# wrapping the path in quotation marks is the safest approach
356-
with run_context.prefix(f'{cd_command} "{custom_working_dir}"'):
357-
return run_context.run(
358-
command=cli_full_line,
359-
echo=False,
360-
hide=True,
361-
warn=True,
362-
env=custom_env,
363-
encoding="utf-8",
364-
)
365-
366-
return _run
367-
368-
369-
@pytest.fixture(scope="function")
370-
def working_dir(tmpdir_factory) -> str:
371-
"""Create a temporary folder for the test to run in. It will be created before running each test and deleted at the
372-
end. This way all the tests work in isolation.
373-
"""
374-
work_dir = tmpdir_factory.mktemp(basename="TestWorkingDir")
375-
yield str(work_dir)
File renamed without changes.

0 commit comments

Comments
 (0)