summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
authorevan.peterson.EP@gmail.com <evan.peterson.EP@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-22 17:18:55 +0000
committerevan.peterson.EP@gmail.com <evan.peterson.EP@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-22 17:18:55 +0000
commitfdd3b93bb5861fefc2901d1760ec85037bf1ed07 (patch)
treee66d4bd9f674d9c9bf4b5437e0dc941d602537ed /chrome/common
parent15fe32703792bb7af62f96ec9d2aeb9df4bdacc1 (diff)
downloadchromium_src-fdd3b93bb5861fefc2901d1760ec85037bf1ed07.zip
chromium_src-fdd3b93bb5861fefc2901d1760ec85037bf1ed07.tar.gz
chromium_src-fdd3b93bb5861fefc2901d1760ec85037bf1ed07.tar.bz2
Adding AvailabilityFinder to Doc Server.
This is a large part of automatically generating API intro tables. This patch does not connect AvailabilityFinder with the rest of the server; a future patch will take care of that. BUG=233968 Review URL: https://chromiumcodereview.appspot.com/17397010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@208075 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/extensions/docs/server2/app.yaml2
-rw-r--r--chrome/common/extensions/docs/server2/availability_finder.py247
-rwxr-xr-xchrome/common/extensions/docs/server2/availability_finder_test.py181
-rw-r--r--chrome/common/extensions/docs/server2/branch_utility.py15
-rwxr-xr-xchrome/common/extensions/docs/server2/branch_utility_test.py21
-rw-r--r--chrome/common/extensions/docs/server2/cron.yaml8
-rwxr-xr-xchrome/common/extensions/docs/server2/cron_servlet_test.py2
-rwxr-xr-xchrome/common/extensions/docs/server2/instance_servlet_test.py2
-rw-r--r--chrome/common/extensions/docs/server2/test_branch_utility.py27
-rw-r--r--chrome/common/extensions/docs/server2/test_data/__init__.py0
-rw-r--r--chrome/common/extensions/docs/server2/test_data/canned_data.py703
-rw-r--r--chrome/common/extensions/docs/templates/json/api_availabilities.json18
12 files changed, 1212 insertions, 14 deletions
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index 35c406b..f8c706ba7 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
application: chrome-apps-doc
-version: 2-7-1
+version: 2-7-2
runtime: python27
api_version: 1
threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/availability_finder.py b/chrome/common/extensions/docs/server2/availability_finder.py
new file mode 100644
index 0000000..4105703
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/availability_finder.py
@@ -0,0 +1,247 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import collections
+import os
+
+from branch_utility import BranchUtility
+from compiled_file_system import CompiledFileSystem
+from file_system import FileNotFoundError
+import svn_constants
+from third_party.json_schema_compiler import json_parse, model
+from third_party.json_schema_compiler.memoize import memoize
+
+_API_AVAILABILITIES = svn_constants.JSON_PATH + '/api_availabilities.json'
+_API_FEATURES = svn_constants.API_PATH + '/_api_features.json'
+_EXTENSION_API = svn_constants.API_PATH + '/extension_api.json'
+_MANIFEST_FEATURES = svn_constants.API_PATH + '/_manifest_features.json'
+_PERMISSION_FEATURES = svn_constants.API_PATH + '/_permission_features.json'
+_STABLE = 'stable'
+
+class AvailabilityInfo(object):
+ def __init__(self, channel, version):
+ self.channel = channel
+ self.version = version
+
+def _GetChannelFromFeatures(api_name, file_system, path):
+ '''Finds API channel information within _features.json files at the given
+ |path| for the given |file_system|. Returns None if channel information for
+ the API cannot be located.
+ '''
+ feature = file_system.GetFromFile(path).get(api_name)
+
+ if feature is None:
+ return None
+ if isinstance(feature, collections.Mapping):
+ # The channel information dict is nested within a list for whitelisting
+ # purposes.
+ return feature.get('channel')
+ # Features can contain a list of entries. Take the newest branch.
+ return BranchUtility.NewestChannel(entry.get('channel')
+ for entry in feature)
+
+def _GetChannelFromApiFeatures(api_name, file_system):
+ try:
+ return _GetChannelFromFeatures(api_name, file_system, _API_FEATURES)
+ except FileNotFoundError as e:
+ # TODO(epeterson) Remove except block once _api_features is in all channels.
+ return None
+
+def _GetChannelFromPermissionFeatures(api_name, file_system):
+ return _GetChannelFromFeatures(api_name, file_system, _PERMISSION_FEATURES)
+
+def _GetChannelFromManifestFeatures(api_name, file_system):
+ return _GetChannelFromFeatures(#_manifest_features uses unix_style API names
+ model.UnixName(api_name),
+ file_system,
+ _MANIFEST_FEATURES)
+
+def _ExistsInFileSystem(api_name, file_system):
+ '''Checks for existence of |api_name| within the list of files in the api/
+ directory found using the given file system.
+ '''
+ file_names = file_system.GetFromFileListing(svn_constants.API_PATH)
+ # File names switch from unix_hacker_style to camelCase at versions <= 20.
+ return model.UnixName(api_name) in file_names or api_name in file_names
+
+def _ExistsInExtensionApi(api_name, file_system):
+ '''Parses the api/extension_api.json file (available in Chrome versions
+ before 18) for an API namespace. If this is successfully found, then the API
+ is considered to have been 'stable' for the given version.
+ '''
+ try:
+ extension_api_json = file_system.GetFromFile(_EXTENSION_API)
+ api_rows = [row.get('namespace') for row in extension_api_json
+ if 'namespace' in row]
+ return True if api_name in api_rows else False
+ except FileNotFoundError as e:
+ # This should only happen on preview.py since extension_api.json is no
+ # longer present in trunk.
+ return False
+
+class AvailabilityFinder(object):
+ '''Uses API data sources generated by a ChromeVersionDataSource in order to
+ search the filesystem for the earliest existence of a specified API throughout
+ the different versions of Chrome; this constitutes an API's availability.
+ '''
+ class Factory(object):
+ def __init__(self,
+ object_store_creator,
+ compiled_host_fs_factory,
+ branch_utility,
+ # Takes a |version|, and returns a caching offline or online
+ # subversion file system for that version.
+ create_file_system_at_version):
+ self._object_store_creator = object_store_creator
+ self._compiled_host_fs_factory = compiled_host_fs_factory
+ self._branch_utility = branch_utility
+ self._create_file_system_at_version = create_file_system_at_version
+
+ def Create(self):
+ return AvailabilityFinder(self._object_store_creator,
+ self._compiled_host_fs_factory,
+ self._branch_utility,
+ self._create_file_system_at_version)
+
+ def __init__(self,
+ object_store_creator,
+ compiled_host_fs_factory,
+ branch_utility,
+ create_file_system_at_version):
+ self._object_store_creator = object_store_creator
+ self._json_cache = compiled_host_fs_factory.Create(
+ lambda _, json: json_parse.Parse(json),
+ AvailabilityFinder,
+ 'json-cache')
+ self._branch_utility = branch_utility
+ self._create_file_system_at_version = create_file_system_at_version
+ self._object_store = object_store_creator.Create(AvailabilityFinder)
+
+ @memoize
+ def _CreateFeaturesAndNamesFileSystems(self, version):
+ '''The 'features' compiled file system's populate function parses and
+ returns the contents of a _features.json file. The 'names' compiled file
+ system's populate function creates a list of file names with .json or .idl
+ extensions.
+ '''
+ fs_factory = CompiledFileSystem.Factory(
+ self._create_file_system_at_version(version),
+ self._object_store_creator)
+ features_fs = fs_factory.Create(lambda _, json: json_parse.Parse(json),
+ AvailabilityFinder,
+ category='features')
+ names_fs = fs_factory.Create(self._GetExtNames,
+ AvailabilityFinder,
+ category='names')
+ return (features_fs, names_fs)
+
+ def _GetExtNames(self, base_path, apis):
+ return [os.path.splitext(api)[0] for api in apis
+ if os.path.splitext(api)[1][1:] in ['json', 'idl']]
+
+ def _FindEarliestStableAvailability(self, api_name, version):
+ '''Searches in descending order through filesystem caches tied to specific
+ chrome version numbers and looks for the availability of an API, |api_name|,
+ on the stable channel. When a version is found where the API is no longer
+ available on stable, returns the previous version number (the last known
+ version where the API was stable).
+ '''
+ available = True
+ while available:
+ if version < 5:
+ # SVN data isn't available below version 5.
+ return version + 1
+ available = False
+ features_fs, names_fs = self._CreateFeaturesAndNamesFileSystems(version)
+ if version >= 28:
+ # The _api_features.json file first appears in version 28 and should be
+ # the most reliable for finding API availabilities, so it gets checked
+ # first. The _permission_features.json and _manifest_features.json files
+ # are present in Chrome 20 and onwards. Fall back to a check for file
+ # system existence if the API is not stable in any of the _features.json
+ # files.
+ available = _GetChannelFromApiFeatures(api_name, features_fs) == _STABLE
+ if version >= 20:
+ # Check other _features.json files/file existence if the API wasn't
+ # found in _api_features.json, or if _api_features.json wasn't present.
+ available = available or (
+ _GetChannelFromPermissionFeatures(api_name, features_fs) == _STABLE
+ or _GetChannelFromManifestFeatures(api_name, features_fs) == _STABLE
+ or _ExistsInFileSystem(api_name, names_fs))
+ elif version >= 18:
+ # These versions are a little troublesome. Version 19 has
+ # _permission_features.json, but it lacks 'channel' information.
+ # Version 18 lacks all of the _features.json files. For now, we're using
+ # a simple check for filesystem existence here.
+ available = _ExistsInFileSystem(api_name, names_fs)
+ elif version >= 5:
+ # Versions 17 and down to 5 have an extension_api.json file which
+ # contains namespaces for each API that was available at the time. We
+ # can use this file to check for API existence.
+ available = _ExistsInExtensionApi(api_name, features_fs)
+
+ if not available:
+ return version + 1
+ version -= 1
+
+ def _GetAvailableChannelForVersion(self, api_name, version):
+ '''Searches through the _features files for a given |version| and returns
+ the channel that the given API is determined to be available on.
+ '''
+ features_fs, names_fs = self._CreateFeaturesAndNamesFileSystems(version)
+ channel = (_GetChannelFromApiFeatures(api_name, features_fs)
+ or _GetChannelFromPermissionFeatures(api_name, features_fs)
+ or _GetChannelFromManifestFeatures(api_name, features_fs))
+ if channel is None and _ExistsInFileSystem(api_name, names_fs):
+ # If an API is not represented in any of the _features files, but exists
+ # in the filesystem, then assume it is available in this version.
+ # The windows API is an example of this.
+ return self._branch_utility.GetChannelForVersion(version)
+
+ return channel
+
+ def GetApiAvailability(self, api_name):
+ '''Determines the availability for an API by testing several scenarios.
+ (i.e. Is the API experimental? Only available on certain development
+ channels? If it's stable, when did it first become stable? etc.)
+ '''
+ availability = self._object_store.Get(api_name).Get()
+ if availability is not None:
+ return availability
+
+ # Check for a predetermined availability for this API.
+ api_info = self._json_cache.GetFromFile(_API_AVAILABILITIES).get(api_name)
+ if api_info is not None:
+ channel = api_info.get('channel')
+ return AvailabilityInfo(
+ channel,
+ api_info.get('version') if channel == _STABLE else None)
+
+ # Check for the API in the development channels.
+ availability = None
+ for channel_info in self._branch_utility.GetAllChannelInfo():
+ available_channel = self._GetAvailableChannelForVersion(
+ api_name,
+ channel_info.version)
+ # If the |available_channel| for the API is the same as, or older than,
+ # the channel we're checking, then the API is available on this channel.
+ if (available_channel is not None and
+ BranchUtility.NewestChannel((available_channel, channel_info.channel))
+ == channel_info.channel):
+ availability = AvailabilityInfo(channel_info.channel,
+ channel_info.version)
+ break
+
+ # The API should at least be available on trunk. It's a bug otherwise.
+ assert availability, 'No availability found for %s' % api_name
+
+ # If the API is in stable, find the chrome version in which it became
+ # stable.
+ if availability.channel == _STABLE:
+ availability.version = self._FindEarliestStableAvailability(
+ api_name,
+ availability.version)
+
+ self._object_store.Set(api_name, availability)
+ return availability
diff --git a/chrome/common/extensions/docs/server2/availability_finder_test.py b/chrome/common/extensions/docs/server2/availability_finder_test.py
new file mode 100755
index 0000000..6577ee5
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/availability_finder_test.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import sys
+import unittest
+
+from availability_finder import AvailabilityFinder
+from branch_utility import BranchUtility
+from compiled_file_system import CompiledFileSystem
+from fake_url_fetcher import FakeUrlFetcher
+from object_store_creator import ObjectStoreCreator
+from test_file_system import TestFileSystem
+from test_data.canned_data import (CANNED_API_FILE_SYSTEM_DATA, CANNED_BRANCHES)
+
+def _CreateCannedFileSystem(version):
+ branch = CANNED_BRANCHES[version]
+ return TestFileSystem(CANNED_API_FILE_SYSTEM_DATA[str(branch)])
+
+class AvailabilityFinderTest(unittest.TestCase):
+ def setUp(self):
+ self._avail_ds_factory = AvailabilityFinder.Factory(
+ ObjectStoreCreator.ForTest(),
+ CompiledFileSystem.Factory(
+ TestFileSystem(CANNED_API_FILE_SYSTEM_DATA['trunk']),
+ ObjectStoreCreator.ForTest()),
+ BranchUtility(
+ os.path.join('branch_utility', 'first.json'),
+ os.path.join('branch_utility', 'second.json'),
+ FakeUrlFetcher(os.path.join(sys.path[0], 'test_data')),
+ ObjectStoreCreator.ForTest()),
+ _CreateCannedFileSystem)
+ self._avail_ds = self._avail_ds_factory.Create()
+
+ def testGetApiAvailability(self):
+ # Key: Using 'channel' (i.e. 'beta') to represent an availability listing
+ # for an API in a _features.json file, and using |channel| (i.e. |dev|) to
+ # represent the development channel, or phase of development, where an API's
+ # availability is being checked.
+
+ # Testing the predetermined APIs found in
+ # templates/json/api_availabilities.json.
+ self.assertEqual('stable',
+ self._avail_ds.GetApiAvailability('jsonAPI1').channel)
+ self.assertEqual(10,
+ self._avail_ds.GetApiAvailability('jsonAPI1').version)
+ self.assertEqual('trunk',
+ self._avail_ds.GetApiAvailability('jsonAPI2').channel)
+ self.assertEqual(None,
+ self._avail_ds.GetApiAvailability('jsonAPI2').version)
+ self.assertEqual('dev',
+ self._avail_ds.GetApiAvailability('jsonAPI3').channel)
+ self.assertEqual(None,
+ self._avail_ds.GetApiAvailability('jsonAPI3').version)
+
+ # Testing APIs found only by checking file system existence.
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('windows').channel)
+ self.assertEquals(23,
+ self._avail_ds.GetApiAvailability('windows').version)
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('tabs').channel)
+ self.assertEquals(18,
+ self._avail_ds.GetApiAvailability('tabs').version)
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('input.ime').channel)
+ self.assertEquals(18,
+ self._avail_ds.GetApiAvailability('input.ime').version)
+
+ # Testing API channel existence for _api_features.json.
+ # Listed as 'dev' on |beta|, 'dev' on |dev|.
+ self.assertEquals('dev',
+ self._avail_ds.GetApiAvailability('systemInfo.stuff').channel)
+ self.assertEquals(28,
+ self._avail_ds.GetApiAvailability('systemInfo.stuff').version)
+ # Listed as 'stable' on |beta|.
+ self.assertEquals('beta',
+ self._avail_ds.GetApiAvailability('systemInfo.cpu').channel)
+ self.assertEquals(27,
+ self._avail_ds.GetApiAvailability('systemInfo.cpu').version)
+
+ # Testing API channel existence for _manifest_features.json.
+ # Listed as 'trunk' on all channels.
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('sync').channel)
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('sync').version)
+ # No records of API until |trunk|.
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('history').channel)
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('history').version)
+ # Listed as 'dev' on |dev|.
+ self.assertEquals('dev',
+ self._avail_ds.GetApiAvailability('storage').channel)
+ self.assertEquals(28,
+ self._avail_ds.GetApiAvailability('storage').version)
+ # Stable in _manifest_features and into pre-18 versions.
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('pageAction').channel)
+ self.assertEquals(8,
+ self._avail_ds.GetApiAvailability('pageAction').version)
+
+ # Testing API channel existence for _permission_features.json.
+ # Listed as 'beta' on |trunk|.
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('falseBetaAPI').version)
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('falseBetaAPI').version)
+ # Listed as 'trunk' on |trunk|.
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('trunkAPI').channel)
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('trunkAPI').version)
+ # Listed as 'trunk' on all development channels.
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('declarativeContent').channel)
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('declarativeContent').version)
+ # Listed as 'dev' on all development channels.
+ self.assertEquals('dev',
+ self._avail_ds.GetApiAvailability('bluetooth').channel)
+ self.assertEquals(28,
+ self._avail_ds.GetApiAvailability('bluetooth').version)
+ # Listed as 'dev' on |dev|.
+ self.assertEquals('dev',
+ self._avail_ds.GetApiAvailability('cookies').channel)
+ self.assertEquals(28,
+ self._avail_ds.GetApiAvailability('cookies').version)
+ # Treated as 'stable' APIs.
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('alarms').channel)
+ self.assertEquals(24,
+ self._avail_ds.GetApiAvailability('alarms').version)
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('bookmarks').channel)
+ self.assertEquals(21,
+ self._avail_ds.GetApiAvailability('bookmarks').version)
+
+ # Testing older API existence using extension_api.json.
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('menus').channel)
+ self.assertEquals(6,
+ self._avail_ds.GetApiAvailability('menus').version)
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('idle').channel)
+ self.assertEquals(5,
+ self._avail_ds.GetApiAvailability('idle').version)
+
+ # Switches between _features.json files across branches.
+ # Listed as 'trunk' on all channels, in _api, _permission, or _manifest.
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('contextMenus').channel)
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('contextMenus').version)
+ # Moves between _permission and _manifest as file system is traversed.
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('systemInfo.display').channel)
+ self.assertEquals(23,
+ self._avail_ds.GetApiAvailability('systemInfo.display').version)
+ self.assertEquals('stable',
+ self._avail_ds.GetApiAvailability('webRequest').channel)
+ self.assertEquals(17,
+ self._avail_ds.GetApiAvailability('webRequest').version)
+
+ # Mid-upgrade cases:
+ # Listed as 'dev' on |beta| and 'beta' on |dev|.
+ self.assertEquals('dev',
+ self._avail_ds.GetApiAvailability('notifications').channel)
+ self.assertEquals(28,
+ self._avail_ds.GetApiAvailability('notifications').version)
+ # Listed as 'beta' on |stable|, 'dev' on |beta| ... until |stable| on trunk.
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('events').channel)
+ self.assertEquals('trunk',
+ self._avail_ds.GetApiAvailability('events').version)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chrome/common/extensions/docs/server2/branch_utility.py b/chrome/common/extensions/docs/server2/branch_utility.py
index 1c683c6..4f49113 100644
--- a/chrome/common/extensions/docs/server2/branch_utility.py
+++ b/chrome/common/extensions/docs/server2/branch_utility.py
@@ -137,14 +137,23 @@ class BranchUtility(object):
version_json = json.loads(self._history_result.Get().content)
for entry in version_json['events']:
- # Here, entry['title'] looks like: 'title - version#.#.branch#.#'
+ # Here, entry['title'] looks like: '<title> - <version>.##.<branch>.##'
version_title = entry['title'].split(' - ')[1].split('.')
if version_title[0] == str(version):
self._branch_object_store.Set(str(version), version_title[2])
return int(version_title[2])
- raise ValueError(
- 'The branch for %s could not be found.' % version)
+ raise ValueError('The branch for %s could not be found.' % version)
+
+ def GetChannelForVersion(self, version):
+ '''Returns the name of the development channel corresponding to a given
+ version number.
+ '''
+ for channel_info in self.GetAllChannelInfo():
+ if channel_info.channel == 'stable' and version <= channel_info.version:
+ return channel_info.channel
+ if version == channel_info.version:
+ return channel_info.channel
def GetLatestVersionNumber(self):
'''Returns the most recent version number found using data stored on
diff --git a/chrome/common/extensions/docs/server2/branch_utility_test.py b/chrome/common/extensions/docs/server2/branch_utility_test.py
index c6a5034..ea9198e 100755
--- a/chrome/common/extensions/docs/server2/branch_utility_test.py
+++ b/chrome/common/extensions/docs/server2/branch_utility_test.py
@@ -120,5 +120,26 @@ class BranchUtilityTest(unittest.TestCase):
self.assertEquals(396,
self._branch_util.GetBranchForVersion(5))
+ def testGetChannelForVersion(self):
+ self.assertEquals('trunk',
+ self._branch_util.GetChannelForVersion('trunk'))
+ self.assertEquals('dev',
+ self._branch_util.GetChannelForVersion(28))
+ self.assertEquals('beta',
+ self._branch_util.GetChannelForVersion(27))
+ self.assertEquals('stable',
+ self._branch_util.GetChannelForVersion(26))
+ self.assertEquals('stable',
+ self._branch_util.GetChannelForVersion(22))
+ self.assertEquals('stable',
+ self._branch_util.GetChannelForVersion(18))
+ self.assertEquals('stable',
+ self._branch_util.GetChannelForVersion(14))
+ self.assertEquals(None,
+ self._branch_util.GetChannelForVersion(30))
+ self.assertEquals(None,
+ self._branch_util.GetChannelForVersion(42))
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml
index 3c6f142..9529324 100644
--- a/chrome/common/extensions/docs/server2/cron.yaml
+++ b/chrome/common/extensions/docs/server2/cron.yaml
@@ -2,19 +2,19 @@ cron:
- description: Load everything for trunk.
url: /_cron/trunk
schedule: every 5 minutes
- target: 2-7-1
+ target: 2-7-2
- description: Load everything for dev.
url: /_cron/dev
schedule: every 5 minutes
- target: 2-7-1
+ target: 2-7-2
- description: Load everything for beta.
url: /_cron/beta
schedule: every 5 minutes
- target: 2-7-1
+ target: 2-7-2
- description: Load everything for stable.
url: /_cron/stable
schedule: every 5 minutes
- target: 2-7-1
+ target: 2-7-2
diff --git a/chrome/common/extensions/docs/server2/cron_servlet_test.py b/chrome/common/extensions/docs/server2/cron_servlet_test.py
index 0ee14a3..c0655a2 100755
--- a/chrome/common/extensions/docs/server2/cron_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/cron_servlet_test.py
@@ -27,7 +27,7 @@ class _TestDelegate(CronServlet.Delegate):
self._app_version = GetAppVersion()
def CreateBranchUtility(self, object_store_creator):
- return TestBranchUtility()
+ return TestBranchUtility.CreateWithCannedData()
def CreateHostFileSystemForBranchAndRevision(self, branch, revision):
file_system = self._create_file_system(revision)
diff --git a/chrome/common/extensions/docs/server2/instance_servlet_test.py b/chrome/common/extensions/docs/server2/instance_servlet_test.py
index fb92fe1..0ac7a4a 100755
--- a/chrome/common/extensions/docs/server2/instance_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/instance_servlet_test.py
@@ -19,7 +19,7 @@ class _TestDelegate(InstanceServlet.Delegate):
self._file_system_type = file_system_type
def CreateBranchUtility(self, object_store_creator):
- return TestBranchUtility()
+ return TestBranchUtility.CreateWithCannedData()
def CreateHostFileSystemForBranch(self, branch):
return self._file_system_type()
diff --git a/chrome/common/extensions/docs/server2/test_branch_utility.py b/chrome/common/extensions/docs/server2/test_branch_utility.py
index aaabdca..5dec476 100644
--- a/chrome/common/extensions/docs/server2/test_branch_utility.py
+++ b/chrome/common/extensions/docs/server2/test_branch_utility.py
@@ -3,19 +3,38 @@
# found in the LICENSE file.
from branch_utility import BranchUtility, ChannelInfo
+from test_data.canned_data import (CANNED_BRANCHES, CANNED_CHANNELS)
class TestBranchUtility(object):
'''Mimics BranchUtility to return valid-ish data without needing omahaproxy
data.
'''
+ def __init__(self, branches, channels):
+ ''' Parameters: |branches| is a mapping of versions to branches, and
+ |channels| is a mapping of channels to versions.
+ '''
+ self._branches = branches
+ self._channels = channels
+
+ @staticmethod
+ def CreateWithCannedData():
+ '''Returns a TestBranchUtility that uses 'canned' test data pulled from
+ older branches of SVN data.
+ '''
+ return TestBranchUtility(CANNED_BRANCHES, CANNED_CHANNELS)
+
def GetAllChannelInfo(self):
return [self.GetChannelInfo(channel)
for channel in BranchUtility.GetAllChannelNames()]
def GetChannelInfo(self, channel):
- return ChannelInfo(channel,
- 'fakebranch-%s' % channel,
- 'fakeversion-%s' % channel)
+ version = self._channels[channel]
+ return ChannelInfo(channel, self.GetBranchForVersion(version), version)
def GetBranchForVersion(self, version):
- return 'fakebranch-%s' % version
+ return self._branches[version]
+
+ def GetChannelForVersion(self, version):
+ for channel in self._channels.iterkeys():
+ if self._channels[channel] == version:
+ return channel
diff --git a/chrome/common/extensions/docs/server2/test_data/__init__.py b/chrome/common/extensions/docs/server2/test_data/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/test_data/__init__.py
diff --git a/chrome/common/extensions/docs/server2/test_data/canned_data.py b/chrome/common/extensions/docs/server2/test_data/canned_data.py
new file mode 100644
index 0000000..a28707e
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/test_data/canned_data.py
@@ -0,0 +1,703 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import json
+
+CANNED_CHANNELS = {
+ 'trunk': 'trunk',
+ 'dev': 28,
+ 'beta': 27,
+ 'stable': 26
+}
+
+CANNED_BRANCHES = {
+ 'trunk': 'trunk',
+ 28: 1500,
+ 27: 1453,
+ 26: 1410,
+ 25: 1364,
+ 24: 1312,
+ 23: 1271,
+ 22: 1229,
+ 21: 1180,
+ 20: 1132,
+ 19: 1084,
+ 18: 1025,
+ 17: 963,
+ 16: 912,
+ 15: 874,
+ 14: 835,
+ 13: 782,
+ 12: 742,
+ 11: 696,
+ 10: 648,
+ 9: 597,
+ 8: 552,
+ 7: 544,
+ 6: 495,
+ 5: 396
+}
+
+CANNED_TEST_FILE_SYSTEM_DATA = {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'manifest': 'features'
+ }),
+ '_permission_features.json': json.dumps({
+ 'permission': 'features'
+ })
+ },
+ 'docs': {
+ 'templates': {
+ 'intros': {
+ 'test.html': '<h1>hi</h1>you<h2>first</h2><h3>inner</h3><h2>second</h2>'
+ },
+ 'json': {
+ 'api_availabilities.json': json.dumps({
+ 'tester': {
+ 'channel': 'stable',
+ 'version': 42
+ }
+ }),
+ 'intro_tables.json': json.dumps({
+ 'tester': {
+ 'Permissions': [
+ {
+ 'permission': 'tester'
+ },
+ {
+ 'extra': 'is an API.'
+ }
+ ],
+ 'LearnMore': [
+ {
+ 'href': 'https://tester.test.com/welcome.html',
+ 'content': 'Welcome!'
+ }
+ ]
+ }
+ })
+ }
+ }
+ }
+}
+
+CANNED_API_FILE_SYSTEM_DATA = {
+ 'trunk': {
+ 'api': {
+ '_api_features.json': json.dumps({
+ 'contextMenus': {
+ 'channel': 'stable'
+ },
+ 'events': {
+ 'channel': 'stable'
+ },
+ 'extension': {
+ 'channel': 'stable'
+ }
+ }),
+ '_manifest_features.json': json.dumps({
+ 'history': {
+ 'channel': 'beta'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ },
+ 'storage': {
+ 'channel': 'beta'
+ },
+ 'sync': {
+ 'channel': 'trunk'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'alarms': {
+ 'channel': 'stable'
+ },
+ 'bluetooth': {
+ 'channel': 'dev'
+ },
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'cookies': {
+ 'channel': 'dev'
+ },
+ 'declarativeContent': {
+ 'channel': 'trunk'
+ },
+ 'falseBetaAPI': {
+ 'channel': 'beta'
+ },
+ 'trunkAPI': {
+ 'channel': 'trunk'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents',
+ 'windows.json': 'windows contents'
+ },
+ 'docs': {
+ 'templates': {
+ 'json': {
+ 'api_availabilities.json': json.dumps({
+ 'jsonAPI1': {
+ 'channel': 'stable',
+ 'version': 10
+ },
+ 'jsonAPI2': {
+ 'channel': 'trunk'
+ },
+ 'jsonAPI3': {
+ 'channel': 'dev'
+ }
+ }),
+ 'intro_tables.json': json.dumps({
+ 'test': [
+ {
+ 'Permissions': 'probably none'
+ }
+ ]
+ })
+ }
+ }
+ }
+ },
+ '1500': {
+ 'api': {
+ '_api_features.json': json.dumps({
+ 'events': {
+ 'channel': 'trunk'
+ },
+ 'extension': {
+ 'channel': 'stable'
+ },
+ 'systemInfo.stuff': {
+ 'channel': 'dev'
+ }
+ }),
+ '_manifest_features.json': json.dumps({
+ 'contextMenus': {
+ 'channel': 'trunk'
+ },
+ 'notifications': {
+ 'channel': 'beta'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ },
+ 'storage': {
+ 'channel': 'dev'
+ },
+ 'sync': {
+ 'channel': 'trunk'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'alarms': {
+ 'channel': 'stable'
+ },
+ 'bluetooth': {
+ 'channel': 'dev'
+ },
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'cookies': {
+ 'channel': 'dev'
+ },
+ 'declarativeContent': {
+ 'channel': 'trunk'
+ },
+ 'downloads': {
+ 'channel': 'beta'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents',
+ 'windows.json': 'windows contents'
+ }
+ },
+ '1453': {
+ 'api': {
+ '_api_features.json': json.dumps({
+ 'events': {
+ 'channel': 'dev'
+ },
+ 'extension': {
+ 'channel': 'stable'
+ },
+ 'systemInfo.cpu': {
+ 'channel': 'stable'
+ },
+ 'systemInfo.stuff': {
+ 'channel': 'dev'
+ }
+ }),
+ '_manifest_features.json': json.dumps({
+ 'notifications': {
+ 'channel': 'dev'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ },
+ 'storage': {
+ 'channel': 'dev'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'alarms': {
+ 'channel': 'stable'
+ },
+ 'bluetooth': {
+ 'channel': 'dev'
+ },
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'context_menus': {
+ 'channel': 'trunk'
+ },
+ 'declarativeContent': {
+ 'channel': 'trunk'
+ },
+ 'downloads': {
+ 'channel': 'dev'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents',
+ 'windows.json': 'windows contents'
+ }
+ },
+ '1410': {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'events': {
+ 'channel': 'beta'
+ },
+ 'notifications': {
+ 'channel': 'dev'
+ },
+ 'page_action': {
+ 'channel': 'stable'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ },
+ 'web_request': {
+ 'channel': 'stable'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'alarms': {
+ 'channel': 'stable'
+ },
+ 'bluetooth': {
+ 'channel': 'dev'
+ },
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'context_menus': {
+ 'channel': 'trunk'
+ },
+ 'declarativeContent': {
+ 'channel': 'trunk'
+ },
+ 'systemInfo.display': {
+ 'channel': 'stable'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents',
+ 'windows.json': 'windows contents'
+ }
+ },
+ '1364': {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'page_action': {
+ 'channel': 'stable'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'alarms': {
+ 'channel': 'stable'
+ },
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'systemInfo.display': {
+ 'channel': 'stable'
+ },
+ 'webRequest': {
+ 'channel': 'stable'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents',
+ 'windows.json': 'windows contents'
+ }
+ },
+ '1312': {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'page_action': {
+ 'channel': 'stable'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ },
+ 'web_request': {
+ 'channel': 'stable'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'alarms': {
+ 'channel': 'stable'
+ },
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'systemInfo.display': {
+ 'channel': 'stable'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents',
+ 'windows.json': 'windows contents'
+ }
+ },
+ '1271': {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'page_action': {
+ 'channel': 'stable'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ },
+ 'system_info_display': {
+ 'channel': 'stable'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'alarms': {
+ 'channel': 'beta'
+ },
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'webRequest': {
+ 'channel': 'stable'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents',
+ 'windows.json': 'windows contents'
+ }
+ },
+ '1229': {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'page_action': {
+ 'channel': 'stable'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ },
+ 'web_request': {
+ 'channel': 'stable'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'systemInfo.display': {
+ 'channel': 'beta'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents'
+ }
+ },
+ '1180': {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'page_action': {
+ 'channel': 'stable'
+ },
+ 'runtime': {
+ 'channel': 'stable'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'bookmarks': {
+ 'channel': 'stable'
+ },
+ 'webRequest': {
+ 'channel': 'stable'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input_ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents'
+ }
+ },
+ '1132': {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'page_action': {
+ 'channel': 'stable'
+ }
+ }),
+ '_permission_features.json': json.dumps({
+ 'webRequest': {
+ 'channel': 'stable'
+ }
+ }),
+ 'idle.json': 'idle contents',
+ 'input.ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'tabs.json': 'tabs contents'
+ }
+ },
+ '1084': {
+ 'api': {
+ '_manifest_features.json': json.dumps({
+ 'contents': 'nothing of interest here,really'
+ }),
+ 'idle.json': 'idle contents',
+ 'input.ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'pageAction.json': 'pageAction contents',
+ 'tabs.json': 'tabs contents',
+ 'webRequest.json': 'webRequest contents'
+ }
+ },
+ '1025': {
+ 'api': {
+ 'idle.json': 'idle contents',
+ 'input.ime.json': 'input.ime contents',
+ 'menus.json': 'menus contents',
+ 'pageAction.json': 'pageAction contents',
+ 'tabs.json': 'tabs contents',
+ 'webRequest.json': 'webRequest contents'
+ }
+ },
+ '963': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ },
+ {
+ 'namespace': 'webRequest'
+ }
+ ])
+ }
+ },
+ '912': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ },
+ {
+ 'namespace': 'experimental.webRequest'
+ }
+ ])
+ }
+ },
+ '874': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ }
+ ])
+ }
+ },
+ '835': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ }
+ ])
+ }
+ },
+ '782': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ }
+ ])
+ }
+ },
+ '742': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ }
+ ])
+ }
+ },
+ '696': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ }
+ ])
+ }
+ },
+ '648': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ }
+ ])
+ }
+ },
+ '597': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ }
+ ])
+ }
+ },
+ '552': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ },
+ {
+ 'namespace': 'pageAction'
+ }
+ ])
+ }
+ },
+ '544': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ }
+ ])
+ }
+ },
+ '495': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'menus'
+ }
+ ])
+ }
+ },
+ '396': {
+ 'api': {
+ 'extension_api.json': json.dumps([
+ {
+ 'namespace': 'idle'
+ },
+ {
+ 'namespace': 'experimental.menus'
+ }
+ ])
+ }
+ }
+}
diff --git a/chrome/common/extensions/docs/templates/json/api_availabilities.json b/chrome/common/extensions/docs/templates/json/api_availabilities.json
new file mode 100644
index 0000000..a81f194
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/json/api_availabilities.json
@@ -0,0 +1,18 @@
+{
+ "devtools.inspectedWindow": {
+ "channel": "stable",
+ "version": 18
+ },
+ "devtools.network": {
+ "channel": "stable",
+ "version": 18
+ },
+ "devtools.panels": {
+ "channel": "stable",
+ "version": 18
+ },
+ "webstore": {
+ "channel": "stable",
+ "version": 15
+ }
+}