availability_finder_test.py revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1#!/usr/bin/env python
2# Copyright 2013 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5import os
6import sys
7import unittest
8from collections import namedtuple
9
10import api_schema_graph
11from availability_finder import AvailabilityFinder
12from branch_utility import BranchUtility, ChannelInfo
13from compiled_file_system import CompiledFileSystem
14from fake_url_fetcher import FakeUrlFetcher
15from host_file_system_iterator import HostFileSystemIterator
16from mock_file_system import MockFileSystem
17from mock_function import MockFunction
18from object_store_creator import ObjectStoreCreator
19from test_file_system import TestFileSystem
20from test_data.canned_data import (CANNED_API_FILE_SYSTEM_DATA, CANNED_BRANCHES)
21from test_data.object_level_availability.tabs import TABS_SCHEMA_BRANCHES
22from third_party.json_schema_compiler.memoize import memoize
23
24
25TABS_UNMODIFIED_VERSIONS = (16, 20, 23, 24)
26
27
28class _FakeHostFileSystemProvider(object):
29
30  def __init__(self, file_system_data):
31    self._file_system_data = file_system_data
32
33  def GetTrunk(self):
34    return self.GetBranch('trunk')
35
36  @memoize
37  def GetBranch(self, branch):
38    return MockFileSystem(TestFileSystem(self._file_system_data[str(branch)]))
39
40
41class AvailabilityFinderTest(unittest.TestCase):
42
43  def setUp(self):
44    self._branch_utility = BranchUtility(
45        os.path.join('branch_utility', 'first.json'),
46        os.path.join('branch_utility', 'second.json'),
47        FakeUrlFetcher(os.path.join(sys.path[0], 'test_data')),
48        ObjectStoreCreator.ForTest())
49    api_fs_creator = _FakeHostFileSystemProvider(CANNED_API_FILE_SYSTEM_DATA)
50    self._node_fs_creator = _FakeHostFileSystemProvider(TABS_SCHEMA_BRANCHES)
51
52    def create_availability_finder(host_fs_creator):
53      test_object_store = ObjectStoreCreator.ForTest()
54      return AvailabilityFinder(
55          self._branch_utility,
56          CompiledFileSystem.Factory(test_object_store),
57          HostFileSystemIterator(host_fs_creator,
58                                 self._branch_utility),
59          host_fs_creator.GetTrunk(),
60          test_object_store)
61
62    self._avail_finder = create_availability_finder(api_fs_creator)
63    self._node_avail_finder = create_availability_finder(self._node_fs_creator)
64
65    # Imitate the actual SVN file system by incrementing the stats for paths
66    # where an API schema has changed.
67    last_stat = type('last_stat', (object,), {'val': 0})
68
69    def stat_paths(file_system, channel_info):
70      if channel_info.version not in TABS_UNMODIFIED_VERSIONS:
71        last_stat.val += 1
72      # HACK: |file_system| is a MockFileSystem backed by a TestFileSystem.
73      # Increment the TestFileSystem stat count.
74      file_system._file_system.IncrementStat(by=last_stat.val)
75      # Continue looping. The iterator will stop after 'trunk' automatically.
76      return True
77
78    # Use the HostFileSystemIterator created above to change global stat values
79    # for the TestFileSystems that it creates.
80    self._node_avail_finder._file_system_iterator.Ascending(
81        # The earliest version represented with the tabs' test data is 13.
82        self._branch_utility.GetStableChannelInfo(13),
83        stat_paths)
84
85  def testGraphOptimization(self):
86    # Keep track of how many times the APISchemaGraph constructor is called.
87    original_constructor = api_schema_graph.APISchemaGraph
88    mock_constructor = MockFunction(original_constructor)
89    api_schema_graph.APISchemaGraph = mock_constructor
90
91    try:
92      # The test data includes an extra branch where the API does not exist.
93      num_versions = len(TABS_SCHEMA_BRANCHES) - 1
94      # We expect an APISchemaGraph to be created only when an API schema file
95      # has different stat data from the previous version's schema file.
96      num_graphs_created = num_versions - len(TABS_UNMODIFIED_VERSIONS)
97
98      # Run the logic for object-level availability for an API.
99      self._node_avail_finder.GetApiNodeAvailability('tabs')
100
101      self.assertTrue(*api_schema_graph.APISchemaGraph.CheckAndReset(
102          num_graphs_created))
103    finally:
104      # Ensure that the APISchemaGraph constructor is reset to be the original
105      # constructor.
106      api_schema_graph.APISchemaGraph = original_constructor
107
108  def testGetApiAvailability(self):
109    # Key: Using 'channel' (i.e. 'beta') to represent an availability listing
110    # for an API in a _features.json file, and using |channel| (i.e. |dev|) to
111    # represent the development channel, or phase of development, where an API's
112    # availability is being checked.
113
114    # Testing APIs with predetermined availability.
115    self.assertEqual(
116        ChannelInfo('trunk', 'trunk', 'trunk'),
117        self._avail_finder.GetApiAvailability('jsonTrunkAPI'))
118    self.assertEqual(
119        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
120        self._avail_finder.GetApiAvailability('jsonDevAPI'))
121    self.assertEqual(
122        ChannelInfo('beta', CANNED_BRANCHES[27], 27),
123        self._avail_finder.GetApiAvailability('jsonBetaAPI'))
124    self.assertEqual(
125        ChannelInfo('stable', CANNED_BRANCHES[20], 20),
126        self._avail_finder.GetApiAvailability('jsonStableAPI'))
127
128    # Testing a whitelisted API.
129    self.assertEquals(
130        ChannelInfo('beta', CANNED_BRANCHES[27], 27),
131        self._avail_finder.GetApiAvailability('declarativeWebRequest'))
132
133    # Testing APIs found only by checking file system existence.
134    self.assertEquals(
135        ChannelInfo('stable', CANNED_BRANCHES[23], 23),
136        self._avail_finder.GetApiAvailability('windows'))
137    self.assertEquals(
138        ChannelInfo('stable', CANNED_BRANCHES[18], 18),
139        self._avail_finder.GetApiAvailability('tabs'))
140    self.assertEquals(
141        ChannelInfo('stable', CANNED_BRANCHES[18], 18),
142        self._avail_finder.GetApiAvailability('input.ime'))
143
144    # Testing API channel existence for _api_features.json.
145    # Listed as 'dev' on |beta|, 'dev' on |dev|.
146    self.assertEquals(
147        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
148        self._avail_finder.GetApiAvailability('systemInfo.stuff'))
149    # Listed as 'stable' on |beta|.
150    self.assertEquals(
151        ChannelInfo('beta', CANNED_BRANCHES[27], 27),
152        self._avail_finder.GetApiAvailability('systemInfo.cpu'))
153
154    # Testing API channel existence for _manifest_features.json.
155    # Listed as 'trunk' on all channels.
156    self.assertEquals(
157        ChannelInfo('trunk', 'trunk', 'trunk'),
158        self._avail_finder.GetApiAvailability('sync'))
159    # No records of API until |trunk|.
160    self.assertEquals(
161        ChannelInfo('trunk', 'trunk', 'trunk'),
162        self._avail_finder.GetApiAvailability('history'))
163    # Listed as 'dev' on |dev|.
164    self.assertEquals(
165        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
166        self._avail_finder.GetApiAvailability('storage'))
167    # Stable in _manifest_features and into pre-18 versions.
168    self.assertEquals(
169        ChannelInfo('stable', CANNED_BRANCHES[8], 8),
170        self._avail_finder.GetApiAvailability('pageAction'))
171
172    # Testing API channel existence for _permission_features.json.
173    # Listed as 'beta' on |trunk|.
174    self.assertEquals(
175        ChannelInfo('trunk', 'trunk', 'trunk'),
176        self._avail_finder.GetApiAvailability('falseBetaAPI'))
177    # Listed as 'trunk' on |trunk|.
178    self.assertEquals(
179        ChannelInfo('trunk', 'trunk', 'trunk'),
180        self._avail_finder.GetApiAvailability('trunkAPI'))
181    # Listed as 'trunk' on all development channels.
182    self.assertEquals(
183        ChannelInfo('trunk', 'trunk', 'trunk'),
184        self._avail_finder.GetApiAvailability('declarativeContent'))
185    # Listed as 'dev' on all development channels.
186    self.assertEquals(
187        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
188        self._avail_finder.GetApiAvailability('bluetooth'))
189    # Listed as 'dev' on |dev|.
190    self.assertEquals(
191        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
192        self._avail_finder.GetApiAvailability('cookies'))
193    # Treated as 'stable' APIs.
194    self.assertEquals(
195        ChannelInfo('stable', CANNED_BRANCHES[24], 24),
196        self._avail_finder.GetApiAvailability('alarms'))
197    self.assertEquals(
198        ChannelInfo('stable', CANNED_BRANCHES[21], 21),
199        self._avail_finder.GetApiAvailability('bookmarks'))
200
201    # Testing older API existence using extension_api.json.
202    self.assertEquals(
203        ChannelInfo('stable', CANNED_BRANCHES[6], 6),
204        self._avail_finder.GetApiAvailability('menus'))
205    self.assertEquals(
206        ChannelInfo('stable', CANNED_BRANCHES[5], 5),
207        self._avail_finder.GetApiAvailability('idle'))
208
209    # Switches between _features.json files across branches.
210    # Listed as 'trunk' on all channels, in _api, _permission, or _manifest.
211    self.assertEquals(
212        ChannelInfo('trunk', 'trunk', 'trunk'),
213        self._avail_finder.GetApiAvailability('contextMenus'))
214    # Moves between _permission and _manifest as file system is traversed.
215    self.assertEquals(
216        ChannelInfo('stable', CANNED_BRANCHES[23], 23),
217        self._avail_finder.GetApiAvailability('systemInfo.display'))
218    self.assertEquals(
219        ChannelInfo('stable', CANNED_BRANCHES[17], 17),
220        self._avail_finder.GetApiAvailability('webRequest'))
221
222    # Mid-upgrade cases:
223    # Listed as 'dev' on |beta| and 'beta' on |dev|.
224    self.assertEquals(
225        ChannelInfo('dev', CANNED_BRANCHES[28], 28),
226        self._avail_finder.GetApiAvailability('notifications'))
227    # Listed as 'beta' on |stable|, 'dev' on |beta| ... until |stable| on trunk.
228    self.assertEquals(
229        ChannelInfo('trunk', 'trunk', 'trunk'),
230        self._avail_finder.GetApiAvailability('events'))
231
232  def testGetApiNodeAvailability(self):
233    # Allow the LookupResult constructions below to take just one line.
234    lookup_result = api_schema_graph.LookupResult
235    availability_graph = self._node_avail_finder.GetApiNodeAvailability('tabs')
236
237    self.assertEquals(
238        lookup_result(True, self._branch_utility.GetChannelInfo('trunk')),
239        availability_graph.Lookup('tabs', 'properties',
240                                  'fakeTabsProperty3'))
241    self.assertEquals(
242        lookup_result(True, self._branch_utility.GetChannelInfo('dev')),
243        availability_graph.Lookup('tabs', 'events', 'onActivated',
244                                  'parameters', 'activeInfo', 'properties',
245                                  'windowId'))
246    self.assertEquals(
247        lookup_result(True, self._branch_utility.GetChannelInfo('dev')),
248        availability_graph.Lookup('tabs', 'events', 'onUpdated', 'parameters',
249                                  'tab'))
250    self.assertEquals(
251        lookup_result(True, self._branch_utility.GetChannelInfo('beta')),
252        availability_graph.Lookup('tabs', 'events','onActivated'))
253    self.assertEquals(
254        lookup_result(True, self._branch_utility.GetChannelInfo('beta')),
255        availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
256                                  'tabId'))
257    self.assertEquals(
258        lookup_result(True, self._branch_utility.GetChannelInfo('stable')),
259        availability_graph.Lookup('tabs', 'types', 'InjectDetails',
260                                  'properties', 'code'))
261    self.assertEquals(
262        lookup_result(True, self._branch_utility.GetChannelInfo('stable')),
263        availability_graph.Lookup('tabs', 'types', 'InjectDetails',
264                                  'properties', 'file'))
265    self.assertEquals(
266        lookup_result(True, self._branch_utility.GetStableChannelInfo(25)),
267        availability_graph.Lookup('tabs', 'types', 'InjectDetails'))
268
269    # Nothing new in version 24 or 23.
270
271    self.assertEquals(
272        lookup_result(True, self._branch_utility.GetStableChannelInfo(22)),
273        availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
274                                  'windowId'))
275    self.assertEquals(
276        lookup_result(True, self._branch_utility.GetStableChannelInfo(21)),
277        availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
278                                  'selected'))
279
280    # Nothing new in version 20.
281
282    self.assertEquals(
283        lookup_result(True, self._branch_utility.GetStableChannelInfo(19)),
284        availability_graph.Lookup('tabs', 'functions', 'getCurrent'))
285    self.assertEquals(
286        lookup_result(True, self._branch_utility.GetStableChannelInfo(18)),
287        availability_graph.Lookup('tabs', 'types', 'Tab', 'properties',
288                                  'index'))
289    self.assertEquals(
290        lookup_result(True, self._branch_utility.GetStableChannelInfo(17)),
291        availability_graph.Lookup('tabs', 'events', 'onUpdated', 'parameters',
292                                  'changeInfo'))
293
294    # Nothing new in version 16.
295
296    self.assertEquals(
297        lookup_result(True, self._branch_utility.GetStableChannelInfo(15)),
298        availability_graph.Lookup('tabs', 'properties',
299                                  'fakeTabsProperty2'))
300
301    # Everything else is available at the API's release, version 14 here.
302    self.assertEquals(
303        lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
304        availability_graph.Lookup('tabs', 'types', 'Tab'))
305    self.assertEquals(
306        lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
307        availability_graph.Lookup('tabs', 'types', 'Tab',
308                                  'properties', 'url'))
309    self.assertEquals(
310        lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
311        availability_graph.Lookup('tabs', 'properties',
312                                  'fakeTabsProperty1'))
313    self.assertEquals(
314        lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
315        availability_graph.Lookup('tabs', 'functions', 'get', 'parameters',
316                                  'callback'))
317    self.assertEquals(
318        lookup_result(True, self._branch_utility.GetStableChannelInfo(14)),
319        availability_graph.Lookup('tabs', 'events', 'onUpdated'))
320
321    # Test things that aren't available.
322    self.assertEqual(lookup_result(False, None),
323                     availability_graph.Lookup('tabs', 'types',
324                                               'UpdateInfo'))
325    self.assertEqual(lookup_result(False, None),
326                     availability_graph.Lookup('tabs', 'functions', 'get',
327                                               'parameters', 'callback',
328                                               'parameters', 'tab', 'id'))
329    self.assertEqual(lookup_result(False, None),
330                     availability_graph.Lookup('functions'))
331    self.assertEqual(lookup_result(False, None),
332                     availability_graph.Lookup('events', 'onActivated',
333                                               'parameters', 'activeInfo',
334                                               'tabId'))
335
336
337if __name__ == '__main__':
338  unittest.main()
339