Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 5 additions & 48 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ environment:
# See: http://stackoverflow.com/a/13751649/163740
CMD_IN_ENV: 'cmd /E:ON /V:ON /C .\tests\scripts\appveyor\run_with_env.cmd'

PYTEST: py.test --maxfail 5 --durations=10 --junitxml=junit-results.xml
PYTEST: py.test -n3 --maxfail 5 --durations=10 --junitxml=junit-results.xml

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be very careful. When I last tested (#2024), xdist caused seemingly random test failures on windows. Unless these problems have been fixed, I wouldn't do this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that I had quashed all of the pytest errors but there is apparently one more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be sure we're on the same page, the root case I saw (some time ago) when playing with the -n3 option was that the xdist plugin didn't work reliably on Windows; it seemed to work quite well on Linux. I would, of course, be overjoyed if this works now, since Appveyor testing time is sooooo long.

# Break the tests into two runs, since together they exceed the 1 hour limit.
# See https://github.com/pyinstaller/pyinstaller/issues/2024#issuecomment-224129520
# for more discussion.
Expand All @@ -27,63 +27,26 @@ environment:
- PYTHON: C:\Python36-x64
PYTHON_VERSION: 3.6
PYTHON_ARCH: 64
TEST_LIBRARIES: NO

- PYTHON: C:\Python36-x64
PYTHON_VERSION: 3.6
PYTHON_ARCH: 64
TEST_LIBRARIES: YES

- PYTHON: C:\Python36
PYTHON_VERSION: 3.6
PYTHON_ARCH: 32
TEST_LIBRARIES: NO

- PYTHON: C:\Python36
PYTHON_VERSION: 3.6
PYTHON_ARCH: 32
TEST_LIBRARIES: YES

- PYTHON: C:\Python35
PYTHON_VERSION: 3.5
PYTHON_ARCH: 32
TEST_LIBRARIES: NO

- PYTHON: C:\Python35
PYTHON_VERSION: 3.5
PYTHON_ARCH: 32
TEST_LIBRARIES: YES

- PYTHON: C:\Python34
PYTHON_VERSION: 3.4
PYTHON_ARCH: 32
TEST_LIBRARIES: NO

- PYTHON: C:\Python34
PYTHON_VERSION: 3.4
PYTHON_ARCH: 32
TEST_LIBRARIES: YES

- PYTHON: C:\Python33
PYTHON_VERSION: 3.3
PYTHON_ARCH: 32
TEST_LIBRARIES: NO

- PYTHON: C:\Python33
PYTHON_VERSION: 3.3
PYTHON_ARCH: 32
TEST_LIBRARIES: YES

- PYTHON: C:\Python27
PYTHON_VERSION: 2.7
PYTHON_ARCH: 32
TEST_LIBRARIES: NO

- PYTHON: C:\Python27
PYTHON_VERSION: 2.7
PYTHON_ARCH: 32
TEST_LIBRARIES: YES


init:
- "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%"
Expand Down Expand Up @@ -136,11 +99,7 @@ install:

# Install the PyInstaller test dependencies.
- '%CMD_IN_ENV% pip install -U --timeout 5 --retries 2
-r tests/requirements-tools.txt'
- 'if "%TEST_LIBRARIES%" == "YES" (
%CMD_IN_ENV% pip install -U --timeout 5 --retries 2
-r tests/requirements-libraries.txt
)'
-r tests/requirements-libraries.txt -r tests/requirements-tools.txt'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Un-splitting the tests is a different change then "enable parallel testing" and should go into a separate commit. I suggest adding to the commit message something like "Now the test are running in parallel, the test-suite runs short/quick enough to not time-out. So we can unify the split test-runs." (If this is correct, of course, - which would be nice :-)

# Install PyInstaller into virtualenv.
- '%CMD_IN_ENV% pip install -e .'

Expand All @@ -150,11 +109,8 @@ test_script:
# Run the tests appropriate for this entry in the test matrix. Skip tests
# if we're just updating the cache.
- 'if not "%APPVEYOR_SCHEDULED_BUILD%" == "True" (
if /i "%TEST_LIBRARIES%" == "YES" (
%CMD_IN_ENV% %PYTEST% %TESTS_LIBRARIES%
) else (
%CMD_IN_ENV% %PYTEST% %TESTS_UNITTESTS%
))'
%CMD_IN_ENV% %PYTEST% 2> nul
)'

on_success:
# Remove old or huge cache files to hopefully not exceed the 1GB cache limit.
Expand All @@ -173,6 +129,7 @@ on_success:

on_finish:
- ps: |
python .\scripts\compact-junit.py junit-results.xml
(new-object net.webclient).UploadFile(
"https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)",
(Resolve-Path .\junit-results.xml)
Expand Down
17 changes: 17 additions & 0 deletions scripts/compact-junit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import sys

from junitparser import JUnitXml, Failure


def main():
junit_xml_file = sys.argv[1]
suite = JUnitXml.fromfile(junit_xml_file)
for case in suite:
if not isinstance(case.result, Failure):
case.system_out = ''
case.system_err = ''
suite.write()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious: This script is simply reading and writing back the data. How it is "compressing" then? maybe a short comment explaining this would be useful.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the data is loaded into memory as objects, not xml. Therefore, xml metadata is lost during the read, which reduces file size. The xml metadata has no influence on the test results displayed.



if __name__ == '__main__':
main()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is unrelated to "enable parallel testing". Please move this (and the related changes) into a separate commit.

66 changes: 50 additions & 16 deletions tests/functional/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import textwrap
import io
import shutil
import tempfile
import shutil

# Third-party imports
# -------------------
Expand All @@ -41,7 +43,7 @@
from PyInstaller import configure, config
from PyInstaller import __main__ as pyi_main
from PyInstaller.utils.cliutils import archive_viewer
from PyInstaller.compat import is_darwin, is_win, is_py2, safe_repr, \
from PyInstaller.compat import is_darwin, is_win, is_py2, is_py3, safe_repr, \
architecture
from PyInstaller.depend.analysis import initialize_modgraph
from PyInstaller.utils.win32 import winutils
Expand Down Expand Up @@ -343,27 +345,59 @@ def _run_executable(self, prog, args, run_from_path, runtime):
# Windows command prompt. Py.test is then able to collect stdout/sterr
# messages and display them if a test fails.

process = psutil.Popen(args, executable=exe_path, stdout=sys.stdout,
stderr=sys.stderr, env=prog_env, cwd=prog_cwd)
# 'psutil' allows to use timeout in waiting for a subprocess.
# If not timeout was specified then it is 'None' - no timeout, just waiting.
# Runtime is useful mostly for interactive tests.
try:
timeout = runtime if runtime else _EXE_TIMEOUT
retcode = process.wait(timeout=timeout)
except psutil.TimeoutExpired:
# Note that we cannot let Popen get ahold of sys.stderr/out because it
# will attempt to close the files with nonstandard (system-level)
# methods via fileno(). This causes problems on win32 from which pytest
# cannot correctly recover.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is the core issue? There's no need to patch xdist if Popen is made to use pipes instead of stdio?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct. Even passing in my own tempfiles did not fix the problem on py3 because they were closed early.


def timeout_process(process):
# Kill the subprocess and its child processes.
for p in process.children(recursive=True):
p.kill()

if runtime:
# When 'runtime' is set then expired timeout is a good sing
# that the executable was running successfully for a specified time.
# TODO Is there a better way return success than 'retcode = 0'?
retcode = 0
return 0
else:
# Exe is still running and it is not an interactive test. Fail the test.
retcode = 1
# Kill the subprocess and its child processes.
for p in process.children(recursive=True):
p.kill()
process.kill()
return 1

# 'psutil' allows to use timeout in waiting for a subprocess.
# If not timeout was specified then it is 'None' - no timeout, just waiting.
# Runtime is useful mostly for interactive tests.
timeout = runtime if runtime else _EXE_TIMEOUT
if is_py3:
process = subprocess.Popen(args, executable=exe_path, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, env=prog_env, cwd=prog_cwd)
try:
stdout, stderr = process.communicate(timeout=timeout)
retcode = process.returncode
except subprocess.TimeoutExpired:
retcode = timeout_process(psutil.Process(process.pid))
process.kill()
stdout, stderr = process.communicate()

sys.stdout.write(stdout)
sys.stderr.write(stderr)
else:
stderr = tempfile.TemporaryFile()
stdout = tempfile.TemporaryFile()
process = psutil.Popen(args, executable=exe_path, stdout=stdout,
stderr=stderr, env=prog_env, cwd=prog_cwd)

stderr.seek(0)
stdout.seek(0)

shutil.copyfileobj(stderr, sys.stderr)
shutil.copyfileobj(stdout, sys.stdout)

try:
retcode = process.wait(timeout=timeout)
except psutil.TimeoutExpired:
retcode = timeout_process(process)
process.kill()

return retcode

Expand Down
3 changes: 2 additions & 1 deletion tests/requirements-tools.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
git+https://github.com/pytest-dev/execnet.git

# For running tests
pytest >= 2.7.3 # Testing framework.
pytest >= 3.2.1 # Testing framework.
pytest-xdist # Plugin allowing running tests in parallel.
pytest-timeout # Plugin to abort hanging tests.
pytest-catchlog # Capture log output separately from stdout/stderr
pytest-drop-dup-tests # allows specifying order without duplicates

psutil # Better subprocess alternative with implemented timeout.
junitparser # For compacting junit results