diff options
author | evan.peterson.EP@gmail.com <evan.peterson.EP@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-22 17:18:55 +0000 |
---|---|---|
committer | evan.peterson.EP@gmail.com <evan.peterson.EP@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-22 17:18:55 +0000 |
commit | fdd3b93bb5861fefc2901d1760ec85037bf1ed07 (patch) | |
tree | e66d4bd9f674d9c9bf4b5437e0dc941d602537ed /chrome/common | |
parent | 15fe32703792bb7af62f96ec9d2aeb9df4bdacc1 (diff) | |
download | chromium_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')
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 + } +} |