2023-02-13 16:44:26 +01:00
|
|
|
use crate::blobservice::BlobService;
|
|
|
|
use crate::blobservice::SledBlobService;
|
|
|
|
use crate::chunkservice::ChunkService;
|
|
|
|
use crate::chunkservice::SledChunkService;
|
|
|
|
use crate::directoryservice::DirectoryService;
|
|
|
|
use crate::directoryservice::SledDirectoryService;
|
|
|
|
use crate::nar::NARRenderer;
|
2023-01-29 20:48:23 +01:00
|
|
|
use crate::proto;
|
|
|
|
use crate::proto::DirectoryNode;
|
|
|
|
use crate::proto::FileNode;
|
|
|
|
use crate::proto::SymlinkNode;
|
|
|
|
use lazy_static::lazy_static;
|
2023-02-13 16:44:26 +01:00
|
|
|
use std::path::Path;
|
|
|
|
use tempfile::TempDir;
|
2023-01-29 20:48:23 +01:00
|
|
|
|
|
|
|
const HELLOWORLD_BLOB_CONTENTS: &[u8] = b"Hello World!";
|
|
|
|
const EMPTY_BLOB_CONTENTS: &[u8] = b"";
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
static ref HELLOWORLD_BLOB_DIGEST: Vec<u8> =
|
|
|
|
blake3::hash(HELLOWORLD_BLOB_CONTENTS).as_bytes().to_vec();
|
|
|
|
static ref EMPTY_BLOB_DIGEST: Vec<u8> = blake3::hash(EMPTY_BLOB_CONTENTS).as_bytes().to_vec();
|
|
|
|
static ref DIRECTORY_WITH_KEEP: proto::Directory = proto::Directory {
|
|
|
|
directories: vec![],
|
|
|
|
files: vec![FileNode {
|
|
|
|
name: ".keep".to_string(),
|
|
|
|
digest: EMPTY_BLOB_DIGEST.to_vec(),
|
|
|
|
size: 0,
|
|
|
|
executable: false,
|
|
|
|
}],
|
|
|
|
symlinks: vec![],
|
|
|
|
};
|
|
|
|
static ref DIRECTORY_COMPLICATED: proto::Directory = proto::Directory {
|
|
|
|
directories: vec![DirectoryNode {
|
|
|
|
name: "keep".to_string(),
|
|
|
|
digest: DIRECTORY_WITH_KEEP.digest(),
|
|
|
|
size: DIRECTORY_WITH_KEEP.size(),
|
|
|
|
}],
|
|
|
|
files: vec![FileNode {
|
|
|
|
name: ".keep".to_string(),
|
|
|
|
digest: EMPTY_BLOB_DIGEST.to_vec(),
|
|
|
|
size: 0,
|
|
|
|
executable: false,
|
|
|
|
}],
|
|
|
|
symlinks: vec![SymlinkNode {
|
|
|
|
name: "aa".to_string(),
|
|
|
|
target: "/nix/store/somewhereelse".to_string(),
|
|
|
|
}],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-13 16:44:26 +01:00
|
|
|
fn gen_blob_service(p: &Path) -> impl BlobService {
|
|
|
|
SledBlobService::new(p.join("blobs")).unwrap()
|
2023-01-29 20:48:23 +01:00
|
|
|
}
|
|
|
|
|
2023-02-13 16:44:26 +01:00
|
|
|
fn gen_chunk_service(p: &Path) -> impl ChunkService + Clone {
|
|
|
|
SledChunkService::new(p.join("chunks")).unwrap()
|
2023-01-29 20:48:23 +01:00
|
|
|
}
|
|
|
|
|
2023-02-13 16:44:26 +01:00
|
|
|
fn gen_directory_service(p: &Path) -> impl DirectoryService {
|
|
|
|
SledDirectoryService::new(p.join("directories")).unwrap()
|
2023-01-29 20:48:23 +01:00
|
|
|
}
|
|
|
|
|
2023-02-13 16:44:26 +01:00
|
|
|
#[test]
|
|
|
|
fn single_symlink() -> anyhow::Result<()> {
|
|
|
|
let tmpdir = TempDir::new()?;
|
|
|
|
let renderer = NARRenderer::new(
|
|
|
|
gen_blob_service(tmpdir.path()),
|
|
|
|
gen_chunk_service(tmpdir.path()),
|
|
|
|
gen_directory_service(tmpdir.path()),
|
|
|
|
);
|
|
|
|
// don't put anything in the stores, as we don't actually do any requests.
|
|
|
|
|
2023-01-29 20:48:23 +01:00
|
|
|
let mut buf: Vec<u8> = vec![];
|
|
|
|
|
2023-02-13 16:44:26 +01:00
|
|
|
renderer
|
|
|
|
.write_nar(
|
|
|
|
&mut buf,
|
|
|
|
crate::proto::node::Node::Symlink(SymlinkNode {
|
|
|
|
name: "doesntmatter".to_string(),
|
|
|
|
target: "/nix/store/somewhereelse".to_string(),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.expect("must succeed");
|
2023-01-29 20:48:23 +01:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
buf,
|
|
|
|
vec![
|
|
|
|
13, 0, 0, 0, 0, 0, 0, 0, 110, 105, 120, 45, 97, 114, 99, 104, 105, 118, 101, 45, 49, 0,
|
|
|
|
0, 0, // "nix-archive-1"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 116, 121, 112, 101, 0, 0, 0, 0, // "type"
|
|
|
|
7, 0, 0, 0, 0, 0, 0, 0, 115, 121, 109, 108, 105, 110, 107, 0, // "symlink"
|
|
|
|
6, 0, 0, 0, 0, 0, 0, 0, 116, 97, 114, 103, 101, 116, 0, 0, // target
|
|
|
|
24, 0, 0, 0, 0, 0, 0, 0, 47, 110, 105, 120, 47, 115, 116, 111, 114, 101, 47, 115, 111,
|
|
|
|
109, 101, 119, 104, 101, 114, 101, 101, 108, 115,
|
|
|
|
101, // "/nix/store/somewhereelse"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0 // ")"
|
|
|
|
]
|
|
|
|
);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-02-13 16:44:26 +01:00
|
|
|
#[test]
|
|
|
|
fn single_file() -> anyhow::Result<()> {
|
|
|
|
let tmpdir = TempDir::new()?;
|
|
|
|
|
|
|
|
let blob_service = gen_blob_service(tmpdir.path());
|
|
|
|
let chunk_service = gen_chunk_service(tmpdir.path());
|
|
|
|
|
|
|
|
chunk_service
|
|
|
|
.put(HELLOWORLD_BLOB_CONTENTS.to_vec())
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
blob_service
|
|
|
|
.put(
|
|
|
|
&HELLOWORLD_BLOB_DIGEST,
|
|
|
|
proto::BlobMeta {
|
|
|
|
chunks: vec![proto::blob_meta::ChunkMeta {
|
|
|
|
digest: HELLOWORLD_BLOB_DIGEST.to_vec(),
|
|
|
|
size: HELLOWORLD_BLOB_CONTENTS.len() as u32,
|
|
|
|
}],
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let renderer = NARRenderer::new(
|
|
|
|
blob_service,
|
|
|
|
chunk_service,
|
|
|
|
gen_directory_service(tmpdir.path()),
|
|
|
|
);
|
2023-01-29 20:48:23 +01:00
|
|
|
let mut buf: Vec<u8> = vec![];
|
2023-02-13 16:44:26 +01:00
|
|
|
|
|
|
|
renderer
|
|
|
|
.write_nar(
|
|
|
|
&mut buf,
|
|
|
|
crate::proto::node::Node::File(FileNode {
|
|
|
|
name: "doesntmatter".to_string(),
|
|
|
|
digest: HELLOWORLD_BLOB_DIGEST.to_vec(),
|
|
|
|
size: HELLOWORLD_BLOB_CONTENTS.len() as u32,
|
|
|
|
executable: false,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.expect("must succeed");
|
2023-01-29 20:48:23 +01:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
buf,
|
|
|
|
vec![
|
|
|
|
13, 0, 0, 0, 0, 0, 0, 0, 110, 105, 120, 45, 97, 114, 99, 104, 105, 118, 101, 45, 49, 0,
|
|
|
|
0, 0, // "nix-archive-1"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 116, 121, 112, 101, 0, 0, 0, 0, // "type"
|
|
|
|
7, 0, 0, 0, 0, 0, 0, 0, 114, 101, 103, 117, 108, 97, 114, 0, // "regular"
|
|
|
|
8, 0, 0, 0, 0, 0, 0, 0, 99, 111, 110, 116, 101, 110, 116, 115, // "contents"
|
|
|
|
12, 0, 0, 0, 0, 0, 0, 0, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 0, 0,
|
|
|
|
0, 0, // "Hello World!"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0 // ")"
|
|
|
|
]
|
|
|
|
);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-02-13 16:44:26 +01:00
|
|
|
#[test]
|
|
|
|
fn test_complicated() -> anyhow::Result<()> {
|
|
|
|
let tmpdir = TempDir::new()?;
|
|
|
|
|
|
|
|
let blob_service = gen_blob_service(tmpdir.path());
|
|
|
|
let chunk_service = gen_chunk_service(tmpdir.path());
|
|
|
|
let directory_service = gen_directory_service(tmpdir.path());
|
|
|
|
|
|
|
|
// put all data into the stores.
|
|
|
|
for blob_contents in [HELLOWORLD_BLOB_CONTENTS, EMPTY_BLOB_CONTENTS] {
|
|
|
|
let digest = chunk_service.put(blob_contents.to_vec()).unwrap();
|
|
|
|
|
|
|
|
blob_service
|
|
|
|
.put(
|
|
|
|
&digest,
|
|
|
|
proto::BlobMeta {
|
|
|
|
chunks: vec![proto::blob_meta::ChunkMeta {
|
|
|
|
digest: digest.to_vec(),
|
|
|
|
size: blob_contents.len() as u32,
|
|
|
|
}],
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
directory_service.put(DIRECTORY_WITH_KEEP.clone()).unwrap();
|
|
|
|
directory_service
|
|
|
|
.put(DIRECTORY_COMPLICATED.clone())
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let renderer = NARRenderer::new(blob_service, chunk_service, directory_service);
|
2023-01-29 20:48:23 +01:00
|
|
|
let mut buf: Vec<u8> = vec![];
|
2023-02-13 16:44:26 +01:00
|
|
|
|
|
|
|
renderer
|
|
|
|
.write_nar(
|
|
|
|
&mut buf,
|
|
|
|
crate::proto::node::Node::Directory(DirectoryNode {
|
|
|
|
name: "doesntmatter".to_string(),
|
|
|
|
digest: DIRECTORY_COMPLICATED.digest(),
|
|
|
|
size: DIRECTORY_COMPLICATED.size(),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.expect("must succeed");
|
2023-01-29 20:48:23 +01:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
buf,
|
|
|
|
vec![
|
|
|
|
13, 0, 0, 0, 0, 0, 0, 0, 110, 105, 120, 45, 97, 114, 99, 104, 105, 118, 101, 45, 49, 0,
|
|
|
|
0, 0, // "nix-archive-1"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 116, 121, 112, 101, 0, 0, 0, 0, // "type"
|
|
|
|
9, 0, 0, 0, 0, 0, 0, 0, 100, 105, 114, 101, 99, 116, 111, 114, 121, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, // "directory"
|
|
|
|
5, 0, 0, 0, 0, 0, 0, 0, 101, 110, 116, 114, 121, 0, 0, 0, // "entry"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 110, 97, 109, 101, 0, 0, 0, 0, // "name"
|
|
|
|
5, 0, 0, 0, 0, 0, 0, 0, 46, 107, 101, 101, 112, 0, 0, 0, // ".keep"
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 110, 111, 100, 101, 0, 0, 0, 0, // "node"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 116, 121, 112, 101, 0, 0, 0, 0, // "type"
|
|
|
|
7, 0, 0, 0, 0, 0, 0, 0, 114, 101, 103, 117, 108, 97, 114, 0, // "regular"
|
|
|
|
8, 0, 0, 0, 0, 0, 0, 0, 99, 111, 110, 116, 101, 110, 116, 115, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, // "contents"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, // ")"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, // ")"
|
|
|
|
5, 0, 0, 0, 0, 0, 0, 0, 101, 110, 116, 114, 121, 0, 0, 0, // "entry"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 110, 97, 109, 101, 0, 0, 0, 0, // "name"
|
|
|
|
2, 0, 0, 0, 0, 0, 0, 0, 97, 97, 0, 0, 0, 0, 0, 0, // "aa"
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 110, 111, 100, 101, 0, 0, 0, 0, // "node"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 116, 121, 112, 101, 0, 0, 0, 0, // "type"
|
|
|
|
7, 0, 0, 0, 0, 0, 0, 0, 115, 121, 109, 108, 105, 110, 107, 0, // "symlink"
|
|
|
|
6, 0, 0, 0, 0, 0, 0, 0, 116, 97, 114, 103, 101, 116, 0, 0, // "target"
|
|
|
|
24, 0, 0, 0, 0, 0, 0, 0, 47, 110, 105, 120, 47, 115, 116, 111, 114, 101, 47, 115, 111,
|
|
|
|
109, 101, 119, 104, 101, 114, 101, 101, 108, 115,
|
|
|
|
101, // "/nix/store/somewhereelse"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, // ")"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, // ")"
|
|
|
|
5, 0, 0, 0, 0, 0, 0, 0, 101, 110, 116, 114, 121, 0, 0, 0, // "entry"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 110, 97, 109, 101, 0, 0, 0, 0, // "name"
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 107, 101, 101, 112, 0, 0, 0, 0, // "keep"
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 110, 111, 100, 101, 0, 0, 0, 0, // "node"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 116, 121, 112, 101, 0, 0, 0, 0, // "type"
|
|
|
|
9, 0, 0, 0, 0, 0, 0, 0, 100, 105, 114, 101, 99, 116, 111, 114, 121, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, // "directory"
|
|
|
|
5, 0, 0, 0, 0, 0, 0, 0, 101, 110, 116, 114, 121, 0, 0, 0, // "entry"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 110, 97, 109, 101, 0, 0, 0, 0, // "name"
|
|
|
|
5, 0, 0, 0, 0, 0, 0, 0, 46, 107, 101, 101, 112, 0, 0, 0, // ".keep"
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 110, 111, 100, 101, 0, 0, 0, 0, // "node"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, // "("
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 0, 116, 121, 112, 101, 0, 0, 0, 0, // "type"
|
|
|
|
7, 0, 0, 0, 0, 0, 0, 0, 114, 101, 103, 117, 108, 97, 114, 0, // "regular"
|
|
|
|
8, 0, 0, 0, 0, 0, 0, 0, 99, 111, 110, 116, 101, 110, 116, 115, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, // "contents"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, // ")"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, // ")"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, // ")"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, // ")"
|
|
|
|
1, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0 // ")"
|
|
|
|
]
|
|
|
|
);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|