Identity/MusicStore/ErrorPage test re-anabling
Fixes #10672 #7925 #10670 Also, moves MusicStore tests to SQLite for better reliability
This commit is contained in:
parent
400835e0b4
commit
173cf1786e
|
|
@ -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<IConfiguration>(new ConfigurationBuilder().Build())
|
||||
.AddDbContext<IdentityDbContext>(o =>
|
||||
.AddDbContext<VerstappenDbContext>(o =>
|
||||
o.UseSqlite(fixture.Connection)
|
||||
.ConfigureWarnings(b => b.Log(CoreEventId.ManyServiceProvidersCreatedWarning)))
|
||||
.AddIdentity<IdentityUser, IdentityRole>(o => o.Stores.MaxLengthForKeys = 128)
|
||||
.AddEntityFrameworkStores<IdentityDbContext>();
|
||||
.AddEntityFrameworkStores<VerstappenDbContext>();
|
||||
|
||||
services.AddLogging();
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
_builder = new ApplicationBuilder(provider);
|
||||
_builder = new ApplicationBuilder(services.BuildServiceProvider());
|
||||
|
||||
using (var scoped = provider.GetRequiredService<IServiceScopeFactory>().CreateScope())
|
||||
using (var db = scoped.ServiceProvider.GetRequiredService<IdentityDbContext>())
|
||||
using (var scope = _builder.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
|
||||
{
|
||||
db.Database.EnsureCreated();
|
||||
scope.ServiceProvider.GetRequiredService<VerstappenDbContext>().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<IdentityUser, IdentityRole, string>
|
||||
{
|
||||
public VerstappenDbContext(DbContextOptions options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[ConditionalFact]
|
||||
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
|
||||
[OSSkipCondition(OperatingSystems.Linux)]
|
||||
[OSSkipCondition(OperatingSystems.MacOSX)]
|
||||
public void EnsureDefaultSchema()
|
||||
{
|
||||
var db = _builder.ApplicationServices.GetRequiredService<IdentityDbContext>();
|
||||
VerifyDefaultSchema(db);
|
||||
using (var scope = _builder.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
|
||||
{
|
||||
var db = scope.ServiceProvider.GetRequiredService<VerstappenDbContext>();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Theory(Skip = "https://github.com/aspnet/AspNetCore/issues/7925")]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task CustomPersonalDataPropertiesAreProtected(bool protect)
|
||||
[Fact]
|
||||
public Task CustomPersonalDataPropertiesCanBeProtected()
|
||||
=> CustomPersonalDataPropertiesAreProtected<ProtectedIdentityDbContext>(true);
|
||||
|
||||
/// <summary>
|
||||
/// Test.
|
||||
/// </summary>
|
||||
/// <returns>Task</returns>
|
||||
[Fact]
|
||||
public Task CustomPersonalDataPropertiesCanBeNotProtected()
|
||||
=> CustomPersonalDataPropertiesAreProtected<UnprotectedIdentityDbContext>(false);
|
||||
|
||||
private async Task CustomPersonalDataPropertiesAreProtected<TContext>(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<CustomUser, IdentityRole>(options =>
|
||||
{
|
||||
options.Stores.ProtectPersonalData = protect;
|
||||
})
|
||||
.AddEntityFrameworkStores<IdentityDbContext<CustomUser>>()
|
||||
.AddEntityFrameworkStores<TContext>()
|
||||
.AddPersonalDataProtection<InkProtector, DefaultKeyRing>();
|
||||
|
||||
var dbOptions = new DbContextOptionsBuilder().UseSqlite(scratch.Connection)
|
||||
.UseApplicationServiceProvider(services.BuildServiceProvider())
|
||||
.Options;
|
||||
var dbContext = new IdentityDbContext<CustomUser>(dbOptions);
|
||||
services.AddSingleton(dbContext);
|
||||
dbContext.Database.EnsureCreated();
|
||||
services.AddDbContext<TContext>(b => b.UseSqlite(connection));
|
||||
|
||||
var sp = services.BuildServiceProvider();
|
||||
var manager = sp.GetService<UserManager<CustomUser>>();
|
||||
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<TContext>();
|
||||
dbContext.Database.EnsureCreated();
|
||||
|
||||
IdentityResultAssert.IsSuccess(await manager.ResetAuthenticatorKeyAsync(user));
|
||||
IdentityResultAssert.IsSuccess(await manager.SetAuthenticationTokenAsync(user, "loginProvider", "token", "value"));
|
||||
var manager = scope.ServiceProvider.GetService<UserManager<CustomUser>>();
|
||||
|
||||
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<CustomUser>
|
||||
{
|
||||
public ProtectedIdentityDbContext(DbContextOptions<ProtectedIdentityDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class UnprotectedIdentityDbContext : IdentityDbContext<CustomUser>
|
||||
{
|
||||
public UnprotectedIdentityDbContext(DbContextOptions<UnprotectedIdentityDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<AppSettings>(Configuration.GetSection("AppSettings"));
|
||||
|
||||
// Add EF services to the services container
|
||||
if (_platform.UseInMemoryStore)
|
||||
{
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseInMemoryDatabase("Scratch"));
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
|
||||
}
|
||||
// Add EF services to the services container
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlite("Data Source=MusicStore.db"));
|
||||
|
||||
// Add Identity services to the services container
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
|
|
|
|||
|
|
@ -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<AppSettings>(Configuration.GetSection("AppSettings"));
|
||||
|
||||
// Add EF services to the services container
|
||||
if (_platform.UseInMemoryStore)
|
||||
{
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseInMemoryDatabase("Scratch"));
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
|
||||
}
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlite("Data Source=MusicStore.db"));
|
||||
|
||||
// Add Identity services to the services container
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
|
|
|
|||
|
|
@ -115,17 +115,18 @@ namespace MusicStore.Models
|
|||
.SumAsync();
|
||||
}
|
||||
|
||||
public Task<decimal> GetTotal()
|
||||
public async Task<decimal> 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)
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@
|
|||
<Reference Include="Microsoft.AspNetCore.Server.IISIntegration" />
|
||||
<Reference Include="Microsoft.AspNetCore.Session" />
|
||||
<Reference Include="Microsoft.AspNetCore.StaticFiles" />
|
||||
<Reference Include="Microsoft.EntityFrameworkCore.InMemory" />
|
||||
<Reference Include="Microsoft.EntityFrameworkCore.SqlServer" />
|
||||
<Reference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||
<Reference Include="Microsoft.Extensions.Configuration.CommandLine" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -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<AppSettings>(Configuration.GetSection("AppSettings"));
|
||||
|
||||
// Add EF services to the services container
|
||||
if (_platform.UseInMemoryStore)
|
||||
{
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseInMemoryDatabase("Scratch"));
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlServer(Configuration[StoreConfig.ConnectionStringKey.Replace("__", ":")]));
|
||||
}
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlite("Data Source=MusicStore.db"));
|
||||
|
||||
// Add Identity services to the services container
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ namespace MusicStore
|
|||
|
||||
// Add EF services to the services container
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
|
||||
options.UseSqlite("Data Source=MusicStore.db"));
|
||||
|
||||
// Add Identity services to the services container
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
|
|
|
|||
|
|
@ -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<AppSettings>(Configuration.GetSection("AppSettings"));
|
||||
|
||||
// Add EF services to the services container
|
||||
if (_platform.UseInMemoryStore)
|
||||
{
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseInMemoryDatabase("Scratch"));
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
|
||||
}
|
||||
services.AddDbContext<MusicStoreContext>(options =>
|
||||
options.UseSqlite("Data Source=MusicStore.db"));
|
||||
|
||||
// Add Identity services to the services container
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
|
|
|
|||
|
|
@ -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<SqliteInMemoryFixture>
|
||||
{
|
||||
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<MusicStoreContext>(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<MusicStoreContext>();
|
||||
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 =>
|
||||
|
|
|
|||
|
|
@ -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<SqliteInMemoryFixture>
|
||||
{
|
||||
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<MusicStoreContext>(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<ILogger<CheckoutController>>());
|
||||
var controller = new CheckoutController(_fixture.ServiceProvider.GetService<ILogger<CheckoutController>>());
|
||||
|
||||
// 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<MusicStoreContext>();
|
||||
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<ILogger<CheckoutController>>());
|
||||
var controller = new CheckoutController(_fixture.ServiceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
|
|
@ -105,17 +93,17 @@ namespace MusicStore.Controllers
|
|||
{
|
||||
// Arrange
|
||||
var context = new DefaultHttpContext();
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var dbContext = _fixture.Context;
|
||||
|
||||
// AddressAndPayment action reads the Promo code from FormCollection.
|
||||
context.Request.Form =
|
||||
new FormCollection(new Dictionary<string, StringValues>());
|
||||
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
var controller = new CheckoutController(_fixture.ServiceProvider.GetService<ILogger<CheckoutController>>());
|
||||
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<string, StringValues>());
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var dbContext = _fixture.Context;
|
||||
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
var controller = new CheckoutController(_fixture.ServiceProvider.GetService<ILogger<CheckoutController>>());
|
||||
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<ILogger<CheckoutController>>());
|
||||
var controller = new CheckoutController(_fixture.ServiceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ModelState.AddModelError("a", "ModelErrorA");
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
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<MusicStoreContext>();
|
||||
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<ILogger<CheckoutController>>());
|
||||
var controller = new CheckoutController(_fixture.ServiceProvider.GetService<ILogger<CheckoutController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
|
|
@ -215,10 +214,9 @@ namespace MusicStore.Controllers
|
|||
{
|
||||
// Arrange
|
||||
var invalidOrderId = 100;
|
||||
var dbContext =
|
||||
_serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var dbContext = _fixture.Context;
|
||||
|
||||
var controller = new CheckoutController(_serviceProvider.GetService<ILogger<CheckoutController>>());
|
||||
var controller = new CheckoutController(_fixture.ServiceProvider.GetService<ILogger<CheckoutController>>());
|
||||
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 =>
|
||||
|
|
|
|||
|
|
@ -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<SqliteInMemoryFixture>
|
||||
{
|
||||
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<MusicStoreContext>(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<MusicStoreContext>();
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -12,22 +12,14 @@ using Xunit;
|
|||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
public class HomeControllerTest
|
||||
public class HomeControllerTest : IClassFixture<SqliteInMemoryFixture>
|
||||
{
|
||||
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<MusicStoreContext>(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<MusicStoreContext>();
|
||||
var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
|
||||
var dbContext = _fixture.Context;
|
||||
var cache = _fixture.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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<ManageControllerTest.Fixture>
|
||||
{
|
||||
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<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddOptions();
|
||||
services
|
||||
.AddMemoryCache()
|
||||
.AddDbContext<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddEntityFrameworkStores<MusicStoreContext>();
|
||||
|
||||
services.AddMvc();
|
||||
services.AddSingleton<IAuthenticationService, NoOpAuth>();
|
||||
services.AddLogging();
|
||||
|
||||
// IHttpContextAccessor is required for SignInManager, and UserManager
|
||||
var context = new DefaultHttpContext();
|
||||
services.AddSingleton<IHttpContextAccessor>(
|
||||
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<Claim> { new Claim(ClaimTypes.NameIdentifier, userId) };
|
||||
|
||||
var userManager = _serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var userManager = _fixture.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
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<SignInManager<ApplicationUser>>();
|
||||
var signInManager = _fixture.ServiceProvider.GetRequiredService<SignInManager<ApplicationUser>>();
|
||||
|
||||
var httpContext = _serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
|
||||
var httpContext = _fixture.ServiceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
|
||||
httpContext.User = new ClaimsPrincipal(new ClaimsIdentity(claims));
|
||||
httpContext.RequestServices = _serviceProvider;
|
||||
httpContext.RequestServices = _fixture.ServiceProvider;
|
||||
|
||||
var schemeProvider = _serviceProvider.GetRequiredService<IAuthenticationSchemeProvider>();
|
||||
var schemeProvider = _fixture.ServiceProvider.GetRequiredService<IAuthenticationSchemeProvider>();
|
||||
|
||||
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<IConfiguration>(new ConfigurationBuilder().Build());
|
||||
services.AddOptions();
|
||||
|
||||
|
||||
services.AddIdentity<ApplicationUser, IdentityRole>()
|
||||
.AddEntityFrameworkStores<MusicStoreContext>();
|
||||
|
||||
services.AddMvc();
|
||||
services.AddSingleton<IAuthenticationService, NoOpAuth>();
|
||||
services.AddLogging();
|
||||
|
||||
|
||||
// IHttpContextAccessor is required for SignInManager, and UserManager
|
||||
var context = new DefaultHttpContext();
|
||||
services.AddSingleton<IHttpContextAccessor>(
|
||||
new HttpContextAccessor()
|
||||
{
|
||||
HttpContext = context,
|
||||
});
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ShoppingCartFixture>
|
||||
public class ShoppingCartTest : IClassFixture<SqliteInMemoryFixture>
|
||||
{
|
||||
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<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
public virtual MusicStoreContext CreateContext()
|
||||
=> _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ShoppingCartControllerTest.Fixture>
|
||||
{
|
||||
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<MusicStoreContext>(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<MusicStoreContext>(),
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
_fixture.Context,
|
||||
_fixture.ServiceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
|
|
@ -71,8 +60,8 @@ namespace MusicStore.Controllers
|
|||
httpContext.Session.SetString("Session", "CartId_A");
|
||||
|
||||
var controller = new ShoppingCartController(
|
||||
_serviceProvider.GetRequiredService<MusicStoreContext>(),
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
_fixture.Context,
|
||||
_fixture.ServiceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
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<MusicStoreContext>();
|
||||
var dbContext = _fixture.Context;
|
||||
var cartItems = CreateTestCartItems(
|
||||
cartId,
|
||||
itemPrice: 10,
|
||||
|
|
@ -108,7 +97,7 @@ namespace MusicStore.Controllers
|
|||
|
||||
var controller = new ShoppingCartController(
|
||||
dbContext,
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
_fixture.ServiceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
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<MusicStoreContext>();
|
||||
var dbContext = _fixture.Context;
|
||||
var albums = CreateTestAlbums(itemPrice: 10);
|
||||
dbContext.AddRange(albums);
|
||||
dbContext.SaveChanges();
|
||||
|
||||
var controller = new ShoppingCartController(
|
||||
dbContext,
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
_fixture.ServiceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
|
|
@ -172,7 +161,7 @@ namespace MusicStore.Controllers
|
|||
httpContext.Session.SetString("Session", cartId);
|
||||
|
||||
// DbContext initialization
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
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<IServiceProvidersFeature>(serviceProviderFeature);
|
||||
|
||||
// AntiForgery initialization
|
||||
serviceProviderFeature.RequestServices = _serviceProvider;
|
||||
serviceProviderFeature.RequestServices = _fixture.ServiceProvider;
|
||||
var antiForgery = serviceProviderFeature.RequestServices.GetRequiredService<IAntiforgery>();
|
||||
var tokens = antiForgery.GetTokens(httpContext);
|
||||
|
||||
|
|
@ -196,7 +185,7 @@ namespace MusicStore.Controllers
|
|||
// Cotroller initialization
|
||||
var controller = new ShoppingCartController(
|
||||
dbContext,
|
||||
_serviceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
_fixture.ServiceProvider.GetService<ILogger<ShoppingCartController>>());
|
||||
controller.ControllerContext.HttpContext = httpContext;
|
||||
|
||||
// Act
|
||||
|
|
@ -207,7 +196,7 @@ namespace MusicStore.Controllers
|
|||
var viewModel = Assert.IsType<ShoppingCartRemoveViewModel>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<MusicStoreContext>(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<MusicStoreContext>();
|
||||
|
||||
public virtual void CreateDatabase()
|
||||
{
|
||||
Dispose();
|
||||
_connection = new SqliteConnection("Data Source=:memory:");
|
||||
_connection.Open();
|
||||
Context.Database.EnsureCreated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,29 +12,21 @@ using Xunit;
|
|||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
public class StoreControllerTest
|
||||
public class StoreControllerTest : IClassFixture<SqliteInMemoryFixture>
|
||||
{
|
||||
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<MusicStoreContext>(b => b.UseInMemoryDatabase("Scratch").UseInternalServiceProvider(efServiceProvider));
|
||||
|
||||
_serviceProvider = services.BuildServiceProvider();
|
||||
_fixture = fixture;
|
||||
_fixture.CreateDatabase();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Index_CreatesViewWithGenres()
|
||||
{
|
||||
// Arrange
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
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<MusicStoreContext>(),
|
||||
_fixture.Context,
|
||||
new TestAppSettings());
|
||||
|
||||
// Act
|
||||
|
|
@ -72,7 +64,7 @@ namespace MusicStore.Controllers
|
|||
// Arrange
|
||||
var genreName = "Genre 1";
|
||||
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
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<MusicStoreContext>(),
|
||||
_fixture.Context,
|
||||
new TestAppSettings());
|
||||
|
||||
// Act
|
||||
var result = await controller.Details(_serviceProvider.GetRequiredService<IMemoryCache>(), albumId);
|
||||
var result = await controller.Details(_fixture.ServiceProvider.GetRequiredService<IMemoryCache>(), albumId);
|
||||
|
||||
// Assert
|
||||
Assert.IsType<NotFoundResult>(result);
|
||||
|
|
@ -113,10 +105,10 @@ namespace MusicStore.Controllers
|
|||
// Arrange
|
||||
var albumId = 1;
|
||||
|
||||
var dbContext = _serviceProvider.GetRequiredService<MusicStoreContext>();
|
||||
var dbContext = _fixture.Context;
|
||||
var genres = CreateTestGenres(numberOfGenres: 3, numberOfAlbums: 3, dbContext: dbContext);
|
||||
|
||||
var cache = _serviceProvider.GetRequiredService<IMemoryCache>();
|
||||
var cache = _fixture.ServiceProvider.GetRequiredService<IMemoryCache>();
|
||||
|
||||
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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue