-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
SNOW-723810: Add coverage for SFRemoteStorageUtil (#773)
### Description Regarding issue 113 The PR adds tests for SFRemoteStorageUtil to increase code coverage ### Checklist - [x] Code compiles correctly - [x] Code is formatted according to [Coding Conventions](../CodingConventions.md) - [x] Created tests which fail without the change (if possible) - [x] All tests passing (`dotnet test`) - [x] Extended the README / documentation, if necessary - [x] Provide JIRA issue id (if possible) or GitHub issue id in PR name
- Loading branch information
1 parent
6fceac1
commit bd89073
Showing
3 changed files
with
737 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/* | ||
* Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved. | ||
*/ | ||
|
||
using Moq; | ||
using Snowflake.Data.Core.FileTransfer.StorageClient; | ||
using System; | ||
using System.IO; | ||
using System.Net; | ||
using System.Text; | ||
|
||
namespace Snowflake.Data.Tests.Mock | ||
{ | ||
|
||
class MockRemoteStorageClient | ||
{ | ||
// Mock data for downloaded file | ||
internal const string FileContent = "RemoteStorageClientTest"; | ||
|
||
// Mock content length | ||
internal const int ContentLength = 9999; | ||
|
||
// Mock error message | ||
internal const string ErrorMessage = "Mock GCS Remote Storage Error"; | ||
|
||
// Variables for the encryption data | ||
[ThreadStatic] static Stream t_encryptedStream = null; | ||
[ThreadStatic] static string t_encryptedStreamIV = null; | ||
[ThreadStatic] static string t_encryptedStreamKey = null; | ||
|
||
static internal void SetEncryptionData(Stream stream, string iv, string key) | ||
{ | ||
t_encryptedStream = stream; | ||
t_encryptedStreamIV = iv; | ||
t_encryptedStreamKey = key; | ||
} | ||
|
||
// Sets up the mock sequence when Remote Storage uploads a file | ||
// 1. Get the file header | ||
// 2. Upload the file | ||
static internal HttpWebResponse SequenceResponseForUploadFile(ref bool firstRequest, HttpStatusCode statusCode, HttpStatusCode statusCodeAfterRetry) | ||
{ | ||
try | ||
{ | ||
// For the first call to GetResponse(), return the file header response | ||
// For the second call to GetResponse(), return the upload response | ||
var response = firstRequest ? | ||
CreateResponseForFileHeader(statusCode) : | ||
CreateResponseForUploadFile(statusCodeAfterRetry); | ||
|
||
return response; | ||
} | ||
finally | ||
{ | ||
// If an exception is thrown, the value will still be changed | ||
firstRequest = false; | ||
} | ||
} | ||
|
||
// Create a mock response for GetFileHeader | ||
static internal HttpWebResponse CreateResponseForFileHeader(HttpStatusCode httpStatusCode) | ||
{ | ||
var response = new Mock<HttpWebResponse>(); | ||
|
||
if (httpStatusCode == HttpStatusCode.OK) | ||
{ | ||
response.Setup(c => c.Headers).Returns(new WebHeaderCollection()); | ||
response.Object.Headers.Add("content-length", MockGCSClient.ContentLength.ToString()); | ||
response.Object.Headers.Add(SFGCSClient.GCS_METADATA_SFC_DIGEST, MockGCSClient.SFCDigest); | ||
} | ||
else | ||
{ | ||
response.SetupGet(c => c.StatusCode) | ||
.Returns(httpStatusCode); | ||
throw new WebException(ErrorMessage, null, 0, response.Object); | ||
} | ||
|
||
return response.Object; | ||
} | ||
|
||
// Create a mock response for UploadFile | ||
static internal HttpWebResponse CreateResponseForUploadFile(HttpStatusCode httpStatusCode) | ||
{ | ||
var response = new Mock<HttpWebResponse>(); | ||
|
||
if (httpStatusCode != HttpStatusCode.OK) | ||
{ | ||
response.SetupGet(c => c.StatusCode) | ||
.Returns(httpStatusCode); | ||
throw new WebException(ErrorMessage, null, 0, response.Object); | ||
} | ||
|
||
return response.Object; | ||
} | ||
|
||
// Create a mock response for DownloadFile | ||
static internal HttpWebResponse CreateResponseForDownloadFile(HttpStatusCode httpStatusCode) | ||
{ | ||
var response = new Mock<HttpWebResponse>(); | ||
|
||
if (httpStatusCode == HttpStatusCode.OK) | ||
{ | ||
response.Setup(c => c.Headers).Returns(new WebHeaderCollection()); | ||
|
||
// For downloads with encryption material | ||
if (t_encryptedStream != null) | ||
{ | ||
// Set the position to 0 and return the encrypted stream | ||
t_encryptedStream.Position = 0; | ||
response.Setup(c => c.GetResponseStream()).Returns(t_encryptedStream); | ||
|
||
// Set the iv and key to the ones used for encrypting the stream | ||
response.Object.Headers.Add(SFGCSClient.GCS_METADATA_ENCRYPTIONDATAPROP, | ||
"{" + | ||
$"\"ContentEncryptionIV\": \"{t_encryptedStreamIV}\", " + | ||
$"\"WrappedContentKey\": {{\"EncryptedKey\":\"{t_encryptedStreamKey}\"}}" + | ||
"}"); | ||
|
||
t_encryptedStreamIV = null; | ||
t_encryptedStreamKey = null; | ||
t_encryptedStream = null; | ||
} | ||
else // For unencrypted downloads | ||
{ | ||
response.Setup(c => c.GetResponseStream()).Returns(new MemoryStream(Encoding.ASCII.GetBytes(FileContent))); | ||
response.Object.Headers.Add(SFGCSClient.GCS_METADATA_ENCRYPTIONDATAPROP, | ||
"{" + | ||
$"\"ContentEncryptionIV\": \"{MockGCSClient.GcsIV}\", " + | ||
$"\"WrappedContentKey\": {{\"EncryptedKey\":\"{MockGCSClient.GcsKey}\"}}" + | ||
"}"); | ||
} | ||
|
||
response.Object.Headers.Add(SFGCSClient.GCS_METADATA_MATDESC_KEY, MockGCSClient.GcsMatdesc); | ||
response.Object.Headers.Add(SFGCSClient.GCS_METADATA_SFC_DIGEST, MockGCSClient.SFCDigest); | ||
response.Object.Headers.Add(SFGCSClient.GCS_FILE_HEADER_CONTENT_LENGTH, MockGCSClient.ContentLength.ToString()); | ||
} | ||
else | ||
{ | ||
response.SetupGet(c => c.StatusCode) | ||
.Returns(httpStatusCode); | ||
throw new WebException(ErrorMessage, null, 0, response.Object); | ||
} | ||
|
||
return response.Object; | ||
} | ||
} | ||
} | ||
|
Oops, something went wrong.