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. 5 6 import json 7 import unittest 8 9 from api_models import APIModels 10 from compiled_file_system import CompiledFileSystem 11 from extensions_paths import API_PATHS, CHROME_API, CHROME_EXTENSIONS 12 from features_bundle import FeaturesBundle 13 from file_system import FileNotFoundError 14 from mock_file_system import MockFileSystem 15 from object_store_creator import ObjectStoreCreator 16 from test_file_system import TestFileSystem 17 from test_util import ReadFile 18 from future import Future 19 from schema_processor import SchemaProcessorFactoryForTest 20 21 22 _TEST_DATA = { 23 'api': { 24 'devtools': { 25 'inspected_window.json': ReadFile( 26 CHROME_API, 'devtools', 'inspected_window.json'), 27 }, 28 '_api_features.json': json.dumps({ 29 'alarms': {}, 30 'app': {}, 31 'app.runtime': {'noparent': True}, 32 'app.runtime.foo': {}, 33 'declarativeWebRequest': {}, 34 'devtools.inspectedWindow': {}, 35 'input': {}, 36 'input.ime': {}, 37 'storage': {}, 38 }), 39 '_manifest_features.json': '{}', 40 '_permission_features.json': '{}', 41 'alarms.idl': ReadFile(CHROME_API, 'alarms.idl'), 42 'input_ime.json': ReadFile(CHROME_API, 'input_ime.json'), 43 'page_action.json': ReadFile(CHROME_API, 'page_action.json'), 44 }, 45 'docs': { 46 'templates': { 47 'json': { 48 'manifest.json': '{}', 49 'permissions.json': '{}', 50 } 51 } 52 }, 53 } 54 55 56 class APIModelsTest(unittest.TestCase): 57 def setUp(self): 58 object_store_creator = ObjectStoreCreator.ForTest() 59 compiled_fs_factory = CompiledFileSystem.Factory(object_store_creator) 60 self._mock_file_system = MockFileSystem( 61 TestFileSystem(_TEST_DATA, relative_to=CHROME_EXTENSIONS)) 62 features_bundle = FeaturesBundle(self._mock_file_system, 63 compiled_fs_factory, 64 object_store_creator, 65 'extensions') 66 self._api_models = APIModels(features_bundle, 67 compiled_fs_factory, 68 self._mock_file_system, 69 object_store_creator, 70 'extensions', 71 SchemaProcessorFactoryForTest()) 72 73 def testGetNames(self): 74 # Both 'app' and 'app.runtime' appear here because 'app.runtime' has 75 # noparent:true, but 'app.runtime.foo' etc doesn't so it's a sub-feature of 76 # 'app.runtime' not a separate API. 'devtools.inspectedWindow' is an API 77 # because there is no 'devtools'. 78 self.assertEqual( 79 ['alarms', 'app', 'app.runtime', 'declarativeWebRequest', 80 'devtools.inspectedWindow', 'input', 'storage'], 81 sorted(self._api_models.GetNames())) 82 83 def testGetModel(self): 84 def get_model_name(api_name): 85 return self._api_models.GetModel(api_name).Get().name 86 self.assertEqual('devtools.inspectedWindow', 87 get_model_name('devtools.inspectedWindow')) 88 self.assertEqual('devtools.inspectedWindow', 89 get_model_name('devtools/inspected_window.json')) 90 self.assertEqual('devtools.inspectedWindow', 91 get_model_name(CHROME_API + 92 'devtools/inspected_window.json')) 93 self.assertEqual('alarms', get_model_name('alarms')) 94 self.assertEqual('alarms', get_model_name('alarms.idl')) 95 self.assertEqual('alarms', get_model_name(CHROME_API + 'alarms.idl')) 96 self.assertEqual('input.ime', get_model_name('input.ime')) 97 self.assertEqual('input.ime', get_model_name('input_ime.json')) 98 self.assertEqual('input.ime', 99 get_model_name(CHROME_API + 'input_ime.json')) 100 self.assertEqual('pageAction', get_model_name('pageAction')) 101 self.assertEqual('pageAction', get_model_name('page_action.json')) 102 self.assertEqual('pageAction', get_model_name(CHROME_API + 103 'page_action.json')) 104 105 def testGetNonexistentModel(self): 106 self.assertRaises(FileNotFoundError, 107 self._api_models.GetModel('declarativeWebRequest').Get) 108 self.assertRaises(FileNotFoundError, 109 self._api_models.GetModel( 110 'declarative_web_request.json').Get) 111 self.assertRaises(FileNotFoundError, 112 self._api_models.GetModel( 113 CHROME_API + 'declarative_web_request.json').Get) 114 self.assertRaises(FileNotFoundError, 115 self._api_models.GetModel('notfound').Get) 116 self.assertRaises(FileNotFoundError, 117 self._api_models.GetModel('notfound.json').Get) 118 self.assertRaises(FileNotFoundError, 119 self._api_models.GetModel(CHROME_API + 120 'notfound.json').Get) 121 self.assertRaises(FileNotFoundError, 122 self._api_models.GetModel(CHROME_API + 123 'alarms.json').Get) 124 self.assertRaises(FileNotFoundError, 125 self._api_models.GetModel('storage').Get) 126 self.assertRaises(FileNotFoundError, 127 self._api_models.GetModel(CHROME_API + 128 'storage.json').Get) 129 self.assertRaises(FileNotFoundError, 130 self._api_models.GetModel(CHROME_API + 131 'storage.idl').Get) 132 133 def testSingleFile(self): 134 # 2 stats (1 for JSON and 1 for IDL) for each available API path. 135 # 1 read (for IDL file which existed). 136 future = self._api_models.GetModel('alarms') 137 self.assertTrue(*self._mock_file_system.CheckAndReset( 138 read_count=1, stat_count=len(API_PATHS)*2)) 139 140 # 1 read-resolve (for the IDL file). 141 # 142 # The important part here and above is that it's only doing a single read; 143 # any more would break the contract that only a single file is accessed - 144 # see the SingleFile annotation in api_models._CreateAPIModel. 145 future.Get() 146 self.assertTrue(*self._mock_file_system.CheckAndReset( 147 read_resolve_count=1)) 148 149 # 2 stats (1 for JSON and 1 for IDL) for each available API path. 150 # No reads (still cached). 151 future = self._api_models.GetModel('alarms') 152 self.assertTrue(*self._mock_file_system.CheckAndReset( 153 stat_count=len(API_PATHS)*2)) 154 future.Get() 155 self.assertTrue(*self._mock_file_system.CheckAndReset()) 156 157 158 if __name__ == '__main__': 159 unittest.main() 160