Home | History | Annotate | Download | only in server2
      1 #!/usr/bin/env python
      2 # Copyright 2013 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 unittest
      7 
      8 from app_yaml_helper import AppYamlHelper
      9 from content_providers import IgnoreMissingContentProviders
     10 from cron_servlet import CronServlet
     11 from empty_dir_file_system import EmptyDirFileSystem
     12 from environment import GetAppVersion
     13 from extensions_paths import (
     14     APP_YAML, CONTENT_PROVIDERS, CHROME_EXTENSIONS, PUBLIC_TEMPLATES, SERVER2,
     15     STATIC_DOCS)
     16 from gcs_file_system_provider import CloudStorageFileSystemProvider
     17 from github_file_system_provider import GithubFileSystemProvider
     18 from host_file_system_provider import HostFileSystemProvider
     19 from local_file_system import LocalFileSystem
     20 from mock_file_system import MockFileSystem
     21 from servlet import Request
     22 from test_branch_utility import TestBranchUtility
     23 from test_file_system import MoveTo, TestFileSystem
     24 from test_util import EnableLogging, ReadFile
     25 
     26 
     27 # NOTE(kalman): The ObjectStore created by the CronServlet is backed onto our
     28 # fake AppEngine memcache/datastore, so the tests aren't isolated. Of course,
     29 # if the host file systems have different identities, they will be, sort of.
     30 class _TestDelegate(CronServlet.Delegate):
     31   def __init__(self, create_file_system):
     32     self.file_systems = []
     33     # A callback taking a revision and returning a file system.
     34     self._create_file_system = create_file_system
     35     self._app_version = GetAppVersion()
     36 
     37   def CreateBranchUtility(self, object_store_creator):
     38     return TestBranchUtility.CreateWithCannedData()
     39 
     40   def CreateHostFileSystemProvider(self,
     41                                   object_store_creator,
     42                                   max_trunk_revision=None):
     43     def constructor(branch=None, revision=None):
     44       file_system = self._create_file_system(revision)
     45       self.file_systems.append(file_system)
     46       return file_system
     47     return HostFileSystemProvider(object_store_creator,
     48                                   max_trunk_revision=max_trunk_revision,
     49                                   constructor_for_test=constructor)
     50 
     51   def CreateGithubFileSystemProvider(self, object_store_creator):
     52     return GithubFileSystemProvider.ForEmpty()
     53 
     54   def CreateGCSFileSystemProvider(self, object_store_creator):
     55     return CloudStorageFileSystemProvider.ForEmpty()
     56 
     57   def GetAppVersion(self):
     58     return self._app_version
     59 
     60   # (non-Delegate method).
     61   def SetAppVersion(self, app_version):
     62     self._app_version = app_version
     63 
     64 class CronServletTest(unittest.TestCase):
     65   @EnableLogging('info')
     66   def testEverything(self):
     67     # All these tests are dependent (see above comment) so lump everything in
     68     # the one test.
     69     delegate = _TestDelegate(lambda _: MockFileSystem(LocalFileSystem.Create()))
     70 
     71     # Test that the cron runs successfully.
     72     response = CronServlet(Request.ForTest('trunk'),
     73                            delegate_for_test=delegate).Get()
     74     self.assertEqual(200, response.status)
     75 
     76     # Save the file systems created, start with a fresh set for the next run.
     77     first_run_file_systems = delegate.file_systems[:]
     78     delegate.file_systems[:] = []
     79 
     80     # When re-running, all file systems should be Stat()d the same number of
     81     # times, but the second round shouldn't have been re-Read() since the
     82     # Stats haven't changed.
     83     response = CronServlet(Request.ForTest('trunk'),
     84                            delegate_for_test=delegate).Get()
     85     self.assertEqual(200, response.status)
     86 
     87     self.assertEqual(len(first_run_file_systems), len(delegate.file_systems))
     88     for i, second_run_file_system in enumerate(delegate.file_systems):
     89       self.assertTrue(*second_run_file_system.CheckAndReset(
     90           read_count=0,
     91           stat_count=first_run_file_systems[i].GetStatCount()))
     92 
     93   @IgnoreMissingContentProviders
     94   def testSafeRevision(self):
     95     test_data = {
     96       'api': {
     97         '_api_features.json': '{}',
     98         '_manifest_features.json': '{}',
     99         '_permission_features.json': '{}',
    100       },
    101       'docs': {
    102         'examples': {
    103           'examples.txt': 'examples.txt contents'
    104         },
    105         'server2': {
    106           'app.yaml': AppYamlHelper.GenerateAppYaml('2-0-8')
    107         },
    108         'static': {
    109           'static.txt': 'static.txt contents'
    110         },
    111         'templates': {
    112           'articles': {
    113             'activeTab.html': 'activeTab.html contents'
    114           },
    115           'intros': {
    116             'browserAction.html': 'activeTab.html contents'
    117           },
    118           'private': {
    119             'table_of_contents.html': 'table_of_contents.html contents',
    120           },
    121           'public': {
    122             'apps': {
    123               'storage.html': '<h1>storage.html</h1> contents'
    124             },
    125             'extensions': {
    126               'storage.html': '<h1>storage.html</h1> contents'
    127             },
    128           },
    129           'json': {
    130             'chrome_sidenav.json': '{}',
    131             'content_providers.json': ReadFile(CONTENT_PROVIDERS),
    132             'manifest.json': '{}',
    133             'permissions.json': '{}',
    134             'strings.json': '{}',
    135             'whats_new.json': '{}',
    136           },
    137         }
    138       }
    139     }
    140 
    141     updates = []
    142 
    143     def app_yaml_update(version):
    144       return MoveTo(SERVER2, {
    145         'app.yaml': AppYamlHelper.GenerateAppYaml(version)
    146       })
    147     def storage_html_update(update):
    148       return MoveTo(PUBLIC_TEMPLATES, {
    149         'apps': {'storage.html': update}
    150       })
    151     def static_txt_update(update):
    152       return MoveTo(STATIC_DOCS, {
    153         'static.txt': update
    154       })
    155 
    156     storage_html_path = PUBLIC_TEMPLATES + 'apps/storage.html'
    157     static_txt_path = STATIC_DOCS + 'static.txt'
    158 
    159     def create_file_system(revision=None):
    160       '''Creates a MockFileSystem at |revision| by applying that many |updates|
    161       to it.
    162       '''
    163       mock_file_system = MockFileSystem(
    164           TestFileSystem(test_data, relative_to=CHROME_EXTENSIONS))
    165       updates_for_revision = (
    166           updates if revision is None else updates[:int(revision)])
    167       for update in updates_for_revision:
    168         mock_file_system.Update(update)
    169       return mock_file_system
    170 
    171     delegate = _TestDelegate(create_file_system)
    172     delegate.SetAppVersion('2-0-8')
    173 
    174     file_systems = delegate.file_systems
    175 
    176     # No updates applied yet.
    177     CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
    178     self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
    179                      file_systems[-1].ReadSingle(APP_YAML).Get())
    180     self.assertEqual('<h1>storage.html</h1> contents',
    181                      file_systems[-1].ReadSingle(storage_html_path).Get())
    182 
    183     # Apply updates to storage.html.
    184     updates.append(storage_html_update('interim contents'))
    185     updates.append(storage_html_update('<h1>new</h1> contents'))
    186 
    187     CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
    188     self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
    189                      file_systems[-1].ReadSingle(APP_YAML).Get())
    190     self.assertEqual('<h1>new</h1> contents',
    191                      file_systems[-1].ReadSingle(storage_html_path).Get())
    192 
    193     # Apply several updates to storage.html and app.yaml. The file system
    194     # should be pinned at the version before app.yaml changed.
    195     updates.append(storage_html_update('<h1>stuck here</h1> contents'))
    196 
    197     double_update = storage_html_update('<h1>newer</h1> contents')
    198     double_update.update(app_yaml_update('2-0-10'))
    199     updates.append(double_update)
    200 
    201     updates.append(storage_html_update('never gonna reach here'))
    202 
    203     CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
    204     self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
    205                      file_systems[-1].ReadSingle(APP_YAML).Get())
    206     self.assertEqual('<h1>stuck here</h1> contents',
    207                      file_systems[-1].ReadSingle(storage_html_path).Get())
    208 
    209     # Further pushes to storage.html will keep it pinned.
    210     updates.append(storage_html_update('<h1>y</h1> u not update!'))
    211 
    212     CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
    213     self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
    214                      file_systems[-1].ReadSingle(APP_YAML).Get())
    215     self.assertEqual('<h1>stuck here</h1> contents',
    216                      file_systems[-1].ReadSingle(storage_html_path).Get())
    217 
    218     # Likewise app.yaml.
    219     updates.append(app_yaml_update('2-1-0'))
    220 
    221     CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
    222     self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
    223                      file_systems[-1].ReadSingle(APP_YAML).Get())
    224     self.assertEqual('<h1>stuck here</h1> contents',
    225                      file_systems[-1].ReadSingle(storage_html_path).Get())
    226 
    227     # And updates to other content won't happen either.
    228     updates.append(static_txt_update('important content!'))
    229 
    230     CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
    231     self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
    232                      file_systems[-1].ReadSingle(APP_YAML).Get())
    233     self.assertEqual('<h1>stuck here</h1> contents',
    234                      file_systems[-1].ReadSingle(storage_html_path).Get())
    235     self.assertEqual('static.txt contents',
    236                      file_systems[-1].ReadSingle(static_txt_path).Get())
    237 
    238     # Lastly - when the app version changes, everything should no longer be
    239     # pinned.
    240     delegate.SetAppVersion('2-1-0')
    241     CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
    242     self.assertEqual(AppYamlHelper.GenerateAppYaml('2-1-0'),
    243                      file_systems[-1].ReadSingle(APP_YAML).Get())
    244     self.assertEqual('<h1>y</h1> u not update!',
    245                      file_systems[-1].ReadSingle(storage_html_path).Get())
    246     self.assertEqual('important content!',
    247                      file_systems[-1].ReadSingle(static_txt_path).Get())
    248 
    249 
    250 if __name__ == '__main__':
    251   unittest.main()
    252