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)
Exemple #3
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'])