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
 
   8 from pathlib import Path
 
  12 import nominatim.db.properties
 
  14 import nominatim.clicmd.api
 
  15 import nominatim.clicmd.refresh
 
  16 import nominatim.clicmd.admin
 
  17 import nominatim.clicmd.setup
 
  18 import nominatim.indexer.indexer
 
  19 import nominatim.tools.admin
 
  20 import nominatim.tools.check_database
 
  21 import nominatim.tools.database_import
 
  22 import nominatim.tools.freeze
 
  23 import nominatim.tools.refresh
 
  24 import nominatim.tools.postcodes
 
  25 import nominatim.tokenizer.factory
 
  27 from mocks import MockParamCapture
 
  29 SRC_DIR = (Path(__file__) / '..' / '..' / '..').resolve()
 
  31 def call_nominatim(*args):
 
  32     return nominatim.cli.nominatim(module_dir='build/module',
 
  33                                    osm2pgsql_path='build/osm2pgsql/osm2pgsql',
 
  34                                    phplib_dir=str(SRC_DIR / 'lib-php'),
 
  35                                    data_dir=str(SRC_DIR / 'data'),
 
  36                                    phpcgi_path='/usr/bin/php-cgi',
 
  37                                    sqllib_dir=str(SRC_DIR / 'lib-sql'),
 
  38                                    config_dir=str(SRC_DIR / 'settings'),
 
  43 def mock_run_legacy(monkeypatch):
 
  44     mock = MockParamCapture()
 
  45     monkeypatch.setattr(nominatim.cli, 'run_legacy_script', mock)
 
  50 def mock_func_factory(monkeypatch):
 
  51     def get_mock(module, func):
 
  52         mock = MockParamCapture()
 
  54         monkeypatch.setattr(module, func, mock)
 
  61 def tokenizer_mock(monkeypatch):
 
  63         def __init__(self, *args, **kwargs):
 
  64             self.update_sql_functions_called = False
 
  66         def update_sql_functions(self, *args):
 
  67             self.update_sql_functions_called = True
 
  69     tok = DummyTokenizer()
 
  70     monkeypatch.setattr(nominatim.tokenizer.factory, 'get_tokenizer_for_db' ,
 
  76 def test_cli_help(capsys):
 
  77     """ Running nominatim tool without arguments prints help.
 
  79     assert 1 == call_nominatim()
 
  81     captured = capsys.readouterr()
 
  82     assert captured.out.startswith('usage:')
 
  85 @pytest.mark.parametrize("command,script", [
 
  86                          (('add-data', '--file', 'foo.osm'), 'update'),
 
  87                          (('export',), 'export')
 
  89 def test_legacy_commands_simple(mock_run_legacy, command, script):
 
  90     assert 0 == call_nominatim(*command)
 
  92     assert mock_run_legacy.called == 1
 
  93     assert mock_run_legacy.last_args[0] == script + '.php'
 
  96 def test_import_missing_file(temp_db):
 
  97     assert 1 == call_nominatim('import', '--osm-file', 'sfsafegweweggdgw.reh.erh')
 
 100 def test_import_bad_file(temp_db):
 
 101     assert 1 == call_nominatim('import', '--osm-file', '.')
 
 104 def test_import_full(temp_db, mock_func_factory):
 
 106         mock_func_factory(nominatim.tools.database_import, 'setup_database_skeleton'),
 
 107         mock_func_factory(nominatim.tools.database_import, 'import_osm_data'),
 
 108         mock_func_factory(nominatim.tools.refresh, 'import_wikipedia_articles'),
 
 109         mock_func_factory(nominatim.tools.database_import, 'truncate_data_tables'),
 
 110         mock_func_factory(nominatim.tools.database_import, 'load_data'),
 
 111         mock_func_factory(nominatim.tools.database_import, 'create_tables'),
 
 112         mock_func_factory(nominatim.tools.database_import, 'create_table_triggers'),
 
 113         mock_func_factory(nominatim.tools.database_import, 'create_partition_tables'),
 
 114         mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
 
 115         mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
 
 116         mock_func_factory(nominatim.tokenizer.factory, 'create_tokenizer'),
 
 117         mock_func_factory(nominatim.tools.refresh, 'load_address_levels_from_file'),
 
 118         mock_func_factory(nominatim.tools.postcodes, 'import_postcodes'),
 
 119         mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_full'),
 
 120         mock_func_factory(nominatim.tools.refresh, 'setup_website'),
 
 121         mock_func_factory(nominatim.db.properties, 'set_property')
 
 124     cf_mock = mock_func_factory(nominatim.tools.refresh, 'create_functions')
 
 126     assert 0 == call_nominatim('import', '--osm-file', __file__)
 
 128     assert cf_mock.called > 1
 
 131         assert mock.called == 1, "Mock '{}' not called".format(mock.func_name)
 
 134 def test_import_continue_load_data(temp_db, mock_func_factory):
 
 136         mock_func_factory(nominatim.tools.database_import, 'truncate_data_tables'),
 
 137         mock_func_factory(nominatim.tools.database_import, 'load_data'),
 
 138         mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
 
 139         mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
 
 140         mock_func_factory(nominatim.tokenizer.factory, 'create_tokenizer'),
 
 141         mock_func_factory(nominatim.tools.postcodes, 'import_postcodes'),
 
 142         mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_full'),
 
 143         mock_func_factory(nominatim.tools.refresh, 'setup_website'),
 
 144         mock_func_factory(nominatim.db.properties, 'set_property')
 
 147     assert 0 == call_nominatim('import', '--continue', 'load-data')
 
 150         assert mock.called == 1, "Mock '{}' not called".format(mock.func_name)
 
 153 def test_import_continue_indexing(temp_db, mock_func_factory, placex_table, temp_db_conn):
 
 155         mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
 
 156         mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
 
 157         mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_full'),
 
 158         mock_func_factory(nominatim.tokenizer.factory, 'get_tokenizer_for_db'),
 
 159         mock_func_factory(nominatim.tools.refresh, 'setup_website'),
 
 160         mock_func_factory(nominatim.db.properties, 'set_property')
 
 163     assert 0 == call_nominatim('import', '--continue', 'indexing')
 
 166         assert mock.called == 1, "Mock '{}' not called".format(mock.func_name)
 
 168     assert temp_db_conn.index_exists('idx_placex_pendingsector')
 
 170     # Calling it again still works for the index
 
 171     assert 0 == call_nominatim('import', '--continue', 'indexing')
 
 172     assert temp_db_conn.index_exists('idx_placex_pendingsector')
 
 175 def test_import_continue_postprocess(temp_db, mock_func_factory):
 
 177         mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
 
 178         mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
 
 179         mock_func_factory(nominatim.tools.refresh, 'setup_website'),
 
 180         mock_func_factory(nominatim.tokenizer.factory, 'get_tokenizer_for_db'),
 
 181         mock_func_factory(nominatim.db.properties, 'set_property')
 
 184     assert 0 == call_nominatim('import', '--continue', 'db-postprocess')
 
 187         assert mock.called == 1, "Mock '{}' not called".format(mock.func_name)
 
 190 def test_freeze_command(mock_func_factory, temp_db):
 
 191     mock_drop = mock_func_factory(nominatim.tools.freeze, 'drop_update_tables')
 
 192     mock_flatnode = mock_func_factory(nominatim.tools.freeze, 'drop_flatnode_file')
 
 194     assert 0 == call_nominatim('freeze')
 
 196     assert mock_drop.called == 1
 
 197     assert mock_flatnode.called == 1
 
 200 @pytest.mark.parametrize("params", [('--warm', ),
 
 201                                     ('--warm', '--reverse-only'),
 
 202                                     ('--warm', '--search-only')])
 
 203 def test_admin_command_legacy(mock_func_factory, params):
 
 204     mock_run_legacy = mock_func_factory(nominatim.clicmd.admin, 'run_legacy_script')
 
 206     assert 0 == call_nominatim('admin', *params)
 
 208     assert mock_run_legacy.called == 1
 
 211 @pytest.mark.parametrize("func, params", [('analyse_indexing', ('--analyse-indexing', ))])
 
 212 def test_admin_command_tool(temp_db, mock_func_factory, func, params):
 
 213     mock = mock_func_factory(nominatim.tools.admin, func)
 
 215     assert 0 == call_nominatim('admin', *params)
 
 216     assert mock.called == 1
 
 219 def test_admin_command_check_database(mock_func_factory):
 
 220     mock = mock_func_factory(nominatim.tools.check_database, 'check_database')
 
 222     assert 0 == call_nominatim('admin', '--check-database')
 
 223     assert mock.called == 1
 
 226 @pytest.mark.parametrize("name,oid", [('file', 'foo.osm'), ('diff', 'foo.osc'),
 
 227                                       ('node', 12), ('way', 8), ('relation', 32)])
 
 228 def test_add_data_command(mock_run_legacy, name, oid):
 
 229     assert 0 == call_nominatim('add-data', '--' + name, str(oid))
 
 231     assert mock_run_legacy.called == 1
 
 232     assert mock_run_legacy.last_args == ('update.php', '--import-' + name, oid)
 
 235 @pytest.mark.parametrize("params,do_bnds,do_ranks", [
 
 237                           (['--boundaries-only'], 1, 0),
 
 238                           (['--no-boundaries'], 0, 1),
 
 239                           (['--boundaries-only', '--no-boundaries'], 0, 0)])
 
 240 def test_index_command(mock_func_factory, temp_db_cursor, tokenizer_mock,
 
 241                        params, do_bnds, do_ranks):
 
 242     temp_db_cursor.execute("CREATE TABLE import_status (indexed bool)")
 
 243     bnd_mock = mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_boundaries')
 
 244     rank_mock = mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_by_rank')
 
 246     assert 0 == call_nominatim('index', *params)
 
 248     assert bnd_mock.called == do_bnds
 
 249     assert rank_mock.called == do_ranks
 
 251 def test_special_phrases_command(temp_db, mock_func_factory, tokenizer_mock):
 
 252     func = mock_func_factory(nominatim.clicmd.special_phrases.SpecialPhrasesImporter, 'import_from_wiki')
 
 254     call_nominatim('special-phrases', '--import-from-wiki')
 
 256     assert func.called == 1
 
 258 @pytest.mark.parametrize("command,func", [
 
 259                          ('postcodes', 'update_postcodes'),
 
 260                          ('word-counts', 'recompute_word_counts'),
 
 261                          ('address-levels', 'load_address_levels_from_file'),
 
 262                          ('wiki-data', 'import_wikipedia_articles'),
 
 263                          ('importance', 'recompute_importance'),
 
 264                          ('website', 'setup_website'),
 
 266 def test_refresh_command(mock_func_factory, temp_db, command, func):
 
 267     func_mock = mock_func_factory(nominatim.tools.refresh, func)
 
 269     assert 0 == call_nominatim('refresh', '--' + command)
 
 270     assert func_mock.called == 1
 
 273 def test_refresh_create_functions(mock_func_factory, temp_db, tokenizer_mock):
 
 274     func_mock = mock_func_factory(nominatim.tools.refresh, 'create_functions')
 
 276     assert 0 == call_nominatim('refresh', '--functions')
 
 277     assert func_mock.called == 1
 
 278     assert tokenizer_mock.update_sql_functions_called
 
 281 def test_refresh_importance_computed_after_wiki_import(monkeypatch, temp_db):
 
 283     monkeypatch.setattr(nominatim.tools.refresh, 'import_wikipedia_articles',
 
 284                         lambda *args, **kwargs: calls.append('import') or 0)
 
 285     monkeypatch.setattr(nominatim.tools.refresh, 'recompute_importance',
 
 286                         lambda *args, **kwargs: calls.append('update'))
 
 288     assert 0 == call_nominatim('refresh', '--importance', '--wiki-data')
 
 290     assert calls == ['import', 'update']
 
 293 def test_serve_command(mock_func_factory):
 
 294     func = mock_func_factory(nominatim.cli, 'run_php_server')
 
 296     call_nominatim('serve')
 
 298     assert func.called == 1
 
 300 @pytest.mark.parametrize("params", [
 
 301                          ('search', '--query', 'new'),
 
 302                          ('reverse', '--lat', '0', '--lon', '0'),
 
 303                          ('lookup', '--id', 'N1'),
 
 304                          ('details', '--node', '1'),
 
 305                          ('details', '--way', '1'),
 
 306                          ('details', '--relation', '1'),
 
 307                          ('details', '--place_id', '10001'),
 
 310 def test_api_commands_simple(mock_func_factory, params):
 
 311     mock_run_api = mock_func_factory(nominatim.clicmd.api, 'run_api_script')
 
 313     assert 0 == call_nominatim(*params)
 
 315     assert mock_run_api.called == 1
 
 316     assert mock_run_api.last_args[0] == params[0]