diff --git a/src/Identity/EntityFrameworkCore/test/EF.Test/MaxKeyLengthSchemaTest.cs b/src/Identity/EntityFrameworkCore/test/EF.Test/MaxKeyLengthSchemaTest.cs index dcc20802f1..55d18b1f8c 100644 --- a/src/Identity/EntityFrameworkCore/test/EF.Test/MaxKeyLengthSchemaTest.cs +++ b/src/Identity/EntityFrameworkCore/test/EF.Test/MaxKeyLengthSchemaTest.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Data.SqlClient; using Microsoft.AspNetCore.Builder.Internal; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Data.Sqlite; @@ -24,59 +23,73 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test services .AddSingleton(new ConfigurationBuilder().Build()) - .AddDbContext(o => + .AddDbContext(o => o.UseSqlite(fixture.Connection) .ConfigureWarnings(b => b.Log(CoreEventId.ManyServiceProvidersCreatedWarning))) .AddIdentity(o => o.Stores.MaxLengthForKeys = 128) - .AddEntityFrameworkStores(); + .AddEntityFrameworkStores(); services.AddLogging(); - var provider = services.BuildServiceProvider(); - _builder = new ApplicationBuilder(provider); + _builder = new ApplicationBuilder(services.BuildServiceProvider()); - using (var scoped = provider.GetRequiredService().CreateScope()) - using (var db = scoped.ServiceProvider.GetRequiredService()) + using (var scope = _builder.ApplicationServices.GetRequiredService().CreateScope()) { - db.Database.EnsureCreated(); + scope.ServiceProvider.GetRequiredService().Database.EnsureCreated(); } } - [ConditionalFact(Skip = "https://github.com/aspnet/AspNetCore/issues/7925")] + // Need a different context type here since EF model is changing by having MaxLengthForKeys + public class VerstappenDbContext : IdentityDbContext + { + public VerstappenDbContext(DbContextOptions options) + : base(options) + { + } + } + + [ConditionalFact] [FrameworkSkipCondition(RuntimeFrameworks.Mono)] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] public void EnsureDefaultSchema() { - var db = _builder.ApplicationServices.GetRequiredService(); - VerifyDefaultSchema(db); + using (var scope = _builder.ApplicationServices.GetRequiredService().CreateScope()) + { + var db = scope.ServiceProvider.GetRequiredService(); + + VerifyDefaultSchema(db); + } } - private static void VerifyDefaultSchema(IdentityDbContext dbContext) + private static void VerifyDefaultSchema(VerstappenDbContext dbContext) { - var sqlConn = dbContext.Database.GetDbConnection(); + var sqlConn = (SqliteConnection)dbContext.Database.GetDbConnection(); - using (var db = new SqliteConnection(sqlConn.ConnectionString)) + try { - db.Open(); - Assert.True(DbUtil.VerifyColumns(db, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp", + sqlConn.Open(); + Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp", "EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled", "LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail")); - Assert.True(DbUtil.VerifyColumns(db, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp")); - Assert.True(DbUtil.VerifyColumns(db, "AspNetUserRoles", "UserId", "RoleId")); - Assert.True(DbUtil.VerifyColumns(db, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue")); - Assert.True(DbUtil.VerifyColumns(db, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName")); - Assert.True(DbUtil.VerifyColumns(db, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value")); + Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp")); + Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserRoles", "UserId", "RoleId")); + Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue")); + Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName")); + Assert.True(DbUtil.VerifyColumns(sqlConn, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value")); Assert.True(DbUtil.VerifyMaxLength(dbContext, "AspNetUsers", 256, "UserName", "Email", "NormalizedUserName", "NormalizedEmail")); Assert.True(DbUtil.VerifyMaxLength(dbContext, "AspNetRoles", 256, "Name", "NormalizedName")); Assert.True(DbUtil.VerifyMaxLength(dbContext, "AspNetUserLogins", 128, "LoginProvider", "ProviderKey")); Assert.True(DbUtil.VerifyMaxLength(dbContext, "AspNetUserTokens", 128, "LoginProvider", "Name")); - DbUtil.VerifyIndex(db, "AspNetRoles", "RoleNameIndex", isUnique: true); - DbUtil.VerifyIndex(db, "AspNetUsers", "UserNameIndex", isUnique: true); - DbUtil.VerifyIndex(db, "AspNetUsers", "EmailIndex"); - db.Close(); + DbUtil.VerifyIndex(sqlConn, "AspNetRoles", "RoleNameIndex", isUnique: true); + DbUtil.VerifyIndex(sqlConn, "AspNetUsers", "UserNameIndex", isUnique: true); + DbUtil.VerifyIndex(sqlConn, "AspNetUsers", "EmailIndex"); + } + finally + { + sqlConn.Close(); } } } diff --git a/src/Identity/EntityFrameworkCore/test/EF.Test/UserStoreEncryptPersonalDataTest.cs b/src/Identity/EntityFrameworkCore/test/EF.Test/UserStoreEncryptPersonalDataTest.cs index bf186561ed..62ec339141 100644 --- a/src/Identity/EntityFrameworkCore/test/EF.Test/UserStoreEncryptPersonalDataTest.cs +++ b/src/Identity/EntityFrameworkCore/test/EF.Test/UserStoreEncryptPersonalDataTest.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Data.Common; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity.Test; +using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -105,10 +106,10 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test public InkProtector() { } public string Unprotect(string keyId, string data) - => "ink"; + => data?.Substring(4); public string Protect(string keyId, string data) - => "ink"; + => "ink:" + data; } private class CustomUser : IdentityUser @@ -133,8 +134,8 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { if (reader.Read()) { - Assert.Equal("Default:ink", reader.GetString(0)); - return reader.GetString(0) == "Default:ink"; + var value = reader.GetString(0); + return value.StartsWith("Default:ink:"); } } } @@ -155,8 +156,8 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test { if (reader.Read()) { - Assert.Equal("Default:ink", reader.GetString(0)); - return reader.GetString(0) == "Default:ink"; + var value = reader.GetString(0); + return value.StartsWith("Default:ink:"); } } } @@ -167,75 +168,103 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test /// Test. /// /// Task - [Theory(Skip = "https://github.com/aspnet/AspNetCore/issues/7925")] - [InlineData(true)] - [InlineData(false)] - public async Task CustomPersonalDataPropertiesAreProtected(bool protect) + [Fact] + public Task CustomPersonalDataPropertiesCanBeProtected() + => CustomPersonalDataPropertiesAreProtected(true); + + /// + /// Test. + /// + /// Task + [Fact] + public Task CustomPersonalDataPropertiesCanBeNotProtected() + => CustomPersonalDataPropertiesAreProtected(false); + + private async Task CustomPersonalDataPropertiesAreProtected(bool protect) + where TContext : DbContext { - using (var scratch = new ScratchDatabaseFixture()) + using (var connection = new SqliteConnection($"DataSource=D{Guid.NewGuid()}.db")) { var services = new ServiceCollection().AddLogging(); services.AddIdentity(options => { options.Stores.ProtectPersonalData = protect; }) - .AddEntityFrameworkStores>() + .AddEntityFrameworkStores() .AddPersonalDataProtection(); - var dbOptions = new DbContextOptionsBuilder().UseSqlite(scratch.Connection) - .UseApplicationServiceProvider(services.BuildServiceProvider()) - .Options; - var dbContext = new IdentityDbContext(dbOptions); - services.AddSingleton(dbContext); - dbContext.Database.EnsureCreated(); + services.AddDbContext(b => b.UseSqlite(connection)); - var sp = services.BuildServiceProvider(); - var manager = sp.GetService>(); + var applicationServiceProvider = services.BuildServiceProvider(); - var guid = Guid.NewGuid().ToString(); - var user = new CustomUser(); - user.Id = guid; - user.UserName = guid; - IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); - user.Email = "test@test.com"; - user.PersonalData1 = "p1"; - user.PersonalData2 = "p2"; - user.NonPersonalData1 = "np1"; - user.NonPersonalData2 = "np2"; - user.SafePersonalData = "safe"; - user.PhoneNumber = "12345678"; - IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user)); + using (var scope = applicationServiceProvider.CreateScope()) + { + var dbContext = scope.ServiceProvider.GetRequiredService(); + dbContext.Database.EnsureCreated(); - IdentityResultAssert.IsSuccess(await manager.ResetAuthenticatorKeyAsync(user)); - IdentityResultAssert.IsSuccess(await manager.SetAuthenticationTokenAsync(user, "loginProvider", "token", "value")); + var manager = scope.ServiceProvider.GetService>(); - var conn = dbContext.Database.GetDbConnection(); - conn.Open(); - if (protect) - { - Assert.True(FindInk(conn, "PhoneNumber", guid)); - Assert.True(FindInk(conn, "Email", guid)); - Assert.True(FindInk(conn, "UserName", guid)); - Assert.True(FindInk(conn, "PersonalData1", guid)); - Assert.True(FindInk(conn, "PersonalData2", guid)); - Assert.True(FindAuthenticatorKeyInk(conn, guid)); - Assert.True(FindTokenInk(conn, guid, "loginProvider", "token")); + var guid = Guid.NewGuid().ToString(); + var user = new CustomUser(); + user.Id = guid; + user.UserName = guid; + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + user.Email = "test@test.com"; + user.PersonalData1 = "p1"; + user.PersonalData2 = "p2"; + user.NonPersonalData1 = "np1"; + user.NonPersonalData2 = "np2"; + user.SafePersonalData = "safe"; + user.PhoneNumber = "12345678"; + IdentityResultAssert.IsSuccess(await manager.UpdateAsync(user)); + + IdentityResultAssert.IsSuccess(await manager.ResetAuthenticatorKeyAsync(user)); + IdentityResultAssert.IsSuccess(await manager.SetAuthenticationTokenAsync(user, "loginProvider", "token", "value")); + + connection.Open(); + if (protect) + { + Assert.True(FindInk(connection, "PhoneNumber", guid)); + Assert.True(FindInk(connection, "Email", guid)); + Assert.True(FindInk(connection, "UserName", guid)); + Assert.True(FindInk(connection, "PersonalData1", guid)); + Assert.True(FindInk(connection, "PersonalData2", guid)); + Assert.True(FindAuthenticatorKeyInk(connection, guid)); + Assert.True(FindTokenInk(connection, guid, "loginProvider", "token")); + } + else + { + Assert.False(FindInk(connection, "PhoneNumber", guid)); + Assert.False(FindInk(connection, "Email", guid)); + Assert.False(FindInk(connection, "UserName", guid)); + Assert.False(FindInk(connection, "PersonalData1", guid)); + Assert.False(FindInk(connection, "PersonalData2", guid)); + Assert.False(FindAuthenticatorKeyInk(connection, guid)); + Assert.False(FindTokenInk(connection, guid, "loginProvider", "token")); + } + + Assert.False(FindInk(connection, "NonPersonalData1", guid)); + Assert.False(FindInk(connection, "NonPersonalData2", guid)); + Assert.False(FindInk(connection, "SafePersonalData", guid)); + + connection.Close(); } - else - { - Assert.False(FindInk(conn, "PhoneNumber", guid)); - Assert.False(FindInk(conn, "Email", guid)); - Assert.False(FindInk(conn, "UserName", guid)); - Assert.False(FindInk(conn, "PersonalData1", guid)); - Assert.False(FindInk(conn, "PersonalData2", guid)); - Assert.False(FindAuthenticatorKeyInk(conn, guid)); - Assert.False(FindTokenInk(conn, guid, "loginProvider", "token")); - } - Assert.False(FindInk(conn, "NonPersonalData1", guid)); - Assert.False(FindInk(conn, "NonPersonalData2", guid)); - Assert.False(FindInk(conn, "SafePersonalData", guid)); + } + } - conn.Close(); + private class ProtectedIdentityDbContext : IdentityDbContext + { + public ProtectedIdentityDbContext(DbContextOptions options) + : base(options) + { + } + } + + private class UnprotectedIdentityDbContext : IdentityDbContext + { + public UnprotectedIdentityDbContext(DbContextOptions options) + : base(options) + { } } diff --git a/src/Identity/EntityFrameworkCore/test/EF.Test/UserStoreTest.cs b/src/Identity/EntityFrameworkCore/test/EF.Test/UserStoreTest.cs index 7703c05996..21a2c34446 100644 --- a/src/Identity/EntityFrameworkCore/test/EF.Test/UserStoreTest.cs +++ b/src/Identity/EntityFrameworkCore/test/EF.Test/UserStoreTest.cs @@ -258,7 +258,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test } } - [ConditionalFact(Skip = "TODO: Fix for new EF. Issue #10670")] + [ConditionalFact] [FrameworkSkipCondition(RuntimeFrameworks.Mono)] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] diff --git a/src/Middleware/Diagnostics/test/FunctionalTests/DatabaseErrorPageSampleTest.cs b/src/Middleware/Diagnostics/test/FunctionalTests/DatabaseErrorPageSampleTest.cs index fb059fa3fa..f985dc7360 100644 --- a/src/Middleware/Diagnostics/test/FunctionalTests/DatabaseErrorPageSampleTest.cs +++ b/src/Middleware/Diagnostics/test/FunctionalTests/DatabaseErrorPageSampleTest.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Diagnostics.FunctionalTests public HttpClient Client { get; } - [ConditionalFact(Skip = "TODO: EF query interception for opening connection. Issue #10672")] + [ConditionalFact] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] public async Task DatabaseErrorPage_ShowsError() diff --git a/src/MusicStore/samples/MusicStore/Controllers/StoreController.cs b/src/MusicStore/samples/MusicStore/Controllers/StoreController.cs index dfa2336fe1..718ce85b76 100644 --- a/src/MusicStore/samples/MusicStore/Controllers/StoreController.cs +++ b/src/MusicStore/samples/MusicStore/Controllers/StoreController.cs @@ -36,7 +36,6 @@ namespace MusicStore.Controllers { // Retrieve Genre genre and its Associated associated Albums albums from database var genreModel = await DbContext.Genres - .Include(g => g.Albums) .Where(g => g.Name == genre) .FirstOrDefaultAsync(); @@ -45,6 +44,8 @@ namespace MusicStore.Controllers return NotFound(); } + await DbContext.Entry(genreModel).Collection(g => g.Albums).LoadAsync(); + return View(genreModel); } @@ -83,4 +84,4 @@ namespace MusicStore.Controllers return View(album); } } -} \ No newline at end of file +} diff --git a/src/MusicStore/samples/MusicStore/ForTesting/Mocks/StartupOpenIdConnectTesting.cs b/src/MusicStore/samples/MusicStore/ForTesting/Mocks/StartupOpenIdConnectTesting.cs index bb066895a9..677d93abdd 100644 --- a/src/MusicStore/samples/MusicStore/ForTesting/Mocks/StartupOpenIdConnectTesting.cs +++ b/src/MusicStore/samples/MusicStore/ForTesting/Mocks/StartupOpenIdConnectTesting.cs @@ -3,16 +3,13 @@ using System.Globalization; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Localization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using MusicStore.Components; using MusicStore.Mocks.Common; @@ -47,16 +44,9 @@ namespace MusicStore services.Configure(Configuration.GetSection("AppSettings")); // Add EF services to the services container - if (_platform.UseInMemoryStore) - { - services.AddDbContext(options => - options.UseInMemoryDatabase("Scratch")); - } - else - { - services.AddDbContext(options => - options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])); - } + // Add EF services to the services container + services.AddDbContext(options => + options.UseSqlite("Data Source=MusicStore.db")); // Add Identity services to the services container services.AddIdentity() diff --git a/src/MusicStore/samples/MusicStore/ForTesting/Mocks/StartupSocialTesting.cs b/src/MusicStore/samples/MusicStore/ForTesting/Mocks/StartupSocialTesting.cs index ba7baefdd2..2bc26bbb51 100644 --- a/src/MusicStore/samples/MusicStore/ForTesting/Mocks/StartupSocialTesting.cs +++ b/src/MusicStore/samples/MusicStore/ForTesting/Mocks/StartupSocialTesting.cs @@ -1,20 +1,15 @@ -using System; using System.Globalization; using Microsoft.AspNetCore.Authentication.OAuth; using Microsoft.AspNetCore.Authentication.Twitter; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Localization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using MusicStore.Components; using MusicStore.Mocks.Common; using MusicStore.Mocks.Facebook; @@ -50,16 +45,8 @@ namespace MusicStore services.Configure(Configuration.GetSection("AppSettings")); // Add EF services to the services container - if (_platform.UseInMemoryStore) - { - services.AddDbContext(options => - options.UseInMemoryDatabase("Scratch")); - } - else - { - services.AddDbContext(options => - options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])); - } + services.AddDbContext(options => + options.UseSqlite("Data Source=MusicStore.db")); // Add Identity services to the services container services.AddIdentity() diff --git a/src/MusicStore/samples/MusicStore/Models/ShoppingCart.cs b/src/MusicStore/samples/MusicStore/Models/ShoppingCart.cs index cdc21eb01d..3f159adb1d 100644 --- a/src/MusicStore/samples/MusicStore/Models/ShoppingCart.cs +++ b/src/MusicStore/samples/MusicStore/Models/ShoppingCart.cs @@ -115,17 +115,18 @@ namespace MusicStore.Models .SumAsync(); } - public Task GetTotal() + public async Task GetTotal() { // Multiply album price by count of that album to get // the current price for each of those albums in the cart // sum all album price totals to get the cart total - return _dbContext + return (await _dbContext .CartItems .Where(c => c.CartId == _shoppingCartId) .Select(c => c.Album.Price * c.Count) - .SumAsync(); + .ToListAsync()) + .Sum(); } public async Task CreateOrder(Order order) diff --git a/src/MusicStore/samples/MusicStore/MusicStore.csproj b/src/MusicStore/samples/MusicStore/MusicStore.csproj index d91f54cd3c..989c42a4a6 100644 --- a/src/MusicStore/samples/MusicStore/MusicStore.csproj +++ b/src/MusicStore/samples/MusicStore/MusicStore.csproj @@ -31,8 +31,7 @@ - - + diff --git a/src/MusicStore/samples/MusicStore/Startup.cs b/src/MusicStore/samples/MusicStore/Startup.cs index faf4a05bae..74aa6931b8 100644 --- a/src/MusicStore/samples/MusicStore/Startup.cs +++ b/src/MusicStore/samples/MusicStore/Startup.cs @@ -3,12 +3,10 @@ using System.Runtime.InteropServices; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Localization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using MusicStore.Components; using MusicStore.Models; @@ -40,16 +38,8 @@ namespace MusicStore services.Configure(Configuration.GetSection("AppSettings")); // Add EF services to the services container - if (_platform.UseInMemoryStore) - { - services.AddDbContext(options => - options.UseInMemoryDatabase("Scratch")); - } - else - { - services.AddDbContext(options => - options.UseSqlServer(Configuration[StoreConfig.ConnectionStringKey.Replace("__", ":")])); - } + services.AddDbContext(options => + options.UseSqlite("Data Source=MusicStore.db")); // Add Identity services to the services container services.AddIdentity() diff --git a/src/MusicStore/samples/MusicStore/StartupNtlmAuthentication.cs b/src/MusicStore/samples/MusicStore/StartupNtlmAuthentication.cs index 5eadf1f8a0..86860af5e5 100644 --- a/src/MusicStore/samples/MusicStore/StartupNtlmAuthentication.cs +++ b/src/MusicStore/samples/MusicStore/StartupNtlmAuthentication.cs @@ -57,7 +57,7 @@ namespace MusicStore // Add EF services to the services container services.AddDbContext(options => - options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])); + options.UseSqlite("Data Source=MusicStore.db")); // Add Identity services to the services container services.AddIdentity() diff --git a/src/MusicStore/samples/MusicStore/StartupOpenIdConnect.cs b/src/MusicStore/samples/MusicStore/StartupOpenIdConnect.cs index 397ca1f011..e44deae3f7 100644 --- a/src/MusicStore/samples/MusicStore/StartupOpenIdConnect.cs +++ b/src/MusicStore/samples/MusicStore/StartupOpenIdConnect.cs @@ -2,12 +2,10 @@ using System.Globalization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Localization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using MusicStore.Components; using MusicStore.Models; @@ -57,16 +55,8 @@ namespace MusicStore services.Configure(Configuration.GetSection("AppSettings")); // Add EF services to the services container - if (_platform.UseInMemoryStore) - { - services.AddDbContext(options => - options.UseInMemoryDatabase("Scratch")); - } - else - { - services.AddDbContext(options => - options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"])); - } + services.AddDbContext(options => + options.UseSqlite("Data Source=MusicStore.db")); // Add Identity services to the services container services.AddIdentity() diff --git a/src/MusicStore/test/MusicStore.Test/CartSummaryComponentTest.cs b/src/MusicStore/test/MusicStore.Test/CartSummaryComponentTest.cs index c5ba830c80..3ab3265b5e 100644 --- a/src/MusicStore/test/MusicStore.Test/CartSummaryComponentTest.cs +++ b/src/MusicStore/test/MusicStore.Test/CartSummaryComponentTest.cs @@ -1,33 +1,22 @@ -using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewComponents; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using MusicStore.Controllers; using MusicStore.Models; using Xunit; namespace MusicStore.Components { - public class CartSummaryComponentTest + public class CartSummaryComponentTest : IClassFixture { - private readonly IServiceProvider _serviceProvider; + private readonly SqliteInMemoryFixture _fixture; - public CartSummaryComponentTest() + public CartSummaryComponentTest(SqliteInMemoryFixture fixture) { - var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); - - var services = new ServiceCollection(); - - services - .AddMemoryCache() - .AddLogging() - .AddDbContext(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider)); - - _serviceProvider = services.BuildServiceProvider(); + _fixture = fixture; + _fixture.CreateDatabase(); } [Fact] @@ -45,7 +34,7 @@ namespace MusicStore.Components viewContext.HttpContext.Session.SetString("Session", cartId); // DbContext initialization - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; PopulateData(dbContext, cartId, albumTitle: "AlbumA", itemCount: 10); // CartSummaryComponent initialization @@ -68,10 +57,20 @@ namespace MusicStore.Components private static void PopulateData(MusicStoreContext context, string cartId, string albumTitle, int itemCount) { - var album = new Album() + var album = new Album { AlbumId = 1, Title = albumTitle, + Artist = new Artist + { + ArtistId = 1, + Name = "Kung Fu Kenny" + }, + Genre = new Genre + { + GenreId = 1, + Name = "Rap" + } }; var cartItems = Enumerable.Range(1, itemCount).Select(n => diff --git a/src/MusicStore/test/MusicStore.Test/CheckoutControllerTest.cs b/src/MusicStore/test/MusicStore.Test/CheckoutControllerTest.cs index e978410877..e93a8943a9 100644 --- a/src/MusicStore/test/MusicStore.Test/CheckoutControllerTest.cs +++ b/src/MusicStore/test/MusicStore.Test/CheckoutControllerTest.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; @@ -15,29 +14,21 @@ using Xunit; namespace MusicStore.Controllers { - public class CheckoutControllerTest + public class CheckoutControllerTest : IClassFixture { - private readonly IServiceProvider _serviceProvider; + private readonly SqliteInMemoryFixture _fixture; - public CheckoutControllerTest() + public CheckoutControllerTest(SqliteInMemoryFixture fixture) { - var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); - - var services = new ServiceCollection(); - - services - .AddMemoryCache() - .AddLogging() - .AddDbContext(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider)); - - _serviceProvider = services.BuildServiceProvider(); + _fixture = fixture; + _fixture.CreateDatabase(); } [Fact] public void AddressAndPayment_ReturnsDefaultView() { // Arrange - var controller = new CheckoutController(_serviceProvider.GetService>()); + var controller = new CheckoutController(_fixture.ServiceProvider.GetService>()); // Act var result = controller.AddressAndPayment(); @@ -54,10 +45,7 @@ namespace MusicStore.Controllers var httpContext = new DefaultHttpContext(); var orderId = 10; - var order = new Order() - { - OrderId = orderId, - }; + var order = CreateOrder(10); // Session initialization var cartId = "CartId_A"; @@ -76,7 +64,7 @@ namespace MusicStore.Controllers httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(claims)); // DbContext initialization - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; var cartItems = CreateTestCartItems( cartId, itemPrice: 10, @@ -85,7 +73,7 @@ namespace MusicStore.Controllers dbContext.AddRange(cartItems); dbContext.SaveChanges(); - var controller = new CheckoutController(_serviceProvider.GetService>()); + var controller = new CheckoutController(_fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = httpContext; // Act @@ -105,17 +93,17 @@ namespace MusicStore.Controllers { // Arrange var context = new DefaultHttpContext(); - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; // AddressAndPayment action reads the Promo code from FormCollection. context.Request.Form = new FormCollection(new Dictionary()); - var controller = new CheckoutController(_serviceProvider.GetService>()); + var controller = new CheckoutController(_fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = context; // Do not need actual data for Order; the Order object will be checked for the reference equality. - var order = new Order(); + var order = CreateOrder(); // Act var result = await controller.AddressAndPayment(dbContext, order, CancellationToken.None); @@ -135,12 +123,12 @@ namespace MusicStore.Controllers var context = new DefaultHttpContext(); context.Request.Form = new FormCollection(new Dictionary()); - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; - var controller = new CheckoutController(_serviceProvider.GetService>()); + var controller = new CheckoutController(_fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = context; - var order = new Order(); + var order = CreateOrder(); // Act var result = await controller.AddressAndPayment(dbContext, order, new CancellationToken(true)); @@ -157,11 +145,11 @@ namespace MusicStore.Controllers public async Task AddressAndPayment_ReturnsOrderIfInvalidOrderModel() { // Arrange - var controller = new CheckoutController(_serviceProvider.GetService>()); + var controller = new CheckoutController(_fixture.ServiceProvider.GetService>()); controller.ModelState.AddModelError("a", "ModelErrorA"); - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; - var order = new Order(); + var order = CreateOrder(); // Act var result = await controller.AddressAndPayment(dbContext, order, CancellationToken.None); @@ -174,6 +162,22 @@ namespace MusicStore.Controllers Assert.Same(order, viewResult.ViewData.Model); } + private Order CreateOrder(int orderId = 100, string userName = "TestUserA") + => new Order + { + OrderId = orderId, + Username = userName, + FirstName = "Macavity", + LastName = "Clark", + Address = "11 Meadow Drive", + City = "Healing", + State = "IA", + PostalCode = "DN37 7RU", + Country = "USK", + Phone = "555 887876", + Email = "mc@sample.com" + }; + [Fact] public async Task Complete_ReturnsOrderIdIfValid() { @@ -187,16 +191,11 @@ namespace MusicStore.Controllers User = new ClaimsPrincipal(new ClaimsIdentity(claims)), }; - var dbContext = - _serviceProvider.GetRequiredService(); - dbContext.Add(new Order() - { - OrderId = orderId, - Username = userName - }); + var dbContext = _fixture.Context; + dbContext.Add(CreateOrder(orderId, userName)); dbContext.SaveChanges(); - var controller = new CheckoutController(_serviceProvider.GetService>()); + var controller = new CheckoutController(_fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = httpContext; // Act @@ -215,10 +214,9 @@ namespace MusicStore.Controllers { // Arrange var invalidOrderId = 100; - var dbContext = - _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; - var controller = new CheckoutController(_serviceProvider.GetService>()); + var controller = new CheckoutController(_fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = new DefaultHttpContext(); // Act @@ -233,10 +231,21 @@ namespace MusicStore.Controllers private static CartItem[] CreateTestCartItems(string cartId, decimal itemPrice, int numberOfItem) { var albums = Enumerable.Range(1, 10).Select(n => - new Album() + new Album { AlbumId = n, Price = itemPrice, + Title = "Greatest Hits", + Artist = new Artist + { + ArtistId = 1, + Name = "Kung Fu Kenny" + }, + Genre = new Genre + { + GenreId = 1, + Name = "Rap" + } }).ToArray(); var cartItems = Enumerable.Range(1, numberOfItem).Select(n => diff --git a/src/MusicStore/test/MusicStore.Test/GenreMenuComponentTest.cs b/src/MusicStore/test/MusicStore.Test/GenreMenuComponentTest.cs index 30ac743ec0..1a7683d83d 100644 --- a/src/MusicStore/test/MusicStore.Test/GenreMenuComponentTest.cs +++ b/src/MusicStore/test/MusicStore.Test/GenreMenuComponentTest.cs @@ -1,38 +1,27 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.ViewComponents; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using MusicStore.Models; using Xunit; namespace MusicStore.Components { - public class GenreMenuComponentTest + public class GenreMenuComponentTest : IClassFixture { - private readonly IServiceProvider _serviceProvider; + private readonly SqliteInMemoryFixture _fixture; - public GenreMenuComponentTest() + public GenreMenuComponentTest(SqliteInMemoryFixture fixture) { - var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); - - var services = new ServiceCollection(); - - services - .AddMemoryCache() - .AddLogging() - .AddDbContext(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider)); - - _serviceProvider = services.BuildServiceProvider(); + _fixture = fixture; + _fixture.CreateDatabase(); } [Fact] public async Task GenreMenuComponent_Returns_NineGenres() { // Arrange - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; var genreMenuComponent = new GenreMenuComponent(dbContext); PopulateData(dbContext); @@ -50,7 +39,7 @@ namespace MusicStore.Components private static void PopulateData(MusicStoreContext context) { - var genres = Enumerable.Range(1, 10).Select(n => new Genre { GenreId = n }); + var genres = Enumerable.Range(1, 10).Select(n => new Genre { GenreId = n, Name = $"G{n}" }); context.AddRange(genres); context.SaveChanges(); diff --git a/src/MusicStore/test/MusicStore.Test/HomeControllerTest.cs b/src/MusicStore/test/MusicStore.Test/HomeControllerTest.cs index 3a12ab8f3a..0197db3c64 100644 --- a/src/MusicStore/test/MusicStore.Test/HomeControllerTest.cs +++ b/src/MusicStore/test/MusicStore.Test/HomeControllerTest.cs @@ -12,22 +12,14 @@ using Xunit; namespace MusicStore.Controllers { - public class HomeControllerTest + public class HomeControllerTest : IClassFixture { - private readonly IServiceProvider _serviceProvider; + private readonly SqliteInMemoryFixture _fixture; - public HomeControllerTest() + public HomeControllerTest(SqliteInMemoryFixture fixture) { - var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); - - var services = new ServiceCollection(); - - services - .AddMemoryCache() - .AddLogging() - .AddDbContext(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider)); - - _serviceProvider = services.BuildServiceProvider(); + _fixture = fixture; + _fixture.CreateDatabase(); } [Fact] @@ -50,8 +42,8 @@ namespace MusicStore.Controllers public async Task Index_GetsSixTopAlbums() { // Arrange - var dbContext = _serviceProvider.GetRequiredService(); - var cache = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; + var cache = _fixture.ServiceProvider.GetRequiredService(); var controller = new HomeController(new TestAppSettings()); PopulateData(dbContext); @@ -116,12 +108,13 @@ namespace MusicStore.Controllers }).ToArray(); var albums = Enumerable.Range(1, 10).Select(n => - new Album() + new Album { Artist = artists[n - 1], ArtistId = n, Genre = generes[n - 1], GenreId = n, + Title = "Greatest Hits", }).ToArray(); return albums; diff --git a/src/MusicStore/test/MusicStore.Test/ManageControllerTest.cs b/src/MusicStore/test/MusicStore.Test/ManageControllerTest.cs index 459f91db33..c6a351ca17 100644 --- a/src/MusicStore/test/MusicStore.Test/ManageControllerTest.cs +++ b/src/MusicStore/test/MusicStore.Test/ManageControllerTest.cs @@ -5,9 +5,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using MusicStore.Models; @@ -15,37 +13,14 @@ using Xunit; namespace MusicStore.Controllers { - public class ManageControllerTest + public class ManageControllerTest : IClassFixture { - private readonly IServiceProvider _serviceProvider; + private readonly Fixture _fixture; - public ManageControllerTest() + public ManageControllerTest(Fixture fixture) { - var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); - - var services = new ServiceCollection(); - services.AddSingleton(new ConfigurationBuilder().Build()); - services.AddOptions(); - services - .AddMemoryCache() - .AddDbContext(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider)); - - services.AddIdentity() - .AddEntityFrameworkStores(); - - services.AddMvc(); - services.AddSingleton(); - services.AddLogging(); - - // IHttpContextAccessor is required for SignInManager, and UserManager - var context = new DefaultHttpContext(); - services.AddSingleton( - new HttpContextAccessor() - { - HttpContext = context, - }); - - _serviceProvider = services.BuildServiceProvider(); + _fixture = fixture; + _fixture.CreateDatabase(); } [Fact] @@ -56,19 +31,19 @@ namespace MusicStore.Controllers var phone = "abcdefg"; var claims = new List { new Claim(ClaimTypes.NameIdentifier, userId) }; - var userManager = _serviceProvider.GetRequiredService>(); + var userManager = _fixture.ServiceProvider.GetRequiredService>(); var userManagerResult = await userManager.CreateAsync( new ApplicationUser { Id = userId, UserName = "Test", TwoFactorEnabled = true, PhoneNumber = phone }, "Pass@word1"); Assert.True(userManagerResult.Succeeded); - var signInManager = _serviceProvider.GetRequiredService>(); + var signInManager = _fixture.ServiceProvider.GetRequiredService>(); - var httpContext = _serviceProvider.GetRequiredService().HttpContext; + var httpContext = _fixture.ServiceProvider.GetRequiredService().HttpContext; httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(claims)); - httpContext.RequestServices = _serviceProvider; + httpContext.RequestServices = _fixture.ServiceProvider; - var schemeProvider = _serviceProvider.GetRequiredService(); + var schemeProvider = _fixture.ServiceProvider.GetRequiredService(); var controller = new ManageController(userManager, signInManager, schemeProvider); controller.ControllerContext.HttpContext = httpContext; @@ -117,5 +92,34 @@ namespace MusicStore.Controllers } } + public class Fixture : SqliteInMemoryFixture + { + public override IServiceCollection ConfigureServices(IServiceCollection services) + { + services = base.ConfigureServices(services); + + services.AddSingleton(new ConfigurationBuilder().Build()); + services.AddOptions(); + + + services.AddIdentity() + .AddEntityFrameworkStores(); + + services.AddMvc(); + services.AddSingleton(); + services.AddLogging(); + + + // IHttpContextAccessor is required for SignInManager, and UserManager + var context = new DefaultHttpContext(); + services.AddSingleton( + new HttpContextAccessor() + { + HttpContext = context, + }); + + return services; + } + } } } diff --git a/src/MusicStore/test/MusicStore.Test/Models/ShoppingCartTest.cs b/src/MusicStore/test/MusicStore.Test/Models/ShoppingCartTest.cs index 58dd56c9a8..918e516f77 100644 --- a/src/MusicStore/test/MusicStore.Test/Models/ShoppingCartTest.cs +++ b/src/MusicStore/test/MusicStore.Test/Models/ShoppingCartTest.cs @@ -3,62 +3,49 @@ using System; using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; using MusicStore.Models; using Xunit; namespace MusicStore.Test { - public class ShoppingCartTest : IClassFixture + public class ShoppingCartTest : IClassFixture { - private readonly ShoppingCartFixture _fixture; + private readonly SqliteInMemoryFixture _fixture; - public ShoppingCartTest(ShoppingCartFixture fixture) + public ShoppingCartTest(SqliteInMemoryFixture fixture) { _fixture = fixture; + _fixture.CreateDatabase(); } [Fact] public async Task ComputesTotal() { var cartId = Guid.NewGuid().ToString(); - using (var db = _fixture.CreateContext()) - { - var a = db.Albums.Add( - new Album + var db = _fixture.Context; + var a = db.Albums.Add( + new Album + { + AlbumId = 1, + Title = "Greatest Hits", + Price = 15.99m, + Artist = new Artist { - Price = 15.99m - }).Entity; + ArtistId = 1, + Name = "Kung Fu Kenny" + }, + Genre = new Genre + { + GenreId = 1, + Name = "Rap" + } + }).Entity; - db.CartItems.Add(new CartItem { Album = a, Count = 2, CartId = cartId }); + db.CartItems.Add(new CartItem { Album = a, Count = 2, CartId = cartId }); - db.SaveChanges(); + db.SaveChanges(); - Assert.Equal(31.98m, await ShoppingCart.GetCart(db, cartId).GetTotal()); - } + Assert.Equal(31.98m, await ShoppingCart.GetCart(db, cartId).GetTotal()); } } - - public class ShoppingCartFixture - { - private readonly IServiceProvider _serviceProvider; - - public ShoppingCartFixture() - { - var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); - - var services = new ServiceCollection(); - - services - .AddMemoryCache() - .AddLogging() - .AddDbContext(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider)); - - _serviceProvider = services.BuildServiceProvider(); - } - - public virtual MusicStoreContext CreateContext() - => _serviceProvider.GetRequiredService(); - } } diff --git a/src/MusicStore/test/MusicStore.Test/ShoppingCartControllerTest.cs b/src/MusicStore/test/MusicStore.Test/ShoppingCartControllerTest.cs index 1306b48475..7e4145b46d 100644 --- a/src/MusicStore/test/MusicStore.Test/ShoppingCartControllerTest.cs +++ b/src/MusicStore/test/MusicStore.Test/ShoppingCartControllerTest.cs @@ -7,10 +7,8 @@ using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.Primitives; using MusicStore.Models; using MusicStore.ViewModels; @@ -18,23 +16,14 @@ using Xunit; namespace MusicStore.Controllers { - public class ShoppingCartControllerTest + public class ShoppingCartControllerTest : IClassFixture { - private readonly IServiceProvider _serviceProvider; + private readonly Fixture _fixture; - public ShoppingCartControllerTest() + public ShoppingCartControllerTest(Fixture fixture) { - var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); - - var services = new ServiceCollection(); - services - .AddMemoryCache() - .AddLogging() - .AddDbContext(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider)); - - services.AddMvc(); - - _serviceProvider = services.BuildServiceProvider(); + _fixture = fixture; + _fixture.CreateDatabase(); } [Fact] @@ -45,8 +34,8 @@ namespace MusicStore.Controllers httpContext.Session = new TestSession(); var controller = new ShoppingCartController( - _serviceProvider.GetRequiredService(), - _serviceProvider.GetService>()); + _fixture.Context, + _fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = httpContext; // Act @@ -71,8 +60,8 @@ namespace MusicStore.Controllers httpContext.Session.SetString("Session", "CartId_A"); var controller = new ShoppingCartController( - _serviceProvider.GetRequiredService(), - _serviceProvider.GetService>()); + _fixture.Context, + _fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = httpContext; // Act @@ -97,7 +86,7 @@ namespace MusicStore.Controllers httpContext.Session = new TestSession(); httpContext.Session.SetString("Session", cartId); - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; var cartItems = CreateTestCartItems( cartId, itemPrice: 10, @@ -108,7 +97,7 @@ namespace MusicStore.Controllers var controller = new ShoppingCartController( dbContext, - _serviceProvider.GetService>()); + _fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = httpContext; // Act @@ -134,14 +123,14 @@ namespace MusicStore.Controllers httpContext.Session.SetString("Session", "CartId_A"); // Creates the albums of AlbumId = 1 ~ 10. - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; var albums = CreateTestAlbums(itemPrice: 10); dbContext.AddRange(albums); dbContext.SaveChanges(); var controller = new ShoppingCartController( dbContext, - _serviceProvider.GetService>()); + _fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = httpContext; // Act @@ -172,7 +161,7 @@ namespace MusicStore.Controllers httpContext.Session.SetString("Session", cartId); // DbContext initialization - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; var cartItems = CreateTestCartItems(cartId, unitPrice, numberOfItem); dbContext.AddRange(cartItems.Select(n => n.Album).Distinct()); dbContext.AddRange(cartItems); @@ -183,7 +172,7 @@ namespace MusicStore.Controllers httpContext.Features.Set(serviceProviderFeature); // AntiForgery initialization - serviceProviderFeature.RequestServices = _serviceProvider; + serviceProviderFeature.RequestServices = _fixture.ServiceProvider; var antiForgery = serviceProviderFeature.RequestServices.GetRequiredService(); var tokens = antiForgery.GetTokens(httpContext); @@ -196,7 +185,7 @@ namespace MusicStore.Controllers // Cotroller initialization var controller = new ShoppingCartController( dbContext, - _serviceProvider.GetService>()); + _fixture.ServiceProvider.GetService>()); controller.ControllerContext.HttpContext = httpContext; // Act @@ -207,7 +196,7 @@ namespace MusicStore.Controllers var viewModel = Assert.IsType(jsonResult.Value); Assert.Equal(numberOfItem - 1, viewModel.CartCount); Assert.Equal((numberOfItem - 1) * 10, viewModel.CartTotal); - Assert.Equal(" has been removed from your shopping cart.", viewModel.Message); + Assert.Equal("Greatest Hits has been removed from your shopping cart.", viewModel.Message); var cart = ShoppingCart.GetCart(dbContext, httpContext); Assert.DoesNotContain((await cart.GetCartItems()), c => c.CartItemId == cartItemId); @@ -232,11 +221,34 @@ namespace MusicStore.Controllers private static Album[] CreateTestAlbums(decimal itemPrice) { return Enumerable.Range(1, 10).Select(n => - new Album() + new Album { + Title = "Greatest Hits", AlbumId = n, Price = itemPrice, + Artist = new Artist + { + ArtistId = 1, + Name = "Kung Fu Kenny" + }, + Genre = new Genre + { + GenreId = 1, + Name = "Rap" + } }).ToArray(); } + + public class Fixture : SqliteInMemoryFixture + { + public override IServiceCollection ConfigureServices(IServiceCollection services) + { + services = base.ConfigureServices(services); + + services.AddMvc(); + + return services; + } + } } } diff --git a/src/MusicStore/test/MusicStore.Test/SqliteInMemoryFixture.cs b/src/MusicStore/test/MusicStore.Test/SqliteInMemoryFixture.cs new file mode 100644 index 0000000000..fb2824cfdf --- /dev/null +++ b/src/MusicStore/test/MusicStore.Test/SqliteInMemoryFixture.cs @@ -0,0 +1,52 @@ +using System; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using MusicStore.Models; + +namespace MusicStore +{ + public class SqliteInMemoryFixture : IDisposable + { + private IServiceScope _serviceScope; + private SqliteConnection _connection; + + public virtual void Dispose() + { + _connection?.Close(); + _connection?.Dispose(); + _serviceScope?.Dispose(); + _serviceScope= null; + } + + public virtual IServiceCollection ConfigureServices(IServiceCollection services) + => services + .AddMemoryCache() + .AddLogging() + .AddDbContext(b => b.UseSqlite(_connection)); + + public virtual IServiceProvider ServiceProvider + { + get + { + if (_serviceScope == null) + { + _serviceScope = ConfigureServices(new ServiceCollection()).BuildServiceProvider().CreateScope(); + } + + return _serviceScope.ServiceProvider; + } + } + + public virtual MusicStoreContext Context + => ServiceProvider.GetRequiredService(); + + public virtual void CreateDatabase() + { + Dispose(); + _connection = new SqliteConnection("Data Source=:memory:"); + _connection.Open(); + Context.Database.EnsureCreated(); + } + } +} diff --git a/src/MusicStore/test/MusicStore.Test/StoreControllerTest.cs b/src/MusicStore/test/MusicStore.Test/StoreControllerTest.cs index e7c278bf12..530930e903 100644 --- a/src/MusicStore/test/MusicStore.Test/StoreControllerTest.cs +++ b/src/MusicStore/test/MusicStore.Test/StoreControllerTest.cs @@ -12,29 +12,21 @@ using Xunit; namespace MusicStore.Controllers { - public class StoreControllerTest + public class StoreControllerTest : IClassFixture { - private readonly IServiceProvider _serviceProvider; + private readonly SqliteInMemoryFixture _fixture; - public StoreControllerTest() + public StoreControllerTest(SqliteInMemoryFixture fixture) { - var efServiceProvider = new ServiceCollection().AddEntityFrameworkInMemoryDatabase().BuildServiceProvider(); - - var services = new ServiceCollection(); - - services - .AddMemoryCache() - .AddLogging() - .AddDbContext(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider)); - - _serviceProvider = services.BuildServiceProvider(); + _fixture = fixture; + _fixture.CreateDatabase(); } [Fact] public async Task Index_CreatesViewWithGenres() { // Arrange - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; CreateTestGenres(numberOfGenres: 10, numberOfAlbums: 1, dbContext: dbContext); var controller = new StoreController(dbContext, new TestAppSettings()); @@ -56,7 +48,7 @@ namespace MusicStore.Controllers { // Arrange var controller = new StoreController( - _serviceProvider.GetRequiredService(), + _fixture.Context, new TestAppSettings()); // Act @@ -72,7 +64,7 @@ namespace MusicStore.Controllers // Arrange var genreName = "Genre 1"; - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, dbContext: dbContext); var controller = new StoreController(dbContext, new TestAppSettings()); @@ -97,11 +89,11 @@ namespace MusicStore.Controllers // Arrange var albumId = int.MinValue; var controller = new StoreController( - _serviceProvider.GetRequiredService(), + _fixture.Context, new TestAppSettings()); // Act - var result = await controller.Details(_serviceProvider.GetRequiredService(), albumId); + var result = await controller.Details(_fixture.ServiceProvider.GetRequiredService(), albumId); // Assert Assert.IsType(result); @@ -113,10 +105,10 @@ namespace MusicStore.Controllers // Arrange var albumId = 1; - var dbContext = _serviceProvider.GetRequiredService(); + var dbContext = _fixture.Context; var genres = CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, dbContext: dbContext); - var cache = _serviceProvider.GetRequiredService(); + var cache = _fixture.ServiceProvider.GetRequiredService(); var controller = new StoreController(dbContext, new TestAppSettings()); @@ -148,31 +140,22 @@ namespace MusicStore.Controllers artist.Name = "Artist1"; var albums = Enumerable.Range(1, numberOfAlbums * numberOfGenres).Select(n => - new Album() + new Album { AlbumId = n, Artist = artist, - ArtistId = artist.ArtistId + ArtistId = artist.ArtistId, + Title = "Greatest Hits", }).ToList(); var generes = Enumerable.Range(1, numberOfGenres).Select(n => - new Genre() + new Genre { Albums = albums.Where(i => i.AlbumId % numberOfGenres == n - 1).ToList(), GenreId = n, Name = "Genre " + n }); - var artis = Enumerable.Range(1, numberOfGenres).Select(n => - new Genre() - { - Albums = albums.Where(i => i.AlbumId % numberOfGenres == n - 1).ToList(), - GenreId = n, - Name = "Genre " + n, - }); - - dbContext.Add(artist); - dbContext.AddRange(albums); dbContext.AddRange(generes); dbContext.SaveChanges();