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