Skip to content
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

Add: test-virtual (related issue #71) #72

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
**/target
**/*.rs.bk
**/.redo
Cargo.lock
*.iml
*.ipr
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "macrotest"
version = "1.0.9" # remember to update in lib.rs
authors = ["eupn <[email protected]>"]
edition = "2018"
edition = "2021"
rust-version = "1.56"
license = "MIT OR Apache-2.0"
readme = "README.md"
Expand Down
33 changes: 33 additions & 0 deletions test-virtual/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[workspace]
resolver = "2"
members = [
"wrkspc",
"wrkspc-dev",
"wrkspc-macro",
"wrkspc-test",
]

[workspace.package]
version = "0.0.0"
authors = ["eupn <[email protected]>", "Mark Van de Vyver <[email protected]>"]
license = "Apache-2.0"
edition = "2021"
rust-version = "1.56"
description = "A virtual workspace example for macrotest"
homepage = "https://github.com/eupn/macrotest"
repository = "https://github.com/eupn/macrotest"
documentation = "https://docs.rs/macrotest"
readme = "README.md"
publish = false

[workspace.dependencies]
wrkspc = { path = "wrkspc" }
wrkspc-dev = { path = "wrkspc-dev" }
wrkspc-macro = { path = "wrkspc-macro" }
wrkspc-test = { path = "wrkspc-test" }

macrotest = { path = "../" }

proc-macro2 = "1.0"
quote = "1"
syn = "2.0"
155 changes: 155 additions & 0 deletions test-virtual/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# `test-virtual`

A convention over configuration template for integration tests of proc-macros,
in a workspace.

This example workspace contains crates:

- `wrkspc`: A library crate.
- `wrkspc-dev`: A development crate.
- `wrkspc-macro`: The Proc-macro crate.
- `wrkspc-test`: Integration tests, and DJB's `redo` build system for `wrkspc-macro`.

Where:

- `wrkspc`: A "Hello world" style library (for release as a crate).
- `wrkspc-dev`: A "Hello world" style library for development (not for release).
- `wrkspc-macro`: The `test-promacro-project` adjusted to fit into the workspace plugin-test harness. This crate provides a declarative `test_vec![]` macro
to test its expansion under the [tests](tests) directory with [`macrostest`](https://crates.io/crates/macrotest).
- `wrkspc-test`: The `test-project` adjusted to fit into the workspace integrated test harness.

The integration test harness, `wkspc-test`, uses [DJB's redo build system](https://cr.yp.to/redo.html), as implemented by [apenwarr](https://github.com/apenwarr/redo/) and as ported to Rust by [zombiezen](https://github.com/zombiezen/redo-rs).

In this build process `all.do` flows to a generic build step `default.do`. Hence, `all.do` is responsible for iterating over all source files and `default.do` is responsible for processing each individual file. The `default.do` is kept generic by adhering to some naming conventions, shared between the macro and test crates:

In this setup:

- `all.do` is the starting point of the build process.
- `default.do` is called by `all.do` for each source file.
- `default.do` processes each file by:
- Extracting the filename from the path using `basename`, resulting in `bin`.
- Removing the `.expanded.rs` extension using `cut`, resulting in `bin`.

The next diagram shows the flow of data in the files between the folders `wkspc-macro` and `wkspc-test`:

- `wkspc-macro` is the source directory containing the `.rs` to be tested files.
- `all.do` processes each `.rs` file in `wkspc-macro`.
- `default.expand.do` is called by `all.do` for each `.rs` file and generates a corresponding `.expanded.rs` file if the source file has changed.
- The `.expanded.rs` files are placed in the `wkspc-test` directory.
- If redoing the expanded file fails, it records the error message.
- If the build succeeds, it removes `exp_file.staged`.

[Build data flow](./images/figure-data.png)
<!--
flowchart LR
A[wkspc-macro] -->|Source .rs files| B[all.do]
B -->|Processes each file| C[default.expand.do]
C -->|Generates .expanded.rs files if source file has changed| D[wkspc-test]
D -->|If redo fails| E[Records error message]
E --> F[error_messages]
D -->|If build succeeds| G[Removes exp_file.staged]
-->

Here's a Mermaid diagram that shows how the build process in `all.do` flows to `default.expand.do` and then to `default.do`. In this first diagram:

- `all.do` is the starting point of the build process.
- `default.expand.do` is called by `all.do` for each source file.
- `default.expand.do` processes each file by:
- Extracting the filename from the path using `basename`, resulting in `bin_file`.
- Removing the `.expanded.rs` extension using `cut`, resulting in `bin_name`.
- Checking if the .expanded.rs file exists. If it does, it continues processing. If it doesn't, it skips the file.
- Getting the relative path of the source file using `realpath`, resulting in `rel_path`.
- Constructing the path of the expanded file using string concatenation, resulting in `expanded_path`.
- Checking if the source file has changed. If it has, it redoes the expanded file. If it hasn't, it skips the file.
- If redoing the expanded file fails, it increments the error count and records the error message.
- `default.do` is called for each file that is not skipped.
- It copies the source file to the destination, resulting in `exp_file.staged`.
- It builds the file using `cargo build`. If the build succeeds, it removes `exp_file.staged`.

[Build logic flow](./images/figure-logic.png)
<!--
workflow TD
A[all.do] -->|Iterates over all source files| B[default.expand.do]
B --> C{Processes each file}
C -->|1. Extracts filename from path| D[Uses basename]
D --> E[bin_file]
C -->|2. Removes .expanded.rs extension| F[Uses cut]
F --> G[bin_name]
C -->|3. Checks if .expanded.rs file exists| H[If file exists]
H -->|Yes| I[Continues processing]
I -->|4. Gets relative path of source file| J[Uses realpath]
J --> K[rel_path]
I -->|5. Constructs path of expanded file| L[Uses string concatenation]
L --> M[expanded_path]
I -->|6. Checks if source file has changed| N[If file has changed]
N -->|Yes| O[Redoes expanded file]
O -->|If redo fails| P[Increments error count and records error message]
P --> Q[error_count and error_messages]
N -->|No| R[Skips file]
R --> S[default.do]
S -->|7. Copies source file to destination| T[Uses cp]
T --> U[exp_file.staged]
S -->|8. Builds with cargo| V[Uses cargo build]
V -->|If build succeeds| W[Removes exp_file.staged]
-->

## Containers

To run Testcontainers-based tests,
you need a Docker-API compatible container runtime,
such as using [Testcontainers Cloud](https://www.testcontainers.cloud/) or installing [Podman](https://podman.io/) or Docker locally. [Testcontainers Desktop](https://testcontainers.com/desktop/) takes care of most of the manual configuration for alternative runtimes. See [Customizing Docker host detection](#customizing-docker-host-detection) for general configuration mechanisms.

### Podman

In order to run testcontainers against [podman](https://podman.io/) the env vars bellow should be set

MacOS:

```bash
{% raw %}
export DOCKER_HOST=unix://$(podman machine inspect --format '{{.ConnectionInfo.PodmanSocket.Path}}')
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
{% endraw %}
```

Linux:

```bash
export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/podman/podman.sock
```

If you're running Podman in rootless mode, ensure to include the following line to disable Ryuk:

```bash
export TESTCONTAINERS_RYUK_DISABLED=true
```

!!! note
Previous to version 1.19.0, `export TESTCONTAINERS_RYUK_PRIVILEGED=true`
was required for rootful mode. Starting with 1.19.0, this is no longer required.

### Container environment discovery

Testcontainers will try to connect to a Docker daemon using the following strategies in order:

- Environment variables:
- `DOCKER_HOST`
- `DOCKER_TLS_VERIFY`
- `DOCKER_CERT_PATH`
- Defaults:
- `DOCKER_HOST=https://localhost:2376`
- `DOCKER_TLS_VERIFY=1`
- `DOCKER_CERT_PATH=~/.docker`
- If Docker Machine is installed, the docker machine environment for the *first* machine found. Docker Machine needs to be on the PATH for this to succeed.
- If you're going to run your tests inside a container, please read [Patterns for running tests inside a docker container](continuous_integration/dind_patterns.md) first.

### Docker registry authentication

Testcontainers will try to authenticate to registries with supplied config using the following strategies in order:

- Environment variables:
- `DOCKER_AUTH_CONFIG`
- Docker config
- At location specified in `DOCKER_CONFIG` or at `{HOME}/.docker/config.json`

### Customizing Docker host detection
137 changes: 137 additions & 0 deletions test-virtual/TESTCONTAINERS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# [Custom configuration](https://github.com/testcontainers/testcontainers-java/blob/main/docs/features/configuration.md)

You can override some default properties if your environment requires that.

## Configuration locations

The configuration will be loaded from multiple locations. Properties are considered in the following order:

1. Environment variables
2. `.testcontainers.properties` in user's home folder. Example locations:
**Linux:** `/home/myuser/.testcontainers.properties`
**Windows:** `C:/Users/myuser/.testcontainers.properties`
**macOS:** `/Users/myuser/.testcontainers.properties`
3. `testcontainers.properties` on the classpath.

Note that when using environment variables, configuration property names should be set in upper
case with underscore separators, preceded by `TESTCONTAINERS_` - e.g. `checks.disable` becomes
`TESTCONTAINERS_CHECKS_DISABLE`.

The classpath `testcontainers.properties` file may exist within the local codebase (e.g. within the `src/test/resources` directory) or within library dependencies that you may have.
Any such configuration files will have their contents merged.
If any keys conflict, the value will be taken on the basis of the first value found in:

* 'local' classpath (i.e. where the URL of the file on the classpath begins with `file:`), then
* other classpath locations (i.e. JAR files) - considered in _alphabetical order of path_ to provide deterministic ordering.

## Disabling the startup checks
>
> **checks.disable = [true|false]**

Before running any containers Testcontainers will perform a set of startup checks to ensure that your environment is configured correctly. Usually they look like this:

```
ℹ︎ Checking the system...
✔ Docker version should be at least 1.6.0
✔ File should be mountable
✔ A port exposed by a docker container should be accessible
```

It takes a couple of seconds, but if you want to speed up your tests, you can disable the checks once you have everything configured. Add `checks.disable=true` to your `$HOME/.testcontainers.properties` to completely disable them.

## Customizing images

!!! note
This approach is discouraged and deprecated, but is documented for completeness.
Overriding individual image names via configuration may be removed in 2021.
See [Image Name Substitution](./image_name_substitution.md) for other strategies for substituting image names to pull from other registries.

Testcontainers uses public Docker images to perform different actions like startup checks, VNC recording and others.
Some companies disallow the usage of Docker Hub, but you can override `*.image` properties with your own images from your private registry to workaround that.

> **ryuk.container.image = testcontainers/ryuk:0.3.3**
> Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk))

> **tinyimage.container.image = alpine:3.16**
> Used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](#disabling-the-startup-checks))

> **sshd.container.image = testcontainers/sshd:1.1.0**
> Required if [exposing host ports to containers](./networking.md#exposing-host-ports-to-the-container)

> **vncrecorder.container.image = testcontainers/vnc-recorder:1.3.0**
> Used by VNC recorder in Testcontainers' Selenium integration

> **socat.container.image = alpine/socat**
> **compose.container.image = docker/compose:1.8.0**
> Required if using [Docker Compose](../modules/docker_compose.md)

> **kafka.container.image = confluentinc/cp-kafka**
> Used by KafkaContainer

> **localstack.container.image = localstack/localstack**
> Used by LocalStack

> **pulsar.container.image = apachepulsar/pulsar:2.2.0**
> Used by Apache Pulsar

## Customizing Ryuk resource reaper

> **ryuk.container.image = testcontainers/ryuk:0.3.3**
> The resource reaper is responsible for container removal and automatic cleanup of dead containers at JVM shutdown

> **ryuk.container.privileged = true**
> In some environments ryuk must be started in privileged mode to work properly (--privileged flag)

### Disabling Ryuk

Ryuk must be started as a privileged container.
If your environment already implements automatic cleanup of containers after the execution,
but does not allow starting privileged containers, you can turn off the Ryuk container by setting
`TESTCONTAINERS_RYUK_DISABLED` **environment variable** to `true`.

!!!tip
Note that Testcontainers will continue doing the cleanup at JVM's shutdown, unless you `kill -9` your JVM process.

## Customizing image pull behaviour

> **pull.pause.timeout = 30**
> By default Testcontainers will abort the pull of an image if the pull appears stalled (no data transferred) for longer than this duration (in seconds).

## Customizing client ping behaviour

> **client.ping.timeout = 5**
> Specifies for how long Testcontainers will try to connect to the Docker client to obtain valid info about the client before giving up and trying next strategy, if applicable (in seconds).

## Customizing Docker host detection

Testcontainers will attempt to detect the Docker environment and configure everything to work automatically.

However, sometimes customization is required. Testcontainers will respect the following **environment variables**:

> **DOCKER_HOST** = unix:///var/run/docker.sock
> See [Docker environment variables](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables)
>
> **TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE**
> Path to Docker's socket. Used by Ryuk, Docker Compose, and a few other containers that need to perform Docker actions.
> Example: `/var/run/docker-alt.sock`
>
> **TESTCONTAINERS_HOST_OVERRIDE**
> Docker's host on which ports are exposed.
> Example: `docker.svc.local`

For advanced users, the Docker host connection can be configured **via configuration** in `~/.testcontainers.properties`.
Note that these settings require use of the `EnvironmentAndSystemPropertyClientProviderStrategy`. The example below
illustrates usage:

```properties
docker.client.strategy=org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy
docker.host=tcp\://my.docker.host\:1234 # Equivalent to the DOCKER_HOST environment variable. Colons should be escaped.
docker.tls.verify=1 # Equivalent to the DOCKER_TLS_VERIFY environment variable
docker.cert.path=/some/path # Equivalent to the DOCKER_CERT_PATH environment variable
```

In addition, you can deactivate this behaviour by specifying:

```properties
dockerconfig.source=autoIgnoringUserProperties # 'auto' by default
```
Binary file added test-virtual/images/figure-data.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test-virtual/images/figure-logic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions test-virtual/wrkspc-dev/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "wrkspc-dev"
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
description.workspace = true
documentation.workspace = true
homepage.workspace = true
repository.workspace = true
license.workspace = true
readme.workspace = true
publish = false

[dependencies]
wrkspc-macro.workspace = true
# inventory.workspace = true
macrotest.workspace = true
5 changes: 5 additions & 0 deletions test-virtual/wrkspc-dev/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub use wrkspc_macro::*;

pub fn hello() {
println!("Hello Developer World!")
}
4 changes: 4 additions & 0 deletions test-virtual/wrkspc-dev/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#[test]
fn wrkspc_test() {
assert_eq!("equal", "equal")
}
3 changes: 3 additions & 0 deletions test-virtual/wrkspc-macro/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock
Loading