Skip to content

Commit deda040

Browse files
committed
[skip changelog] Optimize a bit integration tests
1 parent 0bf48ae commit deda040

8 files changed

+157
-125
lines changed

test/conftest.py

+76-5
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,11 @@ def data_dir(tmpdir_factory):
5454
if platform.system() == "Windows":
5555
with tempfile.TemporaryDirectory() as tmp:
5656
yield tmp
57+
shutil.rmtree(tmp, ignore_errors=True)
5758
else:
58-
yield str(tmpdir_factory.mktemp("ArduinoTest"))
59+
data = tmpdir_factory.mktemp("ArduinoTest")
60+
yield str(data)
61+
shutil.rmtree(data, ignore_errors=True)
5962

6063

6164
@pytest.fixture(scope="session")
@@ -64,7 +67,9 @@ def downloads_dir(tmpdir_factory):
6467
To save time and bandwidth, all the tests will access
6568
the same download cache folder.
6669
"""
67-
return str(tmpdir_factory.mktemp("ArduinoTest"))
70+
download_dir = tmpdir_factory.mktemp("ArduinoTest")
71+
yield str(download_dir)
72+
shutil.rmtree(download_dir, ignore_errors=True)
6873

6974

7075
@pytest.fixture(scope="function")
@@ -74,7 +79,9 @@ def working_dir(tmpdir_factory):
7479
will be created before running each test and deleted
7580
at the end, this way all the tests work in isolation.
7681
"""
77-
return str(tmpdir_factory.mktemp("ArduinoTestWork"))
82+
work_dir = tmpdir_factory.mktemp("ArduinoTestWork")
83+
yield str(work_dir)
84+
shutil.rmtree(work_dir, ignore_errors=True)
7885

7986

8087
@pytest.fixture(scope="function")
@@ -95,9 +102,12 @@ def run_command(pytestconfig, data_dir, downloads_dir, working_dir):
95102
}
96103
(Path(data_dir) / "packages").mkdir()
97104

98-
def _run(cmd_string, custom_working_dir=None):
105+
def _run(cmd_string, custom_working_dir=None, custom_env=None):
106+
99107
if not custom_working_dir:
100108
custom_working_dir = working_dir
109+
if not custom_env:
110+
custom_env = env
101111
cli_full_line = '"{}" {}'.format(cli_path, cmd_string)
102112
run_context = Context()
103113
# It might happen that we need to change directories between drives on Windows,
@@ -109,7 +119,7 @@ def _run(cmd_string, custom_working_dir=None):
109119
# It escapes spaces in the path using "\ " but it doesn't always work,
110120
# wrapping the path in quotation marks is the safest approach
111121
with run_context.prefix(f'{cd_command} "{custom_working_dir}"'):
112-
return run_context.run(cli_full_line, echo=False, hide=True, warn=True, env=env)
122+
return run_context.run(cli_full_line, echo=False, hide=True, warn=True, env=custom_env)
113123

114124
return _run
115125

@@ -195,3 +205,64 @@ def copy_sketch(working_dir):
195205
test_sketch_path = Path(working_dir) / "sketch_simple"
196206
shutil.copytree(sketch_path, test_sketch_path)
197207
yield str(test_sketch_path)
208+
209+
210+
@pytest.fixture(scope="function")
211+
def core_update_index(run_command, data_dir, downloads_dir, working_dir, tmpdir_factory):
212+
"""
213+
To save time and bandwidth we install and cache cores indexes and copy them to each individual test environment
214+
"""
215+
216+
def _update_index():
217+
index_dir = tmpdir_factory.getbasetemp() / "core-indexes"
218+
if not index_dir.exists():
219+
index_dir.mkdir()
220+
env = {
221+
"ARDUINO_DATA_DIR": str(index_dir),
222+
"ARDUINO_DOWNLOADS_DIR": downloads_dir,
223+
}
224+
run_command("core update-index", working_dir, env)
225+
shutil.copytree(index_dir, data_dir, dirs_exist_ok=True)
226+
227+
return _update_index
228+
229+
230+
@pytest.fixture(scope="function")
231+
def lib_update_index(run_command, data_dir, downloads_dir, working_dir, tmpdir_factory):
232+
"""
233+
To save time and bandwidth we install and cache libraries indexes and copy them to each individual test environment
234+
"""
235+
236+
def _update_index():
237+
index_dir = tmpdir_factory.getbasetemp() / "lib-indexes"
238+
if not index_dir.exists():
239+
index_dir.mkdir()
240+
env = {
241+
"ARDUINO_DATA_DIR": str(index_dir),
242+
"ARDUINO_DOWNLOADS_DIR": downloads_dir,
243+
}
244+
run_command("lib update-index", working_dir, env)
245+
shutil.copyfile(index_dir / "library_index.json", Path(data_dir) / "library_index.json")
246+
247+
return _update_index
248+
249+
250+
@pytest.fixture(scope="function")
251+
def core_install(run_command, data_dir, downloads_dir, working_dir, tmpdir_factory):
252+
"""
253+
To save time and bandwidth we install and cache cores and copy them to each individual test environment
254+
"""
255+
data_dir = Path(data_dir) / "packages"
256+
257+
def _install(core):
258+
core_dir = tmpdir_factory.getbasetemp() / core.replace(":", "")
259+
if not core_dir.exists():
260+
core_dir.mkdir()
261+
env = {
262+
"ARDUINO_DATA_DIR": str(core_dir),
263+
"ARDUINO_DOWNLOADS_DIR": downloads_dir,
264+
}
265+
run_command(f"core install {core}", working_dir, env)
266+
shutil.copytree(core_dir / "packages", data_dir, dirs_exist_ok=True)
267+
268+
return _install

test/test_board.py

+19-30
Original file line numberDiff line numberDiff line change
@@ -389,9 +389,8 @@
389389
""" # noqa: E501
390390

391391

392-
def test_board_list(run_command):
393-
result = run_command("core update-index")
394-
assert result.ok
392+
def test_board_list(run_command, core_update_index):
393+
core_update_index()
395394
result = run_command("board list --format json")
396395
assert result.ok
397396
# check is a valid json and contains a list of ports
@@ -403,19 +402,17 @@ def test_board_list(run_command):
403402

404403

405404
@pytest.mark.skipif(running_on_ci(), reason="VMs have no serial ports")
406-
def test_board_listall(run_command):
407-
assert run_command("core update-index")
405+
def test_board_listall(run_command, core_update_index):
406+
core_update_index()
408407
result = run_command("board listall")
409408
assert result.ok
410409
assert ["Board", "Name", "FQBN"] == result.stdout.splitlines()[0].strip().split()
411410

412411

413-
def test_board_details(run_command):
414-
result = run_command("core update-index")
415-
assert result.ok
412+
def test_board_details(run_command, core_update_index, core_install):
413+
core_update_index()
416414
# Download samd core pinned to 1.8.6
417-
result = run_command("core install arduino:[email protected]")
418-
assert result.ok
415+
core_install("arduino:[email protected]")
419416

420417
# Test board listall with and without showing hidden elements
421418
result = run_command("board listall MIPS --format json")
@@ -447,12 +444,10 @@ def test_board_details(run_command):
447444

448445

449446
# old `arduino-cli board details` did not need -b <fqbn> flag to work
450-
def test_board_details_old(run_command):
451-
result = run_command("core update-index")
452-
assert result.ok
447+
def test_board_details_old(run_command, core_update_index, core_install):
448+
core_update_index()
453449
# Download samd core pinned to 1.8.6
454-
result = run_command("core install arduino:[email protected]")
455-
assert result.ok
450+
core_install("arduino:[email protected]")
456451
result = run_command("board details arduino:samd:nano_33_iot --format json")
457452
assert result.ok
458453
# Sort everything before compare
@@ -472,24 +467,20 @@ def test_board_details_old(run_command):
472467
assert programmer in result["programmers"]
473468

474469

475-
def test_board_details_no_flags(run_command):
476-
result = run_command("core update-index")
477-
assert result.ok
470+
def test_board_details_no_flags(run_command, core_update_index, core_install):
471+
core_update_index()
478472
# Download samd core pinned to 1.8.6
479-
result = run_command("core install arduino:[email protected]")
480-
assert result.ok
473+
core_install("arduino:[email protected]")
481474
result = run_command("board details")
482475
assert not result.ok
483476
assert "Error getting board details: parsing fqbn: invalid fqbn:" in result.stderr
484477
assert result.stdout == ""
485478

486479

487-
def test_board_details_list_programmers_without_flag(run_command):
488-
result = run_command("core update-index")
489-
assert result.ok
480+
def test_board_details_list_programmers_without_flag(run_command, core_update_index, core_install):
481+
core_update_index()
490482
# Download samd core pinned to 1.8.6
491-
result = run_command("core install arduino:[email protected]")
492-
assert result.ok
483+
core_install("arduino:[email protected]")
493484
result = run_command("board details -b arduino:samd:nano_33_iot")
494485
assert result.ok
495486
lines = [l.strip() for l in result.stdout.splitlines()]
@@ -502,12 +493,10 @@ def test_board_details_list_programmers_without_flag(run_command):
502493
assert "sam_ice Atmel SAM-ICE" in lines
503494

504495

505-
def test_board_details_list_programmers_flag(run_command):
506-
result = run_command("core update-index")
507-
assert result.ok
496+
def test_board_details_list_programmers_flag(run_command, core_update_index, core_install):
497+
core_update_index()
508498
# Download samd core pinned to 1.8.6
509-
result = run_command("core install arduino:[email protected]")
510-
assert result.ok
499+
core_install("arduino:[email protected]")
511500
result = run_command("board details -b arduino:samd:nano_33_iot --list-programmers")
512501
assert result.ok
513502

test/test_compile.py

+30-49
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,24 @@
2121
from .common import running_on_ci
2222

2323

24-
def test_compile_without_fqbn(run_command):
24+
def test_compile_without_fqbn(run_command, core_update_index, core_install):
2525
# Init the environment explicitly
26-
result = run_command("core update-index")
27-
assert result.ok
26+
core_update_index()
2827

2928
# Install Arduino AVR Boards
30-
result = run_command("core install arduino:[email protected]")
31-
assert result.ok
29+
core_install("arduino:[email protected]")
3230

3331
# Build sketch without FQBN
3432
result = run_command("compile")
3533
assert result.failed
3634

3735

38-
def test_compile_with_simple_sketch(run_command, data_dir, working_dir):
36+
def test_compile_with_simple_sketch(run_command, data_dir, working_dir, core_update_index, core_install):
3937
# Init the environment explicitly
40-
result = run_command("core update-index")
41-
assert result.ok
38+
core_update_index()
4239

4340
# Download latest AVR
44-
result = run_command("core install arduino:avr")
45-
assert result.ok
41+
core_install("arduino:avr")
4642

4743
sketch_name = "CompileIntegrationTest"
4844
sketch_path = os.path.join(data_dir, sketch_name)
@@ -65,12 +61,9 @@ def test_compile_with_simple_sketch(run_command, data_dir, working_dir):
6561

6662
# let's test from the logs if the hex file produced by successful compile is moved to our sketch folder
6763
log_json = open(log_file_path, "r")
68-
json_log_lines = log_json.readlines()
69-
expected_trace_sequence = [
70-
"Compile {sketch} for {fqbn} started".format(sketch=sketch_path, fqbn=fqbn),
71-
"Compile {sketch} for {fqbn} successful".format(sketch=sketch_name, fqbn=fqbn),
72-
]
73-
assert is_message_sequence_in_json_log_traces(expected_trace_sequence, json_log_lines)
64+
traces = parse_json_traces(log_json.readlines())
65+
assert f"Compile {sketch_path} for {fqbn} started" in traces
66+
assert f"Compile {sketch_name} for {fqbn} successful" in traces
7467

7568
# Test the --output-dir flag with absolute path
7669
target = os.path.join(data_dir, "test_dir")
@@ -87,14 +80,12 @@ def test_compile_with_simple_sketch(run_command, data_dir, working_dir):
8780
running_on_ci() and platform.system() == "Windows",
8881
reason="Test disabled on Github Actions Win VM until tmpdir inconsistent behavior bug is fixed",
8982
)
90-
def test_output_flag_default_path(run_command, data_dir, working_dir):
83+
def test_output_flag_default_path(run_command, data_dir, working_dir, core_update_index, core_install):
9184
# Init the environment explicitly
92-
result = run_command("core update-index")
93-
assert result.ok
85+
core_update_index()
9486

9587
# Install Arduino AVR Boards
96-
result = run_command("core install arduino:[email protected]")
97-
assert result.ok
88+
core_install("arduino:[email protected]")
9889

9990
# Create a test sketch
10091
sketch_path = os.path.join(data_dir, "test_output_flag_default_path")
@@ -109,14 +100,12 @@ def test_output_flag_default_path(run_command, data_dir, working_dir):
109100
assert os.path.exists(target) and os.path.isdir(target)
110101

111102

112-
def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir):
103+
def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir, core_update_index, core_install):
113104
# Init the environment explicitly
114-
result = run_command("core update-index")
115-
assert result.ok
105+
core_update_index()
116106

117107
# Install Arduino AVR Boards
118-
result = run_command("core install arduino:[email protected]")
119-
assert result.ok
108+
core_install("arduino:[email protected]")
120109

121110
sketch_name = "CompileIntegrationTestSymlinkSelfLoop"
122111
sketch_path = os.path.join(data_dir, sketch_name)
@@ -162,15 +151,13 @@ def test_compile_with_sketch_with_symlink_selfloop(run_command, data_dir):
162151

163152

164153
@pytest.mark.skipif(running_on_ci(), reason="VMs have no serial ports")
165-
def test_compile_and_upload_combo(run_command, data_dir, detected_boards):
154+
def test_compile_and_upload_combo(run_command, data_dir, detected_boards, core_update_index, core_install):
166155
# Init the environment explicitly
167-
result = run_command("core update-index")
168-
assert result.ok
156+
core_update_index()
169157

170158
# Install required core(s)
171-
result = run_command("core install arduino:[email protected]")
172-
result = run_command("core install arduino:[email protected]")
173-
assert result.ok
159+
core_install("arduino:[email protected]")
160+
core_install("arduino:[email protected]")
174161

175162
# Create a test sketch
176163
sketch_name = "CompileAndUploadIntegrationTest"
@@ -196,41 +183,35 @@ def run_test(s):
196183

197184
# check from the logs if the bin file were uploaded on the current board
198185
log_json = open(log_file_path, "r")
199-
json_log_lines = log_json.readlines()
200-
expected_trace_sequence = [
201-
"Compile {sketch} for {fqbn} started".format(sketch=sketch_path, fqbn=board.fqbn),
202-
"Compile {sketch} for {fqbn} successful".format(sketch=sketch_name, fqbn=board.fqbn),
203-
"Upload {sketch} on {fqbn} started".format(sketch=sketch_path, fqbn=board.fqbn),
204-
"Upload {sketch} on {fqbn} successful".format(sketch=sketch_name, fqbn=board.fqbn),
205-
]
206-
assert is_message_sequence_in_json_log_traces(expected_trace_sequence, json_log_lines)
186+
traces = parse_json_traces(log_json.readlines())
187+
assert f"Compile {sketch_path} for {board.fqbn} started" in traces
188+
assert f"Compile {sketch_name} for {board.fqbn} successful" in traces
189+
assert f"Upload {sketch_path} on {board.fqbn} started" in traces
190+
assert "Upload successful" in traces
207191

208192
run_test(sketch_path)
209193
run_test(sketch_main_file)
210194

211195

212-
def is_message_sequence_in_json_log_traces(message_sequence, log_json_lines):
196+
def parse_json_traces(log_json_lines):
213197
trace_entries = []
214198
for entry in log_json_lines:
215199
entry = json.loads(entry)
216200
if entry.get("level") == "trace":
217-
if entry.get("msg") in message_sequence:
218-
trace_entries.append(entry.get("msg"))
219-
return message_sequence == trace_entries
201+
trace_entries.append(entry.get("msg"))
202+
return trace_entries
220203

221204

222-
def test_compile_blacklisted_sketchname(run_command, data_dir):
205+
def test_compile_blacklisted_sketchname(run_command, data_dir, core_update_index, core_install):
223206
"""
224207
Compile should ignore folders named `RCS`, `.git` and the likes, but
225208
it should be ok for a sketch to be named like RCS.ino
226209
"""
227210
# Init the environment explicitly
228-
result = run_command("core update-index")
229-
assert result.ok
211+
core_update_index()
230212

231213
# Install Arduino AVR Boards
232-
result = run_command("core install arduino:[email protected]")
233-
assert result.ok
214+
core_install("arduino:[email protected]")
234215

235216
sketch_name = "RCS"
236217
sketch_path = os.path.join(data_dir, sketch_name)

test/test_lib.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import simplejson as json
1616

1717

18-
def test_list(run_command):
18+
def test_list(run_command, core_update_index):
1919
# Init the environment explicitly
20-
assert run_command("core update-index")
20+
core_update_index()
2121

2222
# When output is empty, nothing is printed out, no matter the output format
2323
result = run_command("lib list")

0 commit comments

Comments
 (0)