Skip to content

Commit

Permalink
[tests] Add support for locally spawned fcgi process
Browse files Browse the repository at this point in the history
- No building of spawn-fcgi or managing of spawned process, yet
  • Loading branch information
dakcarto committed Sep 2, 2013
1 parent 9328843 commit d8b05c2
Show file tree
Hide file tree
Showing 33 changed files with 3,898 additions and 128 deletions.
284 changes: 204 additions & 80 deletions tests/src/python/qgis_local_server.py
Expand Up @@ -17,6 +17,7 @@
import os
import ConfigParser
import urllib
import urlparse
import tempfile

# allow import error to be raised if qgis is not on sys.path
Expand All @@ -26,6 +27,19 @@
raise ImportError(str(e) + '\n\nPlace path to pyqgis modules on sys.path,'
' or assign to PYTHONPATH')

import qgis_local_server_spawn.flup_fcgi_client as fcgi_client

if sys.version_info[0:2] < (2, 7):
try:
from unittest2 import TestCase, expectedFailure
import unittest2 as unittest
except ImportError:
print "You should install unittest2 to run the salt tests"
sys.exit(0)
else:
from unittest import TestCase, expectedFailure
import unittest


class ServerNotAccessibleError(Exception):

Expand All @@ -43,10 +57,11 @@ def __str__(self):

class QgisLocalServer(object):

def __init__(self, cgiurl, chkcapa=False):
def __init__(self, cgiurl, chkcapa=False, spawn=False):
self.cgiurl = cgiurl
self.params = {}
self.active = False
self.spawn = spawn

# check capabilities to verify server is accessible
if chkcapa:
Expand Down Expand Up @@ -74,12 +89,22 @@ def getCapabilities(self, params, browser=False):
url = self.cgiurl + '?' + self._processParams()
self.params = {}

xml = ''
if self.spawn:
xml = requestFromSpawn(url)[2]

if browser:
tmp = tempfile.NamedTemporaryFile(suffix=".html", delete=False)
tmp.write(xml)
url = tmp.name
tmp.close()
openInBrowserTab(url)
return False, ''

res = urllib.urlopen(url)
xml = res.read()
if not self.spawn:
res = urllib.urlopen(url)
xml = res.read()

success = ('perhaps you left off the .qgs extension' in xml or
'WMS_Capabilities' in xml)
return success, xml
Expand All @@ -98,18 +123,39 @@ def getMap(self, params, browser=False):
url = self.cgiurl + '?' + self._processParams()
self.params = {}

if browser:
if browser and not self.spawn:
openInBrowserTab(url)
return False, ''

tmp = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
tmp.close()
res = urllib.urlretrieve(url, tmp.name)
filepath = res[0]
success = True
if (res[1].getmaintype() != 'image' or
res[1].getheader('Content-Type') != 'image/png'):
success = False
filepath = tmp.name
# print 'filepath: ' + filepath

if self.spawn:
status, headers, result, err = requestFromSpawn(url)
tmp.write(result)
tmp.close()

# print 'status: ' + status
# print 'headers: ' + repr(headers)

if (status != '200 OK' or
'content-type' not in headers or
headers['content-type'] != 'image/png'):
success = False

if browser:
openInBrowserTab('file://' + filepath)
return False, ''

else:
tmp.close()
filepath2, headers = urllib.urlretrieve(url, tmp.name)

if (headers.getmaintype() != 'image' or
headers.getheader('Content-Type') != 'image/png'):
success = False

return success, filepath

Expand Down Expand Up @@ -146,7 +192,7 @@ def _convertInstances(self):
class ServerConfigNotAccessibleError(Exception):

def __init__(self, err=''):
self.msg = '\n\n' + str(err) + '\n'
self.msg = '\n' + ('\n' + str(err) + '\n' if err else '')
self.msg += """
#----------------------------------------------------------------#
Local test QGIS Server is not accessible
Expand All @@ -172,32 +218,59 @@ def __str__(self):
return self.msg


class ServerSpawnNotAccessibleError(Exception):

def __init__(self, cgiurl, err=''):
self.msg = '\n' + ('\n' + str(err) + '\n' if err else '')
self.msg += """
#----------------------------------------------------------------#
Locally spawned test QGIS Server is not accessible at:
{0}
#----------------------------------------------------------------#
""".format(cgiurl)

def __str__(self):
return self.msg


class QgisLocalServerConfig(QgisLocalServer):

def __init__(self, cfgdir, chkcapa=False):
def __init__(self, cfgdir, chkcapa=False, spawn=False):
msg = 'Server configuration directory required'
assert cfgdir, msg

self.cfgdir = cfgdir
self.cfg = os.path.normpath(os.path.join(self.cfgdir,
'qgis_local_server.cfg'))
if not os.path.exists(self.cfg):
msg = ('Default server configuration file could not be written'
' to {0}'.format(self.cfg))
assert self._writeDefaultServerConfig(), msg

self._checkItemFound('file', self.cfg)
self._checkItemReadable('file', self.cfg)

cgiurl, self.projdir = self._readServerConfig()
# cfgdir is either path to temp project dir (spawned) or settings dir
# temp dir for spawned server is used lke 'projdir' in configured
if spawn:
# predefined and runs in user space
cgiurl = 'http://127.0.0.1:8448/qgis_mapserv.fcgi'
self.projdir = cfgdir
else:
self.cfgdir = cfgdir
self.cfg = os.path.normpath(os.path.join(self.cfgdir,
'qgis_local_server.cfg'))
if not os.path.exists(self.cfg):
msg = ('Default server configuration file could not be written'
' to {0}'.format(self.cfg))
assert self._writeDefaultServerConfig(), msg

_checkItemFound('file', self.cfg)
_checkItemReadable('file', self.cfg)

cgiurl, self.projdir = self._readServerConfig()

try:
self._checkItemFound('project directory', self.projdir)
self._checkItemReadable('project directory', self.projdir)
self._checkItemWriteable('project directory', self.projdir)
super(QgisLocalServerConfig, self).__init__(cgiurl, chkcapa)
_checkItemFound('project directory', self.projdir)
_checkItemReadable('project directory', self.projdir)
_checkItemWriteable('project directory', self.projdir)
super(QgisLocalServerConfig, self).__init__(cgiurl,
chkcapa=chkcapa,
spawn=spawn)
except Exception, err:
raise ServerConfigNotAccessibleError(err)
if spawn:
raise ServerSpawnNotAccessibleError(cgiurl, '')
else:
raise ServerConfigNotAccessibleError(err)

def projectDir(self):
return self.projdir
Expand All @@ -218,22 +291,8 @@ def getMap(self, params, browser=False):
msg = 'Project could not be found at {0}'.format(proj)
assert os.path.exists(proj), msg

return super(QgisLocalServerConfig, self).getMap(params, browser)

def _checkItemFound(self, item, path):
msg = ('Server configuration {0} could not be found at:\n'
' {1}'.format(item, path))
assert os.path.exists(path), msg

def _checkItemReadable(self, item, path):
msg = ('Server configuration {0} is not readable from:\n'
' {1}'.format(item, path))
assert os.access(path, os.R_OK), msg

def _checkItemWriteable(self, item, path):
msg = ('Server configuration {0} is not writeable from:\n'
' {1}'.format(item, path))
assert os.access(path, os.W_OK), msg
return super(QgisLocalServerConfig, self).getMap(params,
browser=browser)

def _writeDefaultServerConfig(self):
"""Overwrites any existing server configuration file with default"""
Expand Down Expand Up @@ -268,6 +327,50 @@ def _readServerConfig(self):
return url, projdir


def _checkItemFound(item, path):
msg = ('Server configuration {0} could not be found at:\n'
' {1}'.format(item, path))
assert os.path.exists(path), msg


def _checkItemReadable(item, path):
msg = ('Server configuration {0} is not readable from:\n'
' {1}'.format(item, path))
assert os.access(path, os.R_OK), msg


def _checkItemWriteable(item, path):
msg = ('Server configuration {0} is not writeable from:\n'
' {1}'.format(item, path))
assert os.access(path, os.W_OK), msg


def requestFromSpawn(url):
""" load fastcgi page """
prl = urlparse.urlparse(url)
fcgi_host, fcgi_port = prl.hostname, prl.port
try:
fcgi = fcgi_client.FCGIApp(host=fcgi_host, port=fcgi_port)
env = {
'SCRIPT_FILENAME': prl.path[1:],
'QUERY_STRING': prl.query,
'REQUEST_METHOD': 'GET',
'SCRIPT_NAME': prl.path[1:],
'REQUEST_URI': prl.path + '?' + prl.query,
'GATEWAY_INTERFACE': 'CGI/1.1',
# 'DOCUMENT_ROOT': '/qgisserver/',
'SERVER_ADDR': fcgi_host,
'SERVER_PORT': str(fcgi_port),
'SERVER_PROTOCOL': 'HTTP/1.0',
'SERVER_NAME': fcgi_host
}
ret = fcgi(env)
return ret
except:
print 'Locally spawned fcgi server not accessible'
return '500', [], '', ''


def openInBrowserTab(url):
if sys.platform[:3] in ('win', 'dar'):
import webbrowser
Expand All @@ -282,39 +385,60 @@ def openInBrowserTab(url):
stderr=subprocess.STDOUT).pid


class TestQgisLocalServerConfig(TestCase):

def config_dir(self):
# for when testing local writes to projdir
if TESTSPAWN:
return tempfile.mkdtemp()
else:
return os.path.join(os.path.expanduser('~'), '.qgis2')

# @unittest.skip('')
def test_check_capabilities(self):
server = QgisLocalServerConfig(self.config_dir(),
chkcapa=True,
spawn=TESTSPAWN)
# print '\nServer accessible and returned capabilities'

# @unittest.skip('')
def test_get_map_serverconfig(self):
server = QgisLocalServerConfig(self.config_dir(), spawn=TESTSPAWN)

# creating crs needs app instance to access /resources/srs.db
# crs = QgsCoordinateReferenceSystem()
# # default for labeling test data sources: WGS 84 / UTM zone 13N
# crs.createFromSrid(32613)
ext = QgsRectangle(606510, 4823130, 612510, 4827130)
params = {
'SERVICE': 'WMS',
'VERSION': '1.3.0',
'REQUEST': 'GetMap',
'MAP': TESTPROJ,
# layer stacking order for rendering: bottom,to,top
'LAYERS': ['background', 'point'], # or 'background,point'
'STYLES': ',',
'CRS': 'EPSG:32613', # or: QgsCoordinateReferenceSystem obj
'BBOX': ext, # or: '606510,4823130,612510,4827130'
'FORMAT': 'image/png', # or: 'image/png; mode=8bit'
'WIDTH': '600',
'HEIGHT': '400',
'DPI': '72',
'MAP_RESOLUTION': '72',
'FORMAT_OPTIONS': 'dpi:72',
'TRANSPARENT': 'FALSE',
'IgnoreGetMapUrl': '1'
}
if 'QGISSERVER_PNG' in os.environ and not TESTSPAWN:
# open resultant png with system
res, filepath = server.getMap(params, False)
openInBrowserTab('file://' + filepath)
else:
# open GetMap url in browser
res, filepath = server.getMap(params, True)


if __name__ == '__main__':
qgishome = os.path.join(os.path.expanduser('~'), '.qgis2')
server = QgisLocalServerConfig(qgishome, True)
# print '\nServer accessible and returned capabilities'

# creating crs needs app instance to access /resources/srs.db
# crs = QgsCoordinateReferenceSystem()
# # default for labeling test data sources: WGS 84 / UTM zone 13N
# crs.createFromSrid(32613)
ext = QgsRectangle(606510, 4823130, 612510, 4827130)
params = {
'SERVICE': 'WMS',
'VERSION': '1.3.0',
'REQUEST': 'GetMap',
'MAP': '/test-projects/tests/tests.qgs',
# layer stacking order for rendering: bottom,to,top
'LAYERS': ['background', 'point'], # or 'background,point'
'STYLES': ',',
'CRS': 'EPSG:32613', # or: QgsCoordinateReferenceSystem obj
'BBOX': ext, # or: '606510,4823130,612510,4827130'
'FORMAT': 'image/png', # or: 'image/png; mode=8bit'
'WIDTH': '600',
'HEIGHT': '400',
'DPI': '72',
'MAP_RESOLUTION': '72',
'FORMAT_OPTIONS': 'dpi:72',
'TRANSPARENT': 'TRUE',
'IgnoreGetMapUrl': '1'
}
if 'QGISSERVER_PNG' in os.environ:
# open resultant png with system
res, filepath = server.getMap(params, False)
openInBrowserTab('file://' + filepath)
else:
# open GetMap url in browser
res, filepath = server.getMap(params, True)
TESTSPAWN = True
TESTPROJ = '/test-projects/tests/pal_test.qgs'
unittest.main(verbosity=2)
Empty file.

0 comments on commit d8b05c2

Please sign in to comment.