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