about summary refs log tree commit diff
path: root/tvix/store/src/tests
diff options
context:
space:
mode:
authorFlorian Klink <flokli@flokli.de>2023-05-11T12·49+0300
committerflokli <flokli@flokli.de>2023-05-11T14·27+0000
commit616fa4476f93e1782e68dc713e9e8cb77a426c7d (patch)
treef76a43e95c75d848d079706fbccfd442210ebebc /tvix/store/src/tests
parentb22b685f0b2524c088deacbf4e80e7b7c73b5afc (diff)
refactor(tvix/store): remove ChunkService r/6133
Whether chunking is involved or not, is an implementation detail of each
Blobstore. Consumers of a whole blob shouldn't need to worry about that.
It currently is not visible in the gRPC interface either. It
shouldn't bleed into everything.

Let the BlobService trait provide `open_read` and `open_write` methods,
which return handles providing io::Read or io::Write, and leave the
details up to the implementation.

This means, our custom BlobReader module can go away, and all the
chunking bits in there, too.

In the future, we might still want to add more chunking-aware syncing,
but as a syncing strategy some stores can expose, not as a fundamental
protocol component.

This currently needs "SyncReadIntoAsyncRead", taken and vendored in from
https://github.com/tokio-rs/tokio/pull/5669.
It provides a AsyncRead for a sync Read, which is necessary to connect
our (sync) BlobReader interface to a GRPC server implementation.

As an alternative, we could also make the BlobReader itself async, and
let consumers of the trait (EvalIO) deal with the async-ness, but this
is less of a change for now.

In terms of vendoring, I initially tried to move our tokio crate to
these commits, but ended up in version incompatibilities, so let's
vendor it in for now.

Change-Id: I5969ebbc4c0e1ceece47981be3b9e7cfb3f59ad0
Reviewed-on: https://cl.tvl.fyi/c/depot/+/8551
Tested-by: BuildkiteCI
Reviewed-by: tazjin <tazjin@tvl.su>
Diffstat (limited to 'tvix/store/src/tests')
-rw-r--r--tvix/store/src/tests/import.rs31
-rw-r--r--tvix/store/src/tests/nar_renderer.rs179
-rw-r--r--tvix/store/src/tests/utils.rs5
3 files changed, 87 insertions, 128 deletions
diff --git a/tvix/store/src/tests/import.rs b/tvix/store/src/tests/import.rs
index 3a48df9e33..ed5154d6fe 100644
--- a/tvix/store/src/tests/import.rs
+++ b/tvix/store/src/tests/import.rs
@@ -1,4 +1,4 @@
-use super::utils::{gen_blob_service, gen_chunk_service, gen_directory_service};
+use super::utils::{gen_blob_service, gen_directory_service};
 use crate::blobservice::BlobService;
 use crate::directoryservice::DirectoryService;
 use crate::import::import_path;
@@ -21,7 +21,6 @@ fn symlink() {
 
     let root_node = import_path(
         &mut gen_blob_service(),
-        &mut gen_chunk_service(),
         &mut gen_directory_service(),
         tmpdir.path().join("doesntmatter"),
     )
@@ -46,7 +45,6 @@ fn single_file() {
 
     let root_node = import_path(
         &mut blob_service,
-        &mut gen_chunk_service(),
         &mut gen_directory_service(),
         tmpdir.path().join("root"),
     )
@@ -64,13 +62,8 @@ fn single_file() {
 
     // ensure the blob has been uploaded
     assert!(blob_service
-        .stat(&proto::StatBlobRequest {
-            digest: HELLOWORLD_BLOB_DIGEST.to_vec(),
-            include_chunks: false,
-            ..Default::default()
-        })
-        .unwrap()
-        .is_some());
+        .has(&HELLOWORLD_BLOB_DIGEST.to_vec().try_into().unwrap())
+        .unwrap());
 }
 
 #[test]
@@ -89,13 +82,8 @@ fn complicated() {
     let mut blob_service = gen_blob_service();
     let mut directory_service = gen_directory_service();
 
-    let root_node = import_path(
-        &mut blob_service,
-        &mut gen_chunk_service(),
-        &mut directory_service,
-        tmpdir.path(),
-    )
-    .expect("must succeed");
+    let root_node = import_path(&mut blob_service, &mut directory_service, tmpdir.path())
+        .expect("must succeed");
 
     // ensure root_node matched expectations
     assert_eq!(
@@ -124,11 +112,6 @@ fn complicated() {
 
     // ensure EMPTY_BLOB_CONTENTS has been uploaded
     assert!(blob_service
-        .stat(&proto::StatBlobRequest {
-            digest: EMPTY_BLOB_DIGEST.to_vec(),
-            include_chunks: false,
-            include_bao: false
-        })
-        .unwrap()
-        .is_some());
+        .has(&EMPTY_BLOB_DIGEST.to_vec().try_into().unwrap())
+        .unwrap());
 }
diff --git a/tvix/store/src/tests/nar_renderer.rs b/tvix/store/src/tests/nar_renderer.rs
index 2d612d9c27..b5dbf59596 100644
--- a/tvix/store/src/tests/nar_renderer.rs
+++ b/tvix/store/src/tests/nar_renderer.rs
@@ -1,21 +1,17 @@
 use crate::blobservice::BlobService;
-use crate::chunkservice::ChunkService;
+use crate::blobservice::BlobWriter;
 use crate::directoryservice::DirectoryService;
 use crate::nar::NARRenderer;
-use crate::proto;
 use crate::proto::DirectoryNode;
 use crate::proto::FileNode;
 use crate::proto::SymlinkNode;
 use crate::tests::fixtures::*;
 use crate::tests::utils::*;
+use std::io;
 
 #[test]
 fn single_symlink() {
-    let renderer = NARRenderer::new(
-        gen_blob_service(),
-        gen_chunk_service(),
-        gen_directory_service(),
-    );
+    let renderer = NARRenderer::new(gen_blob_service(), gen_directory_service());
     // don't put anything in the stores, as we don't actually do any requests.
 
     let mut buf: Vec<u8> = vec![];
@@ -37,11 +33,7 @@ fn single_symlink() {
 /// match what's in the store.
 #[test]
 fn single_file_missing_blob() {
-    let renderer = NARRenderer::new(
-        gen_blob_service(),
-        gen_chunk_service(),
-        gen_directory_service(),
-    );
+    let renderer = NARRenderer::new(gen_blob_service(), gen_directory_service());
     let mut buf: Vec<u8> = vec![];
 
     let e = renderer
@@ -56,10 +48,11 @@ fn single_file_missing_blob() {
         )
         .expect_err("must fail");
 
-    if let crate::nar::RenderError::BlobNotFound(actual_digest, _) = e {
-        assert_eq!(HELLOWORLD_BLOB_DIGEST.to_vec(), actual_digest);
-    } else {
-        panic!("unexpected error")
+    match e {
+        crate::nar::RenderError::NARWriterError(e) => {
+            assert_eq!(io::ErrorKind::NotFound, e.kind());
+        }
+        _ => panic!("unexpected error: {:?}", e),
     }
 }
 
@@ -68,84 +61,79 @@ fn single_file_missing_blob() {
 #[test]
 fn single_file_wrong_blob_size() {
     let blob_service = gen_blob_service();
-    let chunk_service = gen_chunk_service();
 
-    // insert blob and chunk into the stores
-    chunk_service
-        .put(HELLOWORLD_BLOB_CONTENTS.to_vec())
-        .unwrap();
-
-    blob_service
-        .put(
-            &HELLOWORLD_BLOB_DIGEST,
-            proto::BlobMeta {
-                chunks: vec![proto::blob_meta::ChunkMeta {
+    // insert blob into the store
+    let mut writer = blob_service.open_write().unwrap();
+    io::copy(
+        &mut io::Cursor::new(HELLOWORLD_BLOB_CONTENTS.to_vec()),
+        &mut writer,
+    )
+    .unwrap();
+    assert_eq!(HELLOWORLD_BLOB_DIGEST.to_vec(), writer.close().unwrap());
+
+    let renderer = NARRenderer::new(blob_service, gen_directory_service());
+
+    // Test with a root FileNode of a too big size
+    {
+        let mut buf: Vec<u8> = vec![];
+        let e = 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,
-                }],
-                ..Default::default()
-            },
-        )
-        .unwrap();
-
-    let renderer = NARRenderer::new(blob_service, chunk_service, gen_directory_service());
-    let mut buf: Vec<u8> = vec![];
-
-    let e = renderer
-        .write_nar(
-            &mut buf,
-            &crate::proto::node::Node::File(FileNode {
-                name: "doesntmatter".to_string(),
-                digest: HELLOWORLD_BLOB_DIGEST.to_vec(),
-                size: 42, // <- note the wrong size here!
-                executable: false,
-            }),
-        )
-        .expect_err("must fail");
+                    size: 42, // <- note the wrong size here!
+                    executable: false,
+                }),
+            )
+            .expect_err("must fail");
+
+        match e {
+            crate::nar::RenderError::NARWriterError(e) => {
+                assert_eq!(io::ErrorKind::UnexpectedEof, e.kind());
+            }
+            _ => panic!("unexpected error: {:?}", e),
+        }
+    }
 
-    if let crate::nar::RenderError::UnexpectedBlobMeta(digest, _, expected_size, actual_size) = e {
-        assert_eq!(
-            digest,
-            HELLOWORLD_BLOB_DIGEST.to_vec(),
-            "expect digest to match"
-        );
-        assert_eq!(
-            expected_size, 42,
-            "expected expected size to be what's passed in the request"
-        );
-        assert_eq!(
-            actual_size,
-            HELLOWORLD_BLOB_CONTENTS.len() as u32,
-            "expected actual size to be correct"
-        );
-    } else {
-        panic!("unexpected error")
+    // Test with a root FileNode of a too small size
+    {
+        let mut buf: Vec<u8> = vec![];
+        let e = renderer
+            .write_nar(
+                &mut buf,
+                &crate::proto::node::Node::File(FileNode {
+                    name: "doesntmatter".to_string(),
+                    digest: HELLOWORLD_BLOB_DIGEST.to_vec(),
+                    size: 2, // <- note the wrong size here!
+                    executable: false,
+                }),
+            )
+            .expect_err("must fail");
+
+        match e {
+            crate::nar::RenderError::NARWriterError(e) => {
+                assert_eq!(io::ErrorKind::InvalidInput, e.kind());
+            }
+            _ => panic!("unexpected error: {:?}", e),
+        }
     }
 }
 
 #[test]
 fn single_file() {
     let blob_service = gen_blob_service();
-    let chunk_service = gen_chunk_service();
 
-    chunk_service
-        .put(HELLOWORLD_BLOB_CONTENTS.to_vec())
-        .unwrap();
+    // insert blob into the store
+    let mut writer = blob_service.open_write().unwrap();
+    io::copy(
+        &mut io::Cursor::new(HELLOWORLD_BLOB_CONTENTS.to_vec()),
+        &mut writer,
+    )
+    .unwrap();
+    assert_eq!(HELLOWORLD_BLOB_DIGEST.to_vec(), writer.close().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());
+    let renderer = NARRenderer::new(blob_service, gen_directory_service());
     let mut buf: Vec<u8> = vec![];
 
     renderer
@@ -166,31 +154,24 @@ fn single_file() {
 #[test]
 fn test_complicated() {
     let blob_service = gen_blob_service();
-    let chunk_service = gen_chunk_service();
     let directory_service = gen_directory_service();
 
     // put all data into the stores.
-    let digest = chunk_service.put(EMPTY_BLOB_CONTENTS.to_vec()).unwrap();
-
-    blob_service
-        .put(
-            &digest,
-            proto::BlobMeta {
-                chunks: vec![proto::blob_meta::ChunkMeta {
-                    digest: digest.to_vec(),
-                    size: EMPTY_BLOB_CONTENTS.len() as u32,
-                }],
-                ..Default::default()
-            },
-        )
-        .unwrap();
+    // insert blob into the store
+    let mut writer = blob_service.open_write().unwrap();
+    io::copy(
+        &mut io::Cursor::new(EMPTY_BLOB_CONTENTS.to_vec()),
+        &mut writer,
+    )
+    .unwrap();
+    assert_eq!(EMPTY_BLOB_DIGEST.to_vec(), writer.close().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);
+    let renderer = NARRenderer::new(blob_service, directory_service);
     let mut buf: Vec<u8> = vec![];
 
     renderer
diff --git a/tvix/store/src/tests/utils.rs b/tvix/store/src/tests/utils.rs
index 916e651621..2991feed41 100644
--- a/tvix/store/src/tests/utils.rs
+++ b/tvix/store/src/tests/utils.rs
@@ -1,6 +1,5 @@
 use crate::{
     blobservice::{BlobService, MemoryBlobService},
-    chunkservice::{ChunkService, MemoryChunkService},
     directoryservice::{DirectoryService, MemoryDirectoryService},
     pathinfoservice::{MemoryPathInfoService, PathInfoService},
 };
@@ -9,10 +8,6 @@ pub fn gen_blob_service() -> impl BlobService + Send + Sync + Clone + 'static {
     MemoryBlobService::default()
 }
 
-pub fn gen_chunk_service() -> impl ChunkService + Clone {
-    MemoryChunkService::default()
-}
-
 pub fn gen_directory_service() -> impl DirectoryService + Send + Sync + Clone + 'static {
     MemoryDirectoryService::default()
 }