class AvailabilityFinderTest(unittest.TestCase): def _create_availability_finder(self, host_fs_creator, host_fs_iterator, platform): test_object_store = ObjectStoreCreator.ForTest() return AvailabilityFinder( self._branch_utility, CompiledFileSystem.Factory(test_object_store), host_fs_iterator, host_fs_creator.GetTrunk(), test_object_store, platform) def setUp(self): self._branch_utility = BranchUtility( os.path.join('branch_utility', 'first.json'), os.path.join('branch_utility', 'second.json'), FakeUrlFetcher(Server2Path('test_data')), ObjectStoreCreator.ForTest()) self._api_fs_creator = FakeHostFileSystemProvider( CANNED_API_FILE_SYSTEM_DATA) self._node_fs_creator = FakeHostFileSystemProvider( TABS_SCHEMA_BRANCHES) self._api_fs_iterator = HostFileSystemIterator(self._api_fs_creator, self._branch_utility) self._node_fs_iterator = HostFileSystemIterator( self._node_fs_creator, self._branch_utility) # Imitate the actual SVN file system by incrementing the stats for paths # where an API schema has changed. last_stat = type('last_stat', (object, ), {'val': 0}) def stat_paths(file_system, channel_info): if channel_info.version not in TABS_UNMODIFIED_VERSIONS: last_stat.val += 1 # HACK: |file_system| is a MockFileSystem backed by a TestFileSystem. # Increment the TestFileSystem stat count. file_system._file_system.IncrementStat(by=last_stat.val) # Continue looping. The iterator will stop after 'trunk' automatically. return True # Use the HostFileSystemIterator created above to change global stat values # for the TestFileSystems that it creates. self._node_fs_iterator.Ascending( # The earliest version represented with the tabs' test data is 13. self._branch_utility.GetStableChannelInfo(13), stat_paths) def testGraphOptimization(self): for platform in GetPlatforms(): # Keep track of how many times the APISchemaGraph constructor is called. original_constructor = api_schema_graph.APISchemaGraph mock_constructor = MockFunction(original_constructor) api_schema_graph.APISchemaGraph = mock_constructor node_avail_finder = self._create_availability_finder( self._node_fs_creator, self._node_fs_iterator, platform) try: # The test data includes an extra branch where the API does not exist. num_versions = len(TABS_SCHEMA_BRANCHES) - 1 # We expect an APISchemaGraph to be created only when an API schema file # has different stat data from the previous version's schema file. num_graphs_created = num_versions - len( TABS_UNMODIFIED_VERSIONS) # Run the logic for object-level availability for an API. node_avail_finder.GetAPINodeAvailability('tabs') self.assertTrue(*api_schema_graph.APISchemaGraph.CheckAndReset( num_graphs_created)) finally: # Ensure that the APISchemaGraph constructor is reset to be the original # constructor. api_schema_graph.APISchemaGraph = original_constructor 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. def assertGet(ch_info, api, only_on=None, scheduled=None): for platform in GetPlatforms(): get_availability = self._create_availability_finder( self._api_fs_creator, self._api_fs_iterator, platform if only_on is None else only_on).GetAPIAvailability self.assertEqual( AvailabilityInfo(ch_info, scheduled=scheduled), get_availability(api)) # Testing APIs with predetermined availability. assertGet(ChannelInfo('trunk', 'trunk', 'trunk'), 'jsonTrunkAPI') assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'jsonDevAPI') assertGet(ChannelInfo('beta', CANNED_BRANCHES[30], 30), 'jsonBetaAPI') assertGet(ChannelInfo('stable', CANNED_BRANCHES[20], 20), 'jsonStableAPI') # Testing a whitelisted API. assertGet(ChannelInfo('beta', CANNED_BRANCHES[30], 30), 'declarativeWebRequest') # Testing APIs found only by checking file system existence. assertGet(ChannelInfo('stable', CANNED_BRANCHES[23], 23), 'windows') assertGet(ChannelInfo('stable', CANNED_BRANCHES[18], 18), 'tabs') assertGet(ChannelInfo('stable', CANNED_BRANCHES[18], 18), 'input.ime') # Testing API channel existence for _api_features.json. # Listed as 'dev' on |beta|, 'dev' on |dev|. assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'systemInfo.stuff') # Listed as 'stable' on |beta|. assertGet(ChannelInfo('beta', CANNED_BRANCHES[30], 30), 'systemInfo.cpu', scheduled=31) # Testing API channel existence for _manifest_features.json. # Listed as 'trunk' on all channels. assertGet(ChannelInfo('trunk', 'trunk', 'trunk'), 'sync') # No records of API until |trunk|. assertGet(ChannelInfo('trunk', 'trunk', 'trunk'), 'history') # Listed as 'dev' on |dev|. assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'storage') # Stable in _manifest_features and into pre-18 versions. assertGet(ChannelInfo('stable', CANNED_BRANCHES[8], 8), 'pageAction') # Testing API channel existence for _permission_features.json. # Listed as 'beta' on |trunk|. assertGet(ChannelInfo('trunk', 'trunk', 'trunk'), 'falseBetaAPI') # Listed as 'trunk' on |trunk|. assertGet(ChannelInfo('trunk', 'trunk', 'trunk'), 'trunkAPI') # Listed as 'trunk' on all development channels. assertGet(ChannelInfo('trunk', 'trunk', 'trunk'), 'declarativeContent') # Listed as 'dev' on all development channels. assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'bluetooth') # Listed as 'dev' on |dev|. assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'cookies') # Treated as 'stable' APIs. assertGet(ChannelInfo('stable', CANNED_BRANCHES[24], 24), 'alarms') assertGet(ChannelInfo('stable', CANNED_BRANCHES[21], 21), 'bookmarks') # Testing older API existence using extension_api.json. assertGet(ChannelInfo('stable', CANNED_BRANCHES[6], 6), 'menus') assertGet(ChannelInfo('stable', CANNED_BRANCHES[5], 5), 'idle') # Switches between _features.json files across branches. # Listed as 'trunk' on all channels, in _api, _permission, or _manifest. assertGet(ChannelInfo('trunk', 'trunk', 'trunk'), 'contextMenus') # Moves between _permission and _manifest as file system is traversed. assertGet(ChannelInfo('stable', CANNED_BRANCHES[23], 23), 'systemInfo.display') assertGet(ChannelInfo('stable', CANNED_BRANCHES[17], 17), 'webRequest') # Mid-upgrade cases: # Listed as 'dev' on |beta| and 'beta' on |dev|. assertGet(ChannelInfo('dev', CANNED_BRANCHES[31], 31), 'notifications') # Listed as 'beta' on |stable|, 'dev' on |beta|...until |stable| on trunk. assertGet(ChannelInfo('trunk', 'trunk', 'trunk'), 'events') # Check for differing availability across apps|extensions assertGet(ChannelInfo('stable', CANNED_BRANCHES[26], 26), 'appsFirst', only_on='extensions') assertGet(ChannelInfo('stable', CANNED_BRANCHES[25], 25), 'appsFirst', only_on='apps') def testGetAPINodeAvailability(self): def assertEquals(found, channel_info, actual, scheduled=None): lookup_result = api_schema_graph.LookupResult if channel_info is None: self.assertEquals(lookup_result(found, None), actual) else: self.assertEquals( lookup_result( found, AvailabilityInfo(channel_info, scheduled=scheduled)), actual) for platform in GetPlatforms(): # Allow the LookupResult constructions below to take just one line. avail_finder = self._create_availability_finder( self._node_fs_creator, self._node_fs_iterator, platform) tabs_graph = avail_finder.GetAPINodeAvailability('tabs') fake_tabs_graph = avail_finder.GetAPINodeAvailability('fakeTabs') assertEquals( True, self._branch_utility.GetChannelInfo('trunk'), tabs_graph.Lookup('tabs', 'properties', 'fakeTabsProperty3')) assertEquals(True, self._branch_utility.GetChannelInfo('dev'), tabs_graph.Lookup('tabs', 'events', 'onActivated', 'parameters', 'activeInfo', 'properties', 'windowId'), scheduled=31) assertEquals(True, self._branch_utility.GetChannelInfo('dev'), tabs_graph.Lookup('tabs', 'events', 'onUpdated', 'parameters', 'tab'), scheduled=31) assertEquals(True, self._branch_utility.GetChannelInfo('beta'), tabs_graph.Lookup('tabs', 'events', 'onActivated'), scheduled=30) assertEquals(True, self._branch_utility.GetChannelInfo('beta'), tabs_graph.Lookup('tabs', 'functions', 'get', 'parameters', 'tabId'), scheduled=30) assertEquals( True, self._branch_utility.GetChannelInfo('stable'), tabs_graph.Lookup('tabs', 'types', 'InjectDetails', 'properties', 'code')) assertEquals( True, self._branch_utility.GetChannelInfo('stable'), tabs_graph.Lookup('tabs', 'types', 'InjectDetails', 'properties', 'file')) assertEquals(True, self._branch_utility.GetStableChannelInfo(25), tabs_graph.Lookup('tabs', 'types', 'InjectDetails')) # Test inlined type. assertEquals(True, self._branch_utility.GetChannelInfo('trunk'), tabs_graph.Lookup('tabs', 'types', 'InlinedType')) # Test implicitly inlined type. assertEquals( True, self._branch_utility.GetStableChannelInfo(25), fake_tabs_graph.Lookup('fakeTabs', 'types', 'WasImplicitlyInlinedType')) # Test a node that was restricted to dev channel when it was introduced. assertEquals(True, self._branch_utility.GetChannelInfo('beta'), tabs_graph.Lookup('tabs', 'functions', 'restrictedFunc'), scheduled=30) # Test an explicitly scheduled node. assertEquals(True, self._branch_utility.GetChannelInfo('dev'), tabs_graph.Lookup('tabs', 'functions', 'scheduledFunc'), scheduled=31) # Nothing new in version 24 or 23. assertEquals( True, self._branch_utility.GetStableChannelInfo(22), tabs_graph.Lookup('tabs', 'types', 'Tab', 'properties', 'windowId')) assertEquals( True, self._branch_utility.GetStableChannelInfo(21), tabs_graph.Lookup('tabs', 'types', 'Tab', 'properties', 'selected')) # Nothing new in version 20. assertEquals(True, self._branch_utility.GetStableChannelInfo(19), tabs_graph.Lookup('tabs', 'functions', 'getCurrent')) assertEquals( True, self._branch_utility.GetStableChannelInfo(18), tabs_graph.Lookup('tabs', 'types', 'Tab', 'properties', 'index')) assertEquals( True, self._branch_utility.GetStableChannelInfo(17), tabs_graph.Lookup('tabs', 'events', 'onUpdated', 'parameters', 'changeInfo')) # Nothing new in version 16. assertEquals( True, self._branch_utility.GetStableChannelInfo(15), tabs_graph.Lookup('tabs', 'properties', 'fakeTabsProperty2')) # Everything else is available at the API's release, version 14 here. assertEquals(True, self._branch_utility.GetStableChannelInfo(14), tabs_graph.Lookup('tabs', 'types', 'Tab')) assertEquals( True, self._branch_utility.GetStableChannelInfo(14), tabs_graph.Lookup('tabs', 'types', 'Tab', 'properties', 'url')) assertEquals( True, self._branch_utility.GetStableChannelInfo(14), tabs_graph.Lookup('tabs', 'properties', 'fakeTabsProperty1')) assertEquals( True, self._branch_utility.GetStableChannelInfo(14), tabs_graph.Lookup('tabs', 'functions', 'get', 'parameters', 'callback')) assertEquals(True, self._branch_utility.GetStableChannelInfo(14), tabs_graph.Lookup('tabs', 'events', 'onUpdated')) # Test things that aren't available. assertEquals(False, None, tabs_graph.Lookup('tabs', 'types', 'UpdateInfo')) assertEquals( False, None, tabs_graph.Lookup('tabs', 'functions', 'get', 'parameters', 'callback', 'parameters', 'tab', 'id')) assertEquals(False, None, tabs_graph.Lookup('functions')) assertEquals( False, None, tabs_graph.Lookup('events', 'onActivated', 'parameters', 'activeInfo', 'tabId'))
class HostFileSystemIteratorTest(unittest.TestCase): def setUp(self): def host_file_system_constructor(branch, **optargs): return TestFileSystem(deepcopy( CANNED_API_FILE_SYSTEM_DATA[branch])) host_file_system_provider = HostFileSystemProvider( ObjectStoreCreator.ForTest(), constructor_for_test=host_file_system_constructor) self._branch_utility = TestBranchUtility.CreateWithCannedData() self._iterator = HostFileSystemIterator(host_file_system_provider, self._branch_utility) def _GetStableChannelInfo(self, version): return self._branch_utility.GetStableChannelInfo(version) def _GetChannelInfo(self, channel_name): return self._branch_utility.GetChannelInfo(channel_name) def testAscending(self): # Start at |stable| version 5, and move up towards |trunk|. # Total: 25 file systems. iterations, callback = _GetIterationTracker(0) self.assertEqual( self._iterator.Ascending(self._GetStableChannelInfo(5), callback), self._GetChannelInfo('trunk')) self.assertEqual(len(iterations), 25) # Start at |stable| version 5, and move up towards |trunk|. The callback # fails at |beta|, so the last successful callback was the latest version # of |stable|. Total: 22 file systems. iterations, callback = _GetIterationTracker( self._GetChannelInfo('beta').version) self.assertEqual( self._iterator.Ascending(self._GetStableChannelInfo(5), callback), self._GetChannelInfo('stable')) self.assertEqual(len(iterations), 22) # Start at |stable| version 5, and the callback fails immediately. Since # no file systems are successfully processed, expect a return of None. iterations, callback = _GetIterationTracker(5) self.assertEqual( self._iterator.Ascending(self._GetStableChannelInfo(5), callback), None) self.assertEqual([], iterations) # Start at |stable| version 5, and the callback fails at version 6. # The return should represent |stable| version 5. iterations, callback = _GetIterationTracker(6) self.assertEqual( self._iterator.Ascending(self._GetStableChannelInfo(5), callback), self._GetStableChannelInfo(5)) self.assertEqual([self._GetStableChannelInfo(5)], iterations) # Start at the latest version of |stable|, and the callback fails at # |trunk|. Total: 3 file systems. iterations, callback = _GetIterationTracker('trunk') self.assertEqual( self._iterator.Ascending(self._GetChannelInfo('stable'), callback), self._GetChannelInfo('dev')) self.assertEqual([ self._GetChannelInfo('stable'), self._GetChannelInfo('beta'), self._GetChannelInfo('dev') ], iterations) # Start at |stable| version 10, and the callback fails at |trunk|. iterations, callback = _GetIterationTracker('trunk') self.assertEqual( self._iterator.Ascending(self._GetStableChannelInfo(10), callback), self._GetChannelInfo('dev')) self.assertEqual([ self._GetStableChannelInfo(10), self._GetStableChannelInfo(11), self._GetStableChannelInfo(12), self._GetStableChannelInfo(13), self._GetStableChannelInfo(14), self._GetStableChannelInfo(15), self._GetStableChannelInfo(16), self._GetStableChannelInfo(17), self._GetStableChannelInfo(18), self._GetStableChannelInfo(19), self._GetStableChannelInfo(20), self._GetStableChannelInfo(21), self._GetStableChannelInfo(22), self._GetStableChannelInfo(23), self._GetStableChannelInfo(24), self._GetStableChannelInfo(25), self._GetChannelInfo('stable'), self._GetChannelInfo('beta'), self._GetChannelInfo('dev') ], iterations) def testDescending(self): # Start at |trunk|, and the callback fails immediately. No file systems # are successfully processed, so Descending() will return None. iterations, callback = _GetIterationTracker('trunk') self.assertEqual( self._iterator.Descending(self._GetChannelInfo('trunk'), callback), None) self.assertEqual([], iterations) # Start at |trunk|, and the callback fails at |dev|. Last good iteration # should be |trunk|. iterations, callback = _GetIterationTracker( self._GetChannelInfo('dev').version) self.assertEqual( self._iterator.Descending(self._GetChannelInfo('trunk'), callback), self._GetChannelInfo('trunk')) self.assertEqual([self._GetChannelInfo('trunk')], iterations) # Start at |trunk|, and then move from |dev| down to |stable| at version 5. # Total: 25 file systems. iterations, callback = _GetIterationTracker(0) self.assertEqual( self._iterator.Descending(self._GetChannelInfo('trunk'), callback), self._GetStableChannelInfo(5)) self.assertEqual(len(iterations), 25) # Start at the latest version of |stable|, and move down to |stable| at # version 5. Total: 22 file systems. iterations, callback = _GetIterationTracker(0) self.assertEqual( self._iterator.Descending(self._GetChannelInfo('stable'), callback), self._GetStableChannelInfo(5)) self.assertEqual(len(iterations), 22) # Start at |dev| and iterate down through |stable| versions. The callback # fails at version 10. Total: 18 file systems. iterations, callback = _GetIterationTracker(10) self.assertEqual( self._iterator.Descending(self._GetChannelInfo('dev'), callback), self._GetStableChannelInfo(11)) self.assertEqual([ self._GetChannelInfo('dev'), self._GetChannelInfo('beta'), self._GetStableChannelInfo(26), self._GetStableChannelInfo(25), self._GetStableChannelInfo(24), self._GetStableChannelInfo(23), self._GetStableChannelInfo(22), self._GetStableChannelInfo(21), self._GetStableChannelInfo(20), self._GetStableChannelInfo(19), self._GetStableChannelInfo(18), self._GetStableChannelInfo(17), self._GetStableChannelInfo(16), self._GetStableChannelInfo(15), self._GetStableChannelInfo(14), self._GetStableChannelInfo(13), self._GetStableChannelInfo(12), self._GetStableChannelInfo(11) ], iterations)
class JSCViewWithNodeAvailabilityTest(unittest.TestCase): def setUp(self): tabs_unmodified_versions = (16, 20, 23, 24) self._branch_utility = BranchUtility( os.path.join('branch_utility', 'first.json'), os.path.join('branch_utility', 'second.json'), FakeUrlFetcher(Server2Path('test_data')), ObjectStoreCreator.ForTest()) self._node_fs_creator = FakeHostFileSystemProvider( TABS_SCHEMA_BRANCHES) self._node_fs_iterator = HostFileSystemIterator( self._node_fs_creator, self._branch_utility) test_object_store = ObjectStoreCreator.ForTest() self._avail_finder = AvailabilityFinder( self._branch_utility, CompiledFileSystem.Factory(test_object_store), self._node_fs_iterator, self._node_fs_creator.GetMaster(), test_object_store, 'extensions', SchemaProcessorFactoryForTest()) server_instance = ServerInstance.ForTest( file_system_provider=FakeHostFileSystemProvider( TABS_SCHEMA_BRANCHES)) self._api_models = server_instance.platform_bundle.GetAPIModels( 'extensions') self._json_cache = server_instance.compiled_fs_factory.ForJson( server_instance.host_file_system_provider.GetMaster()) # Imitate the actual SVN file system by incrementing the stats for paths # where an API schema has changed. last_stat = type('last_stat', (object, ), {'val': 0}) def stat_paths(file_system, channel_info): if channel_info.version not in tabs_unmodified_versions: last_stat.val += 1 # HACK: |file_system| is a MockFileSystem backed by a TestFileSystem. # Increment the TestFileSystem stat count. file_system._file_system.IncrementStat(by=last_stat.val) # Continue looping. The iterator will stop after 'master' automatically. return True # Use the HostFileSystemIterator created above to change global stat values # for the TestFileSystems that it creates. self._node_fs_iterator.Ascending( # The earliest version represented with the tabs' test data is 13. self._branch_utility.GetStableChannelInfo(13), stat_paths) @unittest.skipIf(os.name == 'nt', "crbug.com/1114884") def testGetAPINodeAvailability(self): def assertEquals(node, actual): node_availabilities = { 'tabs.Tab': None, 'tabs.fakeTabsProperty1': None, 'tabs.get': None, 'tabs.onUpdated': None, 'tabs.InjectDetails': 25, 'tabs.fakeTabsProperty2': 15, 'tabs.getCurrent': 19, 'tabs.onActivated': 30 } self.assertEquals(node_availabilities[node], actual) model_dict = CreateJSCView( self._api_models.GetContentScriptAPIs().Get(), self._api_models.GetModel('tabs').Get(), self._avail_finder, self._json_cache, _FakeTemplateCache(), _FakeFeaturesBundle(), None, 'extensions', [], Request.ForTest('')) # Test nodes that have the same availability as their parent. # Test type. assertEquals('tabs.Tab', model_dict['types'][0]['availability']) # Test property. assertEquals('tabs.fakeTabsProperty1', model_dict['properties'][1]['availability']) # Test function. assertEquals('tabs.get', model_dict['functions'][1]['availability']) # Test event. assertEquals('tabs.onUpdated', model_dict['events'][1]['availability']) # Test nodes with varying availabilities. # Test type. assertEquals('tabs.InjectDetails', model_dict['types'][1]['availability']['version']) # Test property. assertEquals('tabs.fakeTabsProperty2', model_dict['properties'][3]['availability']['version']) # Test function. assertEquals('tabs.getCurrent', model_dict['functions'][0]['availability']['version']) # Test event. assertEquals('tabs.onActivated', model_dict['events'][0]['availability']['version']) # Test a node that became deprecated. self.assertEquals( { 'scheduled': None, 'version': 26, 'partial': 'motemplate chrome/common/extensions/docs/templates/' + 'private/intro_tables/deprecated_message.html' }, model_dict['types'][2]['availability'])