passerelle/tests/test_arcgis.py

239 lines
9.8 KiB
Python

# -*- coding: utf-8 -*-
import pytest
import mock
import utils
from django.contrib.contenttypes.models import ContentType
from passerelle.apps.arcgis.models import ArcGIS
from passerelle.base.models import ApiUser, AccessRight
# from http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/fold/serv/MapServer/1
STATES = '''{
"fieldAliases" : {
"OBJECTID" : "OBJECTID",
"STATE_NAME" : "STATE_NAME",
"STATE_ABBR" : "STATE_ABBR"
},
"features" : [
{
"attributes" : {
"STATE_NAME" : "Texas",
"STATE_ABBR" : "TX",
"OBJECTID" : 40
},
"geometry" : {
"rings" : [
[
[-105.998886788462, 31.3939400524361],
[-106.21328556164, 31.4782464373727]
]
]
}
},
{
"geometry" : {
"rings" : [
[
[-111.475425113078, 44.7021622250113],
[-111.480804007084, 44.6914159859524]
]
]
},
"attributes" : {
"STATE_NAME" : "Montana",
"STATE_ABBR" : "MT",
"OBJECTID" : 2
}
}
],
"spatialReference" : {
"wkid" : 4326
},
"fields" : [
{
"alias" : "OBJECTID",
"type" : "esriFieldTypeOID",
"name" : "OBJECTID"
},
{
"type" : "esriFieldTypeString",
"alias" : "STATE_NAME",
"length" : 25,
"name" : "STATE_NAME"
},
{
"length" : 2,
"alias" : "STATE_ABBR",
"type" : "esriFieldTypeString",
"name" : "STATE_ABBR"
}
],
"geometryType" : "esriGeometryPolygon",
"displayFieldName" : "STATE_NAME"
}'''
@pytest.fixture
def arcgis(db):
return ArcGIS.objects.create(slug='test',
base_url='https://arcgis.example.net/')
def test_arcgis_mapservice_query(app, arcgis):
endpoint = utils.generic_endpoint_url('arcgis', 'mapservice-query', slug=arcgis.slug)
assert endpoint == '/arcgis/test/mapservice-query'
params = {
'folder': 'fold',
'service': 'serv',
'layer': '1'
}
with mock.patch('passerelle.utils.Request.get') as requests_get:
requests_get.return_value = utils.FakedResponse(content=STATES,
status_code=200)
resp = app.get(endpoint, params=params, status=403)
assert requests_get.call_count == 0
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'django.core.exceptions.PermissionDenied'
# open access
api = ApiUser.objects.create(username='all', keytype='', key='')
obj_type = ContentType.objects.get_for_model(arcgis)
AccessRight.objects.create(codename='can_access', apiuser=api, resource_type=obj_type,
resource_pk=arcgis.pk)
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_count == 1
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/fold/serv/MapServer/1/query'
args = requests_get.call_args[1]['params']
assert args['f'] == 'json'
assert args['outFields'] == '*'
assert args['where'] == '1=1'
assert 'data' in resp.json
assert resp.json['err'] == 0
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == '40'
assert resp.json['data'][0]['text'] == 'Texas'
assert 'geometry' not in resp.json['data'][0]
assert 'metadata' not in resp.json
params['full'] = 'on'
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_count == 2
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/fold/serv/MapServer/1/query'
args = requests_get.call_args[1]['params']
assert args['f'] == 'json'
assert args['outFields'] == '*'
assert args['where'] == '1=1'
assert 'data' in resp.json
assert resp.json['err'] == 0
assert len(resp.json['data']) == 2
assert resp.json['data'][0]['id'] == '40'
assert resp.json['data'][0]['text'] == 'Texas'
assert resp.json['data'][0]['geometry']
assert resp.json['metadata']
params['q'] = 'Texas'
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_count == 3
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/fold/serv/MapServer/1/query'
args = requests_get.call_args[1]['params']
assert args['text'] == 'Texas'
assert 'where' not in args
params['lat'] = '9.87654'
params['lon'] = '1.12345'
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_count == 4
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/fold/serv/MapServer/1/query'
args = requests_get.call_args[1]['params']
assert args['geometry'] == '1.12345,9.87654'
assert args['geometryType'] == 'esriGeometryPoint'
del params['lat'] # missing lat, do not search by geometry
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_count == 5
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/fold/serv/MapServer/1/query'
args = requests_get.call_args[1]['params']
assert 'geometry' not in args
assert 'geometryType' not in args
params.update({'latmin': '1', 'lonmin': '2', 'latmax': '3', 'lonmax': '4'})
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_count == 6
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/fold/serv/MapServer/1/query'
args = requests_get.call_args[1]['params']
assert args['geometry'] == '2.0,1.0,4.0,3.0'
assert args['geometryType'] == 'esriGeometryEnvelope'
del params['latmin'] # incomplete box, do not search by geometry
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_count == 7
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/fold/serv/MapServer/1/query'
args = requests_get.call_args[1]['params']
assert 'geometry' not in args
assert 'geometryType' not in args
# others params are directly sent to ArcGIS
params['spatialRel'] = 'esriSpatialRelContains'
params.update({'latmin': '1', 'lonmin': '2', 'latmax': '3', 'lonmax': '4'})
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_count == 8
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/fold/serv/MapServer/1/query'
args = requests_get.call_args[1]['params']
assert args['geometry'] == '2.0,1.0,4.0,3.0'
assert args['geometryType'] == 'esriGeometryEnvelope'
assert args['spatialRel'] == 'esriSpatialRelContains'
# folder
params['folder'] = 'foo/bar'
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/foo/bar/serv/MapServer/1/query'
del params['folder']
resp = app.get(endpoint, params=params, status=200)
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/serv/MapServer/1/query'
# minimal call
resp = app.get(endpoint, params={'service': 'srv'}, status=200)
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/srv/MapServer/0/query'
args = requests_get.call_args[1]['params']
assert args == {'f': 'json', 'inSR': '4326', 'outSR': '4326',
'outFields': '*', 'where': '1=1'}
# distance
resp = app.get(endpoint, params={'service': 'srv', 'distance': '100'}, status=200)
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/srv/MapServer/0/query'
args = requests_get.call_args[1]['params']
assert args['distance'] == '100'
assert args['units'] == 'esriSRUnit_Meter' # default unit
resp = app.get(endpoint, params={'service': 'srv', 'distance': '5', 'units':
'esriSRUnit_NauticalMile'}, status=200)
assert requests_get.call_args[0][0] == 'https://arcgis.example.net/services/srv/MapServer/0/query'
args = requests_get.call_args[1]['params']
assert args['distance'] == '5'
assert args['units'] == 'esriSRUnit_NauticalMile'
# call errors
with mock.patch('passerelle.utils.Request.get') as requests_get:
requests_get.return_value = utils.FakedResponse(content=STATES,
status_code=200)
resp = app.get(endpoint, params={}, status=400)
assert requests_get.call_count == 0
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'passerelle.views.WrongParameter'
assert resp.json['err_desc'] == "missing parameters: 'service'."
resp = app.get(endpoint, params={'service': 'src', 'lat': '0', 'lon': 'y'}, status=400)
assert requests_get.call_count == 0
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
assert resp.json['err_desc'] == '<lon> and <lat> must be floats'
resp = app.get(endpoint, params={'service': 'src', 'latmin': '0', 'lonmin': 'y',
'latmax': '0', 'lonmax': '1'}, status=400)
assert requests_get.call_count == 0
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'passerelle.utils.jsonresponse.APIError'
assert resp.json['err_desc'] == '<lonmin> <latmin> <lonmax> and <latmax> must be floats'