Skip to content

Commit

Permalink
tests: add the first integration test
Browse files Browse the repository at this point in the history
...and make various adjustments around src/, mostly with regards to
correct types of arguments.
  • Loading branch information
allisonkarlitskaya committed Oct 11, 2024
1 parent 12facff commit fe05ac9
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 32 deletions.
3 changes: 2 additions & 1 deletion src/bin/cfsctl.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::path::PathBuf;
use anyhow::Result;
use clap::{Parser, Subcommand};

Expand All @@ -16,7 +17,7 @@ use composefs_experiments::{
#[clap(name = "cfsctl", version)]
pub struct App {
#[clap(long, group="repopath")]
repo: Option<String>,
repo: Option<PathBuf>,
#[clap(long, group="repopath")]
user: bool,
#[clap(long, group="repopath")]
Expand Down
3 changes: 2 additions & 1 deletion src/bin/mount.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::path::PathBuf;
use clap::Parser;

use composefs_experiments::mount::MountOptions;
Expand All @@ -13,7 +14,7 @@ struct Args {
mountpoint: String,

#[arg(short, long)]
basedir: String,
basedir: PathBuf,

#[arg(short, long)]
digest: Option<String>,
Expand Down
19 changes: 11 additions & 8 deletions src/mount.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::os::fd::{
OwnedFd,
BorrowedFd,
AsFd,
AsRawFd
use std::{
path::Path,
os::fd::{
OwnedFd,
BorrowedFd,
AsFd,
AsRawFd,
},
};

use anyhow::Result;
Expand Down Expand Up @@ -78,7 +81,7 @@ fn proc_self_fd<A: AsFd>(fd: A) -> String {
format!("/proc/self/fd/{}", fd.as_fd().as_raw_fd())
}

pub fn mount_fd<F: AsFd>(image: F, basedir: &str, mountpoint: &str) -> Result<()> {
pub fn mount_fd<F: AsFd>(image: F, basedir: &Path, mountpoint: &str) -> Result<()> {
let erofs = FsHandle::open("erofs")?;
fsconfig_set_string(erofs.as_fd(), "source", proc_self_fd(&image))?;
fsconfig_create(erofs.as_fd())?;
Expand All @@ -101,13 +104,13 @@ pub fn mount_fd<F: AsFd>(image: F, basedir: &str, mountpoint: &str) -> Result<()

pub struct MountOptions<'a> {
image: &'a str,
basedir: &'a str,
basedir: &'a Path,
digest: Option<&'a str>,
verity: bool,
}

impl<'a> MountOptions<'a> {
pub fn new(image: &'a str, basedir: &'a str) -> MountOptions<'a> {
pub fn new(image: &'a str, basedir: &'a Path) -> MountOptions<'a> {
MountOptions { image, basedir, digest: None, verity: false }
}

Expand Down
24 changes: 12 additions & 12 deletions src/oci/tar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,24 +117,13 @@ fn symlink_target_from_tar(pax: Option<Vec<u8>>, gnu: Vec<u8>, short: &[u8]) ->
}
}

fn get_entry<R: Read>(reader: &mut SplitStreamReader<R>) -> Result<Option<Entry<'static>>> {
pub fn get_entry<R: Read>(reader: &mut SplitStreamReader<R>) -> Result<Option<Entry<'static>>> {
let mut gnu_longlink: Vec<u8> = vec![];
let mut gnu_longname: Vec<u8> = vec![];
let mut pax_longlink: Option<Vec<u8>> = None;
let mut pax_longname: Option<Vec<u8>> = None;
let mut xattrs = vec![];

// no root entry in the tar
println!("{}", Entry {
path: Cow::Borrowed(Path::new("/")),
uid: 0,
gid: 0,
mode: FileType::Directory.as_raw_mode() | 0o755,
mtime: Mtime { sec: 0, nsec: 0 },
item: Item::Directory { size: 0, nlink: 1 },
xattrs: vec![]
});

loop {
let mut buf = [0u8; 512];
if !reader.read_inline_exact(&mut buf)? || buf == [0u8; 512] {
Expand Down Expand Up @@ -250,6 +239,17 @@ fn get_entry<R: Read>(reader: &mut SplitStreamReader<R>) -> Result<Option<Entry<
}

pub fn ls<R: Read>(split_stream: &mut R) -> Result<()> {
// no root entry in the tar
println!("{}", Entry {
path: Cow::Borrowed(Path::new("/")),
uid: 0,
gid: 0,
mode: FileType::Directory.as_raw_mode() | 0o755,
mtime: Mtime { sec: 0, nsec: 0 },
item: Item::Directory { size: 0, nlink: 1 },
xattrs: vec![]
});

let mut reader = SplitStreamReader::new(split_stream);
while let Some(entry) = get_entry(&mut reader)? {
println!("{}", entry);
Expand Down
18 changes: 9 additions & 9 deletions src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ use crate::{

pub struct Repository {
repository: OwnedFd,
path: String,
path: PathBuf,
}

impl Drop for Repository {
Expand All @@ -73,13 +73,13 @@ impl Drop for Repository {
}

impl Repository {
pub fn open_path(path: String) -> Result<Repository> {
pub fn open_path(path: PathBuf) -> Result<Repository> {
// O_PATH isn't enough because flock()
let repository = open(&path, OFlags::RDONLY, Mode::empty())
.with_context(|| format!("Cannot open composefs repository '{path}'"))?;
.with_context(|| format!("Cannot open composefs repository {path:?}"))?;

flock(&repository, FlockOperation::LockShared).
with_context(|| format!("Cannot lock repository '{path}'"))?;
with_context(|| format!("Cannot lock repository {path:?}"))?;

Ok(Repository { repository, path })
}
Expand All @@ -88,11 +88,11 @@ impl Repository {
let home = std::env::var("HOME")
.with_context(|| "$HOME must be set when in user mode")?;

Repository::open_path(format!("{}/.var/lib/composefs", home))
Repository::open_path(PathBuf::from(home).join(".var/lib/composefs"))
}

pub fn open_system() -> Result<Repository> {
Repository::open_path("/sysroot/composefs".to_string())
Repository::open_path(PathBuf::from("/sysroot/composefs".to_string()))
}

fn ensure_parent<P: AsRef<Path>>(&self, path: P) -> Result<()> {
Expand Down Expand Up @@ -177,10 +177,10 @@ impl Repository {
let mut hash = Sha256HashValue::EMPTY;
let linkbytes = linkpath.to_bytes();
if linkbytes.len() != 67 || &linkbytes[0..3] != b"../" {
bail!("Incorrectly formatted symlink {}/{}", self.path, filename);
bail!("Incorrectly formatted symlink {:?}/{:?}", self.path, filename);
}
hex::decode_to_slice(&linkpath.to_bytes()[3..], &mut hash).
with_context(|| format!("Incorrectly formatted symlink {}/{}", self.path, filename))?;
with_context(|| format!("Incorrectly formatted symlink {:?}/{:?}", self.path, filename))?;
Ok(Some(hash))
}
}
Expand Down Expand Up @@ -294,7 +294,7 @@ impl Repository {

pub fn mount(self, name: &str, mountpoint: &str) -> Result<()> {
let image = self.open_in_category("images", name)?;
let object_path = format!("{}/objects", self.path);
let object_path = self.path.join("objects");
mount_fd(image, &object_path, mountpoint)
}

Expand Down
68 changes: 67 additions & 1 deletion tests/repo.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,69 @@
use std::{
fs::create_dir_all,
path::PathBuf,
fmt::Write,
};

use anyhow::{
Context,
Result,
};

use composefs_experiments::{
oci,
repository::Repository,
splitstream::SplitStreamReader,
};

fn append_data(builder: &mut tar::Builder<Vec<u8>>, name: &str, size: usize) -> Result<()> {
let mut header = tar::Header::new_ustar();
header.set_uid(0);
header.set_gid(0);
header.set_mode(0o700);
header.set_entry_type(tar::EntryType::Regular);
header.set_size(size as u64);
Ok(builder.append_data(&mut header, name, vec![0u8; size].as_slice())?)
}

fn example_layer() -> Result<Vec<u8>> {
let mut builder = tar::Builder::new(vec![]);
append_data(&mut builder, "file0", 0)?;
append_data(&mut builder, "file4095", 4095)?;
append_data(&mut builder, "file4096", 4096)?;
append_data(&mut builder, "file4097", 4097)?;
Ok(builder.into_inner()?)
}

fn home_var_tmp() -> Result<PathBuf> {
// We can't use /tmp because that's usually a tmpfs (no fsverity)
// We also can't use /var/tmp because it's an overlayfs in toolbox (no fsverity)
// So let's try something in the user's homedir?
let home = std::env::var("HOME")
.with_context(|| "$HOME must be set when in user mode")?;
let tmp = PathBuf::from(home).join(".var/tmp");
create_dir_all(&tmp)?;
Ok(tmp)
}

#[test]
fn test_repo() {
fn test_layer() -> Result<()> {
let layer = example_layer()?;

let tmpfile = tempfile::TempDir::with_prefix_in("composefs-test-", home_var_tmp()?)?;
let repo = Repository::open_path(tmpfile.path().to_path_buf())?;
oci::import_layer(&repo, "name", &mut layer.as_slice())?;

let mut dump = String::new();
let mut split_stream = repo.open_stream("refs/name")?;
let mut reader = SplitStreamReader::new(&mut split_stream);
while let Some(entry) = oci::tar::get_entry(&mut reader)? {
writeln!(dump, "{}", entry)?;
}
assert_eq!(dump, "\
/file0 0 100700 1 0 0 0 0.0 - -
/file4095 4095 100700 1 0 0 0 0.0 - - 5372beb83c78537c8970c8361e3254119fafdf1763854ecd57d3f0fe2da7c719
/file4096 4096 100700 1 0 0 0 0.0 - - babc284ee4ffe7f449377fbf6692715b43aec7bc39c094a95878904d34bac97e
/file4097 4097 100700 1 0 0 0 0.0 - - 093756e4ea9683329106d4a16982682ed182c14bf076463a9e7f97305cbac743
");
Ok(())
}

0 comments on commit fe05ac9

Please sign in to comment.