-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
testing: add tiny framework for testing rustic's compat with latest r…
…estic (#1303) This is the first PR to lay some foundations to test rustic's compatibility against a restic repository. It should essentially show, how to start out with it and give some fixtures to play around with. TODO: - [X] add CI workflow + test that uses restic (latest) via https://github.com/AnimMouse/setup-restic, to create a new repo and run rustic against it - [X] investigate `AnimMouse/setup-restic` failure and fix - [X] forked `AnimMouse/setup-restic` to `rustic-rs/setup-restic` to run on `@main` and apply faster fixes to our CI - [X] used `AnimMouse/setup-restic` as a foundation for `rustic-rs/setup-rustic`, still WIP - [x] update to 'release' feature in test when #1307 is merged --------- Signed-off-by: simonsan <[email protected]>
- Loading branch information
Showing
10 changed files
with
309 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,82 @@ | ||
name: Compatibility | ||
|
||
on: | ||
pull_request: | ||
paths-ignore: | ||
- "**/*.md" | ||
push: | ||
branches: | ||
- main | ||
- "renovate/**" | ||
paths-ignore: | ||
- "**/*.md" | ||
schedule: | ||
- cron: "0 0 * * 0" | ||
merge_group: | ||
types: [checks_requested] | ||
|
||
concurrency: | ||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||
cancel-in-progress: true | ||
|
||
jobs: | ||
test: | ||
name: Test | ||
runs-on: ${{ matrix.job.os }} | ||
strategy: | ||
matrix: | ||
rust: [stable] | ||
feature: [release] | ||
job: | ||
- os: macos-latest | ||
- os: ubuntu-latest | ||
- os: windows-latest | ||
steps: | ||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 | ||
if: github.event_name != 'pull_request' | ||
with: | ||
fetch-depth: 0 | ||
|
||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4 | ||
if: github.event_name == 'pull_request' | ||
with: | ||
ref: ${{ github.event.pull_request.head.sha }} | ||
fetch-depth: 0 | ||
|
||
- name: Setup Restic | ||
uses: rustic-rs/setup-restic@main | ||
|
||
- name: Install Rust toolchain | ||
uses: dtolnay/rust-toolchain@1482605bfc5719782e1267fd0c0cc350fe7646b8 # v1 | ||
with: | ||
toolchain: stable | ||
|
||
- name: Create fixtures | ||
shell: bash | ||
run: | | ||
restic init | ||
restic backup src | ||
mv src/lib.rs lib.rs | ||
restic backup src | ||
mv lib.rs src/lib.rs | ||
env: | ||
RESTIC_REPOSITORY: ./tests/repository-fixtures/repo | ||
RESTIC_PASSWORD: restic | ||
|
||
- uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2 | ||
|
||
- name: Run Cargo Test | ||
run: cargo test -r --test repositories --features ${{ matrix.feature }} -- test_restic_latest_repo_with_rustic_passes --exact --show-output --ignored | ||
|
||
result: | ||
name: Result (Compat) | ||
runs-on: ubuntu-latest | ||
needs: | ||
- test | ||
steps: | ||
- name: Mark the job as successful | ||
run: exit 0 | ||
if: success() | ||
- name: Mark the job as unsuccessful | ||
run: exit 1 | ||
if: "!success()" |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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 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,174 @@ | ||
use anyhow::Result; | ||
use assert_cmd::Command; | ||
use flate2::read::GzDecoder; | ||
use rstest::{fixture, rstest}; | ||
use rustic_testing::TestResult; | ||
use std::{fs::File, path::Path}; | ||
use tar::Archive; | ||
use tempfile::{tempdir, TempDir}; | ||
|
||
#[derive(Debug)] | ||
struct TestSource(TempDir); | ||
|
||
impl TestSource { | ||
pub fn new(tmp: TempDir) -> Self { | ||
Self(tmp) | ||
} | ||
|
||
pub fn into_path(self) -> TempDir { | ||
self.0 | ||
} | ||
} | ||
|
||
fn open_and_unpack(open_path: &'static str, unpack_dir: &TempDir) -> Result<()> { | ||
let path = Path::new(open_path).canonicalize()?; | ||
let tar_gz = File::open(path)?; | ||
let tar = GzDecoder::new(tar_gz); | ||
let mut archive = Archive::new(tar); | ||
archive.set_preserve_permissions(true); | ||
archive.set_preserve_mtime(true); | ||
archive.unpack(unpack_dir)?; | ||
Ok(()) | ||
} | ||
|
||
#[fixture] | ||
fn rustic_repo() -> Result<TestSource> { | ||
let dir = tempdir()?; | ||
let path = "tests/repository-fixtures/rustic-repo.tar.gz"; | ||
open_and_unpack(path, &dir)?; | ||
Ok(TestSource::new(dir)) | ||
} | ||
|
||
#[fixture] | ||
fn restic_repo() -> Result<TestSource> { | ||
let dir = tempdir()?; | ||
let path = "tests/repository-fixtures/restic-repo.tar.gz"; | ||
open_and_unpack(path, &dir)?; | ||
Ok(TestSource::new(dir)) | ||
} | ||
|
||
#[fixture] | ||
fn rustic_copy_repo() -> Result<TestSource> { | ||
let dir = tempdir()?; | ||
let path = "tests/repository-fixtures/rustic-copy-repo.tar.gz"; | ||
open_and_unpack(path, &dir)?; | ||
|
||
Ok(TestSource::new(dir)) | ||
} | ||
|
||
#[fixture] | ||
fn src_snapshot() -> Result<TestSource> { | ||
let dir = tempdir()?; | ||
let path = "tests/repository-fixtures/src-snapshot.tar.gz"; | ||
open_and_unpack(path, &dir)?; | ||
Ok(TestSource::new(dir)) | ||
} | ||
|
||
pub fn rustic_runner(temp_dir: &Path, password: &'static str) -> TestResult<Command> { | ||
let repo_dir = temp_dir.join("repo"); | ||
let mut runner = Command::new(env!("CARGO_BIN_EXE_rustic")); | ||
|
||
runner | ||
.arg("-r") | ||
.arg(repo_dir) | ||
.arg("--password") | ||
.arg(password) | ||
.arg("--no-progress"); | ||
|
||
Ok(runner) | ||
} | ||
|
||
#[rstest] | ||
fn test_rustic_repo_passes(rustic_repo: Result<TestSource>) -> TestResult<()> { | ||
let rustic_repo = rustic_repo?; | ||
let repo_password = "rustic"; | ||
let rustic_repo_path = rustic_repo.into_path(); | ||
let rustic_repo_path = rustic_repo_path.path(); | ||
|
||
{ | ||
let mut runner = rustic_runner(rustic_repo_path, repo_password)?; | ||
runner.args(["check", "--read-data"]).assert().success(); | ||
} | ||
|
||
{ | ||
let mut runner = rustic_runner(rustic_repo_path, repo_password)?; | ||
runner | ||
.arg("snapshots") | ||
.assert() | ||
.success() | ||
.stdout(predicates::str::contains("2 snapshot(s)")); | ||
} | ||
|
||
{ | ||
let mut runner = rustic_runner(rustic_repo_path, repo_password)?; | ||
runner | ||
.arg("diff") | ||
.arg("31d477a2") | ||
.arg("86371783") | ||
.assert() | ||
.success() | ||
.stdout(predicates::str::contains("1 removed")); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[rstest] | ||
fn test_restic_repo_with_rustic_passes(restic_repo: Result<TestSource>) -> TestResult<()> { | ||
let restic_repo = restic_repo?; | ||
let repo_password = "restic"; | ||
let restic_repo_path = restic_repo.into_path(); | ||
let restic_repo_path = restic_repo_path.path(); | ||
|
||
{ | ||
let mut runner = rustic_runner(restic_repo_path, repo_password)?; | ||
runner.args(["check", "--read-data"]).assert().success(); | ||
} | ||
|
||
{ | ||
let mut runner = rustic_runner(restic_repo_path, repo_password)?; | ||
runner | ||
.arg("snapshots") | ||
.assert() | ||
.success() | ||
.stdout(predicates::str::contains("2 snapshot(s)")); | ||
} | ||
|
||
{ | ||
let mut runner = rustic_runner(restic_repo_path, repo_password)?; | ||
runner | ||
.arg("diff") | ||
.arg("9305509c") | ||
.arg("af05ecb6") | ||
.assert() | ||
.success() | ||
.stdout(predicates::str::contains("1 removed")); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[rstest] | ||
#[ignore = "requires live fixture, run manually in CI"] | ||
fn test_restic_latest_repo_with_rustic_passes() -> TestResult<()> { | ||
let path = "tests/repository-fixtures/"; | ||
let repo_password = "restic"; | ||
let restic_repo_path = Path::new(path).canonicalize()?; | ||
let restic_repo_path = restic_repo_path.as_path(); | ||
|
||
{ | ||
let mut runner = rustic_runner(restic_repo_path, repo_password)?; | ||
runner.args(["check", "--read-data"]).assert().success(); | ||
} | ||
|
||
{ | ||
let mut runner = rustic_runner(restic_repo_path, repo_password)?; | ||
runner | ||
.arg("snapshots") | ||
.assert() | ||
.success() | ||
.stdout(predicates::str::contains("2 snapshot(s)")); | ||
} | ||
|
||
Ok(()) | ||
} |
This file contains 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,3 @@ | ||
[repository] | ||
repository = "${{REPOSITORY}}" | ||
password = "${{PASSWORD}}" |
This file contains 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,47 @@ | ||
# Repository Fixtures | ||
|
||
This directory contains fixtures for testing the `rustic` and `restic` | ||
repositories. | ||
|
||
The `rustic` repository is used to test the `rustic` binary. The `restic` | ||
repository is a repository created `restic`. The latter is used to ensure that | ||
`rustic` can read and write to a repository created by `restic`. The | ||
`rustic-copy-repo` repository is used to test the copying of snapshots between | ||
repositories. | ||
|
||
## Accessing the Repositories | ||
|
||
The `rustic` repository is located at `./rustic-repo`. The `restic` repository | ||
is located at `./restic-repo`. There is an empty repository located at | ||
`./rustic-copy-repo` that can be used to test the copying of snapshots between | ||
repositories. | ||
|
||
## Repository Layout | ||
|
||
The `rustic` repository contains the following snapshots: | ||
|
||
```console | ||
| ID | Time | Host | Label | Tags | Paths | Files | Dirs | Size | | ||
|----------|---------------------|---------|-------|------|-------|-------|------|-----------| | ||
| 31d477a2 | 2024-10-08 08:11:00 | TowerPC | | | src | 51 | 7 | 240.5 kiB | | ||
| 86371783 | 2024-10-08 08:13:12 | TowerPC | | | src | 50 | 7 | 238.6 kiB | | ||
``` | ||
|
||
The `restic` repository contains the following snapshots: | ||
|
||
```console | ||
ID Time Host Tags Paths | ||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ||
9305509c 2024-10-08 08:14:50 TowerPC src | ||
af05ecb6 2024-10-08 08:15:05 TowerPC src | ||
``` | ||
|
||
The difference between the two snapshots is that the `lib.rs` file in the `src` | ||
directory was removed between the two snapshots. | ||
|
||
The `rustic-copy-repo` repository is empty and contains no snapshots. | ||
|
||
### Passwords | ||
|
||
The `rustic` repository is encrypted with the password `rustic`. The `restic` | ||
repository is encrypted with the password `restic`. |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.