forked from hans/Nominatim
move php tests in common test dir and unify READMEs
This commit is contained in:
133
test/README.md
Normal file
133
test/README.md
Normal file
@@ -0,0 +1,133 @@
|
||||
This directory contains functional and unit tests for the Nominatim API.
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
* Python 3 (https://www.python.org/)
|
||||
* behave test framework >= 1.2.5 (https://github.com/behave/behave)
|
||||
* nose (https://nose.readthedocs.org)
|
||||
* pytidylib (http://countergram.com/open-source/pytidylib)
|
||||
* psycopg2 (http://initd.org/psycopg/)
|
||||
|
||||
To get the prerequisites on a a fresh Ubuntu LTS 16.04 run:
|
||||
|
||||
[sudo] apt-get install python3-dev python3-pip python3-psycopg2 python3-tidylib phpunit
|
||||
pip3 install --user behave nose
|
||||
|
||||
|
||||
Overall structure
|
||||
=================
|
||||
|
||||
There are two kind of tests in this test suite. There are functional tests
|
||||
which test the API interface using a BDD test framework and there are unit
|
||||
tests for specific PHP functions.
|
||||
|
||||
This test directory is sturctured as follows:
|
||||
|
||||
-+- bdd Functional API tests
|
||||
| \
|
||||
| +- steps Step implementations for test descriptions
|
||||
| +- osm2pgsql Tests for data import via osm2pgsql
|
||||
| +- db Tests for internal data processing on import and update
|
||||
| +- api Tests for API endpoints (search, reverse, etc.)
|
||||
|
|
||||
+- php PHP unit tests
|
||||
+- scenes Geometry test data
|
||||
+- testdb Base data for generating API test database
|
||||
|
||||
|
||||
PHP Unit Tests
|
||||
==============
|
||||
|
||||
Unit tests can be found in the php/ directory and tests selected php functions.
|
||||
Very low coverage.
|
||||
|
||||
To execute the test suite run
|
||||
|
||||
cd test/php
|
||||
phpunit ../
|
||||
|
||||
It will read phpunit.xml which points to the library, test path, bootstrap
|
||||
strip and set other parameters.
|
||||
|
||||
|
||||
BDD Functional Tests
|
||||
====================
|
||||
|
||||
Functional tests are written as BDD instructions. For more information on
|
||||
the philosophy of BDD testing, see http://pythonhosted.org/behave/philosophy.html
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
To run the functional tests, do
|
||||
|
||||
cd test/bdd
|
||||
behave
|
||||
|
||||
The tests can be configured with a set of environment variables:
|
||||
|
||||
* `BUILD_DIR` - build directory of Nominatim installation to test
|
||||
* `TEMPLATE_DB` - name of template database used as a skeleton for
|
||||
the test databases (db tests)
|
||||
* `TEST_DB` - name of test database (db tests)
|
||||
* `ABI_TEST_DB` - name of the database containing the API test data (api tests)
|
||||
* `TEST_SETTINGS_TEMPLATE` - file to write temporary Nominatim settings to
|
||||
* `REMOVE_TEMPLATE` - if true, the template database will not be reused during
|
||||
the next run. Reusing the base templates speeds up tests
|
||||
considerably but might lead to outdated errors for some
|
||||
changes in the database layout.
|
||||
* `KEEP_TEST_DB` - if true, the test database will not be dropped after a test
|
||||
is finished. Should only be used if one single scenario is
|
||||
run, otherwise the result is undefined.
|
||||
|
||||
Logging can be defined through command line parameters of behave itself. Check
|
||||
out `behave --help` for details. Also keep an eye out for the 'work-in-progress'
|
||||
feature of behave which comes in handy when writing new tests.
|
||||
|
||||
Writing Tests
|
||||
-------------
|
||||
|
||||
The following explanation assume that the reader is familiar with the BDD
|
||||
notations of features, scenarios and steps.
|
||||
|
||||
All possible steps can be found in the `steps` directory and should ideally
|
||||
be documented.
|
||||
|
||||
### API Tests (`test/bdd/api`)
|
||||
|
||||
These tests are meant to test the different API endpoints and their parameters.
|
||||
They require a preimported test database, which consists of the import of a
|
||||
planet extract. The polygons defining the extract can be found in the test/testdb
|
||||
directory. There is also a reduced set of wikipedia data for this extract,
|
||||
which you need to import as well.
|
||||
|
||||
The official test dataset is derived from the 160725 planet. Newer
|
||||
planets are likely to work as well but you may see isolated test
|
||||
failures where the data has changed. To recreate the input data
|
||||
for the test database run:
|
||||
|
||||
wget http://free.nchc.org.tw/osm.planet/pbf/planet-160725.osm.pbf
|
||||
osmconvert planet-160725.osm.pbf -B=test/testdb/testdb.polys -o=testdb.pbf
|
||||
|
||||
Before importing make sure to add the following to your local settings:
|
||||
|
||||
@define('CONST_Database_DSN', 'pgsql://@/test_api_nominatim');
|
||||
@define('CONST_Wikipedia_Data_Path', CONST_BasePath.'/test/testdb');
|
||||
|
||||
### Indexing Tests (`test/bdd/db`)
|
||||
|
||||
These tests check the import and update of the Nominatim database. They do not
|
||||
test the correctness of osm2pgsql. Each test will write some data into the `place`
|
||||
table (and optionally `the planet_osm_*` tables if required) and then run
|
||||
Nominatim's processing functions on that.
|
||||
|
||||
These tests need to create their own test databases. By default they will be
|
||||
called `test_template_nominatim` and `test_nominatim`. Names can be changed with
|
||||
the environment variables `TEMPLATE_DB` and `TEST_DB`. The user running the tests
|
||||
needs superuser rights for postgres.
|
||||
|
||||
### Import Tests (`test/bdd/osm2pgsql`)
|
||||
|
||||
These tests check that data is imported correctly into the place table. They
|
||||
use the same template database as the Indexing tests, so the same remarks apply.
|
||||
@@ -18,10 +18,14 @@ Feature: Parenting of objects
|
||||
| object | parent_place_id |
|
||||
| N1 | W1 |
|
||||
| N2 | W1 |
|
||||
And search_name contains
|
||||
| object | nameaddress_vector |
|
||||
| N1 | 4, galoo, 12345 |
|
||||
| N2 | 5, galoo, 99999 |
|
||||
When searching for "4 galoo"
|
||||
Then results contain
|
||||
| ID | osm_type | osm_id | langaddress
|
||||
| 0 | N | 1 | 4, galoo, 12345
|
||||
When searching for "5 galoo"
|
||||
Then results contain
|
||||
| ID | osm_type | osm_id | langaddress
|
||||
| 0 | N | 2 | 5, galoo, 99999
|
||||
|
||||
Scenario: Address without tags, closest street
|
||||
Given the scene roads-with-pois
|
||||
|
||||
@@ -10,7 +10,6 @@ from sys import version_info as python_version
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
userconfig = {
|
||||
'BASEURL' : 'http://localhost/nominatim',
|
||||
'BUILDDIR' : os.path.join(os.path.split(__file__)[0], "../../build"),
|
||||
'REMOVE_TEMPLATE' : False,
|
||||
'KEEP_TEST_DB' : False,
|
||||
|
||||
@@ -264,7 +264,7 @@ def send_api_query(endpoint, params, fmt, context):
|
||||
for h in context.table.headings:
|
||||
params[h] = context.table[0][h]
|
||||
|
||||
env = BASE_SERVER_ENV
|
||||
env = dict(BASE_SERVER_ENV)
|
||||
env['QUERY_STRING'] = urlencode(params)
|
||||
|
||||
env['SCRIPT_NAME'] = '/%s.php' % endpoint
|
||||
|
||||
262
test/php/Nominatim/NominatimTest.php
Normal file
262
test/php/Nominatim/NominatimTest.php
Normal file
@@ -0,0 +1,262 @@
|
||||
<?php
|
||||
|
||||
namespace Nominatim;
|
||||
|
||||
require '../../lib/lib.php';
|
||||
|
||||
class NominatimTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
public function testGetClassTypesWithImportance()
|
||||
{
|
||||
$aClasses = getClassTypesWithImportance();
|
||||
|
||||
$this->assertGreaterThan(
|
||||
200,
|
||||
count($aClasses)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
'label' => "Country",
|
||||
'frequency' => 0,
|
||||
'icon' => "poi_boundary_administrative",
|
||||
'defzoom' => 6,
|
||||
'defdiameter' => 15,
|
||||
'importance' => 3
|
||||
),
|
||||
$aClasses['place:country']
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testGetResultDiameter()
|
||||
{
|
||||
$aResult = array();
|
||||
$this->assertEquals(
|
||||
0.0001,
|
||||
getResultDiameter($aResult)
|
||||
);
|
||||
|
||||
$aResult = array('class' => 'place', 'type' => 'country');
|
||||
$this->assertEquals(
|
||||
15,
|
||||
getResultDiameter($aResult)
|
||||
);
|
||||
|
||||
$aResult = array('class' => 'boundary', 'type' => 'administrative', 'admin_level' => 6);
|
||||
$this->assertEquals(
|
||||
0.32,
|
||||
getResultDiameter($aResult)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testAddQuotes()
|
||||
{
|
||||
// FIXME: not quoting existing quote signs is probably a bug
|
||||
$this->assertSame("'St. John's'", addQuotes("St. John's"));
|
||||
$this->assertSame("''", addQuotes(''));
|
||||
}
|
||||
|
||||
|
||||
public function testLooksLikeLatLonPair()
|
||||
{
|
||||
// no coordinates expected
|
||||
$this->assertNull(looksLikeLatLonPair(''));
|
||||
$this->assertNull(looksLikeLatLonPair('abc'));
|
||||
$this->assertNull(looksLikeLatLonPair('12 34'));
|
||||
$this->assertNull(looksLikeLatLonPair('200.1 89.9')); // because latitude > 180
|
||||
|
||||
// coordinates expected
|
||||
$this->assertNotNull(looksLikeLatLonPair('0.0 -0.0'));
|
||||
|
||||
$this->assertEquals(
|
||||
array( 'lat' => 12.456, 'lon' => -78.90, 'query' => 'abc def'),
|
||||
looksLikeLatLonPair(' abc 12.456 -78.90 def ')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array( 'lat' => 12.456, 'lon' => -78.90, 'query' => ''),
|
||||
looksLikeLatLonPair(' [12.456,-78.90] ')
|
||||
);
|
||||
|
||||
// http://en.wikipedia.org/wiki/Geographic_coordinate_conversion
|
||||
// these all represent the same location
|
||||
$aQueries = array(
|
||||
'40 26.767 N 79 58.933 W',
|
||||
'40° 26.767′ N 79° 58.933′ W',
|
||||
"40° 26.767' N 79° 58.933' W",
|
||||
'N 40 26.767, W 79 58.933',
|
||||
'N 40°26.767′, W 79°58.933′',
|
||||
"N 40°26.767', W 79°58.933'",
|
||||
|
||||
'40 26 46 N 79 58 56 W',
|
||||
'40° 26′ 46″ N 79° 58′ 56″ W',
|
||||
'N 40 26 46 W 79 58 56',
|
||||
'N 40° 26′ 46″, W 79° 58′ 56″',
|
||||
'N 40° 26\' 46", W 79° 58\' 56"',
|
||||
|
||||
'40.446 -79.982',
|
||||
'40.446,-79.982',
|
||||
'40.446° N 79.982° W',
|
||||
'N 40.446° W 79.982°',
|
||||
|
||||
'[40.446 -79.982]',
|
||||
' 40.446 , -79.982 ',
|
||||
);
|
||||
|
||||
|
||||
foreach ($aQueries as $sQuery) {
|
||||
$aRes = looksLikeLatLonPair($sQuery);
|
||||
$this->assertEquals(40.446, $aRes['lat'], 'degrees decimal ' . $sQuery, 0.01);
|
||||
$this->assertEquals(-79.982, $aRes['lon'], 'degrees decimal ' . $sQuery, 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function testGetWordSets()
|
||||
{
|
||||
// given an array of arrays like
|
||||
// array( array('a','b'), array('c','d') )
|
||||
// returns a summary as string: '(a|b),(c|d)'
|
||||
|
||||
|
||||
function serializeSets($aSets)
|
||||
{
|
||||
$aParts = array();
|
||||
foreach ($aSets as $aSet) {
|
||||
$aParts[] = '(' . join('|', $aSet) . ')';
|
||||
}
|
||||
return join(',', $aParts);
|
||||
}
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('')),
|
||||
getWordSets(array(), 0)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'(a)',
|
||||
serializeSets(getWordSets(array("a"), 0))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'(a b),(a|b)',
|
||||
serializeSets(getWordSets(array('a', 'b'), 0))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'(a b c),(a|b c),(a|b|c),(a b|c)',
|
||||
serializeSets(getWordSets(array('a', 'b', 'c'), 0))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
'(a b c d),(a|b c d),(a|b|c d),(a|b|c|d),(a|b c|d),(a b|c d),(a b|c|d),(a b c|d)',
|
||||
serializeSets(getWordSets(array('a', 'b', 'c', 'd'), 0))
|
||||
);
|
||||
|
||||
|
||||
// Inverse
|
||||
$this->assertEquals(
|
||||
'(a b c),(c|a b),(c|b|a),(b c|a)',
|
||||
serializeSets(getInverseWordSets(array('a', 'b', 'c'), 0))
|
||||
);
|
||||
|
||||
|
||||
// make sure we don't create too many sets
|
||||
// 4 words => 8 sets
|
||||
// 10 words => 511 sets
|
||||
// 15 words => 12911 sets
|
||||
// 18 words => 65536 sets
|
||||
// 20 words => 169766 sets
|
||||
// 22 words => 401930 sets
|
||||
// 28 words => 3505699 sets (needs more than 4GB via 'phpunit -d memory_limit=' to run)
|
||||
$this->assertEquals(
|
||||
8,
|
||||
count(getWordSets(array_fill(0, 4, 'a'), 0))
|
||||
);
|
||||
|
||||
|
||||
$this->assertEquals(
|
||||
41226,
|
||||
count(getWordSets(array_fill(0, 18, 'a'), 0))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testCreatePointsAroundCenter()
|
||||
{
|
||||
// you might say we're creating a circle
|
||||
$aPoints = createPointsAroundCenter(0, 0, 2);
|
||||
|
||||
$this->assertEquals(
|
||||
101,
|
||||
count($aPoints)
|
||||
);
|
||||
$this->assertEquals(
|
||||
array(
|
||||
['', 0, 2],
|
||||
['', 0.12558103905863, 1.9960534568565],
|
||||
['', 0.25066646712861, 1.984229402629]
|
||||
),
|
||||
array_splice($aPoints, 0, 3)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testGeometryText2Points()
|
||||
{
|
||||
$fRadius = 1;
|
||||
// invalid value
|
||||
$this->assertEquals(
|
||||
null,
|
||||
geometryText2Points('', $fRadius)
|
||||
);
|
||||
|
||||
// POINT
|
||||
$aPoints = geometryText2Points('POINT(10 20)', $fRadius);
|
||||
$this->assertEquals(
|
||||
101,
|
||||
count($aPoints)
|
||||
);
|
||||
$this->assertEquals(
|
||||
array(
|
||||
[10, 21],
|
||||
[10.062790519529, 20.998026728428],
|
||||
[10.125333233564, 20.992114701314]
|
||||
),
|
||||
array_splice($aPoints, 0, 3)
|
||||
);
|
||||
|
||||
// POLYGON
|
||||
$this->assertEquals(
|
||||
array(
|
||||
['30', '10'],
|
||||
['40', '40'],
|
||||
['20', '40'],
|
||||
['10', '20'],
|
||||
['30', '10']
|
||||
),
|
||||
geometryText2Points('POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))', $fRadius)
|
||||
);
|
||||
|
||||
// MULTIPOLYGON
|
||||
$this->assertEquals(
|
||||
array(
|
||||
['30', '20'], // first polygon only
|
||||
['45', '40'],
|
||||
['10', '40'],
|
||||
['30', '20'],
|
||||
),
|
||||
geometryText2Points('MULTIPOLYGON(((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))', $fRadius)
|
||||
);
|
||||
}
|
||||
}
|
||||
1
test/php/bootstrap.php
Normal file
1
test/php/bootstrap.php
Normal file
@@ -0,0 +1 @@
|
||||
<?php
|
||||
@@ -1,15 +0,0 @@
|
||||
Creating the test database
|
||||
==========================
|
||||
|
||||
The official test dataset is derived from the 160725 planet. Newer
|
||||
planets are likely to work as well but you may see isolated test
|
||||
failures where the data has changed. To recreate the input data
|
||||
for the test database run:
|
||||
|
||||
wget http://free.nchc.org.tw/osm.planet/pbf/planet-160725.osm.pbf
|
||||
osmconvert planet-160725.osm.pbf -B=testdb.polys -o=testdb.pbf
|
||||
|
||||
Before importing make sure to add the following to your local settings:
|
||||
|
||||
@define('CONST_Database_DSN', 'pgsql://@/test_api_nominatim');
|
||||
@define('CONST_Wikipedia_Data_Path', CONST_BasePath.'/test/testdb');
|
||||
Reference in New Issue
Block a user