Skip to content

Commit

Permalink
Updates for shared SQL (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonpollett authored Mar 27, 2020
1 parent 271e4f7 commit 4b85f16
Show file tree
Hide file tree
Showing 16 changed files with 347 additions and 8 deletions.
16 changes: 16 additions & 0 deletions Microsoft.Health.sln
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.SqlServer.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.SqlServer.UnitTests", "src\Microsoft.Health.SqlServer.UnitTests\Microsoft.Health.SqlServer.UnitTests.csproj", "{8FEF74DC-94A5-4E20-9BE2-095941935EC4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.SqlServer.Tests.E2E", "test\Microsoft.Health.SqlServer.Tests.E2E\Microsoft.Health.SqlServer.Tests.E2E.csproj", "{C74D5E00-8BE4-4C99-8A59-9D58D255C140}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{CCD9FF99-E177-446E-B9E5-9F570FD96A34}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Health.SqlServer.Web", "test\Microsoft.Health.SqlServer.Web\Microsoft.Health.SqlServer.Web.csproj", "{85781F6A-28D8-4850-A991-51157E5DF46E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -91,6 +97,14 @@ Global
{8FEF74DC-94A5-4E20-9BE2-095941935EC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FEF74DC-94A5-4E20-9BE2-095941935EC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FEF74DC-94A5-4E20-9BE2-095941935EC4}.Release|Any CPU.Build.0 = Release|Any CPU
{C74D5E00-8BE4-4C99-8A59-9D58D255C140}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C74D5E00-8BE4-4C99-8A59-9D58D255C140}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C74D5E00-8BE4-4C99-8A59-9D58D255C140}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C74D5E00-8BE4-4C99-8A59-9D58D255C140}.Release|Any CPU.Build.0 = Release|Any CPU
{85781F6A-28D8-4850-A991-51157E5DF46E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85781F6A-28D8-4850-A991-51157E5DF46E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85781F6A-28D8-4850-A991-51157E5DF46E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85781F6A-28D8-4850-A991-51157E5DF46E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -108,6 +122,8 @@ Global
{561B1075-FA22-4D4E-881B-366230423B2D} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{7650CF08-00B4-419B-8AF9-26E4079F08F2} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{8FEF74DC-94A5-4E20-9BE2-095941935EC4} = {8AD2A324-DAB5-4380-94A5-31F7D817C384}
{C74D5E00-8BE4-4C99-8A59-9D58D255C140} = {CCD9FF99-E177-446E-B9E5-9F570FD96A34}
{85781F6A-28D8-4850-A991-51157E5DF46E} = {CCD9FF99-E177-446E-B9E5-9F570FD96A34}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
RESX_SortFileContentOnSave = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging.Abstractions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context
try
{
using (var connection = new SqlConnection(_configuration.ConnectionString))
using (SqlCommand command = connection.CreateCommand())
{
await connection.OpenAsync(cancellationToken);

SqlCommand command = connection.CreateCommand();
command.CommandText = "select @@DBTS";

await command.ExecuteScalarAsync(cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,9 @@ private void CompleteSchemaVersion(int schemaVersion)
private void UpsertSchemaVersion(int schemaVersion, string status)
{
using (var connection = new SqlConnection(_sqlServerDataStoreConfiguration.ConnectionString))
using (var upsertCommand = new SqlCommand("dbo.UpsertSchemaVersion", connection))
{
var upsertCommand = new SqlCommand("dbo.UpsertSchemaVersion", connection)
{
CommandType = CommandType.StoredProcedure,
};

upsertCommand.CommandType = CommandType.StoredProcedure;
upsertCommand.Parameters.AddWithValue("@version", schemaVersion);
upsertCommand.Parameters.AddWithValue("@status", status);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ public static class SqlErrorCodes
/// </summary>
public const int MethodNotAllowed = CustomErrorCodeBase + 405;

/// <summary>
/// The resource already exists
/// </summary>
public const int Conflict = CustomErrorCodeBase + 409;

/// <summary>
/// An optimistic concurrency precondition failed
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,17 @@ public SqlServerModelInitializer(SqlServerDataStoreConfiguration configuration,
SchemaInformation = schemaInformation;
_logger = logger;

_initializationOperation = new RetryableInitializationOperation(Initialize);
_initializationOperation = new RetryableInitializationOperation(() =>
{
if (!SchemaInformation.Current.HasValue)
{
_logger.LogError($"The current version of the database is not available. Unable in initialize {nameof(SqlServerModelInitializer)}.");
throw new ServiceUnavailableException();
}

return Initialize();
});

if (SchemaInformation.Current != null)
{
// kick off initialization so that it can be ready for requests. Errors will be observed by requests when they call the method.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<RootNamespace>Microsoft.Health.SqlServer.Tests.E2E</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.Health.SqlServer.Api\Microsoft.Health.SqlServer.Api.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Health.SqlServer\Microsoft.Health.SqlServer.csproj" />
<ProjectReference Include="..\Microsoft.Health.SqlServer.Web\Microsoft.Health.SqlServer.Web.csproj" />
</ItemGroup>

</Project>
151 changes: 151 additions & 0 deletions test/Microsoft.Health.SqlServer.Tests.E2E/SchemaTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Health.SqlServer.Web;
using Newtonsoft.Json.Linq;
using Xunit;

namespace Microsoft.Health.SqlServer.Tests.E2E
{
public class SchemaTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
private readonly HttpClient _client;

public SchemaTests(WebApplicationFactory<Startup> factory)
{
_factory = factory;
_client = factory.CreateClient();
}

public static IEnumerable<object[]> Data =>
new List<object[]>
{
new object[] { "_schema/compatibility" },
new object[] { "_schema/versions/current" },
};

[Fact]
public async Task GivenAServerThatHasSchemas_WhenRequestingAvailable_JsonShouldBeReturned()
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_client.BaseAddress, "_schema/versions"),
};

HttpResponseMessage response = await _client.SendAsync(request);

Assert.Equal(HttpStatusCode.OK, response.StatusCode);

var jArrayResponse = JArray.Parse(await response.Content.ReadAsStringAsync());

Assert.NotEmpty(jArrayResponse);

JToken firstResult = jArrayResponse.First;
string scriptUrl = $"/_schema/versions/{firstResult["id"]}/script";
Assert.Equal(scriptUrl, firstResult["script"]);
}

[Theory]
[MemberData(nameof(Data))]
public async Task GivenGetMethod_WhenRequestingSchema_TheServerShouldReturnNotImplemented(string path)
{
await SendAndVerifyStatusCode(HttpMethod.Get, path, HttpStatusCode.NotImplemented);
}

[Theory]
[MemberData(nameof(Data))]
public async Task GivenPostMethod_WhenRequestingSchema_TheServerShouldReturnNotFound(string path)
{
await SendAndVerifyStatusCode(HttpMethod.Post, path, HttpStatusCode.NotFound);
}

[Theory]
[MemberData(nameof(Data))]
public async Task GivenPutMethod_WhenRequestingSchema_TheServerShouldReturnNotFound(string path)
{
await SendAndVerifyStatusCode(HttpMethod.Put, path, HttpStatusCode.NotFound);
}

[Theory]
[MemberData(nameof(Data))]
public async Task GivenDeleteMethod_WhenRequestingSchema_TheServerShouldReturnNotFound(string path)
{
await SendAndVerifyStatusCode(HttpMethod.Delete, path, HttpStatusCode.NotFound);
}

[Fact]
public async Task GivenNonIntegerVersion_WhenRequestingScript_TheServerShouldReturnNotFound()
{
await SendAndVerifyStatusCode(HttpMethod.Get, "_schema/versions/abc/script", HttpStatusCode.NotFound);
}

[Fact]
public async Task GivenPostMethod_WhenRequestingScript_TheServerShouldReturnNotFound()
{
await SendAndVerifyStatusCode(HttpMethod.Post, "_schema/versions/1/script", HttpStatusCode.NotFound);
}

[Fact]
public async Task GivenPutMethod_WhenRequestingScript_TheServerShouldReturnNotFound()
{
await SendAndVerifyStatusCode(HttpMethod.Put, "_schema/versions/1/script", HttpStatusCode.NotFound);
}

[Fact]
public async Task GivenDeleteMethod_WhenRequestingScript_TheServerShouldReturnNotFound()
{
await SendAndVerifyStatusCode(HttpMethod.Delete, "_schema/versions/1/script", HttpStatusCode.NotFound);
}

[Fact]
public async Task GivenSchemaIdFound_WhenRequestingScript_TheServerShouldReturnScript()
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri(_client.BaseAddress, "_schema/versions/1/script"),
};
HttpResponseMessage response = await _client.SendAsync(request);

Assert.Equal(HttpStatusCode.OK, response.StatusCode);

string script = response.Content.ToString();

Assert.NotEmpty(script);
}

[Fact]
public async Task GivenSchemaIdNotFound_WhenRequestingScript_TheServerShouldReturnNotFoundException()
{
await SendAndVerifyStatusCode(HttpMethod.Get, "_schema/versions/0/script", HttpStatusCode.NotFound);
}

private async Task SendAndVerifyStatusCode(HttpMethod httpMethod, string path, HttpStatusCode httpStatusCode)
{
var request = new HttpRequestMessage
{
Method = httpMethod,
RequestUri = new Uri(_client.BaseAddress, path),
};

// Setting the contentType explicitly because POST/PUT/PATCH throws UnsupportedMediaType
using (var content = new StringContent(" ", Encoding.UTF8, "application/json"))
{
request.Content = content;
HttpResponseMessage response = await _client.SendAsync(request);
Assert.Equal(httpStatusCode, response.StatusCode);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

namespace Microsoft.Health.SqlServer.Web.Features.Schema
{
public enum SchemaVersion
{
Version1 = 1,
Version2 = 2,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.Health.SqlServer.Api\Microsoft.Health.SqlServer.Api.csproj" />
<ProjectReference Include="..\..\src\Microsoft.Health.SqlServer\Microsoft.Health.SqlServer.csproj" />
</ItemGroup>

<ItemGroup>
<None Remove="Features\Schema\Migrations\1.sql" />
<EmbeddedResource Include="Features\Schema\Migrations\1.sql" />
</ItemGroup>

<ItemGroup>
<Folder Include="Properties" />
</ItemGroup>
</Project>
22 changes: 22 additions & 0 deletions test/Microsoft.Health.SqlServer.Web/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// -------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// -------------------------------------------------------------------------------------------------

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace Microsoft.Health.SqlServer.Web
{
public static class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}
}
11 changes: 11 additions & 0 deletions test/Microsoft.Health.SqlServer.Web/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"profiles": {
"Microsoft.Health.SqlServer.Web": {
"commandName": "Project",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:63637/"
}
}
}
Loading

0 comments on commit 4b85f16

Please sign in to comment.