storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/pkg/hash/reader_test.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 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 hash
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/hex"
    22  	"fmt"
    23  	"io"
    24  	"io/ioutil"
    25  	"testing"
    26  )
    27  
    28  // Tests functions like Size(), MD5*(), SHA256*()
    29  func TestHashReaderHelperMethods(t *testing.T) {
    30  	r, err := NewReader(bytes.NewReader([]byte("abcd")), 4, "e2fc714c4727ee9395f324cd2e7f331f", "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", 4)
    31  	if err != nil {
    32  		t.Fatal(err)
    33  	}
    34  	_, err = io.Copy(ioutil.Discard, r)
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	if r.MD5HexString() != "e2fc714c4727ee9395f324cd2e7f331f" {
    39  		t.Errorf("Expected md5hex \"e2fc714c4727ee9395f324cd2e7f331f\", got %s", r.MD5HexString())
    40  	}
    41  	if r.SHA256HexString() != "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589" {
    42  		t.Errorf("Expected sha256hex \"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589\", got %s", r.SHA256HexString())
    43  	}
    44  	if r.MD5Base64String() != "4vxxTEcn7pOV8yTNLn8zHw==" {
    45  		t.Errorf("Expected md5base64 \"4vxxTEcn7pOV8yTNLn8zHw==\", got \"%s\"", r.MD5Base64String())
    46  	}
    47  	if r.Size() != 4 {
    48  		t.Errorf("Expected size 4, got %d", r.Size())
    49  	}
    50  	if r.ActualSize() != 4 {
    51  		t.Errorf("Expected size 4, got %d", r.ActualSize())
    52  	}
    53  	expectedMD5, err := hex.DecodeString("e2fc714c4727ee9395f324cd2e7f331f")
    54  	if err != nil {
    55  		t.Fatal(err)
    56  	}
    57  	if !bytes.Equal(r.MD5(), expectedMD5) {
    58  		t.Errorf("Expected md5hex \"e2fc714c4727ee9395f324cd2e7f331f\", got %s", r.MD5HexString())
    59  	}
    60  	if !bytes.Equal(r.MD5Current(), expectedMD5) {
    61  		t.Errorf("Expected md5hex \"e2fc714c4727ee9395f324cd2e7f331f\", got %s", hex.EncodeToString(r.MD5Current()))
    62  	}
    63  	expectedSHA256, err := hex.DecodeString("88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589")
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	if !bytes.Equal(r.SHA256(), expectedSHA256) {
    68  		t.Errorf("Expected md5hex \"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589\", got %s", r.SHA256HexString())
    69  	}
    70  }
    71  
    72  // Tests hash reader checksum verification.
    73  func TestHashReaderVerification(t *testing.T) {
    74  	testCases := []struct {
    75  		desc              string
    76  		src               io.Reader
    77  		size              int64
    78  		actualSize        int64
    79  		md5hex, sha256hex string
    80  		err               error
    81  	}{
    82  		{
    83  			desc:       "Success, no checksum verification provided.",
    84  			src:        bytes.NewReader([]byte("abcd")),
    85  			size:       4,
    86  			actualSize: 4,
    87  		},
    88  		{
    89  			desc:       "Failure md5 mismatch.",
    90  			src:        bytes.NewReader([]byte("abcd")),
    91  			size:       4,
    92  			actualSize: 4,
    93  			md5hex:     "d41d8cd98f00b204e9800998ecf8427f",
    94  			err: BadDigest{
    95  				"d41d8cd98f00b204e9800998ecf8427f",
    96  				"e2fc714c4727ee9395f324cd2e7f331f",
    97  			},
    98  		},
    99  		{
   100  			desc:       "Failure sha256 mismatch.",
   101  			src:        bytes.NewReader([]byte("abcd")),
   102  			size:       4,
   103  			actualSize: 4,
   104  			sha256hex:  "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031580",
   105  			err: SHA256Mismatch{
   106  				"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031580",
   107  				"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
   108  			},
   109  		},
   110  		{
   111  			desc:       "Nested hash reader NewReader() should merge.",
   112  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "", "", 4),
   113  			size:       4,
   114  			actualSize: 4,
   115  		},
   116  		{
   117  			desc:       "Incorrect sha256, nested",
   118  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "", "", 4),
   119  			size:       4,
   120  			actualSize: 4,
   121  			sha256hex:  "50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c",
   122  			err: SHA256Mismatch{
   123  				ExpectedSHA256:   "50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c",
   124  				CalculatedSHA256: "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
   125  			},
   126  		},
   127  		{
   128  			desc:       "Correct sha256, nested",
   129  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "", "", 4),
   130  			size:       4,
   131  			actualSize: 4,
   132  			sha256hex:  "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
   133  		},
   134  		{
   135  			desc:       "Correct sha256, nested, truncated",
   136  			src:        mustReader(t, bytes.NewReader([]byte("abcd-more-stuff-to-be ignored")), 4, "", "", 4),
   137  			size:       4,
   138  			actualSize: -1,
   139  			sha256hex:  "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
   140  		},
   141  		{
   142  			desc:       "Correct sha256, nested, truncated, swapped",
   143  			src:        mustReader(t, bytes.NewReader([]byte("abcd-more-stuff-to-be ignored")), 4, "", "", -1),
   144  			size:       4,
   145  			actualSize: -1,
   146  			sha256hex:  "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
   147  		},
   148  		{
   149  			desc:       "Incorrect MD5, nested",
   150  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "", "", 4),
   151  			size:       4,
   152  			actualSize: 4,
   153  			md5hex:     "0773da587b322af3a8718cb418a715ce",
   154  			err: BadDigest{
   155  				ExpectedMD5:   "0773da587b322af3a8718cb418a715ce",
   156  				CalculatedMD5: "e2fc714c4727ee9395f324cd2e7f331f",
   157  			},
   158  		},
   159  		{
   160  			desc:       "Correct sha256, truncated",
   161  			src:        bytes.NewReader([]byte("abcd-morethan-4-bytes")),
   162  			size:       4,
   163  			actualSize: 4,
   164  			sha256hex:  "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
   165  		},
   166  		{
   167  			desc:       "Correct MD5, nested",
   168  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "", "", 4),
   169  			size:       4,
   170  			actualSize: 4,
   171  			md5hex:     "e2fc714c4727ee9395f324cd2e7f331f",
   172  		},
   173  		{
   174  			desc:       "Correct MD5, truncated",
   175  			src:        bytes.NewReader([]byte("abcd-morethan-4-bytes")),
   176  			size:       4,
   177  			actualSize: 4,
   178  			sha256hex:  "",
   179  			md5hex:     "e2fc714c4727ee9395f324cd2e7f331f",
   180  		},
   181  		{
   182  			desc:       "Correct MD5, nested, truncated",
   183  			src:        mustReader(t, bytes.NewReader([]byte("abcd-morestuff")), -1, "", "", -1),
   184  			size:       4,
   185  			actualSize: 4,
   186  			md5hex:     "e2fc714c4727ee9395f324cd2e7f331f",
   187  		},
   188  	}
   189  	for i, testCase := range testCases {
   190  		t.Run(fmt.Sprintf("case-%d", i+1), func(t *testing.T) {
   191  			r, err := NewReader(testCase.src, testCase.size, testCase.md5hex, testCase.sha256hex, testCase.actualSize)
   192  			if err != nil {
   193  				t.Fatalf("Test %q: Initializing reader failed %s", testCase.desc, err)
   194  			}
   195  			_, err = io.Copy(ioutil.Discard, r)
   196  			if err != nil {
   197  				if err.Error() != testCase.err.Error() {
   198  					t.Errorf("Test %q: Expected error %s, got error %s", testCase.desc, testCase.err, err)
   199  				}
   200  			}
   201  		})
   202  	}
   203  }
   204  
   205  func mustReader(t *testing.T, src io.Reader, size int64, md5Hex, sha256Hex string, actualSize int64) *Reader {
   206  	r, err := NewReader(src, size, md5Hex, sha256Hex, actualSize)
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  	return r
   211  }
   212  
   213  // Tests NewReader() constructor with invalid arguments.
   214  func TestHashReaderInvalidArguments(t *testing.T) {
   215  	testCases := []struct {
   216  		desc              string
   217  		src               io.Reader
   218  		size              int64
   219  		actualSize        int64
   220  		md5hex, sha256hex string
   221  		success           bool
   222  	}{
   223  		{
   224  			desc:       "Invalid md5sum NewReader() will fail.",
   225  			src:        bytes.NewReader([]byte("abcd")),
   226  			size:       4,
   227  			actualSize: 4,
   228  			md5hex:     "invalid-md5",
   229  			success:    false,
   230  		},
   231  		{
   232  			desc:       "Invalid sha256 NewReader() will fail.",
   233  			src:        bytes.NewReader([]byte("abcd")),
   234  			size:       4,
   235  			actualSize: 4,
   236  			sha256hex:  "invalid-sha256",
   237  			success:    false,
   238  		},
   239  		{
   240  			desc:       "Nested hash reader NewReader() should merge.",
   241  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "", "", 4),
   242  			size:       4,
   243  			actualSize: 4,
   244  			success:    true,
   245  		},
   246  		{
   247  			desc:       "Mismatching sha256",
   248  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "", "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", 4),
   249  			size:       4,
   250  			actualSize: 4,
   251  			sha256hex:  "50d858e0985ecc7f60418aaf0cc5ab587f42c2570a884095a9e8ccacd0f6545c",
   252  			success:    false,
   253  		},
   254  		{
   255  			desc:       "Correct sha256",
   256  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "", "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", 4),
   257  			size:       4,
   258  			actualSize: 4,
   259  			sha256hex:  "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
   260  			success:    true,
   261  		},
   262  		{
   263  			desc:       "Mismatching MD5",
   264  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "e2fc714c4727ee9395f324cd2e7f331f", "", 4),
   265  			size:       4,
   266  			actualSize: 4,
   267  			md5hex:     "0773da587b322af3a8718cb418a715ce",
   268  			success:    false,
   269  		},
   270  		{
   271  			desc:       "Correct MD5",
   272  			src:        mustReader(t, bytes.NewReader([]byte("abcd")), 4, "e2fc714c4727ee9395f324cd2e7f331f", "", 4),
   273  			size:       4,
   274  			actualSize: 4,
   275  			md5hex:     "e2fc714c4727ee9395f324cd2e7f331f",
   276  			success:    true,
   277  		},
   278  		{
   279  			desc:       "Nothing, all ok",
   280  			src:        bytes.NewReader([]byte("abcd")),
   281  			size:       4,
   282  			actualSize: 4,
   283  			success:    true,
   284  		},
   285  		{
   286  			desc:       "Nested, size mismatch",
   287  			src:        mustReader(t, bytes.NewReader([]byte("abcd-morestuff")), 4, "", "", -1),
   288  			size:       2,
   289  			actualSize: -1,
   290  			success:    false,
   291  		},
   292  	}
   293  
   294  	for i, testCase := range testCases {
   295  		t.Run(fmt.Sprintf("case-%d", i+1), func(t *testing.T) {
   296  			_, err := NewReader(testCase.src, testCase.size, testCase.md5hex, testCase.sha256hex, testCase.actualSize)
   297  			if err != nil && testCase.success {
   298  				t.Errorf("Test %q: Expected success, but got error %s instead", testCase.desc, err)
   299  			}
   300  			if err == nil && !testCase.success {
   301  				t.Errorf("Test %q: Expected error, but got success", testCase.desc)
   302  			}
   303  		})
   304  	}
   305  }