diff options
author | Gregory P. Smith <greg@krypto.org> | 2019-09-10 16:14:11 (GMT) |
---|---|---|
committer | T. Wouters <thomas@python.org> | 2019-09-10 16:14:11 (GMT) |
commit | 3f4db4a0bab073b768fae958e93288bd5d24eadd (patch) | |
tree | bc1758c4cb751641531f1440e8ff6177cbd31754 /Lib | |
parent | afdeb189e97033b54cef44a7490d89d2013cb4e5 (diff) | |
download | cpython-3f4db4a0bab073b768fae958e93288bd5d24eadd.zip cpython-3f4db4a0bab073b768fae958e93288bd5d24eadd.tar.gz cpython-3f4db4a0bab073b768fae958e93288bd5d24eadd.tar.bz2 |
bpo-28494: Test existing zipfile working behavior. (GH-15853)
Add unittests for executables with a zipfile appended to test_zipfile, as zipfile.is_zipfile and zipfile.ZipFile work properly on these today.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/test/test_zipfile.py | 40 | ||||
-rw-r--r-- | Lib/test/ziptestdata/README.md | 35 | ||||
-rwxr-xr-x | Lib/test/ziptestdata/exe_with_z64 | bin | 0 -> 978 bytes | |||
-rwxr-xr-x | Lib/test/ziptestdata/exe_with_zip | bin | 0 -> 990 bytes | |||
-rwxr-xr-x | Lib/test/ziptestdata/header.sh | 24 | ||||
-rw-r--r-- | Lib/test/ziptestdata/testdata_module_inside_zip.py | 2 |
6 files changed, 101 insertions, 0 deletions
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index f9ee740..99d599e 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -5,6 +5,8 @@ import os import pathlib import posixpath import struct +import subprocess +import sys import time import unittest import zipfile @@ -2470,6 +2472,44 @@ def build_alpharep_fixture(): return zf +class TestExecutablePrependedZip(unittest.TestCase): + """Test our ability to open zip files with an executable prepended.""" + + def setUp(self): + self.exe_zip = findfile('exe_with_zip', subdir='ziptestdata') + self.exe_zip64 = findfile('exe_with_z64', subdir='ziptestdata') + + def _test_zip_works(self, name): + # bpo-28494 sanity check: ensure is_zipfile works on these. + self.assertTrue(zipfile.is_zipfile(name), + f'is_zipfile failed on {name}') + # Ensure we can operate on these via ZipFile. + with zipfile.ZipFile(name) as zipfp: + for n in zipfp.namelist(): + data = zipfp.read(n) + self.assertIn(b'FAVORITE_NUMBER', data) + + def test_read_zip_with_exe_prepended(self): + self._test_zip_works(self.exe_zip) + + def test_read_zip64_with_exe_prepended(self): + self._test_zip_works(self.exe_zip64) + + @unittest.skipUnless(sys.executable, 'sys.executable required.') + @unittest.skipUnless(os.access('/bin/bash', os.X_OK), + 'Test relies on #!/bin/bash working.') + def test_execute_zip2(self): + output = subprocess.check_output([self.exe_zip, sys.executable]) + self.assertIn(b'number in executable: 5', output) + + @unittest.skipUnless(sys.executable, 'sys.executable required.') + @unittest.skipUnless(os.access('/bin/bash', os.X_OK), + 'Test relies on #!/bin/bash working.') + def test_execute_zip64(self): + output = subprocess.check_output([self.exe_zip64, sys.executable]) + self.assertIn(b'number in executable: 5', output) + + class TestPath(unittest.TestCase): def setUp(self): self.fixtures = contextlib.ExitStack() diff --git a/Lib/test/ziptestdata/README.md b/Lib/test/ziptestdata/README.md new file mode 100644 index 0000000..6b9147d --- /dev/null +++ b/Lib/test/ziptestdata/README.md @@ -0,0 +1,35 @@ +# Test data for `test_zipfile` + +The test executables in this directory are created manually from header.sh and +the `testdata_module_inside_zip.py` file. You must have infozip's zip utility +installed (`apt install zip` on Debian). + +## Purpose + +These are used to test executable files with an appended zipfile, in a scenario +where the executable is _not_ a Python interpreter itself so our automatic +zipimport machinery (that'd look for `__main__.py`) is not being used. + +## Updating the test executables + +If you update header.sh or the testdata_module_inside_zip.py file, rerun the +commands below. These are expected to be rarely changed, if ever. + +### Standard old format (2.0) zip file + +``` +zip -0 zip2.zip testdata_module_inside_zip.py +cat header.sh zip2.zip >exe_with_zip +rm zip2.zip +``` + +### Modern format (4.5) zip64 file + +Redirecting from stdin forces infozip's zip tool to create a zip64. + +``` +zip -0 <testdata_module_inside_zip.py >zip64.zip +cat header.sh zip64.zip >exe_with_z64 +rm zip64.zip +``` + diff --git a/Lib/test/ziptestdata/exe_with_z64 b/Lib/test/ziptestdata/exe_with_z64 Binary files differnew file mode 100755 index 0000000..82b03cf --- /dev/null +++ b/Lib/test/ziptestdata/exe_with_z64 diff --git a/Lib/test/ziptestdata/exe_with_zip b/Lib/test/ziptestdata/exe_with_zip Binary files differnew file mode 100755 index 0000000..c833cdf --- /dev/null +++ b/Lib/test/ziptestdata/exe_with_zip diff --git a/Lib/test/ziptestdata/header.sh b/Lib/test/ziptestdata/header.sh new file mode 100755 index 0000000..52dc91a --- /dev/null +++ b/Lib/test/ziptestdata/header.sh @@ -0,0 +1,24 @@ +#!/bin/bash +INTERPRETER_UNDER_TEST="$1" +if [[ ! -x "${INTERPRETER_UNDER_TEST}" ]]; then + echo "Interpreter must be the command line argument." + exit 4 +fi +EXECUTABLE="$0" exec "${INTERPRETER_UNDER_TEST}" -E - <<END_OF_PYTHON +import os +import zipfile + +namespace = {} + +filename = os.environ['EXECUTABLE'] +print(f'Opening {filename} as a zipfile.') +with zipfile.ZipFile(filename, mode='r') as exe_zip: + for file_info in exe_zip.infolist(): + data = exe_zip.read(file_info) + exec(data, namespace, namespace) + break # Only use the first file in the archive. + +print('Favorite number in executable:', namespace["FAVORITE_NUMBER"]) + +### Archive contents will be appended after this file. ### +END_OF_PYTHON diff --git a/Lib/test/ziptestdata/testdata_module_inside_zip.py b/Lib/test/ziptestdata/testdata_module_inside_zip.py new file mode 100644 index 0000000..6f8dcd6 --- /dev/null +++ b/Lib/test/ziptestdata/testdata_module_inside_zip.py @@ -0,0 +1,2 @@ +# Test data file to be stored within a zip file. +FAVORITE_NUMBER = 5 |