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

service: add some unit test cases #1455

Merged
merged 3 commits into from
Nov 3, 2023
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
13 changes: 11 additions & 2 deletions .github/workflows/smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -610,9 +610,13 @@ jobs:
shared-key: nydus-build
- name: Install cargo nextest
uses: taiki-e/install-action@nextest
- name: Fscache Setup
run: sudo bash misc/fscache/setup.sh
- name: Unit Test
run: |
make ut-nextest
CARGO_HOME=${HOME}/.cargo
CARGO_BIN=$(which cargo)
sudo -E CARGO=${CARGO_BIN} make ut-nextest

nydus-unit-test-coverage:
runs-on: ubuntu-latest
Expand All @@ -626,8 +630,13 @@ jobs:
cache-on-failure: true
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Fscache Setup
imeoer marked this conversation as resolved.
Show resolved Hide resolved
run: sudo bash misc/fscache/setup.sh
- name: Generate code coverage
run: make coverage-codecov
run: |
CARGO_HOME=${HOME}/.cargo
CARGO_BIN=$(which cargo)
sudo -E CARGO=${CARGO_BIN} make coverage-codecov
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
Expand Down
20 changes: 20 additions & 0 deletions docs/nydus-fscache.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ $ sudo yum update kernel --enablerepo Plus
$ sudo reboot
```

## Enable fscache
imeoer marked this conversation as resolved.
Show resolved Hide resolved

1. ``[ -c /dev/cachefiles ] && echo ok`` to test fscache is enable or not. If your result shows `ok`, then fscache has been already enabled; otherwise, please follow the following steps to enable fscache.

2. Download cachefilesd package. For centos users, the command is:
```
sudo yum install cachefilesd
imeoer marked this conversation as resolved.
Show resolved Hide resolved
```

3. Start cachefilesd deamon.
```
sudo systemctl start cachefilesd
sudo systemctl status cachefilesd
```

4. Ensure the device file `/dev/cachefiles` is not occupied. If your result is not empty, please kill all processes the result shows.
```
sudo lsof /dev/cachefiles
```

## Get ctr-remote and the fscache-supported nydusd

1. Make sure you have installed _rust 1.52.1_ version and golang.
Expand Down
17 changes: 17 additions & 0 deletions misc/fscache/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

# This script should be executed in root mode!

apt update
apt install -y cachefilesd
apt list --installed | grep cachefilesd
chmod a+w /etc/default/cachefilesd
sed -i 's/#RUN=yes/RUN=yes/' /etc/default/cachefilesd
cat /etc/default/cachefilesd
/sbin/modprobe -qab cachefiles
/sbin/cachefilesd -f /etc/cachefilesd.conf
systemctl status cachefilesd
[ -c /dev/cachefiles ] && echo "cachefilesd is successfully enabled"
pid=$(lsof /dev/cachefiles | awk '{if (NR>1) {print $2}}')
kill -9 $pid
echo "/dev/cachefiles is available now"
4 changes: 4 additions & 0 deletions service/src/blob_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ mod tests {
is_tarfs_mode: false,
};
assert_eq!(blob.path(), &path);
assert_eq!(blob.blob_id(), "123456789-123");
}

#[test]
Expand Down Expand Up @@ -734,6 +735,9 @@ mod tests {
let blob_id = generate_blob_key(&entry.domain_id, &entry.blob_id);
assert!(mgr.get_config(&blob_id).is_some());

// add the same entry will trigger an error
assert!(mgr.add_blob_entry(&entry).is_err());

// Check existence of data blob referenced by the bootstrap.
let key = generate_blob_key(
&entry.domain_id,
Expand Down
195 changes: 156 additions & 39 deletions service/src/block_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,50 +539,16 @@ mod tests {
use super::*;
use crate::blob_cache::generate_blob_key;
use nydus_api::BlobCacheEntry;
use std::fs;
use nydus_utils::digest::{DigestHasher, RafsDigest};
use std::fs::{self, File};
use std::io::{BufReader, Read};
use std::path::PathBuf;
use vmm_sys_util::tempdir::TempDir;

#[test]
fn test_block_device() {
let tmpdir = TempDir::new().unwrap();
let root_dir = &std::env::var("CARGO_MANIFEST_DIR").expect("$CARGO_MANIFEST_DIR");
let mut source_path = PathBuf::from(root_dir);
source_path.push("../tests/texture/blobs/be7d77eeb719f70884758d1aa800ed0fb09d701aaec469964e9d54325f0d5fef");
let mut dest_path = tmpdir.as_path().to_path_buf();
dest_path.push("be7d77eeb719f70884758d1aa800ed0fb09d701aaec469964e9d54325f0d5fef");
fs::copy(&source_path, &dest_path).unwrap();

let mut source_path = PathBuf::from(root_dir);
source_path.push("../tests/texture/bootstrap/rafs-v6-2.2.boot");
let config = r#"
{
"type": "bootstrap",
"id": "rafs-v6",
"domain_id": "domain2",
"config_v2": {
"version": 2,
"id": "factory1",
"backend": {
"type": "localfs",
"localfs": {
"dir": "/tmp/nydus"
}
},
"cache": {
"type": "filecache",
"filecache": {
"work_dir": "/tmp/nydus"
}
},
"metadata_path": "RAFS_V5"
}
}"#;
let content = config
.replace("/tmp/nydus", tmpdir.as_path().to_str().unwrap())
.replace("RAFS_V5", &source_path.display().to_string());
let mut entry: BlobCacheEntry = serde_json::from_str(&content).unwrap();
assert!(entry.prepare_configuration_info());
let tmp_dir = TempDir::new().unwrap();
let entry = create_bootstrap_entry(&tmp_dir);

let mgr = BlobCacheMgr::new();
mgr.add_blob_entry(&entry).unwrap();
Expand All @@ -597,6 +563,8 @@ mod tests {
assert!(mgr.get_config(&key).is_some());

let mgr = Arc::new(mgr);
// assert with wrong blob_id
assert!(BlockDevice::new_with_cache_manager(String::from("blob_id"), mgr.clone()).is_err());
let device = BlockDevice::new_with_cache_manager(blob_id, mgr).unwrap();
assert_eq!(device.blocks(), 0x209);

Expand Down Expand Up @@ -642,4 +610,153 @@ mod tests {
assert!(res.is_err());
});
}

fn create_bootstrap_entry(tmp_dir: &TempDir) -> BlobCacheEntry {
let root_dir = &std::env::var("CARGO_MANIFEST_DIR").expect("$CARGO_MANIFEST_DIR");
let mut source_path = PathBuf::from(root_dir);
source_path.push("../tests/texture/blobs/be7d77eeb719f70884758d1aa800ed0fb09d701aaec469964e9d54325f0d5fef");
let mut dest_path = tmp_dir.as_path().to_path_buf();
dest_path.push("be7d77eeb719f70884758d1aa800ed0fb09d701aaec469964e9d54325f0d5fef");
fs::copy(&source_path, &dest_path).unwrap();

let mut source_path = PathBuf::from(root_dir);
source_path.push("../tests/texture/bootstrap/rafs-v6-2.2.boot");
let config = r#"
{
"type": "bootstrap",
"id": "rafs-v6",
"domain_id": "domain2",
"config_v2": {
"version": 2,
"id": "factory1",
"backend": {
"type": "localfs",
"localfs": {
"dir": "/tmp/nydus"
}
},
"cache": {
"type": "filecache",
"filecache": {
"work_dir": "/tmp/nydus"
}
},
"metadata_path": "RAFS_V5"
}
}"#;

// config with non-existing path
let entry: BlobCacheEntry = serde_json::from_str(&config).unwrap();
assert!(BlockDevice::new(entry).is_err());

// config with correct path
let content = config
.replace("/tmp/nydus", tmp_dir.as_path().to_str().unwrap())
.replace("RAFS_V5", &source_path.display().to_string());
let mut entry: BlobCacheEntry = serde_json::from_str(&content).unwrap();
assert!(entry.prepare_configuration_info());
entry
}

fn create_block_device() -> BlockDevice {
let tmp_dir = TempDir::new().unwrap();
let entry = create_bootstrap_entry(&tmp_dir);

let device = BlockDevice::new(entry);
assert!(device.is_ok());
let device = device.unwrap();
assert_eq!(device.blocks(), 0x209);

device
}

#[test]
fn test_block_size() {
let mut device = create_block_device();

assert!(!device.is_tarfs_mode);
assert_eq!(device.block_size(), EROFS_BLOCK_SIZE_4096);
assert_ne!(device.block_size(), EROFS_BLOCK_SIZE_512);

device.is_tarfs_mode = true;
assert_ne!(device.block_size(), EROFS_BLOCK_SIZE_4096);
assert_eq!(device.block_size(), EROFS_BLOCK_SIZE_512);
}

#[test]
fn test_size_to_blocks() {
let mut device = create_block_device();

assert!(!device.is_tarfs_mode);
assert_eq!(device.size_to_blocks(0), 0);
assert_eq!(device.size_to_blocks(4096), 1);
assert_ne!(device.size_to_blocks(4096), 4096);
assert_ne!(device.size_to_blocks(4096), 8);

device.is_tarfs_mode = true;
assert_eq!(device.size_to_blocks(0), 0);
assert_eq!(device.size_to_blocks(512), 1);
assert_ne!(device.size_to_blocks(512), 512);
assert_ne!(device.size_to_blocks(4096), 1);
}

#[test]
fn test_blocks_to_size() {
let mut device = create_block_device();

assert!(!device.is_tarfs_mode);
assert_eq!(device.blocks_to_size(0), 0);
assert_eq!(device.blocks_to_size(1), 4096);
assert_ne!(device.blocks_to_size(4096), 4096);
assert_ne!(device.blocks_to_size(8), 4096);

device.is_tarfs_mode = true;
assert_eq!(device.blocks_to_size(0), 0);
assert_eq!(device.blocks_to_size(1), 512);
assert_ne!(device.blocks_to_size(512), 512);
assert_ne!(device.blocks_to_size(1), 4096);
}

fn sha256_digest<R: Read>(mut reader: R) -> Result<String> {
let mut hasher = RafsDigest::hasher(digest::Algorithm::Sha256);
let mut buffer = [0; 1024];

loop {
let count = reader.read(&mut buffer)?;
if count == 0 {
break;
}
hasher.digest_update(&buffer[..count]);
}

Ok(hasher.digest_finalize().into())
}

fn test_export_arg_thread(thread: u32) -> Result<()> {
let entry_tmp_dir = TempDir::new()?;
let entry = create_bootstrap_entry(&entry_tmp_dir);

let tmp_dir = TempDir::new().unwrap();
let data_dir = Some(String::from(tmp_dir.as_path().to_str().unwrap()));

assert!(BlockDevice::export(entry, None, data_dir, thread, true).is_ok());

let mut disk_path = PathBuf::from(tmp_dir.as_path());
disk_path.push("rafs-v6-2.2.boot.disk");
let input = File::open(disk_path)?;
let reader = BufReader::new(input);
let sha256 = sha256_digest(reader)?;
assert_eq!(
sha256,
String::from("5684c330c622350c12d633d0773201f862b9955375d806670e1aaf36ef038b31")
);

Ok(())
}

#[test]
fn test_export() {
assert!(test_export_arg_thread(1).is_ok());
assert!(test_export_arg_thread(2).is_ok());
}
}
67 changes: 67 additions & 0 deletions service/src/fs_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -976,4 +976,71 @@ mod tests {
FsCacheMsgHeader::try_from(vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0].as_slice()).unwrap_err();
FsCacheMsgHeader::try_from(vec![].as_slice()).unwrap_err();
}

#[test]
fn test_fs_cache_msg_open_try_from() {
// request message size too small
assert!(FsCacheMsgOpen::try_from(
vec![1u8, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 2u8, 0, 0].as_slice()
)
.is_err());

// volume key size or cookie key size too large
assert!(FsCacheMsgOpen::try_from(
vec![255u8, 127, 127, 127, 255, 127, 127, 255, 17, 0, 0, 0, 2u8, 0, 0, 0, 4u8, 0, 0, 0]
.as_slice()
)
.is_err());
assert!(FsCacheMsgOpen::try_from(
vec![
255u8, 127, 127, 127, 241u8, 127, 128, 128, 17, 0, 0, 0, 2u8, 0, 0, 0, 4u8, 0, 0,
0,
]
.as_slice()
)
.is_err());

// value size too small
assert!(FsCacheMsgOpen::try_from(
vec![1u8, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 2u8, 0, 0, 0, 0].as_slice()
)
.is_err());

let res = FsCacheMsgOpen::try_from(
vec![
1u8, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 2u8, 0, 0, 0, 4u8, 0, 0, 0,
]
.as_slice(),
);
assert!(res.is_ok());
assert_eq!(
res.unwrap(),
FsCacheMsgOpen {
volume_key: String::from("\u{4}"),
cookie_key: String::from("\0\0"),
fd: 17,
flags: 2
}
);
}

#[test]
fn test_fs_cache_msg_read_try_from() {
assert!(FsCacheMsgRead::try_from(
vec![1u8, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 2u8, 0, 0].as_slice()
)
.is_err());

let res = FsCacheMsgRead::try_from(
vec![1u8, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 2u8, 0, 0, 0].as_slice(),
);
assert!(res.is_ok());
assert_eq!(
res.unwrap(),
FsCacheMsgRead {
off: 8589934593,
len: 8589934609,
}
);
}
}
Loading