-
Notifications
You must be signed in to change notification settings - Fork 311
Port #3399 to release/5.1 #3409
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
apoorvdeshmukh
wants to merge
1
commit into
release/5.1
Choose a base branch
from
dev/ad/rel51port3399
base: release/5.1
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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
196 changes: 196 additions & 0 deletions
196
src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/TestBulkCopyWithUTF8.cs
This file contains hidden or 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,196 @@ | ||
using System; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing license preamble. |
||
using System.Data; | ||
using System.Threading.Tasks; | ||
using Xunit; | ||
|
||
namespace Microsoft.Data.SqlClient.ManualTesting.Tests.SQL.SqlBulkCopyTest | ||
{ | ||
/// <summary> | ||
/// Validates SqlBulkCopy functionality when working with UTF-8 encoded data. | ||
/// Ensures that data copied from a UTF-8 source table to a destination table retains its encoding and content integrity. | ||
/// </summary> | ||
public sealed class TestBulkCopyWithUtf8 : IDisposable | ||
{ | ||
private static string s_sourceTable = DataTestUtility.GetUniqueName("SourceTableForUTF8Data"); | ||
private static string s_destinationTable = DataTestUtility.GetUniqueName("DestinationTableForUTF8Data"); | ||
private static string s_testValue = "test"; | ||
private static byte[] s_testValueInUtf8Bytes = new byte[] { 0x74, 0x65, 0x73, 0x74 }; | ||
private static readonly string s_insertQuery = $"INSERT INTO {s_sourceTable} VALUES('{s_testValue}')"; | ||
|
||
/// <summary> | ||
/// Constructor: Initializes and populates source and destination tables required for the tests. | ||
/// </summary> | ||
public TestBulkCopyWithUtf8() | ||
{ | ||
using SqlConnection sourceConnection = new SqlConnection(GetConnectionString(true)); | ||
sourceConnection.Open(); | ||
SetupTables(sourceConnection, s_sourceTable, s_destinationTable, s_insertQuery); | ||
} | ||
|
||
/// <summary> | ||
/// Cleanup method to drop tables after test completion. | ||
/// </summary> | ||
public void Dispose() | ||
{ | ||
using SqlConnection connection = new SqlConnection(GetConnectionString(true)); | ||
connection.Open(); | ||
DataTestUtility.DropTable(connection, s_sourceTable); | ||
DataTestUtility.DropTable(connection, s_destinationTable); | ||
connection.Close(); | ||
} | ||
|
||
/// <summary> | ||
/// Builds a connection string with or without Multiple Active Result Sets (MARS) property. | ||
/// </summary> | ||
private string GetConnectionString(bool enableMars) | ||
{ | ||
return new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) | ||
{ | ||
MultipleActiveResultSets = enableMars | ||
}.ConnectionString; | ||
} | ||
|
||
/// <summary> | ||
/// Creates source and destination tables with a varchar(max) column with a collation setting | ||
/// that stores the data in UTF8 encoding and inserts the data in the source table. | ||
/// </summary> | ||
private void SetupTables(SqlConnection connection, string sourceTable, string destinationTable, string insertQuery) | ||
{ | ||
string columnDefinition = "(str_col varchar(max) COLLATE Latin1_General_100_CS_AS_KS_WS_SC_UTF8)"; | ||
DataTestUtility.CreateTable(connection, sourceTable, columnDefinition); | ||
DataTestUtility.CreateTable(connection, destinationTable, columnDefinition); | ||
using SqlCommand insertCommand = connection.CreateCommand(); | ||
insertCommand.CommandText = insertQuery; | ||
Helpers.TryExecute(insertCommand, insertQuery); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CI says |
||
} | ||
|
||
/// <summary> | ||
/// Synchronous test case: Validates that data copied using SqlBulkCopy matches UTF-8 byte sequence for test value. | ||
/// Tested with MARS enabled and disabled, and with streaming enabled and disabled. | ||
/// </summary> | ||
[ConditionalTheory(typeof(DataTestUtility), | ||
nameof(DataTestUtility.AreConnStringsSetup), | ||
nameof(DataTestUtility.IsNotAzureServer), | ||
nameof(DataTestUtility.IsNotAzureSynapse))] | ||
[InlineData(true, true)] | ||
[InlineData(false, true)] | ||
[InlineData(true, false)] | ||
[InlineData(false, false)] | ||
public void BulkCopy_Utf8Data_ShouldMatchSource(bool isMarsEnabled, bool enableStreaming) | ||
{ | ||
// Setup connections for source and destination tables | ||
string connectionString = GetConnectionString(isMarsEnabled); | ||
using SqlConnection sourceConnection = new SqlConnection(connectionString); | ||
sourceConnection.Open(); | ||
using SqlConnection destinationConnection = new SqlConnection(connectionString); | ||
destinationConnection.Open(); | ||
|
||
// Read data from source table | ||
using SqlCommand sourceDataCommand = new SqlCommand($"SELECT str_col FROM {s_sourceTable}", sourceConnection); | ||
using SqlDataReader reader = sourceDataCommand.ExecuteReader(CommandBehavior.SequentialAccess); | ||
|
||
// Verify that the destination table is empty before bulk copy | ||
using SqlCommand countCommand = new SqlCommand($"SELECT COUNT(*) FROM {s_destinationTable}", destinationConnection); | ||
Assert.Equal(0, Convert.ToInt16(countCommand.ExecuteScalar())); | ||
|
||
// Initialize bulk copy configuration | ||
using SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection) | ||
{ | ||
EnableStreaming = enableStreaming, | ||
DestinationTableName = s_destinationTable | ||
}; | ||
|
||
try | ||
{ | ||
// Perform bulk copy from source to destination table | ||
bulkCopy.WriteToServer(reader); | ||
} | ||
catch (Exception ex) | ||
{ | ||
// If bulk copy fails, fail the test with the exception message | ||
Assert.Fail($"Bulk copy failed: {ex.Message}"); | ||
paulmedynski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// Verify that the 1 row from the source table has been copied into our destination table. | ||
Assert.Equal(1, Convert.ToInt16(countCommand.ExecuteScalar())); | ||
|
||
// Read the data from destination table as varbinary to verify the UTF-8 byte sequence | ||
using SqlCommand verifyCommand = new SqlCommand($"SELECT cast(str_col as varbinary) FROM {s_destinationTable}", destinationConnection); | ||
using SqlDataReader verifyReader = verifyCommand.ExecuteReader(CommandBehavior.SequentialAccess); | ||
|
||
// Verify that we have data in the destination table | ||
Assert.True(verifyReader.Read(), "No data found in destination table after bulk copy."); | ||
|
||
// Read the value of the column as SqlBinary. | ||
byte[] actualBytes = verifyReader.GetSqlBinary(0).Value; | ||
|
||
// Verify that the byte array matches the expected UTF-8 byte sequence | ||
Assert.Equal(s_testValueInUtf8Bytes.Length, actualBytes.Length); | ||
Assert.Equal(s_testValueInUtf8Bytes, actualBytes); | ||
} | ||
|
||
/// <summary> | ||
/// Asynchronous version of the testcase BulkCopy_Utf8Data_ShouldMatchSource | ||
/// </summary> | ||
[ConditionalTheory(typeof(DataTestUtility), | ||
nameof(DataTestUtility.AreConnStringsSetup), | ||
nameof(DataTestUtility.IsNotAzureServer), | ||
nameof(DataTestUtility.IsNotAzureSynapse))] | ||
[InlineData(true, true)] | ||
[InlineData(false, true)] | ||
[InlineData(true, false)] | ||
[InlineData(false, false)] | ||
public async Task BulkCopy_Utf8Data_ShouldMatchSource_Async(bool isMarsEnabled, bool enableStreaming) | ||
{ | ||
// Setup connections for source and destination tables | ||
string connectionString = GetConnectionString(isMarsEnabled); | ||
using SqlConnection sourceConnection = new SqlConnection(connectionString); | ||
await sourceConnection.OpenAsync(); | ||
using SqlConnection destinationConnection = new SqlConnection(connectionString); | ||
await destinationConnection.OpenAsync(); | ||
|
||
// Read data from source table | ||
using SqlCommand sourceDataCommand = new SqlCommand($"SELECT str_col FROM {s_sourceTable}", sourceConnection); | ||
using SqlDataReader reader = await sourceDataCommand.ExecuteReaderAsync(CommandBehavior.SequentialAccess); | ||
|
||
// Verify that the destination table is empty before bulk copy | ||
using SqlCommand countCommand = new SqlCommand($"SELECT COUNT(*) FROM {s_destinationTable}", destinationConnection); | ||
Assert.Equal(0, Convert.ToInt16(await countCommand.ExecuteScalarAsync())); | ||
|
||
// Initialize bulk copy configuration | ||
using SqlBulkCopy bulkCopy = new SqlBulkCopy(destinationConnection) | ||
{ | ||
EnableStreaming = enableStreaming, | ||
DestinationTableName = s_destinationTable | ||
}; | ||
|
||
try | ||
{ | ||
// Perform bulk copy from source to destination table | ||
await bulkCopy.WriteToServerAsync(reader); | ||
} | ||
catch (Exception ex) | ||
{ | ||
// If bulk copy fails, fail the test with the exception message | ||
Assert.Fail($"Bulk copy failed: {ex.Message}"); | ||
paulmedynski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// Verify that the 1 row from the source table has been copied into our destination table. | ||
Assert.Equal(1, Convert.ToInt16(await countCommand.ExecuteScalarAsync())); | ||
|
||
// Read the data from destination table as varbinary to verify the UTF-8 byte sequence | ||
using SqlCommand verifyCommand = new SqlCommand($"SELECT cast(str_col as varbinary) FROM {s_destinationTable}", destinationConnection); | ||
using SqlDataReader verifyReader = await verifyCommand.ExecuteReaderAsync(CommandBehavior.SequentialAccess); | ||
|
||
// Verify that we have data in the destination table | ||
Assert.True(await verifyReader.ReadAsync(), "No data found in destination table after bulk copy."); | ||
|
||
// Read the value of the column as SqlBinary. | ||
byte[] actualBytes = verifyReader.GetSqlBinary(0).Value; | ||
|
||
// Verify that the byte array matches the expected UTF-8 byte sequence | ||
Assert.Equal(s_testValueInUtf8Bytes.Length, actualBytes.Length); | ||
Assert.Equal(s_testValueInUtf8Bytes, actualBytes); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.