]> git.openstreetmap.org Git - nominatim.git/blob - test/python/test_cli.py
a8efd35670e63e0cc2744a2da097bd7db13f55f3
[nominatim.git] / test / python / test_cli.py
1 """
2 Tests for command line interface wrapper.
3
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
6 the actual functions.
7 """
8 import datetime as dt
9 import psycopg2
10 import pytest
11 import time
12
13 import nominatim.cli
14 import nominatim.clicmd.api
15 import nominatim.clicmd.refresh
16 import nominatim.clicmd.admin
17 import nominatim.indexer.indexer
18 import nominatim.tools.refresh
19 import nominatim.tools.replication
20 from nominatim.errors import UsageError
21 from nominatim.db import status
22
23 def call_nominatim(*args):
24     return nominatim.cli.nominatim(module_dir='build/module',
25                                    osm2pgsql_path='build/osm2pgsql/osm2pgsql',
26                                    phplib_dir='lib-php',
27                                    data_dir='.',
28                                    phpcgi_path='/usr/bin/php-cgi',
29                                    sqllib_dir='lib-sql',
30                                    config_dir='settings',
31                                    cli_args=args)
32
33 class MockParamCapture:
34     """ Mock that records the parameters with which a function was called
35         as well as the number of calls.
36     """
37     def __init__(self, retval=0):
38         self.called = 0
39         self.return_value = retval
40
41     def __call__(self, *args, **kwargs):
42         self.called += 1
43         self.last_args = args
44         self.last_kwargs = kwargs
45         return self.return_value
46
47 @pytest.fixture
48 def mock_run_legacy(monkeypatch):
49     mock = MockParamCapture()
50     monkeypatch.setattr(nominatim.cli, 'run_legacy_script', mock)
51     return mock
52
53
54 def test_cli_help(capsys):
55     """ Running nominatim tool without arguments prints help.
56     """
57     assert 1 == call_nominatim()
58
59     captured = capsys.readouterr()
60     assert captured.out.startswith('usage:')
61
62
63 @pytest.mark.parametrize("command,script", [
64                          (('import', '--continue', 'load-data'), 'setup'),
65                          (('freeze',), 'setup'),
66                          (('special-phrases',), 'specialphrases'),
67                          (('add-data', '--tiger-data', 'tiger'), 'setup'),
68                          (('add-data', '--file', 'foo.osm'), 'update'),
69                          (('export',), 'export')
70                          ])
71 def test_legacy_commands_simple(mock_run_legacy, command, script):
72     assert 0 == call_nominatim(*command)
73
74     assert mock_run_legacy.called == 1
75     assert mock_run_legacy.last_args[0] == script + '.php'
76
77
78 @pytest.mark.parametrize("params", [('--warm', ),
79                                     ('--warm', '--reverse-only'),
80                                     ('--warm', '--search-only'),
81                                     ('--check-database', )])
82 def test_admin_command_legacy(monkeypatch, params):
83     mock_run_legacy = MockParamCapture()
84     monkeypatch.setattr(nominatim.clicmd.admin, 'run_legacy_script', mock_run_legacy)
85
86     assert 0 == call_nominatim('admin', *params)
87
88     assert mock_run_legacy.called == 1
89
90 @pytest.mark.parametrize("func, params", [('analyse_indexing', ('--analyse-indexing', ))])
91 def test_admin_command_tool(temp_db, monkeypatch, func, params):
92     mock = MockParamCapture()
93     monkeypatch.setattr(nominatim.tools.admin, func, mock)
94
95     assert 0 == call_nominatim('admin', *params)
96     assert mock.called == 1
97
98 @pytest.mark.parametrize("name,oid", [('file', 'foo.osm'), ('diff', 'foo.osc'),
99                                       ('node', 12), ('way', 8), ('relation', 32)])
100 def test_add_data_command(mock_run_legacy, name, oid):
101     assert 0 == call_nominatim('add-data', '--' + name, str(oid))
102
103     assert mock_run_legacy.called == 1
104     assert mock_run_legacy.last_args == ('update.php', '--import-' + name, oid)
105
106
107 @pytest.mark.parametrize("params,do_bnds,do_ranks", [
108                           ([], 1, 1),
109                           (['--boundaries-only'], 1, 0),
110                           (['--no-boundaries'], 0, 1),
111                           (['--boundaries-only', '--no-boundaries'], 0, 0)])
112 def test_index_command(monkeypatch, temp_db_cursor, params, do_bnds, do_ranks):
113     temp_db_cursor.execute("CREATE TABLE import_status (indexed bool)")
114     bnd_mock = MockParamCapture()
115     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_boundaries', bnd_mock)
116     rank_mock = MockParamCapture()
117     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_by_rank', rank_mock)
118
119     assert 0 == call_nominatim('index', *params)
120
121     assert bnd_mock.called == do_bnds
122     assert rank_mock.called == do_ranks
123
124
125 @pytest.mark.parametrize("command,params", [
126                          ('wiki-data', ('setup.php', '--import-wikipedia-articles')),
127                          ('importance', ('update.php', '--recompute-importance')),
128                          ('website', ('setup.php', '--setup-website')),
129                          ])
130 def test_refresh_legacy_command(monkeypatch, temp_db, command, params):
131     mock_run_legacy = MockParamCapture()
132     monkeypatch.setattr(nominatim.clicmd.refresh, 'run_legacy_script', mock_run_legacy)
133
134     assert 0 == call_nominatim('refresh', '--' + command)
135
136     assert mock_run_legacy.called == 1
137     assert len(mock_run_legacy.last_args) >= len(params)
138     assert mock_run_legacy.last_args[:len(params)] == params
139
140 @pytest.mark.parametrize("command,func", [
141                          ('postcodes', 'update_postcodes'),
142                          ('word-counts', 'recompute_word_counts'),
143                          ('address-levels', 'load_address_levels_from_file'),
144                          ('functions', 'create_functions'),
145                          ])
146 def test_refresh_command(monkeypatch, temp_db, command, func):
147     func_mock = MockParamCapture()
148     monkeypatch.setattr(nominatim.tools.refresh, func, func_mock)
149
150     assert 0 == call_nominatim('refresh', '--' + command)
151     assert func_mock.called == 1
152
153
154 def test_refresh_importance_computed_after_wiki_import(monkeypatch, temp_db):
155     mock_run_legacy = MockParamCapture()
156     monkeypatch.setattr(nominatim.clicmd.refresh, 'run_legacy_script', mock_run_legacy)
157
158     assert 0 == call_nominatim('refresh', '--importance', '--wiki-data')
159
160     assert mock_run_legacy.called == 2
161     assert mock_run_legacy.last_args == ('update.php', '--recompute-importance')
162
163
164 @pytest.mark.parametrize("params,func", [
165                          (('--init', '--no-update-functions'), 'init_replication'),
166                          (('--check-for-updates',), 'check_for_updates')
167                          ])
168 def test_replication_command(monkeypatch, temp_db, params, func):
169     func_mock = MockParamCapture()
170     monkeypatch.setattr(nominatim.tools.replication, func, func_mock)
171
172     assert 0 == call_nominatim('replication', *params)
173     assert func_mock.called == 1
174
175
176 def test_replication_update_bad_interval(monkeypatch, temp_db):
177     monkeypatch.setenv('NOMINATIM_REPLICATION_UPDATE_INTERVAL', 'xx')
178
179     assert call_nominatim('replication') == 1
180
181
182 def test_replication_update_bad_interval_for_geofabrik(monkeypatch, temp_db):
183     monkeypatch.setenv('NOMINATIM_REPLICATION_URL',
184                        'https://download.geofabrik.de/europe/ireland-and-northern-ireland-updates')
185
186     assert call_nominatim('replication') == 1
187
188
189 @pytest.mark.parametrize("state, retval", [
190                          (nominatim.tools.replication.UpdateState.UP_TO_DATE, 0),
191                          (nominatim.tools.replication.UpdateState.NO_CHANGES, 3)
192                          ])
193 def test_replication_update_once_no_index(monkeypatch, temp_db, temp_db_conn,
194                                           status_table, state, retval):
195     status.set_status(temp_db_conn, date=dt.datetime.now(dt.timezone.utc), seq=1)
196     func_mock = MockParamCapture(retval=state)
197     monkeypatch.setattr(nominatim.tools.replication, 'update', func_mock)
198
199     assert retval == call_nominatim('replication', '--once', '--no-index')
200
201
202 def test_replication_update_continuous(monkeypatch, temp_db_conn, status_table):
203     status.set_status(temp_db_conn, date=dt.datetime.now(dt.timezone.utc), seq=1)
204     states = [nominatim.tools.replication.UpdateState.UP_TO_DATE,
205               nominatim.tools.replication.UpdateState.UP_TO_DATE]
206     monkeypatch.setattr(nominatim.tools.replication, 'update',
207                         lambda *args, **kwargs: states.pop())
208
209     index_mock = MockParamCapture()
210     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_boundaries', index_mock)
211     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_by_rank', index_mock)
212
213     with pytest.raises(IndexError):
214         call_nominatim('replication')
215
216     assert index_mock.called == 4
217
218
219 def test_replication_update_continuous_no_change(monkeypatch, temp_db_conn, status_table):
220     status.set_status(temp_db_conn, date=dt.datetime.now(dt.timezone.utc), seq=1)
221     states = [nominatim.tools.replication.UpdateState.NO_CHANGES,
222               nominatim.tools.replication.UpdateState.UP_TO_DATE]
223     monkeypatch.setattr(nominatim.tools.replication, 'update',
224                         lambda *args, **kwargs: states.pop())
225
226     index_mock = MockParamCapture()
227     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_boundaries', index_mock)
228     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_by_rank', index_mock)
229
230     sleep_mock = MockParamCapture()
231     monkeypatch.setattr(time, 'sleep', sleep_mock)
232
233     with pytest.raises(IndexError):
234         call_nominatim('replication')
235
236     assert index_mock.called == 2
237     assert sleep_mock.called == 1
238     assert sleep_mock.last_args[0] == 60
239
240
241 def test_serve_command(monkeypatch):
242     func = MockParamCapture()
243     monkeypatch.setattr(nominatim.cli, 'run_php_server', func)
244
245     call_nominatim('serve')
246
247     assert func.called == 1
248
249 @pytest.mark.parametrize("params", [
250                          ('search', '--query', 'new'),
251                          ('reverse', '--lat', '0', '--lon', '0'),
252                          ('lookup', '--id', 'N1'),
253                          ('details', '--node', '1'),
254                          ('details', '--way', '1'),
255                          ('details', '--relation', '1'),
256                          ('details', '--place_id', '10001'),
257                          ('status',)
258                          ])
259 def test_api_commands_simple(monkeypatch, params):
260     mock_run_api = MockParamCapture()
261     monkeypatch.setattr(nominatim.clicmd.api, 'run_api_script', mock_run_api)
262
263     assert 0 == call_nominatim(*params)
264
265     assert mock_run_api.called == 1
266     assert mock_run_api.last_args[0] == params[0]