260 lines
10 KiB
Python
260 lines
10 KiB
Python
import io
|
|
import json
|
|
import os
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
from quixote import get_publisher
|
|
|
|
from wcs.api_utils import sign_url
|
|
from wcs.formdef import FormDef
|
|
from wcs.qommon.afterjobs import AfterJob
|
|
from wcs.qommon.http_request import HTTPRequest
|
|
|
|
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app
|
|
|
|
|
|
@pytest.fixture
|
|
def pub(emails):
|
|
pub = create_temporary_pub()
|
|
|
|
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
|
|
pub.set_app_dir(req)
|
|
pub.cfg['identification'] = {'methods': ['password']}
|
|
pub.cfg['language'] = {'language': 'en'}
|
|
pub.write_cfg()
|
|
|
|
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
|
|
fd.write(
|
|
'''\
|
|
[api-secrets]
|
|
coucou = 1234
|
|
'''
|
|
)
|
|
|
|
return pub
|
|
|
|
|
|
def teardown_module(module):
|
|
clean_temporary_pub()
|
|
|
|
|
|
def test_tracking_code(pub):
|
|
FormDef.wipe()
|
|
formdef = FormDef()
|
|
formdef.name = 'test'
|
|
formdef.fields = []
|
|
formdef.enable_tracking_codes = True
|
|
formdef.store()
|
|
|
|
data_class = formdef.data_class()
|
|
formdata = data_class()
|
|
formdata.store()
|
|
|
|
code = get_publisher().tracking_code_class()
|
|
code.formdata = formdata
|
|
code.store()
|
|
|
|
# missing signature
|
|
get_app(pub).get('/api/code/foobar', status=403)
|
|
|
|
resp = get_app(pub).get(sign_url('/api/code/foobar?orig=coucou', '1234'), status=404)
|
|
assert resp.json['err'] == 1
|
|
|
|
resp = get_app(pub).get(sign_url('/api/code/%s?orig=coucou' % code.id, '1234'), status=200)
|
|
assert resp.json['err'] == 0
|
|
assert resp.json['url'] == 'http://example.net/test/%s/' % formdata.id
|
|
assert resp.json['load_url'] == 'http://example.net/code/%s/load' % code.id
|
|
|
|
formdef.enable_tracking_codes = False
|
|
formdef.store()
|
|
resp = get_app(pub).get(sign_url('/api/code/%s?orig=coucou' % code.id, '1234'), status=404)
|
|
|
|
formdef.enable_tracking_codes = True
|
|
formdef.store()
|
|
formdata.remove_self()
|
|
resp = get_app(pub).get(sign_url('/api/code/%s?orig=coucou' % code.id, '1234'), status=404)
|
|
|
|
|
|
def test_validate_expression(pub):
|
|
resp = get_app(pub).get('/api/validate-expression?expression=hello')
|
|
assert resp.json == {'klass': None, 'msg': ''}
|
|
resp = get_app(pub).get('/api/validate-expression?expression=[hello]')
|
|
assert resp.json == {'klass': None, 'msg': ''}
|
|
resp = get_app(pub).get('/api/validate-expression?expression==[hello')
|
|
assert resp.json['klass'] == 'error'
|
|
assert resp.json['msg'].startswith('syntax error')
|
|
resp = get_app(pub).get('/api/validate-expression?expression==[hello]')
|
|
assert resp.json['klass'] == 'warning'
|
|
assert resp.json['msg'].startswith('Make sure you want a Python expression,')
|
|
resp = get_app(pub).get('/api/validate-expression?expression==hello[0]')
|
|
assert resp.json == {'klass': None, 'msg': ''}
|
|
resp = get_app(pub).get('/api/validate-expression?expression==hello[\'plop\']')
|
|
assert resp.json == {'klass': None, 'msg': ''}
|
|
# django with unicode
|
|
resp = get_app(pub).get('/api/validate-expression?expression={{hello+%C3%A9l%C3%A9phant}}')
|
|
assert resp.json['klass'] == 'error'
|
|
assert resp.json['msg'].startswith('syntax error in Django template: Could not parse the remainder')
|
|
# broken ezt
|
|
resp = get_app(pub).get('/api/validate-expression?expression=[for]')
|
|
assert resp.json == {
|
|
'klass': 'error',
|
|
'msg': 'syntax error in ezt template: wrong number of arguments at line 1 and column 1',
|
|
}
|
|
|
|
|
|
def test_validate_condition(pub):
|
|
resp = get_app(pub).get('/api/validate-condition?type=python&value_python=hello')
|
|
assert resp.json == {'klass': None, 'msg': ''}
|
|
resp = get_app(pub).get('/api/validate-condition?type=python&value_python=~2')
|
|
assert resp.json == {'klass': None, 'msg': ''}
|
|
resp = get_app(pub).get('/api/validate-condition?type=python&value_python=hello -')
|
|
assert resp.json['klass'] == 'error'
|
|
assert resp.json['msg'].startswith('syntax error')
|
|
resp = get_app(pub).get('/api/validate-condition?type=python&value_python={{form_number}}==3')
|
|
assert resp.json['klass'] == 'error'
|
|
assert 'Python condition cannot contain {{' in resp.json['msg']
|
|
|
|
resp = get_app(pub).get('/api/validate-condition?type=django&value_django=un+%C3%A9l%C3%A9phant')
|
|
assert resp.json['klass'] == 'error'
|
|
assert resp.json['msg'].startswith("syntax error: Unused 'éléphant'")
|
|
resp = get_app(pub).get('/api/validate-condition?type=django&value_django=~2')
|
|
assert resp.json['klass'] == 'error'
|
|
assert resp.json['msg'].startswith('syntax error')
|
|
resp = get_app(pub).get('/api/validate-condition?type=django&value_django=%22...%22+inf') # "..." + inf
|
|
assert resp.json['klass'] == 'error'
|
|
assert resp.json['msg'].startswith('syntax error')
|
|
|
|
resp = get_app(pub).get('/api/validate-condition?type=unknown&value_unknown=2')
|
|
assert resp.json['klass'] == 'error'
|
|
assert resp.json['msg'] == 'unknown condition type'
|
|
|
|
|
|
def test_reverse_geocoding(pub):
|
|
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
|
|
urlopen.side_effect = lambda *args: io.StringIO(json.dumps({'address': 'xxx'}))
|
|
get_app(pub).get('/api/reverse-geocoding', status=400)
|
|
resp = get_app(pub).get('/api/reverse-geocoding?lat=0&lon=0')
|
|
assert resp.content_type == 'application/json'
|
|
assert resp.text == json.dumps({'address': 'xxx'})
|
|
assert (
|
|
urlopen.call_args[0][0]
|
|
== 'https://nominatim.entrouvert.org/reverse?zoom=18&format=json&addressdetails=1&lat=0&lon=0&accept-language=en'
|
|
)
|
|
|
|
pub.site_options.add_section('options')
|
|
pub.site_options.set('options', 'nominatim_reverse_zoom_level', '16')
|
|
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
|
|
pub.site_options.write(fd)
|
|
resp = get_app(pub).get('/api/reverse-geocoding?lat=0&lon=0')
|
|
assert (
|
|
urlopen.call_args[0][0]
|
|
== 'https://nominatim.entrouvert.org/reverse?zoom=16&format=json&addressdetails=1&lat=0&lon=0&accept-language=en'
|
|
)
|
|
|
|
pub.site_options.set('options', 'nominatim_key', 'KEY')
|
|
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
|
|
pub.site_options.write(fd)
|
|
resp = get_app(pub).get('/api/reverse-geocoding?lat=0&lon=0')
|
|
assert (
|
|
urlopen.call_args[0][0]
|
|
== 'https://nominatim.entrouvert.org/reverse?zoom=16&key=KEY&format=json&addressdetails=1&lat=0&lon=0&accept-language=en'
|
|
)
|
|
|
|
pub.site_options.set(
|
|
'options', 'reverse_geocoding_service_url', 'http://reverse.example.net/?param=value'
|
|
)
|
|
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
|
|
pub.site_options.write(fd)
|
|
resp = get_app(pub).get('/api/reverse-geocoding?lat=0&lon=0')
|
|
assert (
|
|
urlopen.call_args[0][0]
|
|
== 'http://reverse.example.net/?param=value&format=json&addressdetails=1&lat=0&lon=0&accept-language=en'
|
|
)
|
|
|
|
|
|
def test_geocoding(pub):
|
|
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
|
|
urlopen.side_effect = lambda *args: io.StringIO(json.dumps([{'lat': 0, 'lon': 0}]))
|
|
get_app(pub).get('/api/geocoding', status=400)
|
|
resp = get_app(pub).get('/api/geocoding?q=test')
|
|
assert resp.content_type == 'application/json'
|
|
assert resp.text == json.dumps([{'lat': 0, 'lon': 0}])
|
|
assert (
|
|
urlopen.call_args[0][0]
|
|
== 'https://nominatim.entrouvert.org/search?format=json&q=test&accept-language=en'
|
|
)
|
|
|
|
pub.site_options.add_section('options')
|
|
pub.site_options.set('options', 'map-bounds-top-left', '1.23;2.34')
|
|
pub.site_options.set('options', 'map-bounds-bottom-right', '2.34;3.45')
|
|
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
|
|
pub.site_options.write(fd)
|
|
resp = get_app(pub).get('/api/geocoding?q=test')
|
|
assert urlopen.call_args[0][0] == (
|
|
'https://nominatim.entrouvert.org/search?viewbox=2.34,1.23,3.45,2.34&bounded=1&'
|
|
'format=json&q=test&accept-language=en'
|
|
)
|
|
|
|
pub.site_options.set('options', 'nominatim_key', 'KEY')
|
|
pub.site_options.set('options', 'map-bounds-top-left', '')
|
|
pub.site_options.set('options', 'map-bounds-bottom-right', '')
|
|
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
|
|
pub.site_options.write(fd)
|
|
resp = get_app(pub).get('/api/geocoding?q=test')
|
|
assert (
|
|
urlopen.call_args[0][0]
|
|
== 'https://nominatim.entrouvert.org/search?key=KEY&format=json&q=test&accept-language=en'
|
|
)
|
|
|
|
pub.site_options.set('options', 'map-bounds-top-left', '1.23;2.34')
|
|
pub.site_options.set('options', 'map-bounds-bottom-right', '2.34;3.45')
|
|
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
|
|
pub.site_options.write(fd)
|
|
resp = get_app(pub).get('/api/geocoding?q=test')
|
|
assert urlopen.call_args[0][0] == (
|
|
'https://nominatim.entrouvert.org/search?key=KEY&viewbox=2.34,1.23,3.45,2.34&bounded=1&'
|
|
'format=json&q=test&accept-language=en'
|
|
)
|
|
|
|
pub.site_options.set('options', 'geocoding_service_url', 'http://reverse.example.net/?param=value')
|
|
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
|
|
pub.site_options.write(fd)
|
|
resp = get_app(pub).get('/api/geocoding?q=test')
|
|
assert (
|
|
urlopen.call_args[0][0]
|
|
== 'http://reverse.example.net/?param=value&format=json&q=test&accept-language=en'
|
|
)
|
|
|
|
|
|
def test_afterjobs_status(pub):
|
|
job = AfterJob('test')
|
|
job.store()
|
|
|
|
# missing signature
|
|
get_app(pub).get('/api/jobs/%s/' % job.id, status=403)
|
|
# unknown id
|
|
resp = get_app(pub).get(sign_url('/api/jobs/not-a-job-id/?orig=coucou', '1234'), status=404)
|
|
assert resp.json['err'] == 1
|
|
# without trailing /
|
|
resp = get_app(pub).get(sign_url('/api/jobs/%s?orig=coucou' % job.id, '1234'), status=404)
|
|
|
|
resp = get_app(pub).get(sign_url('/api/jobs/%s/?orig=coucou' % job.id, '1234'), status=200)
|
|
assert resp.json == {
|
|
'err': 0,
|
|
'data': {
|
|
'label': 'test',
|
|
'status': 'registered',
|
|
'creation_time': job.creation_time,
|
|
'completion_time': None,
|
|
'completion_status': '',
|
|
},
|
|
}
|
|
|
|
|
|
def test_afterjobs_base_directory(pub):
|
|
# missing signature
|
|
get_app(pub).get('/api/jobs/', status=403)
|
|
# base directory is 404
|
|
get_app(pub).get(sign_url('/api/jobs/?orig=coucou', '1234'), status=404)
|