Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ public static class DataTestUtility
//SQL Server EngineEdition
private static string s_sqlServerEngineEdition;

// JSON Coloumn type
public static readonly bool IsJsonSupported = false;

// Azure Synapse EngineEditionId == 6
// More could be read at https://learn.microsoft.com/en-us/sql/t-sql/functions/serverproperty-transact-sql?view=sql-server-ver16#propertyname
public static bool IsAzureSynapse
Expand Down Expand Up @@ -175,6 +178,7 @@ static DataTestUtility()
ManagedIdentitySupported = c.ManagedIdentitySupported;
IsManagedInstance = c.IsManagedInstance;
AliasName = c.AliasName;
IsJsonSupported = c.IsJsonSupported;

System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@
<Compile Include="SQL\Common\SystemDataInternals\TdsParserStateObjectHelper.cs" />
<Compile Include="SQL\ConnectionTestWithSSLCert\CertificateTest.cs" />
<Compile Include="SQL\ConnectionTestWithSSLCert\CertificateTestWithTdsServer.cs" />
<Compile Include="SQL\JsonTest\JsonTest.cs" />
<Compile Include="SQL\SqlCommand\SqlCommandStoredProcTest.cs" />
<Compile Include="TracingTests\TestTdsServer.cs" />
<Compile Include="XUnitAssemblyAttributes.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlTypes;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Data.SqlClient.ManualTesting.Tests
{
public class JsonTest
{
private readonly ITestOutputHelper _output;

public JsonTest(ITestOutputHelper output)
{
_output = output;
}

private static readonly string jsonDataString = "[{\"name\":\"Dave\",\"skills\":[\"Python\"]},{\"name\":\"Ron\",\"surname\":\"Peter\"}]";

private void ValidateRowsAffected(int rowsAffected)
{
_output.WriteLine($"Rows affected: {rowsAffected}");
Assert.Equal(1, rowsAffected);
}

private void ValidateRows(SqlDataReader reader)
{
while (reader.Read())
{
string jsonData = reader.GetString(0);
_output.WriteLine(jsonData);
Assert.Equal(jsonDataString, jsonData);
}
}

private async Task ValidateRowsAsync(SqlDataReader reader)
{
while (await reader.ReadAsync())
{
string jsonData = reader.GetString(0);
_output.WriteLine(jsonData);
Assert.Equal(jsonDataString, jsonData);
}
}

private void ValidateSchema(SqlDataReader reader)
{
System.Collections.ObjectModel.ReadOnlyCollection<DbColumn> schema = reader.GetColumnSchema();
foreach (DbColumn column in schema)
{
_output.WriteLine("Column Name is " + column.ColumnName);
_output.WriteLine("Column DataType is " + column?.DataType.ToString());
_output.WriteLine("Column DataTypeName is " + column.DataTypeName);
Assert.Equal("json", column.DataTypeName);
}
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsJsonSupported))]
Comment thread
deepaksa1 marked this conversation as resolved.
public void TestJsonWrite()
Comment thread
deepaksa1 marked this conversation as resolved.
{
string tableName = DataTestUtility.GetUniqueNameForSqlServer("Json_Test");
string spName = DataTestUtility.GetUniqueNameForSqlServer("spJson_WriteTest");

string tableCreate = "CREATE TABLE " + tableName + " (Data json)";
string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
string spCreate = "CREATE PROCEDURE " + spName + " (@jsonData json) AS " + tableInsert;

using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
{
connection.Open();

using (SqlCommand command = connection.CreateCommand())
{
//Create Table
command.CommandText = tableCreate;
command.ExecuteNonQuery();

//Create SP for writing json values
command.CommandText = spCreate;
command.ExecuteNonQuery();

command.CommandText = tableInsert;
var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
command.Parameters.Add(parameter);

//Test 1
//Write json value using a parameterized query
parameter.Value = jsonDataString;
int rowsAffected = command.ExecuteNonQuery();
ValidateRowsAffected(rowsAffected);

//Test 2
//Write a SqlString type as json
parameter.Value = new SqlString(jsonDataString);
int rowsAffected2 = command.ExecuteNonQuery();
ValidateRowsAffected(rowsAffected2);

//Test 3
//Write json value using SP
using (SqlCommand command2 = connection.CreateCommand())
{
command2.CommandText = spName;
command2.CommandType = CommandType.StoredProcedure;
var parameter2 = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
parameter2.Value = jsonDataString;
command2.Parameters.Add(parameter2);
int rowsAffected3 = command2.ExecuteNonQuery();
ValidateRowsAffected(rowsAffected3);
}
}
}
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsJsonSupported))]
public async Task TestJsonWriteAsync()
{
string tableName = DataTestUtility.GetUniqueNameForSqlServer("Json_Test");
string spName = DataTestUtility.GetUniqueNameForSqlServer("spJson_WriteTest");

string tableCreate = "CREATE TABLE " + tableName + " (Data json)";
string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
string spCreate = "CREATE PROCEDURE " + spName + " (@jsonData json) AS " + tableInsert;

using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
{
await connection.OpenAsync();

using (SqlCommand command = connection.CreateCommand())
{
//Create Table
command.CommandText = tableCreate;
await command.ExecuteNonQueryAsync();

//Create SP for writing json values
command.CommandText = spCreate;
await command.ExecuteNonQueryAsync();

command.CommandText = tableInsert;
var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
command.Parameters.Add(parameter);

//Test 1
//Write json value using a parameterized query
parameter.Value = jsonDataString;
int rowsAffected = await command.ExecuteNonQueryAsync();
ValidateRowsAffected(rowsAffected);

//Test 2
//Write a SqlString type as json
parameter.Value = new SqlString(jsonDataString);
int rowsAffected2 = await command.ExecuteNonQueryAsync();
ValidateRowsAffected(rowsAffected2);

//Test 3
//Write json value using SP
using (SqlCommand command2 = connection.CreateCommand())
{
command2.CommandText = spName;
command2.CommandType = CommandType.StoredProcedure;
var parameter2 = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
parameter2.Value = jsonDataString;
command2.Parameters.Add(parameter2);
int rowsAffected3 = await command.ExecuteNonQueryAsync();
ValidateRowsAffected(rowsAffected3);
}
}
}
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsJsonSupported))]
public void TestJsonRead()
{
string tableName = DataTestUtility.GetUniqueNameForSqlServer("Json_Test");
string spName = DataTestUtility.GetUniqueNameForSqlServer("spJson_ReadTest");

string tableCreate = "CREATE TABLE " + tableName + " (Data json)";
string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
string tableRead = "SELECT * FROM " + tableName;
string spCreate = "CREATE PROCEDURE " + spName + "AS " + tableRead;

using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
//Create Table
command.CommandText = tableCreate;
command.ExecuteNonQuery();

//Create SP for reading from json column
command.CommandText = spCreate;
command.ExecuteNonQuery();

//Insert sample json data
//This will be used for reading
command.CommandText = tableInsert;
var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
parameter.Value = jsonDataString;
command.Parameters.Add(parameter);
command.ExecuteNonQuery();

//Test 1
//Read json value using query
command.CommandText = tableRead;
var reader = command.ExecuteReader();
ValidateRows(reader);

//Test 2
//Read the column metadata
Comment thread
deepaksa1 marked this conversation as resolved.
ValidateSchema(reader);
reader.Close();

//Test 3
//Read json value using SP
using (SqlCommand command2 = connection.CreateCommand())
{
command2.CommandText = spName;
command2.CommandType = CommandType.StoredProcedure;
var reader2 = command2.ExecuteReader();
ValidateRows(reader2);
reader2.Close();
}
}
}
}

[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsJsonSupported))]
public async Task TestJsonReadAsync()
{
string tableName = DataTestUtility.GetUniqueNameForSqlServer("Json_Test");
string spName = DataTestUtility.GetUniqueNameForSqlServer("spJson_ReadTest");

string tableCreate = "CREATE TABLE " + tableName + " (Data json)";
string tableInsert = "INSERT INTO " + tableName + " VALUES (@jsonData)";
string tableRead = "SELECT * FROM " + tableName;
string spCreate = "CREATE PROCEDURE " + spName + "AS " + tableRead;

using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString))
{
await connection.OpenAsync();
using (SqlCommand command = connection.CreateCommand())
{
//Create Table
command.CommandText = tableCreate;
await command.ExecuteNonQueryAsync();

//Create SP for reading from json column
command.CommandText = spCreate;
await command.ExecuteNonQueryAsync();

//Insert sample json data
//This will be used for reading
command.CommandText = tableInsert;
var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json);
parameter.Value = jsonDataString;
command.Parameters.Add(parameter);
await command.ExecuteNonQueryAsync();

//Test 1
//Read json value using query
command.CommandText = tableRead;
var reader = await command.ExecuteReaderAsync();
await ValidateRowsAsync(reader);

//Test 2
//Read the column metadata
ValidateSchema(reader);
reader.Close();

//Test 3
//Read json value using SP
using (SqlCommand command2 = connection.CreateCommand())
{
command2.CommandText = spName;
command2.CommandType = CommandType.StoredProcedure;
var reader2 = await command2.ExecuteReaderAsync();
await ValidateRowsAsync(reader2);
reader2.Close();
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public class Config
public string KerberosDomainUser = null;
public bool IsManagedInstance = false;
public string AliasName = null;
public bool IsJsonSupported = false;
Copy link
Copy Markdown
Member

@cheenamalhotra cheenamalhotra Aug 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something you can detect after making connection? Any DMV that can be called instead?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cheenamalhotra
Can't be done without turning on Feature Switches on Debug builds of Sql server today.
We will need a hardcoded config value at this moment unfortunately :(

also question for my education @cheenamalhotra . In ConditionalFact check, do we make server calls to check for features. Because that may lead to transient fault handling in test execution condition. I like the idea of dynamically checking the server for the feature, as long as it is not done in the body of the test, since the test would show as executed but it really wont be executed. So adding a server query in ConditionalFact condition would make sense. But wanted to check if there is prior art.

public static Config Load(string configPath = @"config.json")
{
try
Expand Down