Esempio n. 1
0
class AvailabilityFinderTest(unittest.TestCase):
    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())
        api_fs_creator = FakeHostFileSystemProvider(
            CANNED_API_FILE_SYSTEM_DATA)
        self._node_fs_creator = FakeHostFileSystemProvider(
            TABS_SCHEMA_BRANCHES)

        def create_availability_finder(host_fs_creator):
            test_object_store = ObjectStoreCreator.ForTest()
            return AvailabilityFinder(
                self._branch_utility,
                CompiledFileSystem.Factory(test_object_store),
                HostFileSystemIterator(host_fs_creator, self._branch_utility),
                host_fs_creator.GetTrunk(), test_object_store)

        self._avail_finder = create_availability_finder(api_fs_creator)
        self._node_avail_finder = create_availability_finder(
            self._node_fs_creator)

        # 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_avail_finder._file_system_iterator.Ascending(
            # The earliest version represented with the tabs' test data is 13.
            self._branch_utility.GetStableChannelInfo(13),
            stat_paths)

    def testGraphOptimization(self):
        # 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

        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.
            self._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.

        # Testing APIs with predetermined availability.
        self.assertEqual(
            AvailabilityInfo(ChannelInfo('trunk', 'trunk', 'trunk')),
            self._avail_finder.GetAPIAvailability('jsonTrunkAPI'))
        self.assertEqual(
            AvailabilityInfo(ChannelInfo('dev', CANNED_BRANCHES[28], 28)),
            self._avail_finder.GetAPIAvailability('jsonDevAPI'))
        self.assertEqual(
            AvailabilityInfo(ChannelInfo('beta', CANNED_BRANCHES[27], 27)),
            self._avail_finder.GetAPIAvailability('jsonBetaAPI'))
        self.assertEqual(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[20], 20)),
            self._avail_finder.GetAPIAvailability('jsonStableAPI'))

        # Testing a whitelisted API.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('beta', CANNED_BRANCHES[27], 27)),
            self._avail_finder.GetAPIAvailability('declarativeWebRequest'))

        # Testing APIs found only by checking file system existence.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[23], 23)),
            self._avail_finder.GetAPIAvailability('windows'))
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[18], 18)),
            self._avail_finder.GetAPIAvailability('tabs'))
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[18], 18)),
            self._avail_finder.GetAPIAvailability('input.ime'))

        # Testing API channel existence for _api_features.json.
        # Listed as 'dev' on |beta|, 'dev' on |dev|.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('dev', CANNED_BRANCHES[28], 28)),
            self._avail_finder.GetAPIAvailability('systemInfo.stuff'))
        # Listed as 'stable' on |beta|.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('beta', CANNED_BRANCHES[27], 27),
                             scheduled=28),
            self._avail_finder.GetAPIAvailability('systemInfo.cpu'))

        # Testing API channel existence for _manifest_features.json.
        # Listed as 'trunk' on all channels.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('trunk', 'trunk', 'trunk')),
            self._avail_finder.GetAPIAvailability('sync'))
        # No records of API until |trunk|.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('trunk', 'trunk', 'trunk')),
            self._avail_finder.GetAPIAvailability('history'))
        # Listed as 'dev' on |dev|.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('dev', CANNED_BRANCHES[28], 28)),
            self._avail_finder.GetAPIAvailability('storage'))
        # Stable in _manifest_features and into pre-18 versions.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[8], 8)),
            self._avail_finder.GetAPIAvailability('pageAction'))

        # Testing API channel existence for _permission_features.json.
        # Listed as 'beta' on |trunk|.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('trunk', 'trunk', 'trunk')),
            self._avail_finder.GetAPIAvailability('falseBetaAPI'))
        # Listed as 'trunk' on |trunk|.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('trunk', 'trunk', 'trunk')),
            self._avail_finder.GetAPIAvailability('trunkAPI'))
        # Listed as 'trunk' on all development channels.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('trunk', 'trunk', 'trunk')),
            self._avail_finder.GetAPIAvailability('declarativeContent'))
        # Listed as 'dev' on all development channels.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('dev', CANNED_BRANCHES[28], 28)),
            self._avail_finder.GetAPIAvailability('bluetooth'))
        # Listed as 'dev' on |dev|.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('dev', CANNED_BRANCHES[28], 28)),
            self._avail_finder.GetAPIAvailability('cookies'))
        # Treated as 'stable' APIs.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[24], 24)),
            self._avail_finder.GetAPIAvailability('alarms'))
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[21], 21)),
            self._avail_finder.GetAPIAvailability('bookmarks'))

        # Testing older API existence using extension_api.json.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[6], 6)),
            self._avail_finder.GetAPIAvailability('menus'))
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[5], 5)),
            self._avail_finder.GetAPIAvailability('idle'))

        # Switches between _features.json files across branches.
        # Listed as 'trunk' on all channels, in _api, _permission, or _manifest.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('trunk', 'trunk', 'trunk')),
            self._avail_finder.GetAPIAvailability('contextMenus'))
        # Moves between _permission and _manifest as file system is traversed.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[23], 23)),
            self._avail_finder.GetAPIAvailability('systemInfo.display'))
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('stable', CANNED_BRANCHES[17], 17)),
            self._avail_finder.GetAPIAvailability('webRequest'))

        # Mid-upgrade cases:
        # Listed as 'dev' on |beta| and 'beta' on |dev|.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('dev', CANNED_BRANCHES[28], 28)),
            self._avail_finder.GetAPIAvailability('notifications'))
        # Listed as 'beta' on |stable|, 'dev' on |beta| ... until |stable| on trunk.
        self.assertEquals(
            AvailabilityInfo(ChannelInfo('trunk', 'trunk', 'trunk')),
            self._avail_finder.GetAPIAvailability('events'))

    def testGetAPINodeAvailability(self):
        # Allow the LookupResult constructions below to take just one line.
        lookup_result = api_schema_graph.LookupResult
        availability_graph = self._node_avail_finder.GetAPINodeAvailability(
            'tabs')

        self.assertEquals(
            lookup_result(True, self._branch_utility.GetChannelInfo('trunk')),
            availability_graph.Lookup('tabs', 'properties',
                                      'fakeTabsProperty3'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetChannelInfo('dev')),
            availability_graph.Lookup('tabs', 'events', 'onActivated',
                                      'parameters', 'activeInfo', 'properties',
                                      'windowId'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetChannelInfo('dev')),
            availability_graph.Lookup('tabs', 'events', 'onUpdated',
                                      'parameters', 'tab'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetChannelInfo('beta')),
            availability_graph.Lookup('tabs', 'events', 'onActivated'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetChannelInfo('beta')),
            availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
                                      'tabId'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetChannelInfo('stable')),
            availability_graph.Lookup('tabs', 'types', 'InjectDetails',
                                      'properties', 'code'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetChannelInfo('stable')),
            availability_graph.Lookup('tabs', 'types', 'InjectDetails',
                                      'properties', 'file'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(25)),
            availability_graph.Lookup('tabs', 'types', 'InjectDetails'))

        # Nothing new in version 24 or 23.

        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(22)),
            availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
                                      'windowId'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(21)),
            availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
                                      'selected'))

        # Nothing new in version 20.

        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(19)),
            availability_graph.Lookup('tabs', 'functions', 'getCurrent'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(18)),
            availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
                                      'index'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(17)),
            availability_graph.Lookup('tabs', 'events', 'onUpdated',
                                      'parameters', 'changeInfo'))

        # Nothing new in version 16.

        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(15)),
            availability_graph.Lookup('tabs', 'properties',
                                      'fakeTabsProperty2'))

        # Everything else is available at the API's release, version 14 here.
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'types', 'Tab'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
                                      'url'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'properties',
                                      'fakeTabsProperty1'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
                                      'callback'))
        self.assertEquals(
            lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'events', 'onUpdated'))

        # Test things that aren't available.
        self.assertEqual(
            lookup_result(False, None),
            availability_graph.Lookup('tabs', 'types', 'UpdateInfo'))
        self.assertEqual(
            lookup_result(False, None),
            availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
                                      'callback', 'parameters', 'tab', 'id'))
        self.assertEqual(lookup_result(False, None),
                         availability_graph.Lookup('functions'))
        self.assertEqual(
            lookup_result(False, None),
            availability_graph.Lookup('events', 'onActivated', 'parameters',
                                      'activeInfo', 'tabId'))
Esempio n. 2
0
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'])
Esempio n. 3
0
class AvailabilityFinderTest(unittest.TestCase):
    def setUp(self):
        self._branch_utility = 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())

        def create_availability_finder(file_system_data):
            fake_host_fs_creator = FakeHostFileSystemProvider(file_system_data)
            test_object_store = ObjectStoreCreator.ForTest()
            return AvailabilityFinder(
                self._branch_utility,
                CompiledFileSystem.Factory(test_object_store),
                HostFileSystemIterator(fake_host_fs_creator,
                                       self._branch_utility),
                fake_host_fs_creator.GetTrunk(), test_object_store)

        self._avail_finder = create_availability_finder(
            CANNED_API_FILE_SYSTEM_DATA)
        self._node_avail_finder = create_availability_finder(
            TABS_SCHEMA_BRANCHES)

    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 a whitelisted API.
        self.assertEquals(
            ChannelInfo('beta', CANNED_BRANCHES[27], 27),
            self._avail_finder.GetApiAvailability('declarativeWebRequest'))

        # Testing APIs found only by checking file system existence.
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[23], 23),
                          self._avail_finder.GetApiAvailability('windows'))
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[18], 18),
                          self._avail_finder.GetApiAvailability('tabs'))
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[18], 18),
                          self._avail_finder.GetApiAvailability('input.ime'))

        # Testing API channel existence for _api_features.json.
        # Listed as 'dev' on |beta|, 'dev' on |dev|.
        self.assertEquals(
            ChannelInfo('dev', CANNED_BRANCHES[28], 28),
            self._avail_finder.GetApiAvailability('systemInfo.stuff'))
        # Listed as 'stable' on |beta|.
        self.assertEquals(
            ChannelInfo('beta', CANNED_BRANCHES[27], 27),
            self._avail_finder.GetApiAvailability('systemInfo.cpu'))

        # Testing API channel existence for _manifest_features.json.
        # Listed as 'trunk' on all channels.
        self.assertEquals(ChannelInfo('trunk', 'trunk', 'trunk'),
                          self._avail_finder.GetApiAvailability('sync'))
        # No records of API until |trunk|.
        self.assertEquals(ChannelInfo('trunk', 'trunk', 'trunk'),
                          self._avail_finder.GetApiAvailability('history'))
        # Listed as 'dev' on |dev|.
        self.assertEquals(ChannelInfo('dev', CANNED_BRANCHES[28], 28),
                          self._avail_finder.GetApiAvailability('storage'))
        # Stable in _manifest_features and into pre-18 versions.
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[8], 8),
                          self._avail_finder.GetApiAvailability('pageAction'))

        # Testing API channel existence for _permission_features.json.
        # Listed as 'beta' on |trunk|.
        self.assertEquals(
            ChannelInfo('trunk', 'trunk', 'trunk'),
            self._avail_finder.GetApiAvailability('falseBetaAPI'))
        # Listed as 'trunk' on |trunk|.
        self.assertEquals(ChannelInfo('trunk', 'trunk', 'trunk'),
                          self._avail_finder.GetApiAvailability('trunkAPI'))
        # Listed as 'trunk' on all development channels.
        self.assertEquals(
            ChannelInfo('trunk', 'trunk', 'trunk'),
            self._avail_finder.GetApiAvailability('declarativeContent'))
        # Listed as 'dev' on all development channels.
        self.assertEquals(ChannelInfo('dev', CANNED_BRANCHES[28], 28),
                          self._avail_finder.GetApiAvailability('bluetooth'))
        # Listed as 'dev' on |dev|.
        self.assertEquals(ChannelInfo('dev', CANNED_BRANCHES[28], 28),
                          self._avail_finder.GetApiAvailability('cookies'))
        # Treated as 'stable' APIs.
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[24], 24),
                          self._avail_finder.GetApiAvailability('alarms'))
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[21], 21),
                          self._avail_finder.GetApiAvailability('bookmarks'))

        # Testing older API existence using extension_api.json.
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[6], 6),
                          self._avail_finder.GetApiAvailability('menus'))
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[5], 5),
                          self._avail_finder.GetApiAvailability('idle'))

        # Switches between _features.json files across branches.
        # Listed as 'trunk' on all channels, in _api, _permission, or _manifest.
        self.assertEquals(
            ChannelInfo('trunk', 'trunk', 'trunk'),
            self._avail_finder.GetApiAvailability('contextMenus'))
        # Moves between _permission and _manifest as file system is traversed.
        self.assertEquals(
            ChannelInfo('stable', CANNED_BRANCHES[23], 23),
            self._avail_finder.GetApiAvailability('systemInfo.display'))
        self.assertEquals(ChannelInfo('stable', CANNED_BRANCHES[17], 17),
                          self._avail_finder.GetApiAvailability('webRequest'))

        # Mid-upgrade cases:
        # Listed as 'dev' on |beta| and 'beta' on |dev|.
        self.assertEquals(
            ChannelInfo('dev', CANNED_BRANCHES[28], 28),
            self._avail_finder.GetApiAvailability('notifications'))
        # Listed as 'beta' on |stable|, 'dev' on |beta| ... until |stable| on trunk.
        self.assertEquals(ChannelInfo('trunk', 'trunk', 'trunk'),
                          self._avail_finder.GetApiAvailability('events'))

    def testGetApiNodeAvailability(self):
        availability_graph = self._node_avail_finder.GetApiNodeAvailability(
            'tabs')

        self.assertEquals(
            LookupResult(True, self._branch_utility.GetChannelInfo('trunk')),
            availability_graph.Lookup('tabs', 'properties',
                                      'fakeTabsProperty3'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetChannelInfo('dev')),
            availability_graph.Lookup('tabs', 'events', 'onActivated',
                                      'parameters', 'activeInfo', 'properties',
                                      'windowId'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetChannelInfo('dev')),
            availability_graph.Lookup('tabs', 'events', 'onUpdated',
                                      'parameters', 'tab'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetChannelInfo('beta')),
            availability_graph.Lookup('tabs', 'events', 'onActivated'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetChannelInfo('beta')),
            availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
                                      'tabId'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetChannelInfo('stable')),
            availability_graph.Lookup('tabs', 'types', 'InjectDetails',
                                      'properties', 'code'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetChannelInfo('stable')),
            availability_graph.Lookup('tabs', 'types', 'InjectDetails',
                                      'properties', 'file'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(25)),
            availability_graph.Lookup('tabs', 'types', 'InjectDetails'))

        # Nothing new in version 24 or 23.

        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(22)),
            availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
                                      'windowId'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(21)),
            availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
                                      'selected'))

        # Nothing new in version 20.

        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(19)),
            availability_graph.Lookup('tabs', 'functions', 'getCurrent'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(18)),
            availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
                                      'index'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(17)),
            availability_graph.Lookup('tabs', 'events', 'onUpdated',
                                      'parameters', 'changeInfo'))

        # Nothing new in version 16.

        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(15)),
            availability_graph.Lookup('tabs', 'properties',
                                      'fakeTabsProperty2'))

        # Everything else is available at the API's release, version 14 here.
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'types', 'Tab'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
                                      'url'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'properties',
                                      'fakeTabsProperty1'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
                                      'callback'))
        self.assertEquals(
            LookupResult(True, self._branch_utility.GetStableChannelInfo(14)),
            availability_graph.Lookup('tabs', 'events', 'onUpdated'))

        # Test things that aren't available.
        self.assertEqual(
            LookupResult(False, None),
            availability_graph.Lookup('tabs', 'types', 'UpdateInfo'))
        self.assertEqual(
            LookupResult(False, None),
            availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
                                      'callback', 'parameters', 'tab', 'id'))
        self.assertEqual(LookupResult(False, None),
                         availability_graph.Lookup('functions'))
        self.assertEqual(
            LookupResult(False, None),
            availability_graph.Lookup('events', 'onActivated', 'parameters',
                                      'activeInfo', 'tabId'))
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.GetMaster(), test_object_store, platform,
            SchemaProcessorFactoryForTest())

    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 '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 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

    @unittest.skipIf(os.name == 'nt', "crbug.com/1114884")
    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('master', 'master', 'master'), 'jsonMasterAPI')
        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 'master' on all channels.
        assertGet(ChannelInfo('master', 'master', 'master'), 'sync')
        # Listed as 'trunk'. See crbug.com/883009.
        assertGet(ChannelInfo('master', 'master', 'master'),
                  'declarativeNetRequest')
        # No records of API until |master|.
        assertGet(ChannelInfo('master', 'master', 'master'), '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 |master|.
        assertGet(ChannelInfo('master', 'master', 'master'), 'falseBetaAPI')
        # Listed as 'master' on |master|.
        assertGet(ChannelInfo('master', 'master', 'master'), 'masterAPI')
        # Listed as 'master' on all development channels.
        assertGet(ChannelInfo('master', 'master', 'master'),
                  '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 'master' on all channels, in _api, _permission, or _manifest.
        assertGet(ChannelInfo('master', 'master', 'master'), '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 master.
        assertGet(ChannelInfo('master', 'master', 'master'), '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')

    @unittest.skipIf(os.name == 'nt', "crbug.com/1114884")
    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')

            # Test an API node with predetermined availability.
            assertEquals(
                True, self._branch_utility.GetStableChannelInfo(27),
                tabs_graph.Lookup('tabs', 'properties', 'fakeTabsProperty4'))

            assertEquals(
                True, self._branch_utility.GetChannelInfo('master'),
                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('master'),
                         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'))