cron_servlet_test.py revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#!/usr/bin/env python
2b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
3b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
4b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# found in the LICENSE file.
5b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
6b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)import unittest
7b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
8a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)from appengine_wrappers import GetAppVersion
9a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)from app_yaml_helper import AppYamlHelper
10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from cron_servlet import CronServlet
11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from empty_dir_file_system import EmptyDirFileSystem
124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)from host_file_system_provider import HostFileSystemProvider
13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from local_file_system import LocalFileSystem
14b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from mock_file_system import MockFileSystem
15b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from servlet import Request
16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from test_branch_utility import TestBranchUtility
17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from test_file_system import TestFileSystem
18b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)from test_util import EnableLogging
19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)# NOTE(kalman): The ObjectStore created by the CronServlet is backed onto our
21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)# fake AppEngine memcache/datastore, so the tests aren't isolated. Of course,
22a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)# if the host file systems have different identities, they will be, sort of.
23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class _TestDelegate(CronServlet.Delegate):
24a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def __init__(self, create_file_system):
25a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.file_systems = []
26a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # A callback taking a revision and returning a file system.
27a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._create_file_system = create_file_system
28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._app_version = GetAppVersion()
29b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
30b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def CreateBranchUtility(self, object_store_creator):
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return TestBranchUtility.CreateWithCannedData()
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def CreateHostFileSystemProvider(self,
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                  object_store_creator,
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                  max_trunk_revision=None):
36ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    def constructor(branch=None, revision=None):
37ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      file_system = self._create_file_system(revision)
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      self.file_systems.append(file_system)
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return file_system
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return HostFileSystemProvider(object_store_creator,
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 max_trunk_revision=max_trunk_revision,
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                 constructor_for_test=constructor)
43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
44b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def CreateAppSamplesFileSystem(self, object_store_creator):
45b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    return EmptyDirFileSystem()
46b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def GetAppVersion(self):
48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return self._app_version
49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
50a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # (non-Delegate method).
51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def SetAppVersion(self, app_version):
52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._app_version = app_version
53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
54b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)class CronServletTest(unittest.TestCase):
55b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  @EnableLogging('info')
56b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  def testEverything(self):
57b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # All these tests are dependent (see above comment) so lump everything in
58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # the one test.
59ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    delegate = _TestDelegate(lambda _: MockFileSystem(LocalFileSystem.Create()))
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # Test that the cron runs successfully.
62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    response = CronServlet(Request.ForTest('trunk'),
63b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           delegate_for_test=delegate).Get()
64b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    self.assertEqual(200, response.status)
65b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
66ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    # Save the file systems created, start with a fresh set for the next run.
67ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    first_run_file_systems = delegate.file_systems[:]
68ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    delegate.file_systems[:] = []
69ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
70b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # When re-running, all file systems should be Stat()d the same number of
71b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # times, but the second round shouldn't have been re-Read() since the
72b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    # Stats haven't changed.
73b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    response = CronServlet(Request.ForTest('trunk'),
74b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                           delegate_for_test=delegate).Get()
75ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    self.assertEqual(200, response.status)
76ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
77ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    self.assertEqual(len(first_run_file_systems), len(delegate.file_systems))
78ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    for i, second_run_file_system in enumerate(delegate.file_systems):
79ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      self.assertTrue(*second_run_file_system.CheckAndReset(
80ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          read_count=0,
81ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch          stat_count=first_run_file_systems[i].GetStatCount()))
82a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
83a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def testSafeRevision(self):
84a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    test_data = {
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      'api': {
86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        '_manifest_features.json': '{}'
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      },
88a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      'docs': {
89a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'examples': {
90a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          'examples.txt': 'examples.txt contents'
91a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        },
92a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'server2': {
93a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          'app.yaml': AppYamlHelper.GenerateAppYaml('2-0-8')
94a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        },
95a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'static': {
96a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          'static.txt': 'static.txt contents'
97a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        },
98a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'templates': {
99a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          'public': {
100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)            'apps': {
101a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              'storage.html': 'storage.html contents'
102a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)            },
103a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)            'extensions': {
104a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)              'storage.html': 'storage.html contents'
105a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)            },
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          },
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          'json': {
108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)            'manifest.json': '{}',
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            'strings.json': '{}',
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            'apps_sidenav.json': '{}',
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            'extensions_sidenav.json': '{}',
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)          },
113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        }
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      }
115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates = []
118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    def app_yaml_update(version):
120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return {'docs': {'server2': {
121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'app.yaml': AppYamlHelper.GenerateAppYaml(version)
122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      }}}
123a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    def storage_html_update(update):
124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return {'docs': {'templates': {'public': {'apps': {
125a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'storage.html': update
126a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      }}}}}
127a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    def static_txt_update(update):
128a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return {'docs': {'static': {
129a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'static.txt': update
130a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      }}}
131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    app_yaml_path = 'docs/server2/app.yaml'
133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    storage_html_path = 'docs/templates/public/apps/storage.html'
134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    static_txt_path = 'docs/static/static.txt'
135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
136ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    def create_file_system(revision=None):
137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      '''Creates a MockFileSystem at |revision| by applying that many |updates|
138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      to it.
139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      '''
140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      mock_file_system = MockFileSystem(TestFileSystem(test_data))
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      updates_for_revision = (
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          updates if revision is None else updates[:int(revision)])
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      for update in updates_for_revision:
144a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        mock_file_system.Update(update)
145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      return mock_file_system
146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    delegate = _TestDelegate(create_file_system)
148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    delegate.SetAppVersion('2-0-8')
149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    file_systems = delegate.file_systems
151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # No updates applied yet.
153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
1554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(app_yaml_path).Get())
156a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('storage.html contents',
1574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(storage_html_path).Get())
158a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # Apply updates to storage.html.
160a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates.append(storage_html_update('interim contents'))
161a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates.append(storage_html_update('new contents'))
162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
163a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
1654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(app_yaml_path).Get())
166a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('new contents',
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(storage_html_path).Get())
168a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
169a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # Apply several updates to storage.html and app.yaml. The file system
170a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # should be pinned at the version before app.yaml changed.
171a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates.append(storage_html_update('stuck here contents'))
172a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
173a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    double_update = storage_html_update('newer contents')
174a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    double_update.update(app_yaml_update('2-0-10'))
175a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates.append(double_update)
176a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
177a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates.append(storage_html_update('never gonna reach here'))
178a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
179a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
180a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
1814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(app_yaml_path).Get())
182a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('stuck here contents',
1834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(storage_html_path).Get())
184a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
185a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # Further pushes to storage.html will keep it pinned.
186a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates.append(storage_html_update('y u not update!'))
187a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
188a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
189a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
1904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(app_yaml_path).Get())
191a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('stuck here contents',
1924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(storage_html_path).Get())
193a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
194a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # Likewise app.yaml.
195a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates.append(app_yaml_update('2-1-0'))
196a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
197a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
198a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
1994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(app_yaml_path).Get())
200a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('stuck here contents',
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(storage_html_path).Get())
202a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
203a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # And updates to other content won't happen either.
204a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    updates.append(static_txt_update('important content!'))
205a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
206a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
207a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-0-8'),
2084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(app_yaml_path).Get())
209a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('stuck here contents',
2104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(storage_html_path).Get())
211a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('static.txt contents',
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(static_txt_path).Get())
213b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
214a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # Lastly - when the app version changes, everything should no longer be
215a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # pinned.
216a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    delegate.SetAppVersion('2-1-0')
217a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    CronServlet(Request.ForTest('trunk'), delegate_for_test=delegate).Get()
218a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual(AppYamlHelper.GenerateAppYaml('2-1-0'),
2194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(app_yaml_path).Get())
220a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('y u not update!',
2214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(storage_html_path).Get())
222a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.assertEqual('important content!',
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     file_systems[-1].ReadSingle(static_txt_path).Get())
224b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
225b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)if __name__ == '__main__':
226b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  unittest.main()
227