]> git.openstreetmap.org Git - nominatim.git/blob - test/python/test_cli.py
Merge remote-tracking branch 'upstream/master'
[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", [nominatim.tools.replication.UpdateState.UP_TO_DATE,
190                                    nominatim.tools.replication.UpdateState.NO_CHANGES])
191 def test_replication_update_once_no_index(monkeypatch, temp_db, temp_db_conn,
192                                           status_table, state):
193     status.set_status(temp_db_conn, date=dt.datetime.now(dt.timezone.utc), seq=1)
194     func_mock = MockParamCapture(retval=state)
195     monkeypatch.setattr(nominatim.tools.replication, 'update', func_mock)
196
197     assert 0 == call_nominatim('replication', '--once', '--no-index')
198
199
200 def test_replication_update_continuous(monkeypatch, temp_db_conn, status_table):
201     status.set_status(temp_db_conn, date=dt.datetime.now(dt.timezone.utc), seq=1)
202     states = [nominatim.tools.replication.UpdateState.UP_TO_DATE,
203               nominatim.tools.replication.UpdateState.UP_TO_DATE]
204     monkeypatch.setattr(nominatim.tools.replication, 'update',
205                         lambda *args, **kwargs: states.pop())
206
207     index_mock = MockParamCapture()
208     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_boundaries', index_mock)
209     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_by_rank', index_mock)
210
211     with pytest.raises(IndexError):
212         call_nominatim('replication')
213
214     assert index_mock.called == 4
215
216
217 def test_replication_update_continuous_no_change(monkeypatch, temp_db_conn, status_table):
218     status.set_status(temp_db_conn, date=dt.datetime.now(dt.timezone.utc), seq=1)
219     states = [nominatim.tools.replication.UpdateState.NO_CHANGES,
220               nominatim.tools.replication.UpdateState.UP_TO_DATE]
221     monkeypatch.setattr(nominatim.tools.replication, 'update',
222                         lambda *args, **kwargs: states.pop())
223
224     index_mock = MockParamCapture()
225     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_boundaries', index_mock)
226     monkeypatch.setattr(nominatim.indexer.indexer.Indexer, 'index_by_rank', index_mock)
227
228     sleep_mock = MockParamCapture()
229     monkeypatch.setattr(time, 'sleep', sleep_mock)
230
231     with pytest.raises(IndexError):
232         call_nominatim('replication')
233
234     assert index_mock.called == 2
235     assert sleep_mock.called == 1
236     assert sleep_mock.last_args[0] == 60
237
238
239 def test_serve_command(monkeypatch):
240     func = MockParamCapture()
241     monkeypatch.setattr(nominatim.cli, 'run_php_server', func)
242
243     call_nominatim('serve')
244
245     assert func.called == 1
246
247 @pytest.mark.parametrize("params", [
248                          ('search', '--query', 'new'),
249                          ('reverse', '--lat', '0', '--lon', '0'),
250                          ('lookup', '--id', 'N1'),
251                          ('details', '--node', '1'),
252                          ('details', '--way', '1'),
253                          ('details', '--relation', '1'),
254                          ('details', '--place_id', '10001'),
255                          ('status',)
256                          ])
257 def test_api_commands_simple(monkeypatch, params):
258     mock_run_api = MockParamCapture()
259     monkeypatch.setattr(nominatim.clicmd.api, 'run_api_script', mock_run_api)
260
261     assert 0 == call_nominatim(*params)
262
263     assert mock_run_api.called == 1
264     assert mock_run_api.last_args[0] == params[0]