-
-
Notifications
You must be signed in to change notification settings - Fork 8
Add PostgreSQL module #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
SapiensAnatis
wants to merge
3
commits into
testcontainers:main
Choose a base branch
from
SapiensAnatis:feature/postgres-module
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| cmake_minimum_required (VERSION 3.26) | ||
| project (postgresql-demo | ||
| VERSION 0.1.0 | ||
| DESCRIPTION "Demonstrates usage of the PostgreSQL module for Testcontainers C in a simple main app" | ||
| LANGUAGES C | ||
| ) | ||
|
|
||
| set(TARGET_OUT demo_postgresql_module.out) | ||
|
|
||
| include(FindPostgreSQL) | ||
|
|
||
| # v17: use a lower version of the client library as not many distros ship libpq v18.x. | ||
| # Client-server communication is fully backwards compatible unless we want to use new client features. | ||
| find_package(PostgreSQL 17) | ||
|
|
||
| if (${PostgreSQL_FOUND}) | ||
| add_executable(${TARGET_OUT} postgresql_module_demo.c) | ||
| target_link_libraries(${TARGET_OUT} PRIVATE testcontainers-c) | ||
| target_link_libraries(${TARGET_OUT} PRIVATE testcontainers-c-postgresql) | ||
| target_link_libraries(${TARGET_OUT} PRIVATE ${PostgreSQL_LIBRARIES}) | ||
| else() | ||
| message(WARNING "Could not find PostgreSQL client libraries. Skipping build of PostgreSQL demo. To fix this, try installing libpq and/or libpq-devel.") | ||
| endif() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Demo - WireMocPostgreSQLk on Testcontainers C | ||
|
|
||
| Demonstrates usage of the [PostgreSQL Module for Testcontainers C](../../modules/postgresql/README.md) in a simple main function. | ||
| No test framework is used here. | ||
|
|
||
| ## Running demo | ||
|
|
||
| First ensure `libpq` and/or `libpq-devel` is installed on your system - this is required to build the example. | ||
|
|
||
| From the root of the repository: | ||
|
|
||
| ```bash | ||
| cmake -B build/ | ||
| cmake --build build/ | ||
| ./build/demo/postgresql/demo_postgresql_module.out | ||
| ``` | ||
|
|
||
| The demo program will start a PostgreSQL container, use `libpq` to connect to it, and then terminate the container. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| #include <stdlib.h> | ||
| #include <stdio.h> | ||
| #include <string.h> | ||
|
|
||
| #include <testcontainers-c-postgresql.h> | ||
| #include <testcontainers-c/container.h> | ||
|
|
||
| #include <libpq-fe.h> | ||
|
|
||
| static const char* postgresqlImage = "postgres:18.1"; | ||
|
|
||
| int main() { | ||
| printf("Creating new PostgreSQL container. Using image: %s\n", postgresqlImage); | ||
| int requestId = tc_psql_new_container(postgresqlImage); | ||
|
|
||
| char* error; | ||
| int containerId = tc_container_run(requestId, error); | ||
|
|
||
| if (containerId == -1) { | ||
| fprintf(stderr, "Failed to run the container: %s\n", error); | ||
| return EXIT_FAILURE; | ||
| } | ||
|
|
||
| char connectionString[512]; | ||
| int bytesWritten = tc_psql_get_connection_string(containerId, connectionString, sizeof(connectionString)); | ||
| if (bytesWritten == -1) { | ||
| fprintf(stderr, "Failed to get connection string\n"); | ||
| return EXIT_FAILURE; | ||
| } | ||
|
|
||
| printf("Connecting to PostgreSQL using connection string: %s\n", connectionString); | ||
|
|
||
| PGconn* conn = PQconnectdb(connectionString); | ||
| if (PQstatus(conn) != CONNECTION_OK) { | ||
| fprintf(stderr, "Failed to connect to PostgreSQL: %s", PQerrorMessage(conn)); | ||
| PQfinish(conn); | ||
| return EXIT_FAILURE; | ||
| } | ||
|
|
||
| printf("Successfully connected to PostgreSQL!\n"); | ||
| PQfinish(conn); | ||
|
|
||
| error = tc_container_terminate(containerId); | ||
| if (error != NULL) { | ||
| fprintf(stderr, "Failed to terminate PostgreSQL container: %s", error); | ||
| return EXIT_FAILURE; | ||
| } | ||
|
|
||
| printf("Terminated PostgreSQL container\n"); | ||
|
|
||
| return EXIT_SUCCESS; | ||
| } | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,7 @@ | |
| go | ||
| ninja | ||
| pre-commit | ||
| libpq | ||
| ]; | ||
| }; | ||
| }; | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| add_subdirectory(wiremock) | ||
| add_subdirectory(postgresql) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| set(TARGET testcontainers-c-postgresql) | ||
| set(TARGET_NAME ${TARGET}) | ||
| set(TARGET_DESCRIPTION "PostgreSQL testcontainer abstractions for C") | ||
| set(TARGET_VERSION ${PROJECT_VERSION}) | ||
|
|
||
| add_library(${TARGET} SHARED | ||
| impl.c | ||
| ) | ||
|
|
||
| target_sources(${TARGET} | ||
| PUBLIC FILE_SET HEADERS | ||
| BASE_DIRS . | ||
| FILES testcontainers-c-postgresql.h | ||
| ) | ||
|
|
||
| target_link_libraries(${TARGET} PRIVATE testcontainers-c) | ||
|
|
||
| configure_file(cmake.pc.in ${TARGET}.pc @ONLY) | ||
| install(TARGETS ${TARGET} | ||
| LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
| PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) | ||
| install(FILES ${CMAKE_BINARY_DIR}/${TARGET}.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # PostgreSQL module for Testcontainers C | ||
|
|
||
| This module allows starting up a PostgreSQL database container with a simpler API surface compared to | ||
| setting one up manually. | ||
|
|
||
| PostgreSQL is a popular open-source SQL-based RDBMS which can be accessed from native apps by using | ||
| the `libpq` library for C or the `libpqxx` library for C++. | ||
|
|
||
| See [this page](https://testcontainers.com/modules/postgresql/) | ||
| for the list of modules for other languages. | ||
|
|
||
| ## Examples | ||
|
|
||
| - [Usage Demo](../../demo/postgresql/README.md) | ||
|
|
||
| ## Read more | ||
|
|
||
| - [libpq: C library for PostgreSQL](https://www.postgresql.org/docs/current/libpq.html) | ||
| - [libpq Examples](https://www.postgresql.org/docs/current/libpq-example.html) | ||
| - [libpqxx: C++ library for PostgreSQL](https://pqxx.org/development/libpqxx/) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| prefix=@CMAKE_INSTALL_PREFIX@ | ||
| exec_prefix=@CMAKE_INSTALL_PREFIX@ | ||
| libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ | ||
| includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ | ||
|
|
||
| Name: @TARGET_NAME@ | ||
| Description: @TARGET_DESCRIPTION@ | ||
| Version: @TARGET_VERSION@ | ||
|
|
||
| Requires: | ||
| Libs: -L${libdir} | ||
| Cflags: -I${includedir} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| #include "testcontainers-c-postgresql.h" | ||
| #include "testcontainers-c/container.h" | ||
|
|
||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| #include <stdio.h> | ||
| #include <stdbool.h> | ||
|
|
||
| #define DEFAULT_POSTGRESQL_IMAGE_NAME "postgres" | ||
| #define DEFAULT_POSTGRESQL_VERSION "18.1" | ||
| #define DEFAULT_POSTGRESQL_PORT 5432 | ||
| #define DEFAULT_POSTGRESQL_IMAGE DEFAULT_POSTGRESQL_IMAGE_NAME ":" DEFAULT_POSTGRESQL_VERSION | ||
|
|
||
| #define DEFAULT_POSTGRESQL_USERNAME "postgres" | ||
| #define DEFAULT_POSTGRESQL_PASSWORD "postgres" | ||
| #define DEFAULT_POSTGRESQL_DB "postgres" | ||
|
|
||
| static bool pg_isready_is_success(int exitCode) { | ||
| return exitCode == 0; | ||
| } | ||
|
|
||
| static const char* pgIsReadyCmd[] = { "pg_isready", "--host", "localhost", "--username", DEFAULT_POSTGRESQL_USERNAME, "--dbname", DEFAULT_POSTGRESQL_DB }; | ||
| static const size_t pgIsReadyCmdLen = sizeof(pgIsReadyCmd) / sizeof(char*); | ||
|
|
||
| int tc_psql_new_default_container() { | ||
| return tc_psql_new_container(DEFAULT_POSTGRESQL_IMAGE); | ||
| } | ||
|
|
||
| int tc_psql_new_container(const char *image) { | ||
| int requestId = tc_container_create(image); | ||
|
|
||
| tc_container_with_env(requestId, "POSTGRES_USER", DEFAULT_POSTGRESQL_USERNAME); | ||
| tc_container_with_env(requestId, "POSTGRES_PASSWORD", DEFAULT_POSTGRESQL_PASSWORD); | ||
| tc_container_with_env(requestId, "POSTGRES_DB", DEFAULT_POSTGRESQL_DB); | ||
| tc_container_with_exposed_tcp_port(requestId, DEFAULT_POSTGRESQL_PORT); | ||
|
|
||
| int strategyId = tc_container_with_wait_for_exec(requestId, pgIsReadyCmd, pgIsReadyCmdLen); | ||
| tc_exec_with_exit_code_matcher(strategyId, pg_isready_is_success); | ||
|
|
||
| // TODO: in other Testcontainers implementations, they pass some command parameters to the container | ||
| // to disable certain hardening features and improve performance as the container is ephemeral. We | ||
| // should consider doing the same if we add the ability to modify container commands to the bridge. | ||
| // See: https://www.postgresql.org/docs/current/non-durability.html | ||
|
|
||
| return requestId; | ||
| } | ||
|
|
||
| int tc_psql_get_connection_string(int containerId, char* buffer, size_t bufferLen) { | ||
| if (buffer == NULL || bufferLen <= 0) { | ||
| // Invalid arguments | ||
| return -1; | ||
| } | ||
|
|
||
| char* error; | ||
|
|
||
| const char* hostname = tc_container_get_hostname(containerId, &error); | ||
| if (hostname == NULL) { | ||
| fprintf(stderr, "Failed to get PostgreSQL hostname: %s", error); | ||
| free(error); | ||
| return -1; | ||
| } | ||
|
|
||
| int port = tc_container_get_mapped_port(containerId, DEFAULT_POSTGRESQL_PORT, &error); | ||
| if (port == -1) { | ||
| fprintf(stderr, "Failed to get PostgreSQL mapped port: %s", error); | ||
| free(error); | ||
| return -1; | ||
| } | ||
|
|
||
|
|
||
| int written = snprintf( | ||
| buffer, | ||
| bufferLen, | ||
| "host=%s port=%d user=%s password=%s dbname=%s", | ||
| hostname, | ||
| port, | ||
| DEFAULT_POSTGRESQL_USERNAME, | ||
| DEFAULT_POSTGRESQL_PASSWORD, | ||
| DEFAULT_POSTGRESQL_DB | ||
| ); | ||
|
|
||
| if (written < 0) { | ||
| return -1; | ||
| } | ||
|
|
||
| if (written >= bufferLen) { | ||
| // Provided buffer was not long enough; truncation has occurred | ||
| // If written == bufferLen, that means we missed 1 character because of the null terminator | ||
| return -1; | ||
| } | ||
|
|
||
| return written; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| #ifndef TESTCONTAINERS_POSTGRESQL_H | ||
| #define TESTCONTAINERS_POSTGRESQL_H | ||
|
|
||
| #include <stddef.h> | ||
|
|
||
| /// @brief Creates a container request with a default image, exposed port and init logic | ||
| /// @return Container request ID | ||
| int tc_psql_new_default_container(); | ||
|
|
||
| /// @brief Creates a container request with a specified image, exposed port and init logic | ||
| /// @param image Full image name | ||
| /// @return Container request ID | ||
| int tc_psql_new_container(const char* image); | ||
|
|
||
| /// @brief Gets the connection string that can be used with libpq/libpqxx to connect to the database. | ||
| /// @param containerId Container ID | ||
| /// @param buffer A buffer to write the connection string into. The written value will be null-terminated. | ||
| /// @param bufferLen The length of the buffer. | ||
| /// @return The number of bytes written, excluding the null terminator, or -1 if there was an error. | ||
| int tc_psql_get_connection_string(int containerId, char* buffer, size_t bufferLen); | ||
|
|
||
| // TODO: further container customisation to allow configuring database name, username, password, etc. | ||
|
|
||
| #endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really know what this does, but I copied it from the WireMock folder ... it seems agnostic of what folder it lives in. Something to do with packaging?