github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/bucket-replication-utils_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 cmd
    19  
    20  import (
    21  	"context"
    22  	"testing"
    23  
    24  	"github.com/minio/minio/internal/bucket/replication"
    25  )
    26  
    27  var replicatedInfosTests = []struct {
    28  	name                              string
    29  	tgtInfos                          []replicatedTargetInfo
    30  	expectedCompletedSize             int64
    31  	expectedReplicationStatusInternal string
    32  	expectedReplicationStatus         replication.StatusType
    33  	expectedOpType                    replication.Type
    34  	expectedAction                    replicationAction
    35  }{
    36  	{ // 1. empty tgtInfos slice
    37  		name:                              "no replicated targets",
    38  		tgtInfos:                          []replicatedTargetInfo{},
    39  		expectedCompletedSize:             0,
    40  		expectedReplicationStatusInternal: "",
    41  		expectedReplicationStatus:         replication.StatusType(""),
    42  		expectedOpType:                    replication.UnsetReplicationType,
    43  		expectedAction:                    replicateNone,
    44  	},
    45  	{ // 2. replication completed to single target
    46  		name: "replication completed to single target",
    47  		tgtInfos: []replicatedTargetInfo{
    48  			{
    49  				Arn:                   "arn1",
    50  				Size:                  249,
    51  				PrevReplicationStatus: replication.Pending,
    52  				ReplicationStatus:     replication.Completed,
    53  				OpType:                replication.ObjectReplicationType,
    54  				ReplicationAction:     replicateAll,
    55  			},
    56  		},
    57  		expectedCompletedSize:             249,
    58  		expectedReplicationStatusInternal: "arn1=COMPLETED;",
    59  		expectedReplicationStatus:         replication.Completed,
    60  		expectedOpType:                    replication.ObjectReplicationType,
    61  		expectedAction:                    replicateAll,
    62  	},
    63  	{ // 3. replication completed to single target; failed to another
    64  		name: "replication completed to single target",
    65  		tgtInfos: []replicatedTargetInfo{
    66  			{
    67  				Arn:                   "arn1",
    68  				Size:                  249,
    69  				PrevReplicationStatus: replication.Pending,
    70  				ReplicationStatus:     replication.Completed,
    71  				OpType:                replication.ObjectReplicationType,
    72  				ReplicationAction:     replicateAll,
    73  			},
    74  			{
    75  				Arn:                   "arn2",
    76  				Size:                  249,
    77  				PrevReplicationStatus: replication.Pending,
    78  				ReplicationStatus:     replication.Failed,
    79  				OpType:                replication.ObjectReplicationType,
    80  				ReplicationAction:     replicateAll,
    81  			},
    82  		},
    83  		expectedCompletedSize:             249,
    84  		expectedReplicationStatusInternal: "arn1=COMPLETED;arn2=FAILED;",
    85  		expectedReplicationStatus:         replication.Failed,
    86  		expectedOpType:                    replication.ObjectReplicationType,
    87  		expectedAction:                    replicateAll,
    88  	},
    89  	{ // 4. replication pending on one target; failed to another
    90  		name: "replication completed to single target",
    91  		tgtInfos: []replicatedTargetInfo{
    92  			{
    93  				Arn:                   "arn1",
    94  				Size:                  249,
    95  				PrevReplicationStatus: replication.Pending,
    96  				ReplicationStatus:     replication.Pending,
    97  				OpType:                replication.ObjectReplicationType,
    98  				ReplicationAction:     replicateAll,
    99  			},
   100  			{
   101  				Arn:                   "arn2",
   102  				Size:                  249,
   103  				PrevReplicationStatus: replication.Pending,
   104  				ReplicationStatus:     replication.Failed,
   105  				OpType:                replication.ObjectReplicationType,
   106  				ReplicationAction:     replicateAll,
   107  			},
   108  		},
   109  		expectedCompletedSize:             0,
   110  		expectedReplicationStatusInternal: "arn1=PENDING;arn2=FAILED;",
   111  		expectedReplicationStatus:         replication.Failed,
   112  		expectedOpType:                    replication.ObjectReplicationType,
   113  		expectedAction:                    replicateAll,
   114  	},
   115  }
   116  
   117  func TestReplicatedInfos(t *testing.T) {
   118  	for i, test := range replicatedInfosTests {
   119  		rinfos := replicatedInfos{
   120  			Targets: test.tgtInfos,
   121  		}
   122  		if actualSize := rinfos.CompletedSize(); actualSize != test.expectedCompletedSize {
   123  			t.Errorf("Test%d (%s): Size  got %d , want %d", i+1, test.name, actualSize, test.expectedCompletedSize)
   124  		}
   125  		if repStatusStr := rinfos.ReplicationStatusInternal(); repStatusStr != test.expectedReplicationStatusInternal {
   126  			t.Errorf("Test%d (%s): Internal replication status  got %s , want %s", i+1, test.name, repStatusStr, test.expectedReplicationStatusInternal)
   127  		}
   128  		if repStatus := rinfos.ReplicationStatus(); repStatus != test.expectedReplicationStatus {
   129  			t.Errorf("Test%d (%s): ReplicationStatus  got %s , want %s", i+1, test.name, repStatus, test.expectedReplicationStatus)
   130  		}
   131  		if action := rinfos.Action(); action != test.expectedAction {
   132  			t.Errorf("Test%d (%s): Action  got %s , want %s", i+1, test.name, action, test.expectedAction)
   133  		}
   134  	}
   135  }
   136  
   137  var parseReplicationDecisionTest = []struct {
   138  	name   string
   139  	dsc    string
   140  	expDsc ReplicateDecision
   141  	expErr error
   142  }{
   143  	{ // 1.
   144  		name: "empty string",
   145  		dsc:  "",
   146  		expDsc: ReplicateDecision{
   147  			targetsMap: map[string]replicateTargetDecision{},
   148  		},
   149  		expErr: nil,
   150  	},
   151  
   152  	{ // 2.
   153  		name:   "replicate decision for one target",
   154  		dsc:    "arn:minio:replication::id:bucket=true;false;arn:minio:replication::id:bucket;id",
   155  		expErr: nil,
   156  		expDsc: ReplicateDecision{
   157  			targetsMap: map[string]replicateTargetDecision{
   158  				"arn:minio:replication::id:bucket": newReplicateTargetDecision("arn:minio:replication::id:bucket", true, false),
   159  			},
   160  		},
   161  	},
   162  	{ // 3.
   163  		name:   "replicate decision for multiple targets",
   164  		dsc:    "arn:minio:replication::id:bucket=true;false;arn:minio:replication::id:bucket;id,arn:minio:replication::id2:bucket=false;true;arn:minio:replication::id2:bucket;id2",
   165  		expErr: nil,
   166  		expDsc: ReplicateDecision{
   167  			targetsMap: map[string]replicateTargetDecision{
   168  				"arn:minio:replication::id:bucket":  newReplicateTargetDecision("arn:minio:replication::id:bucket", true, false),
   169  				"arn:minio:replication::id2:bucket": newReplicateTargetDecision("arn:minio:replication::id2:bucket", false, true),
   170  			},
   171  		},
   172  	},
   173  	{ // 4.
   174  		name:   "invalid format replicate decision for one target",
   175  		dsc:    "arn:minio:replication::id:bucket:true;false;arn:minio:replication::id:bucket;id",
   176  		expErr: errInvalidReplicateDecisionFormat,
   177  		expDsc: ReplicateDecision{
   178  			targetsMap: map[string]replicateTargetDecision{
   179  				"arn:minio:replication::id:bucket": newReplicateTargetDecision("arn:minio:replication::id:bucket", true, false),
   180  			},
   181  		},
   182  	},
   183  }
   184  
   185  func TestParseReplicateDecision(t *testing.T) {
   186  	for i, test := range parseReplicationDecisionTest {
   187  		dsc, err := parseReplicateDecision(context.Background(), "bucket", test.expDsc.String())
   188  		if err != nil {
   189  			if test.expErr != err {
   190  				t.Errorf("Test%d (%s): Expected parse error got %t , want %t", i+1, test.name, err, test.expErr)
   191  			}
   192  			continue
   193  		}
   194  		if len(dsc.targetsMap) != len(test.expDsc.targetsMap) {
   195  			t.Errorf("Test%d (%s): Invalid number of entries in targetsMap  got %d , want %d", i+1, test.name, len(dsc.targetsMap), len(test.expDsc.targetsMap))
   196  		}
   197  		for arn, tdsc := range dsc.targetsMap {
   198  			expDsc, ok := test.expDsc.targetsMap[arn]
   199  			if !ok || expDsc != tdsc {
   200  				t.Errorf("Test%d (%s): Invalid  target replicate decision: got %+v, want %+v", i+1, test.name, tdsc, expDsc)
   201  			}
   202  		}
   203  	}
   204  }
   205  
   206  var replicationStateTest = []struct {
   207  	name      string
   208  	rs        ReplicationState
   209  	arn       string
   210  	expStatus replication.StatusType
   211  }{
   212  	{ // 1. no replication status header
   213  		name:      "no replicated targets",
   214  		rs:        ReplicationState{},
   215  		expStatus: replication.StatusType(""),
   216  	},
   217  	{ // 2. replication status for one target
   218  		name:      "replication status for one target",
   219  		rs:        ReplicationState{ReplicationStatusInternal: "arn1=PENDING;", Targets: map[string]replication.StatusType{"arn1": "PENDING"}},
   220  		expStatus: replication.Pending,
   221  	},
   222  	{ // 3. replication status for one target - incorrect format
   223  		name:      "replication status for one target",
   224  		rs:        ReplicationState{ReplicationStatusInternal: "arn1=PENDING"},
   225  		expStatus: replication.StatusType(""),
   226  	},
   227  	{ // 4. replication status for 3 targets, one of them failed
   228  		name: "replication status for 3 targets - one failed",
   229  		rs: ReplicationState{
   230  			ReplicationStatusInternal: "arn1=COMPLETED;arn2=COMPLETED;arn3=FAILED;",
   231  			Targets:                   map[string]replication.StatusType{"arn1": "COMPLETED", "arn2": "COMPLETED", "arn3": "FAILED"},
   232  		},
   233  		expStatus: replication.Failed,
   234  	},
   235  	{ // 5. replication status for replica version
   236  		name:      "replication status for replica version",
   237  		rs:        ReplicationState{ReplicationStatusInternal: string(replication.Replica)},
   238  		expStatus: replication.Replica,
   239  	},
   240  }
   241  
   242  func TestCompositeReplicationStatus(t *testing.T) {
   243  	for i, test := range replicationStateTest {
   244  		if rstatus := test.rs.CompositeReplicationStatus(); rstatus != test.expStatus {
   245  			t.Errorf("Test%d (%s): Overall replication status  got %s , want %s", i+1, test.name, rstatus, test.expStatus)
   246  		}
   247  	}
   248  }