-
Notifications
You must be signed in to change notification settings - Fork 297
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
Add new Rust-based tests #2048
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
target/ | ||
Cargo.lock |
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" } |
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" |
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() | ||
} |
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(); | ||
} |
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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! Want to try that out? Should make it nicer to hack on. (Not a blocker of course.) There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
)?; | ||
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(()) | ||
} |
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(()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rust-lang/cargo#4944