diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9d5381a..f67ed99 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,8 +25,8 @@ permissions: jobs: tests: - runs-on: ubuntu-latest - timeout-minutes: 30 + runs-on: ${{ matrix.os }} + timeout-minutes: 60 strategy: matrix: os: @@ -68,15 +68,24 @@ jobs: - name: Generate test certificates run: bash tests/gen_certs.sh + # macOS runners have no Docker, so PostgreSQL is only available on Linux. - name: Start PostgreSQL + if: runner.os == 'Linux' run: docker compose up -d --wait - name: Install chronos run: nimble install chronos -y + # Linux runs the full suite against the live PostgreSQL above. - name: Run tests + if: runner.os == 'Linux' run: nimble test -y + # macOS has no PostgreSQL; run only the unit and mock-server tests. + - name: Run unit tests + if: runner.os != 'Linux' + run: nimble test_unit -y + - name: Install async_postgres run: | rm -rf ~/.nimble/pkgs2/async_postgres-* @@ -88,6 +97,8 @@ jobs: - name: Compile examples (chronos) run: for f in examples/*.nim; do nim c -d:asyncBackend=chronos "$f"; done + # Doc generation is platform-independent; run it once (on Linux). - name: Gen docs + if: runner.os == 'Linux' run: | nim doc --project --index:on --outdir:./htmldocs ./async_postgres.nim diff --git a/async_postgres.nimble b/async_postgres.nimble index bbdafad..fb32c31 100644 --- a/async_postgres.nimble +++ b/async_postgres.nimble @@ -11,6 +11,10 @@ requires "nim >= 2.2.4" requires "nimcrypto >= 0.6.0" requires "checksums >= 0.2.0" -task test, "test": +task test, "run the full suite (requires a live PostgreSQL on 127.0.0.1:15432)": exec "nim c -d:asyncBackend=asyncdispatch -r tests/all_tests.nim" exec "nim c -d:asyncBackend=chronos -r tests/all_tests.nim" + +task test_unit, "run unit and mock-server tests only (no PostgreSQL required)": + exec "nim c -d:asyncBackend=asyncdispatch -r tests/all_tests_unit.nim" + exec "nim c -d:asyncBackend=chronos -r tests/all_tests_unit.nim" diff --git a/tests/all_tests.nim b/tests/all_tests.nim index 2bff707..29d444e 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -1,8 +1,6 @@ +## Full test suite: the unit/mock tests plus the live-PostgreSQL integration +## tests. Requires a running PostgreSQL (see docker-compose.yml). For a run +## that needs no database, use all_tests_unit.nim instead. {.push warning[UnusedImport]: off.} -import - test_abandonment_e2e, test_advisory_lock, test_auth, test_cancel_e2e, test_dsn, - test_e2e, test_fill_recvbuf, test_keepalive, test_largeobject, test_listen_reconnect, - test_network_failure, test_physical_replication, test_pool, test_protocol, - test_protocol_fuzz, test_replication, test_replication_keepalive, test_rowdata, - test_session_attrs, test_sql, test_ssl, test_tracing, test_types, test_pool_cluster +import all_tests_unit, all_tests_integration {.pop.} diff --git a/tests/all_tests_integration.nim b/tests/all_tests_integration.nim new file mode 100644 index 0000000..736ef6c --- /dev/null +++ b/tests/all_tests_integration.nim @@ -0,0 +1,8 @@ +## End-to-end tests that require a live PostgreSQL at 127.0.0.1:15432 +## (started via docker-compose.yml). Run these only where Docker/PostgreSQL +## is available; the unit/mock suite lives in all_tests_unit.nim. +{.push warning[UnusedImport]: off.} +import + test_abandonment_e2e, test_advisory_lock, test_cancel_e2e, test_e2e, test_largeobject, + test_tracing +{.pop.} diff --git a/tests/all_tests_unit.nim b/tests/all_tests_unit.nim new file mode 100644 index 0000000..1041209 --- /dev/null +++ b/tests/all_tests_unit.nim @@ -0,0 +1,11 @@ +## Unit and in-process mock-server tests. None of these require a live +## PostgreSQL: every test either exercises pure logic or connects to an +## in-process mock server on an ephemeral port. They therefore run anywhere, +## including CI hosts without Docker (e.g. macOS runners). +{.push warning[UnusedImport]: off.} +import + test_auth, test_dsn, test_fill_recvbuf, test_keepalive, test_listen_reconnect, + test_network_failure, test_physical_replication, test_pool, test_pool_cluster, + test_protocol, test_protocol_fuzz, test_replication, test_replication_keepalive, + test_rowdata, test_session_attrs, test_sql, test_ssl, test_types +{.pop.} diff --git a/tests/test_keepalive.nim b/tests/test_keepalive.nim index c91b57d..57bceb0 100644 --- a/tests/test_keepalive.nim +++ b/tests/test_keepalive.nim @@ -15,6 +15,11 @@ suite "configureKeepalive": doAssert fd != SocketHandle(-1), "socket() failed" fd + proc keepaliveEnabled(fd: SocketHandle): bool = + # macOS/BSD getsockopt returns the SO_KEEPALIVE flag bit (8), Linux returns 1, + # so treat any non-zero value as "enabled". + getIntSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE) != 0 + test "keepAlive=false does not set SO_KEEPALIVE": let fd = makeSocket() defer: @@ -22,7 +27,7 @@ suite "configureKeepalive": var config = ConnConfig() config.keepAlive = false configureKeepalive(fd, config) - check getIntSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE) == 0 + check not keepaliveEnabled(fd) test "keepAlive=true sets SO_KEEPALIVE": let fd = makeSocket() @@ -31,7 +36,7 @@ suite "configureKeepalive": var config = ConnConfig() config.keepAlive = true configureKeepalive(fd, config) - check getIntSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE) == 1 + check keepaliveEnabled(fd) test "keepAlive with idle/interval/count": let fd = makeSocket() @@ -43,7 +48,7 @@ suite "configureKeepalive": config.keepAliveInterval = 7 config.keepAliveCount = 3 configureKeepalive(fd, config) - check getIntSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE) == 1 + check keepaliveEnabled(fd) when defined(linux): check getIntSockOpt(fd, cint(posix.IPPROTO_TCP), TCP_KEEPIDLE) == 42 check getIntSockOpt(fd, cint(posix.IPPROTO_TCP), TCP_KEEPINTVL) == 7 @@ -63,7 +68,7 @@ suite "configureKeepalive": config.keepAliveInterval = 0 config.keepAliveCount = 0 configureKeepalive(fd, config) - check getIntSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE) == 1 + check keepaliveEnabled(fd) test "keepAlive=false with timing params does not set SO_KEEPALIVE": let fd = makeSocket() @@ -75,7 +80,7 @@ suite "configureKeepalive": config.keepAliveInterval = 10 config.keepAliveCount = 3 configureKeepalive(fd, config) - check getIntSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE) == 0 + check not keepaliveEnabled(fd) test "partial timing (idle only)": let fd = makeSocket() @@ -85,7 +90,7 @@ suite "configureKeepalive": config.keepAlive = true config.keepAliveIdle = 99 configureKeepalive(fd, config) - check getIntSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE) == 1 + check keepaliveEnabled(fd) when defined(linux): check getIntSockOpt(fd, cint(posix.IPPROTO_TCP), TCP_KEEPIDLE) == 99 elif defined(macosx):