github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/bucket/object/lock/lock_test.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package lock
    19  
    20  import (
    21  	"encoding/xml"
    22  	"errors"
    23  	"fmt"
    24  	"net/http"
    25  	"reflect"
    26  	"strings"
    27  	"testing"
    28  	"time"
    29  
    30  	xhttp "github.com/minio/minio/internal/http"
    31  )
    32  
    33  func TestParseMode(t *testing.T) {
    34  	testCases := []struct {
    35  		value        string
    36  		expectedMode RetMode
    37  	}{
    38  		{
    39  			value:        "governance",
    40  			expectedMode: RetGovernance,
    41  		},
    42  		{
    43  			value:        "complIAnce",
    44  			expectedMode: RetCompliance,
    45  		},
    46  		{
    47  			value:        "gce",
    48  			expectedMode: "",
    49  		},
    50  	}
    51  
    52  	for _, tc := range testCases {
    53  		if parseRetMode(tc.value) != tc.expectedMode {
    54  			t.Errorf("Expected Mode %s, got %s", tc.expectedMode, parseRetMode(tc.value))
    55  		}
    56  	}
    57  }
    58  
    59  func TestParseLegalHoldStatus(t *testing.T) {
    60  	tests := []struct {
    61  		value          string
    62  		expectedStatus LegalHoldStatus
    63  	}{
    64  		{
    65  			value:          "ON",
    66  			expectedStatus: LegalHoldOn,
    67  		},
    68  		{
    69  			value:          "Off",
    70  			expectedStatus: LegalHoldOff,
    71  		},
    72  		{
    73  			value:          "x",
    74  			expectedStatus: "",
    75  		},
    76  	}
    77  
    78  	for _, tt := range tests {
    79  		actualStatus := parseLegalHoldStatus(tt.value)
    80  		if actualStatus != tt.expectedStatus {
    81  			t.Errorf("Expected legal hold status %s, got %s", tt.expectedStatus, actualStatus)
    82  		}
    83  	}
    84  }
    85  
    86  // TestUnmarshalDefaultRetention checks if default retention
    87  // marshaling and unmarshalling work as expected
    88  func TestUnmarshalDefaultRetention(t *testing.T) {
    89  	days := uint64(4)
    90  	years := uint64(1)
    91  	zerodays := uint64(0)
    92  	invalidDays := uint64(maximumRetentionDays + 1)
    93  	tests := []struct {
    94  		value       DefaultRetention
    95  		expectedErr error
    96  		expectErr   bool
    97  	}{
    98  		{
    99  			value:       DefaultRetention{Mode: "retain"},
   100  			expectedErr: fmt.Errorf("unknown retention mode retain"),
   101  			expectErr:   true,
   102  		},
   103  		{
   104  			value:       DefaultRetention{Mode: RetGovernance},
   105  			expectedErr: fmt.Errorf("either Days or Years must be specified"),
   106  			expectErr:   true,
   107  		},
   108  		{
   109  			value:       DefaultRetention{Mode: RetGovernance, Days: &days},
   110  			expectedErr: nil,
   111  			expectErr:   false,
   112  		},
   113  		{
   114  			value:       DefaultRetention{Mode: RetGovernance, Years: &years},
   115  			expectedErr: nil,
   116  			expectErr:   false,
   117  		},
   118  		{
   119  			value:       DefaultRetention{Mode: RetGovernance, Days: &days, Years: &years},
   120  			expectedErr: fmt.Errorf("either Days or Years must be specified, not both"),
   121  			expectErr:   true,
   122  		},
   123  		{
   124  			value:       DefaultRetention{Mode: RetGovernance, Days: &zerodays},
   125  			expectedErr: fmt.Errorf("Default retention period must be a positive integer value for 'Days'"),
   126  			expectErr:   true,
   127  		},
   128  		{
   129  			value:       DefaultRetention{Mode: RetGovernance, Days: &invalidDays},
   130  			expectedErr: fmt.Errorf("Default retention period too large for 'Days' %d", invalidDays),
   131  			expectErr:   true,
   132  		},
   133  	}
   134  	for _, tt := range tests {
   135  		d, err := xml.MarshalIndent(&tt.value, "", "\t")
   136  		if err != nil {
   137  			t.Fatal(err)
   138  		}
   139  		var dr DefaultRetention
   140  		err = xml.Unmarshal(d, &dr)
   141  		//nolint:gocritic
   142  		if tt.expectedErr == nil {
   143  			if err != nil {
   144  				t.Fatalf("error: expected = <nil>, got = %v", err)
   145  			}
   146  		} else if err == nil {
   147  			t.Fatalf("error: expected = %v, got = <nil>", tt.expectedErr)
   148  		} else if tt.expectedErr.Error() != err.Error() {
   149  			t.Fatalf("error: expected = %v, got = %v", tt.expectedErr, err)
   150  		}
   151  	}
   152  }
   153  
   154  func TestParseObjectLockConfig(t *testing.T) {
   155  	tests := []struct {
   156  		value       string
   157  		expectedErr error
   158  		expectErr   bool
   159  	}{
   160  		{
   161  			value:       `<ObjectLockConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><ObjectLockEnabled>yes</ObjectLockEnabled></ObjectLockConfiguration>`,
   162  			expectedErr: fmt.Errorf("only 'Enabled' value is allowed to ObjectLockEnabled element"),
   163  			expectErr:   true,
   164  		},
   165  		{
   166  			value:       `<ObjectLockConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><ObjectLockEnabled>Enabled</ObjectLockEnabled><Rule><DefaultRetention><Mode>COMPLIANCE</Mode><Days>0</Days></DefaultRetention></Rule></ObjectLockConfiguration>`,
   167  			expectedErr: fmt.Errorf("Default retention period must be a positive integer value for 'Days'"),
   168  			expectErr:   true,
   169  		},
   170  		{
   171  			value:       `<ObjectLockConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><ObjectLockEnabled>Enabled</ObjectLockEnabled><Rule><DefaultRetention><Mode>COMPLIANCE</Mode><Days>30</Days></DefaultRetention></Rule></ObjectLockConfiguration>`,
   172  			expectedErr: nil,
   173  			expectErr:   false,
   174  		},
   175  	}
   176  	for _, tt := range tests {
   177  		tt := tt
   178  		t.Run("", func(t *testing.T) {
   179  			_, err := ParseObjectLockConfig(strings.NewReader(tt.value))
   180  			//nolint:gocritic
   181  			if tt.expectedErr == nil {
   182  				if err != nil {
   183  					t.Fatalf("error: expected = <nil>, got = %v", err)
   184  				}
   185  			} else if err == nil {
   186  				t.Fatalf("error: expected = %v, got = <nil>", tt.expectedErr)
   187  			} else if tt.expectedErr.Error() != err.Error() {
   188  				t.Fatalf("error: expected = %v, got = %v", tt.expectedErr, err)
   189  			}
   190  		})
   191  	}
   192  }
   193  
   194  func TestParseObjectRetention(t *testing.T) {
   195  	tests := []struct {
   196  		value       string
   197  		expectedErr error
   198  		expectErr   bool
   199  	}{
   200  		{
   201  			value:       `<?xml version="1.0" encoding="UTF-8"?><Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Mode>string</Mode><RetainUntilDate>2020-01-02T15:04:05Z</RetainUntilDate></Retention>`,
   202  			expectedErr: ErrUnknownWORMModeDirective,
   203  			expectErr:   true,
   204  		},
   205  		{
   206  			value:       `<?xml version="1.0" encoding="UTF-8"?><Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Mode>COMPLIANCE</Mode><RetainUntilDate>2017-01-02T15:04:05Z</RetainUntilDate></Retention>`,
   207  			expectedErr: ErrPastObjectLockRetainDate,
   208  			expectErr:   true,
   209  		},
   210  		{
   211  			value:       `<?xml version="1.0" encoding="UTF-8"?><Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Mode>GOVERNANCE</Mode><RetainUntilDate>2057-01-02T15:04:05Z</RetainUntilDate></Retention>`,
   212  			expectedErr: nil,
   213  			expectErr:   false,
   214  		},
   215  		{
   216  			value:       `<?xml version="1.0" encoding="UTF-8"?><Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Mode>GOVERNANCE</Mode><RetainUntilDate>2057-01-02T15:04:05.000Z</RetainUntilDate></Retention>`,
   217  			expectedErr: nil,
   218  			expectErr:   false,
   219  		},
   220  	}
   221  	for _, tt := range tests {
   222  		tt := tt
   223  		t.Run("", func(t *testing.T) {
   224  			_, err := ParseObjectRetention(strings.NewReader(tt.value))
   225  			//nolint:gocritic
   226  			if tt.expectedErr == nil {
   227  				if err != nil {
   228  					t.Fatalf("error: expected = <nil>, got = %v", err)
   229  				}
   230  			} else if err == nil {
   231  				t.Fatalf("error: expected = %v, got = <nil>", tt.expectedErr)
   232  			} else if tt.expectedErr.Error() != err.Error() {
   233  				t.Fatalf("error: expected = %v, got = %v", tt.expectedErr, err)
   234  			}
   235  		})
   236  	}
   237  }
   238  
   239  func TestIsObjectLockRequested(t *testing.T) {
   240  	tests := []struct {
   241  		header      http.Header
   242  		expectedVal bool
   243  	}{
   244  		{
   245  			header: http.Header{
   246  				"Authorization":        []string{"AWS4-HMAC-SHA256 <cred_string>"},
   247  				"X-Amz-Content-Sha256": []string{""},
   248  				"Content-Encoding":     []string{""},
   249  			},
   250  			expectedVal: false,
   251  		},
   252  		{
   253  			header: http.Header{
   254  				AmzObjectLockLegalHold: []string{""},
   255  			},
   256  			expectedVal: true,
   257  		},
   258  		{
   259  			header: http.Header{
   260  				AmzObjectLockRetainUntilDate: []string{""},
   261  				AmzObjectLockMode:            []string{""},
   262  			},
   263  			expectedVal: true,
   264  		},
   265  		{
   266  			header: http.Header{
   267  				AmzObjectLockBypassRetGovernance: []string{""},
   268  			},
   269  			expectedVal: false,
   270  		},
   271  	}
   272  	for _, tt := range tests {
   273  		actualVal := IsObjectLockRequested(tt.header)
   274  		if actualVal != tt.expectedVal {
   275  			t.Fatalf("error: expected %v, actual %v", tt.expectedVal, actualVal)
   276  		}
   277  	}
   278  }
   279  
   280  func TestIsObjectLockGovernanceBypassSet(t *testing.T) {
   281  	tests := []struct {
   282  		header      http.Header
   283  		expectedVal bool
   284  	}{
   285  		{
   286  			header: http.Header{
   287  				"Authorization":        []string{"AWS4-HMAC-SHA256 <cred_string>"},
   288  				"X-Amz-Content-Sha256": []string{""},
   289  				"Content-Encoding":     []string{""},
   290  			},
   291  			expectedVal: false,
   292  		},
   293  		{
   294  			header: http.Header{
   295  				AmzObjectLockLegalHold: []string{""},
   296  			},
   297  			expectedVal: false,
   298  		},
   299  		{
   300  			header: http.Header{
   301  				AmzObjectLockRetainUntilDate: []string{""},
   302  				AmzObjectLockMode:            []string{""},
   303  			},
   304  			expectedVal: false,
   305  		},
   306  		{
   307  			header: http.Header{
   308  				AmzObjectLockBypassRetGovernance: []string{""},
   309  			},
   310  			expectedVal: false,
   311  		},
   312  		{
   313  			header: http.Header{
   314  				AmzObjectLockBypassRetGovernance: []string{"true"},
   315  			},
   316  			expectedVal: true,
   317  		},
   318  	}
   319  	for _, tt := range tests {
   320  		actualVal := IsObjectLockGovernanceBypassSet(tt.header)
   321  		if actualVal != tt.expectedVal {
   322  			t.Fatalf("error: expected %v, actual %v", tt.expectedVal, actualVal)
   323  		}
   324  	}
   325  }
   326  
   327  func TestParseObjectLockRetentionHeaders(t *testing.T) {
   328  	tests := []struct {
   329  		header      http.Header
   330  		expectedErr error
   331  	}{
   332  		{
   333  			header: http.Header{
   334  				"Authorization":        []string{"AWS4-HMAC-SHA256 <cred_string>"},
   335  				"X-Amz-Content-Sha256": []string{""},
   336  				"Content-Encoding":     []string{""},
   337  			},
   338  			expectedErr: ErrObjectLockInvalidHeaders,
   339  		},
   340  		{
   341  			header: http.Header{
   342  				xhttp.AmzObjectLockMode:            []string{"lock"},
   343  				xhttp.AmzObjectLockRetainUntilDate: []string{"2017-01-02"},
   344  			},
   345  			expectedErr: ErrUnknownWORMModeDirective,
   346  		},
   347  		{
   348  			header: http.Header{
   349  				xhttp.AmzObjectLockMode: []string{"governance"},
   350  			},
   351  			expectedErr: ErrObjectLockInvalidHeaders,
   352  		},
   353  		{
   354  			header: http.Header{
   355  				xhttp.AmzObjectLockRetainUntilDate: []string{"2017-01-02"},
   356  				xhttp.AmzObjectLockMode:            []string{"governance"},
   357  			},
   358  			expectedErr: ErrInvalidRetentionDate,
   359  		},
   360  		{
   361  			header: http.Header{
   362  				xhttp.AmzObjectLockRetainUntilDate: []string{"2017-01-02T15:04:05Z"},
   363  				xhttp.AmzObjectLockMode:            []string{"governance"},
   364  			},
   365  			expectedErr: ErrPastObjectLockRetainDate,
   366  		},
   367  		{
   368  			header: http.Header{
   369  				xhttp.AmzObjectLockMode:            []string{"governance"},
   370  				xhttp.AmzObjectLockRetainUntilDate: []string{"2017-01-02T15:04:05Z"},
   371  			},
   372  			expectedErr: ErrPastObjectLockRetainDate,
   373  		},
   374  		{
   375  			header: http.Header{
   376  				xhttp.AmzObjectLockMode:            []string{"governance"},
   377  				xhttp.AmzObjectLockRetainUntilDate: []string{"2087-01-02T15:04:05Z"},
   378  			},
   379  			expectedErr: nil,
   380  		},
   381  		{
   382  			header: http.Header{
   383  				xhttp.AmzObjectLockMode:            []string{"governance"},
   384  				xhttp.AmzObjectLockRetainUntilDate: []string{"2087-01-02T15:04:05.000Z"},
   385  			},
   386  			expectedErr: nil,
   387  		},
   388  	}
   389  
   390  	for i, tt := range tests {
   391  		_, _, err := ParseObjectLockRetentionHeaders(tt.header)
   392  		//nolint:gocritic
   393  		if tt.expectedErr == nil {
   394  			if err != nil {
   395  				t.Fatalf("Case %d error: expected = <nil>, got = %v", i, err)
   396  			}
   397  		} else if err == nil {
   398  			t.Fatalf("Case %d error: expected = %v, got = <nil>", i, tt.expectedErr)
   399  		} else if tt.expectedErr.Error() != err.Error() {
   400  			t.Fatalf("Case %d error: expected = %v, got = %v", i, tt.expectedErr, err)
   401  		}
   402  	}
   403  }
   404  
   405  func TestGetObjectRetentionMeta(t *testing.T) {
   406  	tests := []struct {
   407  		metadata map[string]string
   408  		expected ObjectRetention
   409  	}{
   410  		{
   411  			metadata: map[string]string{
   412  				"Authorization":        "AWS4-HMAC-SHA256 <cred_string>",
   413  				"X-Amz-Content-Sha256": "",
   414  				"Content-Encoding":     "",
   415  			},
   416  			expected: ObjectRetention{},
   417  		},
   418  		{
   419  			metadata: map[string]string{
   420  				"x-amz-object-lock-mode": "governance",
   421  			},
   422  			expected: ObjectRetention{Mode: RetGovernance},
   423  		},
   424  		{
   425  			metadata: map[string]string{
   426  				"x-amz-object-lock-retain-until-date": "2020-02-01",
   427  			},
   428  			expected: ObjectRetention{RetainUntilDate: RetentionDate{time.Date(2020, 2, 1, 12, 0, 0, 0, time.UTC)}},
   429  		},
   430  	}
   431  
   432  	for i, tt := range tests {
   433  		o := GetObjectRetentionMeta(tt.metadata)
   434  		if o.Mode != tt.expected.Mode {
   435  			t.Fatalf("Case %d expected %v, got %v", i, tt.expected.Mode, o.Mode)
   436  		}
   437  	}
   438  }
   439  
   440  func TestGetObjectLegalHoldMeta(t *testing.T) {
   441  	tests := []struct {
   442  		metadata map[string]string
   443  		expected ObjectLegalHold
   444  	}{
   445  		{
   446  			metadata: map[string]string{
   447  				"x-amz-object-lock-mode": "governance",
   448  			},
   449  			expected: ObjectLegalHold{},
   450  		},
   451  		{
   452  			metadata: map[string]string{
   453  				"x-amz-object-lock-legal-hold": "on",
   454  			},
   455  			expected: ObjectLegalHold{Status: LegalHoldOn},
   456  		},
   457  		{
   458  			metadata: map[string]string{
   459  				"x-amz-object-lock-legal-hold": "off",
   460  			},
   461  			expected: ObjectLegalHold{Status: LegalHoldOff},
   462  		},
   463  		{
   464  			metadata: map[string]string{
   465  				"x-amz-object-lock-legal-hold": "X",
   466  			},
   467  			expected: ObjectLegalHold{Status: ""},
   468  		},
   469  	}
   470  
   471  	for i, tt := range tests {
   472  		o := GetObjectLegalHoldMeta(tt.metadata)
   473  		if o.Status != tt.expected.Status {
   474  			t.Fatalf("Case %d expected %v, got %v", i, tt.expected.Status, o.Status)
   475  		}
   476  	}
   477  }
   478  
   479  func TestParseObjectLegalHold(t *testing.T) {
   480  	tests := []struct {
   481  		value       string
   482  		expectedErr error
   483  		expectErr   bool
   484  	}{
   485  		{
   486  			value:       `<?xml version="1.0" encoding="UTF-8"?><LegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Status>string</Status></LegalHold>`,
   487  			expectedErr: ErrMalformedXML,
   488  			expectErr:   true,
   489  		},
   490  		{
   491  			value:       `<?xml version="1.0" encoding="UTF-8"?><LegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Status>ON</Status></LegalHold>`,
   492  			expectedErr: nil,
   493  			expectErr:   false,
   494  		},
   495  		{
   496  			value:       `<?xml version="1.0" encoding="UTF-8"?><ObjectLockLegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Status>ON</Status></ObjectLockLegalHold>`,
   497  			expectedErr: nil,
   498  			expectErr:   false,
   499  		},
   500  		// invalid Status key
   501  		{
   502  			value:       `<?xml version="1.0" encoding="UTF-8"?><ObjectLockLegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><MyStatus>ON</MyStatus></ObjectLockLegalHold>`,
   503  			expectedErr: errors.New("expected element type <Status> but have <MyStatus>"),
   504  			expectErr:   true,
   505  		},
   506  		// invalid XML attr
   507  		{
   508  			value:       `<?xml version="1.0" encoding="UTF-8"?><UnknownLegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Status>ON</Status></UnknownLegalHold>`,
   509  			expectedErr: errors.New("expected element type <LegalHold>/<ObjectLockLegalHold> but have <UnknownLegalHold>"),
   510  			expectErr:   true,
   511  		},
   512  		{
   513  			value:       `<?xml version="1.0" encoding="UTF-8"?><LegalHold xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Status>On</Status></LegalHold>`,
   514  			expectedErr: ErrMalformedXML,
   515  			expectErr:   true,
   516  		},
   517  	}
   518  	for i, tt := range tests {
   519  		_, err := ParseObjectLegalHold(strings.NewReader(tt.value))
   520  		//nolint:gocritic
   521  		if tt.expectedErr == nil {
   522  			if err != nil {
   523  				t.Fatalf("Case %d error: expected = <nil>, got = %v", i, err)
   524  			}
   525  		} else if err == nil {
   526  			t.Fatalf("Case %d error: expected = %v, got = <nil>", i, tt.expectedErr)
   527  		} else if tt.expectedErr.Error() != err.Error() {
   528  			t.Fatalf("Case %d error: expected = %v, got = %v", i, tt.expectedErr, err)
   529  		}
   530  	}
   531  }
   532  
   533  func TestFilterObjectLockMetadata(t *testing.T) {
   534  	tests := []struct {
   535  		metadata        map[string]string
   536  		filterRetention bool
   537  		filterLegalHold bool
   538  		expected        map[string]string
   539  	}{
   540  		{
   541  			metadata: map[string]string{
   542  				"Authorization":        "AWS4-HMAC-SHA256 <cred_string>",
   543  				"X-Amz-Content-Sha256": "",
   544  				"Content-Encoding":     "",
   545  			},
   546  			expected: map[string]string{
   547  				"Authorization":        "AWS4-HMAC-SHA256 <cred_string>",
   548  				"X-Amz-Content-Sha256": "",
   549  				"Content-Encoding":     "",
   550  			},
   551  		},
   552  		{
   553  			metadata: map[string]string{
   554  				"x-amz-object-lock-mode": "governance",
   555  			},
   556  			expected: map[string]string{
   557  				"x-amz-object-lock-mode": "governance",
   558  			},
   559  			filterRetention: false,
   560  		},
   561  		{
   562  			metadata: map[string]string{
   563  				"x-amz-object-lock-mode":              "governance",
   564  				"x-amz-object-lock-retain-until-date": "2020-02-01",
   565  			},
   566  			expected:        map[string]string{},
   567  			filterRetention: true,
   568  		},
   569  		{
   570  			metadata: map[string]string{
   571  				"x-amz-object-lock-legal-hold": "off",
   572  			},
   573  			expected:        map[string]string{},
   574  			filterLegalHold: true,
   575  		},
   576  		{
   577  			metadata: map[string]string{
   578  				"x-amz-object-lock-legal-hold": "on",
   579  			},
   580  			expected:        map[string]string{"x-amz-object-lock-legal-hold": "on"},
   581  			filterLegalHold: false,
   582  		},
   583  		{
   584  			metadata: map[string]string{
   585  				"x-amz-object-lock-legal-hold":        "on",
   586  				"x-amz-object-lock-mode":              "governance",
   587  				"x-amz-object-lock-retain-until-date": "2020-02-01",
   588  			},
   589  			expected:        map[string]string{},
   590  			filterRetention: true,
   591  			filterLegalHold: true,
   592  		},
   593  		{
   594  			metadata: map[string]string{
   595  				"x-amz-object-lock-legal-hold":        "on",
   596  				"x-amz-object-lock-mode":              "governance",
   597  				"x-amz-object-lock-retain-until-date": "2020-02-01",
   598  			},
   599  			expected: map[string]string{
   600  				"x-amz-object-lock-legal-hold":        "on",
   601  				"x-amz-object-lock-mode":              "governance",
   602  				"x-amz-object-lock-retain-until-date": "2020-02-01",
   603  			},
   604  		},
   605  	}
   606  
   607  	for i, tt := range tests {
   608  		o := FilterObjectLockMetadata(tt.metadata, tt.filterRetention, tt.filterLegalHold)
   609  		if !reflect.DeepEqual(o, tt.metadata) {
   610  			t.Fatalf("Case %d expected %v, got %v", i, tt.metadata, o)
   611  		}
   612  	}
   613  }