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