2 # Copyright (c) 2014 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Tests for package version."""
14 sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
15 import pynacl.fake_downloader
16 import pynacl.fake_storage
17 import pynacl.file_tools
18 import pynacl.platform
19 import pynacl.working_directory
23 import package_locations
24 import package_version
26 class TestPackageVersion(unittest.TestCase):
29 self._fake_storage = pynacl.fake_storage.FakeStorage()
30 self._fake_downloader = pynacl.fake_downloader.FakeDownloader()
32 def GenerateMockFile(self, work_dir, mock_dir = 'mock_dir',
33 mock_file='mockfile.txt', contents='mock contents'):
34 """Generates a file with random content in it.
37 work_dir: Root working directory where mock directory will live.
38 mock_dir: Mock directory under root directory where mock file will live.
39 mock_file: Mock filename which generated file will be generated under.
40 contents: Base content for the mock file.
42 File path for the mock file with the mock contents with random content.
44 full_mock_dir = os.path.join(work_dir, mock_dir)
45 if not os.path.isdir(full_mock_dir):
46 os.makedirs(full_mock_dir)
48 full_mock_file = os.path.join(full_mock_dir, mock_file)
49 with open(full_mock_file, 'wt') as f:
51 f.write(str(random.random()))
55 def GeneratePackageInfo(self, archive_list, name_dict={},
56 url_dict={}, src_dir_dict={}, dir_dict={}):
57 """Generates a package_info.PackageInfo object for list of archives."
60 archive_list: List of file paths where package archives sit.
61 name_dict: optional dict of archive to names, otherwise use filename.
62 url_dict: dict of archive file path to URL if url exists.
63 src_dir_dict: dict of archive file path to source tar dir if exists.
64 dir_dict: dict of archive file path to root dir if exists.
66 package_desc = package_info.PackageInfo()
67 for archive_file in archive_list:
68 archive_name = name_dict.get(archive_file, os.path.basename(archive_file))
70 if os.path.isfile(archive_file):
71 archive_hash = archive_info.GetArchiveHash(archive_file)
73 archive_hash = 'invalid'
75 archive_url = url_dict.get(archive_file, None)
76 archive_src_tar_dir = src_dir_dict.get(archive_file, '')
77 archive_dir = dir_dict.get(archive_file, '')
78 archive_desc = archive_info.ArchiveInfo(archive_name,
81 tar_src_dir=archive_src_tar_dir,
82 extract_dir=archive_dir)
83 package_desc.AppendArchive(archive_desc)
87 def test_DownloadArchive(self):
88 # Check that we can download a package archive correctly.
89 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
90 mock_tar = self.GenerateMockFile(work_dir)
92 fake_url = 'http://www.fake.com/archive.tar'
93 self._fake_downloader.StoreURL(fake_url, mock_tar)
95 package_desc = self.GeneratePackageInfo(
97 url_dict={mock_tar: fake_url}
100 tar_dir = os.path.join(work_dir, 'tar_dir')
101 package_target = 'archive_target'
102 package_name = 'archive_name'
103 package_version.DownloadPackageArchives(
108 downloader=self._fake_downloader.Download
110 self.assertEqual(self._fake_downloader.GetDownloadCount(), 1,
111 "Expected a single archive to have been downloaded.")
113 mock_name = os.path.basename(mock_tar)
114 local_archive_file = package_locations.GetLocalPackageArchiveFile(
122 archive_info.GetArchiveHash(local_archive_file),
123 archive_info.GetArchiveHash(mock_tar)
126 def test_DownloadArchiveMissingURLFails(self):
127 # Checks that we fail when the archive has no URL set.
128 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
129 package_desc = package_info.PackageInfo()
130 archive_desc = archive_info.ArchiveInfo('missing_name.tar',
133 package_desc.AppendArchive(archive_desc)
135 tar_dir = os.path.join(work_dir, 'tar_dir')
138 package_version.DownloadPackageArchives,
143 downloader=self._fake_downloader.Download
146 def test_DownloadArchiveMismatchFails(self):
147 # Check download archive fails when the hash does not match expected hash.
148 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
149 mock_tar = self.GenerateMockFile(work_dir)
150 fake_url = 'http://www.fake.com/archive.tar'
151 self._fake_downloader.StoreURL(fake_url, mock_tar)
153 package_desc = package_info.PackageInfo()
154 archive_desc = archive_info.ArchiveInfo('invalid_name.tar',
157 package_desc.AppendArchive(archive_desc)
159 tar_dir = os.path.join(work_dir, 'tar_dir')
162 package_version.DownloadPackageArchives,
167 downloader=self._fake_downloader.Download
170 def test_ArchivePackageArchives(self):
171 # Check if we can archive a list of archives to the tar directory.
172 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
173 mock_tar1 = self.GenerateMockFile(
175 mock_file='file1.tar',
176 contents='mock contents 1'
178 mock_tar2 = self.GenerateMockFile(
180 mock_file='file2.tar',
181 contents='mock contents 2'
184 tar_dir = os.path.join(work_dir, 'tar_dir')
185 package_target = 'test_package_archives'
186 package_name = 'package_archives'
187 package_version.ArchivePackageArchives(
191 [mock_tar1, mock_tar2]
194 package_file = package_locations.GetLocalPackageFile(
199 expected_package_desc = self.GeneratePackageInfo([mock_tar1, mock_tar2])
200 package_desc = package_info.PackageInfo(package_file)
202 self.assertEqual(expected_package_desc, package_desc)
203 # "Archived package does not match mock package.")
205 def test_PackageUpload(self):
206 # Check if we can properly upload a package file from the tar directory.
207 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
208 tar_dir = os.path.join(work_dir, 'tar_dir')
209 package_target = 'test_package_archives'
210 package_name = 'package_archives'
211 package_revision = 10
212 package_version.ArchivePackageArchives(
219 package_version.UploadPackage(
228 self._fake_storage.WriteCount(),
230 "Package did not get properly uploaded"
233 remote_package_key = package_locations.GetRemotePackageKey(
239 downloaded_package = os.path.join(work_dir, 'download_package.json')
240 package_info.DownloadPackageInfoFiles(
243 downloader=self._fake_storage.GetFile)
244 downloaded_package_desc = package_info.PackageInfo(downloaded_package)
246 original_package_file = package_locations.GetLocalPackageFile(
251 original_package_desc = package_info.PackageInfo(original_package_file)
253 self.assertEqual(downloaded_package_desc, original_package_desc)
255 def test_CustomPackageUpload(self):
256 # Check if we can upload a package file from a custom location.
257 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
258 custom_package_file = os.path.join(work_dir, 'custom_package.json')
259 package_desc = self.GeneratePackageInfo([])
260 package_desc.SavePackageFile(custom_package_file)
262 tar_dir = os.path.join(work_dir, 'tar_dir')
263 package_target = 'custom_package_target'
264 package_name = 'custom_package'
265 package_revision = 10
267 package_version.UploadPackage(
274 custom_package_file=custom_package_file
277 self._fake_storage.WriteCount(),
279 "Package did not get properly uploaded"
282 remote_package_key = package_locations.GetRemotePackageKey(
288 downloaded_package = os.path.join(work_dir, 'download_package.json')
289 package_info.DownloadPackageInfoFiles(
292 downloader=self._fake_storage.GetFile)
293 downloaded_package_desc = package_info.PackageInfo(downloaded_package)
295 original_package_desc = package_info.PackageInfo(custom_package_file)
297 self.assertEqual(downloaded_package_desc, original_package_desc)
299 def test_UploadKeepsArchiveURL(self):
300 # Checks if the archive URL is kept after a package upload.
301 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
302 mock_tar = self.GenerateMockFile(work_dir)
303 mock_url = 'http://www.mock.com/mock.tar'
304 package_desc = self.GeneratePackageInfo(
306 url_dict={mock_tar: mock_url}
309 package_file = os.path.join(work_dir, 'package_file.json')
310 package_desc.SavePackageFile(package_file)
312 tar_dir = os.path.join(work_dir, 'tar_dir')
313 package_target = 'custom_package_target'
314 package_name = 'custom_package'
315 package_revision = 10
317 package_version.UploadPackage(
324 custom_package_file=package_file
327 self._fake_storage.WriteCount(),
329 "Package did not get properly uploaded"
332 remote_package_key = package_locations.GetRemotePackageKey(
338 downloaded_package = os.path.join(work_dir, 'download_package.json')
339 package_info.DownloadPackageInfoFiles(
342 downloader=self._fake_storage.GetFile)
343 downloaded_package_desc = package_info.PackageInfo(downloaded_package)
345 # Verify everything (including URL) still matches.
346 self.assertEqual(downloaded_package_desc, package_desc)
348 def test_NoArchiveURLDoesUpload(self):
349 # Checks when uploading package with no archive URL, archive is uploaded.
350 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
351 tar_dir = os.path.join(work_dir, 'tar_dir')
352 package_target = 'custom_package_target'
353 package_name = 'custom_package'
354 package_revision = 10
356 mock_file = self.GenerateMockFile(work_dir)
357 mock_tar = package_locations.GetLocalPackageArchiveFile(
363 os.makedirs(os.path.dirname(mock_tar))
364 with tarfile.TarFile(mock_tar, 'w') as f:
367 package_desc = self.GeneratePackageInfo([mock_tar])
369 package_file = os.path.join(work_dir, 'package_file.json')
370 package_desc.SavePackageFile(package_file)
372 package_version.UploadPackage(
379 custom_package_file=package_file
382 self._fake_storage.WriteCount(),
384 "3 files (package, archive_info, archive) should have been uploaded."
387 remote_package_key = package_locations.GetRemotePackageKey(
393 downloaded_package = os.path.join(work_dir, 'download_package.json')
394 package_info.DownloadPackageInfoFiles(
397 downloader=self._fake_storage.GetFile)
398 downloaded_package_desc = package_info.PackageInfo(downloaded_package)
400 archive_list = downloaded_package_desc.GetArchiveList()
401 self.assertEqual(len(archive_list), 1,
402 "The downloaded package does not have 1 archive.")
403 self.assertTrue(archive_list[0].GetArchiveData().url,
404 "The downloaded archive still does not have a proper URL")
406 def test_ExtractPackageTargets(self):
407 # Tests that we can extract package targets from the tar directory properly.
408 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
409 mock_file1 = self.GenerateMockFile(work_dir, mock_file='mockfile1.txt')
410 mock_file2 = self.GenerateMockFile(work_dir, mock_file='mockfile2.txt')
411 mock_file3 = self.GenerateMockFile(work_dir, mock_file='mockfile3.txt')
413 tar_dir = os.path.join(work_dir, 'tar_dir')
414 dest_dir = os.path.join(work_dir, 'dest_dir')
415 package_target = 'custom_package_target'
416 package_name = 'custom_package'
417 package_revision = 10
419 mock_tar1 = package_locations.GetLocalPackageArchiveFile(
425 os.makedirs(os.path.dirname(mock_tar1))
426 with tarfile.TarFile(mock_tar1, 'w') as f:
427 f.add(mock_file1, arcname=os.path.basename(mock_file1))
429 mock_tar2 = package_locations.GetLocalPackageArchiveFile(
435 with tarfile.TarFile(mock_tar2, 'w') as f:
436 f.add(mock_file2, arcname=os.path.basename(mock_file2))
438 mock_tar3 = package_locations.GetLocalPackageArchiveFile(
444 with tarfile.TarFile(mock_tar3, 'w') as f:
445 arcname = os.path.join('rel_dir', os.path.basename(mock_file3))
446 f.add(mock_file3, arcname=arcname)
448 package_desc = self.GeneratePackageInfo(
449 [mock_tar1, mock_tar2, mock_tar3],
450 dir_dict={mock_tar2: 'tar2_dir'},
451 src_dir_dict={mock_tar3: 'rel_dir'},
453 package_file = package_locations.GetLocalPackageFile(
458 package_desc.SavePackageFile(package_file)
460 package_version.ExtractPackageTargets(
461 [(package_target, package_name)],
464 downloader=self._fake_downloader.Download
466 self.assertEqual(self._fake_downloader.GetDownloadCount(), 0,
467 "Extracting a package should not download anything.")
469 full_dest_dir = package_locations.GetFullDestDir(
474 dest_mock_file1 = os.path.join(
476 os.path.basename(mock_file1)
478 dest_mock_file2 = os.path.join(
481 os.path.basename(mock_file2)
483 dest_mock_file3 = os.path.join(
485 os.path.basename(mock_file3)
488 with open(mock_file1, 'rb') as f:
489 mock_contents1 = f.read()
490 with open(mock_file2, 'rb') as f:
491 mock_contents2 = f.read()
492 with open(mock_file3, 'rb') as f:
493 mock_contents3 = f.read()
494 with open(dest_mock_file1, 'rb') as f:
495 dest_mock_contents1 = f.read()
496 with open(dest_mock_file2, 'rb') as f:
497 dest_mock_contents2 = f.read()
498 with open(dest_mock_file3, 'rb') as f:
499 dest_mock_contents3 = f.read()
501 self.assertEqual(mock_contents1, dest_mock_contents1)
502 self.assertEqual(mock_contents2, dest_mock_contents2)
503 self.assertEqual(mock_contents3, dest_mock_contents3)
505 def test_DownloadMismatchArchiveUponExtraction(self):
506 # Tests that mismatching archive files are downloaded upon extraction.
507 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
508 mock_file1 = self.GenerateMockFile(work_dir, mock_file='mockfile1.txt')
509 mock_file2 = self.GenerateMockFile(work_dir, mock_file='mockfile2.txt')
511 tar_dir = os.path.join(work_dir, 'tar_dir')
512 dest_dir = os.path.join(work_dir, 'dest_dir')
513 mock_tars_dir = os.path.join(work_dir, 'mock_tars')
514 package_target = 'custom_package_target'
515 package_name = 'custom_package'
516 package_revision = 10
518 # Create mock tars and mock URLS where the tars can be downloaded from.
519 os.makedirs(mock_tars_dir)
520 mock_tar1 = os.path.join(mock_tars_dir, 'mock1.tar')
521 mock_url1 = 'https://www.mock.com/tar1.tar'
522 with tarfile.TarFile(mock_tar1, 'w') as f:
523 f.add(mock_file1, arcname=os.path.basename(mock_file1))
524 self._fake_downloader.StoreURL(mock_url1, mock_tar1)
526 mock_tar2 = os.path.join(mock_tars_dir, 'mock2.tar')
527 mock_url2 = 'https://www.mock.com/tar2.tar'
528 with tarfile.TarFile(mock_tar2, 'w') as f:
529 f.add(mock_file2, arcname=os.path.basename(mock_file2))
530 self._fake_downloader.StoreURL(mock_url2, mock_tar2)
532 # Have tar1 be missing, have tar2 be a file with invalid data.
533 mismatch_tar2 = package_locations.GetLocalPackageArchiveFile(
539 os.makedirs(os.path.dirname(mismatch_tar2))
540 with open(mismatch_tar2, 'wb') as f:
541 f.write('mismatch tar')
543 package_desc = self.GeneratePackageInfo(
544 [mock_tar1, mock_tar2],
545 url_dict= {mock_tar1: mock_url1, mock_tar2: mock_url2}
547 package_file = package_locations.GetLocalPackageFile(
552 package_desc.SavePackageFile(package_file)
554 package_version.ExtractPackageTargets(
555 [(package_target, package_name)],
558 downloader=self._fake_downloader.Download
560 self.assertEqual(self._fake_downloader.GetDownloadCount(), 2,
561 "Expected to download exactly 2 mismatched archives.")
563 full_dest_dir = package_locations.GetFullDestDir(
569 dest_mock_file2 = os.path.join(
571 os.path.basename(mock_file2)
573 dest_mock_file1 = os.path.join(
575 os.path.basename(mock_file1)
578 with open(mock_file1, 'rb') as f:
579 mock_contents1 = f.read()
580 with open(mock_file2, 'rb') as f:
581 mock_contents2 = f.read()
582 with open(dest_mock_file1, 'rb') as f:
583 dest_mock_contents1 = f.read()
584 with open(dest_mock_file2, 'rb') as f:
585 dest_mock_contents2 = f.read()
587 self.assertEqual(mock_contents1, dest_mock_contents1)
588 self.assertEqual(mock_contents2, dest_mock_contents2)
591 if __name__ == '__main__':