diff --git a/.gitignore b/.gitignore index 134c50eba..8601499e6 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ tests/test-output-multi-point-multi-table tests/test-output-multi-polygon tests/test-output-multi-poly-trivial tests/test-output-pgsql +tests/test-output-pgsql-tablespace tests/test-expire-tiles tests/*.log tests/*.trs diff --git a/Makefile.am b/Makefile.am index be7934805..3a888a00a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,6 +58,7 @@ check_PROGRAMS = \ tests/test-output-multi-polygon \ tests/test-output-multi-poly-trivial \ tests/test-output-pgsql \ + tests/test-output-pgsql-tablespace \ tests/test-pgsql-escape \ tests/test-parse-options \ tests/test-expire-tiles @@ -84,6 +85,8 @@ tests_test_output_multi_poly_trivial_SOURCES = tests/test-output-multi-poly-triv tests_test_output_multi_poly_trivial_LDADD = libosm2pgsql.la tests_test_output_pgsql_SOURCES = tests/test-output-pgsql.cpp tests/common-pg.cpp tests_test_output_pgsql_LDADD = libosm2pgsql.la +tests_test_output_pgsql_tablespace_SOURCES = tests/test-output-pgsql-tablespace.cpp tests/common-pg.cpp +tests_test_output_pgsql_tablespace_LDADD = libosm2pgsql.la tests_test_pgsql_escape_SOURCES = tests/test-pgsql-escape.cpp tests_test_pgsql_escape_LDADD = libosm2pgsql.la tests_test_parse_options_SOURCES = tests/test-parse-options.cpp @@ -145,6 +148,7 @@ tests_test_output_multi_point_multi_table_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_multi_polygon_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_multi_poly_trivial_LDADD += $(GLOBAL_LDFLAGS) tests_test_output_pgsql_LDADD += $(GLOBAL_LDFLAGS) +tests_test_output_pgsql_tablespace_LDADD += $(GLOBAL_LDFLAGS) tests_test_pgsql_escape_LDADD += $(GLOBAL_LDFLAGS) tests_test_parse_options_LDADD += $(GLOBAL_LDFLAGS) tests_test_expire_tiles_LDADD += $(GLOBAL_LDFLAGS) diff --git a/tests/common-pg.cpp b/tests/common-pg.cpp index 48f5633a6..19d7e815d 100644 --- a/tests/common-pg.cpp +++ b/tests/common-pg.cpp @@ -75,22 +75,7 @@ result::~result() { tempdb::tempdb() : m_conn(conn::connect("dbname=postgres")) { - result_ptr res = m_conn->exec("SELECT spcname FROM pg_tablespace WHERE " - "spcname = 'tablespacetest'"); - - if ((PQresultStatus(res->get()) != PGRES_TUPLES_OK) || - (PQntuples(res->get()) != 1)) { - std::ostringstream out; - out << "The test needs a temporary tablespace to run in, but it does not " - << "exist. Please create the temporary tablespace. On Linux, you can " - << "do this by running:\n" - << " sudo mkdir -p /tmp/psql-tablespace\n" - << " sudo /bin/chown postgres.postgres /tmp/psql-tablespace\n" - << " psql -c \"CREATE TABLESPACE tablespacetest LOCATION " - << "'/tmp/psql-tablespace'\" postgres\n"; - throw std::runtime_error(out.str()); - } - + result_ptr res = NULL; m_db_name = (boost::format("osm2pgsql-test-%1%-%2%") % getpid() % time(NULL)).str(); m_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % m_db_name); //tests can be run concurrently which means that this query can collide with other similar ones @@ -116,6 +101,24 @@ tempdb::tempdb() setup_extension(db, "hstore", NULL); } +void tempdb::check_tblspc() { + result_ptr res = m_conn->exec("SELECT spcname FROM pg_tablespace WHERE " + "spcname = 'tablespacetest'"); + if ((PQresultStatus(res->get()) != PGRES_TUPLES_OK) || + (PQntuples(res->get()) != 1)) { + std::ostringstream out; + out << "The test needs a temporary tablespace to run in, but it does not " + << "exist. Please create the temporary tablespace. On Linux, you can " + << "do this by running:\n" + << " sudo mkdir -p /tmp/psql-tablespace\n" + << " sudo /bin/chown postgres.postgres /tmp/psql-tablespace\n" + << " psql -c \"CREATE TABLESPACE tablespacetest LOCATION " + << "'/tmp/psql-tablespace'\" postgres\n"; + throw std::runtime_error(out.str()); + } + +} + tempdb::~tempdb() { if (m_conn) { m_conn->exec(boost::format("DROP DATABASE IF EXISTS \"%1%\"") % m_db_name); diff --git a/tests/common-pg.hpp b/tests/common-pg.hpp index bb3cb080f..faa28889f 100644 --- a/tests/common-pg.hpp +++ b/tests/common-pg.hpp @@ -56,6 +56,8 @@ struct tempdb const std::string &conninfo() const; + void check_tblspc(); + private: void setup_extension(conn_ptr db, const std::string &extension, ...); diff --git a/tests/test-output-multi-line.cpp b/tests/test-output-multi-line.cpp index cf5306770..fe6b60b71 100644 --- a/tests/test-output-multi-line.cpp +++ b/tests/test-output-multi-line.cpp @@ -61,8 +61,6 @@ int main(int argc, char *argv[]) { options_t options; options.conninfo = db->conninfo().c_str(); options.num_procs = 1; - options.tblsslim_index = "tablespacetest"; - options.tblsslim_data = "tablespacetest"; options.slim = 1; boost::shared_ptr processor = diff --git a/tests/test-output-multi-point-multi-table.cpp b/tests/test-output-multi-point-multi-table.cpp index d35f5bbf5..f76c14709 100644 --- a/tests/test-output-multi-point-multi-table.cpp +++ b/tests/test-output-multi-point-multi-table.cpp @@ -67,8 +67,6 @@ int main(int argc, char *argv[]) { options.conninfo = db->conninfo().c_str(); options.num_procs = 1; options.prefix = "osm2pgsql_test"; - options.tblsslim_index = "tablespacetest"; - options.tblsslim_data = "tablespacetest"; options.slim = 1; export_list columns; diff --git a/tests/test-output-multi-point.cpp b/tests/test-output-multi-point.cpp index 36e102a51..fe29481b7 100644 --- a/tests/test-output-multi-point.cpp +++ b/tests/test-output-multi-point.cpp @@ -62,8 +62,6 @@ int main(int argc, char *argv[]) { options.conninfo = db->conninfo().c_str(); options.num_procs = 1; options.prefix = "osm2pgsql_test"; - options.tblsslim_index = "tablespacetest"; - options.tblsslim_data = "tablespacetest"; options.slim = 1; boost::shared_ptr processor = diff --git a/tests/test-output-multi-polygon.cpp b/tests/test-output-multi-polygon.cpp index 38be79480..98370c664 100644 --- a/tests/test-output-multi-polygon.cpp +++ b/tests/test-output-multi-polygon.cpp @@ -62,8 +62,6 @@ int main(int argc, char *argv[]) { options.conninfo = db->conninfo().c_str(); options.num_procs = 1; options.prefix = "osm2pgsql_test"; - options.tblsslim_index = "tablespacetest"; - options.tblsslim_data = "tablespacetest"; options.slim = 1; boost::shared_ptr processor = geometry_processor::create("polygon", &options); diff --git a/tests/test-output-pgsql-tablespace.cpp b/tests/test-output-pgsql-tablespace.cpp new file mode 100755 index 000000000..3f752991e --- /dev/null +++ b/tests/test-output-pgsql-tablespace.cpp @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "osmtypes.hpp" +#include "osmdata.hpp" +#include "output-pgsql.hpp" +#include "options.hpp" +#include "middle-pgsql.hpp" +#include "middle-ram.hpp" +#include "taginfo_impl.hpp" +#include "parse.hpp" + +#include +#include +#include + +#include +#include + +#include "tests/middle-tests.hpp" +#include "tests/common-pg.hpp" + +namespace { + +struct skip_test : public std::exception { + const char *what() { return "Test skipped."; } +}; + +void run_test(const char* test_name, void (*testfunc)()) { + try { + fprintf(stderr, "%s\n", test_name); + testfunc(); + + } catch (const skip_test &) { + exit(77); // <-- code to skip this test. + + } catch (const std::exception& e) { + fprintf(stderr, "%s\n", e.what()); + fprintf(stderr, "FAIL\n"); + exit(EXIT_FAILURE); + } + + fprintf(stderr, "PASS\n"); +} +#define RUN_TEST(x) run_test(#x, &(x)) + +void check_count(pg::conn_ptr &conn, int expected, const std::string &query) { + pg::result_ptr res = conn->exec(query); + + int ntuples = PQntuples(res->get()); + if (ntuples != 1) { + throw std::runtime_error((boost::format("Expected only one tuple from a query " + "to check COUNT(*), but got %1%. Query " + "was: %2%.") + % ntuples % query).str()); + } + + std::string numstr = PQgetvalue(res->get(), 0, 0); + int count = boost::lexical_cast(numstr); + + if (count != expected) { + throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running " + "query: %3%.") + % expected % count % query).str()); + } +} + +void assert_has_table(pg::conn_ptr &test_conn, const std::string &table_name) { + std::string query = (boost::format("select count(*) from pg_catalog.pg_class " + "where relname = '%1%'") + % table_name).str(); + + check_count(test_conn, 1, query); +} + +// "simple" test modeled on the basic regression test from +// the python script. this is just to check everything is +// working as expected before we start the complex stuff. +void test_regression_simple() { + boost::scoped_ptr db; + + try { + db.reset(new pg::tempdb); + db->check_tblspc(); // Unlike others, these tests require a test tablespace + } catch (const std::exception &e) { + std::cerr << "Unable to setup database: " << e.what() << "\n"; + throw skip_test(); + } + + std::string proc_name("test-output-pgsql"), input_file("-"); + char *argv[] = { &proc_name[0], &input_file[0], NULL }; + + boost::shared_ptr mid_pgsql(new middle_pgsql_t()); + options_t options = options_t::parse(2, argv); + options.conninfo = db->conninfo().c_str(); + options.num_procs = 1; + options.prefix = "osm2pgsql_test"; + options.slim = 1; + options.style = "default.style"; + + options.tblsslim_index = "tablespacetest"; + options.tblsslim_data = "tablespacetest"; + + boost::shared_ptr out_test(new output_pgsql_t(mid_pgsql.get(), options)); + + osmdata_t osmdata(mid_pgsql, out_test); + + boost::scoped_ptr parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection)); + + osmdata.start(); + + if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) { + throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'."); + } + + parser.reset(NULL); + + osmdata.stop(); + + // start a new connection to run tests on + pg::conn_ptr test_conn = pg::conn::connect(db->conninfo()); + + assert_has_table(test_conn, "osm2pgsql_test_point"); + assert_has_table(test_conn, "osm2pgsql_test_line"); + assert_has_table(test_conn, "osm2pgsql_test_polygon"); + assert_has_table(test_conn, "osm2pgsql_test_roads"); + + check_count(test_conn, 1342, "SELECT count(*) FROM osm2pgsql_test_point"); + check_count(test_conn, 3300, "SELECT count(*) FROM osm2pgsql_test_line"); + check_count(test_conn, 375, "SELECT count(*) FROM osm2pgsql_test_roads"); + check_count(test_conn, 4128, "SELECT count(*) FROM osm2pgsql_test_polygon"); +} + +} // anonymous namespace + +int main(int argc, char *argv[]) { + RUN_TEST(test_regression_simple); + + return 0; +} diff --git a/tests/test-output-pgsql.cpp b/tests/test-output-pgsql.cpp index 42f490ae8..b7a4053a1 100644 --- a/tests/test-output-pgsql.cpp +++ b/tests/test-output-pgsql.cpp @@ -71,6 +71,27 @@ void check_count(pg::conn_ptr &conn, int expected, const std::string &query) { } } +void check_number(pg::conn_ptr &conn, double expected, const std::string &query) { + pg::result_ptr res = conn->exec(query); + + int ntuples = PQntuples(res->get()); + if (ntuples != 1) { + throw std::runtime_error((boost::format("Expected only one tuple from a query, " + " but got %1%. Query was: %2%.") + % ntuples % query).str()); + } + + std::string numstr = PQgetvalue(res->get(), 0, 0); + double num = boost::lexical_cast(numstr); + + // floating point isn't exact, so allow a 0.01% difference + if ((num > 1.0001*expected) || (num < 0.9999*expected)) { + throw std::runtime_error((boost::format("Expected %1%, but got %2%, when running " + "query: %3%.") + % expected % num % query).str()); + } +} + void assert_has_table(pg::conn_ptr &test_conn, const std::string &table_name) { std::string query = (boost::format("select count(*) from pg_catalog.pg_class " "where relname = '%1%'") @@ -100,8 +121,6 @@ void test_regression_simple() { options.conninfo = db->conninfo().c_str(); options.num_procs = 1; options.prefix = "osm2pgsql_test"; - options.tblsslim_index = "tablespacetest"; - options.tblsslim_data = "tablespacetest"; options.slim = 1; options.style = "default.style"; @@ -133,8 +152,85 @@ void test_regression_simple() { check_count(test_conn, 3300, "SELECT count(*) FROM osm2pgsql_test_line"); check_count(test_conn, 375, "SELECT count(*) FROM osm2pgsql_test_roads"); check_count(test_conn, 4128, "SELECT count(*) FROM osm2pgsql_test_polygon"); + + // Check size of lines + check_number(test_conn, 1696.04, "SELECT ST_Length(way) FROM osm2pgsql_test_line WHERE osm_id = 44822682"); + check_number(test_conn, 1151.26, "SELECT ST_Length(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_line WHERE osm_id = 44822682"); + + check_number(test_conn, 311.21, "SELECT way_area FROM osm2pgsql_test_polygon WHERE osm_id = 157261342"); + check_number(test_conn, 311.21, "SELECT ST_Area(way) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342"); + check_number(test_conn, 143.81, "SELECT ST_Area(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342"); + + // Check a point's location + check_count(test_conn, 1, "SELECT count(*) FROM osm2pgsql_test_point WHERE ST_DWithin(way, 'SRID=900913;POINT(1062645.12 5972593.4)'::geometry, 0.1)"); +} + +void test_latlong() { + boost::scoped_ptr db; + + try { + db.reset(new pg::tempdb); + } catch (const std::exception &e) { + std::cerr << "Unable to setup database: " << e.what() << "\n"; + throw skip_test(); + } + + std::string proc_name("test-output-pgsql"), input_file("-"); + char *argv[] = { &proc_name[0], &input_file[0], NULL }; + + boost::shared_ptr mid_pgsql(new middle_pgsql_t()); + options_t options = options_t::parse(2, argv); + options.conninfo = db->conninfo().c_str(); + options.num_procs = 1; + options.prefix = "osm2pgsql_test"; + options.slim = 1; + options.style = "default.style"; + + options.projection.reset(new reprojection(PROJ_LATLONG)); + options.scale = (options.projection->get_proj_id() == PROJ_LATLONG) ? 10000000 : 100; + + boost::shared_ptr out_test(new output_pgsql_t(mid_pgsql.get(), options)); + + osmdata_t osmdata(mid_pgsql, out_test); + + boost::scoped_ptr parser(new parse_delegate_t(options.extra_attributes, options.bbox, options.projection)); + + osmdata.start(); + + if (parser->streamFile("pbf", "tests/liechtenstein-2013-08-03.osm.pbf", options.sanitize, &osmdata) != 0) { + throw std::runtime_error("Unable to read input file `tests/liechtenstein-2013-08-03.osm.pbf'."); + } + + parser.reset(NULL); + + osmdata.stop(); + + // start a new connection to run tests on + pg::conn_ptr test_conn = pg::conn::connect(db->conninfo()); + + assert_has_table(test_conn, "osm2pgsql_test_point"); + assert_has_table(test_conn, "osm2pgsql_test_line"); + assert_has_table(test_conn, "osm2pgsql_test_polygon"); + assert_has_table(test_conn, "osm2pgsql_test_roads"); + + check_count(test_conn, 1342, "SELECT count(*) FROM osm2pgsql_test_point"); + check_count(test_conn, 3298, "SELECT count(*) FROM osm2pgsql_test_line"); + check_count(test_conn, 374, "SELECT count(*) FROM osm2pgsql_test_roads"); + check_count(test_conn, 4128, "SELECT count(*) FROM osm2pgsql_test_polygon"); + + // Check size of lines + check_number(test_conn, 0.0105343, "SELECT ST_Length(way) FROM osm2pgsql_test_line WHERE osm_id = 44822682"); + check_number(test_conn, 1151.26, "SELECT ST_Length(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_line WHERE osm_id = 44822682"); + + check_number(test_conn, 1.70718e-08, "SELECT way_area FROM osm2pgsql_test_polygon WHERE osm_id = 157261342"); + check_number(test_conn, 1.70718e-08, "SELECT ST_Area(way) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342"); + check_number(test_conn, 143.845, "SELECT ST_Area(ST_Transform(way,4326)::geography) FROM osm2pgsql_test_polygon WHERE osm_id = 157261342"); + + // Check a point's location + check_count(test_conn, 1, "SELECT count(*) FROM osm2pgsql_test_point WHERE ST_DWithin(way, 'SRID=4326;POINT(9.5459035 47.1866494)'::geometry, 0.00001)"); } + void test_area_way_simple() { boost::scoped_ptr db; @@ -259,8 +355,6 @@ void test_clone() { options.conninfo = db->conninfo().c_str(); options.num_procs = 1; options.prefix = "osm2pgsql_test"; - options.tblsslim_index = "tablespacetest"; - options.tblsslim_data = "tablespacetest"; options.slim = 1; options.style = "default.style"; @@ -302,6 +396,7 @@ void test_clone() { int main(int argc, char *argv[]) { RUN_TEST(test_regression_simple); + RUN_TEST(test_latlong); RUN_TEST(test_clone); RUN_TEST(test_area_way_simple); RUN_TEST(test_route_rel);