github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/config/storageclass/storage-class_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 storageclass
    19  
    20  import (
    21  	"errors"
    22  	"reflect"
    23  	"testing"
    24  )
    25  
    26  func TestParseStorageClass(t *testing.T) {
    27  	tests := []struct {
    28  		storageClassEnv string
    29  		wantSc          StorageClass
    30  		expectedError   error
    31  	}{
    32  		{
    33  			"EC:3",
    34  			StorageClass{
    35  				Parity: 3,
    36  			},
    37  			nil,
    38  		},
    39  		{
    40  			"EC:4",
    41  			StorageClass{
    42  				Parity: 4,
    43  			},
    44  			nil,
    45  		},
    46  		{
    47  			"AB:4",
    48  			StorageClass{
    49  				Parity: 4,
    50  			},
    51  			errors.New("Unsupported scheme AB. Supported scheme is EC"),
    52  		},
    53  		{
    54  			"EC:4:5",
    55  			StorageClass{
    56  				Parity: 4,
    57  			},
    58  			errors.New("Too many sections in EC:4:5"),
    59  		},
    60  		{
    61  			"EC:A",
    62  			StorageClass{
    63  				Parity: 4,
    64  			},
    65  			errors.New(`strconv.Atoi: parsing "A": invalid syntax`),
    66  		},
    67  		{
    68  			"AB",
    69  			StorageClass{
    70  				Parity: 4,
    71  			},
    72  			errors.New("Too few sections in AB"),
    73  		},
    74  	}
    75  	for i, tt := range tests {
    76  		gotSc, err := parseStorageClass(tt.storageClassEnv)
    77  		if err != nil && tt.expectedError == nil {
    78  			t.Errorf("Test %d, Expected %s, got %s", i+1, tt.expectedError, err)
    79  			return
    80  		}
    81  		if err == nil && tt.expectedError != nil {
    82  			t.Errorf("Test %d, Expected %s, got %s", i+1, tt.expectedError, err)
    83  			return
    84  		}
    85  		if tt.expectedError == nil && !reflect.DeepEqual(gotSc, tt.wantSc) {
    86  			t.Errorf("Test %d, Expected %v, got %v", i+1, tt.wantSc, gotSc)
    87  			return
    88  		}
    89  		if tt.expectedError != nil && err.Error() != tt.expectedError.Error() {
    90  			t.Errorf("Test %d, Expected `%v`, got `%v`", i+1, tt.expectedError, err)
    91  		}
    92  	}
    93  }
    94  
    95  func TestValidateParity(t *testing.T) {
    96  	tests := []struct {
    97  		rrsParity     int
    98  		ssParity      int
    99  		success       bool
   100  		setDriveCount int
   101  	}{
   102  		{2, 4, true, 16},
   103  		{3, 3, true, 16},
   104  		{0, 0, true, 16},
   105  		{1, 4, true, 16},
   106  		{0, 4, true, 16},
   107  		{7, 6, false, 16},
   108  		{9, 0, false, 16},
   109  		{9, 9, false, 16},
   110  		{2, 9, false, 16},
   111  		{9, 2, false, 16},
   112  	}
   113  	for i, tt := range tests {
   114  		err := validateParity(tt.ssParity, tt.rrsParity, tt.setDriveCount)
   115  		if err != nil && tt.success {
   116  			t.Errorf("Test %d, Expected success, got %s", i+1, err)
   117  		}
   118  		if err == nil && !tt.success {
   119  			t.Errorf("Test %d, Expected failure, got success", i+1)
   120  		}
   121  	}
   122  }
   123  
   124  func TestParityCount(t *testing.T) {
   125  	tests := []struct {
   126  		sc             string
   127  		drivesCount    int
   128  		expectedData   int
   129  		expectedParity int
   130  	}{
   131  		{RRS, 16, 14, 2},
   132  		{STANDARD, 16, 8, 8},
   133  		{"", 16, 8, 8},
   134  		{RRS, 16, 9, 7},
   135  		{STANDARD, 16, 10, 6},
   136  		{"", 16, 9, 7},
   137  	}
   138  	for i, tt := range tests {
   139  		scfg := Config{
   140  			Standard: StorageClass{
   141  				Parity: 8,
   142  			},
   143  			RRS: StorageClass{
   144  				Parity: 2,
   145  			},
   146  			initialized: true,
   147  		}
   148  		// Set env var for test case 4
   149  		if i+1 == 4 {
   150  			scfg.RRS.Parity = 7
   151  		}
   152  		// Set env var for test case 5
   153  		if i+1 == 5 {
   154  			scfg.Standard.Parity = 6
   155  		}
   156  		// Set env var for test case 6
   157  		if i+1 == 6 {
   158  			scfg.Standard.Parity = 7
   159  		}
   160  		parity := scfg.GetParityForSC(tt.sc)
   161  		if (tt.drivesCount - parity) != tt.expectedData {
   162  			t.Errorf("Test %d, Expected data drives %d, got %d", i+1, tt.expectedData, tt.drivesCount-parity)
   163  			continue
   164  		}
   165  		if parity != tt.expectedParity {
   166  			t.Errorf("Test %d, Expected parity drives %d, got %d", i+1, tt.expectedParity, parity)
   167  		}
   168  	}
   169  }
   170  
   171  // Test IsValid method with valid and invalid inputs
   172  func TestIsValidStorageClassKind(t *testing.T) {
   173  	tests := []struct {
   174  		sc   string
   175  		want bool
   176  	}{
   177  		{"STANDARD", true},
   178  		{"REDUCED_REDUNDANCY", true},
   179  		{"", false},
   180  		{"INVALID", false},
   181  		{"123", false},
   182  		{"MINIO_STORAGE_CLASS_RRS", false},
   183  		{"MINIO_STORAGE_CLASS_STANDARD", false},
   184  	}
   185  	for i, tt := range tests {
   186  		if got := IsValid(tt.sc); got != tt.want {
   187  			t.Errorf("Test %d, Expected Storage Class to be %t, got %t", i+1, tt.want, got)
   188  		}
   189  	}
   190  }