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 }