github.com/snowflakedb/gosnowflake@v1.9.0/gcs_storage_client_test.go (about) 1 // Copyright (c) 2023 Snowflake Computing Inc. All rights reserved. 2 3 package gosnowflake 4 5 import ( 6 "bytes" 7 "encoding/json" 8 "errors" 9 "net/http" 10 "net/url" 11 "os" 12 "path" 13 "testing" 14 ) 15 16 type tcFileURL struct { 17 location string 18 fname string 19 bucket string 20 filepath string 21 } 22 23 func TestExtractBucketAndPath(t *testing.T) { 24 gcsUtil := new(snowflakeGcsClient) 25 testcases := []tcBucketPath{ 26 {"sfc-eng-regression/test_sub_dir/", "sfc-eng-regression", "test_sub_dir/"}, 27 {"sfc-eng-regression/dir/test_stg/test_sub_dir/", "sfc-eng-regression", "dir/test_stg/test_sub_dir/"}, 28 {"sfc-eng-regression/", "sfc-eng-regression", ""}, 29 {"sfc-eng-regression//", "sfc-eng-regression", "/"}, 30 {"sfc-eng-regression///", "sfc-eng-regression", "//"}, 31 } 32 for _, test := range testcases { 33 t.Run(test.in, func(t *testing.T) { 34 gcsLoc := gcsUtil.extractBucketNameAndPath(test.in) 35 if gcsLoc.bucketName != test.bucket { 36 t.Errorf("failed. in: %v, expected: %v, got: %v", test.in, test.bucket, gcsLoc.bucketName) 37 } 38 if gcsLoc.path != test.path { 39 t.Errorf("failed. in: %v, expected: %v, got: %v", test.in, test.path, gcsLoc.path) 40 } 41 }) 42 } 43 } 44 45 func TestIsTokenExpiredWith401(t *testing.T) { 46 gcsUtil := new(snowflakeGcsClient) 47 dd := &execResponseData{} 48 execResp := &execResponse{ 49 Data: *dd, 50 Message: "token expired", 51 Code: "401", 52 Success: true, 53 } 54 ba, err := json.Marshal(execResp) 55 if err != nil { 56 panic(err) 57 } 58 resp := &http.Response{StatusCode: http.StatusUnauthorized, Body: &fakeResponseBody{body: ba}} 59 if !gcsUtil.isTokenExpired(resp) { 60 t.Fatalf("expected true for token expired") 61 } 62 } 63 64 func TestIsTokenExpiredWith404(t *testing.T) { 65 gcsUtil := new(snowflakeGcsClient) 66 dd := &execResponseData{} 67 execResp := &execResponse{ 68 Data: *dd, 69 Message: "file not found", 70 Code: "404", 71 Success: true, 72 } 73 ba, err := json.Marshal(execResp) 74 if err != nil { 75 panic(err) 76 } 77 resp := &http.Response{StatusCode: http.StatusNotFound, Body: &fakeResponseBody{body: ba}} 78 if gcsUtil.isTokenExpired(resp) { 79 t.Fatalf("should be false") 80 } 81 resp = &http.Response{ 82 StatusCode: http.StatusOK, 83 Body: &fakeResponseBody{body: []byte{0x12, 0x34}}} 84 85 if gcsUtil.isTokenExpired(resp) { 86 t.Fatalf("should be false") 87 } 88 resp = &http.Response{ 89 StatusCode: http.StatusUnauthorized, 90 Body: &fakeResponseBody{body: []byte{0x12, 0x34}}} 91 92 if !gcsUtil.isTokenExpired(resp) { 93 t.Fatalf("should be true") 94 } 95 } 96 97 func TestGenerateFileURL(t *testing.T) { 98 gcsUtil := new(snowflakeGcsClient) 99 testcases := []tcFileURL{ 100 {"sfc-eng-regression/test_sub_dir/", "file1", "sfc-eng-regression", "test_sub_dir/file1"}, 101 {"sfc-eng-regression/dir/test_stg/test_sub_dir/", "file2", "sfc-eng-regression", "dir/test_stg/test_sub_dir/file2"}, 102 {"sfc-eng-regression/", "file3", "sfc-eng-regression", "file3"}, 103 {"sfc-eng-regression//", "file4", "sfc-eng-regression", "/file4"}, 104 {"sfc-eng-regression///", "file5", "sfc-eng-regression", "//file5"}, 105 } 106 for _, test := range testcases { 107 t.Run(test.location, func(t *testing.T) { 108 gcsURL, err := gcsUtil.generateFileURL(test.location, test.fname) 109 if err != nil { 110 t.Error(err) 111 } 112 expectedURL, err := url.Parse("https://storage.googleapis.com/" + test.bucket + "/" + url.QueryEscape(test.filepath)) 113 if err != nil { 114 t.Error(err) 115 } 116 if gcsURL.String() != expectedURL.String() { 117 t.Fatalf("failed. expected: %v but got: %v", expectedURL.String(), gcsURL.String()) 118 } 119 }) 120 } 121 } 122 123 type clientMock struct { 124 DoFunc func(req *http.Request) (*http.Response, error) 125 } 126 127 func (c *clientMock) Do(req *http.Request) (*http.Response, error) { 128 return c.DoFunc(req) 129 } 130 131 func TestUploadFileWithGcsUploadFailedError(t *testing.T) { 132 info := execResponseStageInfo{ 133 Location: "gcs-blob/storage/users/456/", 134 LocationType: "GCS", 135 } 136 initialParallel := int64(100) 137 dir, err := os.Getwd() 138 if err != nil { 139 t.Error(err) 140 } 141 142 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 143 if err != nil { 144 t.Error(err) 145 } 146 uploadMeta := fileMetadata{ 147 name: "data1.txt.gz", 148 stageLocationType: "GCS", 149 noSleepingTime: true, 150 parallel: initialParallel, 151 client: gcsCli, 152 sha256Digest: "123456789abcdef", 153 stageInfo: &info, 154 dstFileName: "data1.txt.gz", 155 srcFileName: path.Join(dir, "/test_data/put_get_1.txt"), 156 overwrite: true, 157 dstCompressionType: compressionTypes["GZIP"], 158 options: &SnowflakeFileTransferOptions{ 159 MultiPartThreshold: dataSizeThreshold, 160 }, 161 mockGcsClient: &clientMock{ 162 DoFunc: func(req *http.Request) (*http.Response, error) { 163 return nil, errors.New("unexpected error uploading file") 164 }, 165 }, 166 } 167 168 uploadMeta.realSrcFileName = uploadMeta.srcFileName 169 fi, err := os.Stat(uploadMeta.srcFileName) 170 if err != nil { 171 t.Error(err) 172 } 173 uploadMeta.uploadSize = fi.Size() 174 175 err = new(remoteStorageUtil).uploadOneFile(&uploadMeta) 176 if err == nil { 177 t.Fatal("should have failed") 178 } 179 } 180 181 func TestUploadFileWithGcsUploadFailedWithRetry(t *testing.T) { 182 info := execResponseStageInfo{ 183 Location: "gcs-blob/storage/users/456/", 184 LocationType: "GCS", 185 } 186 encMat := snowflakeFileEncryption{ 187 QueryStageMasterKey: "abCdEFO0upIT36dAxGsa0w==", 188 QueryID: "01abc874-0406-1bf0-0000-53b10668e056", 189 SMKID: 92019681909886, 190 } 191 initialParallel := int64(100) 192 dir, err := os.Getwd() 193 if err != nil { 194 t.Error(err) 195 } 196 197 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 198 if err != nil { 199 t.Error(err) 200 } 201 uploadMeta := fileMetadata{ 202 name: "data1.txt.gz", 203 stageLocationType: "GCS", 204 noSleepingTime: true, 205 parallel: initialParallel, 206 client: gcsCli, 207 sha256Digest: "123456789abcdef", 208 stageInfo: &info, 209 dstFileName: "data1.txt.gz", 210 srcFileName: path.Join(dir, "/test_data/put_get_1.txt"), 211 overwrite: true, 212 dstCompressionType: compressionTypes["GZIP"], 213 encryptionMaterial: &encMat, 214 options: &SnowflakeFileTransferOptions{ 215 MultiPartThreshold: dataSizeThreshold, 216 }, 217 mockGcsClient: &clientMock{ 218 DoFunc: func(req *http.Request) (*http.Response, error) { 219 return &http.Response{ 220 Status: "403 Forbidden", 221 StatusCode: 403, 222 }, nil 223 }, 224 }, 225 } 226 227 uploadMeta.realSrcFileName = uploadMeta.srcFileName 228 fi, err := os.Stat(uploadMeta.srcFileName) 229 if err != nil { 230 t.Error(err) 231 } 232 uploadMeta.uploadSize = fi.Size() 233 234 err = new(remoteStorageUtil).uploadOneFile(&uploadMeta) 235 if err == nil { 236 t.Error("should have raised an error") 237 } 238 239 if uploadMeta.resStatus != needRetry { 240 t.Fatalf("expected %v result status, got: %v", 241 needRetry, uploadMeta.resStatus) 242 } 243 } 244 245 func TestUploadFileWithGcsUploadFailedWithTokenExpired(t *testing.T) { 246 info := execResponseStageInfo{ 247 Location: "gcs-blob/storage/users/456/", 248 LocationType: "GCS", 249 Creds: execResponseCredentials{ 250 GcsAccessToken: "test-token-124456577", 251 }, 252 } 253 initialParallel := int64(100) 254 dir, err := os.Getwd() 255 if err != nil { 256 t.Error(err) 257 } 258 259 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 260 if err != nil { 261 t.Error(err) 262 } 263 uploadMeta := fileMetadata{ 264 name: "data1.txt.gz", 265 stageLocationType: "GCS", 266 noSleepingTime: true, 267 parallel: initialParallel, 268 client: gcsCli, 269 sha256Digest: "123456789abcdef", 270 stageInfo: &info, 271 dstFileName: "data1.txt.gz", 272 srcFileName: path.Join(dir, "/test_data/put_get_1.txt"), 273 overwrite: true, 274 options: &SnowflakeFileTransferOptions{ 275 MultiPartThreshold: dataSizeThreshold, 276 }, 277 mockGcsClient: &clientMock{ 278 DoFunc: func(req *http.Request) (*http.Response, error) { 279 return &http.Response{ 280 Status: "401 Unauthorized", 281 StatusCode: 401, 282 }, nil 283 }, 284 }, 285 } 286 287 uploadMeta.realSrcFileName = uploadMeta.srcFileName 288 fi, err := os.Stat(uploadMeta.srcFileName) 289 if err != nil { 290 t.Error(err) 291 } 292 uploadMeta.uploadSize = fi.Size() 293 294 err = new(remoteStorageUtil).uploadOneFile(&uploadMeta) 295 if err != nil { 296 t.Error(err) 297 } 298 299 if uploadMeta.resStatus != renewToken { 300 t.Fatalf("expected %v result status, got: %v", 301 renewToken, uploadMeta.resStatus) 302 } 303 } 304 305 func TestDownloadOneFileFromGcsFailed(t *testing.T) { 306 info := execResponseStageInfo{ 307 Location: "gcs/teststage/users/34/", 308 LocationType: "GCS", 309 } 310 dir, err := os.Getwd() 311 if err != nil { 312 t.Error(err) 313 } 314 315 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 316 if err != nil { 317 t.Error(err) 318 } 319 320 downloadMeta := fileMetadata{ 321 name: "data1.txt.gz", 322 stageLocationType: "GCS", 323 noSleepingTime: true, 324 client: gcsCli, 325 stageInfo: &info, 326 dstFileName: "data1.txt.gz", 327 overwrite: true, 328 srcFileName: "data1.txt.gz", 329 localLocation: dir, 330 options: &SnowflakeFileTransferOptions{ 331 MultiPartThreshold: dataSizeThreshold, 332 }, 333 mockGcsClient: &clientMock{ 334 DoFunc: func(req *http.Request) (*http.Response, error) { 335 return nil, errors.New("unexpected error downloading file") 336 }, 337 }, 338 resStatus: downloaded, // bypass file header request 339 } 340 err = new(remoteStorageUtil).downloadOneFile(&downloadMeta) 341 if err == nil { 342 t.Error("should have raised an error") 343 } 344 } 345 346 func TestDownloadOneFileFromGcsFailedWithRetry(t *testing.T) { 347 info := execResponseStageInfo{ 348 Location: "gcs/teststage/users/34/", 349 LocationType: "GCS", 350 } 351 dir, err := os.Getwd() 352 if err != nil { 353 t.Error(err) 354 } 355 356 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 357 if err != nil { 358 t.Error(err) 359 } 360 361 downloadMeta := fileMetadata{ 362 name: "data1.txt.gz", 363 stageLocationType: "GCS", 364 noSleepingTime: true, 365 client: gcsCli, 366 stageInfo: &info, 367 dstFileName: "data1.txt.gz", 368 overwrite: true, 369 srcFileName: "data1.txt.gz", 370 localLocation: dir, 371 options: &SnowflakeFileTransferOptions{ 372 MultiPartThreshold: dataSizeThreshold, 373 }, 374 mockGcsClient: &clientMock{ 375 DoFunc: func(req *http.Request) (*http.Response, error) { 376 return &http.Response{ 377 Status: "403 Forbidden", 378 StatusCode: 403, 379 }, nil 380 }, 381 }, 382 resStatus: downloaded, // bypass file header request 383 } 384 err = new(remoteStorageUtil).downloadOneFile(&downloadMeta) 385 if err == nil { 386 t.Error("should have raised an error") 387 } 388 389 if downloadMeta.resStatus != needRetry { 390 t.Fatalf("expected %v result status, got: %v", 391 needRetry, downloadMeta.resStatus) 392 } 393 } 394 395 func TestDownloadOneFileFromGcsFailedWithTokenExpired(t *testing.T) { 396 info := execResponseStageInfo{ 397 Location: "gcs/teststage/users/34/", 398 LocationType: "GCS", 399 Creds: execResponseCredentials{ 400 GcsAccessToken: "test-token-124456577", 401 }, 402 } 403 dir, err := os.Getwd() 404 if err != nil { 405 t.Error(err) 406 } 407 408 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 409 if err != nil { 410 t.Error(err) 411 } 412 413 downloadMeta := fileMetadata{ 414 name: "data1.txt.gz", 415 stageLocationType: "GCS", 416 noSleepingTime: true, 417 client: gcsCli, 418 stageInfo: &info, 419 dstFileName: "data1.txt.gz", 420 overwrite: true, 421 srcFileName: "data1.txt.gz", 422 localLocation: dir, 423 options: &SnowflakeFileTransferOptions{ 424 MultiPartThreshold: dataSizeThreshold, 425 }, 426 mockGcsClient: &clientMock{ 427 DoFunc: func(req *http.Request) (*http.Response, error) { 428 return &http.Response{ 429 Status: "401 Unauthorized", 430 StatusCode: 401, 431 }, nil 432 }, 433 }, 434 resStatus: downloaded, // bypass file header request 435 } 436 err = new(remoteStorageUtil).downloadOneFile(&downloadMeta) 437 if err == nil { 438 t.Error("should have raised an error") 439 } 440 441 if downloadMeta.resStatus != renewToken { 442 t.Fatalf("expected %v result status, got: %v", 443 renewToken, downloadMeta.resStatus) 444 } 445 } 446 447 func TestDownloadOneFileFromGcsFailedWithFileNotFound(t *testing.T) { 448 info := execResponseStageInfo{ 449 Location: "gcs/teststage/users/34/", 450 LocationType: "GCS", 451 Creds: execResponseCredentials{ 452 GcsAccessToken: "test-token-124456577", 453 }, 454 } 455 dir, err := os.Getwd() 456 if err != nil { 457 t.Error(err) 458 } 459 460 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 461 if err != nil { 462 t.Error(err) 463 } 464 465 downloadMeta := fileMetadata{ 466 name: "data1.txt.gz", 467 stageLocationType: "GCS", 468 noSleepingTime: true, 469 client: gcsCli, 470 stageInfo: &info, 471 dstFileName: "data1.txt.gz", 472 overwrite: true, 473 srcFileName: "data1.txt.gz", 474 localLocation: dir, 475 options: &SnowflakeFileTransferOptions{ 476 MultiPartThreshold: dataSizeThreshold, 477 }, 478 mockGcsClient: &clientMock{ 479 DoFunc: func(req *http.Request) (*http.Response, error) { 480 return &http.Response{ 481 Status: "404 Not Found", 482 StatusCode: 404, 483 }, nil 484 }, 485 }, 486 resStatus: downloaded, // bypass file header request 487 } 488 err = new(remoteStorageUtil).downloadOneFile(&downloadMeta) 489 if err == nil { 490 t.Error("should have raised an error") 491 } 492 493 if downloadMeta.resStatus != notFoundFile { 494 t.Fatalf("expected %v result status, got: %v", 495 notFoundFile, downloadMeta.resStatus) 496 } 497 } 498 499 func TestGetHeaderTokenExpiredError(t *testing.T) { 500 info := execResponseStageInfo{ 501 Location: "gcs/teststage/users/34/", 502 LocationType: "GCS", 503 Creds: execResponseCredentials{ 504 GcsAccessToken: "test-token-124456577", 505 }, 506 } 507 meta := fileMetadata{ 508 client: info.Creds.GcsAccessToken, 509 stageInfo: &info, 510 mockGcsClient: &clientMock{ 511 DoFunc: func(req *http.Request) (*http.Response, error) { 512 return &http.Response{ 513 Status: "401 Unauthorized", 514 StatusCode: 401, 515 }, nil 516 }, 517 }, 518 } 519 if header, err := new(snowflakeGcsClient).getFileHeader(&meta, "file.txt"); header != nil || err == nil { 520 t.Fatalf("expected null header, got: %v", header) 521 } 522 if meta.resStatus != renewToken { 523 t.Fatalf("expected %v result status, got: %v", 524 renewToken, meta.resStatus) 525 } 526 } 527 528 func TestGetHeaderFileNotFound(t *testing.T) { 529 info := execResponseStageInfo{ 530 Location: "gcs/teststage/users/34/", 531 LocationType: "GCS", 532 Creds: execResponseCredentials{ 533 GcsAccessToken: "test-token-124456577", 534 }, 535 } 536 meta := fileMetadata{ 537 client: info.Creds.GcsAccessToken, 538 stageInfo: &info, 539 mockGcsClient: &clientMock{ 540 DoFunc: func(req *http.Request) (*http.Response, error) { 541 return &http.Response{ 542 Status: "404 Not Found", 543 StatusCode: 404, 544 }, nil 545 }, 546 }, 547 } 548 if header, err := new(snowflakeGcsClient).getFileHeader(&meta, "file.txt"); header != nil || err == nil { 549 t.Fatalf("expected null header, got: %v", header) 550 } 551 if meta.resStatus != notFoundFile { 552 t.Fatalf("expected %v result status, got: %v", 553 notFoundFile, meta.resStatus) 554 } 555 } 556 557 func TestGetHeaderPresignedUrlReturns404(t *testing.T) { 558 info := execResponseStageInfo{ 559 Location: "gcs/teststage/users/34/", 560 LocationType: "GCS", 561 Creds: execResponseCredentials{ 562 GcsAccessToken: "test-token-124456577", 563 }, 564 } 565 presignedURL, err := url.Parse("https://google-cloud.test.com") 566 if err != nil { 567 t.Error(err) 568 } 569 meta := fileMetadata{ 570 client: info.Creds.GcsAccessToken, 571 stageInfo: &info, 572 presignedURL: presignedURL, 573 } 574 header, err := new(snowflakeGcsClient).getFileHeader(&meta, "file.txt") 575 if header != nil { 576 t.Fatalf("expected null header, got: %v", header) 577 } 578 if err != nil { 579 t.Error(err) 580 } 581 if meta.resStatus != notFoundFile { 582 t.Fatalf("expected %v result status, got: %v", 583 notFoundFile, meta.resStatus) 584 } 585 } 586 587 func TestGetHeaderReturnsError(t *testing.T) { 588 info := execResponseStageInfo{ 589 Location: "gcs/teststage/users/34/", 590 LocationType: "GCS", 591 Creds: execResponseCredentials{ 592 GcsAccessToken: "test-token-124456577", 593 }, 594 } 595 meta := fileMetadata{ 596 client: info.Creds.GcsAccessToken, 597 stageInfo: &info, 598 mockGcsClient: &clientMock{ 599 DoFunc: func(req *http.Request) (*http.Response, error) { 600 return nil, errors.New("unexpected exception getting file header") 601 }, 602 }, 603 } 604 if header, err := new(snowflakeGcsClient).getFileHeader(&meta, "file.txt"); header != nil || err == nil { 605 t.Fatalf("expected null header, got: %v", header) 606 } 607 } 608 609 func TestGetHeaderBadRequest(t *testing.T) { 610 info := execResponseStageInfo{ 611 Location: "gcs/teststage/users/34/", 612 LocationType: "GCS", 613 Creds: execResponseCredentials{ 614 GcsAccessToken: "test-token-124456577", 615 }, 616 } 617 meta := fileMetadata{ 618 client: info.Creds.GcsAccessToken, 619 stageInfo: &info, 620 mockGcsClient: &clientMock{ 621 DoFunc: func(req *http.Request) (*http.Response, error) { 622 return &http.Response{ 623 Status: "400 Bad Request", 624 StatusCode: 400, 625 }, nil 626 }, 627 }, 628 } 629 if header, err := new(snowflakeGcsClient).getFileHeader(&meta, "file.txt"); header != nil || err == nil { 630 t.Fatalf("expected null header, got: %v", header) 631 } 632 633 if meta.resStatus != errStatus { 634 t.Fatalf("expected %v result status, got: %v", 635 errStatus, meta.resStatus) 636 } 637 } 638 639 func TestGetHeaderRetryableError(t *testing.T) { 640 info := execResponseStageInfo{ 641 Location: "gcs/teststage/users/34/", 642 LocationType: "GCS", 643 Creds: execResponseCredentials{ 644 GcsAccessToken: "test-token-124456577", 645 }, 646 } 647 meta := fileMetadata{ 648 client: info.Creds.GcsAccessToken, 649 stageInfo: &info, 650 mockGcsClient: &clientMock{ 651 DoFunc: func(req *http.Request) (*http.Response, error) { 652 return &http.Response{ 653 Status: "403 Forbidden", 654 StatusCode: 403, 655 }, nil 656 }, 657 }, 658 } 659 if header, err := new(snowflakeGcsClient).getFileHeader(&meta, "file.txt"); header != nil || err == nil { 660 t.Fatalf("expected null header, got: %v", header) 661 } 662 if meta.resStatus != needRetry { 663 t.Fatalf("expected %v result status, got: %v", 664 needRetry, meta.resStatus) 665 } 666 } 667 668 func TestUploadStreamFailed(t *testing.T) { 669 info := execResponseStageInfo{ 670 Location: "gcs-blob/storage/users/456/", 671 LocationType: "GCS", 672 } 673 initialParallel := int64(100) 674 src := []byte{65, 66, 67} 675 676 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 677 if err != nil { 678 t.Error(err) 679 } 680 681 uploadMeta := fileMetadata{ 682 name: "data1.txt.gz", 683 stageLocationType: "GCS", 684 noSleepingTime: true, 685 parallel: initialParallel, 686 client: gcsCli, 687 sha256Digest: "123456789abcdef", 688 stageInfo: &info, 689 dstFileName: "data1.txt.gz", 690 srcStream: bytes.NewBuffer(src), 691 overwrite: true, 692 options: &SnowflakeFileTransferOptions{ 693 MultiPartThreshold: dataSizeThreshold, 694 }, 695 mockGcsClient: &clientMock{ 696 DoFunc: func(req *http.Request) (*http.Response, error) { 697 return nil, errors.New("unexpected error uploading file") 698 }, 699 }, 700 } 701 702 uploadMeta.realSrcStream = uploadMeta.srcStream 703 704 err = new(remoteStorageUtil).uploadOneFile(&uploadMeta) 705 if err == nil { 706 t.Fatal("should have failed") 707 } 708 } 709 710 func TestUploadFileWithBadRequest(t *testing.T) { 711 info := execResponseStageInfo{ 712 Location: "gcs-blob/storage/users/456/", 713 LocationType: "GCS", 714 } 715 initialParallel := int64(100) 716 dir, err := os.Getwd() 717 if err != nil { 718 t.Error(err) 719 } 720 721 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 722 if err != nil { 723 t.Error(err) 724 } 725 uploadMeta := fileMetadata{ 726 name: "data1.txt.gz", 727 stageLocationType: "GCS", 728 noSleepingTime: true, 729 parallel: initialParallel, 730 client: gcsCli, 731 sha256Digest: "123456789abcdef", 732 stageInfo: &info, 733 dstFileName: "data1.txt.gz", 734 srcFileName: path.Join(dir, "/test_data/put_get_1.txt"), 735 overwrite: true, 736 lastError: nil, 737 options: &SnowflakeFileTransferOptions{ 738 MultiPartThreshold: dataSizeThreshold, 739 }, 740 mockGcsClient: &clientMock{ 741 DoFunc: func(req *http.Request) (*http.Response, error) { 742 return &http.Response{ 743 StatusCode: 400, 744 }, nil 745 }, 746 }, 747 } 748 749 uploadMeta.realSrcFileName = uploadMeta.srcFileName 750 fi, err := os.Stat(uploadMeta.srcFileName) 751 if err != nil { 752 t.Error(err) 753 } 754 uploadMeta.uploadSize = fi.Size() 755 756 err = new(remoteStorageUtil).uploadOneFile(&uploadMeta) 757 if err != nil { 758 t.Error(err) 759 } 760 761 if uploadMeta.resStatus != renewPresignedURL { 762 t.Fatalf("expected %v result status, got: %v", 763 renewPresignedURL, uploadMeta.resStatus) 764 } 765 } 766 767 func TestGetFileHeaderEncryptionData(t *testing.T) { 768 mockEncDataResp := "{\"EncryptionMode\":\"FullBlob\",\"WrappedContentKey\": {\"KeyId\":\"symmKey1\",\"EncryptedKey\":\"testencryptedkey12345678910==\",\"Algorithm\":\"AES_CBC_256\"},\"EncryptionAgent\": {\"Protocol\":\"1.0\",\"EncryptionAlgorithm\":\"AES_CBC_256\"},\"ContentEncryptionIV\":\"testIVkey12345678910==\",\"KeyWrappingMetadata\":{\"EncryptionLibrary\":\"Java 5.3.0\"}}" 769 mockMatDesc := "{\"queryid\":\"01abc874-0406-1bf0-0000-53b10668e056\",\"smkid\":\"92019681909886\",\"key\":\"128\"}" 770 info := execResponseStageInfo{ 771 Location: "gcs/teststage/users/34/", 772 LocationType: "GCS", 773 Creds: execResponseCredentials{ 774 GcsAccessToken: "test-token-124456577", 775 }, 776 } 777 meta := fileMetadata{ 778 client: info.Creds.GcsAccessToken, 779 stageInfo: &info, 780 mockGcsClient: &clientMock{ 781 DoFunc: func(req *http.Request) (*http.Response, error) { 782 return &http.Response{ 783 Status: "200 OK", 784 StatusCode: 200, 785 Header: http.Header{ 786 "X-Goog-Meta-Encryptiondata": []string{mockEncDataResp}, 787 "Content-Length": []string{"4256"}, 788 "X-Goog-Meta-Sfc-Digest": []string{"123456789abcdef"}, 789 "X-Goog-Meta-Matdesc": []string{mockMatDesc}, 790 }, 791 }, nil 792 }, 793 }, 794 } 795 header, err := new(snowflakeGcsClient).getFileHeader(&meta, "file.txt") 796 if err != nil { 797 t.Fatal(err) 798 } 799 expectedFileHeader := &fileHeader{ 800 digest: "123456789abcdef", 801 contentLength: 4256, 802 encryptionMetadata: &encryptMetadata{ 803 key: "testencryptedkey12345678910==", 804 iv: "testIVkey12345678910==", 805 matdesc: mockMatDesc, 806 }, 807 } 808 if header.contentLength != expectedFileHeader.contentLength || header.digest != expectedFileHeader.digest || header.encryptionMetadata.iv != expectedFileHeader.encryptionMetadata.iv || header.encryptionMetadata.key != expectedFileHeader.encryptionMetadata.key || header.encryptionMetadata.matdesc != expectedFileHeader.encryptionMetadata.matdesc { 809 t.Fatalf("unexpected file header. expected: %v, got: %v", expectedFileHeader, header) 810 } 811 } 812 813 func TestGetFileHeaderEncryptionDataInterfaceConversionError(t *testing.T) { 814 mockEncDataResp := "{\"EncryptionMode\":\"FullBlob\",\"WrappedContentKey\": {\"KeyId\":\"symmKey1\",\"EncryptedKey\":\"testencryptedkey12345678910==\",\"Algorithm\":\"AES_CBC_256\"},\"EncryptionAgent\": {\"Protocol\":\"1.0\",\"EncryptionAlgorithm\":\"AES_CBC_256\"},\"ContentEncryptionIV\":\"testIVkey12345678910==\",\"KeyWrappingMetadata\":{\"EncryptionLibrary\":\"Java 5.3.0\"}}" 815 mockMatDesc := "{\"queryid\":\"01abc874-0406-1bf0-0000-53b10668e056\",\"smkid\":\"92019681909886\",\"key\":\"128\"}" 816 info := execResponseStageInfo{ 817 Location: "gcs/teststage/users/34/", 818 LocationType: "GCS", 819 Creds: execResponseCredentials{ 820 GcsAccessToken: "test-token-124456577", 821 }, 822 } 823 meta := fileMetadata{ 824 client: 1, 825 stageInfo: &info, 826 mockGcsClient: &clientMock{ 827 DoFunc: func(req *http.Request) (*http.Response, error) { 828 return &http.Response{ 829 Status: "200 OK", 830 StatusCode: 200, 831 Header: http.Header{ 832 "X-Goog-Meta-Encryptiondata": []string{mockEncDataResp}, 833 "Content-Length": []string{"4256"}, 834 "X-Goog-Meta-Sfc-Digest": []string{"123456789abcdef"}, 835 "X-Goog-Meta-Matdesc": []string{mockMatDesc}, 836 }, 837 }, nil 838 }, 839 }, 840 } 841 _, err := new(snowflakeGcsClient).getFileHeader(&meta, "file.txt") 842 if err == nil { 843 t.Error("should have raised an error") 844 } 845 } 846 847 func TestUploadFileToGcsNoStatus(t *testing.T) { 848 info := execResponseStageInfo{ 849 Location: "gcs-blob/storage/users/456/", 850 LocationType: "GCS", 851 } 852 encMat := snowflakeFileEncryption{ 853 QueryStageMasterKey: "abCdEFO0upIT36dAxGsa0w==", 854 QueryID: "01abc874-0406-1bf0-0000-53b10668e056", 855 SMKID: 92019681909886, 856 } 857 initialParallel := int64(100) 858 dir, err := os.Getwd() 859 if err != nil { 860 t.Error(err) 861 } 862 863 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 864 if err != nil { 865 t.Error(err) 866 } 867 uploadMeta := fileMetadata{ 868 name: "data1.txt.gz", 869 stageLocationType: "GCS", 870 noSleepingTime: true, 871 parallel: initialParallel, 872 client: gcsCli, 873 sha256Digest: "123456789abcdef", 874 stageInfo: &info, 875 dstFileName: "data1.txt.gz", 876 srcFileName: path.Join(dir, "/test_data/put_get_1.txt"), 877 overwrite: true, 878 dstCompressionType: compressionTypes["GZIP"], 879 encryptionMaterial: &encMat, 880 options: &SnowflakeFileTransferOptions{ 881 MultiPartThreshold: dataSizeThreshold, 882 }, 883 mockGcsClient: &clientMock{ 884 DoFunc: func(req *http.Request) (*http.Response, error) { 885 return &http.Response{ 886 Status: "401 Unauthorized", 887 StatusCode: 401, 888 }, nil 889 }, 890 }, 891 } 892 893 uploadMeta.realSrcFileName = uploadMeta.srcFileName 894 fi, err := os.Stat(uploadMeta.srcFileName) 895 if err != nil { 896 t.Error(err) 897 } 898 uploadMeta.uploadSize = fi.Size() 899 900 err = new(remoteStorageUtil).uploadOneFile(&uploadMeta) 901 if err == nil { 902 t.Error("should have raised an error") 903 } 904 } 905 906 func TestDownloadFileFromGcsError(t *testing.T) { 907 info := execResponseStageInfo{ 908 Location: "gcs/teststage/users/34/", 909 LocationType: "GCS", 910 } 911 dir, err := os.Getwd() 912 if err != nil { 913 t.Error(err) 914 } 915 916 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 917 if err != nil { 918 t.Error(err) 919 } 920 921 downloadMeta := fileMetadata{ 922 name: "data1.txt.gz", 923 stageLocationType: "GCS", 924 noSleepingTime: true, 925 client: gcsCli, 926 stageInfo: &info, 927 dstFileName: "data1.txt.gz", 928 overwrite: true, 929 srcFileName: "data1.txt.gz", 930 localLocation: dir, 931 options: &SnowflakeFileTransferOptions{ 932 MultiPartThreshold: dataSizeThreshold, 933 }, 934 mockGcsClient: &clientMock{ 935 DoFunc: func(req *http.Request) (*http.Response, error) { 936 return &http.Response{ 937 Status: "403 Unauthorized", 938 StatusCode: 401, 939 }, nil 940 }, 941 }, 942 resStatus: downloaded, // bypass file header request 943 } 944 err = new(remoteStorageUtil).downloadOneFile(&downloadMeta) 945 if err == nil { 946 t.Error("should have raised an error") 947 } 948 } 949 950 func TestDownloadFileWithBadRequest(t *testing.T) { 951 info := execResponseStageInfo{ 952 Location: "gcs/teststage/users/34/", 953 LocationType: "GCS", 954 } 955 dir, err := os.Getwd() 956 if err != nil { 957 t.Error(err) 958 } 959 960 gcsCli, err := new(snowflakeGcsClient).createClient(&info, false) 961 if err != nil { 962 t.Error(err) 963 } 964 965 downloadMeta := fileMetadata{ 966 name: "data1.txt.gz", 967 stageLocationType: "GCS", 968 noSleepingTime: true, 969 client: gcsCli, 970 stageInfo: &info, 971 dstFileName: "data1.txt.gz", 972 overwrite: true, 973 srcFileName: "data1.txt.gz", 974 localLocation: dir, 975 options: &SnowflakeFileTransferOptions{ 976 MultiPartThreshold: dataSizeThreshold, 977 }, 978 mockGcsClient: &clientMock{ 979 DoFunc: func(req *http.Request) (*http.Response, error) { 980 return &http.Response{ 981 Status: "400 Bad Request", 982 StatusCode: 400, 983 }, nil 984 }, 985 }, 986 resStatus: downloaded, // bypass file header request 987 } 988 err = new(remoteStorageUtil).downloadOneFile(&downloadMeta) 989 if err == nil { 990 t.Error("should have raised an error") 991 } 992 993 if downloadMeta.resStatus != renewPresignedURL { 994 t.Fatalf("expected %v result status, got: %v", 995 renewPresignedURL, downloadMeta.resStatus) 996 } 997 } 998 999 func Test_snowflakeGcsClient_uploadFile(t *testing.T) { 1000 info := execResponseStageInfo{ 1001 Location: "gcs/teststage/users/34/", 1002 LocationType: "GCS", 1003 Creds: execResponseCredentials{ 1004 GcsAccessToken: "test-token-124456577", 1005 }, 1006 } 1007 meta := fileMetadata{ 1008 client: 1, 1009 stageInfo: &info, 1010 } 1011 err := new(snowflakeGcsClient).uploadFile("somedata", &meta, nil, 1, 1) 1012 if err == nil { 1013 t.Error("should have raised an error") 1014 } 1015 } 1016 1017 func Test_snowflakeGcsClient_nativeDownloadFile(t *testing.T) { 1018 info := execResponseStageInfo{ 1019 Location: "gcs/teststage/users/34/", 1020 LocationType: "GCS", 1021 Creds: execResponseCredentials{ 1022 GcsAccessToken: "test-token-124456577", 1023 }, 1024 } 1025 meta := fileMetadata{ 1026 client: 1, 1027 stageInfo: &info, 1028 } 1029 err := new(snowflakeGcsClient).nativeDownloadFile(&meta, "dummy data", 1) 1030 if err == nil { 1031 t.Error("should have raised an error") 1032 } 1033 }