2 Tests for command line interface wrapper.
4 These tests just check that the various command line parameters route to the
5 correct functionionality. They use a lot of monkeypatching to avoid executing
10 import nominatim.db.properties
12 import nominatim.clicmd.api
13 import nominatim.clicmd.refresh
14 import nominatim.clicmd.admin
15 import nominatim.clicmd.setup
16 import nominatim.indexer.indexer
17 import nominatim.tools.admin
18 import nominatim.tools.check_database
19 import nominatim.tools.database_import
20 import nominatim.tools.freeze
21 import nominatim.tools.refresh
22 import nominatim.tools.postcodes
23 import nominatim.tokenizer.factory
25 from mocks import MockParamCapture
28 def mock_run_legacy(monkeypatch):
29 mock = MockParamCapture()
30 monkeypatch.setattr(nominatim.cli, 'run_legacy_script', mock)
35 def mock_func_factory(monkeypatch):
36 def get_mock(module, func):
37 mock = MockParamCapture()
39 monkeypatch.setattr(module, func, mock)
48 @pytest.fixture(autouse=True)
49 def setup_cli_call(self, cli_call):
50 self.call_nominatim = cli_call
53 def test_cli_help(self, capsys):
54 """ Running nominatim tool without arguments prints help.
56 assert self.call_nominatim() == 1
58 captured = capsys.readouterr()
59 assert captured.out.startswith('usage:')
62 @pytest.mark.parametrize("command,script", [
63 (('add-data', '--file', 'foo.osm'), 'update'),
64 (('export',), 'export')
66 def test_legacy_commands_simple(self, mock_run_legacy, command, script):
67 assert self.call_nominatim(*command) == 0
69 assert mock_run_legacy.called == 1
70 assert mock_run_legacy.last_args[0] == script + '.php'
73 @pytest.mark.parametrize("params", [('--warm', ),
74 ('--warm', '--reverse-only'),
75 ('--warm', '--search-only')])
76 def test_admin_command_legacy(self, mock_func_factory, params):
77 mock_run_legacy = mock_func_factory(nominatim.clicmd.admin, 'run_legacy_script')
79 assert self.call_nominatim('admin', *params) == 0
81 assert mock_run_legacy.called == 1
84 def test_admin_command_check_database(self, mock_func_factory):
85 mock = mock_func_factory(nominatim.tools.check_database, 'check_database')
87 assert self.call_nominatim('admin', '--check-database') == 0
88 assert mock.called == 1
91 @pytest.mark.parametrize("name,oid", [('file', 'foo.osm'), ('diff', 'foo.osc'),
92 ('node', 12), ('way', 8), ('relation', 32)])
93 def test_add_data_command(self, mock_run_legacy, name, oid):
94 assert self.call_nominatim('add-data', '--' + name, str(oid)) == 0
96 assert mock_run_legacy.called == 1
97 assert mock_run_legacy.last_args == ('update.php', '--import-' + name, oid)
100 def test_serve_command(self, mock_func_factory):
101 func = mock_func_factory(nominatim.cli, 'run_php_server')
103 self.call_nominatim('serve')
105 assert func.called == 1
108 @pytest.mark.parametrize("params", [('search', '--query', 'new'),
109 ('reverse', '--lat', '0', '--lon', '0'),
110 ('lookup', '--id', 'N1'),
111 ('details', '--node', '1'),
112 ('details', '--way', '1'),
113 ('details', '--relation', '1'),
114 ('details', '--place_id', '10001'),
116 def test_api_commands_simple(self, mock_func_factory, params):
117 mock_run_api = mock_func_factory(nominatim.clicmd.api, 'run_api_script')
119 assert self.call_nominatim(*params) == 0
121 assert mock_run_api.called == 1
122 assert mock_run_api.last_args[0] == params[0]
128 @pytest.fixture(autouse=True)
129 def setup_cli_call(self, cli_call, temp_db):
130 self.call_nominatim = cli_call
133 @pytest.fixture(autouse=True)
134 def setup_tokenizer_mock(self, monkeypatch):
135 class DummyTokenizer:
136 def __init__(self, *args, **kwargs):
137 self.update_sql_functions_called = False
138 self.finalize_import_called = False
140 def update_sql_functions(self, *args):
141 self.update_sql_functions_called = True
143 def finalize_import(self, *args):
144 self.finalize_import_called = True
146 tok = DummyTokenizer()
147 monkeypatch.setattr(nominatim.tokenizer.factory, 'get_tokenizer_for_db',
149 monkeypatch.setattr(nominatim.tokenizer.factory, 'create_tokenizer',
152 self.tokenizer_mock = tok
155 def test_import_missing_file(self):
156 assert self.call_nominatim('import', '--osm-file', 'sfsafegwedgw.reh.erh') == 1
159 def test_import_bad_file(self):
160 assert self.call_nominatim('import', '--osm-file', '.') == 1
163 def test_import_full(self, mock_func_factory):
165 mock_func_factory(nominatim.tools.database_import, 'setup_database_skeleton'),
166 mock_func_factory(nominatim.tools.database_import, 'import_osm_data'),
167 mock_func_factory(nominatim.tools.refresh, 'import_wikipedia_articles'),
168 mock_func_factory(nominatim.tools.database_import, 'truncate_data_tables'),
169 mock_func_factory(nominatim.tools.database_import, 'load_data'),
170 mock_func_factory(nominatim.tools.database_import, 'create_tables'),
171 mock_func_factory(nominatim.tools.database_import, 'create_table_triggers'),
172 mock_func_factory(nominatim.tools.database_import, 'create_partition_tables'),
173 mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
174 mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
175 mock_func_factory(nominatim.tools.refresh, 'load_address_levels_from_file'),
176 mock_func_factory(nominatim.tools.postcodes, 'update_postcodes'),
177 mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_full'),
178 mock_func_factory(nominatim.tools.refresh, 'setup_website'),
179 mock_func_factory(nominatim.db.properties, 'set_property')
182 cf_mock = mock_func_factory(nominatim.tools.refresh, 'create_functions')
184 assert self.call_nominatim('import', '--osm-file', __file__) == 0
185 assert self.tokenizer_mock.finalize_import_called
187 assert cf_mock.called > 1
190 assert mock.called == 1, "Mock '{}' not called".format(mock.func_name)
193 def test_import_continue_load_data(self, mock_func_factory):
195 mock_func_factory(nominatim.tools.database_import, 'truncate_data_tables'),
196 mock_func_factory(nominatim.tools.database_import, 'load_data'),
197 mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
198 mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
199 mock_func_factory(nominatim.tools.postcodes, 'update_postcodes'),
200 mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_full'),
201 mock_func_factory(nominatim.tools.refresh, 'setup_website'),
202 mock_func_factory(nominatim.db.properties, 'set_property')
205 assert self.call_nominatim('import', '--continue', 'load-data') == 0
206 assert self.tokenizer_mock.finalize_import_called
209 assert mock.called == 1, "Mock '{}' not called".format(mock.func_name)
212 def test_import_continue_indexing(self, mock_func_factory, placex_table,
215 mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
216 mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
217 mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_full'),
218 mock_func_factory(nominatim.tools.refresh, 'setup_website'),
219 mock_func_factory(nominatim.db.properties, 'set_property')
222 assert self.call_nominatim('import', '--continue', 'indexing') == 0
225 assert mock.called == 1, "Mock '{}' not called".format(mock.func_name)
227 assert temp_db_conn.index_exists('idx_placex_pendingsector')
229 # Calling it again still works for the index
230 assert self.call_nominatim('import', '--continue', 'indexing') == 0
231 assert temp_db_conn.index_exists('idx_placex_pendingsector')
234 def test_import_continue_postprocess(self, mock_func_factory):
236 mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
237 mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
238 mock_func_factory(nominatim.tools.refresh, 'setup_website'),
239 mock_func_factory(nominatim.db.properties, 'set_property')
242 assert self.call_nominatim('import', '--continue', 'db-postprocess') == 0
244 assert self.tokenizer_mock.finalize_import_called
247 assert mock.called == 1, "Mock '{}' not called".format(mock.func_name)
250 def test_freeze_command(self, mock_func_factory):
251 mock_drop = mock_func_factory(nominatim.tools.freeze, 'drop_update_tables')
252 mock_flatnode = mock_func_factory(nominatim.tools.freeze, 'drop_flatnode_file')
254 assert self.call_nominatim('freeze') == 0
256 assert mock_drop.called == 1
257 assert mock_flatnode.called == 1
261 @pytest.mark.parametrize("func, params", [('analyse_indexing', ('--analyse-indexing', ))])
262 def test_admin_command_tool(self, mock_func_factory, func, params):
263 mock = mock_func_factory(nominatim.tools.admin, func)
265 assert self.call_nominatim('admin', *params) == 0
266 assert mock.called == 1
269 @pytest.mark.parametrize("params,do_bnds,do_ranks", [
271 (['--boundaries-only'], 1, 0),
272 (['--no-boundaries'], 0, 1),
273 (['--boundaries-only', '--no-boundaries'], 0, 0)])
274 def test_index_command(self, mock_func_factory, table_factory,
275 params, do_bnds, do_ranks):
276 table_factory('import_status', 'indexed bool')
277 bnd_mock = mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_boundaries')
278 rank_mock = mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_by_rank')
280 assert self.call_nominatim('index', *params) == 0
282 assert bnd_mock.called == do_bnds
283 assert rank_mock.called == do_ranks
285 @pytest.mark.parametrize("no_replace", [(True), (False)])
286 def test_special_phrases_wiki_command(self, mock_func_factory, no_replace):
287 func = mock_func_factory(nominatim.clicmd.special_phrases.SPImporter, 'import_phrases')
290 self.call_nominatim('special-phrases', '--import-from-wiki', '--no-replace')
292 self.call_nominatim('special-phrases', '--import-from-wiki')
294 assert func.called == 1
296 @pytest.mark.parametrize("no_replace", [(True), (False)])
297 def test_special_phrases_csv_command(self, src_dir, mock_func_factory, no_replace):
298 func = mock_func_factory(nominatim.clicmd.special_phrases.SPImporter, 'import_phrases')
299 testdata = src_dir / 'test' / 'testdb'
300 csv_path = str((testdata / 'full_en_phrases_test.csv').resolve())
303 self.call_nominatim('special-phrases', '--import-from-csv', csv_path, '--no-replace')
305 self.call_nominatim('special-phrases', '--import-from-csv', csv_path)
307 assert func.called == 1
309 @pytest.mark.parametrize("command,func", [
310 ('word-counts', 'recompute_word_counts'),
311 ('address-levels', 'load_address_levels_from_file'),
312 ('wiki-data', 'import_wikipedia_articles'),
313 ('importance', 'recompute_importance'),
314 ('website', 'setup_website'),
316 def test_refresh_command(self, mock_func_factory, command, func):
317 func_mock = mock_func_factory(nominatim.tools.refresh, func)
319 assert self.call_nominatim('refresh', '--' + command) == 0
320 assert func_mock.called == 1
323 def test_refresh_postcodes(self, mock_func_factory, place_table):
324 func_mock = mock_func_factory(nominatim.tools.postcodes, 'update_postcodes')
325 idx_mock = mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_postcodes')
327 assert self.call_nominatim('refresh', '--postcodes') == 0
328 assert func_mock.called == 1
329 assert idx_mock.called == 1
331 def test_refresh_create_functions(self, mock_func_factory):
332 func_mock = mock_func_factory(nominatim.tools.refresh, 'create_functions')
334 assert self.call_nominatim('refresh', '--functions') == 0
335 assert func_mock.called == 1
336 assert self.tokenizer_mock.update_sql_functions_called
339 def test_refresh_importance_computed_after_wiki_import(self, monkeypatch):
341 monkeypatch.setattr(nominatim.tools.refresh, 'import_wikipedia_articles',
342 lambda *args, **kwargs: calls.append('import') or 0)
343 monkeypatch.setattr(nominatim.tools.refresh, 'recompute_importance',
344 lambda *args, **kwargs: calls.append('update'))
346 assert self.call_nominatim('refresh', '--importance', '--wiki-data') == 0
348 assert calls == ['import', 'update']