os/kernel/tests/syscall_tests.rs

320 lines
12 KiB
Rust

//! System call tests
//! Tests for syscall dispatch and error handling
#![allow(dead_code)]
use kernel::syscalls::common::{SyscallError, syscall_error_to_errno};
#[cfg(test)]
mod syscall_error_handling_tests {
use super::*;
/// Test that SyscallError maps to correct POSIX errno values
#[test]
fn test_error_to_errno_mapping() {
// Test basic error mappings
assert_eq!(syscall_error_to_errno(SyscallError::InvalidSyscall), 38); // ENOSYS
assert_eq!(syscall_error_to_errno(SyscallError::PermissionDenied), 1); // EPERM
assert_eq!(syscall_error_to_errno(SyscallError::InvalidArgument), 22); // EINVAL
assert_eq!(syscall_error_to_errno(SyscallError::NotFound), 2); // ENOENT
assert_eq!(syscall_error_to_errno(SyscallError::OutOfMemory), 12); // ENOMEM
assert_eq!(syscall_error_to_errno(SyscallError::Interrupted), 4); // EINTR
assert_eq!(syscall_error_to_errno(SyscallError::IoError), 5); // EIO
assert_eq!(syscall_error_to_errno(SyscallError::WouldBlock), 11); // EAGAIN
assert_eq!(syscall_error_to_errno(SyscallError::NotSupported), 95); // EOPNOTSUPP
}
/// Test extended error mappings
#[test]
fn test_extended_error_mappings() {
assert_eq!(syscall_error_to_errno(SyscallError::BadFileDescriptor), 9); // EBADF
assert_eq!(syscall_error_to_errno(SyscallError::TooManyOpenFiles), 24); // EMFILE
assert_eq!(syscall_error_to_errno(SyscallError::NoBufferSpace), 105); // ENOBUFS
assert_eq!(syscall_error_to_errno(SyscallError::NotADirectory), 20); // ENOTDIR
assert_eq!(syscall_error_to_errno(SyscallError::IsADirectory), 21); // EISDIR
assert_eq!(syscall_error_to_errno(SyscallError::DirectoryNotEmpty), 39); // ENOTEMPTY
assert_eq!(syscall_error_to_errno(SyscallError::FileExists), 17); // EEXIST
assert_eq!(syscall_error_to_errno(SyscallError::CrossDeviceLink), 18); // EXDEV
assert_eq!(syscall_error_to_errno(SyscallError::FileTooBig), 27); // EFBIG
assert_eq!(syscall_error_to_errno(SyscallError::NoSpaceLeft), 28); // ENOSPC
assert_eq!(syscall_error_to_errno(SyscallError::BadAddress), 14); // EFAULT
assert_eq!(syscall_error_to_errno(SyscallError::DeadlockWouldOccur), 35);// EDEADLK
assert_eq!(syscall_error_to_errno(SyscallError::NameTooLong), 36); // ENAMETOOLONG
assert_eq!(syscall_error_to_errno(SyscallError::TooManySymlinks), 40); // ELOOP
assert_eq!(syscall_error_to_errno(SyscallError::ConnectionRefused), 111);// ECONNREFUSED
assert_eq!(syscall_error_to_errno(SyscallError::ConnectionReset), 104); // ECONNRESET
assert_eq!(syscall_error_to_errno(SyscallError::BrokenPipe), 32); // EPIPE
assert_eq!(syscall_error_to_errno(SyscallError::TimedOut), 110); // ETIMEDOUT
}
/// Test that negative errno is returned for errors
#[test]
fn test_error_negation() {
let errno = syscall_error_to_errno(SyscallError::InvalidArgument);
let neg_errno = -(errno as isize);
assert!(neg_errno < 0);
assert_eq!(neg_errno, -22);
}
/// Test that errors are distinct
#[test]
fn test_error_distinctiveness() {
let errors = vec![
SyscallError::InvalidSyscall,
SyscallError::PermissionDenied,
SyscallError::InvalidArgument,
SyscallError::NotFound,
SyscallError::OutOfMemory,
SyscallError::BadFileDescriptor,
SyscallError::TooManyOpenFiles,
SyscallError::NotADirectory,
SyscallError::IsADirectory,
];
let mut errno_values = Vec::new();
for error in errors {
let errno = syscall_error_to_errno(error);
// Ensure no duplicates (except where explicitly aliased like EAGAIN/EWOULDBLOCK)
assert!(!errno_values.contains(&errno) || errno == 11,
"Duplicate errno {} for error {:?}", errno, error);
errno_values.push(errno);
}
}
}
#[cfg(test)]
mod syscall_dispatch_tests {
use super::*;
/// Test invalid syscall number
#[test]
fn test_invalid_syscall() {
// Syscall number out of range should return ENOSYS
let result = kernel::syscalls::dispatch(0xFFFFFFFF, &[]);
assert_eq!(result, -38); // -ENOSYS
}
/// Test basic syscall structure
#[test]
fn test_syscall_ranges() {
// Verify that different syscall ranges are properly routed
// This is a basic sanity check
// Process management syscalls should return an error (no process to manage in test)
let result = kernel::syscalls::dispatch(0x1000, &[]);
// Result could be -ENOSYS or -EINVAL depending on implementation
assert!(result < 0);
// Invalid range should return -ENOSYS
let result = kernel::syscalls::dispatch(0x0FFF, &[]);
assert_eq!(result, -38); // -ENOSYS
}
/// Test argument conversion
#[test]
fn test_argument_conversion() {
// Test that usize arguments are properly converted
let args = vec![1, 2, 3, 4, 5, 6];
let _result = kernel::syscalls::dispatch(0x1000, &args);
// Should not panic during conversion
}
}
#[cfg(test)]
mod error_handling_consistency_tests {
use super::*;
/// Test that all syscall modules return consistent error types
#[test]
fn test_error_consistency() {
// Verify all errors map to valid POSIX errno values
let errors = vec![
SyscallError::InvalidSyscall,
SyscallError::PermissionDenied,
SyscallError::InvalidArgument,
SyscallError::NotFound,
SyscallError::OutOfMemory,
SyscallError::Interrupted,
SyscallError::IoError,
SyscallError::WouldBlock,
SyscallError::NotSupported,
SyscallError::BadFileDescriptor,
SyscallError::TooManyOpenFiles,
SyscallError::NoBufferSpace,
SyscallError::NotADirectory,
SyscallError::IsADirectory,
SyscallError::DirectoryNotEmpty,
SyscallError::FileExists,
SyscallError::CrossDeviceLink,
SyscallError::FileTooBig,
SyscallError::NoSpaceLeft,
SyscallError::BadAddress,
SyscallError::DeadlockWouldOccur,
SyscallError::NameTooLong,
SyscallError::TooManySymlinks,
SyscallError::ConnectionRefused,
SyscallError::ConnectionReset,
SyscallError::BrokenPipe,
SyscallError::TimedOut,
];
for error in errors {
let errno = syscall_error_to_errno(error);
// Check that errno is positive and within valid range
assert!(errno > 0 && errno <= 133,
"Invalid errno {} for error {:?}", errno, error);
// Check that negation produces expected negative value
let neg_errno = -(errno as isize);
assert!(neg_errno < 0);
}
}
/// Test Result type consistency
#[test]
fn test_result_type_usage() {
// Test that SyscallResult can be constructed and converted
let ok_result: Result<u64, SyscallError> = Ok(42);
assert!(ok_result.is_ok());
assert_eq!(ok_result.unwrap(), 42);
let err_result: Result<u64, SyscallError> = Err(SyscallError::InvalidArgument);
assert!(err_result.is_err());
let errno = syscall_error_to_errno(err_result.unwrap_err());
assert_eq!(errno, 22); // EINVAL
}
}
#[cfg(test)]
mod syscall_argument_tests {
use super::*;
/// Test system call argument conversion optimization
#[test]
fn test_syscall_args_no_heap_allocation() {
// Test that system call arguments are converted without heap allocation
// Using fixed-size array instead of Vec
let args = [1usize, 2, 3, 4, 5, 6];
// This should not allocate on the heap
let result = kernel::syscalls::dispatch(0x1000, &args);
// Should not panic and should return an error (no process context)
assert!(result <= 0);
}
/// Test argument extraction
#[test]
fn test_argument_extraction() {
use kernel::syscalls::common::extract_args;
let args = [1u64, 2, 3, 4];
// Extract 2 arguments
let result = extract_args(&args, 2);
assert!(result.is_ok());
let extracted = result.unwrap();
assert_eq!(extracted.len(), 2);
assert_eq!(extracted[0], 1);
assert_eq!(extracted[1], 2);
// Extract more than available should fail
let result = extract_args(&args, 5);
assert!(result.is_err());
}
/// Test argument bounds checking
#[test]
fn test_argument_bounds() {
let args = [1usize, 2, 3];
// Test with valid arguments
let result = kernel::syscalls::dispatch(0x1000, &args);
assert!(result <= 0); // Should return error (no process context)
// Test with empty arguments
let result = kernel::syscalls::dispatch(0x1000, &[]);
assert!(result <= 0);
// Test with maximum arguments
let args = [1usize, 2, 3, 4, 5, 6, 7, 8];
let result = kernel::syscalls::dispatch(0x1000, &args);
assert!(result <= 0);
}
}
#[cfg(test)]
mod epoll_tests {
use super::*;
/// Test epoll_create syscall
#[test]
fn test_epoll_create() {
// Test epoll_create with size parameter
let args = [128u64]; // size parameter
let result = kernel::syscalls::dispatch(0xA000, &args);
// Should return a file descriptor (positive) or error
// In test environment, might return error if not initialized
assert!(result != 0 || result < 0);
}
/// Test epoll_create1 syscall
#[test]
fn test_epoll_create1() {
// Test epoll_create1 with flags
let args = [0u64]; // flags = 0
let result = kernel::syscalls::dispatch(0xA001, &args);
assert!(result != 0 || result < 0);
}
/// Test epoll_ctl syscall
#[test]
fn test_epoll_ctl() {
// Test epoll_ctl with invalid epfd (should fail)
let args = [999u64, 1u64, 1u64, 0u64]; // epfd, op, fd, event_ptr
let result = kernel::syscalls::dispatch(0xA002, &args);
// Should return error for invalid epfd
assert!(result < 0);
}
/// Test epoll_wait syscall
#[test]
fn test_epoll_wait() {
// Test epoll_wait with invalid epfd
let args = [999u64, 0u64, 10u64, 0u64]; // epfd, events, maxevents, timeout
let result = kernel::syscalls::dispatch(0xA003, &args);
// Should return error for invalid epfd
assert!(result < 0);
}
}
#[cfg(test)]
mod filesystem_tests {
use super::*;
/// Test symlink syscall error handling
#[test]
fn test_symlink_error_handling() {
// Test with null pointers (should return EFAULT)
let args = [0u64, 0u64]; // null pointers
let result = kernel::syscalls::dispatch(0x7008, &args);
assert!(result < 0); // Should return error
}
/// Test readlink syscall error handling
#[test]
fn test_readlink_error_handling() {
// Test with null pointers (should return EFAULT)
let args = [0u64, 0u64, 0u64]; // null pointers, zero size
let result = kernel::syscalls::dispatch(0x7009, &args);
assert!(result < 0); // Should return error
}
/// Test fcntl syscall error handling
#[test]
fn test_fcntl_error_handling() {
// Test with invalid file descriptor
let args = [999u64, 3u64, 0u64]; // invalid fd, F_GETFL, arg
let result = kernel::syscalls::dispatch(0x200A, &args);
assert!(result < 0); // Should return EBADF
}
}