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