blob: 7c7720b3b2faaebf5203c4a2e73033726d264b61 [file]
# Copyright 2019 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
import filecmp
import unittest
import zipfile
from bazel_tools.tools.python.runfiles import runfiles
HELLO_CRC = 2069210904
LOREM_CRC = 2178844372
EXECUTABLE_CRC = 342626072
# Unix dir bit and Windows dir bit. Magic from zip spec
UNIX_DIR_BIT = 0o40000
MSDOS_DIR_BIT = 0x10
UNIX_RWX_BITS = 0o777
# The ZIP epoch date: (1980, 1, 1, 0, 0, 0)
_ZIP_EPOCH_DT = datetime.datetime(1980, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
_ZIP_EPOCH_S = int(_ZIP_EPOCH_DT.timestamp())
def seconds_to_ziptime(s):
dt = datetime.datetime.utcfromtimestamp(s)
return (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)
class ZipTest(unittest.TestCase):
def get_test_zip(self, zip_file):
"""Get the file path to a generated zip in the runfiles."""
return self.data_files.Rlocation(
"rules_pkg/tests/zip/" + zip_file
)
def setUp(self):
super(ZipTest, self).setUp()
self.data_files = runfiles.Create()
class ZipContentsCase(ZipTest):
"""Use zipfile to check the contents of some generated zip files."""
def assertZipFileContent(self, zip_file, content):
"""Assert that zip_file contains the entries described by content.
Args:
zip_file: the test-package-relative path to a zip file to test.
content: an array of dictionaries containing a filename and crc key,
and optionally a timestamp key.
"""
with zipfile.ZipFile(self.get_test_zip(zip_file)) as f:
infos = f.infolist()
self.assertEqual(len(infos), len(content))
for info, expected in zip(infos, content):
self.assertEqual(info.filename, expected["filename"])
if "crc" in expected:
self.assertEqual(info.CRC, expected["crc"])
ts = seconds_to_ziptime(expected.get("timestamp", _ZIP_EPOCH_S))
self.assertEqual(info.date_time, ts)
if "isdir" in expected:
expect_dir_bits = UNIX_DIR_BIT << 16 | MSDOS_DIR_BIT
self.assertEqual(info.external_attr & expect_dir_bits,
expect_dir_bits)
self.assertEqual((info.external_attr >> 16) & UNIX_RWX_BITS,
expected.get("attr", 0o555))
def test_empty(self):
self.assertZipFileContent("test_zip_empty.zip", [])
def test_basic(self):
self.assertZipFileContent("test_zip_basic.zip", [
{"filename": "foodir/", "isdir": True, "attr": 0o711},
{"filename": "hello.txt", "crc": HELLO_CRC},
{"filename": "loremipsum.txt", "crc": LOREM_CRC},
{"filename": "usr/bin/foo", "attr": 0o555, "data": "/usr/local/foo/foo.real"},
])
def test_timestamp(self):
self.assertZipFileContent("test_zip_timestamp.zip", [
{"filename": "hello.txt", "crc": HELLO_CRC, "timestamp": 1234567890},
])
def test_permissions(self):
self.assertZipFileContent("test_zip_permissions.zip", [
{
"filename": "executable.sh",
"crc": EXECUTABLE_CRC,
"timestamp": 1234567890,
"attr": 0o644,
}
])
def test_package_dir(self):
self.assertZipFileContent("test_zip_package_dir0.zip", [
{"filename": "abc/def/hello.txt", "crc": HELLO_CRC},
{"filename": "abc/def/loremipsum.txt", "crc": LOREM_CRC},
])
def test_zip_strip_prefix_empty(self):
self.assertZipFileContent("test-zip-strip_prefix-empty.zip", [
{"filename": "loremipsum.txt", "crc": LOREM_CRC},
])
def test_zip_strip_prefix_none(self):
self.assertZipFileContent("test-zip-strip_prefix-none.zip", [
{"filename": "loremipsum.txt", "crc": LOREM_CRC},
])
def test_zip_strip_prefix_zipcontent(self):
self.assertZipFileContent("test-zip-strip_prefix-zipcontent.zip", [
{"filename": "loremipsum.txt", "crc": LOREM_CRC},
])
def test_zip_strip_prefix_dot(self):
self.assertZipFileContent("test-zip-strip_prefix-dot.zip", [
{"filename": "zipcontent/loremipsum.txt", "crc": LOREM_CRC},
])
class ZipEquivalency(ZipTest):
"""Check that some generated zip files are equivalent to each-other."""
def assertFilesEqual(self, actual, expected):
"""Assert that two zip files contain the same bytes."""
zips_are_equal = filecmp.cmp(
self.get_test_zip(actual),
self.get_test_zip(expected),
)
self.assertTrue(zips_are_equal)
def test_small_timestamp(self):
self.assertFilesEqual(
"test_zip_basic_timestamp_before_epoch.zip",
"test_zip_basic.zip",
)
def test_extension(self):
self.assertFilesEqual(
"test_zip_empty_different_extension.otherkindofzip",
"test_zip_empty.zip",
)
def test_package_dir1(self):
self.assertFilesEqual(
"test_zip_package_dir1.zip",
"test_zip_package_dir0.zip",
)
def test_package_dir2(self):
self.assertFilesEqual(
"test_zip_package_dir2.zip",
"test_zip_package_dir0.zip",
)
if __name__ == "__main__":
unittest.main()