Skip to content

Commit

Permalink
Add unit tests for postgres provider
Browse files Browse the repository at this point in the history
basically to get a framework to test the expression compiler
  • Loading branch information
m-kuhn committed May 22, 2015
1 parent babfae9 commit a2ae8b4
Show file tree
Hide file tree
Showing 10 changed files with 184 additions and 33 deletions.
31 changes: 28 additions & 3 deletions .travis.yml
Expand Up @@ -11,19 +11,44 @@ notifications:
on_success: change
skip_join: true

addons:
postgresql: "9.1"

before_install:
- sudo add-apt-repository ppa:ubuntugis/ppa -y
- sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable -y # For postgresql-9.1-postgis-2.1
- sudo add-apt-repository ppa:smspillaz/cmake-3.0.2 -y
- sudo rm -f /etc/apt/sources.list.d/pgdg-source.list # postgis from pgdg requires different gdal package than the grass package
- sudo apt-get update -qq
- sudo apt-get install --no-install-recommends bison cmake cmake-data doxygen flex git graphviz grass-dev libexpat1-dev libfcgi-dev libgdal1-dev libgeos-dev libgsl0-dev libpq-dev libproj-dev libqscintilla2-dev libqt4-dev libqt4-opengl-dev libqtwebkit-dev libqwt-dev libspatialindex-dev libspatialite-dev libsqlite3-dev lighttpd pkg-config poppler-utils pyqt4-dev-tools python python-dev python-qt4 python-qt4-dev python-sip python-sip-dev spawn-fcgi txt2tags xauth xfonts-100dpi xfonts-75dpi xfonts-base xfonts-scalable xvfb
- sudo apt-get remove postgresql-9.1-postgis-2.1 # Remove postgis from pgdg, will install postgis from ubuntugis-unstable instead
- sudo apt-get install --no-install-recommends
bison cmake cmake-data doxygen flex git graphviz
grass-dev libexpat1-dev libfcgi-dev libgdal1-dev
libgeos-dev libgsl0-dev libpq-dev libproj-dev
libqscintilla2-dev libqt4-dev libqt4-opengl-dev
libqtwebkit-dev libqwt-dev libspatialindex-dev
libspatialite-dev libsqlite3-dev lighttpd pkg-config
poppler-utils pyqt4-dev-tools python python-dev
python-qt4 python-qt4-dev python-sip python-sip-dev
spawn-fcgi txt2tags xauth xfonts-100dpi xfonts-75dpi
xfonts-base xfonts-scalable xvfb
postgresql-9.1-postgis-2.1
- cmake --version
- clang --version

install:
- mkdir build
- cd build
- cmake -DWITH_SERVER=ON -DWITH_STAGED_PLUGINS=OFF -DWITH_GRASS=OFF \
-DSUPPRESS_QT_WARNINGS=ON -DENABLE_MODELTEST=ON -DWITH_QWTPOLAR=OFF -DWITH_APIDOC=ON ..
- cmake -DWITH_SERVER=ON -DWITH_STAGED_PLUGINS=OFF -DWITH_GRASS=OFF
-DSUPPRESS_QT_WARNINGS=ON -DENABLE_MODELTEST=ON
-DWITH_QWTPOLAR=OFF -DWITH_APIDOC=ON ..

before_script:
- echo "localhost:*:*:postgres:postgres" > ~/.pgpass
- printf "[qgis_test]\nuser=postgres\nhost=localhost\nuser=postgres" > ~/.pg_service.conf
- psql -c 'CREATE DATABASE qgis_test;' -U postgres
- psql -c 'CREATE EXTENSION postgis;' -U postgres -d qgis_test
- psql -f $TRAVIS_BUILD_DIR/tests/testdata/postgres/testdata.sql -U postgres -d qgis_test

script: xvfb-run ctest -V -E 'PyQgsPalLabelingServer|qgis_wcsprovidertest' -S ../qgis-test-travis.ctest --output-on-failure

12 changes: 6 additions & 6 deletions python/core/qgsexpression.sip
Expand Up @@ -194,7 +194,7 @@ class QgsExpression
class Function
{
public:
Function( QString fnname, int params, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList() );
Function( const QString& fnname, int params, const QString& group, const QString& helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false );
/** The name of the function. */
QString name();
/** The number of parameters this function takes. */
Expand All @@ -219,7 +219,7 @@ class QgsExpression
/** The group the function belongs to. */
QString group();
/** The help text for the function. */
QString helptext();
const QString helptext();

virtual QVariant func( const QVariantList& values, const QgsFeature* f, QgsExpression* parent ) = 0;
};
Expand Down Expand Up @@ -309,7 +309,7 @@ class QgsExpression
~NodeList();
void append( QgsExpression::Node* node /Transfer/ );
int count();
QList<QgsExpression::Node*> list();
const QList<QgsExpression::Node*>& list();

virtual QString dump() const;

Expand Down Expand Up @@ -420,9 +420,9 @@ class QgsExpression
class NodeLiteral : QgsExpression::Node
{
public:
NodeLiteral( QVariant value );
NodeLiteral( const QVariant& value );

QVariant value() const;
const QVariant& value() const;

virtual QgsExpression::NodeType nodeType() const;
virtual bool prepare( QgsExpression* parent, const QgsFields &fields );
Expand All @@ -437,7 +437,7 @@ class QgsExpression
class NodeColumnRef : QgsExpression::Node
{
public:
NodeColumnRef( QString name );
NodeColumnRef( const QString& name );

QString name() const;

Expand Down
13 changes: 5 additions & 8 deletions src/core/qgsexpression.h
Expand Up @@ -286,7 +286,7 @@ class CORE_EXPORT QgsExpression
class CORE_EXPORT Function
{
public:
Function( QString fnname, int params, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false )
Function( const QString& fnname, int params, QString group, QString helpText = QString(), bool usesGeometry = false, QStringList referencedColumns = QStringList(), bool lazyEval = false )
: mName( fnname ), mParams( params ), mUsesGeometry( usesGeometry ), mGroup( group ), mHelpText( helpText ), mReferencedColumns( referencedColumns ), mLazyEval( lazyEval ) {}
/** The name of the function. */
QString name() { return mName; }
Expand All @@ -312,7 +312,7 @@ class CORE_EXPORT QgsExpression
/** The group the function belongs to. */
QString group() { return mGroup; }
/** The help text for the function. */
QString helptext() { return mHelpText.isEmpty() ? QgsExpression::helptext( mName ) : mHelpText; }
const QString helptext() { return mHelpText.isEmpty() ? QgsExpression::helptext( mName ) : mHelpText; }

virtual QVariant func( const QVariantList& values, const QgsFeature* f, QgsExpression* parent ) = 0;

Expand Down Expand Up @@ -424,6 +424,7 @@ class CORE_EXPORT QgsExpression
public:
NodeList() {}
virtual ~NodeList() { qDeleteAll( mList ); }
/** Takes ownership of the provided node */
void append( Node* node ) { mList.append( node ); }
int count() { return mList.count(); }
QList<Node*> list() { return mList; }
Expand Down Expand Up @@ -572,13 +573,9 @@ class CORE_EXPORT QgsExpression
class CORE_EXPORT NodeLiteral : public Node
{
public:
NodeLiteral( QVariant value ) : mValue( value ) {}
NodeLiteral( const QVariant& value ) : mValue( value ) {}

<<<<<<< HEAD
QVariant value() const { return mValue; }
=======
inline QVariant value() const { return mValue; }
>>>>>>> c943e22... Revert "Add convenience method QgsVectorLayer::getFeatures( expression )"

virtual NodeType nodeType() const override { return ntLiteral; }
virtual bool prepare( QgsExpression* parent, const QgsFields &fields ) override;
Expand All @@ -596,7 +593,7 @@ class CORE_EXPORT QgsExpression
class CORE_EXPORT NodeColumnRef : public Node
{
public:
NodeColumnRef( QString name ) : mName( name ), mIndex( -1 ) {}
NodeColumnRef( const QString& name ) : mName( name ), mIndex( -1 ) {}

QString name() const { return mName; }

Expand Down
1 change: 1 addition & 0 deletions src/core/qgsvectorlayer.h
@@ -1,3 +1,4 @@

/***************************************************************************
qgsvectorlayer.h - description
-------------------
Expand Down
5 changes: 0 additions & 5 deletions src/providers/postgres/qgspostgresfeatureiterator.cpp
Expand Up @@ -255,11 +255,6 @@ bool QgsPostgresFeatureIterator::close()
return true;
}

int QgsPostgresFeatureIterator::count()
{

}

///////////////

QString QgsPostgresFeatureIterator::whereClauseRect()
Expand Down
3 changes: 0 additions & 3 deletions src/providers/postgres/qgspostgresfeatureiterator.h
Expand Up @@ -81,9 +81,6 @@ class QgsPostgresFeatureIterator : public QgsAbstractFeatureIteratorFromSource<Q
//! end of iterating: free the resources / lock
virtual bool close() override;

//! the number of features
virtual int count() override;

protected:
//! fetch next feature, return true on success
virtual bool fetchFeature( QgsFeature& feature ) override;
Expand Down
3 changes: 2 additions & 1 deletion tests/src/python/CMakeLists.txt
Expand Up @@ -44,6 +44,7 @@ ADD_PYTHON_TEST(PyQgsGraduatedSymbolRendererV2 test_qgsgraduatedsymbolrendererv2
ADD_PYTHON_TEST(PyQgsNetworkContentFetcher test_qgsnetworkcontentfetcher.py)
ADD_PYTHON_TEST(PyQgsEditWidgets test_qgseditwidgets.py)
ADD_PYTHON_TEST(PyQgsRangeWidgets test_qgsrangewidgets.py)
ADD_PYTHON_TEST(PyQgsPostgresProvider test_postgres_provider.py)
IF (WITH_APIDOC)
ADD_PYTHON_TEST(PyQgsDocCoverage test_qgsdoccoverage.py)
ENDIF (WITH_APIDOC)
ENDIF (WITH_APIDOC)
65 changes: 65 additions & 0 deletions tests/src/python/test_postgres_provider.py
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for the postgres provider.
.. 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__ = 'Matthias Kuhn'
__date__ = '2015-04-23'
__copyright__ = 'Copyright 2015, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import qgis
import os

from qgis.core import QgsVectorLayer, QgsFeatureRequest, QgsFeature, QgsProviderRegistry
from PyQt4.QtCore import QSettings
from utilities import (unitTestDataPath,
getQgisTestApp,
TestCase,
unittest
)
QGISAPP, CANVAS, IFACE, PARENT = getQgisTestApp()
TEST_DATA_DIR = unitTestDataPath()

class TestPyQgsPostgresProvider(TestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""

# Create test database
cls.vl = QgsVectorLayer( u'service=\'qgis_test\' key=\'pk\' table="qgis_test"."someData" sql=', 'test', 'postgres' )


@classmethod
def tearDownClass(cls):
"""Run after all tests"""

# Delete test database

def testGetFeaturesUncompiled(self):
QSettings().setValue( "providers/postgres/compileExpressions", False )
self.runGetFeatureTests()

def testGetFeaturesCompiled(self):
QSettings().setValue( "providers/postgres/compileExpressions", True )
self.runGetFeatureTests()

def runGetFeatureTests(self):
assert len( [f for f in self.vl.getFeatures()] ) == 5
assert len( [f for f in self.vl.getFeatures( 'name IS NOT NULL' )] ) == 4
assert len( [f for f in self.vl.getFeatures( 'name LIKE \'Apple\'' )] ) == 1
assert len( [f for f in self.vl.getFeatures( 'name ILIKE \'aPple\'' )] ) == 1
assert len( [f for f in self.vl.getFeatures( 'name ILIKE \'%pp%\'' )] ) == 1
assert len( [f for f in self.vl.getFeatures( 'cnt > 0' )] ) == 4
assert len( [f for f in self.vl.getFeatures( 'cnt < 0' )] ) == 1
assert len( [f for f in self.vl.getFeatures( 'cnt >= 100' )] ) == 4
assert len( [f for f in self.vl.getFeatures( 'cnt <= 100' )] ) == 2
assert len( [f for f in self.vl.getFeatures( 'pk IN (1, 2, 4, 8)' )] ) == 3


if __name__ == '__main__':
unittest.main()
9 changes: 2 additions & 7 deletions tests/src/python/utilities.py
Expand Up @@ -138,15 +138,10 @@ def getQgisTestApp():


def unitTestDataPath(theSubdir=None):
"""Return the absolute path to the InaSAFE unit test data dir.
.. note:: This is not the same thing as the SVN inasafe_data dir. Rather
this is a new dataset where the test datasets are all tiny for fast
testing and the datasets live in the same repo as the code.
"""Return the absolute path to the QGIS unit test data dir.
Args:
* theSubdir: (Optional) Additional subdir to add to the path - typically
'hazard' or 'exposure'.
* theSubdir: (Optional) Additional subdir to add to the path
"""
myPath = __file__
tmpPath = os.path.split(os.path.dirname(myPath))
Expand Down
75 changes: 75 additions & 0 deletions tests/testdata/postgres/testdata.sql
@@ -0,0 +1,75 @@
--
-- PostgreSQL database dump
--

-- Dumped from database version 9.3.6
-- Dumped by pg_dump version 9.3.6
-- Started on 2015-04-23 18:42:07 CEST

SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;

--
-- TOC entry 7 (class 2615 OID 377760)
-- Name: qgis_test; Type: SCHEMA; Schema: -; Owner: postgres
--

CREATE SCHEMA qgis_test;


ALTER SCHEMA qgis_test OWNER TO postgres;

SET search_path = qgis_test, pg_catalog;

SET default_tablespace = '';

SET default_with_oids = false;

--
-- TOC entry 171 (class 1259 OID 377761)
-- Name: someData; Type: TABLE; Schema: qgis_test; Owner: postgres; Tablespace:
--

CREATE TABLE "someData" (
pk integer NOT NULL,
cnt integer,
name text
);


ALTER TABLE qgis_test."someData" OWNER TO postgres;

--
-- TOC entry 4068 (class 0 OID 377761)
-- Dependencies: 171
-- Data for Name: someData; Type: TABLE DATA; Schema: qgis_test; Owner: postgres
--

COPY "someData" (pk, cnt, name) FROM stdin;
1 100 Orange
2 200 Apple
3 300 Pear
4 400 Honey
5 -200 \N
\.


--
-- TOC entry 3953 (class 2606 OID 377768)
-- Name: someData_pkey; Type: CONSTRAINT; Schema: qgis_test; Owner: postgres; Tablespace:
--

ALTER TABLE ONLY "someData"
ADD CONSTRAINT "someData_pkey" PRIMARY KEY (pk);


-- Completed on 2015-04-23 18:42:07 CEST

--
-- PostgreSQL database dump complete
--

0 comments on commit a2ae8b4

Please sign in to comment.