Skip to content

Conversation

@m4tx
Copy link
Member

@m4tx m4tx commented Jan 27, 2026

This changes the Cot's testing framework to use Testcontainers instead of manually spinning up Docker containers.

This change:

  • makes it easier to run the tests,
  • gives us a bit more flexibility in testing various versions of the dependencies,
  • makes all the tests 100% isolated from each other,
  • makes the tests more robust. It removes our custom Redis database allocation code - while it was smart, it wasn't perfect, and it sometimes caused the tests to be flaky.

This comes with some drawbacks, though:

  • higher test runtime,
  • more resource usage in general,
  • huge increase in the number of dependencies (hence the removal of test feature flag from the full feature set)

Whether it's worth it - I'm leaving this for others to decide.

@github-actions github-actions bot added the C-lib Crate: cot (main library crate) label Jan 27, 2026
@github-actions
Copy link

github-actions bot commented Jan 27, 2026

🐰 Bencher Report

Branchtest-containers
Testbedgithub-ubuntu-latest
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
microseconds (µs)
(Result Δ%)
Upper Boundary
microseconds (µs)
(Limit %)
empty_router/empty_router📈 view plot
🚷 view threshold
6,730.90 µs
(+13.36%)Baseline: 5,937.82 µs
7,140.99 µs
(94.26%)
json_api/json_api📈 view plot
🚷 view threshold
1,052.10 µs
(+3.57%)Baseline: 1,015.79 µs
1,162.89 µs
(90.47%)
nested_routers/nested_routers📈 view plot
🚷 view threshold
972.02 µs
(+3.84%)Baseline: 936.08 µs
1,065.51 µs
(91.23%)
single_root_route/single_root_route📈 view plot
🚷 view threshold
935.89 µs
(+4.31%)Baseline: 897.23 µs
1,023.90 µs
(91.40%)
single_root_route_burst/single_root_route_burst📈 view plot
🚷 view threshold
17,985.00 µs
(+2.35%)Baseline: 17,572.13 µs
20,842.61 µs
(86.29%)
🐰 View full continuous benchmarking report in Bencher

@m4tx m4tx force-pushed the test-containers branch 5 times, most recently from 2478966 to 4d25196 Compare February 1, 2026 20:32
@m4tx m4tx changed the title refactor: use TestContainers refactor!: use TestContainers Feb 1, 2026
@m4tx m4tx force-pushed the test-containers branch 3 times, most recently from b3161ea to 1026eda Compare February 1, 2026 23:24
@github-actions github-actions bot added the C-cli Crate: cot-cli (issues and Pull Requests related to Cot CLI) label Feb 1, 2026
@github-actions github-actions bot added the A-ci Area: CI (Continuous Integration) label Feb 1, 2026
@m4tx m4tx marked this pull request as ready for review February 2, 2026 00:01
Copilot AI review requested due to automatic review settings February 2, 2026 00:01
@github-actions github-actions bot added the C-macros Crate: cot-macros label Feb 2, 2026
@m4tx m4tx requested review from ElijahAhianyo and seqre February 2, 2026 00:01
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request refactors the testing framework to use Testcontainers instead of manually spinning up Docker containers. The change improves test isolation and makes it easier to run tests, but comes with increased resource usage and a significantly larger dependency footprint.

Changes:

  • Replaced manual Docker Compose setup with Testcontainers for all external test dependencies (PostgreSQL, MariaDB/MySQL, Redis, Selenium WebDriver)
  • Removed the test feature from the full feature set and made it an optional dependency
  • Updated CI/CD workflows to remove Docker Compose startup steps
  • Added comprehensive WebDriver management through TestServerWithWebDriver wrapper
  • Modified test ignore messages to be more accurate

Reviewed changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
justfile Removed Docker Compose commands from test targets, simplified test execution
cot/tests/admin.rs Updated WebDriver integration to use Testcontainers, improved test function signatures
cot/src/test.rs Major refactoring to use Testcontainers for databases, Redis, and Selenium; added TestServerWithWebDriver and TestWebDriver types
cot/src/session/store/redis.rs Updated Redis tests to use containerized Redis instances
cot/src/cache/store/redis.rs Updated cache tests to use containerized Redis instances
cot/Cargo.toml Added testcontainers dependencies, removed test from full feature
cot-cli/src/project_template/Cargo.toml.template Added test feature to dev-dependencies for new projects
compose.yml Deleted - no longer needed for testing
clippy.toml Added "WebDriver" to valid identifiers
README.md Updated test instructions to remove Docker Compose requirement
CONTRIBUTING.md Updated test documentation to reflect Testcontainers usage
.github/workflows/rust.yml Removed Docker Compose setup steps from CI/CD
Cargo.lock Added numerous new dependencies for testcontainers ecosystem
cot-macros/tests/ui/derive_into_response_missing_trait_impl.stderr Minor compiler output formatting change

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1580 to 1582
/// function, you can set the `COT_TEST_SERVER_HOST` environment variable
/// or call [`Self::set_host`].
///
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation references a non-existent method Self::set_host. Either this method needs to be implemented or the reference should be removed from the documentation.

Suggested change
/// function, you can set the `COT_TEST_SERVER_HOST` environment variable
/// or call [`Self::set_host`].
///
/// function, you can set the `COT_TEST_SERVER_HOST` environment variable.
///
///

Copilot uses AI. Check for mistakes.
Comment on lines +1240 to +1245
.raw(&format!(
"SELECT pg_terminate_backend(pg_stat_activity.pid) \
FROM pg_stat_activity \
WHERE pg_stat_activity.datname = '{db_name}' \
AND pid <> pg_backend_pid()"
))
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL injection vulnerability: the database name is interpolated directly into the SQL query without proper escaping or parameterization. Although test names are typically controlled, this creates a security risk if a malicious test name is used. Consider using PostgreSQL identifier quoting (e.g., wrapping the identifier in double quotes and escaping any double quotes within it), or using a parameterized query if the database driver supports it for DDL operations.

Copilot uses AI. Check for mistakes.
))
.await?;

database.raw(&format!("DROP DATABASE {db_name}")).await?;
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL injection vulnerability: the database name is interpolated directly into the SQL query without proper escaping or parameterization. Although test names are typically controlled, this creates a security risk if a malicious test name is used. Consider using proper identifier quoting or parameterized queries.

Copilot uses AI. Check for mistakes.
} => {
let database = Database::new(format!("{db_url}/mysql")).await?;

database.raw(&format!("DROP DATABASE {db_name}")).await?;
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL injection vulnerability: the database name is interpolated directly into the SQL query without proper escaping or parameterization. Although test names are typically controlled, this creates a security risk if a malicious test name is used. Consider using proper identifier quoting or parameterized queries.

Copilot uses AI. Check for mistakes.
container is automatically started using Testcontainers.

Alternatively, you can run the tests with a local webdriver server. To do this,
you need to set the `WEBDRIVER_URL` environment variable to the URL of your
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Environment variable name inconsistency: The documentation mentions WEBDRIVER_URL but the code uses COT_WEBDRIVER_URL. These should be consistent. Either update the documentation to say COT_WEBDRIVER_URL or change the code to use WEBDRIVER_URL.

Suggested change
you need to set the `WEBDRIVER_URL` environment variable to the URL of your
you need to set the `COT_WEBDRIVER_URL` environment variable to the URL of your

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Feb 2, 2026

Codecov Report

❌ Patch coverage is 72.50000% with 44 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cot/src/test.rs 67.64% 29 Missing and 15 partials ⚠️
Flag Coverage Δ
rust 89.56% <72.50%> (-0.13%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cot/src/cache/store/redis.rs 92.67% <100.00%> (ø)
cot/src/session/store/redis.rs 88.23% <100.00%> (+0.08%) ⬆️
cot/src/test.rs 81.71% <67.64%> (-4.19%) ⬇️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines +961 to +967
let host_port = container
.get_host_port_ipv4(POSTGRES_PORT)
.await
.map_err(|e| {
TestcontainersError::new("failed to get PostgreSQL container port", e)
})?;
let host_port: u16 = host_port;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why two let statements?


#[derive(Debug, Error)]
#[error("{message}: {inner}")]
struct TestcontainersError {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I know the name matches the library name, but it pains me it's not TestContainersError

/// # Errors
///
/// Returns an error if the container could not be started.
pub async fn with_host_port_exposure(port: u16) -> Result<Self> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I think with_host_post_exposed is better

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ci Area: CI (Continuous Integration) C-cli Crate: cot-cli (issues and Pull Requests related to Cot CLI) C-lib Crate: cot (main library crate) C-macros Crate: cot-macros

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants