Skip to content

Commit

Permalink
[labeling] Add local preconfigured test server unit tests class
Browse files Browse the repository at this point in the history
- Add control images for server output
- Add class for comparison against canvas output
  • Loading branch information
dakcarto committed Aug 21, 2013
1 parent dd26e61 commit 287e0a0
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 14 deletions.
2 changes: 1 addition & 1 deletion tests/src/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ ADD_PYTHON_TEST(PyQgsExpression test_qgsexpression.py)
ADD_PYTHON_TEST(PyQgsPalLabelingBase test_qgspallabeling_base.py)
ADD_PYTHON_TEST(PyQgsPalLabelingCanvas test_qgspallabeling_canvas.py)
#ADD_PYTHON_TEST(PyQgsPalLabelingComposer test_qgspallabeling_composer.py)
#ADD_PYTHON_TEST(PyQgsPalLabelingServer test_qgspallabeling_server.py)
ADD_PYTHON_TEST(PyQgsPalLabelingServer test_qgspallabeling_server.py)
ADD_PYTHON_TEST(PyQgsVectorFileWriter test_qgsvectorfilewriter.py)
ADD_PYTHON_TEST(PyQgsSpatialiteProvider test_qgsspatialiteprovider.py)
ADD_PYTHON_TEST(PyQgsZonalStatistics test_qgszonalstatistics.py)
Expand Down
75 changes: 63 additions & 12 deletions tests/src/python/test_qgspallabeling_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import sys
import datetime
import glob
import shutil
import StringIO
import tempfile
from PyQt4.QtCore import *
Expand All @@ -36,6 +37,7 @@
QgsMapRenderer,
QgsPalLabeling,
QgsPalLayerSettings,
QgsProject,
QgsProviderRegistry,
QgsVectorLayer,
QgsRenderChecker
Expand Down Expand Up @@ -64,6 +66,7 @@ class TestQgsPalLabeling(TestCase):
_PalDataDir = os.path.join(_TestDataDir, 'labeling')
_PalFeaturesDb = os.path.join(_PalDataDir, 'pal_features_v3.sqlite')
_TestFont = TESTFONT
_TestProj = None
_MapRegistry = None
_MapRenderer = None
_Canvas = None
Expand All @@ -77,8 +80,7 @@ def setUpClass(cls):
QGISAPP, CANVAS, IFACE, PARENT

# verify that spatialite provider is available
msg = ('\nSpatialite provider not found, '
'SKIPPING TEST SUITE')
msg = '\nSpatialite provider not found, SKIPPING TEST SUITE'
res = 'spatialite' in QgsProviderRegistry.instance().providerList()
assert res, msg

Expand All @@ -90,6 +92,7 @@ def setUpClass(cls):
cls._TestGroup = ''
cls._TestGroupPrefix = ''
cls._TestGroupAbbr = ''
cls._TestImage = ''

# initialize class MapRegistry, Canvas, MapRenderer, Map and PAL
cls._MapRegistry = QgsMapLayerRegistry.instance()
Expand All @@ -98,10 +101,10 @@ def setUpClass(cls):
cls._Map = cls._Canvas.map()
cls._Map.resize(QSize(600, 400))
cls._MapRenderer = cls._Canvas.mapRenderer()
crs = QgsCoordinateReferenceSystem()
cls._CRS = QgsCoordinateReferenceSystem()
# default for labeling test data sources: WGS 84 / UTM zone 13N
crs.createFromSrid(32613)
cls._MapRenderer.setDestinationCrs(crs)
cls._CRS.createFromSrid(32613)
cls._MapRenderer.setDestinationCrs(cls._CRS)
# use platform's native logical output dpi for QgsMapRenderer on launch

cls._Pal = QgsPalLabeling()
Expand Down Expand Up @@ -195,7 +198,7 @@ def settingsDict(lyr):
res[attr] = value
return res

def saveContolImage(self):
def saveContolImage(self, tmpimg=''):
if 'PAL_CONTROL_IMAGE' not in os.environ:
return
testgrpdir = 'expected_' + self._TestGroupPrefix
Expand All @@ -208,21 +211,69 @@ def saveContolImage(self):
for f in glob.glob(imgbasepath + '.*'):
if os.path.exists(f):
os.remove(f)
self._Map.render()
self._Canvas.saveAsImage(imgpath)

def renderCheck(self, mismatch=0):
if tmpimg:
if os.path.exists(tmpimg):
shutil.copyfile(tmpimg, imgpath)
else:
self._Map.render()
self._Canvas.saveAsImage(imgpath)

def renderCheck(self, mismatch=0, imgpath='', grpprefix=''):
"""Check rendered map canvas or existing image against control image
mismatch: number of pixels different from control, and still valid check
imgpath: existing image; if present, skips rendering canvas
grpprefix: compare test image/rendering against different test group
"""
if not grpprefix:
grpprefix = self._TestGroupPrefix
chk = QgsRenderChecker()
chk.setControlPathPrefix('expected_' + self._TestGroupPrefix)
chk.setControlPathPrefix('expected_' + grpprefix)
chk.setControlName(self._Test)
chk.setMapRenderer(self._MapRenderer)
res = chk.runTest(self._Test, mismatch)
res = False
if imgpath:
res = chk.compareImages(self._Test, mismatch, str(imgpath))
else:
res = chk.runTest(self._Test, mismatch)
if PALREPORT and not res: # don't report ok checks
testname = self._TestGroup + ' . ' + self._Test
PALREPORTS[testname] = str(chk.report().toLocal8Bit())
msg = '\nRender check failed for "{0}"'.format(self._Test)
return res, msg

def defaultWmsParams(self, projpath, layername):
return {
'SERVICE': 'WMS',
'VERSION': '1.3.0',
'REQUEST': 'GetMap',
'MAP': str(projpath).strip(),
# layer stacking order for rendering: bottom,to,top
'LAYERS': ['background', str(layername).strip()], # or 'name,name'
'STYLES': ',',
'CRS': 'EPSG:32613', # self._CRS, # authid str or QgsCoordinateReferenceSystem obj
'BBOX': '606510,4823130,612510,4827130', # self.aoiExtent(),
'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'
}

@classmethod
def setUpServerProjectAndDir(cls, testprojpath, testdir):
cls._TestProj = QgsProject.instance()
cls._TestProj.setFileName(testprojpath)
try:
shutil.copy(cls._PalFeaturesDb, testdir)
for qml in glob.glob(cls._PalDataDir + os.sep + '*.qml'):
shutil.copy(qml, testdir)
except IOError, e:
raise IOError(str(e) + '\nCould not set up test server directory')


class TestPALConfig(TestQgsPalLabeling):

Expand Down
2 changes: 1 addition & 1 deletion tests/src/python/test_qgspallabeling_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def tearDown(self):
"""Run after each test."""
pass

def checkTest(self):
def checkTest(self, **kwargs):
self.lyr.writeToLayer(self.layer)
self.saveContolImage()
self.assertTrue(*self.renderCheck())
Expand Down
111 changes: 111 additions & 0 deletions tests/src/python/test_qgspallabeling_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
"""QGIS unit tests for QgsPalLabeling: label rendering via QGIS Server
From build dir: ctest -R PyQgsPalLabelingServer -V
Set the following env variables when manually running tests:
PAL_SUITE to run specific tests (define in __main__)
PAL_VERBOSE to output individual test summary
PAL_CONTROL_IMAGE to trigger building of new control images
PAL_REPORT to open any failed image check reports in web browser
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""

__author__ = 'Larry Shaffer'
__date__ = '07/12/2013'
__copyright__ = 'Copyright 2013, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import sys
import os
from PyQt4.QtCore import *
from PyQt4.QtGui import *

from qgis.core import *

from utilities import (
unittest,
expectedFailure,
)

from test_qgspallabeling_base import TestQgsPalLabeling, runSuite
from test_qgspallabeling_tests import TestPointBase
from qgis_local_server import (QgisLocalServerConfig,
ServerConfigNotAccessibleError)

SERVER = None
TESTPROJDIR = ''
TESTPROJPATH = ''
try:
SERVER = \
QgisLocalServerConfig(str(QgsApplication.qgisSettingsDirPath()), True)
TESTPROJDIR = SERVER.projectDir()
TESTPROJPATH = os.path.join(TESTPROJDIR, 'pal_test.qgs')
except ServerConfigNotAccessibleError, e:
print e


def skipUnlessHasServer(): # skip test class decorator
if SERVER is not None:
return lambda func: func
return unittest.skip('\nConfigured local QGIS Server is not accessible\n\n')


@skipUnlessHasServer()
class TestServerPoint(TestQgsPalLabeling, TestPointBase):

@classmethod
def setUpClass(cls):
TestQgsPalLabeling.setUpClass()
cls.setUpServerProjectAndDir(TESTPROJPATH, TESTPROJDIR)
cls.layer = TestQgsPalLabeling.loadFeatureLayer('background')
cls.layer = TestQgsPalLabeling.loadFeatureLayer('point')
cls.checkmismatch = 1000
cls.checkgroup = ''

def setUp(self):
"""Run before each test."""
self.configTest('pal_server', 'sp')
self.lyr = self.defaultSettings()
self.params = self.defaultWmsParams(TESTPROJPATH, 'point')
self._TestImage = ''

def tearDown(self):
"""Run after each test."""
pass

def checkTest(self, **kwargs):
self.lyr.writeToLayer(self.layer)
# save project file
self._TestProj.write()
# get server results
res, self._TestImage = SERVER.getMap(self.params, False)
self.saveContolImage(self._TestImage)
self.assertTrue(res, 'Failed to retrieve/save image from test server')
# gp = kwargs['grpprefix'] if 'grpprefix' in kwargs else ''
self.assertTrue(*self.renderCheck(mismatch=self.checkmismatch,
imgpath=self._TestImage,
grpprefix=self.checkgroup))


@skipUnlessHasServer()
class TestServerVsCanvasPoint(TestServerPoint):

@classmethod
def setUpClass(cls):
TestServerPoint.setUpClass()
cls.checkgroup = 'pal_canvas'


if __name__ == '__main__':
# NOTE: unless PAL_SUITE env var is set all test class methods will be run
# ex: 'TestGroup(Point|Line|Curved|Polygon|Feature).test_method'
suite = [
'TestServerVsCanvasPoint.test_text_size_map_unit'
]
res = runSuite(sys.modules[__name__], suite)
sys.exit(not res.wasSuccessful())
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 287e0a0

Please sign in to comment.