1#!/usr/bin/env python 2# Copyright (c) 2012 The Chromium 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. 5 6import copy 7import datetime 8import hashlib 9import logging 10import os 11import posixpath 12import subprocess 13import sys 14import tempfile 15import unittest 16import urlparse 17 18SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 19BUILD_TOOLS_DIR = os.path.dirname(SCRIPT_DIR) 20 21sys.path.append(BUILD_TOOLS_DIR) 22import manifest_util 23import update_nacl_manifest 24from update_nacl_manifest import CANARY_BUNDLE_NAME, BIONIC_CANARY_BUNDLE_NAME 25 26 27HTTPS_BASE_URL = 'https://storage.googleapis.com' \ 28 '/nativeclient_mirror/nacl/nacl_sdk/' 29 30OS_CR = ('cros',) 31OS_L = ('linux',) 32OS_M = ('mac',) 33OS_ML = ('mac', 'linux') 34OS_MW = ('mac', 'win') 35OS_LW = ('linux', 'win') 36OS_MLW = ('mac', 'linux', 'win') 37OS_ALL = ('all',) 38POST_STABLE = 'post_stable' 39STABLE = 'stable' 40BETA = 'beta' 41DEV = 'dev' 42CANARY = 'canary' 43 44 45def GetArchiveURL(basename, version): 46 return urlparse.urljoin(HTTPS_BASE_URL, posixpath.join(version, basename)) 47 48 49def GetPlatformArchiveUrl(host_os, version): 50 basename = 'naclsdk_%s.tar.bz2' % (host_os,) 51 return GetArchiveURL(basename, version) 52 53 54def GetBionicArchiveUrl(version): 55 basename = 'naclsdk_bionic.tar.bz2' 56 return GetArchiveURL(basename, version) 57 58 59def MakeGsUrl(rel_path): 60 return update_nacl_manifest.GS_BUCKET_PATH + rel_path 61 62 63def GetPathFromGsUrl(url): 64 assert url.startswith(update_nacl_manifest.GS_BUCKET_PATH) 65 return url[len(update_nacl_manifest.GS_BUCKET_PATH):] 66 67 68def GetPathFromHttpsUrl(url): 69 assert url.startswith(HTTPS_BASE_URL) 70 return url[len(HTTPS_BASE_URL):] 71 72 73def MakeArchive(url, host_os): 74 archive = manifest_util.Archive(host_os) 75 archive.url = url 76 # dummy values that won't succeed if we ever use them, but will pass 77 # validation. :) 78 archive.checksum = {'sha1': 'foobar'} 79 archive.size = 1 80 return archive 81 82 83def MakePlatformArchive(host_os, version): 84 return MakeArchive(GetPlatformArchiveUrl(host_os, version), host_os) 85 86 87def MakeBionicArchive(host_os, version): 88 return MakeArchive(GetBionicArchiveUrl(version), host_os) 89 90 91def MakeNonPlatformArchive(basename, version): 92 return MakeArchive(GetArchiveURL(basename, version), 'all') 93 94 95def MakeNonPepperBundle(name, with_archives=False): 96 bundle = manifest_util.Bundle(name) 97 bundle.version = 1 98 bundle.revision = 1 99 bundle.description = 'Dummy bundle' 100 bundle.recommended = 'yes' 101 bundle.stability = 'stable' 102 103 if with_archives: 104 for host_os in OS_MLW: 105 archive = manifest_util.Archive(host_os) 106 archive.url = 'http://example.com' 107 archive.checksum = {'sha1': 'blah'} 108 archive.size = 2 109 bundle.AddArchive(archive) 110 return bundle 111 112 113def MakePepperBundle(major_version, revision=0, version=None, stability='dev', 114 bundle_name=None): 115 assert (version is None or 116 version.split('.')[0] == 'trunk' or 117 version.split('.')[0] == str(major_version)) 118 if not bundle_name: 119 bundle_name = 'pepper_' + str(major_version) 120 121 bundle = manifest_util.Bundle(bundle_name) 122 bundle.version = major_version 123 bundle.revision = revision 124 bundle.description = 'Chrome %s bundle, revision %s' % (major_version, 125 revision) 126 bundle.repath = 'pepper_' + str(major_version) 127 bundle.recommended = 'no' 128 bundle.stability = stability 129 130 return bundle 131 132 133def MakePlatformBundle(major_version, revision=0, version=None, host_oses=None, 134 stability='dev'): 135 bundle = MakePepperBundle(major_version, revision, version, stability) 136 137 if host_oses: 138 for host_os in host_oses: 139 bundle.AddArchive(MakePlatformArchive(host_os, version)) 140 141 return bundle 142 143 144def MakeBionicBundle(major_version, revision=0, version=None, host_oses=None): 145 bundle = MakePepperBundle(major_version, revision, version, 'dev') 146 147 if host_oses: 148 for host_os in host_oses: 149 bundle.AddArchive(MakeBionicArchive(host_os, version)) 150 151 return bundle 152 153 154class MakeManifest(manifest_util.SDKManifest): 155 def __init__(self, *args): 156 manifest_util.SDKManifest.__init__(self) 157 158 for bundle in args: 159 self.AddBundle(bundle) 160 161 def AddBundle(self, bundle): 162 self.MergeBundle(bundle, allow_existing=False) 163 164 165class MakeHistory(object): 166 def __init__(self): 167 # used for a dummy timestamp 168 self.datetime = datetime.datetime.utcnow() 169 self.history = [] 170 171 def Add(self, host_oses, channel, version): 172 for host_os in host_oses: 173 timestamp = self.datetime.strftime('%Y-%m-%d %H:%M:%S.%f') 174 self.history.append((host_os, channel, version, timestamp)) 175 self.datetime += datetime.timedelta(0, -3600) # one hour earlier 176 self.datetime += datetime.timedelta(-1) # one day earlier 177 178 179class MakeFiles(dict): 180 def AddOnlineManifest(self, manifest_string): 181 self['naclsdk_manifest2.json'] = manifest_string 182 183 def Add(self, bundle, add_archive_for_os=OS_MLW, add_json_for_os=OS_MLW): 184 for archive in bundle.GetArchives(): 185 if not archive.host_os in add_archive_for_os: 186 continue 187 188 self.AddArchive(bundle, archive, archive.host_os in add_json_for_os) 189 190 def AddArchive(self, bundle, archive, add_json=True): 191 path = GetPathFromHttpsUrl(archive.url) 192 self[path] = 'My Dummy archive' 193 194 if add_json: 195 # add .json manifest snippet, it should look like a normal Bundle, but 196 # only has one archive. 197 new_bundle = manifest_util.Bundle('') 198 new_bundle.CopyFrom(bundle) 199 del new_bundle.archives[:] 200 new_bundle.AddArchive(archive) 201 self[path + '.json'] = new_bundle.GetDataAsString() 202 203 204class TestDelegate(update_nacl_manifest.Delegate): 205 def __init__(self, manifest, history, files): 206 self.manifest = manifest 207 self.history = history 208 self.files = files 209 self.dryrun = 0 210 self.called_gsutil_cp = False 211 self.called_sendmail = False 212 213 def GetRepoManifest(self): 214 return self.manifest 215 216 def GetHistory(self): 217 return self.history 218 219 def GsUtil_ls(self, url): 220 path = GetPathFromGsUrl(url) 221 result = [] 222 for filename in self.files.iterkeys(): 223 if not filename.startswith(path): 224 continue 225 226 # Find the first slash after the prefix (path). 227 # +1, because if the slash is directly after path, then we want to find 228 # the following slash anyway. 229 slash = filename.find('/', len(path) + 1) 230 231 if slash != -1: 232 filename = filename[:slash] 233 234 result.append(MakeGsUrl(filename)) 235 236 # Remove dupes. 237 return list(set(result)) 238 239 def GsUtil_cat(self, url): 240 path = GetPathFromGsUrl(url) 241 if path not in self.files: 242 raise subprocess.CalledProcessError(1, 'gsutil cat %s' % (url,)) 243 return self.files[path] 244 245 def GsUtil_cp(self, src, dest, stdin=None): 246 self.called_gsutil_cp = True 247 dest_path = GetPathFromGsUrl(dest) 248 if src == '-': 249 self.files[dest_path] = stdin 250 else: 251 src_path = GetPathFromGsUrl(src) 252 if src_path not in self.files: 253 raise subprocess.CalledProcessError(1, 'gsutil cp %s %s' % (src, dest)) 254 self.files[dest_path] = self.files[src_path] 255 256 def SendMail(self, subject, text): 257 self.called_sendmail = True 258 259 260# Shorthand for premade bundles/versions 261V18_0_1025_163 = '18.0.1025.163' 262V18_0_1025_175 = '18.0.1025.175' 263V18_0_1025_184 = '18.0.1025.184' 264V19_0_1084_41 = '19.0.1084.41' 265V19_0_1084_67 = '19.0.1084.67' 266V21_0_1145_0 = '21.0.1145.0' 267V21_0_1166_0 = '21.0.1166.0' 268V26_0_1386_0 = '26.0.1386.0' 269V26_0_1386_1 = '26.0.1386.1' 270V37_0_2054_0 = '37.0.2054.0' 271VTRUNK_140819 = 'trunk.140819' 272VTRUNK_277776 = 'trunk.277776' 273B18_0_1025_163_MLW = MakePlatformBundle(18, 132135, V18_0_1025_163, OS_MLW) 274B18_0_1025_184_MLW = MakePlatformBundle(18, 134900, V18_0_1025_184, OS_MLW) 275B18_NONE = MakePlatformBundle(18) 276B19_0_1084_41_MLW = MakePlatformBundle(19, 134854, V19_0_1084_41, OS_MLW) 277B19_0_1084_67_MLW = MakePlatformBundle(19, 142000, V19_0_1084_67, OS_MLW) 278B19_NONE = MakePlatformBundle(19) 279BCANARY_NONE = MakePepperBundle(0, stability=CANARY, 280 bundle_name=CANARY_BUNDLE_NAME) 281B21_0_1145_0_MLW = MakePlatformBundle(21, 138079, V21_0_1145_0, OS_MLW) 282B21_0_1166_0_MW = MakePlatformBundle(21, 140819, V21_0_1166_0, OS_MW) 283B26_NONE = MakePlatformBundle(26) 284B26_0_1386_0_MLW = MakePlatformBundle(26, 177362, V26_0_1386_0, OS_MLW) 285B26_0_1386_1_MLW = MakePlatformBundle(26, 177439, V26_0_1386_1, OS_MLW) 286BTRUNK_140819_MLW = MakePlatformBundle(21, 140819, VTRUNK_140819, OS_MLW) 287BBIONIC_NONE = MakePepperBundle(0, stability=CANARY, 288 bundle_name=BIONIC_CANARY_BUNDLE_NAME) 289BBIONIC_TRUNK_277776 = MakeBionicBundle(37, 277776, VTRUNK_277776, OS_L) 290NON_PEPPER_BUNDLE_NOARCHIVES = MakeNonPepperBundle('foo') 291NON_PEPPER_BUNDLE_ARCHIVES = MakeNonPepperBundle('bar', with_archives=True) 292 293 294class TestUpdateManifest(unittest.TestCase): 295 def setUp(self): 296 self.history = MakeHistory() 297 self.files = MakeFiles() 298 self.version_mapping = {} 299 self.delegate = None 300 self.uploaded_manifest = None 301 self.manifest = None 302 303 def _MakeDelegate(self): 304 self.delegate = TestDelegate(self.manifest, self.history.history, 305 self.files) 306 307 def _Run(self, host_oses, extra_archives=None, fixed_bundle_versions=None): 308 update_nacl_manifest.Run(self.delegate, host_oses, extra_archives, 309 fixed_bundle_versions) 310 311 def _HasUploadedManifest(self): 312 return 'naclsdk_manifest2.json' in self.files 313 314 def _ReadUploadedManifest(self): 315 self.uploaded_manifest = manifest_util.SDKManifest() 316 self.uploaded_manifest.LoadDataFromString( 317 self.files['naclsdk_manifest2.json']) 318 319 def _AssertUploadedManifestHasBundle(self, bundle, stability, 320 bundle_name=None): 321 if not bundle_name: 322 bundle_name = bundle.name 323 324 uploaded_manifest_bundle = self.uploaded_manifest.GetBundle(bundle_name) 325 # Bundles that we create in the test (and in the manifest snippets) have 326 # their stability set to "dev". update_nacl_manifest correctly updates it. 327 # So we have to force the stability of |bundle| so they compare equal. 328 test_bundle = copy.copy(bundle) 329 test_bundle.stability = stability 330 if bundle_name: 331 test_bundle.name = bundle_name 332 self.assertEqual(uploaded_manifest_bundle, test_bundle) 333 334 def _AddCsvHistory(self, history): 335 import csv 336 import cStringIO 337 history_stream = cStringIO.StringIO(history) 338 self.history.history = [(platform, channel, version, date) 339 for platform, channel, version, date in csv.reader(history_stream)] 340 341 def testNoUpdateNeeded(self): 342 self.manifest = MakeManifest(B18_0_1025_163_MLW) 343 self._MakeDelegate() 344 self._Run(OS_MLW) 345 self.assertFalse(self._HasUploadedManifest()) 346 347 # Add another bundle, make sure it still doesn't update 348 self.manifest.AddBundle(B19_0_1084_41_MLW) 349 self._Run(OS_MLW) 350 self.assertFalse(self._HasUploadedManifest()) 351 352 def testSimpleUpdate(self): 353 self.manifest = MakeManifest(B18_NONE) 354 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 355 self.files.Add(B18_0_1025_163_MLW) 356 self._MakeDelegate() 357 self._Run(OS_MLW) 358 self._ReadUploadedManifest() 359 self._AssertUploadedManifestHasBundle(B18_0_1025_163_MLW, BETA) 360 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 361 362 def testOnePlatformHasNewerRelease(self): 363 self.manifest = MakeManifest(B18_NONE) 364 self.history.Add(OS_M, BETA, V18_0_1025_175) # Mac has newer version 365 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 366 self.files.Add(B18_0_1025_163_MLW) 367 self._MakeDelegate() 368 self._Run(OS_MLW) 369 self._ReadUploadedManifest() 370 self._AssertUploadedManifestHasBundle(B18_0_1025_163_MLW, BETA) 371 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 372 373 def testMultipleMissingPlatformsInHistory(self): 374 self.manifest = MakeManifest(B18_NONE) 375 self.history.Add(OS_ML, BETA, V18_0_1025_184) 376 self.history.Add(OS_M, BETA, V18_0_1025_175) 377 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 378 self.files.Add(B18_0_1025_163_MLW) 379 self._MakeDelegate() 380 self._Run(OS_MLW) 381 self._ReadUploadedManifest() 382 self._AssertUploadedManifestHasBundle(B18_0_1025_163_MLW, BETA) 383 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 384 385 def testUpdateOnlyOneBundle(self): 386 self.manifest = MakeManifest(B18_NONE, B19_0_1084_41_MLW) 387 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 388 self.files.Add(B18_0_1025_163_MLW) 389 self._MakeDelegate() 390 self._Run(OS_MLW) 391 self._ReadUploadedManifest() 392 self._AssertUploadedManifestHasBundle(B18_0_1025_163_MLW, BETA) 393 self._AssertUploadedManifestHasBundle(B19_0_1084_41_MLW, DEV) 394 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 2) 395 396 def testUpdateTwoBundles(self): 397 self.manifest = MakeManifest(B18_NONE, B19_NONE) 398 self.history.Add(OS_MLW, DEV, V19_0_1084_41) 399 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 400 self.files.Add(B18_0_1025_163_MLW) 401 self.files.Add(B19_0_1084_41_MLW) 402 self._MakeDelegate() 403 self._Run(OS_MLW) 404 self._ReadUploadedManifest() 405 self._AssertUploadedManifestHasBundle(B18_0_1025_163_MLW, BETA) 406 self._AssertUploadedManifestHasBundle(B19_0_1084_41_MLW, DEV) 407 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 2) 408 409 def testUpdateWithMissingPlatformsInArchives(self): 410 self.manifest = MakeManifest(B18_NONE) 411 self.history.Add(OS_MLW, BETA, V18_0_1025_184) 412 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 413 self.files.Add(B18_0_1025_184_MLW, add_archive_for_os=OS_M) 414 self.files.Add(B18_0_1025_163_MLW) 415 self._MakeDelegate() 416 self._Run(OS_MLW) 417 self._ReadUploadedManifest() 418 self._AssertUploadedManifestHasBundle(B18_0_1025_163_MLW, BETA) 419 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 420 421 def testUpdateWithMissingManifestSnippets(self): 422 self.manifest = MakeManifest(B18_NONE) 423 self.history.Add(OS_MLW, BETA, V18_0_1025_184) 424 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 425 self.files.Add(B18_0_1025_184_MLW, add_json_for_os=OS_ML) 426 self.files.Add(B18_0_1025_163_MLW) 427 self._MakeDelegate() 428 self._Run(OS_MLW) 429 self._ReadUploadedManifest() 430 self._AssertUploadedManifestHasBundle(B18_0_1025_163_MLW, BETA) 431 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 432 433 def testRecommendedIsStable(self): 434 for channel in STABLE, BETA, DEV, CANARY: 435 self.setUp() 436 bundle = copy.deepcopy(B18_NONE) 437 self.manifest = MakeManifest(bundle) 438 self.history.Add(OS_MLW, channel, V18_0_1025_163) 439 self.files.Add(B18_0_1025_163_MLW) 440 self._MakeDelegate() 441 self._Run(OS_MLW) 442 self._ReadUploadedManifest() 443 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 444 uploaded_bundle = self.uploaded_manifest.GetBundle('pepper_18') 445 if channel == STABLE: 446 self.assertEqual(uploaded_bundle.recommended, 'yes') 447 else: 448 self.assertEqual(uploaded_bundle.recommended, 'no') 449 450 def testNoUpdateWithNonPepperBundle(self): 451 self.manifest = MakeManifest(NON_PEPPER_BUNDLE_NOARCHIVES, 452 B18_0_1025_163_MLW) 453 self._MakeDelegate() 454 self._Run(OS_MLW) 455 self.assertFalse(self._HasUploadedManifest()) 456 457 def testUpdateWithHistoryWithExtraneousPlatforms(self): 458 self.manifest = MakeManifest(B18_NONE) 459 self.history.Add(OS_ML, BETA, V18_0_1025_184) 460 self.history.Add(OS_CR, BETA, V18_0_1025_184) 461 self.history.Add(OS_CR, BETA, V18_0_1025_175) 462 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 463 self.files.Add(B18_0_1025_163_MLW) 464 self._MakeDelegate() 465 self._Run(OS_MLW) 466 self._ReadUploadedManifest() 467 self._AssertUploadedManifestHasBundle(B18_0_1025_163_MLW, BETA) 468 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 469 470 def testSnippetWithStringRevisionAndVersion(self): 471 # This test exists because some manifest snippets were uploaded with 472 # strings for their revisions and versions. I want to make sure the 473 # resulting manifest is still consistent with the old format. 474 self.manifest = MakeManifest(B18_NONE) 475 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 476 bundle_string_revision = MakePlatformBundle('18', '1234', V18_0_1025_163, 477 OS_MLW) 478 self.files.Add(bundle_string_revision) 479 self._MakeDelegate() 480 self._Run(OS_MLW) 481 self._ReadUploadedManifest() 482 uploaded_bundle = self.uploaded_manifest.GetBundle( 483 bundle_string_revision.name) 484 self.assertEqual(uploaded_bundle.revision, 1234) 485 self.assertEqual(uploaded_bundle.version, 18) 486 487 def testUpdateCanary(self): 488 self.manifest = MakeManifest(copy.deepcopy(BCANARY_NONE)) 489 self.files.Add(BTRUNK_140819_MLW) 490 self._MakeDelegate() 491 self._Run(OS_MLW) 492 self._ReadUploadedManifest() 493 self._AssertUploadedManifestHasBundle(BTRUNK_140819_MLW, CANARY, 494 bundle_name=CANARY_BUNDLE_NAME) 495 496 def testCanaryShouldOnlyUseCanaryVersions(self): 497 canary_bundle = copy.deepcopy(BCANARY_NONE) 498 self.manifest = MakeManifest(canary_bundle) 499 self.history.Add(OS_MW, CANARY, V21_0_1166_0) 500 self.history.Add(OS_MW, BETA, V19_0_1084_41) 501 self.files.Add(B19_0_1084_41_MLW) 502 self.version_mapping[V21_0_1166_0] = VTRUNK_140819 503 self._MakeDelegate() 504 self.assertRaises(Exception, self._Run, OS_MLW) 505 506 def testExtensionWorksAsBz2(self): 507 # Allow old bundles with just .bz2 extension to work 508 self.manifest = MakeManifest(B18_NONE) 509 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 510 bundle = copy.deepcopy(B18_0_1025_163_MLW) 511 archive_url = bundle.GetArchive('mac').url 512 bundle.GetArchive('mac').url = archive_url.replace('.tar', '') 513 self.files.Add(bundle) 514 self._MakeDelegate() 515 self._Run(OS_MLW) 516 self._ReadUploadedManifest() 517 self._AssertUploadedManifestHasBundle(bundle, BETA) 518 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 519 520 def testOnlyOneStableBundle(self): 521 # Make sure that any bundle that has an older version than STABLE is marked 522 # as POST_STABLE, even if the last version we found was BETA, DEV, etc. 523 for channel in STABLE, BETA, DEV, CANARY: 524 self.setUp() 525 self.manifest = MakeManifest(B18_NONE, B19_NONE) 526 self.history.Add(OS_MLW, channel, V18_0_1025_163) 527 self.history.Add(OS_MLW, STABLE, V19_0_1084_41) 528 self.files.Add(B18_0_1025_163_MLW) 529 self.files.Add(B19_0_1084_41_MLW) 530 self._MakeDelegate() 531 self._Run(OS_MLW) 532 self._ReadUploadedManifest() 533 p18_bundle = self.uploaded_manifest.GetBundle(B18_NONE.name) 534 self.assertEqual(p18_bundle.stability, POST_STABLE) 535 self.assertEqual(p18_bundle.recommended, 'no') 536 p19_bundle = self.uploaded_manifest.GetBundle(B19_NONE.name) 537 self.assertEqual(p19_bundle.stability, STABLE) 538 self.assertEqual(p19_bundle.recommended, 'yes') 539 540 def testDontPushIfNoChange(self): 541 # Make an online manifest that already has this bundle. 542 online_manifest = MakeManifest(B18_0_1025_163_MLW) 543 self.files.AddOnlineManifest(online_manifest.GetDataAsString()) 544 545 self.manifest = MakeManifest(B18_NONE) 546 self.history.Add(OS_MLW, DEV, V18_0_1025_163) 547 self.files.Add(B18_0_1025_163_MLW) 548 549 self._MakeDelegate() 550 self._Run(OS_MLW) 551 self.assertFalse(self.delegate.called_gsutil_cp) 552 553 def testDontPushIfRollback(self): 554 # Make an online manifest that has a newer bundle 555 online_manifest = MakeManifest(B18_0_1025_184_MLW) 556 self.files.AddOnlineManifest(online_manifest.GetDataAsString()) 557 558 self.manifest = MakeManifest(B18_NONE) 559 self.history.Add(OS_MLW, DEV, V18_0_1025_163) 560 self.files.Add(B18_0_1025_163_MLW) 561 562 self._MakeDelegate() 563 self._Run(OS_MLW) 564 self.assertFalse(self.delegate.called_gsutil_cp) 565 566 def testRunWithFixedBundleVersions(self): 567 self.manifest = MakeManifest(B18_NONE) 568 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 569 self.files.Add(B18_0_1025_163_MLW) 570 self.files.Add(B18_0_1025_184_MLW) 571 572 self._MakeDelegate() 573 self._Run(OS_MLW, None, [('pepper_18', '18.0.1025.184')]) 574 self._ReadUploadedManifest() 575 self._AssertUploadedManifestHasBundle(B18_0_1025_184_MLW, BETA) 576 self.assertEqual(len(self.uploaded_manifest.GetBundles()), 1) 577 578 def testRunWithMissingFixedBundleVersions(self): 579 self.manifest = MakeManifest(B18_NONE) 580 self.history.Add(OS_MLW, BETA, V18_0_1025_163) 581 self.files.Add(B18_0_1025_163_MLW) 582 583 self._MakeDelegate() 584 self._Run(OS_MLW, None, [('pepper_18', '18.0.1025.184')]) 585 # Nothing should be uploaded if the user gives a missing fixed version. 586 self.assertFalse(self.delegate.called_gsutil_cp) 587 588 def testDontIncludeRandomBundles(self): 589 self.manifest = MakeManifest(B26_NONE) 590 self.history.Add(OS_MLW, BETA, V26_0_1386_0) 591 self.files.Add(B26_0_1386_0_MLW) 592 593 some_other_bundle = MakePepperBundle(26, 1, V26_0_1386_0, BETA) 594 some_other_archive = MakeNonPlatformArchive('some_other.tar.bz2', 595 V26_0_1386_0) 596 some_other_bundle.AddArchive(some_other_archive) 597 self.files.AddArchive(some_other_bundle, some_other_archive) 598 599 self._MakeDelegate() 600 self._Run(OS_MLW) 601 self._ReadUploadedManifest() 602 uploaded_bundle = self.uploaded_manifest.GetBundle('pepper_26') 603 self.assertEqual(1, len(uploaded_bundle.GetHostOSArchives())) 604 605 def testNaclportsBundle(self): 606 self.manifest = MakeManifest(B26_NONE) 607 self.history.Add(OS_MLW, BETA, V26_0_1386_0) 608 self.files.Add(B26_0_1386_0_MLW) 609 610 # NaclPorts "bundle". 611 naclports_bundle = MakePepperBundle(26, 1, V26_0_1386_0, BETA) 612 naclports_archive = MakeNonPlatformArchive('naclports.tar.bz2', 613 V26_0_1386_0) 614 naclports_bundle.AddArchive(naclports_archive) 615 self.files.AddArchive(naclports_bundle, naclports_archive) 616 617 self._MakeDelegate() 618 self._Run(OS_MLW, [('naclports.tar.bz2', '26.0.1386.0')]) 619 self._ReadUploadedManifest() 620 621 uploaded_bundle = self.uploaded_manifest.GetBundle('pepper_26') 622 self.assertEqual(2, len(uploaded_bundle.GetHostOSArchives())) 623 624 def testKeepBundleOrder(self): 625 # This is a regression test: when a bundle is skipped (because it isn't 626 # newer than the online bundle), it was added to the end of the list. 627 628 # Make an online manifest that already has B18. 629 online_manifest = MakeManifest(B18_0_1025_163_MLW) 630 self.files.AddOnlineManifest(online_manifest.GetDataAsString()) 631 632 self.manifest = MakeManifest(B18_NONE, B19_NONE) 633 self.history.Add(OS_MLW, STABLE, V18_0_1025_163) 634 self.history.Add(OS_MLW, STABLE, V19_0_1084_41) 635 self.files.Add(B18_0_1025_163_MLW) 636 self.files.Add(B19_0_1084_41_MLW) 637 638 self._MakeDelegate() 639 self._Run(OS_MLW) 640 self._ReadUploadedManifest() 641 642 # Bundle 18 should be before bundle 19. 643 bundles = self.uploaded_manifest.GetBundles() 644 self.assertEqual(2, len(bundles)) 645 self.assertEqual('pepper_18', bundles[0].name) 646 self.assertEqual('pepper_19', bundles[1].name) 647 648 def testBundleWithoutHistoryUsesOnline(self): 649 online_manifest = MakeManifest(B18_0_1025_163_MLW) 650 self.files.AddOnlineManifest(online_manifest.GetDataAsString()) 651 652 self.manifest = MakeManifest(B18_NONE) 653 654 self._MakeDelegate() 655 # This should not raise. 656 self._Run(OS_MLW) 657 self._ReadUploadedManifest() 658 659 # But it should have sent an email nagging the users to lock this bundle 660 # manually. 661 self.assertTrue(self.delegate.called_sendmail) 662 663 uploaded_bundle = self.uploaded_manifest.GetBundle('pepper_18') 664 self.assertEqual(uploaded_bundle, B18_0_1025_163_MLW) 665 666 def testBundleWithoutHistoryOrOnlineRaises(self): 667 self.manifest = MakeManifest(B18_NONE) 668 self._MakeDelegate() 669 self.assertRaises(update_nacl_manifest.UnknownLockedBundleException, 670 self._Run, OS_MLW) 671 672 def testUpdateBionic(self): 673 bionic_bundle = copy.deepcopy(BBIONIC_NONE) 674 self.manifest = MakeManifest(bionic_bundle) 675 self.history.Add(OS_MW, CANARY, V37_0_2054_0) 676 self.files.Add(BBIONIC_TRUNK_277776) 677 self.version_mapping[V37_0_2054_0] = VTRUNK_277776 678 self._MakeDelegate() 679 self._Run(OS_MLW) 680 self._ReadUploadedManifest() 681 self._AssertUploadedManifestHasBundle(BBIONIC_TRUNK_277776, CANARY, 682 bundle_name=BIONIC_CANARY_BUNDLE_NAME) 683 684 685class TestUpdateVitals(unittest.TestCase): 686 def setUp(self): 687 f = tempfile.NamedTemporaryFile('w', prefix="test_update_nacl_manifest") 688 self.test_file = f.name 689 f.close() 690 test_data = "Some test data" 691 self.sha1 = hashlib.sha1(test_data).hexdigest() 692 self.data_len = len(test_data) 693 with open(self.test_file, 'w') as f: 694 f.write(test_data) 695 696 def tearDown(self): 697 os.remove(self.test_file) 698 699 def testUpdateVitals(self): 700 archive = manifest_util.Archive(manifest_util.GetHostOS()) 701 path = os.path.abspath(self.test_file) 702 if sys.platform == 'win32': 703 # On Windows, the path must start with three slashes, i.e. 704 # (file:///C:\whatever) 705 path = '/' + path 706 archive.url = 'file://' + path 707 708 bundle = MakePlatformBundle(18) 709 bundle.AddArchive(archive) 710 manifest = MakeManifest(bundle) 711 archive = manifest.GetBundles()[0]['archives'][0] 712 713 self.assertTrue('size' not in archive) 714 self.assertTrue('checksum' not in archive) 715 self.assertRaises(manifest_util.Error, manifest.Validate) 716 717 manifest.Validate(add_missing_info=True) 718 719 self.assertEqual(archive['size'], self.data_len) 720 self.assertEqual(archive['checksum']['sha1'], self.sha1) 721 722 723if __name__ == '__main__': 724 logging.basicConfig(level=logging.CRITICAL) 725 # Uncomment the following line to enable more debugging info. 726 # logging.getLogger('update_nacl_manifest').setLevel(logging.INFO) 727 728 sys.exit(unittest.main()) 729