1
1
from __future__ import absolute_import , unicode_literals
2
2
3
+ import json
4
+ import os
5
+ import subprocess
3
6
import sys
7
+ import threading
4
8
5
9
import pytest
6
10
from flaky import flaky
7
11
12
+ from tox ._pytestplugin import RunResult
13
+
8
14
9
15
def test_parallel (cmd , initproj ):
10
16
initproj (
@@ -26,7 +32,7 @@ def test_parallel(cmd, initproj):
26
32
""" ,
27
33
},
28
34
)
29
- result = cmd ("--parallel " , "all" )
35
+ result = cmd ("-p " , "all" )
30
36
result .assert_success ()
31
37
32
38
@@ -49,7 +55,7 @@ def test_parallel_live(cmd, initproj):
49
55
""" ,
50
56
},
51
57
)
52
- result = cmd ("--parallel " , "all" , "--parallel-live " )
58
+ result = cmd ("-p " , "all" , "-o " )
53
59
result .assert_success ()
54
60
55
61
@@ -73,7 +79,7 @@ def test_parallel_circular(cmd, initproj):
73
79
""" ,
74
80
},
75
81
)
76
- result = cmd ("--parallel " , "1" )
82
+ result = cmd ("-p " , "1" )
77
83
result .assert_fail ()
78
84
assert result .out == "ERROR: circular dependency detected: a | b\n "
79
85
@@ -191,26 +197,96 @@ def test_parallel_show_output(cmd, initproj, monkeypatch):
191
197
assert "stderr always" in result .out , result .output ()
192
198
193
199
194
- def test_parallel_no_spinner ( cmd , initproj , monkeypatch ):
195
- monkeypatch . setenv ( str ( "TOX_PARALLEL_NO_SPINNER" ), str ( "1" ))
196
- initproj (
200
+ @ pytest . fixture ()
201
+ def parallel_project ( initproj ):
202
+ return initproj (
197
203
"pkg123-0.7" ,
198
204
filedefs = {
199
205
"tox.ini" : """
200
206
[tox]
207
+ skipsdist = True
201
208
envlist = a, b
202
- isolated_build = true
203
209
[testenv]
210
+ skip_install = True
204
211
commands=python -c "import sys; print(sys.executable)"
205
- [testenv:b]
206
- depends = a
207
- """ ,
208
- "pyproject.toml" : """
209
- [build-system]
210
- requires = ["setuptools >= 35.0.2"]
211
- build-backend = 'setuptools.build_meta'
212
- """ ,
212
+ """
213
213
},
214
214
)
215
- result = cmd ("--parallel" , "all" )
215
+
216
+
217
+ def test_parallel_no_spinner_on (cmd , parallel_project , monkeypatch ):
218
+ monkeypatch .setenv (str ("TOX_PARALLEL_NO_SPINNER" ), str ("1" ))
219
+ result = cmd ("-p" , "all" )
220
+ result .assert_success ()
221
+ assert "[2] a | b" not in result .out
222
+
223
+
224
+ def test_parallel_no_spinner_off (cmd , parallel_project , monkeypatch ):
225
+ monkeypatch .setenv (str ("TOX_PARALLEL_NO_SPINNER" ), str ("0" ))
226
+ result = cmd ("-p" , "all" )
216
227
result .assert_success ()
228
+ assert "[2] a | b" in result .out
229
+
230
+
231
+ def test_parallel_no_spinner_not_set (cmd , parallel_project , monkeypatch ):
232
+ monkeypatch .delenv (str ("TOX_PARALLEL_NO_SPINNER" ), raising = False )
233
+ result = cmd ("-p" , "all" )
234
+ result .assert_success ()
235
+ assert "[2] a | b" in result .out
236
+
237
+
238
+ def test_parallel_result_json (cmd , parallel_project , tmp_path ):
239
+ parallel_result_json = tmp_path / "parallel.json"
240
+ result = cmd ("-p" , "all" , "--result-json" , "{}" .format (parallel_result_json ))
241
+ ensure_result_json_ok (result , parallel_result_json )
242
+
243
+
244
+ def ensure_result_json_ok (result , json_path ):
245
+ if isinstance (result , RunResult ):
246
+ result .assert_success ()
247
+ else :
248
+ assert not isinstance (result , subprocess .CalledProcessError )
249
+ assert json_path .exists ()
250
+ serial_data = json .loads (json_path .read_text ())
251
+ ensure_key_in_env (serial_data )
252
+
253
+
254
+ def ensure_key_in_env (serial_data ):
255
+ for env in ("a" , "b" ):
256
+ for key in ("setup" , "test" ):
257
+ assert key in serial_data ["testenvs" ][env ], json .dumps (
258
+ serial_data ["testenvs" ], indent = 2
259
+ )
260
+
261
+
262
+ def test_parallel_result_json_concurrent (cmd , parallel_project , tmp_path ):
263
+ # first run to set up the environments (env creation is not thread safe)
264
+ result = cmd ("-p" , "all" )
265
+ result .assert_success ()
266
+
267
+ invoke_result = {}
268
+
269
+ def invoke_tox_in_thread (thread_name , result_json ):
270
+ try :
271
+ # needs to be process to have it's own stdout
272
+ invoke_result [thread_name ] = subprocess .check_output (
273
+ [sys .executable , "-m" , "tox" , "-p" , "all" , "--result-json" , str (result_json )],
274
+ universal_newlines = True ,
275
+ )
276
+ except subprocess .CalledProcessError as exception :
277
+ invoke_result [thread_name ] = exception
278
+
279
+ # now concurrently
280
+ parallel1_result_json = tmp_path / "parallel1.json"
281
+ parallel2_result_json = tmp_path / "parallel2.json"
282
+ threads = [
283
+ threading .Thread (target = invoke_tox_in_thread , args = (k , p ))
284
+ for k , p in (("t1" , parallel1_result_json ), ("t2" , parallel2_result_json ))
285
+ ]
286
+ [t .start () for t in threads ]
287
+ [t .join () for t in threads ]
288
+
289
+ ensure_result_json_ok (invoke_result ["t1" ], parallel1_result_json )
290
+ ensure_result_json_ok (invoke_result ["t2" ], parallel2_result_json )
291
+ # our set_os_env_var is not thread-safe so clean-up TOX_WORK_DIR
292
+ os .environ .pop ("TOX_WORK_DIR" , None )
0 commit comments