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