Skip to content

Commit 5aae5e1

Browse files
[6.1] Stabilize CI Pipelines (#3601)
Co-authored-by: Edward Neal <55035479+edwardneal@users.noreply.github.com>
1 parent 214261f commit 5aae5e1

35 files changed

+361
-208
lines changed

eng/pipelines/common/templates/steps/configure-sql-server-macos-step.yml

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,37 +34,63 @@ steps:
3434
docker pull mcr.microsoft.com/mssql/server:2022-latest
3535
3636
# Password for the SA user (required)
37-
MSSQL_SA_PW=${{parameters.password }}
37+
MSSQL_SA_PW=${{ parameters.password }}
3838
3939
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=$MSSQL_SA_PW" -p 1433:1433 -p 1434:1434 --name sql1 --hostname sql1 -d mcr.microsoft.com/mssql/server:2022-latest
4040
4141
sleep 5
4242
4343
docker ps -a
4444
45-
# Connect to server and get the version:
46-
counter=1
47-
errstatus=1
48-
while [ $counter -le 20 ] && [ $errstatus = 1 ]
45+
# Connect to the SQL Server container and get its version.
46+
#
47+
# It can take a while for the docker container to start listening and be
48+
# ready for connections, so we will wait for up to 2 minutes, checking every
49+
# 3 seconds.
50+
51+
# Wait 3 seconds between attempts.
52+
delay=3
53+
54+
# Try up to 40 times (2 minutes) to connect.
55+
maxAttempts=40
56+
57+
# Attempt counter.
58+
attempt=1
59+
60+
# Flag to indicate when SQL Server is ready to accept connections.
61+
ready=0
62+
63+
while [ $attempt -le $maxAttempts ]
4964
do
50-
echo Waiting for SQL Server to start...
51-
sleep 3
52-
sqlcmd -S 0.0.0.0 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" 2>$SQLCMD_ERRORS
53-
errstatus=$?
54-
((counter++))
65+
echo "Waiting for SQL Server to start (attempt #$attempt of $maxAttempts)..."
66+
67+
sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" >> $SQLCMD_ERRORS 2>&1
68+
69+
# If the command was successful, then the SQL Server is ready.
70+
if [ $? -eq 0 ]; then
71+
ready=1
72+
break
73+
fi
74+
75+
# Increment the attempt counter.
76+
((attempt++))
77+
78+
# Wait before trying again.
79+
sleep $delay
5580
done
5681
57-
# Display error if connection failed:
58-
if [ $errstatus = 1 ]
82+
# Is the SQL Server ready?
83+
if [ $ready -eq 0 ]
5984
then
60-
echo Cannot connect to SQL Server, installation aborted
85+
# No, so report the error(s) and exit.
86+
echo Cannot connect to SQL Server; installation aborted; errors were:
6187
cat $SQLCMD_ERRORS
6288
rm -f $SQLCMD_ERRORS
63-
exit $errstatus
64-
else
65-
rm -f $SQLCMD_ERRORS
89+
exit 1
6690
fi
6791
92+
rm -f $SQLCMD_ERRORS
93+
6894
echo "Use sqlcmd to show which IP addresses are being listened on..."
6995
echo 0.0.0.0
7096
sqlcmd -S 0.0.0.0 -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2
@@ -78,7 +104,7 @@ steps:
78104
sqlcmd -No -U sa -P $MSSQL_SA_PW -Q "SELECT @@VERSION" -l 2
79105
80106
echo "Configuring Dedicated Administer Connections to allow remote connections..."
81-
sqlcmd -S 0.0.0.0 -No -U sa -P $MSSQL_SA_PW -Q "sp_configure 'remote admin connections', 1; RECONFIGURE;"
107+
sqlcmd -S 127.0.0.1 -No -U sa -P $MSSQL_SA_PW -Q "sp_configure 'remote admin connections', 1; RECONFIGURE;"
82108
if [ $? = 1 ]
83109
then
84110
echo "Error configuring DAC for remote access."

src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ public void SqlParameterProperties(string connection)
166166
const string firstColumnName = @"firstColumn";
167167
const string secondColumnName = @"secondColumn";
168168
const string thirdColumnName = @"thirdColumn";
169-
string inputProcedureName = DataTestUtility.GetUniqueName("InputProc").ToString();
170-
string outputProcedureName = DataTestUtility.GetUniqueName("OutputProc").ToString();
169+
string inputProcedureName = DataTestUtility.GetShortName("InputProc").ToString();
170+
string outputProcedureName = DataTestUtility.GetShortName("OutputProc").ToString();
171171
const int charColumnSize = 100;
172172
const int decimalColumnPrecision = 10;
173173
const int decimalColumnScale = 4;
@@ -722,7 +722,7 @@ public void TestExecuteReader(string connection)
722722
[ClassData(typeof(AEConnectionStringProvider))]
723723
public async Task TestExecuteReaderAsyncWithLargeQuery(string connectionString)
724724
{
725-
string randomName = DataTestUtility.GetUniqueName(Guid.NewGuid().ToString().Replace("-", ""), false);
725+
string randomName = DataTestUtility.GetShortName(Guid.NewGuid().ToString().Replace("-", ""), false);
726726
if (randomName.Length > 50)
727727
{
728728
randomName = randomName.Substring(0, 50);
@@ -912,8 +912,8 @@ public void TestEnclaveStoredProceduresWithAndWithoutParameters(string connectio
912912
using SqlCommand sqlCommand = new("", sqlConnection, transaction: null,
913913
columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled);
914914

915-
string procWithoutParams = DataTestUtility.GetUniqueName("EnclaveWithoutParams", withBracket: false);
916-
string procWithParam = DataTestUtility.GetUniqueName("EnclaveWithParams", withBracket: false);
915+
string procWithoutParams = DataTestUtility.GetShortName("EnclaveWithoutParams", withBracket: false);
916+
string procWithParam = DataTestUtility.GetShortName("EnclaveWithParams", withBracket: false);
917917

918918
try
919919
{

src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/CspProviderExt.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void TestRoundTripWithCspAndCertStoreProvider()
5454
[MemberData(nameof(TestEncryptDecryptWithCsp_Data))]
5555
public void TestEncryptDecryptWithCsp(string connectionString, string providerName, int providerType)
5656
{
57-
string keyIdentifier = DataTestUtility.GetUniqueNameForSqlServer("CSP");
57+
string keyIdentifier = DataTestUtility.GetLongName("CSP");
5858
CspParameters namedCspParameters = new CspParameters(providerType, providerName, keyIdentifier);
5959
using SQLSetupStrategyCspProvider sqlSetupStrategyCsp = new SQLSetupStrategyCspProvider(namedCspParameters);
6060

src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs

Lines changed: 169 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public static bool TcpConnectionStringDoesNotUseAadAuth
111111
{
112112
get
113113
{
114-
SqlConnectionStringBuilder builder = new (TCPConnectionString);
114+
SqlConnectionStringBuilder builder = new(TCPConnectionString);
115115
return builder.Authentication == SqlAuthenticationMethod.SqlPassword || builder.Authentication == SqlAuthenticationMethod.NotSpecified;
116116
}
117117
}
@@ -556,59 +556,176 @@ public static bool DoesHostAddressContainBothIPv4AndIPv6()
556556
}
557557
}
558558

559+
// Generate a new GUID and return the characters from its 1st and 4th
560+
// parts, as shown here:
561+
//
562+
// 7ff01cb8-88c7-11f0-b433-00155d7e531e
563+
// ^^^^^^^^ ^^^^
564+
//
565+
// These 12 characters are concatenated together without any
566+
// separators. These 2 parts typically comprise a timestamp and clock
567+
// sequence, most likely to be unique for tests that generate names in
568+
// quick succession.
569+
private static string GetGuidParts()
570+
{
571+
var guid = Guid.NewGuid().ToString();
572+
// GOTCHA: The slice operator is inclusive of the start index and
573+
// exclusive of the end index!
574+
return guid.Substring(0, 8) + guid.Substring(19, 4);
575+
}
576+
559577
/// <summary>
560-
/// Generate a unique name to use in Sql Server;
561-
/// some providers does not support names (Oracle supports up to 30).
578+
/// Generate a short unique database object name, whose maximum length
579+
/// is 30 characters, with the format:
580+
///
581+
/// <Prefix>_<GuidParts>
582+
///
583+
/// The Prefix will be truncated to satisfy the overall maximum length.
584+
///
585+
/// The GUID parts will be the characters from the 1st and 4th blocks
586+
/// from a traditional string representation, as shown here:
587+
///
588+
/// 7ff01cb8-88c7-11f0-b433-00155d7e531e
589+
/// ^^^^^^^^ ^^^^
590+
///
591+
/// These 2 parts typically comprise a timestamp and clock sequence,
592+
/// most likely to be unique for tests that generate names in quick
593+
/// succession. The 12 characters are concatenated together without any
594+
/// separators.
562595
/// </summary>
563-
/// <param name="prefix">The name length will be no more then (16 + prefix.Length + escapeLeft.Length + escapeRight.Length).</param>
564-
/// <param name="withBracket">Name without brackets.</param>
565-
/// <returns>Unique name by considering the Sql Server naming rules.</returns>
566-
public static string GetUniqueName(string prefix, bool withBracket = true)
567-
{
568-
string escapeLeft = withBracket ? "[" : string.Empty;
569-
string escapeRight = withBracket ? "]" : string.Empty;
570-
string uniqueName = string.Format("{0}{1}_{2}_{3}{4}",
571-
escapeLeft,
572-
prefix,
573-
DateTime.Now.Ticks.ToString("X", CultureInfo.InvariantCulture), // up to 8 characters
574-
Guid.NewGuid().ToString().Substring(0, 6), // take the first 6 characters only
575-
escapeRight);
576-
return uniqueName;
596+
///
597+
/// <param name="prefix">
598+
/// The prefix to use when generating the unique name, truncated to at
599+
/// most 18 characters when withBracket is false, and 16 characters when
600+
/// withBracket is true.
601+
///
602+
/// This should not contain any characters that cannot be used in
603+
/// database object names. See:
604+
///
605+
/// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
606+
/// </param>
607+
///
608+
/// <param name="withBracket">
609+
/// When true, the entire generated name will be enclosed in square
610+
/// brackets, for example:
611+
///
612+
/// [MyPrefix_7ff01cb811f0]
613+
/// </param>
614+
///
615+
/// <returns>
616+
/// A unique database object name, no more than 30 characters long.
617+
/// </returns>
618+
public static string GetShortName(string prefix, bool withBracket = true)
619+
{
620+
StringBuilder name = new(30);
621+
622+
if (withBracket)
623+
{
624+
name.Append('[');
625+
}
626+
627+
int maxPrefixLength = withBracket ? 16 : 18;
628+
if (prefix.Length > maxPrefixLength)
629+
{
630+
prefix = prefix.Substring(0, maxPrefixLength);
631+
}
632+
633+
name.Append(prefix);
634+
name.Append('_');
635+
name.Append(GetGuidParts());
636+
637+
if (withBracket)
638+
{
639+
name.Append(']');
640+
}
641+
642+
return name.ToString();
577643
}
578644

579645
/// <summary>
580-
/// Uses environment values `UserName` and `MachineName` in addition to the specified `prefix` and current date
581-
/// to generate a unique name to use in Sql Server;
582-
/// SQL Server supports long names (up to 128 characters), add extra info for troubleshooting.
646+
/// Generate a long unique database object name, whose maximum length is
647+
/// 96 characters, with the format:
648+
///
649+
/// <Prefix>_<GuidParts>_<UserName>_<MachineName>
650+
///
651+
/// The Prefix will be truncated to satisfy the overall maximum length.
652+
///
653+
/// The GUID Parts will be the characters from the 1st and 4th blocks
654+
/// from a traditional string representation, as shown here:
655+
///
656+
/// 7ff01cb8-88c7-11f0-b433-00155d7e531e
657+
/// ^^^^^^^^ ^^^^
658+
///
659+
/// These 2 parts typically comprise a timestamp and clock sequence,
660+
/// most likely to be unique for tests that generate names in quick
661+
/// succession. The 12 characters are concatenated together without any
662+
/// separators.
663+
///
664+
/// The UserName and MachineName are obtained from the Environment,
665+
/// and will be truncated to satisfy the maximum overall length.
583666
/// </summary>
584-
/// <param name="prefix">Add the prefix to the generate string.</param>
585-
/// <param name="withBracket">Database name must be pass with brackets by default.</param>
586-
/// <returns>Unique name by considering the Sql Server naming rules, never longer than 96 characters.</returns>
587-
public static string GetUniqueNameForSqlServer(string prefix, bool withBracket = true)
588-
{
589-
string extendedPrefix = string.Format(
590-
"{0}_{1}_{2}@{3}",
591-
prefix,
592-
Environment.UserName,
593-
Environment.MachineName,
594-
DateTime.Now.ToString("yyyy_MM_dd", CultureInfo.InvariantCulture));
595-
string name = GetUniqueName(extendedPrefix, withBracket);
596-
597-
// Truncate to no more than 96 characters.
598-
const int maxLen = 96;
599-
if (name.Length > maxLen)
600-
{
601-
if (withBracket)
602-
{
603-
name = name.Substring(0, maxLen - 1) + ']';
604-
}
605-
else
606-
{
607-
name = name.Substring(0, maxLen);
608-
}
667+
///
668+
/// <param name="prefix">
669+
/// The prefix to use when generating the unique name, truncated to at
670+
/// most 32 characters.
671+
///
672+
/// This should not contain any characters that cannot be used in
673+
/// database object names. See:
674+
///
675+
/// https://learn.microsoft.com/en-us/sql/relational-databases/databases/database-identifiers?view=sql-server-ver17#rules-for-regular-identifiers
676+
/// </param>
677+
///
678+
/// <param name="withBracket">
679+
/// When true, the entire generated name will be enclosed in square
680+
/// brackets, for example:
681+
///
682+
/// [MyPrefix_7ff01cb811f0_test_user_ci_agent_machine_name]
683+
/// </param>
684+
///
685+
/// <returns>
686+
/// A unique database object name, no more than 96 characters long.
687+
/// </returns>
688+
public static string GetLongName(string prefix, bool withBracket = true)
689+
{
690+
StringBuilder name = new(96);
691+
692+
if (withBracket)
693+
{
694+
name.Append('[');
695+
}
696+
697+
if (prefix.Length > 32)
698+
{
699+
prefix = prefix.Substring(0, 32);
609700
}
610701

611-
return name;
702+
name.Append(prefix);
703+
name.Append('_');
704+
name.Append(GetGuidParts());
705+
name.Append('_');
706+
707+
var suffix =
708+
Environment.UserName + '_' +
709+
Environment.MachineName;
710+
711+
int maxSuffixLength = 96 - name.Length;
712+
if (withBracket)
713+
{
714+
--maxSuffixLength;
715+
}
716+
if (suffix.Length > maxSuffixLength)
717+
{
718+
suffix = suffix.Substring(0, maxSuffixLength);
719+
}
720+
721+
name.Append(suffix);
722+
723+
if (withBracket)
724+
{
725+
name.Append(']');
726+
}
727+
728+
return name.ToString();
612729
}
613730

614731
public static void CreateTable(SqlConnection sqlConnection, string tableName, string createBody)
@@ -1101,6 +1218,8 @@ protected virtual void OnMatchingEventWritten(EventWrittenEventArgs eventData)
11011218

11021219
public readonly ref struct XEventScope // : IDisposable
11031220
{
1221+
private const int MaxXEventsLatencyS = 5;
1222+
11041223
private readonly SqlConnection _connection;
11051224
private readonly bool _useDatabaseSession;
11061225

@@ -1135,6 +1254,8 @@ INNER JOIN sys.dm_xe_sessions AS xe
11351254

11361255
using (SqlCommand command = new SqlCommand(xEventQuery, _connection))
11371256
{
1257+
Thread.Sleep(MaxXEventsLatencyS * 1000);
1258+
11381259
if (_connection.State == ConnectionState.Closed)
11391260
{
11401261
_connection.Open();
@@ -1155,9 +1276,9 @@ private void SetupXEvent(string eventSpecification, string targetSpecification)
11551276
{eventSpecification}
11561277
{targetSpecification}
11571278
WITH (
1158-
MAX_MEMORY=4096 KB,
1279+
MAX_MEMORY=16 MB,
11591280
EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,
1160-
MAX_DISPATCH_LATENCY=30 SECONDS,
1281+
MAX_DISPATCH_LATENCY={MaxXEventsLatencyS} SECONDS,
11611282
MAX_EVENT_SIZE=0 KB,
11621283
MEMORY_PARTITION_MODE=NONE,
11631284
TRACK_CAUSALITY=ON,

0 commit comments

Comments
 (0)