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