#![cfg(feature = "protocol")]
use std::io;
use nfs::v3::protocol::{CreateHow, FileHandle};
use nfs::v3::{FileType, MountStatus, NfsStatus, NfsTime, RemoteTarget, SetAttr, SetTime};
use nfs::v4::Status;
use nfs::xdr;
use nfs::xdr::to_bytes;
use nfs::{AUTH_SYS_MAX_GROUPS, AuthSys, Error};
#[test]
fn parses_remote_targets() {
let target = RemoteTarget::parse("127.0.0.1:/export/data").unwrap();
assert_eq!(target.host, "127.0.0.1");
assert_eq!(target.export, "/export/data");
let target = RemoteTarget::parse("[::1]:/export/data").unwrap();
assert_eq!(target.host, "::1");
assert_eq!(target.export, "/export/data");
assert!(RemoteTarget::parse("127.0.0.1").is_err());
assert!(RemoteTarget::parse("127.0.0.1:relative").is_err());
assert!(RemoteTarget::parse("[::1:/export").is_err());
}
#[test]
fn maps_nfs_status_values() {
assert_eq!(NfsStatus::from_u32(0), NfsStatus::Ok);
assert_eq!(NfsStatus::from_u32(2), NfsStatus::NoEnt);
assert_eq!(NfsStatus::from_u32(10004), NfsStatus::NotSupported);
assert_eq!(NfsStatus::from_u32(10008), NfsStatus::Jukebox);
assert_eq!(NfsStatus::from_u32(4242), NfsStatus::Unknown(4242));
assert_eq!(NfsStatus::NameTooLong.as_u32(), 63);
}
#[test]
fn classifies_common_errors() {
assert!(Error::Io(io::Error::from(io::ErrorKind::NotFound)).is_not_found());
assert!(
Error::Mount {
status: MountStatus::NoEnt
}
.is_not_found()
);
assert!(
Error::Nfs {
procedure: "LOOKUP",
status: NfsStatus::NoEnt,
}
.is_not_found()
);
assert!(
Error::NfsV4 {
operation: "LOOKUP",
status: Status::NoEnt,
}
.is_not_found()
);
assert!(Error::Io(io::Error::from(io::ErrorKind::AlreadyExists)).is_already_exists());
assert!(
Error::Nfs {
procedure: "CREATE",
status: NfsStatus::Exist,
}
.is_already_exists()
);
assert!(
Error::NfsV4 {
operation: "OPEN",
status: Status::Exist,
}
.is_already_exists()
);
}
#[test]
fn classifies_operational_error_semantics() {
assert!(
Error::Mount {
status: MountStatus::Access
}
.is_permission_denied()
);
assert!(
Error::Nfs {
procedure: "READ",
status: NfsStatus::Perm,
}
.is_permission_denied()
);
assert!(
Error::NfsV4 {
operation: "READ",
status: Status::Access,
}
.is_permission_denied()
);
assert!(
Error::NfsV4 {
operation: "READ",
status: Status::WrongSec,
}
.is_permission_denied()
);
assert!(Error::Io(io::Error::from(io::ErrorKind::TimedOut)).is_retryable());
assert!(
Error::Nfs {
procedure: "READ",
status: NfsStatus::Jukebox,
}
.is_retryable()
);
assert!(
Error::NfsV4 {
operation: "SEQUENCE",
status: Status::BadSession,
}
.is_retryable()
);
assert!(
Error::NfsV4 {
operation: "READ",
status: Status::Delay,
}
.is_retryable()
);
assert!(
Error::Nfs {
procedure: "WRITE",
status: NfsStatus::Dquot,
}
.is_no_space()
);
assert!(
Error::NfsV4 {
operation: "WRITE",
status: Status::NoSpc,
}
.is_no_space()
);
assert!(
Error::Nfs {
procedure: "WRITE",
status: NfsStatus::ReadOnlyFs,
}
.is_read_only()
);
assert!(
Error::NfsV4 {
operation: "WRITE",
status: Status::ReadOnlyFs,
}
.is_read_only()
);
}
#[test]
fn classifies_handle_and_v4_state_errors() {
assert!(
Error::Nfs {
procedure: "READ",
status: NfsStatus::Stale,
}
.is_stale_handle()
);
assert!(
Error::NfsV4 {
operation: "GETFH",
status: Status::BadHandle,
}
.is_stale_handle()
);
assert!(
Error::NfsV4 {
operation: "GETFH",
status: Status::FhExpired,
}
.is_stale_handle()
);
let lost_state = Error::NfsV4 {
operation: "READ",
status: Status::DelegRevoked,
};
assert!(lost_state.is_lost_state());
assert!(!lost_state.is_session_recoverable());
let recoverable_session = Error::NfsV4 {
operation: "SEQUENCE",
status: Status::DeadSession,
};
assert!(!recoverable_session.is_lost_state());
assert!(recoverable_session.is_session_recoverable());
}
#[test]
fn classifies_v3_file_types() {
assert!(FileType::Regular.is_file());
assert!(FileType::Directory.is_dir());
assert!(FileType::Symlink.is_symlink());
assert!(!FileType::Socket.is_file());
}
#[test]
fn encodes_nfs_file_handles_as_variable_opaque() {
let handle = FileHandle::new(vec![1, 2, 3]).unwrap();
assert_eq!(to_bytes(&handle).unwrap(), vec![0, 0, 0, 3, 1, 2, 3, 0]);
assert!(FileHandle::new(vec![0; 65]).is_err());
}
#[test]
fn encodes_setattr_discriminated_unions() {
let attr = SetAttr {
mode: Some(0o644),
uid: None,
gid: None,
size: Some(0),
atime: SetTime::ServerTime,
mtime: SetTime::ClientTime(NfsTime {
seconds: 7,
nseconds: 9,
}),
};
assert_eq!(
to_bytes(&attr).unwrap(),
vec![
0, 0, 0, 1, 0, 0, 1, 0xa4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 7, 0, 0, 0, 9, ]
);
}
#[test]
fn encodes_exclusive_create_mode() {
let how = CreateHow::Exclusive([1, 2, 3, 4, 5, 6, 7, 8]);
assert_eq!(
to_bytes(&how).unwrap(),
vec![0, 0, 0, 2, 1, 2, 3, 4, 5, 6, 7, 8]
);
}
#[test]
fn encodes_auth_sys_credentials() {
assert_eq!(AUTH_SYS_MAX_GROUPS, 16);
let auth = AuthSys {
stamp: 1,
machine_name: "host".to_owned(),
uid: 2,
gid: 3,
gids: vec![4, 5],
};
assert_eq!(
xdr::to_bytes(&auth).unwrap(),
vec![
0, 0, 0, 1, 0, 0, 0, 4, b'h', b'o', b's', b't', 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 5, ]
);
}