Skip to content

Commit 8b55475

Browse files
committed
Merge pull request osm2pgsql-dev#415 from pnorman/schema_tests
Schema tests
2 parents dcde2b6 + e794d60 commit 8b55475

18 files changed

+423
-541
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ tests/test-output-multi-poly-trivial
5757
tests/test-output-pgsql
5858
tests/test-output-pgsql-tablespace
5959
tests/test-output-pgsql-z_order
60+
tests/test-output-pgsql-schema
6061
tests/test-expire-tiles
6162
tests/test-hstore-match-only
6263
tests/*.log

Makefile.am

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ check_PROGRAMS = \
5858
tests/test-output-pgsql \
5959
tests/test-output-pgsql-z_order \
6060
tests/test-output-pgsql-tablespace \
61+
tests/test-output-pgsql-schema \
6162
tests/test-pgsql-escape \
6263
tests/test-parse-options \
6364
tests/test-expire-tiles \
@@ -93,6 +94,8 @@ tests_test_output_pgsql_tablespace_SOURCES = tests/test-output-pgsql-tablespace.
9394
tests_test_output_pgsql_tablespace_LDADD = libosm2pgsql.la
9495
tests_test_output_pgsql_z_order_SOURCES = tests/test-output-pgsql-z_order.cpp tests/common-pg.cpp
9596
tests_test_output_pgsql_z_order_LDADD = libosm2pgsql.la
97+
tests_test_output_pgsql_schema_SOURCES = tests/test-output-pgsql-schema.cpp tests/common-pg.cpp
98+
tests_test_output_pgsql_schema_LDADD = libosm2pgsql.la
9699
tests_test_pgsql_escape_SOURCES = tests/test-pgsql-escape.cpp
97100
tests_test_pgsql_escape_LDADD = libosm2pgsql.la
98101
tests_test_parse_options_SOURCES = tests/test-parse-options.cpp
@@ -152,6 +155,7 @@ tests_test_output_multi_poly_trivial_LDADD += $(GLOBAL_LDFLAGS)
152155
tests_test_output_pgsql_LDADD += $(GLOBAL_LDFLAGS)
153156
tests_test_output_pgsql_tablespace_LDADD += $(GLOBAL_LDFLAGS)
154157
tests_test_output_pgsql_z_order_LDADD += $(GLOBAL_LDFLAGS)
158+
tests_test_output_pgsql_schema_LDADD += $(GLOBAL_LDFLAGS)
155159
tests_test_pgsql_escape_LDADD += $(GLOBAL_LDFLAGS)
156160
tests_test_parse_options_LDADD += $(GLOBAL_LDFLAGS)
157161
tests_test_expire_tiles_LDADD += $(GLOBAL_LDFLAGS)

tests/common-pg.cpp

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <boost/filesystem/fstream.hpp>
1010
#include <boost/format.hpp>
1111
#include <boost/algorithm/string/predicate.hpp>
12+
#include <boost/lexical_cast.hpp>
1213

1314
#ifdef _MSC_VER
1415
#include <windows.h>
@@ -76,10 +77,11 @@ result::~result() {
7677
}
7778

7879
tempdb::tempdb()
79-
: m_conn(conn::connect("dbname=postgres")) {
80+
: m_postgres_conn(conn::connect("dbname=postgres"))
81+
{
8082
result_ptr res = nullptr;
8183
database_options.db = (boost::format("osm2pgsql-test-%1%-%2%") % getpid() % time(nullptr)).str();
82-
m_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % database_options.db);
84+
m_postgres_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % database_options.db);
8385
//tests can be run concurrently which means that this query can collide with other similar ones
8486
//so we implement a simple retry here to get around the case that they do collide if we dont
8587
//we often fail due to both trying to access template1 at the same time
@@ -88,18 +90,18 @@ tempdb::tempdb()
8890
while(status != PGRES_COMMAND_OK && retries++ < 20)
8991
{
9092
sleep(1);
91-
res = m_conn->exec(boost::format("CREATE DATABASE \"%1%\" WITH ENCODING 'UTF8'") % database_options.db);
93+
res = m_postgres_conn->exec(boost::format("CREATE DATABASE \"%1%\" WITH ENCODING 'UTF8'") % database_options.db);
9294
status = PQresultStatus(res->get());
9395
}
9496
if (PQresultStatus(res->get()) != PGRES_COMMAND_OK) {
9597
throw std::runtime_error((boost::format("Could not create a database: %1%")
9698
% PQresultErrorMessage(res->get())).str());
9799
}
98100

99-
conn_ptr db = conn::connect(database_options.conninfo());
101+
m_conn = conn::connect(database_options);
100102

101-
setup_extension(db, "postgis", {"postgis-1.5/postgis.sql", "postgis-1.5/spatial_ref_sys.sql"});
102-
setup_extension(db, "hstore");
103+
setup_extension("postgis", {"postgis-1.5/postgis.sql", "postgis-1.5/spatial_ref_sys.sql"});
104+
setup_extension("hstore");
103105
}
104106

105107
void tempdb::check_tblspc() {
@@ -120,23 +122,98 @@ void tempdb::check_tblspc() {
120122

121123
}
122124

125+
void tempdb::check_count(int expected, const std::string &query) {
126+
pg::result_ptr res = m_conn->exec(query);
127+
if (PQresultStatus(res->get()) != PGRES_TUPLES_OK) {
128+
throw std::runtime_error((boost::format("Expected PGRES_TUPLES_OK but "
129+
"got %1%. %2% Query was %3%.")
130+
% PQresStatus(PQresultStatus(res->get()))
131+
% PQresultErrorMessage(res->get())
132+
% query).str());
133+
}
134+
int ntuples = PQntuples(res->get());
135+
if (ntuples != 1) {
136+
throw std::runtime_error((boost::format("Expected one tuple from a query to check "
137+
"COUNT(*), but got %1%. Query was: %2%.")
138+
% ntuples % query).str());
139+
}
140+
141+
std::string numstr = PQgetvalue(res->get(), 0, 0);
142+
int count = boost::lexical_cast<int>(numstr);
143+
144+
if (count != expected) {
145+
throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
146+
"query: %3%.")
147+
% expected % numstr % query).str());
148+
}
149+
}
150+
151+
void tempdb::check_number(double expected, const std::string &query) {
152+
pg::result_ptr res = m_conn->exec(query);
153+
154+
int ntuples = PQntuples(res->get());
155+
if (ntuples != 1) {
156+
throw std::runtime_error((boost::format("Expected only one tuple from a query, "
157+
" but got %1%. Query was: %2%.")
158+
% ntuples % query).str());
159+
}
160+
161+
std::string numstr = PQgetvalue(res->get(), 0, 0);
162+
double num = boost::lexical_cast<double>(numstr);
163+
164+
// floating point isn't exact, so allow a 0.01% difference
165+
if ((num > 1.0001*expected) || (num < 0.9999*expected)) {
166+
throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
167+
"query: %3%.")
168+
% expected % num % query).str());
169+
}
170+
}
171+
172+
void tempdb::check_string(const std::string &expected, const std::string &query) {
173+
pg::result_ptr res = m_conn->exec(query);
174+
175+
int ntuples = PQntuples(res->get());
176+
if (ntuples != 1) {
177+
throw std::runtime_error((boost::format("Expected only one tuple from a query, "
178+
" but got %1%. Query was: %2%.")
179+
% ntuples % query).str());
180+
}
181+
182+
std::string actual = PQgetvalue(res->get(), 0, 0);
183+
184+
if (actual != expected) {
185+
throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
186+
"query: %3%.")
187+
% expected % actual % query).str());
188+
}
189+
}
190+
191+
void tempdb::assert_has_table(const std::string &table_name) {
192+
std::string query = (boost::format("select count(*) from pg_catalog.pg_class "
193+
"where oid = '%1%'::regclass")
194+
% table_name).str();
195+
196+
check_count(1, query);
197+
}
198+
123199
tempdb::~tempdb() {
124-
if (m_conn) {
125-
m_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % database_options.db);
200+
m_conn.reset(); // close the connection to the db
201+
if (m_postgres_conn) {
202+
m_postgres_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % database_options.db);
126203
}
127204
}
128205

129-
void tempdb::setup_extension(conn_ptr db, const std::string &extension,
206+
void tempdb::setup_extension(const std::string &extension,
130207
const std::vector<std::string> &extension_files) {
131208
// first, try the new way of setting up extensions
132-
result_ptr res = db->exec(boost::format("CREATE EXTENSION %1%") % extension);
209+
result_ptr res = m_conn->exec(boost::format("CREATE EXTENSION %1%") % extension);
133210
if (PQresultStatus(res->get()) != PGRES_COMMAND_OK) {
134211
if (extension_files.size() == 0) {
135212
throw std::runtime_error((boost::format("Unable to load extension %1% and no files specified") % extension).str());
136213
}
137214
// if that fails, then fall back to trying to find the files on
138215
// the filesystem to load to create the extension.
139-
res = db->exec("select regexp_replace(split_part(version(),' ',2),'\\.[0-9]*$','');");
216+
res = m_conn->exec("select regexp_replace(split_part(version(),' ',2),'\\.[0-9]*$','');");
140217

141218
if ((PQresultStatus(res->get()) != PGRES_TUPLES_OK) ||
142219
(PQntuples(res->get()) != 1)) {
@@ -162,7 +239,7 @@ void tempdb::setup_extension(conn_ptr db, const std::string &extension,
162239
"load extension \"%2%\".")
163240
% sql_file % extension).str());
164241
}
165-
res = db->exec(sql);
242+
res = m_conn->exec(sql);
166243
if (PQresultStatus(res->get()) != PGRES_COMMAND_OK) {
167244
throw std::runtime_error((boost::format("Could not load extension \"%1%\": %2%")
168245
% extension

tests/common-pg.hpp

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,50 @@ struct tempdb
5959
database_options_t database_options;
6060

6161
void check_tblspc();
62+
/**
63+
* Checks the result of a query with COUNT(*).
64+
* It will work with any integer-returning query.
65+
* \param[in] expected expected result
66+
* \param[in] query SQL query to run. Must return one tuple.
67+
* \throws std::runtime_error if query result is not expected
68+
*/
69+
void check_count(int expected, const std::string &query);
70+
71+
/**
72+
* Checks a floating point number.
73+
* It allows a small variance around the expected result to allow for
74+
* floating point differences.
75+
* The query must only return one tuple
76+
* \param[in] expected expected result
77+
* \param[in] query SQL query to run. Must return one tuple.
78+
* \throws std::runtime_error if query result is not expected
79+
*/
80+
void check_number(double expected, const std::string &query);
81+
82+
/**
83+
* Check the string a query returns.
84+
* \param[in] expected expected result
85+
* \param[in] query SQL query to run. Must return one tuple.
86+
* \throws std::runtime_error if query result is not expected
87+
*/
88+
void check_string(const std::string &expected, const std::string &query);
89+
/**
90+
* Assert that the database has a certain table_name
91+
* \param[in] table_name Name of the table to check, optionally schema-qualified
92+
* \throws std::runtime_error if missing the table
93+
*/
94+
void assert_has_table(const std::string &table_name);
6295

6396
private:
64-
// Sets up an extension, trying first with 9.1 CREATE EXTENSION, and falling back to trying to find extension_files
65-
void setup_extension(conn_ptr db, const std::string &extension, const std::vector<std::string> &extension_files = std::vector<std::string>());
66-
67-
conn_ptr m_conn;
97+
/**
98+
* Sets up an extension, trying first with 9.1 CREATE EXTENSION, and falling
99+
* back to trying to find extension_files. The fallback is not likely to
100+
* work on systems not based on Debian.
101+
*/
102+
void setup_extension(const std::string &extension, const std::vector<std::string> &extension_files = std::vector<std::string>());
103+
104+
conn_ptr m_conn; ///< connection to the test DB
105+
conn_ptr m_postgres_conn; ///< Connection to the "postgres" db, used to create and drop test DBs
68106
};
69107

70108
} // namespace pg

tests/test-hstore-match-only.cpp

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,36 +24,13 @@ The tags of inteest are specified in hstore-match-only.style
2424
#include "taginfo_impl.hpp"
2525
#include "parse.hpp"
2626

27-
#include <libpq-fe.h>
2827
#include <sys/types.h>
2928
#include <unistd.h>
3029

3130
#include <boost/lexical_cast.hpp>
3231

3332
#include "tests/common-pg.hpp"
3433

35-
36-
void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
37-
pg::result_ptr res = conn->exec(query);
38-
39-
int ntuples = PQntuples(res->get());
40-
if (ntuples != 1) {
41-
throw std::runtime_error((boost::format("Expected only one tuple from a query "
42-
"to check COUNT(*), but got %1%. Query "
43-
"was: %2%.")
44-
% ntuples % query).str());
45-
}
46-
47-
std::string numstr = PQgetvalue(res->get(), 0, 0);
48-
int count = boost::lexical_cast<int>(numstr);
49-
50-
if (count != expected) {
51-
throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
52-
"query: %3%.")
53-
% expected % count % query).str());
54-
}
55-
}
56-
5734
int main(int argc, char *argv[]) {
5835
std::unique_ptr<pg::tempdb> db;
5936

@@ -89,14 +66,11 @@ int main(int argc, char *argv[]) {
8966

9067
osmdata.stop();
9168

92-
// start a new connection to run tests on
93-
pg::conn_ptr test_conn = pg::conn::connect(db->database_options);
94-
9569
// tables should not contain any tag columns
96-
check_count(test_conn, 4, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_point'");
97-
check_count(test_conn, 5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_polygon'");
98-
check_count(test_conn, 5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_line'");
99-
check_count(test_conn, 5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_roads'");
70+
db->check_count(4, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_point'");
71+
db->check_count(5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_polygon'");
72+
db->check_count(5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_line'");
73+
db->check_count(5, "select count(column_name) from information_schema.columns where table_name='osm2pgsql_test_roads'");
10074

10175
// the testfile contains 19 tagged ways and 7 tagged nodes
10276
// out of them 18 ways and 6 nodes are interesting as specified by hstore-match-only.style
@@ -106,10 +80,10 @@ int main(int argc, char *argv[]) {
10680
// 12 objects in osm2pgsql_test_line
10781
// 3 objects in osm2pgsql_test_roads
10882

109-
check_count(test_conn, 6, "select count(*) from osm2pgsql_test_point");
110-
check_count(test_conn, 7, "select count(*) from osm2pgsql_test_polygon");
111-
check_count(test_conn, 12, "select count(*) from osm2pgsql_test_line");
112-
check_count(test_conn, 3, "select count(*) from osm2pgsql_test_roads");
83+
db->check_count(6, "select count(*) from osm2pgsql_test_point");
84+
db->check_count(7, "select count(*) from osm2pgsql_test_polygon");
85+
db->check_count(12, "select count(*) from osm2pgsql_test_line");
86+
db->check_count(3, "select count(*) from osm2pgsql_test_roads");
11387

11488
return 0;
11589

tests/test-middle-flat.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "options.hpp"
1313
#include "middle-pgsql.hpp"
1414

15-
#include <libpq-fe.h>
1615
#include <sys/types.h>
1716
#include <unistd.h>
1817

tests/test-middle-pgsql.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
#include "options.hpp"
1313
#include "middle-pgsql.hpp"
1414

15-
#include <libpq-fe.h>
1615
#include <sys/types.h>
1716
#include <unistd.h>
1817

tests/test-output-multi-line-storage.cpp

Lines changed: 6 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include "taginfo_impl.hpp"
1616
#include "parse.hpp"
1717

18-
#include <libpq-fe.h>
1918
#include <sys/types.h>
2019
#include <unistd.h>
2120

@@ -24,27 +23,6 @@
2423
#include "tests/middle-tests.hpp"
2524
#include "tests/common-pg.hpp"
2625

27-
void check_count(pg::conn_ptr &conn, int expected, const std::string &query) {
28-
pg::result_ptr res = conn->exec(query);
29-
30-
int ntuples = PQntuples(res->get());
31-
if (ntuples != 1) {
32-
throw std::runtime_error((boost::format("Expected only one tuple from a query "
33-
"to check COUNT(*), but got %1%. Query "
34-
"was: %2%.")
35-
% ntuples % query).str());
36-
}
37-
38-
std::string numstr = PQgetvalue(res->get(), 0, 0);
39-
int count = boost::lexical_cast<int>(numstr);
40-
41-
if (count != expected) {
42-
throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running "
43-
"query: %3%.")
44-
% expected % count % query).str());
45-
}
46-
}
47-
4826
int main(int argc, char *argv[]) {
4927
std::unique_ptr<pg::tempdb> db;
5028

@@ -84,18 +62,15 @@ int main(int argc, char *argv[]) {
8462

8563
osmdata.stop();
8664

87-
// start a new connection to run tests on
88-
pg::conn_ptr test_conn = pg::conn::connect(db->database_options);
89-
90-
check_count(test_conn, 1, "select count(*) from pg_catalog.pg_class where relname = 'test_line'");
91-
check_count(test_conn, 3, "select count(*) from test_line");
65+
db->check_count(1, "select count(*) from pg_catalog.pg_class where relname = 'test_line'");
66+
db->check_count(3, "select count(*) from test_line");
9267

9368
//check that we have the number of vertexes in each linestring
94-
check_count(test_conn, 3, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 1");
95-
check_count(test_conn, 2, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 2");
96-
check_count(test_conn, 2, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 3");
69+
db->check_count(3, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 1");
70+
db->check_count(2, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 2");
71+
db->check_count(2, "SELECT ST_NumPoints(way) FROM test_line WHERE osm_id = 3");
9772

98-
check_count(test_conn, 3, "SELECT COUNT(*) FROM test_line WHERE foo = 'bar'");
73+
db->check_count(3, "SELECT COUNT(*) FROM test_line WHERE foo = 'bar'");
9974
return 0;
10075

10176
} catch (const std::exception &e) {

0 commit comments

Comments
 (0)