mirror of
https://github.com/chrislusf/seaweedfs
synced 2025-07-24 20:42:47 +02:00
739 lines
19 KiB
Go
739 lines
19 KiB
Go
package s3api
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
|
)
|
|
|
|
// TODO: If needed, re-implement TestPutObjectRetention with proper setup for buckets, objects, and versioning.
|
|
|
|
func TestValidateRetention(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
retention *ObjectRetention
|
|
expectError bool
|
|
errorMsg string
|
|
}{
|
|
{
|
|
name: "Valid GOVERNANCE retention",
|
|
retention: &ObjectRetention{
|
|
Mode: s3_constants.RetentionModeGovernance,
|
|
RetainUntilDate: timePtr(time.Now().Add(24 * time.Hour)),
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Valid COMPLIANCE retention",
|
|
retention: &ObjectRetention{
|
|
Mode: s3_constants.RetentionModeCompliance,
|
|
RetainUntilDate: timePtr(time.Now().Add(24 * time.Hour)),
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Missing Mode",
|
|
retention: &ObjectRetention{
|
|
RetainUntilDate: timePtr(time.Now().Add(24 * time.Hour)),
|
|
},
|
|
expectError: true,
|
|
errorMsg: "retention configuration must specify Mode",
|
|
},
|
|
{
|
|
name: "Missing RetainUntilDate",
|
|
retention: &ObjectRetention{
|
|
Mode: s3_constants.RetentionModeGovernance,
|
|
},
|
|
expectError: true,
|
|
errorMsg: "retention configuration must specify RetainUntilDate",
|
|
},
|
|
{
|
|
name: "Invalid Mode",
|
|
retention: &ObjectRetention{
|
|
Mode: "INVALID_MODE",
|
|
RetainUntilDate: timePtr(time.Now().Add(24 * time.Hour)),
|
|
},
|
|
expectError: true,
|
|
errorMsg: "invalid retention mode",
|
|
},
|
|
{
|
|
name: "Past RetainUntilDate",
|
|
retention: &ObjectRetention{
|
|
Mode: s3_constants.RetentionModeGovernance,
|
|
RetainUntilDate: timePtr(time.Now().Add(-24 * time.Hour)),
|
|
},
|
|
expectError: true,
|
|
errorMsg: "retain until date must be in the future",
|
|
},
|
|
{
|
|
name: "Empty retention",
|
|
retention: &ObjectRetention{},
|
|
expectError: true,
|
|
errorMsg: "retention configuration must specify Mode",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := ValidateRetention(tt.retention)
|
|
|
|
if tt.expectError {
|
|
if err == nil {
|
|
t.Errorf("Expected error but got none")
|
|
} else if !strings.Contains(err.Error(), tt.errorMsg) {
|
|
t.Errorf("Expected error message to contain '%s', got: %v", tt.errorMsg, err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateLegalHold(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
legalHold *ObjectLegalHold
|
|
expectError bool
|
|
errorMsg string
|
|
}{
|
|
{
|
|
name: "Valid ON status",
|
|
legalHold: &ObjectLegalHold{
|
|
Status: s3_constants.LegalHoldOn,
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Valid OFF status",
|
|
legalHold: &ObjectLegalHold{
|
|
Status: s3_constants.LegalHoldOff,
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Invalid status",
|
|
legalHold: &ObjectLegalHold{
|
|
Status: "INVALID_STATUS",
|
|
},
|
|
expectError: true,
|
|
errorMsg: "invalid legal hold status",
|
|
},
|
|
{
|
|
name: "Empty status",
|
|
legalHold: &ObjectLegalHold{
|
|
Status: "",
|
|
},
|
|
expectError: true,
|
|
errorMsg: "invalid legal hold status",
|
|
},
|
|
{
|
|
name: "Lowercase on",
|
|
legalHold: &ObjectLegalHold{
|
|
Status: "on",
|
|
},
|
|
expectError: true,
|
|
errorMsg: "invalid legal hold status",
|
|
},
|
|
{
|
|
name: "Lowercase off",
|
|
legalHold: &ObjectLegalHold{
|
|
Status: "off",
|
|
},
|
|
expectError: true,
|
|
errorMsg: "invalid legal hold status",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := ValidateLegalHold(tt.legalHold)
|
|
|
|
if tt.expectError {
|
|
if err == nil {
|
|
t.Errorf("Expected error but got none")
|
|
} else if !strings.Contains(err.Error(), tt.errorMsg) {
|
|
t.Errorf("Expected error message to contain '%s', got: %v", tt.errorMsg, err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseObjectRetention(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
xmlBody string
|
|
expectError bool
|
|
errorMsg string
|
|
expectedResult *ObjectRetention
|
|
}{
|
|
{
|
|
name: "Valid retention XML",
|
|
xmlBody: `<Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
<Mode>GOVERNANCE</Mode>
|
|
<RetainUntilDate>2024-12-31T23:59:59Z</RetainUntilDate>
|
|
</Retention>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectRetention{
|
|
Mode: "GOVERNANCE",
|
|
RetainUntilDate: timePtr(time.Date(2024, 12, 31, 23, 59, 59, 0, time.UTC)),
|
|
},
|
|
},
|
|
{
|
|
name: "Valid compliance retention XML",
|
|
xmlBody: `<Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
<Mode>COMPLIANCE</Mode>
|
|
<RetainUntilDate>2025-01-01T00:00:00Z</RetainUntilDate>
|
|
</Retention>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectRetention{
|
|
Mode: "COMPLIANCE",
|
|
RetainUntilDate: timePtr(time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)),
|
|
},
|
|
},
|
|
{
|
|
name: "Empty XML body",
|
|
xmlBody: "",
|
|
expectError: true,
|
|
errorMsg: "error parsing XML",
|
|
},
|
|
{
|
|
name: "Invalid XML",
|
|
xmlBody: `<Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Mode>GOVERNANCE</Mode><RetainUntilDate>invalid-date</RetainUntilDate></Retention>`,
|
|
expectError: true,
|
|
errorMsg: "cannot parse",
|
|
},
|
|
{
|
|
name: "Malformed XML",
|
|
xmlBody: "<Retention><Mode>GOVERNANCE</Mode><RetainUntilDate>2024-12-31T23:59:59Z</Retention>",
|
|
expectError: true,
|
|
errorMsg: "error parsing XML",
|
|
},
|
|
{
|
|
name: "Missing Mode",
|
|
xmlBody: `<Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
<RetainUntilDate>2024-12-31T23:59:59Z</RetainUntilDate>
|
|
</Retention>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectRetention{
|
|
Mode: "",
|
|
RetainUntilDate: timePtr(time.Date(2024, 12, 31, 23, 59, 59, 0, time.UTC)),
|
|
},
|
|
},
|
|
{
|
|
name: "Missing RetainUntilDate",
|
|
xmlBody: `<Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
<Mode>GOVERNANCE</Mode>
|
|
</Retention>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectRetention{
|
|
Mode: "GOVERNANCE",
|
|
RetainUntilDate: nil,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Create a mock HTTP request with XML body
|
|
req := &http.Request{
|
|
Body: io.NopCloser(strings.NewReader(tt.xmlBody)),
|
|
}
|
|
|
|
result, err := parseObjectRetention(req)
|
|
|
|
if tt.expectError {
|
|
if err == nil {
|
|
t.Errorf("Expected error but got none")
|
|
} else if !strings.Contains(err.Error(), tt.errorMsg) {
|
|
t.Errorf("Expected error message to contain '%s', got: %v", tt.errorMsg, err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
if result == nil {
|
|
t.Errorf("Expected result but got nil")
|
|
} else {
|
|
if result.Mode != tt.expectedResult.Mode {
|
|
t.Errorf("Expected Mode %s, got %s", tt.expectedResult.Mode, result.Mode)
|
|
}
|
|
if tt.expectedResult.RetainUntilDate == nil {
|
|
if result.RetainUntilDate != nil {
|
|
t.Errorf("Expected RetainUntilDate to be nil, got %v", result.RetainUntilDate)
|
|
}
|
|
} else if result.RetainUntilDate == nil {
|
|
t.Errorf("Expected RetainUntilDate to be %v, got nil", tt.expectedResult.RetainUntilDate)
|
|
} else if !result.RetainUntilDate.Equal(*tt.expectedResult.RetainUntilDate) {
|
|
t.Errorf("Expected RetainUntilDate %v, got %v", tt.expectedResult.RetainUntilDate, result.RetainUntilDate)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseObjectLegalHold(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
xmlBody string
|
|
expectError bool
|
|
errorMsg string
|
|
expectedResult *ObjectLegalHold
|
|
}{
|
|
{
|
|
name: "Valid legal hold ON",
|
|
xmlBody: `<LegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
<Status>ON</Status>
|
|
</LegalHold>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectLegalHold{
|
|
Status: "ON",
|
|
},
|
|
},
|
|
{
|
|
name: "Valid legal hold OFF",
|
|
xmlBody: `<LegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
<Status>OFF</Status>
|
|
</LegalHold>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectLegalHold{
|
|
Status: "OFF",
|
|
},
|
|
},
|
|
{
|
|
name: "Empty XML body",
|
|
xmlBody: "",
|
|
expectError: true,
|
|
errorMsg: "error parsing XML",
|
|
},
|
|
{
|
|
name: "Invalid XML",
|
|
xmlBody: "<LegalHold><Status>ON</Status>",
|
|
expectError: true,
|
|
errorMsg: "error parsing XML",
|
|
},
|
|
{
|
|
name: "Missing Status",
|
|
xmlBody: `<LegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
</LegalHold>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectLegalHold{
|
|
Status: "",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Create a mock HTTP request with XML body
|
|
req := &http.Request{
|
|
Body: io.NopCloser(strings.NewReader(tt.xmlBody)),
|
|
}
|
|
|
|
result, err := parseObjectLegalHold(req)
|
|
|
|
if tt.expectError {
|
|
if err == nil {
|
|
t.Errorf("Expected error but got none")
|
|
} else if !strings.Contains(err.Error(), tt.errorMsg) {
|
|
t.Errorf("Expected error message to contain '%s', got: %v", tt.errorMsg, err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
if result == nil {
|
|
t.Errorf("Expected result but got nil")
|
|
} else {
|
|
if result.Status != tt.expectedResult.Status {
|
|
t.Errorf("Expected Status %s, got %s", tt.expectedResult.Status, result.Status)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseObjectLockConfiguration(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
xmlBody string
|
|
expectError bool
|
|
errorMsg string
|
|
expectedResult *ObjectLockConfiguration
|
|
}{
|
|
{
|
|
name: "Valid object lock configuration",
|
|
xmlBody: `<ObjectLockConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
<ObjectLockEnabled>Enabled</ObjectLockEnabled>
|
|
</ObjectLockConfiguration>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
},
|
|
},
|
|
{
|
|
name: "Valid object lock configuration with rule",
|
|
xmlBody: `<ObjectLockConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
<ObjectLockEnabled>Enabled</ObjectLockEnabled>
|
|
<Rule>
|
|
<DefaultRetention>
|
|
<Mode>GOVERNANCE</Mode>
|
|
<Days>30</Days>
|
|
</DefaultRetention>
|
|
</Rule>
|
|
</ObjectLockConfiguration>`,
|
|
expectError: false,
|
|
expectedResult: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
Days: 30,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Empty XML body",
|
|
xmlBody: "",
|
|
expectError: true,
|
|
errorMsg: "error parsing XML",
|
|
},
|
|
{
|
|
name: "Invalid XML",
|
|
xmlBody: "<ObjectLockConfiguration><ObjectLockEnabled>Enabled</ObjectLockEnabled>",
|
|
expectError: true,
|
|
errorMsg: "error parsing XML",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Create a mock HTTP request with XML body
|
|
req := &http.Request{
|
|
Body: io.NopCloser(strings.NewReader(tt.xmlBody)),
|
|
}
|
|
|
|
result, err := parseObjectLockConfiguration(req)
|
|
|
|
if tt.expectError {
|
|
if err == nil {
|
|
t.Errorf("Expected error but got none")
|
|
} else if !strings.Contains(err.Error(), tt.errorMsg) {
|
|
t.Errorf("Expected error message to contain '%s', got: %v", tt.errorMsg, err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
if result == nil {
|
|
t.Errorf("Expected result but got nil")
|
|
} else {
|
|
if result.ObjectLockEnabled != tt.expectedResult.ObjectLockEnabled {
|
|
t.Errorf("Expected ObjectLockEnabled %s, got %s", tt.expectedResult.ObjectLockEnabled, result.ObjectLockEnabled)
|
|
}
|
|
if tt.expectedResult.Rule == nil {
|
|
if result.Rule != nil {
|
|
t.Errorf("Expected Rule to be nil, got %v", result.Rule)
|
|
}
|
|
} else if result.Rule == nil {
|
|
t.Errorf("Expected Rule to be non-nil")
|
|
} else {
|
|
if result.Rule.DefaultRetention == nil {
|
|
t.Errorf("Expected DefaultRetention to be non-nil")
|
|
} else {
|
|
if result.Rule.DefaultRetention.Mode != tt.expectedResult.Rule.DefaultRetention.Mode {
|
|
t.Errorf("Expected DefaultRetention Mode %s, got %s", tt.expectedResult.Rule.DefaultRetention.Mode, result.Rule.DefaultRetention.Mode)
|
|
}
|
|
if result.Rule.DefaultRetention.Days != tt.expectedResult.Rule.DefaultRetention.Days {
|
|
t.Errorf("Expected DefaultRetention Days %d, got %d", tt.expectedResult.Rule.DefaultRetention.Days, result.Rule.DefaultRetention.Days)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateObjectLockConfiguration(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
config *ObjectLockConfiguration
|
|
expectError bool
|
|
errorMsg string
|
|
}{
|
|
{
|
|
name: "Valid config with ObjectLockEnabled only",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Missing ObjectLockEnabled",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "",
|
|
},
|
|
expectError: true,
|
|
errorMsg: "object lock configuration must specify ObjectLockEnabled",
|
|
},
|
|
{
|
|
name: "Valid config with rule and days",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
Days: 30,
|
|
DaysSet: true,
|
|
},
|
|
},
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Valid config with rule and years",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Mode: "COMPLIANCE",
|
|
Years: 1,
|
|
YearsSet: true,
|
|
},
|
|
},
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Invalid ObjectLockEnabled value",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "InvalidValue",
|
|
},
|
|
expectError: true,
|
|
errorMsg: "invalid object lock enabled value",
|
|
},
|
|
{
|
|
name: "Invalid rule - missing mode",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Days: 30,
|
|
},
|
|
},
|
|
},
|
|
expectError: true,
|
|
errorMsg: "default retention must specify Mode",
|
|
},
|
|
{
|
|
name: "Invalid rule - both days and years",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
Days: 30,
|
|
Years: 1,
|
|
DaysSet: true,
|
|
YearsSet: true,
|
|
},
|
|
},
|
|
},
|
|
expectError: true,
|
|
errorMsg: "default retention cannot specify both Days and Years",
|
|
},
|
|
{
|
|
name: "Invalid rule - neither days nor years",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
},
|
|
},
|
|
},
|
|
expectError: true,
|
|
errorMsg: "default retention must specify either Days or Years",
|
|
},
|
|
{
|
|
name: "Invalid rule - invalid mode",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Mode: "INVALID_MODE",
|
|
Days: 30,
|
|
DaysSet: true,
|
|
},
|
|
},
|
|
},
|
|
expectError: true,
|
|
errorMsg: "invalid default retention mode",
|
|
},
|
|
{
|
|
name: "Invalid rule - days out of range",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
Days: 50000,
|
|
DaysSet: true,
|
|
},
|
|
},
|
|
},
|
|
expectError: true,
|
|
errorMsg: fmt.Sprintf("default retention days must be between 0 and %d", MaxRetentionDays),
|
|
},
|
|
{
|
|
name: "Invalid rule - years out of range",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
Years: 200,
|
|
YearsSet: true,
|
|
},
|
|
},
|
|
},
|
|
expectError: true,
|
|
errorMsg: fmt.Sprintf("default retention years must be between 0 and %d", MaxRetentionYears),
|
|
},
|
|
{
|
|
name: "Invalid rule - missing DefaultRetention",
|
|
config: &ObjectLockConfiguration{
|
|
ObjectLockEnabled: "Enabled",
|
|
Rule: &ObjectLockRule{
|
|
DefaultRetention: nil,
|
|
},
|
|
},
|
|
expectError: true,
|
|
errorMsg: "rule configuration must specify DefaultRetention",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := ValidateObjectLockConfiguration(tt.config)
|
|
|
|
if tt.expectError {
|
|
if err == nil {
|
|
t.Errorf("Expected error but got none")
|
|
} else if !strings.Contains(err.Error(), tt.errorMsg) {
|
|
t.Errorf("Expected error message to contain '%s', got: %v", tt.errorMsg, err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateDefaultRetention(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
retention *DefaultRetention
|
|
expectError bool
|
|
errorMsg string
|
|
}{
|
|
{
|
|
name: "Valid retention with days",
|
|
retention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
Days: 30,
|
|
DaysSet: true,
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Valid retention with years",
|
|
retention: &DefaultRetention{
|
|
Mode: "COMPLIANCE",
|
|
Years: 1,
|
|
YearsSet: true,
|
|
},
|
|
expectError: false,
|
|
},
|
|
{
|
|
name: "Missing mode",
|
|
retention: &DefaultRetention{
|
|
Days: 30,
|
|
DaysSet: true,
|
|
},
|
|
expectError: true,
|
|
errorMsg: "default retention must specify Mode",
|
|
},
|
|
{
|
|
name: "Invalid mode",
|
|
retention: &DefaultRetention{
|
|
Mode: "INVALID",
|
|
Days: 30,
|
|
DaysSet: true,
|
|
},
|
|
expectError: true,
|
|
errorMsg: "invalid default retention mode",
|
|
},
|
|
{
|
|
name: "Both days and years specified",
|
|
retention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
Days: 30,
|
|
Years: 1,
|
|
DaysSet: true,
|
|
YearsSet: true,
|
|
},
|
|
expectError: true,
|
|
errorMsg: "default retention cannot specify both Days and Years",
|
|
},
|
|
{
|
|
name: "Neither days nor years specified",
|
|
retention: &DefaultRetention{
|
|
Mode: "GOVERNANCE",
|
|
},
|
|
expectError: true,
|
|
errorMsg: "default retention must specify either Days or Years",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := validateDefaultRetention(tt.retention)
|
|
|
|
if tt.expectError {
|
|
if err == nil {
|
|
t.Errorf("Expected error but got none")
|
|
} else if !strings.Contains(err.Error(), tt.errorMsg) {
|
|
t.Errorf("Expected error message to contain '%s', got: %v", tt.errorMsg, err)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Helper function to create a time pointer
|
|
func timePtr(t time.Time) *time.Time {
|
|
return &t
|
|
}
|