11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#!/usr/bin/env python
21e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
31e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
41e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)# found in the LICENSE file.
51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
61e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import json
71e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)import unittest
81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
91e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from api_models import APIModels
101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from compiled_file_system import CompiledFileSystem
11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochfrom extensions_paths import API_PATHS, CHROME_API, CHROME_EXTENSIONS
121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from features_bundle import FeaturesBundle
131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from file_system import FileNotFoundError
140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)from mock_file_system import MockFileSystem
151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from object_store_creator import ObjectStoreCreator
161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from test_file_system import TestFileSystem
171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)from test_util import ReadFile
181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)_TEST_DATA = {
211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  'api': {
221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    'devtools': {
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      'inspected_window.json': ReadFile(
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          CHROME_API, 'devtools', 'inspected_window.json'),
251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    },
261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    '_api_features.json': json.dumps({
271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      'alarms': {},
280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      'app': {},
290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      'app.runtime': {'noparent': True},
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      'app.runtime.foo': {},
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      'declarativeWebRequest': {},
321e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      'devtools.inspectedWindow': {},
33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      'input': {},
34c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      'input.ime': {},
351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      'storage': {},
361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }),
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    '_manifest_features.json': '{}',
381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    '_permission_features.json': '{}',
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    'alarms.idl': ReadFile(CHROME_API, 'alarms.idl'),
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    'declarative_web_request.json': ReadFile(
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        CHROME_API, 'declarative_web_request.json'),
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    'input_ime.json': ReadFile(CHROME_API, 'input_ime.json'),
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    'page_action.json': ReadFile(CHROME_API, 'page_action.json'),
441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  },
451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  'docs': {
461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    'templates': {
471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      'json': {
481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        'manifest.json': '{}',
491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        'permissions.json': '{}',
501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      }
511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  },
531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)class APIModelsTest(unittest.TestCase):
571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def setUp(self):
581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    object_store_creator = ObjectStoreCreator.ForTest()
591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    compiled_fs_factory = CompiledFileSystem.Factory(object_store_creator)
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self._mock_file_system = MockFileSystem(
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        TestFileSystem(_TEST_DATA, relative_to=CHROME_EXTENSIONS))
621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    features_bundle = FeaturesBundle(
630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        self._mock_file_system, compiled_fs_factory, object_store_creator)
641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self._api_models = APIModels(
650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        features_bundle, compiled_fs_factory, self._mock_file_system)
661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def testGetNames(self):
680f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    # Both 'app' and 'app.runtime' appear here because 'app.runtime' has
69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    # noparent:true, but 'app.runtime.foo' etc doesn't so it's a sub-feature of
70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    # 'app.runtime' not a separate API. 'devtools.inspectedWindow' is an API
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    # because there is no 'devtools'.
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual(
730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        ['alarms', 'app', 'app.runtime', 'declarativeWebRequest',
74c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch         'devtools.inspectedWindow', 'input', 'storage'],
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        sorted(self._api_models.GetNames()))
761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def testGetModel(self):
781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    def get_model_name(api_name):
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      return self._api_models.GetModel(api_name).Get().name
801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('devtools.inspectedWindow',
811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                     get_model_name('devtools.inspectedWindow'))
821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('devtools.inspectedWindow',
831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                     get_model_name('devtools/inspected_window.json'))
841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('devtools.inspectedWindow',
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     get_model_name(CHROME_API +
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                    'devtools/inspected_window.json'))
871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('alarms', get_model_name('alarms'))
881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('alarms', get_model_name('alarms.idl'))
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertEqual('alarms', get_model_name(CHROME_API + 'alarms.idl'))
901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('declarativeWebRequest',
911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                     get_model_name('declarativeWebRequest'))
921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('declarativeWebRequest',
931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                     get_model_name('declarative_web_request.json'))
941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('declarativeWebRequest',
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     get_model_name(CHROME_API +
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                    'declarative_web_request.json'))
97c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.assertEqual('input.ime', get_model_name('input.ime'))
98c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.assertEqual('input.ime', get_model_name('input_ime.json'))
99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    self.assertEqual('input.ime',
100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     get_model_name(CHROME_API + 'input_ime.json'))
1011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('pageAction', get_model_name('pageAction'))
1021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertEqual('pageAction', get_model_name('page_action.json'))
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertEqual('pageAction', get_model_name(CHROME_API +
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                  'page_action.json'))
1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def testGetNonexistentModel(self):
1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertRaises(FileNotFoundError,
1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      self._api_models.GetModel('notfound').Get)
1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertRaises(FileNotFoundError,
1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      self._api_models.GetModel('notfound.json').Get)
1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertRaises(FileNotFoundError,
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                      self._api_models.GetModel(CHROME_API +
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                'notfound.json').Get)
1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertRaises(FileNotFoundError,
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                      self._api_models.GetModel(CHROME_API +
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                'alarms.json').Get)
1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertRaises(FileNotFoundError,
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                      self._api_models.GetModel('storage').Get)
1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertRaises(FileNotFoundError,
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                      self._api_models.GetModel(CHROME_API +
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                'storage.json').Get)
1221e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.assertRaises(FileNotFoundError,
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                      self._api_models.GetModel(CHROME_API +
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                                'storage.idl').Get)
1251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  def testSingleFile(self):
127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    # 2 stats (1 for JSON and 1 for IDL) for each available API path.
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # 1 read (for IDL file which existed).
1290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    future = self._api_models.GetModel('alarms')
1300f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    self.assertTrue(*self._mock_file_system.CheckAndReset(
131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        read_count=1, stat_count=len(API_PATHS)*2))
1320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    # 1 read-resolve (for the IDL file).
1340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    #
1350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    # The important part here and above is that it's only doing a single read;
1360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    # any more would break the contract that only a single file is accessed -
1370f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    # see the SingleFile annotation in api_models._CreateAPIModel.
1380f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    future.Get()
1390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    self.assertTrue(*self._mock_file_system.CheckAndReset(
1400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        read_resolve_count=1))
1410f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    # 2 stats (1 for JSON and 1 for IDL) for each available API path.
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    # No reads (still cached).
1440f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    future = self._api_models.GetModel('alarms')
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    self.assertTrue(*self._mock_file_system.CheckAndReset(
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        stat_count=len(API_PATHS)*2))
1470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    future.Get()
1480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    self.assertTrue(*self._mock_file_system.CheckAndReset())
1490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)if __name__ == '__main__':
1521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  unittest.main()
153