mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-17 02:15:28 +00:00
add Error test, fix clippy
This commit is contained in:
@@ -5,7 +5,7 @@ use iam::{
|
||||
};
|
||||
use madmin::GroupAddRemove;
|
||||
use matchit::Params;
|
||||
use s3s::{header::CONTENT_TYPE, s3_error, Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result};
|
||||
use s3s::{Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result, header::CONTENT_TYPE, s3_error};
|
||||
use serde::Deserialize;
|
||||
use serde_urlencoded::from_bytes;
|
||||
use tracing::warn;
|
||||
|
||||
@@ -3,7 +3,7 @@ use http::{HeaderMap, StatusCode};
|
||||
use iam::{error::is_err_no_such_user, get_global_action_cred, store::MappedPolicy};
|
||||
use matchit::Params;
|
||||
use policy::policy::Policy;
|
||||
use s3s::{header::CONTENT_TYPE, s3_error, Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result};
|
||||
use s3s::{Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result, header::CONTENT_TYPE, s3_error};
|
||||
use serde::Deserialize;
|
||||
use serde_urlencoded::from_bytes;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -16,7 +16,7 @@ use matchit::Params;
|
||||
use policy::policy::action::{Action, AdminAction};
|
||||
use policy::policy::{Args, Policy};
|
||||
use s3s::S3ErrorCode::InvalidRequest;
|
||||
use s3s::{header::CONTENT_TYPE, s3_error, Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result};
|
||||
use s3s::{Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result, header::CONTENT_TYPE, s3_error};
|
||||
use serde::Deserialize;
|
||||
use serde_urlencoded::from_bytes;
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -10,8 +10,9 @@ use iam::{manager::get_token_signing_key, sys::SESSION_POLICY_NAME};
|
||||
use matchit::Params;
|
||||
use policy::{auth::get_new_credentials_with_metadata, policy::Policy};
|
||||
use s3s::{
|
||||
Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result,
|
||||
dto::{AssumeRoleOutput, Credentials, Timestamp},
|
||||
s3_error, Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result,
|
||||
s3_error,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use ecstore::{peer_rest_client::PeerRestClient, GLOBAL_Endpoints};
|
||||
use ecstore::{GLOBAL_Endpoints, peer_rest_client::PeerRestClient};
|
||||
use http::StatusCode;
|
||||
use hyper::Uri;
|
||||
use madmin::service_commands::ServiceTraceOpts;
|
||||
use matchit::Params;
|
||||
use s3s::{s3_error, Body, S3Request, S3Response, S3Result};
|
||||
use s3s::{Body, S3Request, S3Response, S3Result, s3_error};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::admin::router::Operation;
|
||||
|
||||
@@ -5,10 +5,10 @@ use iam::get_global_action_cred;
|
||||
use madmin::{AccountStatus, AddOrUpdateUserReq};
|
||||
use matchit::Params;
|
||||
use policy::policy::{
|
||||
action::{Action, AdminAction},
|
||||
Args,
|
||||
action::{Action, AdminAction},
|
||||
};
|
||||
use s3s::{header::CONTENT_TYPE, s3_error, Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result};
|
||||
use s3s::{Body, S3Error, S3ErrorCode, S3Request, S3Response, S3Result, header::CONTENT_TYPE, s3_error};
|
||||
use serde::Deserialize;
|
||||
use serde_urlencoded::from_bytes;
|
||||
use tracing::warn;
|
||||
|
||||
+3
-3
@@ -7,13 +7,13 @@ use iam::get_global_action_cred;
|
||||
use iam::sys::SESSION_POLICY_NAME;
|
||||
use policy::auth;
|
||||
use policy::auth::get_claims_from_token_with_secret;
|
||||
use s3s::S3Error;
|
||||
use s3s::S3ErrorCode;
|
||||
use s3s::S3Result;
|
||||
use s3s::auth::S3Auth;
|
||||
use s3s::auth::SecretKey;
|
||||
use s3s::auth::SimpleAuth;
|
||||
use s3s::s3_error;
|
||||
use s3s::S3Error;
|
||||
use s3s::S3ErrorCode;
|
||||
use s3s::S3Result;
|
||||
use serde_json::Value;
|
||||
|
||||
pub struct IAMAuth {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::license::get_license;
|
||||
use axum::{
|
||||
Router,
|
||||
body::Body,
|
||||
http::{Response, StatusCode},
|
||||
response::IntoResponse,
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use axum_extra::extract::Host;
|
||||
use rustfs_config::{RUSTFS_TLS_CERT, RUSTFS_TLS_KEY};
|
||||
@@ -12,7 +12,7 @@ use std::io;
|
||||
|
||||
use axum::response::Redirect;
|
||||
use axum_server::tls_rustls::RustlsConfig;
|
||||
use http::{header, Uri};
|
||||
use http::{Uri, header};
|
||||
use mime_guess::from_path;
|
||||
use rust_embed::RustEmbed;
|
||||
use serde::Serialize;
|
||||
|
||||
@@ -94,3 +94,238 @@ impl From<iam::error::Error> for ApiError {
|
||||
serr.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use s3s::{S3Error, S3ErrorCode};
|
||||
use std::io::{Error as IoError, ErrorKind};
|
||||
|
||||
#[test]
|
||||
fn test_api_error_from_io_error() {
|
||||
let io_error = IoError::new(ErrorKind::PermissionDenied, "permission denied");
|
||||
let api_error: ApiError = io_error.into();
|
||||
|
||||
assert_eq!(api_error.code, S3ErrorCode::InternalError);
|
||||
assert!(api_error.message.contains("permission denied"));
|
||||
assert!(api_error.source.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_from_io_error_different_kinds() {
|
||||
let test_cases = vec![
|
||||
(ErrorKind::NotFound, "not found"),
|
||||
(ErrorKind::InvalidInput, "invalid input"),
|
||||
(ErrorKind::TimedOut, "timed out"),
|
||||
(ErrorKind::WriteZero, "write zero"),
|
||||
(ErrorKind::Other, "other error"),
|
||||
];
|
||||
|
||||
for (kind, message) in test_cases {
|
||||
let io_error = IoError::new(kind, message);
|
||||
let api_error: ApiError = io_error.into();
|
||||
|
||||
assert_eq!(api_error.code, S3ErrorCode::InternalError);
|
||||
assert!(api_error.message.contains(message));
|
||||
assert!(api_error.source.is_some());
|
||||
|
||||
// Test that source can be downcast back to io::Error
|
||||
let source = api_error.source.as_ref().unwrap();
|
||||
let downcast_io_error = source.downcast_ref::<IoError>();
|
||||
assert!(downcast_io_error.is_some());
|
||||
assert_eq!(downcast_io_error.unwrap().kind(), kind);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_other_function() {
|
||||
let custom_error = "Custom API error";
|
||||
let api_error = ApiError::other(custom_error);
|
||||
|
||||
assert_eq!(api_error.code, S3ErrorCode::InternalError);
|
||||
assert_eq!(api_error.message, custom_error);
|
||||
assert!(api_error.source.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_other_function_with_complex_error() {
|
||||
let io_error = IoError::new(ErrorKind::InvalidData, "complex error");
|
||||
let api_error = ApiError::other(io_error);
|
||||
|
||||
assert_eq!(api_error.code, S3ErrorCode::InternalError);
|
||||
assert!(api_error.message.contains("complex error"));
|
||||
assert!(api_error.source.is_some());
|
||||
|
||||
// Test that source can be downcast back to io::Error
|
||||
let source = api_error.source.as_ref().unwrap();
|
||||
let downcast_io_error = source.downcast_ref::<IoError>();
|
||||
assert!(downcast_io_error.is_some());
|
||||
assert_eq!(downcast_io_error.unwrap().kind(), ErrorKind::InvalidData);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_from_storage_error() {
|
||||
let storage_error = StorageError::BucketNotFound("test-bucket".to_string());
|
||||
let api_error: ApiError = storage_error.into();
|
||||
|
||||
assert_eq!(api_error.code, S3ErrorCode::NoSuchBucket);
|
||||
assert!(api_error.message.contains("test-bucket"));
|
||||
assert!(api_error.source.is_some());
|
||||
|
||||
// Test that source can be downcast back to StorageError
|
||||
let source = api_error.source.as_ref().unwrap();
|
||||
let downcast_storage_error = source.downcast_ref::<StorageError>();
|
||||
assert!(downcast_storage_error.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_from_storage_error_mappings() {
|
||||
let test_cases = vec![
|
||||
(StorageError::NotImplemented, S3ErrorCode::NotImplemented),
|
||||
(
|
||||
StorageError::InvalidArgument("test".into(), "test".into(), "test".into()),
|
||||
S3ErrorCode::InvalidArgument,
|
||||
),
|
||||
(StorageError::MethodNotAllowed, S3ErrorCode::MethodNotAllowed),
|
||||
(StorageError::BucketNotFound("test".into()), S3ErrorCode::NoSuchBucket),
|
||||
(StorageError::BucketNotEmpty("test".into()), S3ErrorCode::BucketNotEmpty),
|
||||
(StorageError::BucketNameInvalid("test".into()), S3ErrorCode::InvalidBucketName),
|
||||
(
|
||||
StorageError::ObjectNameInvalid("test".into(), "test".into()),
|
||||
S3ErrorCode::InvalidArgument,
|
||||
),
|
||||
(StorageError::BucketExists("test".into()), S3ErrorCode::BucketAlreadyExists),
|
||||
(StorageError::StorageFull, S3ErrorCode::ServiceUnavailable),
|
||||
(StorageError::SlowDown, S3ErrorCode::SlowDown),
|
||||
(StorageError::PrefixAccessDenied("test".into(), "test".into()), S3ErrorCode::AccessDenied),
|
||||
(StorageError::ObjectNotFound("test".into(), "test".into()), S3ErrorCode::NoSuchKey),
|
||||
(StorageError::ConfigNotFound, S3ErrorCode::NoSuchKey),
|
||||
(StorageError::VolumeNotFound, S3ErrorCode::NoSuchBucket),
|
||||
(StorageError::FileNotFound, S3ErrorCode::NoSuchKey),
|
||||
(StorageError::FileVersionNotFound, S3ErrorCode::NoSuchVersion),
|
||||
];
|
||||
|
||||
for (storage_error, expected_code) in test_cases {
|
||||
let api_error: ApiError = storage_error.into();
|
||||
assert_eq!(api_error.code, expected_code);
|
||||
assert!(api_error.source.is_some());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_from_iam_error() {
|
||||
let iam_error = iam::error::Error::other("IAM test error");
|
||||
let api_error: ApiError = iam_error.into();
|
||||
|
||||
// IAM error is first converted to StorageError, then to ApiError
|
||||
assert!(api_error.source.is_some());
|
||||
assert!(api_error.message.contains("test error"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_to_s3_error() {
|
||||
let api_error = ApiError {
|
||||
code: S3ErrorCode::NoSuchBucket,
|
||||
message: "Bucket not found".to_string(),
|
||||
source: Some(Box::new(IoError::new(ErrorKind::NotFound, "not found"))),
|
||||
};
|
||||
|
||||
let s3_error: S3Error = api_error.into();
|
||||
assert_eq!(*s3_error.code(), S3ErrorCode::NoSuchBucket);
|
||||
assert!(s3_error.message().unwrap_or("").contains("Bucket not found"));
|
||||
assert!(s3_error.source().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_to_s3_error_without_source() {
|
||||
let api_error = ApiError {
|
||||
code: S3ErrorCode::InvalidArgument,
|
||||
message: "Invalid argument".to_string(),
|
||||
source: None,
|
||||
};
|
||||
|
||||
let s3_error: S3Error = api_error.into();
|
||||
assert_eq!(*s3_error.code(), S3ErrorCode::InvalidArgument);
|
||||
assert!(s3_error.message().unwrap_or("").contains("Invalid argument"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_display() {
|
||||
let api_error = ApiError {
|
||||
code: S3ErrorCode::InternalError,
|
||||
message: "Test error message".to_string(),
|
||||
source: None,
|
||||
};
|
||||
|
||||
assert_eq!(api_error.to_string(), "Test error message");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_debug() {
|
||||
let api_error = ApiError {
|
||||
code: S3ErrorCode::NoSuchKey,
|
||||
message: "Object not found".to_string(),
|
||||
source: Some(Box::new(IoError::new(ErrorKind::NotFound, "file not found"))),
|
||||
};
|
||||
|
||||
let debug_str = format!("{:?}", api_error);
|
||||
assert!(debug_str.contains("NoSuchKey"));
|
||||
assert!(debug_str.contains("Object not found"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_roundtrip_through_io_error() {
|
||||
let original_io_error = IoError::new(ErrorKind::PermissionDenied, "original permission error");
|
||||
|
||||
// Convert to ApiError
|
||||
let api_error: ApiError = original_io_error.into();
|
||||
|
||||
// Verify the conversion preserved the information
|
||||
assert_eq!(api_error.code, S3ErrorCode::InternalError);
|
||||
assert!(api_error.message.contains("original permission error"));
|
||||
assert!(api_error.source.is_some());
|
||||
|
||||
// Test that we can downcast back to the original io::Error
|
||||
let source = api_error.source.as_ref().unwrap();
|
||||
let downcast_io_error = source.downcast_ref::<IoError>();
|
||||
assert!(downcast_io_error.is_some());
|
||||
assert_eq!(downcast_io_error.unwrap().kind(), ErrorKind::PermissionDenied);
|
||||
assert!(downcast_io_error.unwrap().to_string().contains("original permission error"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_chain_conversion() {
|
||||
// Start with an io::Error
|
||||
let io_error = IoError::new(ErrorKind::InvalidData, "invalid data");
|
||||
|
||||
// Convert to StorageError (simulating what happens in the codebase)
|
||||
let storage_error = StorageError::other(io_error);
|
||||
|
||||
// Convert to ApiError
|
||||
let api_error: ApiError = storage_error.into();
|
||||
|
||||
// Verify the chain is preserved
|
||||
assert!(api_error.source.is_some());
|
||||
|
||||
// Check that we can still access the original error information
|
||||
let source = api_error.source.as_ref().unwrap();
|
||||
let downcast_storage_error = source.downcast_ref::<StorageError>();
|
||||
assert!(downcast_storage_error.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_error_error_trait_implementation() {
|
||||
let api_error = ApiError {
|
||||
code: S3ErrorCode::InternalError,
|
||||
message: "Test error".to_string(),
|
||||
source: Some(Box::new(IoError::other("source error"))),
|
||||
};
|
||||
|
||||
// Test that it implements std::error::Error
|
||||
let error: &dyn std::error::Error = &api_error;
|
||||
assert_eq!(error.to_string(), "Test error");
|
||||
// ApiError doesn't implement Error::source() properly, so this would be None
|
||||
// This is expected because ApiError is not a typical Error implementation
|
||||
assert!(error.source().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
mod service_state;
|
||||
pub(crate) use service_state::wait_for_shutdown;
|
||||
pub(crate) use service_state::SHUTDOWN_TIMEOUT;
|
||||
pub(crate) use service_state::ServiceState;
|
||||
pub(crate) use service_state::ServiceStateManager;
|
||||
pub(crate) use service_state::ShutdownSignal;
|
||||
pub(crate) use service_state::SHUTDOWN_TIMEOUT;
|
||||
pub(crate) use service_state::wait_for_shutdown;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use atomic_enum::atomic_enum;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::time::Duration;
|
||||
use tokio::signal::unix::{signal, SignalKind};
|
||||
use tokio::signal::unix::{SignalKind, signal};
|
||||
use tracing::info;
|
||||
|
||||
// a configurable shutdown timeout
|
||||
@@ -10,7 +10,7 @@ pub(crate) const SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn notify_systemd(state: &str) {
|
||||
use libsystemd::daemon::{notify, NotifyState};
|
||||
use libsystemd::daemon::{NotifyState, notify};
|
||||
use tracing::{debug, error};
|
||||
let notify_state = match state {
|
||||
"ready" => NotifyState::Ready,
|
||||
|
||||
Reference in New Issue
Block a user