authfs: add unit tests for ChunkedFileReader

Now that Rust tests can run with data:
 - Add unit tests for ChunkedFileReader
 - Update other tests to use test files, instead of include_bytes!
 - Remove `impl ReadOnlyDataByChunk for &[u8]` since it's no longer use.

Test: atest authfs_device_test_src_lib
Bug: 178874539
Change-Id: Idee833a2fd86aa9d8b8550b574686ea56158f93f
diff --git a/authfs/Android.bp b/authfs/Android.bp
index 270be6e..3fc4504 100644
--- a/authfs/Android.bp
+++ b/authfs/Android.bp
@@ -49,4 +49,16 @@
     name: "authfs_device_test_src_lib",
     defaults: ["authfs_defaults"],
     test_suites: ["device-tests"],
+    data: [
+        "testdata/input.4k",
+        "testdata/input.4k.fsv_sig",
+        "testdata/input.4k.merkle_dump",
+        "testdata/input.4k1",
+        "testdata/input.4k1.fsv_sig",
+        "testdata/input.4k1.merkle_dump",
+        "testdata/input.4m",
+        "testdata/input.4m.fsv_sig",
+        "testdata/input.4m.merkle_dump",
+        "testdata/input.4m.merkle_dump.bad",
+    ],
 }
diff --git a/authfs/src/fsverity.rs b/authfs/src/fsverity.rs
index 29e15d4..306c9d9 100644
--- a/authfs/src/fsverity.rs
+++ b/authfs/src/fsverity.rs
@@ -211,89 +211,93 @@
 mod tests {
     use super::*;
     use crate::auth::FakeAuthenticator;
-    use crate::reader::ReadOnlyDataByChunk;
+    use crate::reader::{ChunkedFileReader, ReadOnlyDataByChunk};
     use anyhow::Result;
+    use std::fs::File;
+    use std::io::Read;
+
+    type LocalFsverityChunkedFileReader =
+        FsverityChunkedFileReader<ChunkedFileReader, ChunkedFileReader>;
 
     fn total_chunk_number(file_size: u64) -> u64 {
         (file_size + 4095) / 4096
     }
 
+    // Returns a reader with fs-verity verification and the file size.
+    fn new_reader_with_fsverity(
+        content_path: &str,
+        merkle_tree_path: &str,
+        signature_path: &str,
+    ) -> Result<(LocalFsverityChunkedFileReader, u64)> {
+        let file_reader = ChunkedFileReader::new(File::open(content_path)?)?;
+        let file_size = file_reader.len();
+        let merkle_tree = ChunkedFileReader::new(File::open(merkle_tree_path)?)?;
+        let mut sig = Vec::new();
+        let _ = File::open(signature_path)?.read_to_end(&mut sig)?;
+        let authenticator = FakeAuthenticator::always_succeed();
+        Ok((
+            FsverityChunkedFileReader::new(
+                &authenticator,
+                file_reader,
+                file_size,
+                sig,
+                merkle_tree,
+            )?,
+            file_size,
+        ))
+    }
+
     #[test]
     fn fsverity_verify_full_read_4k() -> Result<()> {
-        let file = &include_bytes!("../testdata/input.4k")[..];
-        let merkle_tree = &include_bytes!("../testdata/input.4k.merkle_dump")[..];
-        let sig = include_bytes!("../testdata/input.4k.fsv_sig").to_vec();
-        let authenticator = FakeAuthenticator::always_succeed();
-        let verified_file = FsverityChunkedFileReader::new(
-            &authenticator,
-            file,
-            file.len() as u64,
-            sig,
-            merkle_tree,
+        let (file_reader, file_size) = new_reader_with_fsverity(
+            "testdata/input.4k",
+            "testdata/input.4k.merkle_dump",
+            "testdata/input.4k.fsv_sig",
         )?;
 
-        for i in 0..total_chunk_number(file.len() as u64) {
+        for i in 0..total_chunk_number(file_size) {
             let mut buf = [0u8; 4096];
-            assert!(verified_file.read_chunk(i, &mut buf[..]).is_ok());
+            assert!(file_reader.read_chunk(i, &mut buf[..]).is_ok());
         }
         Ok(())
     }
 
     #[test]
     fn fsverity_verify_full_read_4k1() -> Result<()> {
-        let file = &include_bytes!("../testdata/input.4k1")[..];
-        let merkle_tree = &include_bytes!("../testdata/input.4k1.merkle_dump")[..];
-        let sig = include_bytes!("../testdata/input.4k1.fsv_sig").to_vec();
-        let authenticator = FakeAuthenticator::always_succeed();
-        let verified_file = FsverityChunkedFileReader::new(
-            &authenticator,
-            file,
-            file.len() as u64,
-            sig,
-            merkle_tree,
+        let (file_reader, file_size) = new_reader_with_fsverity(
+            "testdata/input.4k1",
+            "testdata/input.4k1.merkle_dump",
+            "testdata/input.4k1.fsv_sig",
         )?;
 
-        for i in 0..total_chunk_number(file.len() as u64) {
+        for i in 0..total_chunk_number(file_size) {
             let mut buf = [0u8; 4096];
-            assert!(verified_file.read_chunk(i, &mut buf[..]).is_ok());
+            assert!(file_reader.read_chunk(i, &mut buf[..]).is_ok());
         }
         Ok(())
     }
 
     #[test]
     fn fsverity_verify_full_read_4m() -> Result<()> {
-        let file = &include_bytes!("../testdata/input.4m")[..];
-        let merkle_tree = &include_bytes!("../testdata/input.4m.merkle_dump")[..];
-        let sig = include_bytes!("../testdata/input.4m.fsv_sig").to_vec();
-        let authenticator = FakeAuthenticator::always_succeed();
-        let verified_file = FsverityChunkedFileReader::new(
-            &authenticator,
-            file,
-            file.len() as u64,
-            sig,
-            merkle_tree,
+        let (file_reader, file_size) = new_reader_with_fsverity(
+            "testdata/input.4m",
+            "testdata/input.4m.merkle_dump",
+            "testdata/input.4m.fsv_sig",
         )?;
 
-        for i in 0..total_chunk_number(file.len() as u64) {
+        for i in 0..total_chunk_number(file_size) {
             let mut buf = [0u8; 4096];
-            assert!(verified_file.read_chunk(i, &mut buf[..]).is_ok());
+            assert!(file_reader.read_chunk(i, &mut buf[..]).is_ok());
         }
         Ok(())
     }
 
     #[test]
     fn fsverity_verify_bad_merkle_tree() -> Result<()> {
-        let file = &include_bytes!("../testdata/input.4m")[..];
-        // First leaf node is corrupted.
-        let merkle_tree = &include_bytes!("../testdata/input.4m.merkle_dump.bad")[..];
-        let sig = include_bytes!("../testdata/input.4m.fsv_sig").to_vec();
-        let authenticator = FakeAuthenticator::always_succeed();
-        let verified_file = FsverityChunkedFileReader::new(
-            &authenticator,
-            file,
-            file.len() as u64,
-            sig,
-            merkle_tree,
+        let (file_reader, _) = new_reader_with_fsverity(
+            "testdata/input.4m",
+            "testdata/input.4m.merkle_dump.bad", // First leaf node is corrupted.
+            "testdata/input.4m.fsv_sig",
         )?;
 
         // A lowest broken node (a 4K chunk that contains 128 sha256 hashes) will fail the read
@@ -302,22 +306,23 @@
         let num_hashes = 4096 / 32;
         let last_index = num_hashes;
         for i in 0..last_index {
-            assert!(verified_file.read_chunk(i, &mut buf[..]).is_err());
+            assert!(file_reader.read_chunk(i, &mut buf[..]).is_err());
         }
-        assert!(verified_file.read_chunk(last_index, &mut buf[..]).is_ok());
+        assert!(file_reader.read_chunk(last_index, &mut buf[..]).is_ok());
         Ok(())
     }
 
     #[test]
     fn invalid_signature() -> Result<()> {
         let authenticator = FakeAuthenticator::always_fail();
-        let file = &include_bytes!("../testdata/input.4m")[..];
-        let merkle_tree = &include_bytes!("../testdata/input.4m.merkle_dump")[..];
+        let file_reader = ChunkedFileReader::new(File::open("testdata/input.4m")?)?;
+        let file_size = file_reader.len();
+        let merkle_tree = ChunkedFileReader::new(File::open("testdata/input.4m.merkle_dump")?)?;
         let sig = include_bytes!("../testdata/input.4m.fsv_sig").to_vec();
         assert!(FsverityChunkedFileReader::new(
             &authenticator,
-            file,
-            file.len() as u64,
+            file_reader,
+            file_size,
             sig,
             merkle_tree
         )
diff --git a/authfs/src/main.rs b/authfs/src/main.rs
index f0b5237..46e6fd8 100644
--- a/authfs/src/main.rs
+++ b/authfs/src/main.rs
@@ -120,9 +120,8 @@
 }
 
 fn new_config_local_unverified_file(file_path: &PathBuf) -> Result<FileConfig> {
-    let file = File::open(file_path)?;
-    let file_size = file.metadata()?.len();
-    let file_reader = ChunkedFileReader::new(file)?;
+    let file_reader = ChunkedFileReader::new(File::open(file_path)?)?;
+    let file_size = file_reader.len();
     Ok(FileConfig::LocalUnverifiedFile(file_reader, file_size))
 }
 
diff --git a/authfs/src/reader.rs b/authfs/src/reader.rs
index 2d1b617..d365a41 100644
--- a/authfs/src/reader.rs
+++ b/authfs/src/reader.rs
@@ -54,6 +54,10 @@
         let size = file.metadata()?.len();
         Ok(ChunkedFileReader { file, size })
     }
+
+    pub fn len(&self) -> u64 {
+        self.size
+    }
 }
 
 impl ReadOnlyDataByChunk for ChunkedFileReader {
@@ -65,55 +69,57 @@
     }
 }
 
-impl ReadOnlyDataByChunk for &[u8] {
-    fn read_chunk(&self, chunk_index: u64, buf: &mut [u8]) -> Result<usize> {
-        debug_assert!(buf.len() as u64 >= Self::CHUNK_SIZE);
-        let chunk = &self.chunks(Self::CHUNK_SIZE as usize).nth(chunk_index as usize).unwrap();
-        buf[..chunk.len()].copy_from_slice(&chunk);
-        Ok(chunk.len())
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
+    use std::env::temp_dir;
 
-    fn test_reading_more_than_4kb_data<T: ReadOnlyDataByChunk>(
-        reader: T,
-        data_size: u64,
-    ) -> Result<()> {
+    #[test]
+    fn test_read_4k_file() -> Result<()> {
+        let file_reader = ChunkedFileReader::new(File::open("testdata/input.4k")?)?;
         let mut buf = [0u8; 4096];
-        assert_eq!(reader.read_chunk(0, &mut buf)?, 4096);
-        let last_index = (data_size + 4095) / 4096 - 1;
-        assert_eq!(reader.read_chunk(last_index, &mut buf)?, (data_size % 4096) as usize);
+        let size = file_reader.read_chunk(0, &mut buf)?;
+        assert_eq!(size, buf.len());
         Ok(())
     }
 
-    // TODO(victorhsieh): test ChunkedFileReader once there is a way to access testdata in the test
-    // environement.
-
     #[test]
-    fn test_read_in_memory_data() -> Result<()> {
-        let data = &[1u8; 5000][..];
-        test_reading_more_than_4kb_data(data, data.len() as u64)
-    }
-
-    #[test]
-    #[should_panic]
-    #[allow(unused_must_use)]
-    fn test_read_in_memory_empty_data() {
-        let data = &[][..]; // zero length slice
+    fn test_read_4k1_file() -> Result<()> {
+        let file_reader = ChunkedFileReader::new(File::open("testdata/input.4k1")?)?;
         let mut buf = [0u8; 4096];
-        data.read_chunk(0, &mut buf); // should panic
+        let size = file_reader.read_chunk(0, &mut buf)?;
+        assert_eq!(size, buf.len());
+        let size = file_reader.read_chunk(1, &mut buf)?;
+        assert_eq!(size, 1);
+        Ok(())
+    }
+
+    #[test]
+    fn test_read_4m_file() -> Result<()> {
+        let file_reader = ChunkedFileReader::new(File::open("testdata/input.4m")?)?;
+        for index in 0..file_reader.len() / 4096 {
+            let mut buf = [0u8; 4096];
+            let size = file_reader.read_chunk(index, &mut buf)?;
+            assert_eq!(size, buf.len());
+        }
+        Ok(())
     }
 
     #[test]
     #[should_panic]
-    #[allow(unused_must_use)]
     fn test_read_beyond_file_size() {
-        let data = &[1u8; 5000][..];
+        let file_reader = ChunkedFileReader::new(File::open("testdata/input.4k").unwrap()).unwrap();
         let mut buf = [0u8; 4096];
-        let last_index_plus_1 = (data.len() + 4095) / 4096;
-        data.read_chunk(last_index_plus_1 as u64, &mut buf); // should panic
+        let _ = file_reader.read_chunk(1u64, &mut buf); // should panic
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_read_empty_file() {
+        let mut temp_file = temp_dir();
+        temp_file.push("authfs_test_empty_file");
+        let file_reader = ChunkedFileReader::new(File::create(temp_file).unwrap()).unwrap();
+        let mut buf = [0u8; 4096];
+        let _ = file_reader.read_chunk(0, &mut buf); // should panic
     }
 }