From 3f4db4a0bab073b768fae958e93288bd5d24eadd Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Tue, 10 Sep 2019 17:14:11 +0100 Subject: [PATCH] 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. --- Lib/test/test_zipfile.py | 40 ++++++++++++++++++ Lib/test/ziptestdata/README.md | 35 +++++++++++++++ Lib/test/ziptestdata/exe_with_z64 | Bin 0 -> 978 bytes Lib/test/ziptestdata/exe_with_zip | Bin 0 -> 990 bytes Lib/test/ziptestdata/header.sh | 24 +++++++++++ .../ziptestdata/testdata_module_inside_zip.py | 2 + 6 files changed, 101 insertions(+) create mode 100644 Lib/test/ziptestdata/README.md create mode 100755 Lib/test/ziptestdata/exe_with_z64 create mode 100755 Lib/test/ziptestdata/exe_with_zip create mode 100755 Lib/test/ziptestdata/header.sh create mode 100644 Lib/test/ziptestdata/testdata_module_inside_zip.py diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index f9ee740eb6f..99d599eac79 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 00000000000..6b9147db76e --- /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 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 new file mode 100755 index 0000000000000000000000000000000000000000..82b03cf39d919d9de05866b4f7cdf1dfe47e6eb3 GIT binary patch literal 978 zcmaJ<-EY${5KkEl$xl4ME4rnV(xNp330}q~w6RoFg|_N41e7XrQ)jhEoXByzLbV6} z7bN~nxXZ`b5aOcPclPh+`)uy)&!pO)@qEF01K%5u#vZQ0`QQ{+-#hbQJlMzfN zumhbn*t?s5Bd=_jPG5pq2*m(Jgo_mHo-#sbTHp%FGB+?21c5M360YVDOC^Boi)A8| zaqW`1mIj`)NHXt(_xjvFK6&e598YZ!YZ3l8f{q6rI6U+Qr@^orj6V8rh65&(EY$|m zyw<+SERwNcOz}kI84m>G zSHN@NP(AKCZFVWm;@bWsvo1d0s^NQ(q;qlPXs1m?Of5j_0ahSNH4rM0DoR1B`pzXg zmbq!Q2?j9dhGVD|)zyN}i{}esyQ-xKTZG$#>tt`JC1{4sF91y#s`x7`^Rh*e)YvZy zgkqqkaUCw?O1P{lg45-zR7)d3Et45`xQsPi8a|7~fpf#r#O@xyAC7yz7Yxqdop@t= z+GecTY{GH*C{6^9iZVG|$~dMm;TcwVF6O`^njW)|c@d2ZNMpBKJnC=V?N}s_K0g`u zf>&q1Drr~`txm&wV0p#0b-g#i7nomB!y-wOlGog%8hujhFq@*CrC0V>0$BJLY}9Yu zdAxPoGdZHaQ8}dT$9GygqyF~x9%(2wjr1B?@B4I!vMx6ZdG|^ES=ode_3v$y*}#wR GCH6PMMGy`E literal 0 HcmV?d00001 diff --git a/Lib/test/ziptestdata/exe_with_zip b/Lib/test/ziptestdata/exe_with_zip new file mode 100755 index 0000000000000000000000000000000000000000..c833cdf9f934b08fc449da077efae44aa9a06f18 GIT binary patch literal 990 zcmah{&2G~`5Ozt6#BxUB0BGt|a)MeHBzh^WP)i*V6_O}*5D+43W3QVP_S)KAHz`pi zcm>WJc^aOC$6(e@N~!o+%den-3;)Sr%Y!Z0+w(d{LAMq3-uf@P z9m3N*lNvI$JbmPO%o9e4pea*14H@ji{DR<>2{Yf&&6LZ;8JC$DI=^T*Ba%xlbR%}U zITKu*!h8w30IGn(BDw1{$&~BKrT>oSEll57hHpZeMQq=ZPSXIfv;d*Is6d=aFi`;) zaRyv0|GCCbxYCWL2?L0zrbu-GbtR)wnZ5)z7h1BgVd6I7ve+xfDrk(z4*+%OisT#$ zRkbMQ68mL{7!IasRE86N#$2)x!D-R6OmfXY6zLc{TyYHxO~(n_b*@}Av|9(SyZyHB z1)agGL$7a-nuOHrbvUS!;zZ!62(4hslf;Y(%~9cqML=USJ$k}b$;JhQk>6X~JFcw~ z%d9)^A9mZpvl9=`=Dly-vourMXb_;{MX9UeQ7N~ZpAY<7R_*(II{NZyIx1$jt(Dau zHOneZ9ejjVI+sG|%rH|rlgP`o7b`AXUNIxrip1vZklyjijR&>AvAb(Xm+RYSv;Bwb WTE+Dm&))IcO#@!RC&c}$ajc&zD=F;& literal 0 HcmV?d00001 diff --git a/Lib/test/ziptestdata/header.sh b/Lib/test/ziptestdata/header.sh new file mode 100755 index 00000000000..52dc91acf74 --- /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 - <