From ac769e656b122ff569c3f1534701b71e00fed586 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 27 Oct 2020 19:21:35 +0800 Subject: Split front and back end. --- .../Helpers/AsyncFunctionAssertionsExtensions.cs | 16 -- Timeline.Tests/Helpers/CacheTestHelper.cs | 64 -------- Timeline.Tests/Helpers/HttpClientExtensions.cs | 51 ------ Timeline.Tests/Helpers/HttpResponseExtensions.cs | 35 ----- Timeline.Tests/Helpers/ImageHelper.cs | 26 ---- Timeline.Tests/Helpers/ParameterInfoAssertions.cs | 60 ------- Timeline.Tests/Helpers/ReflectionHelper.cs | 13 -- Timeline.Tests/Helpers/ResponseAssertions.cs | 172 --------------------- Timeline.Tests/Helpers/TestApplication.cs | 72 --------- Timeline.Tests/Helpers/TestClock.cs | 43 ------ Timeline.Tests/Helpers/TestDatabase.cs | 76 --------- 11 files changed, 628 deletions(-) delete mode 100644 Timeline.Tests/Helpers/AsyncFunctionAssertionsExtensions.cs delete mode 100644 Timeline.Tests/Helpers/CacheTestHelper.cs delete mode 100644 Timeline.Tests/Helpers/HttpClientExtensions.cs delete mode 100644 Timeline.Tests/Helpers/HttpResponseExtensions.cs delete mode 100644 Timeline.Tests/Helpers/ImageHelper.cs delete mode 100644 Timeline.Tests/Helpers/ParameterInfoAssertions.cs delete mode 100644 Timeline.Tests/Helpers/ReflectionHelper.cs delete mode 100644 Timeline.Tests/Helpers/ResponseAssertions.cs delete mode 100644 Timeline.Tests/Helpers/TestApplication.cs delete mode 100644 Timeline.Tests/Helpers/TestClock.cs delete mode 100644 Timeline.Tests/Helpers/TestDatabase.cs (limited to 'Timeline.Tests/Helpers') diff --git a/Timeline.Tests/Helpers/AsyncFunctionAssertionsExtensions.cs b/Timeline.Tests/Helpers/AsyncFunctionAssertionsExtensions.cs deleted file mode 100644 index b78309c0..00000000 --- a/Timeline.Tests/Helpers/AsyncFunctionAssertionsExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using FluentAssertions; -using FluentAssertions.Primitives; -using FluentAssertions.Specialized; -using System; -using System.Threading.Tasks; - -namespace Timeline.Tests.Helpers -{ - public static class AsyncFunctionAssertionsExtensions - { - public static async Task> ThrowAsync(this AsyncFunctionAssertions assertions, Type exceptionType, string because = "", params object[] becauseArgs) - { - return (await assertions.ThrowAsync(because, becauseArgs)).Which.Should().BeAssignableTo(exceptionType); - } - } -} diff --git a/Timeline.Tests/Helpers/CacheTestHelper.cs b/Timeline.Tests/Helpers/CacheTestHelper.cs deleted file mode 100644 index b3709a28..00000000 --- a/Timeline.Tests/Helpers/CacheTestHelper.cs +++ /dev/null @@ -1,64 +0,0 @@ -using FluentAssertions; -using System; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading.Tasks; -using Timeline.Models.Http; - -namespace Timeline.Tests.Helpers -{ - public static class CacheTestHelper - { - public static async Task TestCache(HttpClient client, string getUrl) - { - EntityTagHeaderValue eTag; - { - var res = await client.GetAsync(getUrl); - res.Should().HaveStatusCode(200); - var cacheControlHeader = res.Headers.CacheControl; - cacheControlHeader.NoCache.Should().BeTrue(); - cacheControlHeader.NoStore.Should().BeFalse(); - cacheControlHeader.Private.Should().BeTrue(); - cacheControlHeader.Public.Should().BeFalse(); - cacheControlHeader.MustRevalidate.Should().BeTrue(); - cacheControlHeader.MaxAge.Should().NotBeNull().And.Be(TimeSpan.FromDays(14)); - eTag = res.Headers.ETag; - } - - { - using var request = new HttpRequestMessage() - { - RequestUri = new Uri(client.BaseAddress, getUrl), - Method = HttpMethod.Get, - }; - request.Headers.TryAddWithoutValidation("If-None-Match", "\"dsdfd"); - var res = await client.SendAsync(request); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody(ErrorCodes.Common.Header.IfNonMatch_BadFormat); - } - - { - using var request = new HttpRequestMessage() - { - RequestUri = new Uri(client.BaseAddress, getUrl), - Method = HttpMethod.Get, - }; - request.Headers.TryAddWithoutValidation("If-None-Match", "\"aaa\""); - var res = await client.SendAsync(request); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } - - { - using var request = new HttpRequestMessage() - { - RequestUri = new Uri(client.BaseAddress, getUrl), - Method = HttpMethod.Get, - }; - request.Headers.Add("If-None-Match", eTag.ToString()); - var res = await client.SendAsync(request); - res.Should().HaveStatusCode(HttpStatusCode.NotModified); - } - } - } -} diff --git a/Timeline.Tests/Helpers/HttpClientExtensions.cs b/Timeline.Tests/Helpers/HttpClientExtensions.cs deleted file mode 100644 index 6513bbe7..00000000 --- a/Timeline.Tests/Helpers/HttpClientExtensions.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Mime; -using System.Text; -using System.Threading.Tasks; - -namespace Timeline.Tests.Helpers -{ - public static class HttpClientExtensions - { - public static Task PatchAsJsonAsync(this HttpClient client, string url, T body) - { - return client.PatchAsJsonAsync(new Uri(url, UriKind.RelativeOrAbsolute), body); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] - public static Task PatchAsJsonAsync(this HttpClient client, Uri url, T body) - { - return client.PatchAsync(url, new StringContent( - JsonConvert.SerializeObject(body), Encoding.UTF8, MediaTypeNames.Application.Json)); - } - - public static Task PutByteArrayAsync(this HttpClient client, string url, byte[] body, string mimeType) - { - return client.PutByteArrayAsync(new Uri(url, UriKind.RelativeOrAbsolute), body, mimeType); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] - public static Task PutByteArrayAsync(this HttpClient client, Uri url, byte[] body, string mimeType) - { - var content = new ByteArrayContent(body); - content.Headers.ContentLength = body.Length; - content.Headers.ContentType = new MediaTypeHeaderValue(mimeType); - return client.PutAsync(url, content); - } - - public static Task PutStringAsync(this HttpClient client, string url, string body, string mimeType = null) - { - return client.PutStringAsync(new Uri(url, UriKind.RelativeOrAbsolute), body, mimeType); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope")] - public static Task PutStringAsync(this HttpClient client, Uri url, string body, string mimeType = null) - { - var content = new StringContent(body, Encoding.UTF8, mimeType ?? MediaTypeNames.Text.Plain); - return client.PutAsync(url, content); - } - } -} diff --git a/Timeline.Tests/Helpers/HttpResponseExtensions.cs b/Timeline.Tests/Helpers/HttpResponseExtensions.cs deleted file mode 100644 index 2bd497f1..00000000 --- a/Timeline.Tests/Helpers/HttpResponseExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Net.Http; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Timeline.Models.Converters; -using Timeline.Models.Http; - -namespace Timeline.Tests.Helpers -{ - public static class HttpResponseExtensions - { - public static JsonSerializerOptions JsonSerializerOptions { get; } - - static HttpResponseExtensions() - { - JsonSerializerOptions = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); - JsonSerializerOptions.Converters.Add(new JsonDateTimeConverter()); - } - - public static async Task ReadBodyAsJsonAsync(this HttpResponseMessage response) - { - var stream = await response.Content.ReadAsStreamAsync(); - return await JsonSerializer.DeserializeAsync(stream, JsonSerializerOptions); - } - - public static Task ReadBodyAsCommonResponseAsync(this HttpResponseMessage response) - { - return response.ReadBodyAsJsonAsync(); - } - } -} diff --git a/Timeline.Tests/Helpers/ImageHelper.cs b/Timeline.Tests/Helpers/ImageHelper.cs deleted file mode 100644 index 9bed0917..00000000 --- a/Timeline.Tests/Helpers/ImageHelper.cs +++ /dev/null @@ -1,26 +0,0 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.PixelFormats; -using System.IO; - -namespace Timeline.Tests.Helpers -{ - public static class ImageHelper - { - public static byte[] CreatePngWithSize(int width, int height) - { - using var image = new Image(width, height); - using var stream = new MemoryStream(); - image.SaveAsPng(stream); - return stream.ToArray(); - } - - public static byte[] CreateImageWithSize(int width, int height, IImageFormat format) - { - using var image = new Image(width, height); - using var stream = new MemoryStream(); - image.Save(stream, format); - return stream.ToArray(); - } - } -} diff --git a/Timeline.Tests/Helpers/ParameterInfoAssertions.cs b/Timeline.Tests/Helpers/ParameterInfoAssertions.cs deleted file mode 100644 index d3e5a41e..00000000 --- a/Timeline.Tests/Helpers/ParameterInfoAssertions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using FluentAssertions; -using FluentAssertions.Execution; -using FluentAssertions.Formatting; -using FluentAssertions.Primitives; -using System; -using System.Reflection; - -namespace Timeline.Tests.Helpers -{ - public class ParameterInfoValueFormatter : IValueFormatter - { - public bool CanHandle(object value) - { - return value is ParameterInfo; - } - - public string Format(object value, FormattingContext context, FormatChild formatChild) - { - var param = (ParameterInfo)value; - return $"{param.Member.DeclaringType.FullName}.{param.Member.Name}#{param.Name}"; - } - } - - public class ParameterInfoAssertions : ReferenceTypeAssertions - { - static ParameterInfoAssertions() - { - Formatter.AddFormatter(new ParameterInfoValueFormatter()); - } - - public ParameterInfoAssertions(ParameterInfo parameterInfo) - { - Subject = parameterInfo; - } - - protected override string Identifier => "parameter"; - - public AndWhichConstraint BeDecoratedWith(string because = "", params object[] becauseArgs) - where TAttribute : Attribute - { - var attribute = Subject.GetCustomAttribute(false); - - Execute.Assertion - .BecauseOf(because, becauseArgs) - .ForCondition(attribute != null) - .FailWith("Expected {0} {1} to be decorated with {2}{reason}, but that attribute was not found.", - Identifier, Subject, typeof(TAttribute).FullName); - - return new AndWhichConstraint(this, attribute); - } - } - - public static class ParameterInfoAssertionExtensions - { - public static ParameterInfoAssertions Should(this ParameterInfo parameterInfo) - { - return new ParameterInfoAssertions(parameterInfo); - } - } -} diff --git a/Timeline.Tests/Helpers/ReflectionHelper.cs b/Timeline.Tests/Helpers/ReflectionHelper.cs deleted file mode 100644 index 3f6036e3..00000000 --- a/Timeline.Tests/Helpers/ReflectionHelper.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Linq; -using System.Reflection; - -namespace Timeline.Tests.Helpers -{ - public static class ReflectionHelper - { - public static ParameterInfo GetParameter(this MethodInfo methodInfo, string name) - { - return methodInfo.GetParameters().Where(p => p.Name == name).Single(); - } - } -} diff --git a/Timeline.Tests/Helpers/ResponseAssertions.cs b/Timeline.Tests/Helpers/ResponseAssertions.cs deleted file mode 100644 index 024732f5..00000000 --- a/Timeline.Tests/Helpers/ResponseAssertions.cs +++ /dev/null @@ -1,172 +0,0 @@ -using FluentAssertions; -using FluentAssertions.Execution; -using FluentAssertions.Formatting; -using FluentAssertions.Primitives; -using System; -using System.Globalization; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using System.Text.Json.Serialization; -using Timeline.Models.Converters; -using Timeline.Models.Http; - -namespace Timeline.Tests.Helpers -{ - public class HttpResponseMessageValueFormatter : IValueFormatter - { - public bool CanHandle(object value) - { - return value is HttpResponseMessage; - } - - public string Format(object value, FormattingContext context, FormatChild formatChild) - { - string newline = context.UseLineBreaks ? Environment.NewLine : ""; - string padding = new string('\t', context.Depth); - - var res = (HttpResponseMessage)value; - - var builder = new StringBuilder(); - builder.Append($"{newline}{padding} Status Code: {res.StatusCode} ; Body: "); - - try - { - var task = res.Content.ReadAsStringAsync(); - task.Wait(); - var body = task.Result; - if (body.Length > 40) - { - body = body[0..40] + " ..."; - } - builder.Append(body); - } - catch (AggregateException) - { - builder.Append("NOT A STRING."); - } - - return builder.ToString(); - } - } - - public class HttpResponseMessageAssertions - : ReferenceTypeAssertions - { - static HttpResponseMessageAssertions() - { - Formatter.AddFormatter(new HttpResponseMessageValueFormatter()); - } - - public HttpResponseMessageAssertions(HttpResponseMessage instance) - { - Subject = instance; - } - - protected override string Identifier => "HttpResponseMessage"; - - public AndConstraint HaveStatusCode(int expected, string because = "", params object[] becauseArgs) - { - return HaveStatusCode((HttpStatusCode)expected, because, becauseArgs); - } - - public AndConstraint HaveStatusCode(HttpStatusCode expected, string because = "", params object[] becauseArgs) - { - Execute.Assertion.BecauseOf(because, becauseArgs) - .ForCondition(Subject.StatusCode == expected) - .FailWith("Expected status code of {context:HttpResponseMessage} to be {0}{reason}, but found {1}.", expected, Subject.StatusCode); - return new AndConstraint(this); - } - - public AndWhichConstraint HaveJsonBody(string because = "", params object[] becauseArgs) - { - var a = Execute.Assertion.BecauseOf(because, becauseArgs); - string body; - try - { - var task = Subject.Content.ReadAsStringAsync(); - task.Wait(); - body = task.Result; - } - catch (AggregateException e) - { - a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string{reason}, but failed to read it or it was not a string. Exception is {0}.", e.InnerExceptions); - return new AndWhichConstraint(this, null); - } - - - try - { - var options = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - options.Converters.Add(new JsonStringEnumConverter()); - options.Converters.Add(new JsonDateTimeConverter()); - - var result = JsonSerializer.Deserialize(body, options); - - return new AndWhichConstraint(this, result); - } - catch (JsonException e) - { - a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string{reason}, but failed to deserialize it. Exception is {0}.", e); - return new AndWhichConstraint(this, null); - } - } - } - - public static class AssertionResponseExtensions - { - public static HttpResponseMessageAssertions Should(this HttpResponseMessage instance) - { - return new HttpResponseMessageAssertions(instance); - } - - public static AndWhichConstraint HaveCommonBody(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) - { - return assertions.HaveJsonBody(because, becauseArgs); - } - - public static void HaveCommonBody(this HttpResponseMessageAssertions assertions, int code, string message = null, params object[] messageArgs) - { - message = string.IsNullOrEmpty(message) ? "" : ", " + string.Format(CultureInfo.CurrentCulture, message, messageArgs); - var body = assertions.HaveCommonBody("Response body should be CommonResponse{0}", message).Which; - body.Code.Should().Be(code, "Response body code is not the specified one{0}", message); - } - - public static AndWhichConstraint> HaveCommonDataBody(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) - { - return assertions.HaveJsonBody>(because, becauseArgs); - } - - public static void BePut(this HttpResponseMessageAssertions assertions, bool create, string because = "", params object[] becauseArgs) - { - var body = assertions.HaveStatusCode(create ? 201 : 200, because, becauseArgs) - .And.HaveJsonBody(because, becauseArgs) - .Which; - body.Code.Should().Be(0); - body.Data.Create.Should().Be(create); - } - - public static void BeDelete(this HttpResponseMessageAssertions assertions, bool delete, string because = "", params object[] becauseArgs) - { - var body = assertions.HaveStatusCode(200, because, becauseArgs) - .And.HaveJsonBody(because, becauseArgs) - .Which; - body.Code.Should().Be(0); - body.Data.Delete.Should().Be(delete); - } - - public static void BeInvalidModel(this HttpResponseMessageAssertions assertions, string message = null) - { - message = string.IsNullOrEmpty(message) ? "" : ", " + message; - assertions.HaveStatusCode(400, "Invalid Model Error must have 400 status code{0}", message) - .And.HaveCommonBody("Invalid Model Error must have CommonResponse body{0}", message) - .Which.Code.Should().Be(ErrorCodes.Common.InvalidModel, - "Invalid Model Error must have code {0} in body{1}", - ErrorCodes.Common.InvalidModel, message); - } - } -} diff --git a/Timeline.Tests/Helpers/TestApplication.cs b/Timeline.Tests/Helpers/TestApplication.cs deleted file mode 100644 index 684ffe2c..00000000 --- a/Timeline.Tests/Helpers/TestApplication.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.TestHost; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using Timeline.Configs; -using Timeline.Entities; -using Xunit; - -namespace Timeline.Tests.Helpers -{ - public class TestApplication : IAsyncLifetime - { - public TestDatabase Database { get; } - - public IHost Host { get; private set; } - - public string WorkDir { get; private set; } - - public TestApplication() - { - Database = new TestDatabase(false); - } - - public async Task InitializeAsync() - { - await Database.InitializeAsync(); - - WorkDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - Directory.CreateDirectory(WorkDir); - - Host = await Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder() - .ConfigureAppConfiguration((context, config) => - { - config.AddInMemoryCollection(new Dictionary - { - [ApplicationConfiguration.UseMockFrontEndKey] = "true", - ["WorkDir"] = WorkDir - }); - }) - .ConfigureServices(services => - { - services.AddDbContext(options => - { - options.UseSqlite(Database.Connection); - }); - }) - .ConfigureWebHost(webBuilder => - { - webBuilder - .UseTestServer() - .UseStartup(); - }) - .StartAsync(); - } - - public async Task DisposeAsync() - { - await Host.StopAsync(); - Host.Dispose(); - - Directory.Delete(WorkDir, true); - - await Database.DisposeAsync(); - } - } -} diff --git a/Timeline.Tests/Helpers/TestClock.cs b/Timeline.Tests/Helpers/TestClock.cs deleted file mode 100644 index 34adb245..00000000 --- a/Timeline.Tests/Helpers/TestClock.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Timeline.Services; - -namespace Timeline.Tests.Helpers -{ - public class TestClock : IClock - { - private DateTime? _currentTime; - - public DateTime GetCurrentTime() - { - return _currentTime ?? DateTime.UtcNow; - } - - public void SetCurrentTime(DateTime? mockTime) - { - _currentTime = mockTime; - } - - public DateTime SetMockCurrentTime() - { - var time = new DateTime(3000, 1, 1, 1, 1, 1, DateTimeKind.Utc); - _currentTime = time; - return time; - } - - public DateTime ForwardCurrentTime() - { - return ForwardCurrentTime(TimeSpan.FromDays(1)); - } - - public DateTime ForwardCurrentTime(TimeSpan timeSpan) - { - if (_currentTime == null) - return SetMockCurrentTime(); - _currentTime += timeSpan; - return _currentTime.Value; - } - } -} diff --git a/Timeline.Tests/Helpers/TestDatabase.cs b/Timeline.Tests/Helpers/TestDatabase.cs deleted file mode 100644 index f0c26180..00000000 --- a/Timeline.Tests/Helpers/TestDatabase.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging.Abstractions; -using System.Threading.Tasks; -using Timeline.Entities; -using Timeline.Migrations; -using Timeline.Models; -using Timeline.Services; -using Xunit; - -namespace Timeline.Tests.Helpers -{ - public class TestDatabase : IAsyncLifetime - { - private readonly bool _createUser; - - public TestDatabase(bool createUser = true) - { - _createUser = createUser; - Connection = new SqliteConnection("Data Source=:memory:;"); - } - - public async Task InitializeAsync() - { - await Connection.OpenAsync(); - - using (var context = CreateContext()) - { - await context.Database.EnsureCreatedAsync(); - context.JwtToken.Add(new JwtTokenEntity - { - Key = JwtTokenGenerateHelper.GenerateKey() - }); - await context.SaveChangesAsync(); - - if (_createUser) - { - var passwordService = new PasswordService(); - var userService = new UserService(NullLogger.Instance, context, passwordService, new Clock()); - - await userService.CreateUser(new User - { - Username = "admin", - Password = "adminpw", - Administrator = true, - Nickname = "administrator" - }); - - await userService.CreateUser(new User - { - Username = "user", - Password = "userpw", - Administrator = false, - Nickname = "imuser" - }); - } - } - } - - public async Task DisposeAsync() - { - await Connection.CloseAsync(); - await Connection.DisposeAsync(); - } - - public SqliteConnection Connection { get; } - - public DatabaseContext CreateContext() - { - var options = new DbContextOptionsBuilder() - .UseSqlite(Connection).Options; - - return new DatabaseContext(options); - } - } -} -- cgit v1.2.3