From 86c307a21457238d40311fda91ef81530fdcaa31 Mon Sep 17 00:00:00 2001 From: Chip Senkbeil Date: Sat, 25 Sep 2021 11:16:08 -0500 Subject: [PATCH] Add tests for File::readdir and File::stat; change .cirrus.yml to set home directory permissions --- .cirrus.yml | 1 + wezterm-ssh/src/session/sftp.rs | 3 ++ wezterm-ssh/src/session/sftp/file.rs | 7 +++ wezterm-ssh/tests/e2e/sftp/file.rs | 70 ++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+) diff --git a/.cirrus.yml b/.cirrus.yml index 254e790c3..8fb2554c2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -13,6 +13,7 @@ task: - chmod +x /tmp/rustup.sh - RUSTUP_IO_THREADS=1 /tmp/rustup.sh -y -q - env PATH=$HOME/.cargo/bin:$PATH bash get-deps + - chmod og-rw $HOME test_script: - env PATH=$HOME/.cargo/bin:$PATH cargo build --all --release - env PATH=$HOME/.cargo/bin:$PATH cargo test --all --release diff --git a/wezterm-ssh/src/session/sftp.rs b/wezterm-ssh/src/session/sftp.rs index e93ef8818..14bc81f9e 100644 --- a/wezterm-ssh/src/session/sftp.rs +++ b/wezterm-ssh/src/session/sftp.rs @@ -92,6 +92,9 @@ impl Sftp { /// Convenience function to read the files in a directory. /// + /// The returned paths are all joined with dirname when returned, and the paths . and .. are + /// filtered out of the returned list. + /// /// See [`Sftp::readdir`] for more information. pub async fn readdir( &self, diff --git a/wezterm-ssh/src/session/sftp/file.rs b/wezterm-ssh/src/session/sftp/file.rs index bf7541e9e..ff55ca196 100644 --- a/wezterm-ssh/src/session/sftp/file.rs +++ b/wezterm-ssh/src/session/sftp/file.rs @@ -170,6 +170,13 @@ impl File { /// Reads a block of data from a handle and returns file entry information for the next entry, /// if any. /// + /// Note that this provides raw access to the readdir function from libssh2. This will return + /// an error when there are no more files to read, and files such as . and .. will be included + /// in the return values. + /// + /// Also note that the return paths will not be absolute paths, they are the filenames of the + /// files in this directory. + /// /// See [`ssh2::File::readdir`] for more information. pub async fn readdir(&self) -> anyhow::Result<(PathBuf, FileStat)> { let (reply, rx) = bounded(1); diff --git a/wezterm-ssh/tests/e2e/sftp/file.rs b/wezterm-ssh/tests/e2e/sftp/file.rs index c86bc9072..554db4b9c 100644 --- a/wezterm-ssh/tests/e2e/sftp/file.rs +++ b/wezterm-ssh/tests/e2e/sftp/file.rs @@ -2,8 +2,78 @@ use crate::sshd::session; use assert_fs::{prelude::*, TempDir}; use rstest::*; use smol::io::{AsyncReadExt, AsyncWriteExt}; +use std::path::PathBuf; use wezterm_ssh::Session; +#[rstest] +#[smol_potat::test] +async fn stat_should_retrieve_file_stat(#[future] session: Session) { + let session: Session = session.await; + + let temp = TempDir::new().unwrap(); + let file = temp.child("test-file"); + file.touch().unwrap(); + + let remote_file = session + .sftp() + .open(file.path()) + .await + .expect("Failed to open remote file"); + + let stat = remote_file.stat().await.expect("Failed to read file stat"); + + // Verify that file stat makes sense + assert!(stat.is_file(), "Invalid file stat returned"); +} + +#[rstest] +#[smol_potat::test] +async fn readdir_should_retrieve_next_dir_entry(#[future] session: Session) { + let session: Session = session.await; + + let temp = TempDir::new().unwrap(); + let dir = temp.child("dir"); + dir.create_dir_all().unwrap(); + let file = temp.child("file"); + file.touch().unwrap(); + let link = temp.child("link"); + link.symlink_to_file(file.path()).unwrap(); + + let remote_dir = session + .sftp() + .opendir(temp.path()) + .await + .expect("Failed to open remote directory"); + + // Collect all of the directory contents (. and .. are included) + let mut contents = Vec::new(); + while let Ok((path, stat)) = remote_dir.readdir().await { + let ft = stat.file_type(); + contents.push(( + path, + if ft.is_dir() { + "dir" + } else if ft.is_file() { + "file" + } else { + "symlink" + }, + )); + } + contents.sort_unstable_by_key(|(p, _)| p.to_path_buf()); + + assert_eq!( + contents, + vec![ + (PathBuf::from("."), "dir"), + (PathBuf::from(".."), "dir"), + (PathBuf::from("dir"), "dir"), + (PathBuf::from("file"), "file"), + (PathBuf::from("link"), "symlink"), + ] + ); +} + #[rstest] #[smol_potat::test] async fn should_support_async_reading(#[future] session: Session) {