Home | History | Annotate | Download | only in tests
      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