xref: /aosp_15_r20/external/bazelbuild-rules_python/examples/wheel/wheel_test.py (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1*60517a1eSAndroid Build Coastguard Worker# Copyright 2018 The Bazel Authors. All rights reserved.
2*60517a1eSAndroid Build Coastguard Worker#
3*60517a1eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*60517a1eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*60517a1eSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*60517a1eSAndroid Build Coastguard Worker#
7*60517a1eSAndroid Build Coastguard Worker#    http://www.apache.org/licenses/LICENSE-2.0
8*60517a1eSAndroid Build Coastguard Worker#
9*60517a1eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*60517a1eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*60517a1eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*60517a1eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*60517a1eSAndroid Build Coastguard Worker# limitations under the License.
14*60517a1eSAndroid Build Coastguard Worker
15*60517a1eSAndroid Build Coastguard Workerimport hashlib
16*60517a1eSAndroid Build Coastguard Workerimport os
17*60517a1eSAndroid Build Coastguard Workerimport platform
18*60517a1eSAndroid Build Coastguard Workerimport stat
19*60517a1eSAndroid Build Coastguard Workerimport subprocess
20*60517a1eSAndroid Build Coastguard Workerimport unittest
21*60517a1eSAndroid Build Coastguard Workerimport zipfile
22*60517a1eSAndroid Build Coastguard Worker
23*60517a1eSAndroid Build Coastguard Workerfrom python.runfiles import runfiles
24*60517a1eSAndroid Build Coastguard Worker
25*60517a1eSAndroid Build Coastguard Worker
26*60517a1eSAndroid Build Coastguard Workerclass WheelTest(unittest.TestCase):
27*60517a1eSAndroid Build Coastguard Worker    maxDiff = None
28*60517a1eSAndroid Build Coastguard Worker
29*60517a1eSAndroid Build Coastguard Worker    def setUp(self):
30*60517a1eSAndroid Build Coastguard Worker        super().setUp()
31*60517a1eSAndroid Build Coastguard Worker        self.runfiles = runfiles.Create()
32*60517a1eSAndroid Build Coastguard Worker
33*60517a1eSAndroid Build Coastguard Worker    def _get_path(self, filename):
34*60517a1eSAndroid Build Coastguard Worker        runfiles_path = os.path.join("rules_python/examples/wheel", filename)
35*60517a1eSAndroid Build Coastguard Worker        path = self.runfiles.Rlocation(runfiles_path)
36*60517a1eSAndroid Build Coastguard Worker        # The runfiles API can return None if the path doesn't exist or
37*60517a1eSAndroid Build Coastguard Worker        # can't be resolved.
38*60517a1eSAndroid Build Coastguard Worker        if not path:
39*60517a1eSAndroid Build Coastguard Worker            raise AssertionError(f"Runfiles failed to resolve {runfiles_path}")
40*60517a1eSAndroid Build Coastguard Worker        elif not os.path.exists(path):
41*60517a1eSAndroid Build Coastguard Worker            # A non-None value doesn't mean the file actually exists, though
42*60517a1eSAndroid Build Coastguard Worker            raise AssertionError(
43*60517a1eSAndroid Build Coastguard Worker                f"Path {path} does not exist (from runfiles path {runfiles_path}"
44*60517a1eSAndroid Build Coastguard Worker            )
45*60517a1eSAndroid Build Coastguard Worker        else:
46*60517a1eSAndroid Build Coastguard Worker            return path
47*60517a1eSAndroid Build Coastguard Worker
48*60517a1eSAndroid Build Coastguard Worker    def assertFileSha256Equal(self, filename, want):
49*60517a1eSAndroid Build Coastguard Worker        hash = hashlib.sha256()
50*60517a1eSAndroid Build Coastguard Worker        with open(filename, "rb") as f:
51*60517a1eSAndroid Build Coastguard Worker            while True:
52*60517a1eSAndroid Build Coastguard Worker                buf = f.read(2**20)
53*60517a1eSAndroid Build Coastguard Worker                if not buf:
54*60517a1eSAndroid Build Coastguard Worker                    break
55*60517a1eSAndroid Build Coastguard Worker                hash.update(buf)
56*60517a1eSAndroid Build Coastguard Worker        self.assertEqual(want, hash.hexdigest())
57*60517a1eSAndroid Build Coastguard Worker
58*60517a1eSAndroid Build Coastguard Worker    def assertAllEntriesHasReproducibleMetadata(self, zf):
59*60517a1eSAndroid Build Coastguard Worker        for zinfo in zf.infolist():
60*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(zinfo.date_time, (1980, 1, 1, 0, 0, 0), msg=zinfo.filename)
61*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(zinfo.create_system, 3, msg=zinfo.filename)
62*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
63*60517a1eSAndroid Build Coastguard Worker                zinfo.external_attr,
64*60517a1eSAndroid Build Coastguard Worker                (stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO | stat.S_IFREG) << 16,
65*60517a1eSAndroid Build Coastguard Worker                msg=zinfo.filename,
66*60517a1eSAndroid Build Coastguard Worker            )
67*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
68*60517a1eSAndroid Build Coastguard Worker                zinfo.compress_type, zipfile.ZIP_DEFLATED, msg=zinfo.filename
69*60517a1eSAndroid Build Coastguard Worker            )
70*60517a1eSAndroid Build Coastguard Worker
71*60517a1eSAndroid Build Coastguard Worker    def test_py_library_wheel(self):
72*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path("example_minimal_library-0.0.1-py3-none-any.whl")
73*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
74*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
75*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
76*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
77*60517a1eSAndroid Build Coastguard Worker                [
78*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/module_with_data.py",
79*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/simple_module.py",
80*60517a1eSAndroid Build Coastguard Worker                    "example_minimal_library-0.0.1.dist-info/WHEEL",
81*60517a1eSAndroid Build Coastguard Worker                    "example_minimal_library-0.0.1.dist-info/METADATA",
82*60517a1eSAndroid Build Coastguard Worker                    "example_minimal_library-0.0.1.dist-info/RECORD",
83*60517a1eSAndroid Build Coastguard Worker                ],
84*60517a1eSAndroid Build Coastguard Worker            )
85*60517a1eSAndroid Build Coastguard Worker        self.assertFileSha256Equal(
86*60517a1eSAndroid Build Coastguard Worker            filename, "79a4e9c1838c0631d5d8fa49a26efd6e9a364f6b38d9597c0f6df112271a0e28"
87*60517a1eSAndroid Build Coastguard Worker        )
88*60517a1eSAndroid Build Coastguard Worker
89*60517a1eSAndroid Build Coastguard Worker    def test_py_package_wheel(self):
90*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
91*60517a1eSAndroid Build Coastguard Worker            "example_minimal_package-0.0.1-py3-none-any.whl",
92*60517a1eSAndroid Build Coastguard Worker        )
93*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
94*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
95*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
96*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
97*60517a1eSAndroid Build Coastguard Worker                [
98*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/data.txt",
99*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/module_with_data.py",
100*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/simple_module.py",
101*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/main.py",
102*60517a1eSAndroid Build Coastguard Worker                    "example_minimal_package-0.0.1.dist-info/WHEEL",
103*60517a1eSAndroid Build Coastguard Worker                    "example_minimal_package-0.0.1.dist-info/METADATA",
104*60517a1eSAndroid Build Coastguard Worker                    "example_minimal_package-0.0.1.dist-info/RECORD",
105*60517a1eSAndroid Build Coastguard Worker                ],
106*60517a1eSAndroid Build Coastguard Worker            )
107*60517a1eSAndroid Build Coastguard Worker        self.assertFileSha256Equal(
108*60517a1eSAndroid Build Coastguard Worker            filename, "b4815a1d3a17cc6a5ce717ed42b940fa7788cb5168f5c1de02f5f50abed7083e"
109*60517a1eSAndroid Build Coastguard Worker        )
110*60517a1eSAndroid Build Coastguard Worker
111*60517a1eSAndroid Build Coastguard Worker    def test_customized_wheel(self):
112*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
113*60517a1eSAndroid Build Coastguard Worker            "example_customized-0.0.1-py3-none-any.whl",
114*60517a1eSAndroid Build Coastguard Worker        )
115*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
116*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
117*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
118*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
119*60517a1eSAndroid Build Coastguard Worker                [
120*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/data.txt",
121*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/module_with_data.py",
122*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/simple_module.py",
123*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/main.py",
124*60517a1eSAndroid Build Coastguard Worker                    "example_customized-0.0.1.dist-info/WHEEL",
125*60517a1eSAndroid Build Coastguard Worker                    "example_customized-0.0.1.dist-info/METADATA",
126*60517a1eSAndroid Build Coastguard Worker                    "example_customized-0.0.1.dist-info/entry_points.txt",
127*60517a1eSAndroid Build Coastguard Worker                    "example_customized-0.0.1.dist-info/NOTICE",
128*60517a1eSAndroid Build Coastguard Worker                    "example_customized-0.0.1.dist-info/README",
129*60517a1eSAndroid Build Coastguard Worker                    "example_customized-0.0.1.dist-info/RECORD",
130*60517a1eSAndroid Build Coastguard Worker                ],
131*60517a1eSAndroid Build Coastguard Worker            )
132*60517a1eSAndroid Build Coastguard Worker            record_contents = zf.read("example_customized-0.0.1.dist-info/RECORD")
133*60517a1eSAndroid Build Coastguard Worker            wheel_contents = zf.read("example_customized-0.0.1.dist-info/WHEEL")
134*60517a1eSAndroid Build Coastguard Worker            metadata_contents = zf.read("example_customized-0.0.1.dist-info/METADATA")
135*60517a1eSAndroid Build Coastguard Worker            entry_point_contents = zf.read(
136*60517a1eSAndroid Build Coastguard Worker                "example_customized-0.0.1.dist-info/entry_points.txt"
137*60517a1eSAndroid Build Coastguard Worker            )
138*60517a1eSAndroid Build Coastguard Worker
139*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
140*60517a1eSAndroid Build Coastguard Worker                record_contents,
141*60517a1eSAndroid Build Coastguard Worker                # The entries are guaranteed to be sorted.
142*60517a1eSAndroid Build Coastguard Worker                b"""\
143*60517a1eSAndroid Build Coastguard Workerexamples/wheel/lib/data.txt,sha256=9vJKEdfLu8bZRArKLroPZJh1XKkK3qFMXiM79MBL2Sg,12
144*60517a1eSAndroid Build Coastguard Workerexamples/wheel/lib/module_with_data.py,sha256=8s0Khhcqz3yVsBKv2IB5u4l4TMKh7-c_V6p65WVHPms,637
145*60517a1eSAndroid Build Coastguard Workerexamples/wheel/lib/simple_module.py,sha256=z2hwciab_XPNIBNH8B1Q5fYgnJvQTeYf0ZQJpY8yLLY,637
146*60517a1eSAndroid Build Coastguard Workerexamples/wheel/main.py,sha256=sgg5iWN_9inYBjm6_Zw27hYdmo-l24fA-2rfphT-IlY,909
147*60517a1eSAndroid Build Coastguard Workerexample_customized-0.0.1.dist-info/WHEEL,sha256=sobxWSyDDkdg_rinUth-jxhXHqoNqlmNMJY3aTZn2Us,91
148*60517a1eSAndroid Build Coastguard Workerexample_customized-0.0.1.dist-info/METADATA,sha256=QYQcDJFQSIqan8eiXqL67bqsUfgEAwf2hoK_Lgi1S-0,559
149*60517a1eSAndroid Build Coastguard Workerexample_customized-0.0.1.dist-info/entry_points.txt,sha256=pqzpbQ8MMorrJ3Jp0ntmpZcuvfByyqzMXXi2UujuXD0,137
150*60517a1eSAndroid Build Coastguard Workerexample_customized-0.0.1.dist-info/NOTICE,sha256=Xpdw-FXET1IRgZ_wTkx1YQfo1-alET0FVf6V1LXO4js,76
151*60517a1eSAndroid Build Coastguard Workerexample_customized-0.0.1.dist-info/README,sha256=WmOFwZ3Jga1bHG3JiGRsUheb4UbLffUxyTdHczS27-o,40
152*60517a1eSAndroid Build Coastguard Workerexample_customized-0.0.1.dist-info/RECORD,,
153*60517a1eSAndroid Build Coastguard Worker""",
154*60517a1eSAndroid Build Coastguard Worker            )
155*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
156*60517a1eSAndroid Build Coastguard Worker                wheel_contents,
157*60517a1eSAndroid Build Coastguard Worker                b"""\
158*60517a1eSAndroid Build Coastguard WorkerWheel-Version: 1.0
159*60517a1eSAndroid Build Coastguard WorkerGenerator: bazel-wheelmaker 1.0
160*60517a1eSAndroid Build Coastguard WorkerRoot-Is-Purelib: true
161*60517a1eSAndroid Build Coastguard WorkerTag: py3-none-any
162*60517a1eSAndroid Build Coastguard Worker""",
163*60517a1eSAndroid Build Coastguard Worker            )
164*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
165*60517a1eSAndroid Build Coastguard Worker                metadata_contents,
166*60517a1eSAndroid Build Coastguard Worker                b"""\
167*60517a1eSAndroid Build Coastguard WorkerMetadata-Version: 2.1
168*60517a1eSAndroid Build Coastguard WorkerName: example_customized
169*60517a1eSAndroid Build Coastguard WorkerAuthor: Example Author with non-ascii characters: \xc5\xbc\xc3\xb3\xc5\x82w
170*60517a1eSAndroid Build Coastguard WorkerAuthor-email: [email protected]
171*60517a1eSAndroid Build Coastguard WorkerHome-page: www.example.com
172*60517a1eSAndroid Build Coastguard WorkerLicense: Apache 2.0
173*60517a1eSAndroid Build Coastguard WorkerDescription-Content-Type: text/markdown
174*60517a1eSAndroid Build Coastguard WorkerSummary: A one-line summary of this test package
175*60517a1eSAndroid Build Coastguard WorkerProject-URL: Bug Tracker, www.example.com/issues
176*60517a1eSAndroid Build Coastguard WorkerProject-URL: Documentation, www.example.com/docs
177*60517a1eSAndroid Build Coastguard WorkerClassifier: License :: OSI Approved :: Apache Software License
178*60517a1eSAndroid Build Coastguard WorkerClassifier: Intended Audience :: Developers
179*60517a1eSAndroid Build Coastguard WorkerRequires-Dist: pytest
180*60517a1eSAndroid Build Coastguard WorkerVersion: 0.0.1
181*60517a1eSAndroid Build Coastguard Worker
182*60517a1eSAndroid Build Coastguard WorkerThis is a sample description of a wheel.
183*60517a1eSAndroid Build Coastguard Worker""",
184*60517a1eSAndroid Build Coastguard Worker            )
185*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
186*60517a1eSAndroid Build Coastguard Worker                entry_point_contents,
187*60517a1eSAndroid Build Coastguard Worker                b"""\
188*60517a1eSAndroid Build Coastguard Worker[console_scripts]
189*60517a1eSAndroid Build Coastguard Workeranother = foo.bar:baz
190*60517a1eSAndroid Build Coastguard Workercustomized_wheel = examples.wheel.main:main
191*60517a1eSAndroid Build Coastguard Worker
192*60517a1eSAndroid Build Coastguard Worker[group2]
193*60517a1eSAndroid Build Coastguard Workerfirst = first.main:f
194*60517a1eSAndroid Build Coastguard Workersecond = second.main:s""",
195*60517a1eSAndroid Build Coastguard Worker            )
196*60517a1eSAndroid Build Coastguard Worker        self.assertFileSha256Equal(
197*60517a1eSAndroid Build Coastguard Worker            filename, "27f3038be6e768d28735441a1bc567eca2213bd3568d18b22a414e6399a2d48e"
198*60517a1eSAndroid Build Coastguard Worker        )
199*60517a1eSAndroid Build Coastguard Worker
200*60517a1eSAndroid Build Coastguard Worker    def test_filename_escaping(self):
201*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
202*60517a1eSAndroid Build Coastguard Worker            "file_name_escaping-0.0.1rc1+ubuntu.r7-py3-none-any.whl",
203*60517a1eSAndroid Build Coastguard Worker        )
204*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
205*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
206*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
207*60517a1eSAndroid Build Coastguard Worker                [
208*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/data.txt",
209*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/module_with_data.py",
210*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/lib/simple_module.py",
211*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/main.py",
212*60517a1eSAndroid Build Coastguard Worker                    # PEP calls for replacing only in the archive filename.
213*60517a1eSAndroid Build Coastguard Worker                    # Alas setuptools also escapes in the dist-info directory
214*60517a1eSAndroid Build Coastguard Worker                    # name, so let's be compatible.
215*60517a1eSAndroid Build Coastguard Worker                    "file_name_escaping-0.0.1rc1+ubuntu.r7.dist-info/WHEEL",
216*60517a1eSAndroid Build Coastguard Worker                    "file_name_escaping-0.0.1rc1+ubuntu.r7.dist-info/METADATA",
217*60517a1eSAndroid Build Coastguard Worker                    "file_name_escaping-0.0.1rc1+ubuntu.r7.dist-info/RECORD",
218*60517a1eSAndroid Build Coastguard Worker                ],
219*60517a1eSAndroid Build Coastguard Worker            )
220*60517a1eSAndroid Build Coastguard Worker            metadata_contents = zf.read(
221*60517a1eSAndroid Build Coastguard Worker                "file_name_escaping-0.0.1rc1+ubuntu.r7.dist-info/METADATA"
222*60517a1eSAndroid Build Coastguard Worker            )
223*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
224*60517a1eSAndroid Build Coastguard Worker                metadata_contents,
225*60517a1eSAndroid Build Coastguard Worker                b"""\
226*60517a1eSAndroid Build Coastguard WorkerMetadata-Version: 2.1
227*60517a1eSAndroid Build Coastguard WorkerName: File--Name-Escaping
228*60517a1eSAndroid Build Coastguard WorkerVersion: 0.0.1rc1+ubuntu.r7
229*60517a1eSAndroid Build Coastguard Worker
230*60517a1eSAndroid Build Coastguard WorkerUNKNOWN
231*60517a1eSAndroid Build Coastguard Worker""",
232*60517a1eSAndroid Build Coastguard Worker            )
233*60517a1eSAndroid Build Coastguard Worker
234*60517a1eSAndroid Build Coastguard Worker    def test_custom_package_root_wheel(self):
235*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
236*60517a1eSAndroid Build Coastguard Worker            "examples_custom_package_root-0.0.1-py3-none-any.whl",
237*60517a1eSAndroid Build Coastguard Worker        )
238*60517a1eSAndroid Build Coastguard Worker
239*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
240*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
241*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
242*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
243*60517a1eSAndroid Build Coastguard Worker                [
244*60517a1eSAndroid Build Coastguard Worker                    "wheel/lib/data.txt",
245*60517a1eSAndroid Build Coastguard Worker                    "wheel/lib/module_with_data.py",
246*60517a1eSAndroid Build Coastguard Worker                    "wheel/lib/simple_module.py",
247*60517a1eSAndroid Build Coastguard Worker                    "wheel/main.py",
248*60517a1eSAndroid Build Coastguard Worker                    "examples_custom_package_root-0.0.1.dist-info/WHEEL",
249*60517a1eSAndroid Build Coastguard Worker                    "examples_custom_package_root-0.0.1.dist-info/METADATA",
250*60517a1eSAndroid Build Coastguard Worker                    "examples_custom_package_root-0.0.1.dist-info/entry_points.txt",
251*60517a1eSAndroid Build Coastguard Worker                    "examples_custom_package_root-0.0.1.dist-info/RECORD",
252*60517a1eSAndroid Build Coastguard Worker                ],
253*60517a1eSAndroid Build Coastguard Worker            )
254*60517a1eSAndroid Build Coastguard Worker
255*60517a1eSAndroid Build Coastguard Worker            record_contents = zf.read(
256*60517a1eSAndroid Build Coastguard Worker                "examples_custom_package_root-0.0.1.dist-info/RECORD"
257*60517a1eSAndroid Build Coastguard Worker            ).decode("utf-8")
258*60517a1eSAndroid Build Coastguard Worker
259*60517a1eSAndroid Build Coastguard Worker            # Ensure RECORD files do not have leading forward slashes
260*60517a1eSAndroid Build Coastguard Worker            for line in record_contents.splitlines():
261*60517a1eSAndroid Build Coastguard Worker                self.assertFalse(line.startswith("/"))
262*60517a1eSAndroid Build Coastguard Worker        self.assertFileSha256Equal(
263*60517a1eSAndroid Build Coastguard Worker            filename, "f034b3278781f4df32a33df70d794bb94170b450e477c8bd9cd42d2d922476ae"
264*60517a1eSAndroid Build Coastguard Worker        )
265*60517a1eSAndroid Build Coastguard Worker
266*60517a1eSAndroid Build Coastguard Worker    def test_custom_package_root_multi_prefix_wheel(self):
267*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
268*60517a1eSAndroid Build Coastguard Worker            "example_custom_package_root_multi_prefix-0.0.1-py3-none-any.whl",
269*60517a1eSAndroid Build Coastguard Worker        )
270*60517a1eSAndroid Build Coastguard Worker
271*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
272*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
273*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
274*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
275*60517a1eSAndroid Build Coastguard Worker                [
276*60517a1eSAndroid Build Coastguard Worker                    "data.txt",
277*60517a1eSAndroid Build Coastguard Worker                    "module_with_data.py",
278*60517a1eSAndroid Build Coastguard Worker                    "simple_module.py",
279*60517a1eSAndroid Build Coastguard Worker                    "main.py",
280*60517a1eSAndroid Build Coastguard Worker                    "example_custom_package_root_multi_prefix-0.0.1.dist-info/WHEEL",
281*60517a1eSAndroid Build Coastguard Worker                    "example_custom_package_root_multi_prefix-0.0.1.dist-info/METADATA",
282*60517a1eSAndroid Build Coastguard Worker                    "example_custom_package_root_multi_prefix-0.0.1.dist-info/RECORD",
283*60517a1eSAndroid Build Coastguard Worker                ],
284*60517a1eSAndroid Build Coastguard Worker            )
285*60517a1eSAndroid Build Coastguard Worker
286*60517a1eSAndroid Build Coastguard Worker            record_contents = zf.read(
287*60517a1eSAndroid Build Coastguard Worker                "example_custom_package_root_multi_prefix-0.0.1.dist-info/RECORD"
288*60517a1eSAndroid Build Coastguard Worker            ).decode("utf-8")
289*60517a1eSAndroid Build Coastguard Worker
290*60517a1eSAndroid Build Coastguard Worker            # Ensure RECORD files do not have leading forward slashes
291*60517a1eSAndroid Build Coastguard Worker            for line in record_contents.splitlines():
292*60517a1eSAndroid Build Coastguard Worker                self.assertFalse(line.startswith("/"))
293*60517a1eSAndroid Build Coastguard Worker        self.assertFileSha256Equal(
294*60517a1eSAndroid Build Coastguard Worker            filename, "ff19f5e4540948247742716338bb4194d619cb56df409045d1a99f265ce8e36c"
295*60517a1eSAndroid Build Coastguard Worker        )
296*60517a1eSAndroid Build Coastguard Worker
297*60517a1eSAndroid Build Coastguard Worker    def test_custom_package_root_multi_prefix_reverse_order_wheel(self):
298*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
299*60517a1eSAndroid Build Coastguard Worker            "example_custom_package_root_multi_prefix_reverse_order-0.0.1-py3-none-any.whl",
300*60517a1eSAndroid Build Coastguard Worker        )
301*60517a1eSAndroid Build Coastguard Worker
302*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
303*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
304*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
305*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
306*60517a1eSAndroid Build Coastguard Worker                [
307*60517a1eSAndroid Build Coastguard Worker                    "lib/data.txt",
308*60517a1eSAndroid Build Coastguard Worker                    "lib/module_with_data.py",
309*60517a1eSAndroid Build Coastguard Worker                    "lib/simple_module.py",
310*60517a1eSAndroid Build Coastguard Worker                    "main.py",
311*60517a1eSAndroid Build Coastguard Worker                    "example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/WHEEL",
312*60517a1eSAndroid Build Coastguard Worker                    "example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/METADATA",
313*60517a1eSAndroid Build Coastguard Worker                    "example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/RECORD",
314*60517a1eSAndroid Build Coastguard Worker                ],
315*60517a1eSAndroid Build Coastguard Worker            )
316*60517a1eSAndroid Build Coastguard Worker
317*60517a1eSAndroid Build Coastguard Worker            record_contents = zf.read(
318*60517a1eSAndroid Build Coastguard Worker                "example_custom_package_root_multi_prefix_reverse_order-0.0.1.dist-info/RECORD"
319*60517a1eSAndroid Build Coastguard Worker            ).decode("utf-8")
320*60517a1eSAndroid Build Coastguard Worker
321*60517a1eSAndroid Build Coastguard Worker            # Ensure RECORD files do not have leading forward slashes
322*60517a1eSAndroid Build Coastguard Worker            for line in record_contents.splitlines():
323*60517a1eSAndroid Build Coastguard Worker                self.assertFalse(line.startswith("/"))
324*60517a1eSAndroid Build Coastguard Worker        self.assertFileSha256Equal(
325*60517a1eSAndroid Build Coastguard Worker            filename, "4331e378ea8b8148409ae7c02177e4eb24d151a85ef937bb44b79ff5258d634b"
326*60517a1eSAndroid Build Coastguard Worker        )
327*60517a1eSAndroid Build Coastguard Worker
328*60517a1eSAndroid Build Coastguard Worker    def test_python_requires_wheel(self):
329*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
330*60517a1eSAndroid Build Coastguard Worker            "example_python_requires_in_a_package-0.0.1-py3-none-any.whl",
331*60517a1eSAndroid Build Coastguard Worker        )
332*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
333*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
334*60517a1eSAndroid Build Coastguard Worker            metadata_contents = zf.read(
335*60517a1eSAndroid Build Coastguard Worker                "example_python_requires_in_a_package-0.0.1.dist-info/METADATA"
336*60517a1eSAndroid Build Coastguard Worker            )
337*60517a1eSAndroid Build Coastguard Worker            # The entries are guaranteed to be sorted.
338*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
339*60517a1eSAndroid Build Coastguard Worker                metadata_contents,
340*60517a1eSAndroid Build Coastguard Worker                b"""\
341*60517a1eSAndroid Build Coastguard WorkerMetadata-Version: 2.1
342*60517a1eSAndroid Build Coastguard WorkerName: example_python_requires_in_a_package
343*60517a1eSAndroid Build Coastguard WorkerRequires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
344*60517a1eSAndroid Build Coastguard WorkerVersion: 0.0.1
345*60517a1eSAndroid Build Coastguard Worker
346*60517a1eSAndroid Build Coastguard WorkerUNKNOWN
347*60517a1eSAndroid Build Coastguard Worker""",
348*60517a1eSAndroid Build Coastguard Worker            )
349*60517a1eSAndroid Build Coastguard Worker        self.assertFileSha256Equal(
350*60517a1eSAndroid Build Coastguard Worker            filename, "b34676828f93da8cd898d50dcd4f36e02fe273150e213aacb999310a05f5f38c"
351*60517a1eSAndroid Build Coastguard Worker        )
352*60517a1eSAndroid Build Coastguard Worker
353*60517a1eSAndroid Build Coastguard Worker    def test_python_abi3_binary_wheel(self):
354*60517a1eSAndroid Build Coastguard Worker        arch = "amd64"
355*60517a1eSAndroid Build Coastguard Worker        if platform.system() != "Windows":
356*60517a1eSAndroid Build Coastguard Worker            arch = subprocess.check_output(["uname", "-m"]).strip().decode()
357*60517a1eSAndroid Build Coastguard Worker        # These strings match the strings from py_wheel() in BUILD
358*60517a1eSAndroid Build Coastguard Worker        os_strings = {
359*60517a1eSAndroid Build Coastguard Worker            "Linux": "manylinux2014",
360*60517a1eSAndroid Build Coastguard Worker            "Darwin": "macosx_11_0",
361*60517a1eSAndroid Build Coastguard Worker            "Windows": "win",
362*60517a1eSAndroid Build Coastguard Worker        }
363*60517a1eSAndroid Build Coastguard Worker        os_string = os_strings[platform.system()]
364*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
365*60517a1eSAndroid Build Coastguard Worker            f"example_python_abi3_binary_wheel-0.0.1-cp38-abi3-{os_string}_{arch}.whl",
366*60517a1eSAndroid Build Coastguard Worker        )
367*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
368*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
369*60517a1eSAndroid Build Coastguard Worker            metadata_contents = zf.read(
370*60517a1eSAndroid Build Coastguard Worker                "example_python_abi3_binary_wheel-0.0.1.dist-info/METADATA"
371*60517a1eSAndroid Build Coastguard Worker            )
372*60517a1eSAndroid Build Coastguard Worker            # The entries are guaranteed to be sorted.
373*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
374*60517a1eSAndroid Build Coastguard Worker                metadata_contents,
375*60517a1eSAndroid Build Coastguard Worker                b"""\
376*60517a1eSAndroid Build Coastguard WorkerMetadata-Version: 2.1
377*60517a1eSAndroid Build Coastguard WorkerName: example_python_abi3_binary_wheel
378*60517a1eSAndroid Build Coastguard WorkerRequires-Python: >=3.8
379*60517a1eSAndroid Build Coastguard WorkerVersion: 0.0.1
380*60517a1eSAndroid Build Coastguard Worker
381*60517a1eSAndroid Build Coastguard WorkerUNKNOWN
382*60517a1eSAndroid Build Coastguard Worker""",
383*60517a1eSAndroid Build Coastguard Worker            )
384*60517a1eSAndroid Build Coastguard Worker            wheel_contents = zf.read(
385*60517a1eSAndroid Build Coastguard Worker                "example_python_abi3_binary_wheel-0.0.1.dist-info/WHEEL"
386*60517a1eSAndroid Build Coastguard Worker            )
387*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
388*60517a1eSAndroid Build Coastguard Worker                wheel_contents.decode(),
389*60517a1eSAndroid Build Coastguard Worker                f"""\
390*60517a1eSAndroid Build Coastguard WorkerWheel-Version: 1.0
391*60517a1eSAndroid Build Coastguard WorkerGenerator: bazel-wheelmaker 1.0
392*60517a1eSAndroid Build Coastguard WorkerRoot-Is-Purelib: false
393*60517a1eSAndroid Build Coastguard WorkerTag: cp38-abi3-{os_string}_{arch}
394*60517a1eSAndroid Build Coastguard Worker""",
395*60517a1eSAndroid Build Coastguard Worker            )
396*60517a1eSAndroid Build Coastguard Worker
397*60517a1eSAndroid Build Coastguard Worker    def test_rule_creates_directory_and_is_included_in_wheel(self):
398*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
399*60517a1eSAndroid Build Coastguard Worker            "use_rule_with_dir_in_outs-0.0.1-py3-none-any.whl",
400*60517a1eSAndroid Build Coastguard Worker        )
401*60517a1eSAndroid Build Coastguard Worker
402*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
403*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
404*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
405*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
406*60517a1eSAndroid Build Coastguard Worker                [
407*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/main.py",
408*60517a1eSAndroid Build Coastguard Worker                    "examples/wheel/someDir/foo.py",
409*60517a1eSAndroid Build Coastguard Worker                    "use_rule_with_dir_in_outs-0.0.1.dist-info/WHEEL",
410*60517a1eSAndroid Build Coastguard Worker                    "use_rule_with_dir_in_outs-0.0.1.dist-info/METADATA",
411*60517a1eSAndroid Build Coastguard Worker                    "use_rule_with_dir_in_outs-0.0.1.dist-info/RECORD",
412*60517a1eSAndroid Build Coastguard Worker                ],
413*60517a1eSAndroid Build Coastguard Worker            )
414*60517a1eSAndroid Build Coastguard Worker        self.assertFileSha256Equal(
415*60517a1eSAndroid Build Coastguard Worker            filename, "ac9216bd54dcae1a6270c35fccf8a73b0be87c1b026c28e963b7c76b2f9b722b"
416*60517a1eSAndroid Build Coastguard Worker        )
417*60517a1eSAndroid Build Coastguard Worker
418*60517a1eSAndroid Build Coastguard Worker    def test_rule_expands_workspace_status_keys_in_wheel_metadata(self):
419*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path(
420*60517a1eSAndroid Build Coastguard Worker            "example_minimal_library{BUILD_USER}-0.1.{BUILD_TIMESTAMP}-py3-none-any.whl"
421*60517a1eSAndroid Build Coastguard Worker        )
422*60517a1eSAndroid Build Coastguard Worker
423*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
424*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
425*60517a1eSAndroid Build Coastguard Worker            metadata_file = None
426*60517a1eSAndroid Build Coastguard Worker            for f in zf.namelist():
427*60517a1eSAndroid Build Coastguard Worker                self.assertNotIn("{BUILD_TIMESTAMP}", f)
428*60517a1eSAndroid Build Coastguard Worker                self.assertNotIn("{BUILD_USER}", f)
429*60517a1eSAndroid Build Coastguard Worker                if os.path.basename(f) == "METADATA":
430*60517a1eSAndroid Build Coastguard Worker                    metadata_file = f
431*60517a1eSAndroid Build Coastguard Worker            self.assertIsNotNone(metadata_file)
432*60517a1eSAndroid Build Coastguard Worker
433*60517a1eSAndroid Build Coastguard Worker            version = None
434*60517a1eSAndroid Build Coastguard Worker            name = None
435*60517a1eSAndroid Build Coastguard Worker            with zf.open(metadata_file) as fp:
436*60517a1eSAndroid Build Coastguard Worker                for line in fp:
437*60517a1eSAndroid Build Coastguard Worker                    if line.startswith(b"Version:"):
438*60517a1eSAndroid Build Coastguard Worker                        version = line.decode().split()[-1]
439*60517a1eSAndroid Build Coastguard Worker                    if line.startswith(b"Name:"):
440*60517a1eSAndroid Build Coastguard Worker                        name = line.decode().split()[-1]
441*60517a1eSAndroid Build Coastguard Worker            self.assertIsNotNone(version)
442*60517a1eSAndroid Build Coastguard Worker            self.assertIsNotNone(name)
443*60517a1eSAndroid Build Coastguard Worker            self.assertNotIn("{BUILD_TIMESTAMP}", version)
444*60517a1eSAndroid Build Coastguard Worker            self.assertNotIn("{BUILD_USER}", name)
445*60517a1eSAndroid Build Coastguard Worker
446*60517a1eSAndroid Build Coastguard Worker    def test_requires_file_and_extra_requires_files(self):
447*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path("requires_files-0.0.1-py3-none-any.whl")
448*60517a1eSAndroid Build Coastguard Worker
449*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
450*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
451*60517a1eSAndroid Build Coastguard Worker            metadata_file = None
452*60517a1eSAndroid Build Coastguard Worker            for f in zf.namelist():
453*60517a1eSAndroid Build Coastguard Worker                if os.path.basename(f) == "METADATA":
454*60517a1eSAndroid Build Coastguard Worker                    metadata_file = f
455*60517a1eSAndroid Build Coastguard Worker            self.assertIsNotNone(metadata_file)
456*60517a1eSAndroid Build Coastguard Worker
457*60517a1eSAndroid Build Coastguard Worker            requires = []
458*60517a1eSAndroid Build Coastguard Worker            with zf.open(metadata_file) as fp:
459*60517a1eSAndroid Build Coastguard Worker                for line in fp:
460*60517a1eSAndroid Build Coastguard Worker                    if line.startswith(b"Requires-Dist:"):
461*60517a1eSAndroid Build Coastguard Worker                        requires.append(line.decode("utf-8").strip())
462*60517a1eSAndroid Build Coastguard Worker
463*60517a1eSAndroid Build Coastguard Worker            print(requires)
464*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
465*60517a1eSAndroid Build Coastguard Worker                [
466*60517a1eSAndroid Build Coastguard Worker                    "Requires-Dist: tomli>=2.0.0",
467*60517a1eSAndroid Build Coastguard Worker                    "Requires-Dist: starlark",
468*60517a1eSAndroid Build Coastguard Worker                    "Requires-Dist: pyyaml!=6.0.1,>=6.0.0; extra == 'example'",
469*60517a1eSAndroid Build Coastguard Worker                    'Requires-Dist: toml; ((python_version == "3.11" or python_version == "3.12") and python_version != "3.8") and extra == \'example\'',
470*60517a1eSAndroid Build Coastguard Worker                    'Requires-Dist: wheel; (python_version == "3.11" or python_version == "3.12") and extra == \'example\'',
471*60517a1eSAndroid Build Coastguard Worker                ],
472*60517a1eSAndroid Build Coastguard Worker                requires,
473*60517a1eSAndroid Build Coastguard Worker            )
474*60517a1eSAndroid Build Coastguard Worker
475*60517a1eSAndroid Build Coastguard Worker    def test_minimal_data_files(self):
476*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path("minimal_data_files-0.0.1-py3-none-any.whl")
477*60517a1eSAndroid Build Coastguard Worker
478*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
479*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
480*60517a1eSAndroid Build Coastguard Worker            metadata_file = None
481*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
482*60517a1eSAndroid Build Coastguard Worker                zf.namelist(),
483*60517a1eSAndroid Build Coastguard Worker                [
484*60517a1eSAndroid Build Coastguard Worker                    "minimal_data_files-0.0.1.dist-info/WHEEL",
485*60517a1eSAndroid Build Coastguard Worker                    "minimal_data_files-0.0.1.dist-info/METADATA",
486*60517a1eSAndroid Build Coastguard Worker                    "minimal_data_files-0.0.1.data/data/target/path/README.md",
487*60517a1eSAndroid Build Coastguard Worker                    "minimal_data_files-0.0.1.data/scripts/NOTICE",
488*60517a1eSAndroid Build Coastguard Worker                    "minimal_data_files-0.0.1.dist-info/RECORD",
489*60517a1eSAndroid Build Coastguard Worker                ],
490*60517a1eSAndroid Build Coastguard Worker            )
491*60517a1eSAndroid Build Coastguard Worker
492*60517a1eSAndroid Build Coastguard Worker    def test_extra_requires(self):
493*60517a1eSAndroid Build Coastguard Worker        filename = self._get_path("extra_requires-0.0.1-py3-none-any.whl")
494*60517a1eSAndroid Build Coastguard Worker
495*60517a1eSAndroid Build Coastguard Worker        with zipfile.ZipFile(filename) as zf:
496*60517a1eSAndroid Build Coastguard Worker            self.assertAllEntriesHasReproducibleMetadata(zf)
497*60517a1eSAndroid Build Coastguard Worker            metadata_file = None
498*60517a1eSAndroid Build Coastguard Worker            for f in zf.namelist():
499*60517a1eSAndroid Build Coastguard Worker                if os.path.basename(f) == "METADATA":
500*60517a1eSAndroid Build Coastguard Worker                    metadata_file = f
501*60517a1eSAndroid Build Coastguard Worker            self.assertIsNotNone(metadata_file)
502*60517a1eSAndroid Build Coastguard Worker
503*60517a1eSAndroid Build Coastguard Worker            requires = []
504*60517a1eSAndroid Build Coastguard Worker            with zf.open(metadata_file) as fp:
505*60517a1eSAndroid Build Coastguard Worker                for line in fp:
506*60517a1eSAndroid Build Coastguard Worker                    if line.startswith(b"Requires-Dist:"):
507*60517a1eSAndroid Build Coastguard Worker                        requires.append(line.decode("utf-8").strip())
508*60517a1eSAndroid Build Coastguard Worker
509*60517a1eSAndroid Build Coastguard Worker            print(requires)
510*60517a1eSAndroid Build Coastguard Worker            self.assertEqual(
511*60517a1eSAndroid Build Coastguard Worker                [
512*60517a1eSAndroid Build Coastguard Worker                    "Requires-Dist: tomli>=2.0.0",
513*60517a1eSAndroid Build Coastguard Worker                    "Requires-Dist: starlark",
514*60517a1eSAndroid Build Coastguard Worker                    'Requires-Dist: pytest; python_version != "3.8"',
515*60517a1eSAndroid Build Coastguard Worker                    "Requires-Dist: pyyaml!=6.0.1,>=6.0.0; extra == 'example'",
516*60517a1eSAndroid Build Coastguard Worker                    'Requires-Dist: toml; ((python_version == "3.11" or python_version == "3.12") and python_version != "3.8") and extra == \'example\'',
517*60517a1eSAndroid Build Coastguard Worker                    'Requires-Dist: wheel; (python_version == "3.11" or python_version == "3.12") and extra == \'example\'',
518*60517a1eSAndroid Build Coastguard Worker                ],
519*60517a1eSAndroid Build Coastguard Worker                requires,
520*60517a1eSAndroid Build Coastguard Worker            )
521*60517a1eSAndroid Build Coastguard Worker
522*60517a1eSAndroid Build Coastguard Worker
523*60517a1eSAndroid Build Coastguard Workerif __name__ == "__main__":
524*60517a1eSAndroid Build Coastguard Worker    unittest.main()
525