blob: 7ba722b7444ec72c0164c2f26e7160d21609a477 [file] [log] [blame]
# Copyright 2021 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.
"""Test time stamping in pkg_tar"""
import datetime
import tarfile
import time
import unittest
import zipfile
from bazel_tools.tools.python.runfiles import runfiles
# keep in sync with archive.py
PORTABLE_MTIME = 946684800 # 2000-01-01 00:00:00.000 UTC
class StampTest(unittest.TestCase):
"""Test for non-epoch time stamps in packages."""
target_mtime = int(time.time())
zip_epoch_dt = datetime.datetime(1980, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
ZIP_EPOCH = int(zip_epoch_dt.timestamp())
# We allow the stamp on the build file to be within this delta back in
# time from now. That allows for the test data to be built early in a clean
# CI run and have the test run a few seconds later. Ideally, this would
# be no greater than the expected total CI run time, but the extra margin
# does not hurt.
ALLOWED_DELTA_FROM_NOW = 30000 # seconds
def check_mtime(self, mtime, file_path, file_name):
"""Checks that a time stamp is reasonable.
This checks that a timestamp is not 0 or any of the well known EPOCH values,
and that it is within some delta from the current time.
Args:
mtime: timestamp in seconds
file_path: path to archive name
file_name: file within archive
"""
if mtime == 0:
self.fail('Archive %s contains file %s with mtime == 0' % (
file_path, file_name))
if mtime == PORTABLE_MTIME:
self.fail('Archive %s contains file %s with portable mtime' % (
file_path, file_name))
if mtime == StampTest.ZIP_EPOCH:
self.fail('Archive %s contains file %s with ZIP epoch' % (
file_path, file_name))
if ((mtime < self.target_mtime - StampTest.ALLOWED_DELTA_FROM_NOW)
or (mtime > self.target_mtime)):
self.fail(
'Archive %s contains file %s with mtime:%d, expected:%d +/- %d.' % (
file_path, file_name, mtime, self.target_mtime,
StampTest.ALLOWED_DELTA_FROM_NOW) +
' This may be a false positive if your build cache is more than' +
' %s seconds old. If so, try bazel clean and rerun the test.' %
StampTest.ALLOWED_DELTA_FROM_NOW)
def assertTarFilesAreAlmostNew(self, file_name):
"""Assert that tarfile contains files with an mtime of roughly now.
This is used to prove that the test data was a file which was presumably:
built with 'stamp=1' or ('stamp=-1' and --stamp) contains files which
all have a fairly recent mtime, thus indicating they are "current" time
rather than the epoch or some other time.
Args:
file_name: the path to the TAR file to test.
"""
file_path = runfiles.Create().Rlocation('rules_pkg/tests/' + file_name)
with tarfile.open(file_path, 'r:*') as f:
for info in f:
self.check_mtime(info.mtime, file_path, info.name)
def assertZipFilesAreAlmostNew(self, file_name):
"""Assert that zipfile contains files with an mtime of roughly now.
This is used to prove that the test data was a file which was presumably:
built with 'stamp=1' or ('stamp=-1' and --stamp) contains files which
all have a fairly recent mtime, thus indicating they are "current" time
rather than the epoch or some other time.
Args:
file_name: the path to the ZIP file to test.
"""
file_path = runfiles.Create().Rlocation('rules_pkg/tests/' + file_name)
target_mtime = int(time.time())
with zipfile.ZipFile(file_path, mode='r') as f:
for info in f.infolist():
d = info.date_time
dt = datetime.datetime(d[0], d[1], d[2], d[3], d[4], d[5], tzinfo=datetime.timezone.utc)
self.check_mtime(int(dt.timestamp()), file_path, info.filename)
def test_not_epoch_times_tar(self):
self.assertTarFilesAreAlmostNew('stamped_tar.tar')
def test_not_epoch_times_zip(self):
self.assertZipFilesAreAlmostNew('stamped_zip.zip')
if __name__ == '__main__':
unittest.main()