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 new Rust-based tests #2048

Merged
Merged
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
2 changes: 1 addition & 1 deletion .cci.jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ codestyle: {
// Build FCOS and do a kola basic run
stage("More builds and test") {
parallel fcos: {
cosaPod(runAsUser: 0, memory: "2048Mi", cpu: "2") {
cosaPod(buildroot: true, runAsUser: 0, memory: "3072Mi", cpu: "4") {
stage("Build FCOS") {
checkout scm
unstash 'build'
Expand Down
32 changes: 1 addition & 31 deletions tests/basic-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

set -euo pipefail

echo "1..$((89 + ${extra_basic_tests:-0}))"
echo "1..$((86 + ${extra_basic_tests:-0}))"

CHECKOUT_U_ARG=""
CHECKOUT_H_ARGS="-H"
Expand Down Expand Up @@ -1031,17 +1031,6 @@ stat '--format=%Y' test2-checkout/baz/deeper > deeper-mtime
assert_file_has_content deeper-mtime 0
echo "ok content mtime"

cd ${test_tmpdir}
rm -rf test2-checkout
mkdir -p test2-checkout
cd test2-checkout
mkfifo afifo
if $OSTREE commit ${COMMIT_ARGS} -b test2 -s "Attempt to commit a FIFO" 2>../errmsg; then
assert_not_reached "Committing a FIFO unexpetedly succeeded!"
assert_file_has_content ../errmsg "Unsupported file type"
fi
echo "ok commit of fifo was rejected"

cd ${test_tmpdir}
rm repo2 -rf
mkdir repo2
Expand Down Expand Up @@ -1180,22 +1169,3 @@ if test "$(id -u)" != "0"; then
else
echo "ok # SKIP not run when root"
fi

cd ${test_tmpdir}
rm -rf test2-checkout
mkdir -p test2-checkout
cd test2-checkout
touch blah
stat --printf="%.Y\n" ${test_tmpdir}/repo > ${test_tmpdir}/timestamp-orig.txt
$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Should bump the mtime"
stat --printf="%.Y\n" ${test_tmpdir}/repo > ${test_tmpdir}/timestamp-new.txt
cd ..
if cmp timestamp-{orig,new}.txt; then
assert_not_reached "failed to update mtime on repo"
fi
echo "ok mtime updated"

cd ${test_tmpdir}
$OSTREE init --mode=bare --repo=repo-extensions
assert_has_dir repo-extensions/extensions
echo "ok extensions dir"
2 changes: 2 additions & 0 deletions tests/inst/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/

Choose a reason for hiding this comment

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

Suggested change
target/
/target

rust-lang/cargo#4944

Cargo.lock
42 changes: 42 additions & 0 deletions tests/inst/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[package]
name = "ostree-test"
version = "0.1.0"
authors = ["Colin Walters <walters@verbum.org>"]
edition = "2018"

[[bin]]
name = "ostree-test"
path = "src/insttest.rs"

[dependencies]
clap = "2.32.0"
structopt = "0.2"
commandspec = "0.12.2"
anyhow = "1.0"
tempfile = "3.1.0"
gio = "0.8"
ostree = { version = "0.7.1", features = ["v2020_1"] }
libtest-mimic = "0.2.0"
twoway = "0.2.1"
hyper = "0.13"
futures = "0.3.4"
http = "0.2.0"
hyper-staticfile = "0.5.1"
tokio = { version = "0.2", features = ["full"] }
futures-util = "0.3.1"
base64 = "0.12.0"
procspawn = "0.8"
proc-macro2 = "0.4"
quote = "0.6"
syn = "0.15"
linkme = "0.2"

itest-macro = { path = "itest-macro" }

with-procspawn-tempdir = { git = "https://github.com/cgwalters/with-procspawn-tempdir" }
#with-procspawn-tempdir = { path = "/var/srv/walters/src/github/cgwalters/with-procspawn-tempdir" }

# See https://github.com/tcr/commandspec/pulls?q=is%3Apr+author%3Acgwalters+
[patch.crates-io]
commandspec = { git = "https://github.com/cgwalters/commandspec", branch = 'walters-master' }
#commandspec = { path = "/var/srv/walters/src/github/tcr/commandspec" }
14 changes: 14 additions & 0 deletions tests/inst/itest-macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "itest-macro"
version = "0.1.0"
edition = "2018"

[lib]
proc-macro = true
path = "src/itest-macro.rs"

[dependencies]
quote = "1.0.3"
proc-macro2 = "1.0.10"
syn = { version = "1.0.3", features = ["full"] }
anyhow = "1.0"
32 changes: 32 additions & 0 deletions tests/inst/itest-macro/src/itest-macro.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;

/// Wraps function using `procspawn` to allocate a new temporary directory,
/// make it the process' working directory, and run the function.
#[proc_macro_attribute]
pub fn itest(attrs: TokenStream, input: TokenStream) -> TokenStream {
let attrs = syn::parse_macro_input!(attrs as syn::AttributeArgs);
if attrs.len() > 0 {
return syn::Error::new_spanned(&attrs[0], "itest takes no attributes")
.to_compile_error()
.into();
}
let func = syn::parse_macro_input!(input as syn::ItemFn);
let fident = func.sig.ident.clone();
let varident = quote::format_ident!("ITEST_{}", fident);
let fidentstrbuf = format!(r#"{}"#, fident);
let fidentstr = syn::LitStr::new(&fidentstrbuf, Span::call_site());
let output = quote! {
#[linkme::distributed_slice(TESTS)]
#[allow(non_upper_case_globals)]
static #varident : Test = Test {
name: #fidentstr,
f: #fident,
};
#func
};
output.into()
}
46 changes: 46 additions & 0 deletions tests/inst/src/insttest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use anyhow::Result;
// use structopt::StructOpt;
// // https://github.com/clap-rs/clap/pull/1397
// #[macro_use]
// extern crate clap;

mod repobin;
mod sysroot;
mod test;

fn gather_tests() -> Vec<test::TestImpl> {
test::TESTS
.iter()
.map(|t| libtest_mimic::Test {
name: t.name.into(),
kind: "".into(),
is_ignored: false,
is_bench: false,
data: t,
})
.collect()
}

fn run_test(test: &test::TestImpl) -> libtest_mimic::Outcome {
if let Err(e) = (test.data.f)() {
libtest_mimic::Outcome::Failed {
msg: Some(e.to_string()),
}
} else {
libtest_mimic::Outcome::Passed
}
}

fn main() -> Result<()> {
procspawn::init();

// Ensure we're always in tempdir so we can rely on it globally
let tmp_dir = tempfile::Builder::new()
.prefix("ostree-insttest-top")
.tempdir()?;
std::env::set_current_dir(tmp_dir.path())?;

let args = libtest_mimic::Arguments::from_args();
let tests = gather_tests();
libtest_mimic::run_tests(&args, tests, run_test).exit();
}
121 changes: 121 additions & 0 deletions tests/inst/src/repobin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//! Tests that mostly use the CLI and operate on temporary
//! repositories.

use std::path::Path;

use crate::test::*;
use anyhow::{Context, Result};
use commandspec::{sh_command, sh_execute};
use tokio::runtime::Runtime;
use with_procspawn_tempdir::with_procspawn_tempdir;

#[itest]
fn test_basic() -> Result<()> {
sh_execute!(r"ostree --help >/dev/null")?;
Ok(())
}

#[itest]
#[with_procspawn_tempdir]
fn test_nofifo() -> Result<()> {
assert!(std::path::Path::new(".procspawn-tmpdir").exists());
sh_execute!(
r"ostree --repo=repo init --mode=archive
mkdir tmproot
mkfifo tmproot/afile
"
)?;
cmd_fails_with(
sh_command!(
r#"ostree --repo=repo commit -b fifotest -s "commit fifo" --tree=dir=./tmproot"#
)
.unwrap(),
"Not a regular file or symlink",
)?;
Ok(())
}

#[itest]
#[with_procspawn_tempdir]
fn test_mtime() -> Result<()> {
sh_execute!(
r"ostree --repo=repo init --mode=archive
mkdir tmproot
echo afile > tmproot/afile
ostree --repo=repo commit -b test --tree=dir=tmproot >/dev/null
"
)?;
let ts = Path::new("repo").metadata()?.modified().unwrap();
sh_execute!(
r#"ostree --repo=repo commit -b test -s "bump mtime" --tree=dir=tmproot >/dev/null"#
)?;
assert_ne!(ts, Path::new("repo").metadata()?.modified().unwrap());
Ok(())
}

#[itest]
#[with_procspawn_tempdir]
fn test_extensions() -> Result<()> {
sh_execute!(r"ostree --repo=repo init --mode=bare")?;
assert!(Path::new("repo/extensions").exists());
Ok(())
}

async fn impl_test_pull_basicauth() -> Result<()> {
let opts = TestHttpServerOpts {
basicauth: true,
..Default::default()
};
let serverrepo = Path::new("server/repo");
std::fs::create_dir_all(&serverrepo)?;
let addr = http_server(&serverrepo, opts).await?;
tokio::task::spawn_blocking(move || -> Result<()> {
let baseuri = http::Uri::from_maybe_shared(format!("http://{}/", addr).into_bytes())?;
let unauthuri =
http::Uri::from_maybe_shared(format!("http://unknown:badpw@{}/", addr).into_bytes())?;
let authuri = http::Uri::from_maybe_shared(
format!("http://{}@{}/", TEST_HTTP_BASIC_AUTH, addr).into_bytes(),
)?;
let osroot = Path::new("osroot");
mkroot(&osroot)?;
sh_execute!(
r#"ostree --repo={serverrepo} init --mode=archive
ostree --repo={serverrepo} commit -b os --tree=dir={osroot} >/dev/null
mkdir client
cd client
ostree --repo=repo init --mode=archive
ostree --repo=repo remote add --set=gpg-verify=false origin-unauth {baseuri}
ostree --repo=repo remote add --set=gpg-verify=false origin-badauth {unauthuri}
ostree --repo=repo remote add --set=gpg-verify=false origin-goodauth {authuri}
"#,
osroot = osroot.to_str(),
serverrepo = serverrepo.to_str(),
baseuri = baseuri.to_string(),
unauthuri = unauthuri.to_string(),
authuri = authuri.to_string()
Comment on lines +91 to +95
Copy link
Member

Choose a reason for hiding this comment

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

I wish Rust had Python-style string interpolation.

Oh hey, looks like there's a crate for that!
https://crates.io/crates/ifmt

Want to try that out? Should make it nicer to hack on. (Not a blocker of course.)

Copy link
Member Author

Choose a reason for hiding this comment

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

I was more thinking of adding this to the commandspec crate (which we are forking right now because the maintainer is unresponsive). Though the implementation of that could indeed be ifmt perhaps?

)?;
for rem in &["unauth", "badauth"] {
cmd_fails_with(
sh_command!(
r#"ostree --repo=client/repo pull origin-{rem} os >/dev/null"#,
rem = *rem
)
.unwrap(),
"HTTP 403",
)
.context(rem)?;
}
sh_execute!(r#"ostree --repo=client/repo pull origin-goodauth os >/dev/null"#,)?;
Ok(())
})
.await??;
Ok(())
}

#[itest]
#[with_procspawn_tempdir]
fn test_pull_basicauth() -> Result<()> {
let mut rt = Runtime::new()?;
rt.block_on(async move { impl_test_pull_basicauth().await })?;
Ok(())
}
33 changes: 33 additions & 0 deletions tests/inst/src/sysroot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//! Tests that mostly use the API and access the booted sysroot read-only.

use anyhow::Result;
use gio::prelude::*;
use ostree::prelude::*;

use crate::test::*;

#[itest]
fn test_sysroot_ro() -> Result<()> {
// TODO add a skipped identifier
if !std::path::Path::new("/run/ostree-booted").exists() {
return Ok(());
}
let cancellable = Some(gio::Cancellable::new());
let sysroot = ostree::Sysroot::new_default();
sysroot.load(cancellable.as_ref())?;
assert!(sysroot.is_booted());

let booted = sysroot.get_booted_deployment().expect("booted deployment");
assert!(!booted.is_staged());
let repo = sysroot.repo().expect("repo");

let csum = booted.get_csum().expect("booted csum");
let csum = csum.as_str();

let (root, rev) = repo.read_commit(csum, cancellable.as_ref())?;
assert_eq!(rev, csum);
let root = root.downcast::<ostree::RepoFile>().expect("downcast");
root.ensure_resolved()?;

Ok(())
}
Loading