I was reading this thread
https://internals.rust-lang.org/t/from-life-before-main-to-common-life-in-main/16006/30
and that reminded me about this code, which it turns out actually
doesn't compile with my default local cargo config:
```
$ cat ~/.cargo/config
[target.x86_64-unknown-linux-gnu]
rustflags = ["-Ctarget-cpu=native", "-C", "link-arg=-fuse-ld=lld"]
[profile.release]
incremental = true
$ cargo b
...
error: linking with `cc` failed: exit status: 1
|
= note: "cc" "-m64" "/var/srv/walters/src/github/ostreedev/ostree/target/debug/deps/ostree_test-
4ca8e730f9dc6ffc.10325uqlhkyr5uol.rcgu.o" "/var/srv/walte"
= note: ld.lld: error: undefined symbol: __start_linkme_NONDESTRUCTIVE_TESTS
>>> referenced by 22nn09lfsklfqvyy
>>> /var/srv/walters/src/github/ostreedev/ostree/target/debug/deps/ostree_test-
4ca8e730f9dc6ffc.22nn09lfsklfqvyy.rcgu.o:(ostree_tes)
```
For now let's just go back to having a static list of functions.
We don't have *too* many of those.
base64 = "0.12.0"
procspawn = "0.8"
rand = "0.7.3"
-linkme = "0.2"
strum = "0.18.0"
strum_macros = "0.18.0"
openat = "0.1.19"
# This one I might publish to crates.io, not sure yet
with-procspawn-tempdir = { git = "https://github.com/cgwalters/with-procspawn-tempdir" }
-
-# Internal crate for the test macro
-itest-macro = { path = "itest-macro" }
+++ /dev/null
-[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"
+++ /dev/null
-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() > 1 {
- return syn::Error::new_spanned(&attrs[1], "itest takes 0 or 1 attributes")
- .to_compile_error()
- .into();
- }
- let destructive = match attrs.get(0) {
- Some(syn::NestedMeta::Meta(syn::Meta::NameValue(namevalue))) => {
- if let Some(name) = namevalue.path.get_ident().map(|i| i.to_string()) {
- if name == "destructive" {
- match &namevalue.lit {
- syn::Lit::Bool(v) => v.value,
- _ => {
- return syn::Error::new_spanned(
- &attrs[1],
- format!("destructive must be bool {}", name),
- )
- .to_compile_error()
- .into();
- }
- }
- } else {
- return syn::Error::new_spanned(
- &attrs[1],
- format!("Unknown argument {}", name),
- )
- .to_compile_error()
- .into();
- }
- } else {
- false
- }
- }
- Some(v) => {
- return syn::Error::new_spanned(&v, "Unexpected argument")
- .to_compile_error()
- .into()
- }
- None => false,
- };
- 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 testident = if destructive {
- quote::format_ident!("{}", "DESTRUCTIVE_TESTS")
- } else {
- quote::format_ident!("{}", "NONDESTRUCTIVE_TESTS")
- };
- let output = quote! {
- #[linkme::distributed_slice(#testident)]
- #[allow(non_upper_case_globals)]
- static #varident : Test = Test {
- name: #fidentstr,
- f: #fident,
- };
- #func
- };
- output.into()
-}
}
}
-#[itest(destructive = true)]
-fn transactionality() -> Result<()> {
+pub(crate) fn itest_transactionality() -> Result<()> {
testinit()?;
let mark = get_reboot_mark()?;
let cancellable = Some(gio::Cancellable::new());
// Written by Ignition
const DESTRUCTIVE_TEST_STAMP: &str = "/etc/ostree-destructive-test-ok";
+macro_rules! test {
+ ($f: path) => {
+ (stringify!($f), $f)
+ };
+}
+
+type StaticTest = (&'static str, fn() -> Result<()>);
+
+const TESTS: &[StaticTest] = &[
+ test!(sysroot::itest_sysroot_ro),
+ test!(sysroot::itest_immutable_bit),
+ test!(sysroot::itest_tmpfiles),
+ test!(repobin::itest_basic),
+ test!(repobin::itest_nofifo),
+ test!(repobin::itest_extensions),
+ test!(repobin::itest_pull_basicauth),
+];
+const DESTRUCTIVE_TESTS: &[StaticTest] = &[test!(destructive::itest_transactionality)];
+
#[derive(Debug, StructOpt)]
#[structopt(rename_all = "kebab-case")]
#[allow(clippy::enum_variant_names)]
Args(Vec<String>),
}
-fn libtest_from_test(t: &'static test::Test) -> test::TestImpl {
+fn libtest_from_test(t: &StaticTest) -> test::TestImpl {
libtest_mimic::Test {
- name: t.name.into(),
+ name: t.0.into(),
kind: "".into(),
is_ignored: false,
is_bench: false,
- data: t,
+ data: t.1,
}
}
fn run_test(test: &test::TestImpl) -> libtest_mimic::Outcome {
- if let Err(e) = (test.data.f)() {
+ if let Err(e) = (test.data)() {
libtest_mimic::Outcome::Failed {
msg: Some(e.to_string()),
}
match opt {
Opt::ListDestructive => {
- for t in test::DESTRUCTIVE_TESTS.iter() {
- println!("{}", t.name);
+ for t in DESTRUCTIVE_TESTS {
+ println!("{}", t.0);
}
Ok(())
}
// FIXME add method to parse subargs
let NonDestructiveOpts::Args(iter) = subopt;
let libtestargs = libtest_mimic::Arguments::from_iter(iter);
- let tests: Vec<_> = test::NONDESTRUCTIVE_TESTS
- .iter()
- .map(libtest_from_test)
- .collect();
+ let tests: Vec<_> = TESTS.iter().map(libtest_from_test).collect();
libtest_mimic::run_tests(&libtestargs, tests, run_test).exit();
}
Opt::RunDestructive { name } => {
bail!("An ostree-based host is required")
}
- for t in test::DESTRUCTIVE_TESTS.iter() {
- if t.name == name {
- (t.f)()?;
- println!("ok destructive test: {}", t.name);
+ for (tname, f) in DESTRUCTIVE_TESTS {
+ if *tname == name.as_str() {
+ (f)()?;
+ println!("ok destructive test: {}", tname);
return Ok(());
}
}
use sh_inline::{bash, bash_command};
use with_procspawn_tempdir::with_procspawn_tempdir;
-#[itest]
-fn test_basic() -> Result<()> {
+pub(crate) fn itest_basic() -> Result<()> {
bash!(r"ostree --help >/dev/null")?;
Ok(())
}
-#[itest]
#[with_procspawn_tempdir]
-fn test_nofifo() -> Result<()> {
+pub(crate) fn itest_nofifo() -> Result<()> {
assert!(std::path::Path::new(".procspawn-tmpdir").exists());
bash!(
r"ostree --repo=repo init --mode=archive
Ok(())
}
-#[itest]
#[with_procspawn_tempdir]
-fn test_mtime() -> Result<()> {
+pub(crate) fn itest_mtime() -> Result<()> {
bash!(
r"ostree --repo=repo init --mode=archive
mkdir tmproot
Ok(())
}
-#[itest]
#[with_procspawn_tempdir]
-fn test_extensions() -> Result<()> {
+pub(crate) fn itest_extensions() -> Result<()> {
bash!(r"ostree --repo=repo init --mode=bare")?;
assert!(Path::new("repo/extensions").exists());
Ok(())
}
-#[itest]
#[with_procspawn_tempdir]
-fn test_pull_basicauth() -> Result<()> {
+pub(crate) fn itest_pull_basicauth() -> Result<()> {
let opts = TestHttpServerOpts {
basicauth: true,
..Default::default()
!std::path::Path::new("/run/ostree-booted").exists()
}
-#[itest]
-fn test_sysroot_ro() -> Result<()> {
+pub(crate) fn itest_sysroot_ro() -> Result<()> {
// TODO add a skipped identifier
if skip_non_ostree_host() {
return Ok(());
Ok(())
}
-#[itest]
-fn test_immutable_bit() -> Result<()> {
+pub(crate) fn itest_immutable_bit() -> Result<()> {
if skip_non_ostree_host() {
return Ok(());
}
Ok(())
}
-#[itest]
-fn test_tmpfiles() -> Result<()> {
+pub(crate) fn itest_tmpfiles() -> Result<()> {
if skip_non_ostree_host() {
return Ok(());
}
use std::time;
use anyhow::{bail, Context, Result};
-use linkme::distributed_slice;
use rand::Rng;
-pub use itest_macro::itest;
pub use with_procspawn_tempdir::with_procspawn_tempdir;
// HTTP Server deps
use tokio::runtime::Runtime;
pub(crate) type TestFn = fn() -> Result<()>;
-
-#[derive(Debug)]
-pub(crate) struct Test {
- pub(crate) name: &'static str,
- pub(crate) f: TestFn,
-}
-
-pub(crate) type TestImpl = libtest_mimic::Test<&'static Test>;
-
-#[distributed_slice]
-pub(crate) static NONDESTRUCTIVE_TESTS: [Test] = [..];
-#[distributed_slice]
-pub(crate) static DESTRUCTIVE_TESTS: [Test] = [..];
+pub(crate) type TestImpl = libtest_mimic::Test<TestFn>;
/// Run command and assert that its stderr contains pat
pub(crate) fn cmd_fails_with<C: BorrowMut<Command>>(mut c: C, pat: &str) -> Result<()> {