diff --git a/rustfs/src/app/bucket_usecase.rs b/rustfs/src/app/bucket_usecase.rs index b72d2ecac..bf8f041e5 100644 --- a/rustfs/src/app/bucket_usecase.rs +++ b/rustfs/src/app/bucket_usecase.rs @@ -1669,6 +1669,28 @@ mod tests { assert!(versioning_configuration_has_object_lock_incompatible_settings(&config)); } + #[test] + fn versioning_configuration_has_object_lock_incompatible_settings_rejects_exclude_folders() { + let config = VersioningConfiguration { + exclude_folders: Some(true), + ..Default::default() + }; + + assert!(versioning_configuration_has_object_lock_incompatible_settings(&config)); + } + + #[test] + fn versioning_configuration_has_object_lock_incompatible_settings_rejects_excluded_prefixes() { + let config = VersioningConfiguration { + excluded_prefixes: Some(vec![ExcludedPrefix { + prefix: Some("archive/".to_string()), + }]), + ..Default::default() + }; + + assert!(versioning_configuration_has_object_lock_incompatible_settings(&config)); + } + #[test] fn resolve_notification_region_prefers_global_region() { let binding = resolve_notification_region(Some("us-east-1".parse().unwrap()), Some("ap-southeast-1".parse().unwrap())); diff --git a/rustfs/src/app/object_usecase.rs b/rustfs/src/app/object_usecase.rs index 1d00abc1d..57e0ddefd 100644 --- a/rustfs/src/app/object_usecase.rs +++ b/rustfs/src/app/object_usecase.rs @@ -5189,6 +5189,51 @@ mod tests { assert_eq!(err.code(), &S3ErrorCode::MalformedXML); } + #[test] + fn validate_object_lock_configuration_rejects_missing_default_retention() { + let cfg = ObjectLockConfiguration { + object_lock_enabled: Some(ObjectLockEnabled::from_static(ObjectLockEnabled::ENABLED)), + rule: Some(ObjectLockRule { default_retention: None }), + }; + + let err = validate_object_lock_configuration_input(&cfg).unwrap_err(); + assert_eq!(err.code(), &S3ErrorCode::MalformedXML); + } + + #[test] + fn validate_object_lock_configuration_rejects_zero_days() { + let cfg = ObjectLockConfiguration { + object_lock_enabled: Some(ObjectLockEnabled::from_static(ObjectLockEnabled::ENABLED)), + rule: Some(ObjectLockRule { + default_retention: Some(DefaultRetention { + mode: Some(ObjectLockRetentionMode::from_static(ObjectLockRetentionMode::GOVERNANCE)), + days: Some(0), + years: None, + }), + }), + }; + + let err = validate_object_lock_configuration_input(&cfg).unwrap_err(); + assert_eq!(err.code(), &S3ErrorCode::Custom("InvalidRetentionPeriod".into())); + } + + #[test] + fn validate_object_lock_configuration_rejects_too_many_years() { + let cfg = ObjectLockConfiguration { + object_lock_enabled: Some(ObjectLockEnabled::from_static(ObjectLockEnabled::ENABLED)), + rule: Some(ObjectLockRule { + default_retention: Some(DefaultRetention { + mode: Some(ObjectLockRetentionMode::from_static(ObjectLockRetentionMode::COMPLIANCE)), + days: None, + years: Some(MAXIMUM_RETENTION_YEARS + 1), + }), + }), + }; + + let err = validate_object_lock_configuration_input(&cfg).unwrap_err(); + assert_eq!(err.code(), &S3ErrorCode::Custom("InvalidRetentionPeriod".into())); + } + #[tokio::test] async fn execute_put_object_retention_returns_internal_error_when_store_uninitialized() { let input = PutObjectRetentionInput::builder()