Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
9 changes: 7 additions & 2 deletions performance/SqlBindingBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System.Diagnostics;
using System.Linq;
using BenchmarkDotNet.Running;
using Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration;
using Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common;

namespace Microsoft.Azure.WebJobs.Extensions.Sql.Performance
{
Expand All @@ -13,7 +14,8 @@ public static void Main(string[] args)
{
bool runAll = args.Length == 0;

using var testFixture = new IntegrationTestFixture();
Process azuriteHost = TestUtils.StartAzurite();
TestUtils.SetupDatabase(out string masterConnectionString, out string connectionString);

// **IMPORTANT** If changing these make sure to update template-steps-performance.yml as well
if (runAll || args.Contains("input"))
Expand Down Expand Up @@ -48,6 +50,9 @@ public static void Main(string[] args)
{
BenchmarkRunner.Run<SqlTriggerBindingPerformance_ChangeRate>();
}

TestUtils.StopAzurite(azuriteHost);

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.

These should go in a finally block

TestUtils.DropDatabase(masterConnectionString, connectionString);
}
}
}
120 changes: 120 additions & 0 deletions test/Common/TestUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common;
using Microsoft.Data.SqlClient;

namespace Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common
{
Expand All @@ -22,6 +23,125 @@ public static class TestUtils
{
internal static int ThreadId;

/// <summary>
/// This returns a running Azurite storage emulator.
/// </summary>
public static Process StartAzurite()
{
Console.WriteLine("Starting Azurite Host...");
var azuriteHost = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "azurite",
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true
}
};

azuriteHost.Start();
return azuriteHost;
}

public static void StopAzurite(Process azuriteHost)
{
Console.WriteLine("Stopping Azurite Host...");
try
{
azuriteHost.Kill(true);
azuriteHost.Dispose();
}
catch (Exception e)
{
Console.WriteLine($"Failed to stop Azurite, Error: {e.Message}");
}
}

/// <summary>
/// Sets up a test database for the tests to use.
/// </summary>
/// <remarks>
/// The server the database will be created on can be set by the environment variable "TEST_SERVER", otherwise localhost will be used by default.
/// By default, integrated authentication will be used to connect to the server, unless the env variable "SA_PASSWORD" is set.
/// In this case, connection will be made using SQL login with user "SA" and the provided password.
/// </remarks>
public static void SetupDatabase(out string MasterConnectionString, out string DatabaseName)
{
SqlConnectionStringBuilder connectionStringBuilder;
string connectionString = Environment.GetEnvironmentVariable("TEST_CONNECTION_STRING");
string masterConnectionString;
if (connectionString != null)
{
masterConnectionString = connectionString;
connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
}
else
{
// Get the test server name from environment variable "TEST_SERVER", default to localhost if not set
string testServer = Environment.GetEnvironmentVariable("TEST_SERVER");
if (string.IsNullOrEmpty(testServer))
{
testServer = "localhost";
}

// First connect to master to create the database
connectionStringBuilder = new SqlConnectionStringBuilder()
{
DataSource = testServer,
InitialCatalog = "master",
Pooling = false,
Encrypt = SqlConnectionEncryptOption.Optional
};

// Either use integrated auth or SQL login depending if SA_PASSWORD is set
string userId = "SA";
string password = Environment.GetEnvironmentVariable("SA_PASSWORD");
if (string.IsNullOrEmpty(password))
{
connectionStringBuilder.IntegratedSecurity = true;
}
else
{
connectionStringBuilder.UserID = userId;
connectionStringBuilder.Password = password;
}
masterConnectionString = connectionStringBuilder.ToString();
}

// Create database
// Retry this in case the server isn't fully initialized yet
string databaseName = GetUniqueDBName("SqlBindingsTest");
Retry(() =>
{
using var masterConnection = new SqlConnection(masterConnectionString);
masterConnection.Open();
ExecuteNonQuery(masterConnection, $"CREATE DATABASE [{databaseName}]", Console.WriteLine);
// Enable change tracking for trigger tests
ExecuteNonQuery(masterConnection, $"ALTER DATABASE [{databaseName}] SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);", Console.WriteLine);
}, Console.WriteLine);

connectionStringBuilder.InitialCatalog = databaseName;

// Set SqlConnectionString env var for the tests to use
Environment.SetEnvironmentVariable("SqlConnectionString", connectionStringBuilder.ToString());
MasterConnectionString = masterConnectionString;
DatabaseName = databaseName;
}

public static void DropDatabase(string masterConnectionString, string databaseName)
{
try
{
using var masterConnection = new SqlConnection(masterConnectionString);
masterConnection.Open();
ExecuteNonQuery(masterConnection, $"DROP DATABASE IF EXISTS {databaseName}", Console.WriteLine);
}
catch (Exception e)
{
Console.WriteLine($"Failed to drop {databaseName}, Error: {e.Message}");
}
}

/// <summary>
/// Returns a mangled name that unique based on Prefix + Machine + Process
/// </summary>
Expand Down
122 changes: 7 additions & 115 deletions test/Integration/IntegrationTestFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common;
using Microsoft.Data.SqlClient;
using Xunit;
using static Microsoft.Azure.WebJobs.Extensions.Sql.Telemetry.Telemetry;

Expand All @@ -22,17 +21,17 @@ public class IntegrationTestFixture : IDisposable
/// Host process for Azurite local storage emulator. This is required for non-HTTP trigger functions:
/// https://docs.microsoft.com/azure/azure-functions/functions-develop-local
/// </summary>
private Process AzuriteHost;
private readonly Process AzuriteHost;

/// <summary>
/// Connection string to the master database on the test server, mainly used for database setup and teardown.
/// </summary>
private string MasterConnectionString;
private readonly string MasterConnectionString;

/// <summary>
/// Name of the database used.
/// </summary>
private string DatabaseName;
private readonly string DatabaseName;

/// <summary>
/// List of all functions in the samples folder that will be started before the
Expand All @@ -56,98 +55,11 @@ public class IntegrationTestFixture : IDisposable

public IntegrationTestFixture()
{
this.StartAzurite();
this.SetupDatabase();
this.AzuriteHost = TestUtils.StartAzurite();
TestUtils.SetupDatabase(out this.MasterConnectionString, out this.DatabaseName);
this.StartFunctionHosts();
}

/// <summary>
/// This starts the Azurite storage emulator.
/// </summary>
protected void StartAzurite()
{
Console.WriteLine("Starting Azurite Host...");
this.AzuriteHost = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "azurite",
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = true
}
};

this.AzuriteHost.Start();
}

/// <summary>
/// Sets up a test database for the tests to use.
/// </summary>
/// <remarks>
/// The server the database will be created on can be set by the environment variable "TEST_SERVER", otherwise localhost will be used by default.
/// By default, integrated authentication will be used to connect to the server, unless the env variable "SA_PASSWORD" is set.
/// In this case, connection will be made using SQL login with user "SA" and the provided password.
/// </remarks>
private void SetupDatabase()
{
SqlConnectionStringBuilder connectionStringBuilder;
string connectionString = Environment.GetEnvironmentVariable("TEST_CONNECTION_STRING");
if (connectionString != null)
{
this.MasterConnectionString = connectionString;
connectionStringBuilder = new SqlConnectionStringBuilder(connectionString);
}
else
{
// Get the test server name from environment variable "TEST_SERVER", default to localhost if not set
string testServer = Environment.GetEnvironmentVariable("TEST_SERVER");
if (string.IsNullOrEmpty(testServer))
{
testServer = "localhost";
}

// First connect to master to create the database
connectionStringBuilder = new SqlConnectionStringBuilder()
{
DataSource = testServer,
InitialCatalog = "master",
Pooling = false,
Encrypt = SqlConnectionEncryptOption.Optional
};

// Either use integrated auth or SQL login depending if SA_PASSWORD is set
string userId = "SA";
string password = Environment.GetEnvironmentVariable("SA_PASSWORD");
if (string.IsNullOrEmpty(password))
{
connectionStringBuilder.IntegratedSecurity = true;
}
else
{
connectionStringBuilder.UserID = userId;
connectionStringBuilder.Password = password;
}
this.MasterConnectionString = connectionStringBuilder.ToString();
}

// Create database
// Retry this in case the server isn't fully initialized yet
this.DatabaseName = TestUtils.GetUniqueDBName("SqlBindingsTest");
TestUtils.Retry(() =>
{
using var masterConnection = new SqlConnection(this.MasterConnectionString);
masterConnection.Open();
TestUtils.ExecuteNonQuery(masterConnection, $"CREATE DATABASE [{this.DatabaseName}]", Console.WriteLine);
// Enable change tracking for trigger tests
TestUtils.ExecuteNonQuery(masterConnection, $"ALTER DATABASE [{this.DatabaseName}] SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);", Console.WriteLine);
}, Console.WriteLine);

connectionStringBuilder.InitialCatalog = this.DatabaseName;

// Set SqlConnectionString env var for the tests to use
Environment.SetEnvironmentVariable("SqlConnectionString", connectionStringBuilder.ToString());
}

/// <summary>
/// This starts the function hosts for each language.
/// </summary>
Expand Down Expand Up @@ -257,28 +169,8 @@ void TestOutputHandler(object sender, DataReceivedEventArgs e)
public void Dispose()
{
this.DisposeFunctionHosts();

try
{
this.AzuriteHost.Kill(true);
this.AzuriteHost.Dispose();
}
catch (Exception e)
{
Console.WriteLine($"Failed to stop Azurite, Error: {e.Message}");
}

try
{
// Drop the test database
using var masterConnection = new SqlConnection(this.MasterConnectionString);
masterConnection.Open();
TestUtils.ExecuteNonQuery(masterConnection, $"DROP DATABASE IF EXISTS {this.DatabaseName}", Console.WriteLine);
}
catch (Exception e4)
{
Console.WriteLine($"Failed to drop {this.DatabaseName}, Error: {e4.Message}");
}
TestUtils.StopAzurite(this.AzuriteHost);
TestUtils.DropDatabase(this.MasterConnectionString, this.DatabaseName);

GC.SuppressFinalize(this);
}
Expand Down