github.com/minio/console@v1.4.1/api/user_buckets_lifecycle_test.go (about)

     1  // This file is part of MinIO Console Server
     2  // Copyright (c) 2021 MinIO, Inc.
     3  //
     4  // This program is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Affero General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // This program is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  // GNU Affero General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Affero General Public License
    15  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package api
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"testing"
    24  
    25  	"github.com/minio/console/models"
    26  	"github.com/stretchr/testify/assert"
    27  
    28  	bucketApi "github.com/minio/console/api/operations/bucket"
    29  	"github.com/minio/minio-go/v7/pkg/lifecycle"
    30  )
    31  
    32  // assigning mock at runtime instead of compile time
    33  var minioGetLifecycleRulesMock func(ctx context.Context, bucketName string) (lifecycle *lifecycle.Configuration, err error)
    34  
    35  // mock function of getLifecycleRules()
    36  func (ac minioClientMock) getLifecycleRules(ctx context.Context, bucketName string) (lifecycle *lifecycle.Configuration, err error) {
    37  	return minioGetLifecycleRulesMock(ctx, bucketName)
    38  }
    39  
    40  // assign mock for set Bucket Lifecycle
    41  var minioSetBucketLifecycleMock func(ctx context.Context, bucketName string, config *lifecycle.Configuration) error
    42  
    43  // mock function of setBucketLifecycle()
    44  func (ac minioClientMock) setBucketLifecycle(ctx context.Context, bucketName string, config *lifecycle.Configuration) error {
    45  	return minioSetBucketLifecycleMock(ctx, bucketName, config)
    46  }
    47  
    48  func TestGetLifecycleRules(t *testing.T) {
    49  	assert := assert.New(t)
    50  	// mock minIO client
    51  	minClient := minioClientMock{}
    52  
    53  	function := "getBucketLifecycle()"
    54  	bucketName := "testBucket"
    55  	ctx, cancel := context.WithCancel(context.Background())
    56  	defer cancel()
    57  
    58  	// Test-1 : getBucketLifecycle() get list of events for a particular bucket only one config
    59  	// mock lifecycle response from MinIO
    60  	mockLifecycle := lifecycle.Configuration{
    61  		Rules: []lifecycle.Rule{
    62  			{
    63  				ID:         "TESTRULE",
    64  				Expiration: lifecycle.Expiration{Days: 15},
    65  				Status:     "Enabled",
    66  				RuleFilter: lifecycle.Filter{Tag: lifecycle.Tag{Key: "tag1", Value: "val1"}, And: lifecycle.And{Prefix: "prefix1"}},
    67  			},
    68  		},
    69  	}
    70  
    71  	expectedOutput := models.BucketLifecycleResponse{
    72  		Lifecycle: []*models.ObjectBucketLifecycle{
    73  			{
    74  				ID:         "TESTRULE",
    75  				Status:     "Enabled",
    76  				Prefix:     "prefix1",
    77  				Expiration: &models.ExpirationResponse{Days: int64(15)},
    78  				Transition: &models.TransitionResponse{},
    79  				Tags:       []*models.LifecycleTag{{Key: "tag1", Value: "val1"}},
    80  			},
    81  		},
    82  	}
    83  
    84  	minioGetLifecycleRulesMock = func(_ context.Context, _ string) (lifecycle *lifecycle.Configuration, err error) {
    85  		return &mockLifecycle, nil
    86  	}
    87  
    88  	lifeCycleConfigs, err := getBucketLifecycle(ctx, minClient, bucketName)
    89  	if err != nil {
    90  		t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
    91  	}
    92  	// verify length of buckets is correct
    93  	assert.Equal(len(expectedOutput.Lifecycle), len(lifeCycleConfigs.Lifecycle), fmt.Sprintf("Failed on %s: length of lists is not the same", function))
    94  	for i, conf := range lifeCycleConfigs.Lifecycle {
    95  		assert.Equal(expectedOutput.Lifecycle[i].ID, conf.ID)
    96  		assert.Equal(expectedOutput.Lifecycle[i].Status, conf.Status)
    97  		assert.Equal(expectedOutput.Lifecycle[i].Prefix, conf.Prefix)
    98  		assert.Equal(expectedOutput.Lifecycle[i].Expiration.Days, conf.Expiration.Days)
    99  		for j, event := range conf.Tags {
   100  			assert.Equal(expectedOutput.Lifecycle[i].Tags[j], event)
   101  		}
   102  	}
   103  
   104  	// Test-2 : getBucketLifecycle() get list of events is empty
   105  	mockLifecycleT2 := lifecycle.Configuration{
   106  		Rules: []lifecycle.Rule{},
   107  	}
   108  
   109  	expectedOutputT2 := models.BucketLifecycleResponse{
   110  		Lifecycle: []*models.ObjectBucketLifecycle{},
   111  	}
   112  
   113  	minioGetLifecycleRulesMock = func(_ context.Context, _ string) (lifecycle *lifecycle.Configuration, err error) {
   114  		return &mockLifecycleT2, nil
   115  	}
   116  
   117  	lifeCycleConfigsT2, err := getBucketLifecycle(ctx, minClient, bucketName)
   118  	if err != nil {
   119  		t.Errorf("Failed on %s:, error occurred: %s", function, err.Error())
   120  	}
   121  	// verify length of buckets is correct
   122  	assert.Equal(len(expectedOutputT2.Lifecycle), len(lifeCycleConfigsT2.Lifecycle), fmt.Sprintf("Failed on %s: length of lists is not the same", function))
   123  
   124  	// Test-3 : getBucketLifecycle() get list of events returns an error
   125  
   126  	minioGetLifecycleRulesMock = func(_ context.Context, _ string) (lifecycle *lifecycle.Configuration, err error) {
   127  		return nil, errors.New("error returned")
   128  	}
   129  
   130  	_, errT3 := getBucketLifecycle(ctx, minClient, bucketName)
   131  
   132  	errorCompare := errors.New("error returned")
   133  
   134  	assert.Equal(errorCompare, errT3, fmt.Sprintf("Failed on %s: Invalid error message", function))
   135  
   136  	// verify length of buckets is correct
   137  	assert.Equal(len(expectedOutputT2.Lifecycle), len(lifeCycleConfigsT2.Lifecycle), fmt.Sprintf("Failed on %s: length of lists is not the same", function))
   138  }
   139  
   140  func TestSetLifecycleRule(t *testing.T) {
   141  	assert := assert.New(t)
   142  	// mock minIO client
   143  	minClient := minioClientMock{}
   144  
   145  	function := "addBucketLifecycle()"
   146  	ctx, cancel := context.WithCancel(context.Background())
   147  	defer cancel()
   148  
   149  	// Test-1 : addBucketLifecycle() get list of events for a particular bucket only one config
   150  	// mock create request
   151  	mockLifecycle := lifecycle.Configuration{
   152  		Rules: []lifecycle.Rule{
   153  			{
   154  				ID:         "TESTRULE",
   155  				Expiration: lifecycle.Expiration{Days: 15},
   156  				Status:     "Enabled",
   157  				RuleFilter: lifecycle.Filter{Tag: lifecycle.Tag{Key: "tag1", Value: "val1"}, And: lifecycle.And{Prefix: "prefix1"}},
   158  			},
   159  		},
   160  	}
   161  
   162  	minioGetLifecycleRulesMock = func(_ context.Context, _ string) (lifecycle *lifecycle.Configuration, err error) {
   163  		return &mockLifecycle, nil
   164  	}
   165  
   166  	expiryRule := "expiry"
   167  
   168  	insertMock := bucketApi.AddBucketLifecycleParams{
   169  		BucketName: "testBucket",
   170  		Body: &models.AddBucketLifecycle{
   171  			Type:                                    expiryRule,
   172  			Disable:                                 false,
   173  			ExpiredObjectDeleteMarker:               false,
   174  			ExpiryDays:                              int32(16),
   175  			NoncurrentversionExpirationDays:         0,
   176  			NoncurrentversionTransitionDays:         0,
   177  			NoncurrentversionTransitionStorageClass: "",
   178  			Prefix:                                  "pref1",
   179  			StorageClass:                            "",
   180  			Tags:                                    "",
   181  			TransitionDays:                          0,
   182  		},
   183  	}
   184  
   185  	minioSetBucketLifecycleMock = func(_ context.Context, _ string, _ *lifecycle.Configuration) error {
   186  		return nil
   187  	}
   188  
   189  	err := addBucketLifecycle(ctx, minClient, insertMock)
   190  
   191  	assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
   192  
   193  	// Test-2 : addBucketLifecycle() returns error
   194  
   195  	minioSetBucketLifecycleMock = func(_ context.Context, _ string, _ *lifecycle.Configuration) error {
   196  		return errors.New("error setting lifecycle")
   197  	}
   198  
   199  	err2 := addBucketLifecycle(ctx, minClient, insertMock)
   200  
   201  	assert.Equal(errors.New("error setting lifecycle"), err2, fmt.Sprintf("Failed on %s: Error returned", function))
   202  }
   203  
   204  func TestUpdateLifecycleRule(t *testing.T) {
   205  	assert := assert.New(t)
   206  	// mock minIO client
   207  	minClient := minioClientMock{}
   208  
   209  	function := "editBucketLifecycle()"
   210  	ctx, cancel := context.WithCancel(context.Background())
   211  	defer cancel()
   212  
   213  	// Test-1 : editBucketLifecycle() get list of events for a particular bucket only one config (get lifecycle mock)
   214  	// mock create request
   215  	mockLifecycle := lifecycle.Configuration{
   216  		Rules: []lifecycle.Rule{
   217  			{
   218  				ID:         "TESTRULE",
   219  				Expiration: lifecycle.Expiration{Days: 15},
   220  				Status:     "Enabled",
   221  				RuleFilter: lifecycle.Filter{Tag: lifecycle.Tag{Key: "tag1", Value: "val1"}, And: lifecycle.And{Prefix: "prefix1"}},
   222  			},
   223  		},
   224  	}
   225  
   226  	minioGetLifecycleRulesMock = func(_ context.Context, _ string) (lifecycle *lifecycle.Configuration, err error) {
   227  		return &mockLifecycle, nil
   228  	}
   229  
   230  	// Test-2 : editBucketLifecycle() Update lifecycle rule
   231  
   232  	expiryRule := "expiry"
   233  
   234  	editMock := bucketApi.UpdateBucketLifecycleParams{
   235  		BucketName: "testBucket",
   236  		Body: &models.UpdateBucketLifecycle{
   237  			Type:                                    &expiryRule,
   238  			Disable:                                 false,
   239  			ExpiredObjectDeleteMarker:               false,
   240  			ExpiryDays:                              int32(16),
   241  			NoncurrentversionExpirationDays:         0,
   242  			NoncurrentversionTransitionDays:         0,
   243  			NoncurrentversionTransitionStorageClass: "",
   244  			Prefix:                                  "pref1",
   245  			StorageClass:                            "",
   246  			Tags:                                    "",
   247  			TransitionDays:                          0,
   248  		},
   249  		LifecycleID: "TESTRULE",
   250  	}
   251  
   252  	minioSetBucketLifecycleMock = func(_ context.Context, _ string, _ *lifecycle.Configuration) error {
   253  		return nil
   254  	}
   255  
   256  	err := editBucketLifecycle(ctx, minClient, editMock)
   257  
   258  	assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
   259  
   260  	// Test-2a : editBucketLifecycle() Update lifecycle rule
   261  
   262  	transitionRule := "transition"
   263  
   264  	editMock = bucketApi.UpdateBucketLifecycleParams{
   265  		BucketName: "testBucket",
   266  		Body: &models.UpdateBucketLifecycle{
   267  			Type:                                    &transitionRule,
   268  			Disable:                                 false,
   269  			ExpiredObjectDeleteMarker:               false,
   270  			NoncurrentversionTransitionDays:         5,
   271  			Prefix:                                  "pref1",
   272  			StorageClass:                            "TEST",
   273  			NoncurrentversionTransitionStorageClass: "TESTNC",
   274  			Tags:                                    "",
   275  			TransitionDays:                          int32(16),
   276  		},
   277  		LifecycleID: "TESTRULE",
   278  	}
   279  
   280  	minioSetBucketLifecycleMock = func(_ context.Context, _ string, _ *lifecycle.Configuration) error {
   281  		return nil
   282  	}
   283  
   284  	err = editBucketLifecycle(ctx, minClient, editMock)
   285  
   286  	assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
   287  
   288  	// Test-3 : editBucketLifecycle() returns error
   289  
   290  	minioSetBucketLifecycleMock = func(_ context.Context, _ string, _ *lifecycle.Configuration) error {
   291  		return errors.New("error setting lifecycle")
   292  	}
   293  
   294  	err2 := editBucketLifecycle(ctx, minClient, editMock)
   295  
   296  	assert.Equal(errors.New("error setting lifecycle"), err2, fmt.Sprintf("Failed on %s: Error returned", function))
   297  }
   298  
   299  func TestDeleteLifecycleRule(t *testing.T) {
   300  	assert := assert.New(t)
   301  	// mock minIO client
   302  	minClient := minioClientMock{}
   303  
   304  	function := "deleteBucketLifecycle()"
   305  	ctx, cancel := context.WithCancel(context.Background())
   306  	defer cancel()
   307  
   308  	minioSetBucketLifecycleMock = func(_ context.Context, _ string, _ *lifecycle.Configuration) error {
   309  		return nil
   310  	}
   311  
   312  	// Test-1 : deleteBucketLifecycle() get list of events for a particular bucket only one config (get lifecycle mock)
   313  	// mock create request
   314  	mockLifecycle := lifecycle.Configuration{
   315  		Rules: []lifecycle.Rule{
   316  			{
   317  				ID:         "TESTRULE",
   318  				Expiration: lifecycle.Expiration{Days: 15},
   319  				Status:     "Enabled",
   320  				RuleFilter: lifecycle.Filter{Tag: lifecycle.Tag{Key: "tag1", Value: "val1"}, And: lifecycle.And{Prefix: "prefix1"}},
   321  			},
   322  			{
   323  				ID:         "TESTRULE2",
   324  				Transition: lifecycle.Transition{Days: 10, StorageClass: "TESTSTCLASS"},
   325  				Status:     "Enabled",
   326  				RuleFilter: lifecycle.Filter{Tag: lifecycle.Tag{Key: "tag1", Value: "val1"}, And: lifecycle.And{Prefix: "prefix1"}},
   327  			},
   328  		},
   329  	}
   330  
   331  	minioGetLifecycleRulesMock = func(_ context.Context, _ string) (lifecycle *lifecycle.Configuration, err error) {
   332  		return &mockLifecycle, nil
   333  	}
   334  
   335  	// Test-2 : deleteBucketLifecycle() try to delete an available rule
   336  
   337  	availableParams := bucketApi.DeleteBucketLifecycleRuleParams{
   338  		LifecycleID: "TESTRULE2",
   339  		BucketName:  "testBucket",
   340  	}
   341  
   342  	err := deleteBucketLifecycle(ctx, minClient, availableParams)
   343  
   344  	assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
   345  
   346  	// Test-3 : deleteBucketLifecycle() returns error trying to delete a non available rule
   347  
   348  	nonAvailableParams := bucketApi.DeleteBucketLifecycleRuleParams{
   349  		LifecycleID: "INVALIDTESTRULE",
   350  		BucketName:  "testBucket",
   351  	}
   352  
   353  	err2 := deleteBucketLifecycle(ctx, minClient, nonAvailableParams)
   354  
   355  	assert.Equal(fmt.Errorf("lifecycle rule for id '%s' doesn't exist", nonAvailableParams.LifecycleID), err2, fmt.Sprintf("Failed on %s: Error returned", function))
   356  
   357  	// Test-4 : deleteBucketLifecycle() returns error trying to delete a rule when no rules are available
   358  
   359  	mockLifecycle2 := lifecycle.Configuration{
   360  		Rules: []lifecycle.Rule{},
   361  	}
   362  
   363  	minioGetLifecycleRulesMock = func(_ context.Context, _ string) (lifecycle *lifecycle.Configuration, err error) {
   364  		return &mockLifecycle2, nil
   365  	}
   366  
   367  	err3 := deleteBucketLifecycle(ctx, minClient, nonAvailableParams)
   368  
   369  	assert.Equal(errors.New("no rules available to delete"), err3, fmt.Sprintf("Failed on %s: Error returned", function))
   370  }