storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/erasure-metadata_test.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2015, 2016, 2017 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"context"
    21  	"strconv"
    22  	"testing"
    23  	"time"
    24  
    25  	humanize "github.com/dustin/go-humanize"
    26  )
    27  
    28  const ActualSize = 1000
    29  
    30  // Test FileInfo.AddObjectPart()
    31  func TestAddObjectPart(t *testing.T) {
    32  	testCases := []struct {
    33  		partNum       int
    34  		expectedIndex int
    35  	}{
    36  		{1, 0},
    37  		{2, 1},
    38  		{4, 2},
    39  		{5, 3},
    40  		{7, 4},
    41  		// Insert part.
    42  		{3, 2},
    43  		// Replace existing part.
    44  		{4, 3},
    45  		// Missing part.
    46  		{6, -1},
    47  	}
    48  
    49  	// Setup.
    50  	fi := newFileInfo("test-object", 8, 8)
    51  	fi.Erasure.Index = 1
    52  	if !fi.IsValid() {
    53  		t.Fatalf("unable to get xl meta")
    54  	}
    55  
    56  	// Test them.
    57  	for _, testCase := range testCases {
    58  		if testCase.expectedIndex > -1 {
    59  			partNumString := strconv.Itoa(testCase.partNum)
    60  			fi.AddObjectPart(testCase.partNum, "etag."+partNumString, int64(testCase.partNum+humanize.MiByte), ActualSize)
    61  		}
    62  
    63  		if index := objectPartIndex(fi.Parts, testCase.partNum); index != testCase.expectedIndex {
    64  			t.Fatalf("%+v: expected = %d, got: %d", testCase, testCase.expectedIndex, index)
    65  		}
    66  	}
    67  }
    68  
    69  // Test objectPartIndex(). generates a sample FileInfo data and asserts
    70  // the output of objectPartIndex() with the expected value.
    71  func TestObjectPartIndex(t *testing.T) {
    72  	testCases := []struct {
    73  		partNum       int
    74  		expectedIndex int
    75  	}{
    76  		{2, 1},
    77  		{1, 0},
    78  		{5, 3},
    79  		{4, 2},
    80  		{7, 4},
    81  	}
    82  
    83  	// Setup.
    84  	fi := newFileInfo("test-object", 8, 8)
    85  	fi.Erasure.Index = 1
    86  	if !fi.IsValid() {
    87  		t.Fatalf("unable to get xl meta")
    88  	}
    89  
    90  	// Add some parts for testing.
    91  	for _, testCase := range testCases {
    92  		partNumString := strconv.Itoa(testCase.partNum)
    93  		fi.AddObjectPart(testCase.partNum, "etag."+partNumString, int64(testCase.partNum+humanize.MiByte), ActualSize)
    94  	}
    95  
    96  	// Add failure test case.
    97  	testCases = append(testCases, struct {
    98  		partNum       int
    99  		expectedIndex int
   100  	}{6, -1})
   101  
   102  	// Test them.
   103  	for _, testCase := range testCases {
   104  		if index := objectPartIndex(fi.Parts, testCase.partNum); index != testCase.expectedIndex {
   105  			t.Fatalf("%+v: expected = %d, got: %d", testCase, testCase.expectedIndex, index)
   106  		}
   107  	}
   108  }
   109  
   110  // Test FileInfo.ObjectToPartOffset().
   111  func TestObjectToPartOffset(t *testing.T) {
   112  	// Setup.
   113  	fi := newFileInfo("test-object", 8, 8)
   114  	fi.Erasure.Index = 1
   115  	if !fi.IsValid() {
   116  		t.Fatalf("unable to get xl meta")
   117  	}
   118  
   119  	// Add some parts for testing.
   120  	// Total size of all parts is 5,242,899 bytes.
   121  	for _, partNum := range []int{1, 2, 4, 5, 7} {
   122  		partNumString := strconv.Itoa(partNum)
   123  		fi.AddObjectPart(partNum, "etag."+partNumString, int64(partNum+humanize.MiByte), ActualSize)
   124  	}
   125  
   126  	testCases := []struct {
   127  		offset         int64
   128  		expectedIndex  int
   129  		expectedOffset int64
   130  		expectedErr    error
   131  	}{
   132  		{0, 0, 0, nil},
   133  		{1 * humanize.MiByte, 0, 1 * humanize.MiByte, nil},
   134  		{1 + humanize.MiByte, 1, 0, nil},
   135  		{2 + humanize.MiByte, 1, 1, nil},
   136  		// Its valid for zero sized object.
   137  		{-1, 0, -1, nil},
   138  		// Max fffset is always (size - 1).
   139  		{(1 + 2 + 4 + 5 + 7) + (5 * humanize.MiByte) - 1, 4, 1048582, nil},
   140  		// Error if offset is size.
   141  		{(1 + 2 + 4 + 5 + 7) + (5 * humanize.MiByte), 0, 0, InvalidRange{}},
   142  	}
   143  
   144  	// Test them.
   145  	for _, testCase := range testCases {
   146  		index, offset, err := fi.ObjectToPartOffset(context.Background(), testCase.offset)
   147  		if err != testCase.expectedErr {
   148  			t.Fatalf("%+v: expected = %s, got: %s", testCase, testCase.expectedErr, err)
   149  		}
   150  		if index != testCase.expectedIndex {
   151  			t.Fatalf("%+v: index: expected = %d, got: %d", testCase, testCase.expectedIndex, index)
   152  		}
   153  		if offset != testCase.expectedOffset {
   154  			t.Fatalf("%+v: offset: expected = %d, got: %d", testCase, testCase.expectedOffset, offset)
   155  		}
   156  	}
   157  }
   158  
   159  func TestFindFileInfoInQuorum(t *testing.T) {
   160  	getNFInfo := func(n int, quorum int, t int64, dataDir string) []FileInfo {
   161  		fi := newFileInfo("test", 8, 8)
   162  		fi.AddObjectPart(1, "etag", 100, 100)
   163  		fi.ModTime = time.Unix(t, 0)
   164  		fi.DataDir = dataDir
   165  		fis := make([]FileInfo, n)
   166  		for i := range fis {
   167  			fis[i] = fi
   168  			fis[i].Erasure.Index = i + 1
   169  			quorum--
   170  			if quorum == 0 {
   171  				break
   172  			}
   173  		}
   174  		return fis
   175  	}
   176  
   177  	tests := []struct {
   178  		fis         []FileInfo
   179  		modTime     time.Time
   180  		dataDir     string
   181  		expectedErr error
   182  	}{
   183  		{
   184  			fis:         getNFInfo(16, 16, 1603863445, "36a21454-a2ca-11eb-bbaa-93a81c686f21"),
   185  			modTime:     time.Unix(1603863445, 0),
   186  			dataDir:     "36a21454-a2ca-11eb-bbaa-93a81c686f21",
   187  			expectedErr: nil,
   188  		},
   189  		{
   190  			fis:         getNFInfo(16, 7, 1603863445, "36a21454-a2ca-11eb-bbaa-93a81c686f21"),
   191  			modTime:     time.Unix(1603863445, 0),
   192  			dataDir:     "36a21454-a2ca-11eb-bbaa-93a81c686f21",
   193  			expectedErr: errErasureReadQuorum,
   194  		},
   195  	}
   196  
   197  	for _, test := range tests {
   198  		test := test
   199  		t.Run("", func(t *testing.T) {
   200  			_, err := findFileInfoInQuorum(context.Background(), test.fis, test.modTime, test.dataDir, 8)
   201  			if err != test.expectedErr {
   202  				t.Errorf("Expected %s, got %s", test.expectedErr, err)
   203  			}
   204  		})
   205  	}
   206  }