diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index adbd2ff54..f1a35a1e7 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -24,7 +24,7 @@ ExternalProject_Add( include_directories(SYSTEM ${CMAKE_CURRENT_BINARY_DIR}/include) # enable a bunch of warnings and make them errors -target_compile_options(ozo_benchmark PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror) +target_compile_options(ozo_benchmark PRIVATE -Wall -Wextra -Wsign-compare -Werror) # ignore specific error for clang if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") @@ -37,7 +37,7 @@ target_link_libraries(ozo_benchmark_performance ozo) target_link_libraries(ozo_benchmark_performance Boost::program_options) # enable a bunch of warnings and make them errors -target_compile_options(ozo_benchmark_performance PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror) +target_compile_options(ozo_benchmark_performance PRIVATE -Wall -Wextra -Wsign-compare -Werror) # ignore specific error for clang if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") diff --git a/docker-compose.yml b/docker-compose.yml index c92d7ba17..21433488c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,8 +29,10 @@ services: POSTGRES_DB: *POSTGRES_DB POSTGRES_USER: *POSTGRES_USER POSTGRES_PASSWORD: *POSTGRES_PASSWORD + PROXY_HOST: ozo_proxy depends_on: - ozo_postgres + - ozo_proxy volumes: - ~/.ccache:/ccache - .:/code @@ -64,5 +66,17 @@ services: - .:/code networks: - ozo + ozo_proxy: + build: docker/proxy + image: ozo_proxy + privileged: true + environment: + POSTGRES_HOST: ozo_postgres + depends_on: + - ozo_postgres + volumes: + - .:/code + networks: + - ozo networks: ozo: {} diff --git a/docker/proxy/Dockerfile b/docker/proxy/Dockerfile new file mode 100644 index 000000000..8d34ffe46 --- /dev/null +++ b/docker/proxy/Dockerfile @@ -0,0 +1,16 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install -y \ + iptables \ + simpleproxy \ + && \ + rm -rf /var/lib/apt/lists/* + +VOLUME /code + +WORKDIR /code + +EXPOSE 5432 + +ENTRYPOINT scripts/run_proxy.sh diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index cd1acd349..017022584 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -5,22 +5,22 @@ if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) endif() -add_executable(ozo_request request.cpp) -target_link_libraries(ozo_request ozo) +add_executable(ozo_request_coroutine request_coroutine.cpp) +target_link_libraries(ozo_request_coroutine ozo) # enable a bunch of warnings and make them errors -target_compile_options(ozo_request PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror) +target_compile_options(ozo_request_coroutine PRIVATE -Wall -Wextra -Wsign-compare -Werror) # ignore specific errors for clang if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - target_compile_options(ozo_request PRIVATE -Wno-ignored-optimization-argument) + target_compile_options(ozo_request_coroutine PRIVATE -Wno-ignored-optimization-argument) endif() add_executable(ozo_transaction transaction.cpp) target_link_libraries(ozo_transaction ozo) # enable a bunch of warnings and make them errors -target_compile_options(ozo_transaction PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror) +target_compile_options(ozo_transaction PRIVATE -Wall -Wextra -Wsign-compare -Werror) # ignore specific errors for clang if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") @@ -31,7 +31,7 @@ add_executable(ozo_retry_request retry_request.cpp) target_link_libraries(ozo_retry_request ozo) # enable a bunch of warnings and make them errors -target_compile_options(ozo_retry_request PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror) +target_compile_options(ozo_retry_request PRIVATE -Wall -Wextra -Wsign-compare -Werror) # ignore specific errors for clang if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") @@ -42,7 +42,7 @@ add_executable(ozo_role_based_request role_based_request.cpp) target_link_libraries(ozo_role_based_request ozo) # enable a bunch of warnings and make them errors -target_compile_options(ozo_role_based_request PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror) +target_compile_options(ozo_role_based_request PRIVATE -Wall -Wextra -Wsign-compare -Werror) # ignore specific errors for clang if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") @@ -53,9 +53,53 @@ add_executable(ozo_connection_pool connection_pool.cpp) target_link_libraries(ozo_connection_pool ozo) # enable a bunch of warnings and make them errors -target_compile_options(ozo_connection_pool PRIVATE -Wall -Wextra -Wsign-compare -pedantic -Werror) +target_compile_options(ozo_connection_pool PRIVATE -Wall -Wextra -Wsign-compare -Werror) # ignore specific errors for clang if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") target_compile_options(ozo_connection_pool PRIVATE -Wno-ignored-optimization-argument) endif() + +add_executable(ozo_request_future request_future.cpp) +target_link_libraries(ozo_request_future ozo) + +# enable a bunch of warnings and make them errors +target_compile_options(ozo_request_future PRIVATE -Wall -Wextra -Wsign-compare -Werror) + +# ignore specific errors for clang +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + target_compile_options(ozo_request_future PRIVATE -Wno-ignored-optimization-argument) +endif() + +add_executable(ozo_request_callback request_callback.cpp) +target_link_libraries(ozo_request_callback ozo) + +# enable a bunch of warnings and make them errors +target_compile_options(ozo_request_callback PRIVATE -Wall -Wextra -Wsign-compare -Werror) + +# ignore specific errors for clang +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + target_compile_options(ozo_request_callback PRIVATE -Wno-ignored-optimization-argument) +endif() + +add_executable(ozo_retry_request_pool retry_request_pool.cpp) +target_link_libraries(ozo_retry_request_pool ozo) + +# enable a bunch of warnings and make them errors +target_compile_options(ozo_retry_request_pool PRIVATE -Wall -Wextra -Wsign-compare -Werror) + +# ignore specific errors for clang +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + target_compile_options(ozo_retry_request_pool PRIVATE -Wno-ignored-optimization-argument) +endif() + +add_executable(ozo_composite_types composite_types.cpp) +target_link_libraries(ozo_composite_types ozo) + +# enable a bunch of warnings and make them errors +target_compile_options(ozo_composite_types PRIVATE -Wall -Wextra -Wsign-compare -Werror) + +# ignore specific errors for clang +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + target_compile_options(ozo_composite_types PRIVATE -Wno-ignored-optimization-argument) +endif() diff --git a/examples/composite_types.cpp b/examples/composite_types.cpp new file mode 100644 index 000000000..295ee4510 --- /dev/null +++ b/examples/composite_types.cpp @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace asio = boost::asio; +namespace hana = boost::hana; + +struct attach { + std::string filename; + std::string type; + std::int64_t size; +}; + +BOOST_HANA_ADAPT_STRUCT(attach, filename, type, size); +BOOST_FUSION_ADAPT_STRUCT(attach, filename, type, size) + +OZO_PG_DEFINE_CUSTOM_TYPE(attach, "ozo_test.attach") +OZO_PG_DEFINE_CUSTOM_TYPE(std::vector, "ozo_test.attach[]") + +const auto throw_if_error = [](ozo::error_code ec, const auto& conn) { + if (ec) { + std::ostringstream s; + if (!ozo::is_null_recursive(conn)) { + s << "libpq error message: \"" << ozo::error_message(conn) + << "\", error context: \"" << ozo::get_error_context(conn) << "\""; + } + throw ozo::system_error(ec, s.str()); + } +}; + +std::ostream& operator <<(std::ostream& stream, const attach& value) { + stream << "attach {"; + hana::for_each(hana::members(value), [&] (const auto& v) { stream << v << ", "; }); + return stream << "}"; +} + +template +std::ostream& operator <<(std::ostream& stream, const std::vector& value) { + stream << "{"; + boost::for_each(value, [&] (const auto& v) { stream << v << ", "; }); + return stream << "}"; +} + +template +std::ostream& operator <<(std::ostream& stream, const hana::tuple ...>& value) { + stream << "{"; + hana::for_each(value, [&] (const auto& v) { stream << v.get() << ", "; }); + return stream << "}"; +} + +template +std::ostream& operator <<(std::ostream& stream, const hana::tuple& value) { + stream << "{"; + hana::for_each(value, [&] (const auto& v) { stream << v << ", "; }); + return stream << "}"; +} + +template +std::ostream& operator <<(std::ostream& stream, const std::tuple& value) { + stream << "{"; + hana::for_each(value, [&] (const auto& v) { stream << v << ", "; }); + return stream << "}"; +} + +template +void create_database(T initiator, asio::yield_context yield) { + using namespace ozo::literals; + using namespace std::chrono_literals; + + constexpr auto init_queries = hana::make_tuple( + "DROP SCHEMA IF EXISTS ozo_test CASCADE;"_SQL, + "CREATE SCHEMA ozo_test;"_SQL, + "CREATE TYPE ozo_test.attach AS (filename text, type text, size bigint);"_SQL, + "CREATE TABLE ozo_test.messages (uid bigint, mid bigint, attaches ozo_test.attach[]);"_SQL + ); + + hana::for_each(init_queries, [&] (const auto& query_builder) { + const auto query = query_builder.build(); + + std::cout << "Perform request with query: " << ozo::to_const_char(ozo::get_text(query)) << std::endl; + + ozo::error_code ec; + const auto connection = ozo::execute(initiator, query, 3s, yield[ec]); + throw_if_error(ec, connection); + }); +} + +template +T fill_database(T&& transaction, asio::yield_context yield) { + using namespace ozo::literals; + using namespace std::chrono_literals; + + std::int64_t uid = 0; + std::int64_t mid = 0; + std::vector attaches; + const auto query_builder = "INSERT INTO ozo_test.messages (uid, mid, attaches) VALUES ("_SQL + + std::cref(uid) + ", "_SQL + std::cref(mid) + ", "_SQL + std::cref(attaches) + ")"_SQL; + + const auto values = { + std::make_tuple(std::int64_t(1), std::int64_t(1), std::vector({})), + std::make_tuple(std::int64_t(1), std::int64_t(2), std::vector({ + attach {"foo.jpeg", "image/jpeg", 13124} + })), + std::make_tuple(std::int64_t(1), std::int64_t(3), std::vector({ + attach {"report.txt", "text/plain", 5344}, + attach {"doc.txt", "text/plain", 3434} + })), + std::make_tuple(std::int64_t(2), std::int64_t(1), std::vector({})), + std::make_tuple(std::int64_t(2), std::int64_t(2), std::vector({})), + }; + + boost::for_each(values, [&] (const auto& value) { + ozo::error_code ec; + std::tie(uid, mid, attaches) = value; + const auto query = query_builder.build(); + std::cout << "Perform request with query: " << ozo::to_const_char(ozo::get_text(query)) + << ", params: " << ozo::get_params(query) + << std::endl; + transaction = ozo::execute(std::move(transaction), query, 3s, yield[ec]); + throw_if_error(ec, transaction); + }); + + return std::move(transaction); +} + +template +T query_database(T&& transaction, asio::yield_context yield) { + using namespace ozo::literals; + using namespace std::chrono_literals; + + const auto query = ( + "SELECT mid, attaches "_SQL + + "FROM ozo_test.messages "_SQL + + "WHERE uid = "_SQL + std::int64_t(1) + + " AND mid = ANY("_SQL + std::vector({2, 3}) + ")"_SQL + ).build(); + + ozo::rows_of> result; + ozo::error_code ec; + std::cout << "Perform request with query: " << ozo::to_const_char(ozo::get_text(query)) + << ", params: " << ozo::get_params(query) + << std::endl; + ozo::request(transaction, query, 3s, std::back_inserter(result), yield[ec]); + throw_if_error(ec, transaction); + + std::cout << "Selected attaches:" << std::endl; + boost::for_each(result, [&] (const auto& v) { + std::cout << std::get<0>(v) << ", " << std::get<1>(v) << std::endl; + }); + + return std::move(transaction); +} + +int main(int argc, char **argv) { + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + asio::io_context io; + asio::spawn(io, [&] (asio::yield_context yield) { + using namespace ozo::literals; + using namespace std::chrono_literals; + + try { + create_database(ozo::connection_info(argv[1])[io], yield); + + const auto oid_map = ozo::register_types>(); + ozo::connection_info connection_info(argv[1], oid_map); + ozo::error_code ec; + auto transaction = ozo::begin(connection_info[io], 3s, yield[ec]); + throw_if_error(ec, transaction); + + transaction = fill_database(std::move(transaction), yield); + transaction = query_database(std::move(transaction), yield); + + const auto connection = ozo::rollback(std::move(transaction), 3s, yield[ec]); + throw_if_error(ec, connection); + } catch (const std::exception& e) { + std::cout << e.what() << std::endl; + } + }); + + io.run(); + + return 0; +} diff --git a/examples/request_callback.cpp b/examples/request_callback.cpp new file mode 100644 index 000000000..cb3d86e7b --- /dev/null +++ b/examples/request_callback.cpp @@ -0,0 +1,72 @@ +#include +#include +#include + +#include + +#include + +namespace asio = boost::asio; + +int main(int argc, char **argv) { + std::cout << "OZO request example" << std::endl; + + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + // Ozo perform all IO using Boost.Asio, so first thing we need to do is setup asio::io_context + asio::io_context io; + + // To make a request we need to make a ConnectionSource. It knows how to connect to database using + // connection string. See https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING + // how to make a connection string. + auto conn_info = ozo::connection_info(argv[1]); + + // Request result is always set of rows. Client should take care of output object lifetime. + auto result = std::make_unique>(); + + // First we take a reference to result to be able move unique_ptr to callback context. + const auto result_ref = ozo::into(*result); + + // All IO is asynchronous, therefore we need to define a CompletionToken. + // We use callback function that will be called after operation is finished. + auto callback = [result = std::move(result)] (ozo::error_code ec, auto connection) { + // When request is completed we check whether there is an error. This example should not produce any errors + // if there are no problems with target database, network or permissions for given user in connection + // string. + if (ec) { + std::cout << "Request failed with error: " << ec.message(); + // Here we should check if the connection is in null state to avoid UB. + if (!ozo::is_null_recursive(connection)) { + // Then check for libpq native error message and print if it's there + if (auto msg = ozo::error_message(connection); !msg.empty()) { + std::cout << ", error message: " << msg; + } + // Sometimes libpq native error message is not enough, so let's check + // the additional error context from OZO + if (auto ctx = ozo::get_error_context(connection); !ctx.empty()) { + std::cout << ", error context: " << ctx; + } + } + std::cout << std::endl; + return; + } + + // Just print request result + std::cout << "Selected:" << std::endl; + for (auto value : *result) { + std::cout << std::get<0>(value) << std::endl; + } + }; + + // This allows to use _SQL literals + using namespace ozo::literals; + using namespace std::chrono_literals; + ozo::request(conn_info[io], "SELECT 1"_SQL, 1s, result_ref, asio::bind_executor(io, std::move(callback))); + + io.run(); + + return 0; +} diff --git a/examples/request.cpp b/examples/request_coroutine.cpp similarity index 100% rename from examples/request.cpp rename to examples/request_coroutine.cpp diff --git a/examples/request_future.cpp b/examples/request_future.cpp new file mode 100644 index 000000000..8d9471ad4 --- /dev/null +++ b/examples/request_future.cpp @@ -0,0 +1,69 @@ +#include +#include +#include + +#include +#include + +#include +#include + +namespace asio = boost::asio; + +int main(int argc, char **argv) { + std::cout << "OZO request example" << std::endl; + + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + // Ozo perform all IO using Boost.Asio, so first thing we need to do is setup asio::io_context + asio::io_context io; + + // To make a request we need to make a ConnectionSource. It knows how to connect to database using + // connection string. See https://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-CONNSTRING + // how to make a connection string. + auto conn_info = ozo::connection_info(argv[1]); + + // All IO is asynchronous, therefore we need to define a CompletionToken. We use boost::asio::use_future. + // To make this example more real all asynchronous operation will be performed in a separate thread. + // Work guard will help to keep io_context running until we decide to stop it. + boost::asio::executor_work_guard guard = boost::asio::make_work_guard(io); + std::thread worker([&io] { + io.run(); + }); + + // Request result is always a set of rows. Client should take care of output object lifetime. + ozo::rows_of result; + + // This allows to use _SQL literals + using namespace ozo::literals; + using namespace std::chrono_literals; + auto connection = ozo::request(conn_info[io], "SELECT 1"_SQL, 1s, ozo::into(result), asio::use_future); + + // When request is completed we check whether there is an exception. This example should not produce any errors + // if there are no problems with target database, network or permissions for given user in the connection + // string. + try { + // Here we wait until asynchronous operation in a different thread is finished. If any error is occured + // an exception will be thrown. Boost only provides static error code message without any additional context. + connection.get(); + + // Just print request result + std::cout << "Selected:" << std::endl; + for (auto value : result) { + std::cout << std::get<0>(value) << std::endl; + } + } catch (const std::exception& error) { + std::cout << "Request failed with error: " << error.what(); + } + + // Reset work guard to release io and make it able to stop. + guard.reset(); + + // Make sure thread is finished. + worker.join(); + + return 0; +} diff --git a/examples/retry_request_pool.cpp b/examples/retry_request_pool.cpp new file mode 100644 index 000000000..c7e5c61b7 --- /dev/null +++ b/examples/retry_request_pool.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace asio = boost::asio; + +template +void print_error(ozo::error_code ec, const Conn& conn) { + std::cout << "error code message: \"" << ec.message(); + // Here we should check if the connection is in null state to avoid UB. + if (!ozo::is_null_recursive(conn)) { + std::cout << "\", libpq error message: \"" << ozo::error_message(conn) + << "\", error context: \"" << ozo::get_error_context(conn); + } + std::cout << "\"" << std::endl; +} + +const auto retry_error = [](ozo::error_code ec, const auto& conn) { + std::cout << "Retry failed; "; + print_error(ec, conn); +}; + +int main(int argc, char **argv) { + using namespace std::chrono_literals; + + std::cout << "OZO retry request with connection pool example" << std::endl; + + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + asio::io_context io; + + auto conn_info = ozo::connection_info(argv[1]); + + ozo::connection_pool_config conn_pool_config; + + // Maximum limit for number of stored connections + conn_pool_config.capacity = 3; + // Maximum limit for number of waiting requests for connection + conn_pool_config.queue_capacity = 10; + // Maximum time duration to store unused open connection + conn_pool_config.idle_timeout = 1s; + // Maximum time duration to keep connection open + conn_pool_config.lifespan = 24h; + + // Creating connection pool from connection_info as the underlying ConnectionSource + ozo::connection_pool conn_pool(conn_info, conn_pool_config); + + // Use timer to add a pause between requests + asio::steady_timer timer(io); + + asio::spawn(io, [&] (asio::yield_context yield) { + const auto start = std::chrono::steady_clock::now(); + while (std::chrono::steady_clock::now() - start < 10s) { + const auto stats = conn_pool.stats(); + std::cout << "Connection pool stats: size=" << stats.size + << " available=" << stats.available << " used=" << stats.used << std::endl; + + ozo::rows_of result; + ozo::error_code ec; + using namespace ozo::literals; + using namespace std::chrono_literals; + namespace failover = ozo::failover; + using retry_options = failover::retry_options; + // Here we will retry operation no more than 3 times on connection errors + // Each try will have its own time constraint + // 1st try will be limited by 1/3 sec. + // 2nd try will be limited by (1 - t(1st try)) / 2 sec, which is not less than 1/3 sec. + // 3rd try will be limited by 1 - (t(1st try) + t(2nd try)), which is not less than 1/3 sec too. + auto retry = 3*failover::retry(ozo::errc::connection_error) + // We want to print out information about retries + .set(retry_options::on_retry = retry_error); + // Here a request call with retry fallback strategy + auto conn = ozo::request[retry](conn_pool[io], "SELECT 1"_SQL, 1s, ozo::into(result), yield[ec]); + + // When request is completed we check is there an error. + if (ec) { + std::cout << "Request failed; "; + print_error(ec, conn); + continue; + } + + // Just print request result + std::cout << "Selected:" << std::endl; + for (auto value : result) { + std::cout << std::get<0>(value) << std::endl; + } + + timer.expires_after(300ms); + timer.async_wait(yield[ec]); + } + }); + + io.run(); + + return 0; +} diff --git a/scripts/run_example.sh b/scripts/run_example.sh index 7a3a6312c..678052ec5 100755 --- a/scripts/run_example.sh +++ b/scripts/run_example.sh @@ -2,21 +2,39 @@ scripts/build.sh pg docker clang release -docker-compose up -d ozo_postgres +docker-compose up -d ozo_postgres ozo_proxy -docker-compose run \ - --rm \ - --user "$(id -u):$(id -g)" \ - ozo_build_with_pg_tests \ - bash \ - -exc '/code/scripts/wait_postgres.sh; ${BASE_BUILD_DIR}/clang_release/examples/ozo_request "host=${POSTGRES_HOST} user=${POSTGRES_USER} dbname=${POSTGRES_DB} password=${POSTGRES_PASSWORD}"' +function run_example { + BINARY="\${BASE_BUILD_DIR}/clang_release/examples/${1:?}" + CONN_INFO='"host=${POSTGRES_HOST:?} user=${POSTGRES_USER:?} dbname=${POSTGRES_DB:?} password=${POSTGRES_PASSWORD:?}"' + docker-compose run \ + --rm \ + --user "$(id -u):$(id -g)" \ + ozo_build_with_pg_tests \ + bash \ + -exc "/code/scripts/wait_postgres.sh; ${BINARY:?} ${CONN_INFO:?} ${CONN_INFO:?}" +} -docker-compose run \ - --rm \ - --user "$(id -u):$(id -g)" \ - ozo_build_with_pg_tests \ - bash \ - -exc '/code/scripts/wait_postgres.sh; ${BASE_BUILD_DIR}/clang_release/examples/ozo_connection_pool "host=${POSTGRES_HOST} user=${POSTGRES_USER} dbname=${POSTGRES_DB} password=${POSTGRES_PASSWORD}"' +function run_example_proxy { + BINARY="\${BASE_BUILD_DIR}/clang_release/examples/${1:?}" + CONN_INFO='"host=${PROXY_HOST:?} user=${POSTGRES_USER:?} dbname=${POSTGRES_DB:?} password=${POSTGRES_PASSWORD:?}"' + docker-compose run \ + --rm \ + --user "$(id -u):$(id -g)" \ + ozo_build_with_pg_tests \ + bash \ + -exc "/code/scripts/wait_proxy.sh; ${BINARY:?} ${CONN_INFO:?} ${CONN_INFO:?}" +} -docker-compose stop ozo_postgres -docker-compose rm -f ozo_postgres +run_example ozo_request_coroutine +run_example ozo_connection_pool +run_example ozo_retry_request +run_example ozo_role_based_request +run_example ozo_transaction +run_example ozo_request_future +run_example ozo_request_callback +run_example_proxy ozo_retry_request_pool +run_example ozo_composite_types + +docker-compose stop ozo_postgres ozo_proxy +docker-compose rm -f ozo_postgres ozo_proxy diff --git a/scripts/run_proxy.sh b/scripts/run_proxy.sh new file mode 100755 index 000000000..2252a990b --- /dev/null +++ b/scripts/run_proxy.sh @@ -0,0 +1,17 @@ +#!/bin/bash -e + +{ + iptables -t filter -A INPUT -p tcp --dport 5432 -j ACCEPT + while true; do + sleep 1 + iptables -t filter -R INPUT 1 -p tcp --dport 5432 -j DROP + sleep 2 + iptables -t filter -R INPUT 1 -p tcp --dport 5432 -j ACCEPT + sleep 1 + iptables -t filter -R INPUT 1 -p tcp --dport 5432 -j DROP + sleep 0.5 + iptables -t filter -R INPUT 1 -p tcp --dport 5432 -j ACCEPT + done +} & + +simpleproxy -L 5432 -R ${POSTGRES_HOST:?}:5432 diff --git a/scripts/wait_proxy.sh b/scripts/wait_proxy.sh new file mode 100755 index 000000000..916be78d1 --- /dev/null +++ b/scripts/wait_proxy.sh @@ -0,0 +1,6 @@ +#!/bin/bash -e + +while ! pg_isready -h ${PROXY_HOST:?} -p 5432 -U ${POSTGRES_USER:?}; do + echo "waiting until postgres at ${PROXY_HOST:?}:5432 is accepting connections..." + sleep 1 +done diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 170916bb3..31e280d5a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -88,7 +88,7 @@ if(CCACHE_FOUND) endif() # enable useful warnings and errors -target_compile_options(ozo_tests PRIVATE -Wall -Wextra -pedantic -Werror) +target_compile_options(ozo_tests PRIVATE -Wall -Wextra -Werror) # ignore specific errors for clang if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") diff --git a/tests/external_project/CMakeLists.txt b/tests/external_project/CMakeLists.txt index 04c263d98..b74bb03ea 100644 --- a/tests/external_project/CMakeLists.txt +++ b/tests/external_project/CMakeLists.txt @@ -2,6 +2,5 @@ cmake_minimum_required(VERSION 3.12) project(my_ozo_using_project) find_package(ozo REQUIRED) -add_executable(my_app ../../examples/request.cpp warning_option_propagation.cpp) -target_compile_options(my_app PRIVATE -Wall -Wextra -pedantic -Werror) +add_executable(my_app ../../examples/request_coroutine.cpp) target_link_libraries(my_app PRIVATE yandex::ozo)