From 48d53341db4953b3d583dd825b48d854c0a166e9 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 13 Nov 2020 17:08:20 +0800 Subject: ... --- .../Timeline.Tests/IntegratedTests/TimelineTest.cs | 23 +++++++++------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs index ec46b96a..fd574a82 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -55,22 +55,17 @@ namespace Timeline.Tests.IntegratedTests await CreateTestTimelines(); } - private List _testTimelines; - private async Task CreateTestTimelines() { - _testTimelines = new List(); for (int i = 0; i <= 3; i++) { var client = await CreateClientAs(i); var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = $"t{i}" }); - var timelineInfo = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - _testTimelines.Add(timelineInfo); + res.Should().HaveStatusCode(200); } } - private static string CalculateUrlTail(string subpath, ICollection> query) + private static string CalculateUrlTail(string? subpath, ICollection>? query) { StringBuilder result = new StringBuilder(); if (subpath != null) @@ -96,12 +91,12 @@ namespace Timeline.Tests.IntegratedTests return result.ToString(); } - private static string GeneratePersonalTimelineUrl(int id, string subpath = null, ICollection> query = null) + private static string GeneratePersonalTimelineUrl(int id, string? subpath = null, ICollection>? query = null) { return $"timelines/@{(id == 0 ? "admin" : ("user" + id))}{CalculateUrlTail(subpath, query)}"; } - private static string GenerateOrdinaryTimelineUrl(int id, string subpath = null, ICollection> query = null) + private static string GenerateOrdinaryTimelineUrl(int id, string? subpath = null, ICollection>? query = null) { return $"timelines/t{id}{CalculateUrlTail(subpath, query)}"; } @@ -114,12 +109,12 @@ namespace Timeline.Tests.IntegratedTests yield return new[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl) }; } - private static string GeneratePersonalTimelineUrlByName(string name, string subpath = null) + private static string GeneratePersonalTimelineUrlByName(string name, string? subpath = null) { return $"timelines/@{name}{(subpath == null ? "" : "/" + subpath)}"; } - private static string GenerateOrdinaryTimelineUrlByName(string name, string subpath = null) + private static string GenerateOrdinaryTimelineUrlByName(string name, string? subpath = null) { return $"timelines/{name}{(subpath == null ? "" : "/" + subpath)}"; } @@ -136,9 +131,9 @@ namespace Timeline.Tests.IntegratedTests using var client = await CreateDefaultClient(); { var res = await client.GetAsync("timelines/@user1"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Owner.Should().BeEquivalentTo(UserInfos[1]); + var body = await res.Should().HaveStatusCode(200) + .And.HaveAndGetJsonBodyAsync(); + body.Owner.Should().; body.Visibility.Should().Be(TimelineVisibility.Register); body.Description.Should().Be(""); body.Members.Should().NotBeNull().And.BeEmpty(); -- cgit v1.2.3 From 301780410580647b994e13bc2367153569d04634 Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 14 Nov 2020 01:58:38 +0800 Subject: ... --- BackEnd/Timeline.Tests/Helpers/CacheTestHelper.cs | 66 --- .../Timeline.Tests/Helpers/HttpClientExtensions.cs | 36 -- .../Helpers/HttpResponseExtensions.cs | 30 -- .../Timeline.Tests/Helpers/ResponseAssertions.cs | 128 ------ .../IntegratedTests/CacheTestHelper.cs | 66 +++ .../IntegratedTests/CommonJsonSerializeOptions.cs | 21 + .../IntegratedTests/HttpClientExtensions.cs | 48 +++ .../HttpClientTimelineExtensions.cs | 30 ++ .../IntegratedTests/HttpClientUserExtensions.cs | 17 + .../IntegratedTests/HttpResponseExtensions.cs | 14 + .../IntegratedTests/IntegratedTestBase.cs | 9 +- .../IntegratedTests/ResponseAssertions.cs | 136 +++++++ .../Timeline.Tests/IntegratedTests/TimelineTest.cs | 452 +++++---------------- .../IntegratedTests/UserPermissionTest.cs | 64 +-- 14 files changed, 478 insertions(+), 639 deletions(-) delete mode 100644 BackEnd/Timeline.Tests/Helpers/CacheTestHelper.cs delete mode 100644 BackEnd/Timeline.Tests/Helpers/HttpClientExtensions.cs delete mode 100644 BackEnd/Timeline.Tests/Helpers/HttpResponseExtensions.cs delete mode 100644 BackEnd/Timeline.Tests/Helpers/ResponseAssertions.cs create mode 100644 BackEnd/Timeline.Tests/IntegratedTests/CacheTestHelper.cs create mode 100644 BackEnd/Timeline.Tests/IntegratedTests/CommonJsonSerializeOptions.cs create mode 100644 BackEnd/Timeline.Tests/IntegratedTests/HttpClientExtensions.cs create mode 100644 BackEnd/Timeline.Tests/IntegratedTests/HttpClientTimelineExtensions.cs create mode 100644 BackEnd/Timeline.Tests/IntegratedTests/HttpClientUserExtensions.cs create mode 100644 BackEnd/Timeline.Tests/IntegratedTests/HttpResponseExtensions.cs create mode 100644 BackEnd/Timeline.Tests/IntegratedTests/ResponseAssertions.cs (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs') diff --git a/BackEnd/Timeline.Tests/Helpers/CacheTestHelper.cs b/BackEnd/Timeline.Tests/Helpers/CacheTestHelper.cs deleted file mode 100644 index ef230cb0..00000000 --- a/BackEnd/Timeline.Tests/Helpers/CacheTestHelper.cs +++ /dev/null @@ -1,66 +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.Should().NotBeNull(); - 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)); - res.Headers.ETag.Should().NotBeNull(); - 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); - await res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBodyWithCodeAsync(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/BackEnd/Timeline.Tests/Helpers/HttpClientExtensions.cs b/BackEnd/Timeline.Tests/Helpers/HttpClientExtensions.cs deleted file mode 100644 index 47335a22..00000000 --- a/BackEnd/Timeline.Tests/Helpers/HttpClientExtensions.cs +++ /dev/null @@ -1,36 +0,0 @@ -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 PutByteArrayAsync(this HttpClient client, string url, byte[] body, string mimeType) - { - return client.PutByteArrayAsync(new Uri(url, UriKind.RelativeOrAbsolute), body, mimeType); - } - - public static Task PutByteArrayAsync(this HttpClient client, Uri url, byte[] body, string mimeType) - { - using 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); - } - - public static Task PutStringAsync(this HttpClient client, Uri url, string body, string? mimeType = null) - { - using var content = new StringContent(body, Encoding.UTF8, mimeType ?? MediaTypeNames.Text.Plain); - return client.PutAsync(url, content); - } - } -} diff --git a/BackEnd/Timeline.Tests/Helpers/HttpResponseExtensions.cs b/BackEnd/Timeline.Tests/Helpers/HttpResponseExtensions.cs deleted file mode 100644 index 01497434..00000000 --- a/BackEnd/Timeline.Tests/Helpers/HttpResponseExtensions.cs +++ /dev/null @@ -1,30 +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); - } - } -} diff --git a/BackEnd/Timeline.Tests/Helpers/ResponseAssertions.cs b/BackEnd/Timeline.Tests/Helpers/ResponseAssertions.cs deleted file mode 100644 index 95df3eda..00000000 --- a/BackEnd/Timeline.Tests/Helpers/ResponseAssertions.cs +++ /dev/null @@ -1,128 +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.Net.Http.Json; -using System.Text; -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 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; - return $"{newline}{padding} Status Code: {res.StatusCode}"; - } - } - - 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 async Task HaveAndGetJsonBodyAsync(string because = "", params object[] becauseArgs) - { - var a = Execute.Assertion.BecauseOf(because, becauseArgs); - - var body = await Subject.ReadBodyAsJsonAsync(); - if (body == null) - { - a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string of type {0}{reason}, but failed to read it or it was not a valid json string.", typeof(T).FullName); - return default!; - } - return body; - } - } - - public static class AssertionResponseExtensions - { - public static HttpResponseMessageAssertions Should(this HttpResponseMessage instance) - { - return new HttpResponseMessageAssertions(instance); - } - - public static Task HaveAndGetCommonBodyAsync(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) - { - return assertions.HaveAndGetJsonBodyAsync(because, becauseArgs); - } - - public static async Task HaveCommonBodyWithCodeAsync(this HttpResponseMessageAssertions assertions, int code, string? message = null, params object[] messageArgs) - { - message = string.IsNullOrEmpty(message) ? "" : ", " + string.Format(CultureInfo.CurrentCulture, message, messageArgs); - var body = await assertions.HaveAndGetCommonBodyAsync("Response body should be CommonResponse{0}", message); - body.Code.Should().Be(code, "Response body code is not the specified one{0}", message); - } - - public static Task> HaveAndGetCommonDataBodyAsync(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) - { - return assertions.HaveAndGetJsonBodyAsync>(because, becauseArgs); - } - - public static async Task BePutAsync(this HttpResponseMessageAssertions assertions, bool create, string because = "", params object[] becauseArgs) - { - var body = await assertions.HaveStatusCode(create ? 201 : 200, because, becauseArgs) - .And.HaveAndGetJsonBodyAsync(because, becauseArgs); - body.Code.Should().Be(0); - body.Data.Create.Should().Be(create); - } - - public static async Task BeDeleteAsync(this HttpResponseMessageAssertions assertions, bool delete, string because = "", params object[] becauseArgs) - { - var body = await assertions.HaveStatusCode(200, because, becauseArgs) - .And.HaveAndGetJsonBodyAsync(because, becauseArgs); - body.Code.Should().Be(0); - body.Data.Delete.Should().Be(delete); - } - - public static async Task BeInvalidModelAsync(this HttpResponseMessageAssertions assertions, string message = null) - { - message = string.IsNullOrEmpty(message) ? "" : ", " + message; - var body = await assertions.HaveStatusCode(400, "Invalid Model Error must have 400 status code{0}", message) - .And.HaveAndGetCommonBodyAsync("Invalid Model Error must have CommonResponse body{0}", message); - body.Code.Should().Be(ErrorCodes.Common.InvalidModel, - "Invalid Model Error must have code {0} in body{1}", - ErrorCodes.Common.InvalidModel, message); - } - } -} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/CacheTestHelper.cs b/BackEnd/Timeline.Tests/IntegratedTests/CacheTestHelper.cs new file mode 100644 index 00000000..bafb2fcf --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests/CacheTestHelper.cs @@ -0,0 +1,66 @@ +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.IntegratedTests +{ + 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.Should().NotBeNull(); + 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)); + res.Headers.ETag.Should().NotBeNull(); + 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); + await res.Should().HaveStatusCode(HttpStatusCode.BadRequest) + .And.HaveCommonBodyWithCodeAsync(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/BackEnd/Timeline.Tests/IntegratedTests/CommonJsonSerializeOptions.cs b/BackEnd/Timeline.Tests/IntegratedTests/CommonJsonSerializeOptions.cs new file mode 100644 index 00000000..a14c8eef --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests/CommonJsonSerializeOptions.cs @@ -0,0 +1,21 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using Timeline.Models.Converters; + +namespace Timeline.Tests.IntegratedTests +{ + public static class CommonJsonSerializeOptions + { + public static JsonSerializerOptions Options { get; } + + static CommonJsonSerializeOptions() + { + Options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + Options.Converters.Add(new JsonStringEnumConverter()); + Options.Converters.Add(new JsonDateTimeConverter()); + } + } +} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientExtensions.cs new file mode 100644 index 00000000..9258e644 --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientExtensions.cs @@ -0,0 +1,48 @@ +using System; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Net.Mime; +using System.Text; +using System.Threading.Tasks; + +namespace Timeline.Tests.IntegratedTests +{ + public static class HttpClientExtensions + { + public static async Task PatchAsJsonAsync(this HttpClient client, string url, T body) + { + using var reqContent = JsonContent.Create(body, options: CommonJsonSerializeOptions.Options); + return await client.PatchAsync(url, reqContent); + } + + public static Task PutAsync(this HttpClient client, string url) + { + return client.PutAsync(url, null!); + } + + public static Task PutByteArrayAsync(this HttpClient client, string url, byte[] body, string mimeType) + { + return client.PutByteArrayAsync(new Uri(url, UriKind.RelativeOrAbsolute), body, mimeType); + } + + public static async Task PutByteArrayAsync(this HttpClient client, Uri url, byte[] body, string mimeType) + { + using var content = new ByteArrayContent(body); + content.Headers.ContentLength = body.Length; + content.Headers.ContentType = new MediaTypeHeaderValue(mimeType); + return await 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); + } + + public static async Task PutStringAsync(this HttpClient client, Uri url, string body, string? mimeType = null) + { + using var content = new StringContent(body, Encoding.UTF8, mimeType ?? MediaTypeNames.Text.Plain); + return await client.PutAsync(url, content); + } + } +} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTimelineExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTimelineExtensions.cs new file mode 100644 index 00000000..125435f9 --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTimelineExtensions.cs @@ -0,0 +1,30 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Timeline.Models.Http; + +namespace Timeline.Tests.IntegratedTests +{ + public static class HttpClientTimelineExtensions + { + public static async Task GetTimelineAsync(this HttpClient client, string timelineName) + { + var res = await client.GetAsync($"timelines/{timelineName}"); + res.Should().HaveStatusCode(HttpStatusCode.OK); + return await res.Should().HaveAndGetJsonBodyAsync(); + } + + public static async Task PatchTimelineAsync(this HttpClient client, string timelineName, TimelinePatchRequest body) + { + var res = await client.PatchAsJsonAsync($"timelines/{timelineName}", body); + res.Should().HaveStatusCode(HttpStatusCode.OK); + return await res.Should().HaveAndGetJsonBodyAsync(); + } + + public static async Task PutTimelineMemberAsync(this HttpClient client, string timelineName, string memberUsername) + { + var res = await client.PutAsync($"timelines/{timelineName}/members/{memberUsername}"); + res.Should().HaveStatusCode(HttpStatusCode.OK); + } + } +} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientUserExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientUserExtensions.cs new file mode 100644 index 00000000..0ce2325f --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientUserExtensions.cs @@ -0,0 +1,17 @@ +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Timeline.Models.Http; + +namespace Timeline.Tests.IntegratedTests +{ + public static class HttpClientUserExtensions + { + public static async Task GetUserAsync(this HttpClient client, string username) + { + var res = await client.GetAsync($"users/{username}"); + res.Should().HaveStatusCode(HttpStatusCode.OK); + return await res.Should().HaveAndGetJsonBodyAsync(); + } + } +} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseExtensions.cs new file mode 100644 index 00000000..097fefd1 --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseExtensions.cs @@ -0,0 +1,14 @@ +using System.Net.Http; +using System.Net.Http.Json; +using System.Threading.Tasks; + +namespace Timeline.Tests.IntegratedTests +{ + public static class HttpResponseExtensions + { + public static async Task ReadBodyAsJsonAsync(this HttpResponseMessage response) + { + return await response.Content.ReadFromJsonAsync(CommonJsonSerializeOptions.Options); + } + } +} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs b/BackEnd/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs index 79d2d5bf..070b456f 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs @@ -4,10 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; 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; using Timeline.Services; using Timeline.Tests.Helpers; @@ -19,7 +16,7 @@ namespace Timeline.Tests.IntegratedTests { protected TestApplication TestApp { get; } - private readonly int _userCount; + protected int TestUserCount { get; } public IntegratedTestBase() : this(1) { @@ -31,7 +28,7 @@ namespace Timeline.Tests.IntegratedTests if (userCount < 0) throw new ArgumentOutOfRangeException(nameof(userCount), userCount, "User count can't be negative."); - _userCount = userCount; + TestUserCount = userCount; TestApp = new TestApplication(); } @@ -65,7 +62,7 @@ namespace Timeline.Tests.IntegratedTests ("admin", "adminpw", "administrator") }; - for (int i = 1; i <= _userCount; i++) + for (int i = 1; i <= TestUserCount; i++) { users.Add(($"user{i}", $"user{i}pw", $"imuser{i}")); } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/ResponseAssertions.cs b/BackEnd/Timeline.Tests/IntegratedTests/ResponseAssertions.cs new file mode 100644 index 00000000..166cde09 --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests/ResponseAssertions.cs @@ -0,0 +1,136 @@ +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.Threading.Tasks; +using Timeline.Models.Http; + +namespace Timeline.Tests.IntegratedTests +{ + 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; + return $"{newline}{padding} Status Code: {res.StatusCode}"; + } + } + + 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 async Task HaveAndGetJsonBodyAsync(string because = "", params object[] becauseArgs) + { + var a = Execute.Assertion.BecauseOf(because, becauseArgs); + + var body = await Subject.ReadBodyAsJsonAsync(); + if (body == null) + { + a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string of type {0}{reason}, but failed to read it or it was not a valid json string.", typeof(T).FullName); + return default!; + } + return body; + } + + public async Task> HaveJsonBodyAsync(string because = "", params object[] becauseArgs) + { + var a = Execute.Assertion.BecauseOf(because, becauseArgs); + + var body = await Subject.ReadBodyAsJsonAsync(); + if (body == null) + { + a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string of type {0}{reason}, but failed to read it or it was not a valid json string.", typeof(T).FullName); + return new(Subject, null); + } + return new(Subject, body); + } + } + + public static class AssertionResponseExtensions + { + public static HttpResponseMessageAssertions Should(this HttpResponseMessage instance) + { + return new HttpResponseMessageAssertions(instance); + } + + public static Task HaveAndGetCommonBodyAsync(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + return assertions.HaveAndGetJsonBodyAsync(because, becauseArgs); + } + + public static async Task HaveCommonBodyWithCodeAsync(this HttpResponseMessageAssertions assertions, int code, string? message = null, params object[] messageArgs) + { + message = string.IsNullOrEmpty(message) ? "" : ", " + string.Format(CultureInfo.CurrentCulture, message, messageArgs); + var body = await assertions.HaveAndGetCommonBodyAsync("Response body should be CommonResponse{0}", message); + body.Code.Should().Be(code, "Response body code is not the specified one{0}", message); + } + + public static Task> HaveAndGetCommonDataBodyAsync(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) + { + return assertions.HaveAndGetJsonBodyAsync>(because, becauseArgs); + } + + public static async Task BePutAsync(this HttpResponseMessageAssertions assertions, bool create, string because = "", params object[] becauseArgs) + { + var body = await assertions.HaveStatusCode(create ? 201 : 200, because, becauseArgs) + .And.HaveAndGetJsonBodyAsync(because, becauseArgs); + body.Code.Should().Be(0); + body.Data.Create.Should().Be(create); + } + + public static async Task BeDeleteAsync(this HttpResponseMessageAssertions assertions, bool delete, string because = "", params object[] becauseArgs) + { + var body = await assertions.HaveStatusCode(200, because, becauseArgs) + .And.HaveAndGetJsonBodyAsync(because, becauseArgs); + body.Code.Should().Be(0); + body.Data.Delete.Should().Be(delete); + } + + public static async Task BeInvalidModelAsync(this HttpResponseMessageAssertions assertions, string? message = null) + { + message = string.IsNullOrEmpty(message) ? "" : ", " + message; + var body = await assertions.HaveStatusCode(400, "Invalid Model Error must have 400 status code{0}", message) + .And.HaveAndGetCommonBodyAsync("Invalid Model Error must have CommonResponse body{0}", message); + body.Code.Should().Be(ErrorCodes.Common.InvalidModel, + "Invalid Model Error must have code {0} in body{1}", + ErrorCodes.Common.InvalidModel, message); + } + } +} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs index fd574a82..e996be45 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -9,12 +9,13 @@ using System.Globalization; using System.Linq; using System.Net; using System.Net.Http; -using System.Text; +using System.Net.Http.Json; using System.Threading.Tasks; using Timeline.Entities; using Timeline.Models; using Timeline.Models.Http; using Timeline.Tests.Helpers; +using Timeline.Tests.IntegratedTests; using Xunit; namespace Timeline.Tests.IntegratedTests @@ -59,81 +60,32 @@ namespace Timeline.Tests.IntegratedTests { for (int i = 0; i <= 3; i++) { - var client = await CreateClientAs(i); + using var client = await CreateClientAs(i); var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = $"t{i}" }); res.Should().HaveStatusCode(200); } } - private static string CalculateUrlTail(string? subpath, ICollection>? query) + [Fact] + public async Task TimelineGet_Should_Work() { - StringBuilder result = new StringBuilder(); - if (subpath != null) + using var client = await CreateDefaultClient(); + { - if (!subpath.StartsWith("/", StringComparison.OrdinalIgnoreCase)) - result.Append('/'); - result.Append(subpath); + var res = await client.GetAsync("timelines/@!!!"); + await res.Should().BeInvalidModelAsync(); } - if (query != null && query.Count != 0) { - result.Append('?'); - foreach (var (key, value, index) in query.Select((pair, index) => (pair.Key, pair.Value, index))) - { - result.Append(WebUtility.UrlEncode(key)); - result.Append('='); - result.Append(WebUtility.UrlEncode(value)); - if (index != query.Count - 1) - result.Append('&'); - } + var res = await client.GetAsync("timelines/!!!"); + await res.Should().BeInvalidModelAsync(); } - return result.ToString(); - } - - private static string GeneratePersonalTimelineUrl(int id, string? subpath = null, ICollection>? query = null) - { - return $"timelines/@{(id == 0 ? "admin" : ("user" + id))}{CalculateUrlTail(subpath, query)}"; - } - - private static string GenerateOrdinaryTimelineUrl(int id, string? subpath = null, ICollection>? query = null) - { - return $"timelines/t{id}{CalculateUrlTail(subpath, query)}"; - } - - public delegate string TimelineUrlGenerator(int userId, string subpath = null, ICollection> query = null); - - public static IEnumerable TimelineUrlGeneratorData() - { - yield return new[] { new TimelineUrlGenerator(GeneratePersonalTimelineUrl) }; - yield return new[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl) }; - } - - private static string GeneratePersonalTimelineUrlByName(string name, string? subpath = null) - { - return $"timelines/@{name}{(subpath == null ? "" : "/" + subpath)}"; - } - - private static string GenerateOrdinaryTimelineUrlByName(string name, string? subpath = null) - { - return $"timelines/{name}{(subpath == null ? "" : "/" + subpath)}"; - } - - public static IEnumerable TimelineUrlByNameGeneratorData() - { - yield return new[] { new Func(GeneratePersonalTimelineUrlByName) }; - yield return new[] { new Func(GenerateOrdinaryTimelineUrlByName) }; - } - - [Fact] - public async Task TimelineGet_Should_Work() - { - using var client = await CreateDefaultClient(); { var res = await client.GetAsync("timelines/@user1"); var body = await res.Should().HaveStatusCode(200) .And.HaveAndGetJsonBodyAsync(); - body.Owner.Should().; + body.Owner.Should().BeEquivalentTo(await client.GetUserAsync("user1")); body.Visibility.Should().Be(TimelineVisibility.Register); body.Description.Should().Be(""); body.Members.Should().NotBeNull().And.BeEmpty(); @@ -145,9 +97,9 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.GetAsync("timelines/t1"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Owner.Should().BeEquivalentTo(UserInfos[1]); + var body = await res.Should().HaveStatusCode(200) + .And.HaveAndGetJsonBodyAsync(); + body.Owner.Should().BeEquivalentTo(await client.GetUserAsync("user1")); body.Visibility.Should().Be(TimelineVisibility.Register); body.Description.Should().Be(""); body.Members.Should().NotBeNull().And.BeEmpty(); @@ -159,33 +111,45 @@ namespace Timeline.Tests.IntegratedTests } [Fact] - public async Task TimelineList() + public async Task TimelineList_Should_Work() { - TimelineInfo user1Timeline; + using var client = await CreateDefaultClient(); - var client = await CreateDefaultClient(); + var result = new List + { + await client.GetTimelineAsync("@user1") + }; + for (int i = 0; i <= TestUserCount; i++) { - var res = await client.GetAsync("timelines/@user1"); - user1Timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + result.Add(await client.GetTimelineAsync($"t{i}")); } - { - var testResult = new List(); - testResult.Add(user1Timeline); - testResult.AddRange(_testTimelines); - var res = await client.GetAsync("timelines"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which.Should().BeEquivalentTo(testResult); - } + var res = await client.GetAsync("timelines"); + var body = res.Should().HaveStatusCode(200) + .And.HaveAndGetJsonBodyAsync>(); + + body.Should().BeEquivalentTo(result); } [Fact] - public async Task TimelineList_WithQuery() + public async Task TimelineListWithQuery_Should_Work() { + { + using var client = await CreateDefaultClient(); + + async Task TestAgainst(string url) + { + var res = await client.GetAsync(url); + await res.Should().BeInvalidModelAsync(); + } + + await TestAgainst("timelines?relate=us!!"); + await TestAgainst("timelines?relateType=aaa"); + await TestAgainst("timelines?visibility=aaa"); + } + var testResultRelate = new List(); var testResultOwn = new List(); var testResultJoin = new List(); @@ -196,32 +160,15 @@ namespace Timeline.Tests.IntegratedTests var testResultPublic = new List(); { - var client = await CreateClientAsUser(); - - { - var res = await client.PutAsync("timelines/@user1/members/user3", null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PutAsync("timelines/t1/members/user3", null); - res.Should().HaveStatusCode(200); - } + using var client = await CreateClientAsUser(); - { - var res = await client.PatchAsJsonAsync("timelines/@user1", new TimelinePatchRequest { Visibility = TimelineVisibility.Public }); - res.Should().HaveStatusCode(200); - } + await client.PutTimelineMemberAsync("@user1", "user3"); + await client.PutTimelineMemberAsync("t1", "user3"); + await client.PatchTimelineAsync("@user1", new() { Visibility = TimelineVisibility.Public }); + await client.PatchTimelineAsync("t1", new() { Visibility = TimelineVisibility.Register }); { - var res = await client.PatchAsJsonAsync("timelines/t1", new TimelinePatchRequest { Visibility = TimelineVisibility.Register }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.GetAsync("timelines/@user1"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + var timeline = await client.GetTimelineAsync("@user1"); testResultRelate.Add(timeline); testResultJoin.Add(timeline); testResultRelatePublic.Add(timeline); @@ -229,9 +176,7 @@ namespace Timeline.Tests.IntegratedTests } { - var res = await client.GetAsync("timelines/t1"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + var timeline = await client.GetTimelineAsync("t1"); testResultRelate.Add(timeline); testResultJoin.Add(timeline); testResultRelateRegister.Add(timeline); @@ -239,41 +184,22 @@ namespace Timeline.Tests.IntegratedTests } { - var client = await CreateClientAs(2); - - { - var res = await client.PutAsync("timelines/@user2/members/user3", null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PutAsync("timelines/t2/members/user3", null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PatchAsJsonAsync("timelines/@user2", new TimelinePatchRequest { Visibility = TimelineVisibility.Register }); - res.Should().HaveStatusCode(200); - } + using var client = await CreateClientAs(2); - { - var res = await client.PatchAsJsonAsync("timelines/t2", new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } + await client.PutTimelineMemberAsync("@user2", "user3"); + await client.PutTimelineMemberAsync("t2", "user3"); + await client.PatchTimelineAsync("@user2", new() { Visibility = TimelineVisibility.Register }); + await client.PatchTimelineAsync("t2", new() { Visibility = TimelineVisibility.Private }); { - var res = await client.GetAsync("timelines/@user2"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + var timeline = await client.GetTimelineAsync("@user2"); testResultRelate.Add(timeline); testResultJoin.Add(timeline); testResultRelateRegister.Add(timeline); } { - var res = await client.GetAsync("timelines/t2"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + var timeline = await client.GetTimelineAsync("t2"); testResultRelate.Add(timeline); testResultJoin.Add(timeline); testResultJoinPrivate.Add(timeline); @@ -281,31 +207,19 @@ namespace Timeline.Tests.IntegratedTests } { - var client = await CreateClientAs(3); - - { - var res = await client.PatchAsJsonAsync("timelines/@user3", new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.PatchAsJsonAsync("timelines/t3", new TimelinePatchRequest { Visibility = TimelineVisibility.Register }); - res.Should().HaveStatusCode(200); - } + using var client = await CreateClientAs(3); + await client.PatchTimelineAsync("@user3", new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); + await client.PatchTimelineAsync("t3", new TimelinePatchRequest { Visibility = TimelineVisibility.Register }); { - var res = await client.GetAsync("timelines/@user3"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + var timeline = await client.GetTimelineAsync("@user3"); testResultRelate.Add(timeline); testResultOwn.Add(timeline); testResultOwnPrivate.Add(timeline); } { - var res = await client.GetAsync("timelines/t3"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + var timeline = await client.GetTimelineAsync("t3"); testResultRelate.Add(timeline); testResultOwn.Add(timeline); testResultRelateRegister.Add(timeline); @@ -313,86 +227,23 @@ namespace Timeline.Tests.IntegratedTests } { - var client = await CreateClientAs(3); - { - var res = await client.GetAsync("timelines?relate=user3"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultRelate); - } - - { - var res = await client.GetAsync("timelines?relate=user3&relateType=own"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultOwn); - } - - { - var res = await client.GetAsync("timelines?relate=user3&visibility=public"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultRelatePublic); - } - - { - var res = await client.GetAsync("timelines?relate=user3&visibility=register"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultRelateRegister); - } + using var client = await CreateDefaultClient(); + async Task TestAgainst(string url, List against) { - var res = await client.GetAsync("timelines?relate=user3&relateType=join&visibility=private"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultJoinPrivate); + var res = await client.GetAsync(url); + var body = await res.Should().HaveStatusCode(200) + .And.HaveAndGetJsonBodyAsync>(); + body.Should().BeEquivalentTo(against); } - { - var res = await client.GetAsync("timelines?relate=user3&relateType=own&visibility=private"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultOwnPrivate); - } - } - - { - var client = await CreateDefaultClient(); - { - var res = await client.GetAsync("timelines?visibility=public"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - body.Should().BeEquivalentTo(testResultPublic); - } - } - } - - [Fact] - public async Task TimelineList_InvalidModel() - { - var client = await CreateClientAsUser(); - - { - var res = await client.GetAsync("timelines?relate=us!!"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.GetAsync("timelines?relateType=aaa"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.GetAsync("timelines?visibility=aaa"); - res.Should().BeInvalidModel(); + await TestAgainst("timelines?relate=user3", testResultRelate); + await TestAgainst("timelines?relate=user3&relateType=own", testResultOwn); + await TestAgainst("timelines?relate=user3&visibility=public", testResultRelatePublic); + await TestAgainst("timelines?relate=user3&visibility=register", testResultRelateRegister); + await TestAgainst("timelines?relate=user3&relateType=join&visibility=private", testResultJoinPrivate); + await TestAgainst("timelines?relate=user3&relateType=own&visibility=private", testResultOwnPrivate); + await TestAgainst("timelines?visibility=public", testResultPublic); } } @@ -405,31 +256,25 @@ namespace Timeline.Tests.IntegratedTests res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); } - using (var client = await CreateClientAsUser()) { + using var client = await CreateClientAsUser(); + { var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "!!!" }); - res.Should().BeInvalidModel(); + await res.Should().BeInvalidModelAsync(); } - TimelineInfo timelineInfo; { var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - timelineInfo = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - } - - { - var res = await client.GetAsync("timelines/aaa"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(timelineInfo); + var body = await res.Should().HaveStatusCode(200) + .And.HaveAndGetJsonBodyAsync(); + body.Should().BeEquivalentTo(await client.GetTimelineAsync("aaa")); } { var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.TimelineController.NameConflict); + await res.Should().HaveStatusCode(400) + .And.HaveCommonBodyWithCodeAsync(ErrorCodes.TimelineController.NameConflict); } } } @@ -454,17 +299,17 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.DeleteAsync("timelines/!!!"); - res.Should().BeInvalidModel(); + await res.Should().BeInvalidModelAsync(); } { var res = await client.DeleteAsync("timelines/t2"); - res.Should().BeDelete(true); + await res.Should().BeDeleteAsync(true); } { var res = await client.DeleteAsync("timelines/t2"); - res.Should().BeDelete(false); + await res.Should().BeDeleteAsync(false); } } @@ -473,12 +318,12 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.DeleteAsync("timelines/!!!"); - res.Should().BeInvalidModel(); + await res.Should().BeInvalidModelAsync(); } { var res = await client.DeleteAsync("timelines/t1"); - res.Should().BeDelete(true); + await res.Should().BeDeleteAsync(true); } { @@ -489,122 +334,47 @@ namespace Timeline.Tests.IntegratedTests } [Theory] - [MemberData(nameof(TimelineUrlByNameGeneratorData))] - public async Task InvalidModel_BadName(Func generator) + [InlineData("@user1")] + [InlineData("t1")] + public async Task TimelineDescription_Should_Work(string timelineName) { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.GetAsync(generator("aaa!!!", null)); - res.Should().BeInvalidModel(); - } - { - var res = await client.PatchAsJsonAsync(generator("aaa!!!", null), new TimelinePatchRequest { }); - res.Should().BeInvalidModel(); - } - { - var res = await client.PutAsync(generator("aaa!!!", "members/user1"), null); - res.Should().BeInvalidModel(); - } - { - var res = await client.DeleteAsync(generator("aaa!!!", "members/user1")); - res.Should().BeInvalidModel(); - } - { - var res = await client.GetAsync(generator("aaa!!!", "posts")); - res.Should().BeInvalidModel(); - } - { - var res = await client.PostAsJsonAsync(generator("aaa!!!", "posts"), TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().BeInvalidModel(); - } - { - var res = await client.DeleteAsync(generator("aaa!!!", "posts/123")); - res.Should().BeInvalidModel(); - } + using var client = await CreateClientAsUser(); + { - var res = await client.GetAsync(generator("aaa!!!", "posts/123/data")); - res.Should().BeInvalidModel(); + var timeline = await client.GetTimelineAsync(timelineName); + timeline.Description.Should().BeEmpty(); } - } - [Theory] - [MemberData(nameof(TimelineUrlByNameGeneratorData))] - public async Task Ordinary_NotFound(Func generator) - { - var errorCode = generator == GenerateOrdinaryTimelineUrlByName ? ErrorCodes.TimelineController.NotExist : ErrorCodes.UserCommon.NotExist; + const string mockDescription = "haha"; - using var client = await CreateClientAsAdministrator(); - { - var res = await client.GetAsync(generator("notexist", null)); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); - } { - var res = await client.PatchAsJsonAsync(generator("notexist", null), new TimelinePatchRequest { }); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.PutAsync(generator("notexist", "members/user1"), null); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.DeleteAsync(generator("notexist", "members/user1")); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.GetAsync(generator("notexist", "posts")); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); - } - { - var res = await client.PostAsJsonAsync(generator("notexist", "posts"), TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); - } - { - var res = await client.DeleteAsync(generator("notexist", "posts/123")); - res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); + var timeline = await client.PatchTimelineAsync(timelineName, new() { Description = mockDescription }); + timeline.Description.Should().Be(mockDescription); } + { - var res = await client.GetAsync(generator("notexist", "posts/123/data")); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); + var timeline = await client.GetTimelineAsync(timelineName); + timeline.Description.Should().Be(mockDescription); } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Description_Should_Work(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - async Task AssertDescription(string description) { - var res = await client.GetAsync(generator(1, null)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Description.Should().Be(description); + var timeline = await client.PatchTimelineAsync(timelineName, new() { Description = null }); + timeline.Description.Should().Be(mockDescription); } - const string mockDescription = "haha"; - - await AssertDescription(""); { - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Description = mockDescription }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Description.Should().Be(mockDescription); - await AssertDescription(mockDescription); + var timeline = await client.GetTimelineAsync(timelineName); + timeline.Description.Should().Be(mockDescription); } + { - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Description = null }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Description.Should().Be(mockDescription); - await AssertDescription(mockDescription); + var timeline = await client.PatchTimelineAsync(timelineName, new() { Description = "" }); + timeline.Description.Should().BeEmpty(); } + { - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Description = "" }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Description.Should().Be(""); - await AssertDescription(""); + var timeline = await client.GetTimelineAsync(timelineName); + timeline.Description.Should().BeEmpty(); } } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs index cf27a6c6..80f31be9 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs @@ -3,10 +3,10 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; -using System.Net.Http.Json; using System.Threading.Tasks; using Timeline.Models.Http; using Timeline.Services; +using Timeline.Tests.Helpers; using Xunit; namespace Timeline.Tests.IntegratedTests @@ -21,7 +21,7 @@ namespace Timeline.Tests.IntegratedTests using var client = await CreateDefaultClient(); var res = await client.GetAsync("users/admin"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(Enum.GetNames()); } @@ -31,7 +31,7 @@ namespace Timeline.Tests.IntegratedTests using var client = await CreateDefaultClient(); var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEmpty(); } @@ -54,19 +54,19 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.GetAsync("users/admin"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(Enum.GetNames()); } { - var res = await client.PutAsync($"users/admin/permissions/{permission}", null); + var res = await client.PutAsync($"users/admin/permissions/{permission}"); res.StatusCode.Should().Be(HttpStatusCode.OK); } { var res = await client.GetAsync("users/admin"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(Enum.GetNames()); } } @@ -78,14 +78,14 @@ namespace Timeline.Tests.IntegratedTests using var client = await CreateClientAsAdministrator(); { - var res = await client.PutAsync($"users/user1/permissions/{permission}", null); + var res = await client.PutAsync($"users/user1/permissions/{permission}"); res.StatusCode.Should().Be(HttpStatusCode.OK); } { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(permission.ToString()); } @@ -97,7 +97,7 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEmpty(); } } @@ -109,26 +109,26 @@ namespace Timeline.Tests.IntegratedTests using var client = await CreateClientAsAdministrator(); { - var res = await client.PutAsync($"users/user1/permissions/{permission}", null); + var res = await client.PutAsync($"users/user1/permissions/{permission}"); res.StatusCode.Should().Be(HttpStatusCode.OK); } { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(permission.ToString()); } { - var res = await client.PutAsync($"users/user1/permissions/{permission}", null); + var res = await client.PutAsync($"users/user1/permissions/{permission}"); res.StatusCode.Should().Be(HttpStatusCode.OK); } { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(permission.ToString()); } } @@ -147,7 +147,7 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEmpty(); } } @@ -158,39 +158,39 @@ namespace Timeline.Tests.IntegratedTests using var client = await CreateClientAsAdministrator(); { - var res = await client.PutAsync($"users/user1/permissions/{UserPermission.AllTimelineManagement}", null); + var res = await client.PutAsync($"users/user1/permissions/{UserPermission.AllTimelineManagement}"); res.StatusCode.Should().Be(HttpStatusCode.OK); } { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(UserPermission.AllTimelineManagement.ToString()); } { - var res = await client.PutAsync($"users/user1/permissions/{UserPermission.HighlightTimelineManangement}", null); + var res = await client.PutAsync($"users/user1/permissions/{UserPermission.HighlightTimelineManangement}"); res.StatusCode.Should().Be(HttpStatusCode.OK); } { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(UserPermission.AllTimelineManagement.ToString(), UserPermission.HighlightTimelineManangement.ToString()); } { - var res = await client.PutAsync($"users/user1/permissions/{UserPermission.UserManagement}", null); + var res = await client.PutAsync($"users/user1/permissions/{UserPermission.UserManagement}"); res.StatusCode.Should().Be(HttpStatusCode.OK); } { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo( UserPermission.AllTimelineManagement.ToString(), UserPermission.HighlightTimelineManangement.ToString(), @@ -205,7 +205,7 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo( UserPermission.AllTimelineManagement.ToString(), UserPermission.UserManagement.ToString()); @@ -219,19 +219,19 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(UserPermission.UserManagement.ToString()); } { - var res = await client.PutAsync($"users/user1/permissions/{UserPermission.HighlightTimelineManangement}", null); + var res = await client.PutAsync($"users/user1/permissions/{UserPermission.HighlightTimelineManangement}"); res.StatusCode.Should().Be(HttpStatusCode.OK); } { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo( UserPermission.HighlightTimelineManangement.ToString(), UserPermission.UserManagement.ToString()); } @@ -244,7 +244,7 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEquivalentTo(UserPermission.UserManagement.ToString()); } @@ -256,7 +256,7 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.GetAsync("users/user1"); res.StatusCode.Should().Be(HttpStatusCode.OK); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetJsonBodyAsync(); body.Permissions.Should().BeEmpty(); } } @@ -269,16 +269,16 @@ namespace Timeline.Tests.IntegratedTests using var client = await CreateClientAsAdministrator(); { - var res = await client.PutAsync(url, null); + var res = await client.PutAsync(url); res.StatusCode.Should().Be(HttpStatusCode.BadRequest); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetCommonBodyAsync(); body.Code.Should().Be(ErrorCodes.Common.InvalidModel); } { var res = await client.DeleteAsync(url); res.StatusCode.Should().Be(HttpStatusCode.BadRequest); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetCommonBodyAsync(); body.Code.Should().Be(ErrorCodes.Common.InvalidModel); } } @@ -291,16 +291,16 @@ namespace Timeline.Tests.IntegratedTests const string url = "users/user123/permissions/UserManagement"; { - var res = await client.PutAsync(url, null); + var res = await client.PutAsync(url); res.StatusCode.Should().Be(HttpStatusCode.NotFound); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetCommonBodyAsync(); body.Code.Should().Be(ErrorCodes.UserCommon.NotExist); } { var res = await client.DeleteAsync(url); res.StatusCode.Should().Be(HttpStatusCode.NotFound); - var body = await res.Content.ReadFromJsonAsync(); + var body = await res.Should().HaveAndGetCommonBodyAsync(); body.Code.Should().Be(ErrorCodes.UserCommon.NotExist); } } -- cgit v1.2.3 From f5ccd0d9855f82e14c6b765eee6a04b22c50dc8a Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 15 Nov 2020 01:44:48 +0800 Subject: ... --- .../IntegratedTests/CacheTestHelper.cs | 47 ++- .../Timeline.Tests/IntegratedTests/FrontEndTest.cs | 6 +- .../IntegratedTests/HttpClientExtensions.cs | 48 --- .../IntegratedTests/HttpClientTestExtensions.cs | 192 +++++++++++ .../HttpClientTimelineExtensions.cs | 26 +- .../IntegratedTests/HttpClientUserExtensions.cs | 8 +- .../IntegratedTests/HttpResponseAssertions.cs | 136 -------- .../IntegratedTests/HttpResponseExtensions.cs | 14 - .../IntegratedTests/IntegratedTestBase.cs | 5 +- .../Timeline.Tests/IntegratedTests/TimelineTest.cs | 358 ++++++--------------- 10 files changed, 320 insertions(+), 520 deletions(-) delete mode 100644 BackEnd/Timeline.Tests/IntegratedTests/HttpClientExtensions.cs create mode 100644 BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs delete mode 100644 BackEnd/Timeline.Tests/IntegratedTests/HttpResponseAssertions.cs delete mode 100644 BackEnd/Timeline.Tests/IntegratedTests/HttpResponseExtensions.cs (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/CacheTestHelper.cs b/BackEnd/Timeline.Tests/IntegratedTests/CacheTestHelper.cs index bafb2fcf..8308eca8 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/CacheTestHelper.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/CacheTestHelper.cs @@ -13,9 +13,10 @@ namespace Timeline.Tests.IntegratedTests public static async Task TestCache(HttpClient client, string getUrl) { EntityTagHeaderValue eTag; + { var res = await client.GetAsync(getUrl); - res.Should().HaveStatusCode(200); + res.StatusCode.Should().Be(HttpStatusCode.OK); var cacheControlHeader = res.Headers.CacheControl; cacheControlHeader.Should().NotBeNull(); cacheControlHeader!.NoCache.Should().BeTrue(); @@ -28,39 +29,27 @@ namespace Timeline.Tests.IntegratedTests eTag = res.Headers.ETag!; } - { - using var request = new HttpRequestMessage() + await client.TestSendAssertErrorAsync(HttpMethod.Get, getUrl, + expectedStatusCode: HttpStatusCode.BadRequest, + errorCode: ErrorCodes.Common.Header.IfNonMatch_BadFormat, + headerSetup: static (headers, _) => { - RequestUri = new Uri(client.BaseAddress!, getUrl), - Method = HttpMethod.Get, - }; - request.Headers.TryAddWithoutValidation("If-None-Match", "\"dsdfd"); - var res = await client.SendAsync(request); - await res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBodyWithCodeAsync(ErrorCodes.Common.Header.IfNonMatch_BadFormat); - } + headers.TryAddWithoutValidation("If-None-Match", "\"dsdfd"); + }); - { - using var request = new HttpRequestMessage() + await client.TestSendAsync(HttpMethod.Get, getUrl, + expectedStatusCode: HttpStatusCode.OK, + headerSetup: static (headers, _) => { - 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); - } + headers.TryAddWithoutValidation("If-None-Match", "\"aaa\""); + }); - { - using var request = new HttpRequestMessage() + await client.TestSendAsync(HttpMethod.Get, getUrl, + expectedStatusCode: HttpStatusCode.NotModified, + headerSetup: (headers, _) => { - 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); - } + headers.Add("If-None-Match", eTag.ToString()); + }); } } } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/FrontEndTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/FrontEndTest.cs index 86cde11f..1843c412 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/FrontEndTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/FrontEndTest.cs @@ -1,7 +1,7 @@ using FluentAssertions; +using System.Net; using System.Net.Mime; using System.Threading.Tasks; -using Timeline.Tests.Helpers; using Xunit; namespace Timeline.Tests.IntegratedTests @@ -13,7 +13,7 @@ namespace Timeline.Tests.IntegratedTests { using var client = await CreateDefaultClient(false); var res = await client.GetAsync("index.html"); - res.Should().HaveStatusCode(200); + res.StatusCode.Should().Be(HttpStatusCode.OK); var contentTypeHeader = res.Content.Headers.ContentType; contentTypeHeader.Should().NotBeNull(); contentTypeHeader!.MediaType.Should().Be(MediaTypeNames.Text.Html); @@ -24,7 +24,7 @@ namespace Timeline.Tests.IntegratedTests { using var client = await CreateDefaultClient(false); var res = await client.GetAsync("aaaaaaaaaaaaaaa"); - res.Should().HaveStatusCode(200); + res.StatusCode.Should().Be(HttpStatusCode.OK); var contentTypeHeader = res.Content.Headers.ContentType; contentTypeHeader.Should().NotBeNull(); contentTypeHeader!.MediaType.Should().Be(MediaTypeNames.Text.Html); diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientExtensions.cs deleted file mode 100644 index 9258e644..00000000 --- a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientExtensions.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Http.Json; -using System.Net.Mime; -using System.Text; -using System.Threading.Tasks; - -namespace Timeline.Tests.IntegratedTests -{ - public static class HttpClientExtensions - { - public static async Task PatchAsJsonAsync(this HttpClient client, string url, T body) - { - using var reqContent = JsonContent.Create(body, options: CommonJsonSerializeOptions.Options); - return await client.PatchAsync(url, reqContent); - } - - public static Task PutAsync(this HttpClient client, string url) - { - return client.PutAsync(url, null!); - } - - public static Task PutByteArrayAsync(this HttpClient client, string url, byte[] body, string mimeType) - { - return client.PutByteArrayAsync(new Uri(url, UriKind.RelativeOrAbsolute), body, mimeType); - } - - public static async Task PutByteArrayAsync(this HttpClient client, Uri url, byte[] body, string mimeType) - { - using var content = new ByteArrayContent(body); - content.Headers.ContentLength = body.Length; - content.Headers.ContentType = new MediaTypeHeaderValue(mimeType); - return await 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); - } - - public static async Task PutStringAsync(this HttpClient client, Uri url, string body, string? mimeType = null) - { - using var content = new StringContent(body, Encoding.UTF8, mimeType ?? MediaTypeNames.Text.Plain); - return await client.PutAsync(url, content); - } - } -} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs new file mode 100644 index 00000000..18334622 --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs @@ -0,0 +1,192 @@ +using FluentAssertions; +using System; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Threading.Tasks; +using Timeline.Models.Http; + +namespace Timeline.Tests.IntegratedTests +{ + public delegate void HeaderSetup(HttpRequestHeaders requestHeaders, HttpContentHeaders? contentHeaders); + + public static class HttpClientTestExtensions + { + public static async Task TestSendAsync(this HttpClient client, HttpMethod method, string url, HttpContent? body = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, HeaderSetup? headerSetup = null) + { + using var req = new HttpRequestMessage + { + Method = method, + RequestUri = new Uri(url, UriKind.Relative), + Content = body + }; + headerSetup?.Invoke(req.Headers, body?.Headers); + var res = await client.SendAsync(req); + res.StatusCode.Should().Be(expectedStatusCode); + return res; + } + + public static async Task AssertJsonBodyAsync(HttpResponseMessage response) + { + var body = await response.Content.ReadFromJsonAsync(CommonJsonSerializeOptions.Options); + body.Should().NotBeNull($"Body is not json format of type {typeof(T).FullName}"); + return body!; + } + + public static async Task TestJsonSendAsync(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, HeaderSetup? headerSetup = null) + { + using JsonContent? reqContent = jsonBody == null ? null : JsonContent.Create(jsonBody, options: CommonJsonSerializeOptions.Options); + await client.TestSendAsync(method, url, reqContent, expectedStatusCode, headerSetup); + } + + public static async Task TestJsonSendAsync(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, HeaderSetup? headerSetup = null) + { + using JsonContent? reqContent = jsonBody == null ? null : JsonContent.Create(jsonBody, options: CommonJsonSerializeOptions.Options); + var res = await client.TestSendAsync(method, url, reqContent, expectedStatusCode, headerSetup); + var resBody = await AssertJsonBodyAsync(res); + return resBody; + } + + public static async Task TestGetAsync(this HttpClient client, string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + await client.TestJsonSendAsync(HttpMethod.Get, url, expectedStatusCode: expectedStatusCode); + } + + public static async Task TestGetAsync(this HttpClient client, string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + return await client.TestJsonSendAsync(HttpMethod.Get, url, expectedStatusCode: expectedStatusCode); + } + + public static async Task TestPostAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + await client.TestJsonSendAsync(HttpMethod.Post, url, jsonBody, expectedStatusCode: expectedStatusCode); + } + + public static async Task TestPostAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + return await client.TestJsonSendAsync(HttpMethod.Post, url, jsonBody, expectedStatusCode: expectedStatusCode); + } + + public static async Task TestPutAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + await client.TestJsonSendAsync(HttpMethod.Put, url, jsonBody, expectedStatusCode: expectedStatusCode); + } + + public static async Task TestPutAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + return await client.TestJsonSendAsync(HttpMethod.Put, url, jsonBody, expectedStatusCode: expectedStatusCode); + } + + public static async Task TestPatchAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + return await client.TestJsonSendAsync(HttpMethod.Patch, url, jsonBody, expectedStatusCode: expectedStatusCode); + } + + public static async Task TestDeleteAsync(this HttpClient client, string url, bool? delete = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + var body = await client.TestJsonSendAsync(HttpMethod.Delete, url, expectedStatusCode: expectedStatusCode); + if (delete.HasValue) + body.Data.Delete.Should().Be(delete.Value); + } + + public static async Task TestSendAssertErrorAsync(this HttpClient client, HttpMethod method, string url, HttpContent? body = null, HttpStatusCode expectedStatusCode = HttpStatusCode.BadRequest, int? errorCode = null, HeaderSetup? headerSetup = null) + { + var res = await client.TestSendAsync(method, url, body, expectedStatusCode, headerSetup); + if (errorCode.HasValue) + { + var resBody = await AssertJsonBodyAsync(res); + resBody.Code.Should().Be(errorCode.Value); + } + } + + public static async Task TestJsonSendAssertErrorAsync(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.BadRequest, int? errorCode = null, HeaderSetup? headerSetup = null) + { + using JsonContent? reqContent = jsonBody == null ? null : JsonContent.Create(jsonBody, options: CommonJsonSerializeOptions.Options); + await client.TestSendAssertErrorAsync(method, url, reqContent, expectedStatusCode, errorCode, headerSetup); + } + + public static async Task TestPostAssertErrorAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.BadRequest, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertErrorAsync(HttpMethod.Post, url, jsonBody, expectedStatusCode, errorCode, headerSetup); + } + + public static async Task TestPutAssertErrorAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.BadRequest, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertErrorAsync(HttpMethod.Put, url, jsonBody, expectedStatusCode, errorCode, headerSetup); + } + + public static async Task TestDeleteAssertErrorAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.BadRequest, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertErrorAsync(HttpMethod.Delete, url, jsonBody, expectedStatusCode, errorCode, headerSetup); + } + + public static async Task TestJsonSendAssertInvalidModelAsync(this HttpClient client, HttpMethod method, string url, object? jsonBody = null) + { + await client.TestJsonSendAssertErrorAsync(method, url, jsonBody, expectedStatusCode: HttpStatusCode.BadRequest, errorCode: ErrorCodes.Common.InvalidModel); + } + + public static async Task TestGetAssertInvalidModelAsync(this HttpClient client, string url) + { + await client.TestJsonSendAssertInvalidModelAsync(HttpMethod.Get, url); + } + + public static async Task TestPostAssertInvalidModelAsync(this HttpClient client, string url, object? jsonBody = null) + { + await client.TestJsonSendAssertInvalidModelAsync(HttpMethod.Post, url, jsonBody); + } + + public static async Task TestDeleteAssertInvalidModelAsync(this HttpClient client, string url, object? jsonBody = null) + { + await client.TestJsonSendAssertInvalidModelAsync(HttpMethod.Delete, url, jsonBody); + } + + public static async Task TestJsonSendAssertUnauthorizedAsync(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertErrorAsync(method, url, jsonBody, HttpStatusCode.Unauthorized, errorCode, headerSetup); + } + + public static async Task TestGetAssertUnauthorizedAsync(this HttpClient client, string url, object? jsonBody = null, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertUnauthorizedAsync(HttpMethod.Get, url, jsonBody, errorCode, headerSetup); + } + + public static async Task TestPostAssertUnauthorizedAsync(this HttpClient client, string url, object? jsonBody = null, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertUnauthorizedAsync(HttpMethod.Post, url, jsonBody, errorCode, headerSetup); + } + + public static async Task TestDeleteAssertUnauthorizedAsync(this HttpClient client, string url, object? jsonBody = null, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertUnauthorizedAsync(HttpMethod.Delete, url, jsonBody, errorCode, headerSetup); + } + + public static async Task TestJsonSendAssertForbiddenAsync(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertErrorAsync(method, url, jsonBody, HttpStatusCode.Forbidden, errorCode, headerSetup); + } + + public static async Task TestGetAssertForbiddenAsync(this HttpClient client, string url, object? jsonBody = null, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertForbiddenAsync(HttpMethod.Get, url, jsonBody, errorCode, headerSetup); + } + + public static async Task TestPostAssertForbiddenAsync(this HttpClient client, string url, object? jsonBody = null, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertForbiddenAsync(HttpMethod.Post, url, jsonBody, errorCode, headerSetup); + } + + public static async Task TestDeleteAssertForbiddenAsync(this HttpClient client, string url, object? jsonBody = null, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertForbiddenAsync(HttpMethod.Delete, url, jsonBody, errorCode, headerSetup); + } + + public static async Task TestPutByteArrayAsync(this HttpClient client, string url, byte[] body, string mimeType, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + { + using var content = new ByteArrayContent(body); + content.Headers.ContentLength = body.Length; + content.Headers.ContentType = new MediaTypeHeaderValue(mimeType); + return await client.TestSendAsync(HttpMethod.Put, url, content); + } + } +} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTimelineExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTimelineExtensions.cs index 125435f9..992889e3 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTimelineExtensions.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTimelineExtensions.cs @@ -7,24 +7,16 @@ namespace Timeline.Tests.IntegratedTests { public static class HttpClientTimelineExtensions { - public static async Task GetTimelineAsync(this HttpClient client, string timelineName) - { - var res = await client.GetAsync($"timelines/{timelineName}"); - res.Should().HaveStatusCode(HttpStatusCode.OK); - return await res.Should().HaveAndGetJsonBodyAsync(); - } + public static Task GetTimelineAsync(this HttpClient client, string timelineName) + => client.TestGetAsync($"timelines/{timelineName}"); - public static async Task PatchTimelineAsync(this HttpClient client, string timelineName, TimelinePatchRequest body) - { - var res = await client.PatchAsJsonAsync($"timelines/{timelineName}", body); - res.Should().HaveStatusCode(HttpStatusCode.OK); - return await res.Should().HaveAndGetJsonBodyAsync(); - } + public static Task PatchTimelineAsync(this HttpClient client, string timelineName, TimelinePatchRequest body) + => client.TestPatchAsync($"timelines/{timelineName}", body); - public static async Task PutTimelineMemberAsync(this HttpClient client, string timelineName, string memberUsername) - { - var res = await client.PutAsync($"timelines/{timelineName}/members/{memberUsername}"); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } + public static Task PutTimelineMemberAsync(this HttpClient client, string timelineName, string memberUsername) + => client.TestPutAsync($"timelines/{timelineName}/members/{memberUsername}"); + + public static Task DeleteTimelineMemberAsync(this HttpClient client, string timelineName, string memberUsername, bool? delete) + => client.TestDeleteAsync($"timelines/{timelineName}/members/{memberUsername}", delete); } } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientUserExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientUserExtensions.cs index 0ce2325f..0ccefa55 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientUserExtensions.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientUserExtensions.cs @@ -7,11 +7,7 @@ namespace Timeline.Tests.IntegratedTests { public static class HttpClientUserExtensions { - public static async Task GetUserAsync(this HttpClient client, string username) - { - var res = await client.GetAsync($"users/{username}"); - res.Should().HaveStatusCode(HttpStatusCode.OK); - return await res.Should().HaveAndGetJsonBodyAsync(); - } + public static Task GetUserAsync(this HttpClient client, string username) + => client.TestGetAsync($"users/{username}"); } } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseAssertions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseAssertions.cs deleted file mode 100644 index 166cde09..00000000 --- a/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseAssertions.cs +++ /dev/null @@ -1,136 +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.Threading.Tasks; -using Timeline.Models.Http; - -namespace Timeline.Tests.IntegratedTests -{ - 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; - return $"{newline}{padding} Status Code: {res.StatusCode}"; - } - } - - 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 async Task HaveAndGetJsonBodyAsync(string because = "", params object[] becauseArgs) - { - var a = Execute.Assertion.BecauseOf(because, becauseArgs); - - var body = await Subject.ReadBodyAsJsonAsync(); - if (body == null) - { - a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string of type {0}{reason}, but failed to read it or it was not a valid json string.", typeof(T).FullName); - return default!; - } - return body; - } - - public async Task> HaveJsonBodyAsync(string because = "", params object[] becauseArgs) - { - var a = Execute.Assertion.BecauseOf(because, becauseArgs); - - var body = await Subject.ReadBodyAsJsonAsync(); - if (body == null) - { - a.FailWith("Expected response body of {context:HttpResponseMessage} to be json string of type {0}{reason}, but failed to read it or it was not a valid json string.", typeof(T).FullName); - return new(Subject, null); - } - return new(Subject, body); - } - } - - public static class AssertionResponseExtensions - { - public static HttpResponseMessageAssertions Should(this HttpResponseMessage instance) - { - return new HttpResponseMessageAssertions(instance); - } - - public static Task HaveAndGetCommonBodyAsync(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) - { - return assertions.HaveAndGetJsonBodyAsync(because, becauseArgs); - } - - public static async Task HaveCommonBodyWithCodeAsync(this HttpResponseMessageAssertions assertions, int code, string? message = null, params object[] messageArgs) - { - message = string.IsNullOrEmpty(message) ? "" : ", " + string.Format(CultureInfo.CurrentCulture, message, messageArgs); - var body = await assertions.HaveAndGetCommonBodyAsync("Response body should be CommonResponse{0}", message); - body.Code.Should().Be(code, "Response body code is not the specified one{0}", message); - } - - public static Task> HaveAndGetCommonDataBodyAsync(this HttpResponseMessageAssertions assertions, string because = "", params object[] becauseArgs) - { - return assertions.HaveAndGetJsonBodyAsync>(because, becauseArgs); - } - - public static async Task BePutAsync(this HttpResponseMessageAssertions assertions, bool create, string because = "", params object[] becauseArgs) - { - var body = await assertions.HaveStatusCode(create ? 201 : 200, because, becauseArgs) - .And.HaveAndGetJsonBodyAsync(because, becauseArgs); - body.Code.Should().Be(0); - body.Data.Create.Should().Be(create); - } - - public static async Task BeDeleteAsync(this HttpResponseMessageAssertions assertions, bool delete, string because = "", params object[] becauseArgs) - { - var body = await assertions.HaveStatusCode(200, because, becauseArgs) - .And.HaveAndGetJsonBodyAsync(because, becauseArgs); - body.Code.Should().Be(0); - body.Data.Delete.Should().Be(delete); - } - - public static async Task BeInvalidModelAsync(this HttpResponseMessageAssertions assertions, string? message = null) - { - message = string.IsNullOrEmpty(message) ? "" : ", " + message; - var body = await assertions.HaveStatusCode(400, "Invalid Model Error must have 400 status code{0}", message) - .And.HaveAndGetCommonBodyAsync("Invalid Model Error must have CommonResponse body{0}", message); - body.Code.Should().Be(ErrorCodes.Common.InvalidModel, - "Invalid Model Error must have code {0} in body{1}", - ErrorCodes.Common.InvalidModel, message); - } - } -} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseExtensions.cs deleted file mode 100644 index 097fefd1..00000000 --- a/BackEnd/Timeline.Tests/IntegratedTests/HttpResponseExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Net.Http; -using System.Net.Http.Json; -using System.Threading.Tasks; - -namespace Timeline.Tests.IntegratedTests -{ - public static class HttpResponseExtensions - { - public static async Task ReadBodyAsJsonAsync(this HttpResponseMessage response) - { - return await response.Content.ReadFromJsonAsync(CommonJsonSerializeOptions.Options); - } - } -} diff --git a/BackEnd/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs b/BackEnd/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs index 070b456f..72480dc6 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs @@ -104,10 +104,9 @@ namespace Timeline.Tests.IntegratedTests public async Task CreateClientWithCredential(string username, string password, bool setApiBase = true) { var client = await CreateDefaultClient(setApiBase); - var response = await client.PostAsJsonAsync("token/create", + var res = await client.TestPostAsync("token/create", new CreateTokenRequest { Username = username, Password = password }); - var token = (await response.Should().HaveStatusCode(200) - .And.HaveAndGetJsonBodyAsync()).Token; + var token = res.Token; client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); return client; } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs index e996be45..fbcdb3fc 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -7,7 +7,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Net; using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; @@ -15,7 +14,6 @@ using Timeline.Entities; using Timeline.Models; using Timeline.Models.Http; using Timeline.Tests.Helpers; -using Timeline.Tests.IntegratedTests; using Xunit; namespace Timeline.Tests.IntegratedTests @@ -61,8 +59,7 @@ namespace Timeline.Tests.IntegratedTests for (int i = 0; i <= 3; i++) { using var client = await CreateClientAs(i); - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = $"t{i}" }); - res.Should().HaveStatusCode(200); + await client.TestPostAsync("timelines", new TimelineCreateRequest { Name = $"t{i}" }); } } @@ -71,20 +68,12 @@ namespace Timeline.Tests.IntegratedTests { using var client = await CreateDefaultClient(); - { - var res = await client.GetAsync("timelines/@!!!"); - await res.Should().BeInvalidModelAsync(); - } + await client.TestGetAssertInvalidModelAsync("timelines/@!!!"); + await client.TestGetAssertInvalidModelAsync("timelines/!!!"); - { - var res = await client.GetAsync("timelines/!!!"); - await res.Should().BeInvalidModelAsync(); - } { - var res = await client.GetAsync("timelines/@user1"); - var body = await res.Should().HaveStatusCode(200) - .And.HaveAndGetJsonBodyAsync(); + var body = await client.TestGetAsync("timelines/@user1"); body.Owner.Should().BeEquivalentTo(await client.GetUserAsync("user1")); body.Visibility.Should().Be(TimelineVisibility.Register); body.Description.Should().Be(""); @@ -96,9 +85,7 @@ namespace Timeline.Tests.IntegratedTests } { - var res = await client.GetAsync("timelines/t1"); - var body = await res.Should().HaveStatusCode(200) - .And.HaveAndGetJsonBodyAsync(); + var body = await client.TestGetAsync("timelines/t1"); body.Owner.Should().BeEquivalentTo(await client.GetUserAsync("user1")); body.Visibility.Should().Be(TimelineVisibility.Register); body.Description.Should().Be(""); @@ -126,10 +113,7 @@ namespace Timeline.Tests.IntegratedTests } - var res = await client.GetAsync("timelines"); - var body = res.Should().HaveStatusCode(200) - .And.HaveAndGetJsonBodyAsync>(); - + var body = await client.TestGetAsync>("timelines"); body.Should().BeEquivalentTo(result); } @@ -139,15 +123,9 @@ namespace Timeline.Tests.IntegratedTests { using var client = await CreateDefaultClient(); - async Task TestAgainst(string url) - { - var res = await client.GetAsync(url); - await res.Should().BeInvalidModelAsync(); - } - - await TestAgainst("timelines?relate=us!!"); - await TestAgainst("timelines?relateType=aaa"); - await TestAgainst("timelines?visibility=aaa"); + await client.TestGetAssertInvalidModelAsync("timelines?relate=us!!"); + await client.TestGetAssertInvalidModelAsync("timelines?relateType=aaa"); + await client.TestGetAssertInvalidModelAsync("timelines?visibility=aaa"); } var testResultRelate = new List(); @@ -231,9 +209,7 @@ namespace Timeline.Tests.IntegratedTests async Task TestAgainst(string url, List against) { - var res = await client.GetAsync(url); - var body = await res.Should().HaveStatusCode(200) - .And.HaveAndGetJsonBodyAsync>(); + var body = await client.TestGetAsync>(url); body.Should().BeEquivalentTo(against); } @@ -252,30 +228,20 @@ namespace Timeline.Tests.IntegratedTests { { using var client = await CreateDefaultClient(); - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); + await client.TestPostAssertUnauthorizedAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); } { using var client = await CreateClientAsUser(); - { - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "!!!" }); - await res.Should().BeInvalidModelAsync(); - } + await client.TestPostAssertInvalidModelAsync("timelines", new TimelineCreateRequest { Name = "!!!" }); { - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - var body = await res.Should().HaveStatusCode(200) - .And.HaveAndGetJsonBodyAsync(); + var body = await client.TestPostAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); body.Should().BeEquivalentTo(await client.GetTimelineAsync("aaa")); } - { - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - await res.Should().HaveStatusCode(400) - .And.HaveCommonBodyWithCodeAsync(ErrorCodes.TimelineController.NameConflict); - } + await client.TestPostAssertErrorAsync("timelines", new TimelineCreateRequest { Name = "aaa" }, errorCode: ErrorCodes.TimelineController.NameConflict); } } @@ -284,61 +250,49 @@ namespace Timeline.Tests.IntegratedTests { { using var client = await CreateDefaultClient(); - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); + await client.TestDeleteAssertUnauthorizedAsync("timelines/t1"); } { using var client = await CreateClientAs(2); - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); + await client.TestDeleteAssertForbiddenAsync("timelines/t1"); } { using var client = await CreateClientAsAdministrator(); - { - var res = await client.DeleteAsync("timelines/!!!"); - await res.Should().BeInvalidModelAsync(); - } - - { - var res = await client.DeleteAsync("timelines/t2"); - await res.Should().BeDeleteAsync(true); - } - - { - var res = await client.DeleteAsync("timelines/t2"); - await res.Should().BeDeleteAsync(false); - } + await client.TestDeleteAssertInvalidModelAsync("timelines/!!!"); + await client.TestDeleteAsync("timelines/t2", true); + await client.TestDeleteAsync("timelines/t2", false); } { using var client = await CreateClientAs(1); - { - var res = await client.DeleteAsync("timelines/!!!"); - await res.Should().BeInvalidModelAsync(); - } + await client.TestDeleteAssertInvalidModelAsync("timelines/!!!"); + await client.TestDeleteAsync("timelines/t1", true); + await client.TestDeleteAssertErrorAsync("timelines/t1"); + } + } - { - var res = await client.DeleteAsync("timelines/t1"); - await res.Should().BeDeleteAsync(true); - } + public static string CreatePersonalTimelineName(int i) => i == 0 ? "@admin" : $"@user{i}"; + public static string CreateOrdinaryTimelineName(int i) => $"t{i}"; + public delegate string TimelineNameGenerator(int i); - { - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(400); - } - } + public static IEnumerable TimelineNameGeneratorTestData() + { + yield return new object[] { new TimelineNameGenerator(CreatePersonalTimelineName) }; + yield return new object[] { new TimelineNameGenerator(CreateOrdinaryTimelineName) }; } [Theory] - [InlineData("@user1")] - [InlineData("t1")] - public async Task TimelineDescription_Should_Work(string timelineName) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task TimelineDescription_Should_Work(TimelineNameGenerator generator) { + // TODO! Permission tests. + using var client = await CreateClientAsUser(); + var timelineName = generator(1); { var timeline = await client.GetTimelineAsync(timelineName); @@ -379,309 +333,185 @@ namespace Timeline.Tests.IntegratedTests } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Member_Should_Work(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task Member_Should_Work(TimelineNameGenerator generator) { - var getUrl = generator(1, null); + // TODO! Invalid model tests. + // TODO! Permission tests. + using var client = await CreateClientAsUser(); - async Task AssertMembers(IList members) + var timelineName = generator(1); + + async Task AssertMembers(List members) { - var res = await client.GetAsync(getUrl); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Members.Should().NotBeNull().And.BeEquivalentTo(members); + var body = await client.GetTimelineAsync(timelineName); + body.Members.Should().NotBeNull().And.BeEquivalentTo(members); } async Task AssertEmptyMembers() { - var res = await client.GetAsync(getUrl); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Members.Should().NotBeNull().And.BeEmpty(); + var body = await client.GetTimelineAsync(timelineName); + body.Members.Should().NotBeNull().And.BeEmpty(); } await AssertEmptyMembers(); - { - var res = await client.PutAsync(generator(1, "members/usernotexist"), null); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.TimelineController.MemberPut_NotExist); - } + await client.TestPutAssertErrorAsync($"timelines/{timelineName}/members/usernotexist", errorCode: ErrorCodes.TimelineController.MemberPut_NotExist); await AssertEmptyMembers(); - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } - await AssertMembers(new List { UserInfos[2] }); - { - var res = await client.DeleteAsync(generator(1, "members/user2")); - res.Should().BeDelete(true); - } + await client.PutTimelineMemberAsync(timelineName, "user2"); + await AssertMembers(new List { await client.GetUserAsync("user2") }); + await client.DeleteTimelineMemberAsync(timelineName, "user2", true); await AssertEmptyMembers(); - { - var res = await client.DeleteAsync(generator(1, "members/aaa")); - res.Should().BeDelete(false); - } + await client.DeleteTimelineMemberAsync(timelineName, "aaa", false); await AssertEmptyMembers(); } - public static IEnumerable Permission_Timeline_Data() - { - yield return new object[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl), -1, 200, 401, 401, 401, 401 }; - yield return new object[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl), 1, 200, 200, 403, 200, 403 }; - yield return new object[] { new TimelineUrlGenerator(GenerateOrdinaryTimelineUrl), 0, 200, 200, 200, 200, 200 }; - yield return new object[] { new TimelineUrlGenerator(GeneratePersonalTimelineUrl), -1, 200, 401, 401, 401, 401 }; - yield return new object[] { new TimelineUrlGenerator(GeneratePersonalTimelineUrl), 1, 200, 200, 403, 200, 403 }; - yield return new object[] { new TimelineUrlGenerator(GeneratePersonalTimelineUrl), 0, 200, 200, 200, 200, 200 }; - } - - [Theory] - [MemberData(nameof(Permission_Timeline_Data))] - public async Task Permission_Timeline(TimelineUrlGenerator generator, int userNumber, int get, int opPatchUser, int opPatchAdmin, int opMemberUser, int opMemberAdmin) - { - using var client = await CreateClientAs(userNumber); - { - var res = await client.GetAsync("timelines/t1"); - res.Should().HaveStatusCode(get); - } - - { - var res = await client.PatchAsJsonAsync(generator(1, null), new TimelinePatchRequest { Description = "hahaha" }); - res.Should().HaveStatusCode(opPatchUser); - } - - { - var res = await client.PatchAsJsonAsync(generator(0, null), new TimelinePatchRequest { Description = "hahaha" }); - res.Should().HaveStatusCode(opPatchAdmin); - } - - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(opMemberUser); - } - - { - var res = await client.DeleteAsync(generator(1, "members/user2")); - res.Should().HaveStatusCode(opMemberUser); - } - - { - var res = await client.PutAsync(generator(0, "members/user2"), null); - res.Should().HaveStatusCode(opMemberAdmin); - } - - { - var res = await client.DeleteAsync(generator(0, "members/user2")); - res.Should().HaveStatusCode(opMemberAdmin); - } - } - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Visibility_Test(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task GetPostsAndVisibility_Should_Work(TimelineNameGenerator generator) { - var userUrl = generator(1, "posts"); - var adminUrl = generator(0, "posts"); - { - - using var client = await CreateClientAsUser(); - using var content = new StringContent(@"{""visibility"":""abcdefg""}", System.Text.Encoding.UTF8, System.Net.Mime.MediaTypeNames.Application.Json); - var res = await client.PatchAsync(generator(1, null), content); - res.Should().BeInvalidModel(); - } { // default visibility is registered { using var client = await CreateDefaultClient(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(403); + await client.TestGetAssertForbiddenAsync($"timelines/{generator(1)}/posts"); } { using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(200); + await client.TestGetAsync($"timelines/{generator(0)}/posts"); } } { // change visibility to public { using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Visibility = TimelineVisibility.Public }); - res.Should().HaveStatusCode(200); + await client.PatchTimelineAsync(generator(1), new() { Visibility = TimelineVisibility.Public }); } + { using var client = await CreateDefaultClient(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(200); + await client.TestGetAsync($"timelines/{generator(1)}/posts"); } } { // change visibility to private { using var client = await CreateClientAsAdministrator(); - { - var res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } - { - var res = await client.PatchAsJsonAsync(generator(0, null), - new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } + await client.PatchTimelineAsync(generator(1), new() { Visibility = TimelineVisibility.Private }); + await client.PatchTimelineAsync(generator(0), new() { Visibility = TimelineVisibility.Private }); } { using var client = await CreateDefaultClient(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(403); + await client.TestGetAssertForbiddenAsync($"timelines/{generator(1)}/posts"); } { // user can't read admin's using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(403); + await client.TestGetAssertForbiddenAsync($"timelines/{generator(0)}/posts"); } { // admin can read user's using var client = await CreateClientAsAdministrator(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(200); + await client.TestGetAsync($"timelines/{generator(1)}/posts"); } { // add member using var client = await CreateClientAsAdministrator(); - var res = await client.PutAsync(generator(0, "members/user1"), null); - res.Should().HaveStatusCode(200); + await client.PutTimelineMemberAsync(generator(0), "user1"); } { // now user can read admin's using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(200); + await client.TestGetAsync($"timelines/{generator(0)}/posts"); } } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Permission_Post_Create(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task CreatePostPermission_Should_Work(TimelineNameGenerator generator) { using (var client = await CreateClientAsUser()) { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); + await client.PutTimelineMemberAsync(generator(1), "user2"); } using (var client = await CreateDefaultClient()) - { - { // no auth should get 401 - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(401); - } + { // no auth should get 401 + await client.TestPostAssertUnauthorizedAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); } using (var client = await CreateClientAsUser()) { - { // post self's - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(200); - } - { // post other not as a member should get 403 - var res = await client.PostAsJsonAsync(generator(0, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(403); - } + // post self's + await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); + // post other not as a member should get 403 + await client.TestPostAssertForbiddenAsync($"timelines/{generator(0)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); } using (var client = await CreateClientAsAdministrator()) - { - { // post as admin - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(200); - } + { // post as admin + await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); } using (var client = await CreateClientAs(2)) - { - { // post as member - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(200); - } + { // post as member + await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Permission_Post_Delete(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task DeletePostPermission_Should_Work(TimelineNameGenerator generator) { async Task CreatePost(int userNumber) { using var client = await CreateClientAs(userNumber); - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - return res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Id; + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); + return body.Id; } using (var client = await CreateClientAsUser()) { - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } - { - var res = await client.PutAsync(generator(1, "members/user3"), null); - res.Should().HaveStatusCode(200); - } + await client.PutTimelineMemberAsync(generator(1), "user2"); + await client.PutTimelineMemberAsync(generator(1), "user3"); } { // no auth should get 401 using var client = await CreateDefaultClient(); - var res = await client.DeleteAsync(generator(1, "posts/12")); - res.Should().HaveStatusCode(401); + await client.TestDeleteAssertUnauthorizedAsync($"timelines/{generator(1)}/posts/12"); } { // self can delete self var postId = await CreatePost(1); using var client = await CreateClientAsUser(); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(200); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}"); } { // admin can delete any var postId = await CreatePost(1); using var client = await CreateClientAsAdministrator(); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(200); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}"); } { // owner can delete other var postId = await CreatePost(2); using var client = await CreateClientAsUser(); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(200); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}"); } { // author can delete self var postId = await CreatePost(2); using var client = await CreateClientAs(2); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(200); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}"); } { // otherwise is forbidden var postId = await CreatePost(2); using var client = await CreateClientAs(3); - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().HaveStatusCode(403); + await client.TestDeleteAssertForbiddenAsync($"timelines/{generator(1)}/posts/{postId}"); } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task TextPost_ShouldWork(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task TextPost_Should_Work(TimelineNameGenerator generator) { { using var client = await CreateClientAsUser(); -- cgit v1.2.3 From 67fff3b0883ffaf2a2b314252412e5476413bbf0 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 15 Nov 2020 02:28:10 +0800 Subject: ... --- .../IntegratedTests/HttpClientTestExtensions.cs | 13 +- .../Timeline.Tests/IntegratedTests/TimelineTest.cs | 485 +++++++-------------- 2 files changed, 167 insertions(+), 331 deletions(-) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs index 18334622..5091a7f7 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs @@ -48,14 +48,14 @@ namespace Timeline.Tests.IntegratedTests return resBody; } - public static async Task TestGetAsync(this HttpClient client, string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + public static async Task TestGetAsync(this HttpClient client, string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, HeaderSetup? headerSetup = null) { - await client.TestJsonSendAsync(HttpMethod.Get, url, expectedStatusCode: expectedStatusCode); + await client.TestJsonSendAsync(HttpMethod.Get, url, expectedStatusCode: expectedStatusCode, headerSetup: headerSetup); } - public static async Task TestGetAsync(this HttpClient client, string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) + public static async Task TestGetAsync(this HttpClient client, string url, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, HeaderSetup? headerSetup = null) { - return await client.TestJsonSendAsync(HttpMethod.Get, url, expectedStatusCode: expectedStatusCode); + return await client.TestJsonSendAsync(HttpMethod.Get, url, expectedStatusCode: expectedStatusCode, headerSetup: headerSetup); } public static async Task TestPostAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) @@ -106,6 +106,11 @@ namespace Timeline.Tests.IntegratedTests await client.TestSendAssertErrorAsync(method, url, reqContent, expectedStatusCode, errorCode, headerSetup); } + public static async Task TestGetAssertErrorAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.BadRequest, int? errorCode = null, HeaderSetup? headerSetup = null) + { + await client.TestJsonSendAssertErrorAsync(HttpMethod.Get, url, jsonBody, expectedStatusCode, errorCode, headerSetup); + } + public static async Task TestPostAssertErrorAsync(this HttpClient client, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.BadRequest, int? errorCode = null, HeaderSetup? headerSetup = null) { await client.TestJsonSendAssertErrorAsync(HttpMethod.Post, url, jsonBody, expectedStatusCode, errorCode, headerSetup); diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs index fbcdb3fc..44a5584e 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Net; using System.Net.Http; using System.Net.Http.Json; using System.Threading.Tasks; @@ -513,95 +514,63 @@ namespace Timeline.Tests.IntegratedTests [MemberData(nameof(TimelineNameGeneratorTestData))] public async Task TextPost_Should_Work(TimelineNameGenerator generator) { + using var client = await CreateClientAsUser(); + { - using var client = await CreateClientAsUser(); - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().NotBeNull().And.BeEmpty(); - } - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest(null)); - res.Should().BeInvalidModel(); - } - const string mockContent = "aaa"; - TimelinePostInfo createRes; - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest(mockContent)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - body.Should().NotBeNull(); - body.Content.Should().BeEquivalentTo(TimelineHelper.TextPostContent(mockContent)); - body.Author.Should().BeEquivalentTo(UserInfos[1]); - body.Deleted.Should().BeFalse(); - createRes = body; - } - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().NotBeNull().And.BeEquivalentTo(createRes); - } - const string mockContent2 = "bbb"; - var mockTime2 = DateTime.UtcNow.AddDays(-1); - TimelinePostInfo createRes2; - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest(mockContent2, mockTime2)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - body.Should().NotBeNull(); - body.Content.Should().BeEquivalentTo(TimelineHelper.TextPostContent(mockContent2)); - body.Author.Should().BeEquivalentTo(UserInfos[1]); - body.Time.Should().BeCloseTo(mockTime2, 1000); - body.Deleted.Should().BeFalse(); - createRes2 = body; - } - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().NotBeNull().And.BeEquivalentTo(createRes, createRes2); - } - { - var res = await client.DeleteAsync(generator(1, $"posts/{createRes.Id}")); - res.Should().BeDelete(true); - } - { - var res = await client.DeleteAsync(generator(1, $"posts/{createRes.Id}")); - res.Should().BeDelete(false); - } - { - var res = await client.DeleteAsync(generator(1, "posts/30000")); - res.Should().BeDelete(false); - } - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().NotBeNull().And.BeEquivalentTo(createRes2); - } + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); + body.Should().BeEmpty(); + } + + const string mockContent = "aaa"; + TimelinePostInfo createRes; + { + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest(mockContent)); + body.Content.Should().BeEquivalentTo(TimelineHelper.TextPostContent(mockContent)); + body.Author.Should().BeEquivalentTo(await client.GetUserAsync("user1")); + body.Deleted.Should().BeFalse(); + createRes = body; + } + { + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); + body.Should().BeEquivalentTo(createRes); + } + const string mockContent2 = "bbb"; + var mockTime2 = DateTime.UtcNow.AddDays(-1); + TimelinePostInfo createRes2; + { + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest(mockContent2, mockTime2)); + body.Should().NotBeNull(); + body.Content.Should().BeEquivalentTo(TimelineHelper.TextPostContent(mockContent2)); + body.Author.Should().BeEquivalentTo(await client.GetUserAsync("user1")); + body.Time.Should().BeCloseTo(mockTime2, 1000); + body.Deleted.Should().BeFalse(); + createRes2 = body; + } + { + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); + body.Should().BeEquivalentTo(createRes, createRes2); + } + { + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{createRes.Id}", true); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{createRes.Id}", false); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/30000", false); + } + { + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); + body.Should().BeEquivalentTo(createRes2); } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task GetPost_Should_Ordered(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task GetPost_Should_Ordered(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); async Task CreatePost(DateTime time) { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa", time)); - return res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Id; + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa", time)); + return body.Id; } var now = DateTime.UtcNow; @@ -610,60 +579,31 @@ namespace Timeline.Tests.IntegratedTests var id2 = await CreatePost(now); { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Select(p => p.Id).Should().Equal(id1, id2, id0); + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); + body.Select(p => p.Id).Should().Equal(id1, id2, id0); } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task CreatePost_InvalidModel(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task CreatePost_InvalidModel(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = null }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = null } }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "hahaha" } }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "text", Text = null } }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = null } }); - res.Should().BeInvalidModel(); - } - - { - // image not base64 - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = "!!!" } }); - res.Should().BeInvalidModel(); - } - - { - // image base64 not image - var res = await client.PostAsJsonAsync(generator(1, "posts"), new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = Convert.ToBase64String(new byte[] { 0x01, 0x02, 0x03 }) } }); - res.Should().BeInvalidModel(); - } + var postUrl = $"timelines/{generator(1)}/posts"; + await client.TestPostAssertInvalidModelAsync(postUrl, new TimelinePostCreateRequest { Content = null! }); + await client.TestPostAssertInvalidModelAsync(postUrl, new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = null! } }); + await client.TestPostAssertInvalidModelAsync(postUrl, new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "hahaha" } }); + await client.TestPostAssertInvalidModelAsync(postUrl, new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "text", Text = null } }); + await client.TestPostAssertInvalidModelAsync(postUrl, new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = null } }); + // image not base64 + await client.TestPostAssertInvalidModelAsync(postUrl, new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = "!!!" } }); + // image base64 not image + await client.TestPostAssertInvalidModelAsync(postUrl, new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Type = "image", Data = Convert.ToBase64String(new byte[] { 0x01, 0x02, 0x03 }) } }); } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task ImagePost_ShouldWork(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task ImagePost_ShouldWork(TimelineNameGenerator generator) { var imageData = ImageHelper.CreatePngWithSize(100, 200); @@ -673,14 +613,14 @@ namespace Timeline.Tests.IntegratedTests void AssertPostContent(TimelinePostContentInfo content) { content.Type.Should().Be(TimelinePostContentTypes.Image); - content.Url.Should().EndWith(generator(1, $"posts/{postId}/data")); + content.Url.Should().EndWith($"timelines/{generator(1)}/posts/{postId}/data"); content.Text.Should().Be(null); } using var client = await CreateClientAsUser(); { - var res = await client.PostAsJsonAsync(generator(1, "posts"), + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent @@ -689,26 +629,22 @@ namespace Timeline.Tests.IntegratedTests Data = Convert.ToBase64String(imageData) } }); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; postId = body.Id; - postImageUrl = body.Content.Url; + postImageUrl = body.Content!.Url!; AssertPostContent(body.Content); } { - var res = await client.GetAsync(generator(1, "posts")); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); body.Should().HaveCount(1); var post = body[0]; post.Id.Should().Be(postId); - AssertPostContent(post.Content); + AssertPostContent(post.Content!); } { - var res = await client.GetAsync(generator(1, $"posts/{postId}/data")); - res.Content.Headers.ContentType.MediaType.Should().Be("image/png"); + var res = await client.GetAsync($"timelines/{generator(1)}/posts/{postId}/data"); + res.Content.Headers.ContentType!.MediaType.Should().Be("image/png"); var data = await res.Content.ReadAsByteArrayAsync(); var image = Image.Load(data, out var format); image.Width.Should().Be(100); @@ -716,25 +652,13 @@ namespace Timeline.Tests.IntegratedTests format.Name.Should().Be(PngFormat.Instance.Name); } - { - await CacheTestHelper.TestCache(client, generator(1, $"posts/{postId}/data")); - } + await CacheTestHelper.TestCache(client, $"timelines/{generator(1)}/posts/{postId}/data"); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}/data", true); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}/data", false); { - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().BeDelete(true); - } - - { - var res = await client.DeleteAsync(generator(1, $"posts/{postId}")); - res.Should().BeDelete(false); - } - - { - var res = await client.GetAsync(generator(1, "posts")); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEmpty(); + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts/{postId}/data"); + body.Should().BeEmpty(); } { @@ -746,83 +670,60 @@ namespace Timeline.Tests.IntegratedTests } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task ImagePost_400(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task ImagePost_400(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); - { - var res = await client.GetAsync(generator(1, "posts/11234/data")); - res.Should().HaveStatusCode(404) - .And.HaveCommonBody(ErrorCodes.TimelineController.PostNotExist); - } + await client.TestGetAssertErrorAsync($"timelines/{generator(1)}/posts/11234/data", errorCode: ErrorCodes.TimelineController.PostNotExist); long postId; { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); postId = body.Id; } - { - var res = await client.GetAsync(generator(1, $"posts/{postId}/data")); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.TimelineController.PostNoData); - } + await client.TestGetAssertErrorAsync($"timelines/{generator(1)}/posts/{postId}/data", errorCode: ErrorCodes.TimelineController.PostNoData); } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Timeline_LastModified(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task Timeline_LastModified(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); DateTime lastModified; { - var res = await client.GetAsync(generator(1)); - lastModified = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified; + var body = await client.GetTimelineAsync(generator(1)); + lastModified = body.LastModified; } await Task.Delay(1000); { - var res = await client.PatchAsJsonAsync(generator(1), new TimelinePatchRequest { Description = "123" }); - lastModified = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified.Should().BeAfter(lastModified).And.Subject.Value; + var body = await client.PatchTimelineAsync(generator(1), new() { Description = "123" }); + lastModified = body.LastModified.Should().BeAfter(lastModified).And.Subject!.Value; } { - var res = await client.GetAsync(generator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified.Should().Be(lastModified); + var body = await client.GetTimelineAsync(generator(1)); + body.LastModified.Should().Be(lastModified); } await Task.Delay(1000); - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } + await client.PutTimelineMemberAsync(generator(1), "user2"); { - var res = await client.GetAsync(generator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified.Should().BeAfter(lastModified); + var body = await client.GetTimelineAsync(generator(1)); + body.LastModified.Should().BeAfter(lastModified); } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Post_ModifiedSince(TimelineUrlGenerator generator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task Post_ModifiedSince(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); @@ -831,32 +732,24 @@ namespace Timeline.Tests.IntegratedTests foreach (var content in postContentList) { - var res = await client.PostAsJsonAsync(generator(1, "posts"), + var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); - var post = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; posts.Add(post); await Task.Delay(1000); } - { - var res = await client.DeleteAsync(generator(1, $"posts/{posts[2].Id}")); - res.Should().BeDelete(true); - } + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{posts[2].Id}", true); { - var res = await client.GetAsync(generator(1, "posts", - new Dictionary { { "modifiedSince", posts[1].LastUpdated.ToString("s", CultureInfo.InvariantCulture) } })); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which.Should().HaveCount(2) - .And.Subject.Select(p => p.Content.Text).Should().Equal("b", "d"); + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts?modifiedSince={posts[1].LastUpdated.ToString("s", CultureInfo.InvariantCulture) }"); + body.Should().HaveCount(2) + .And.Subject.Select(p => p.Content!.Text).Should().Equal("b", "d"); } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task PostList_IncludeDeleted(TimelineUrlGenerator urlGenerator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task PostList_IncludeDeleted(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); @@ -865,23 +758,18 @@ namespace Timeline.Tests.IntegratedTests foreach (var content in postContentList) { - var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); - posts.Add(res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which); + posts.Add(body); } foreach (var id in new long[] { posts[0].Id, posts[2].Id }) { - var res = await client.DeleteAsync(urlGenerator(1, $"posts/{id}")); - res.Should().BeDelete(true); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{id}", true); } { - var res = await client.GetAsync(urlGenerator(1, "posts", new Dictionary { ["includeDeleted"] = "true" })); - posts = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; + posts = await client.TestGetAsync>($"timelines/{generator(1)}/posts?includeDeleted=true"); posts.Should().HaveCount(4); posts.Select(p => p.Deleted).Should().Equal(true, false, true, false); posts.Select(p => p.Content == null).Should().Equal(true, false, true, false); @@ -889,8 +777,8 @@ namespace Timeline.Tests.IntegratedTests } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Post_ModifiedSince_And_IncludeDeleted(TimelineUrlGenerator urlGenerator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task Post_ModifiedSince_And_IncludeDeleted(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); @@ -899,29 +787,17 @@ namespace Timeline.Tests.IntegratedTests foreach (var (content, index) in postContentList.Select((v, i) => (v, i))) { - var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), + var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); - var post = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; posts.Add(post); await Task.Delay(1000); } - { - var res = await client.DeleteAsync(urlGenerator(1, $"posts/{posts[2].Id}")); - res.Should().BeDelete(true); - } + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{posts[2].Id}", true); { - var res = await client.GetAsync(urlGenerator(1, "posts", - new Dictionary { - { "modifiedSince", posts[1].LastUpdated.ToString("s", CultureInfo.InvariantCulture) }, - { "includeDeleted", "true" } - })); - posts = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; + posts = await client.TestGetAsync>($"timelines/{generator(1)}/posts?modifiedSince={posts[1].LastUpdated.ToString("s", CultureInfo.InvariantCulture)}&includeDeleted=true"); posts.Should().HaveCount(3); posts.Select(p => p.Deleted).Should().Equal(false, true, false); posts.Select(p => p.Content == null).Should().Equal(false, true, false); @@ -929,8 +805,8 @@ namespace Timeline.Tests.IntegratedTests } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Timeline_Get_IfModifiedSince_And_CheckUniqueId(TimelineUrlGenerator urlGenerator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task Timeline_Get_IfModifiedSince_And_CheckUniqueId(TimelineNameGenerator urlGenerator) { using var client = await CreateClientAsUser(); @@ -939,96 +815,71 @@ namespace Timeline.Tests.IntegratedTests string uniqueId; { - var res = await client.GetAsync(urlGenerator(1)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; + var body = await client.GetTimelineAsync(urlGenerator(1)); timeline = body; lastModifiedTime = body.LastModified; uniqueId = body.UniqueId; } { - using var req = new HttpRequestMessage - { - RequestUri = new Uri(client.BaseAddress, urlGenerator(1)), - Method = HttpMethod.Get, - }; - req.Headers.IfModifiedSince = lastModifiedTime.AddSeconds(1); - var res = await client.SendAsync(req); - res.Should().HaveStatusCode(304); + await client.TestGetAsync($"timelines/{urlGenerator(1)}", + expectedStatusCode: HttpStatusCode.NotModified, + headerSetup: (headers, _) => + { + headers.IfModifiedSince = lastModifiedTime.AddSeconds(1); + }); } { - using var req = new HttpRequestMessage - { - RequestUri = new Uri(client.BaseAddress, urlGenerator(1)), - Method = HttpMethod.Get, - }; - req.Headers.IfModifiedSince = lastModifiedTime.AddSeconds(-1); - var res = await client.SendAsync(req); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(timeline); + + var body = await client.TestGetAsync($"timelines/{urlGenerator(1)}", + expectedStatusCode: HttpStatusCode.NotModified, + headerSetup: (headers, _) => + { + headers.IfModifiedSince = lastModifiedTime.AddSeconds(-1); + }); + body.Should().BeEquivalentTo(timeline); } { - var res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) } })); - res.Should().HaveStatusCode(304); + await client.TestGetAsync($"timelines/{urlGenerator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }", expectedStatusCode: HttpStatusCode.NotModified); } { - var res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(-1).ToString("s", CultureInfo.InvariantCulture) } })); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(timeline); + var body = await client.TestGetAsync($"timelines/{urlGenerator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(-1).ToString("s", CultureInfo.InvariantCulture) }"); + body.Should().BeEquivalentTo(timeline); } { - var res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }, - {"checkUniqueId", uniqueId } })); - res.Should().HaveStatusCode(304); + await client.TestGetAsync($"timelines/{urlGenerator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }&checkUniqueId={uniqueId}", expectedStatusCode: HttpStatusCode.NotModified); } { var testUniqueId = (uniqueId[0] == 'a' ? "b" : "a") + uniqueId[1..]; - var res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }, - {"checkUniqueId", testUniqueId } })); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(timeline); + var body = await client.TestGetAsync($"timelines/{urlGenerator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }&checkUniqueId={testUniqueId}", expectedStatusCode: HttpStatusCode.NotModified); + body.Should().BeEquivalentTo(timeline); } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Title(TimelineUrlGenerator urlGenerator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task Title(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); { - var res = await client.GetAsync(urlGenerator(1)); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - timeline.Title.Should().Be(timeline.Name); + var body = await client.GetTimelineAsync(generator(1)); + body.Title.Should().Be(body.Name); } { - var res = await client.PatchAsJsonAsync(urlGenerator(1), new TimelinePatchRequest { Title = "atitle" }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Title.Should().Be("atitle"); + var body = await client.PatchTimelineAsync(generator(1), new TimelinePatchRequest { Title = "atitle" }); + body.Title.Should().Be("atitle"); } { - var res = await client.GetAsync(urlGenerator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Title.Should().Be("atitle"); + var body = await client.GetTimelineAsync(generator(1)); + body.Title.Should().Be("atitle"); } } @@ -1037,53 +888,35 @@ namespace Timeline.Tests.IntegratedTests { { using var client = await CreateDefaultClient(); - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); - res.Should().HaveStatusCode(401); + await client.TestPostAssertUnauthorizedAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); } { using var client = await CreateClientAs(2); - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); - res.Should().HaveStatusCode(403); + await client.TestPostAssertForbiddenAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); } using (var client = await CreateClientAsUser()) { - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "!!!", NewName = "tttttttt" }); - res.Should().BeInvalidModel(); - } + await client.TestPostAssertInvalidModelAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "!!!", NewName = "tttttttt" }); - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttt", NewName = "!!!!" }); - res.Should().BeInvalidModel(); - } + await client.TestPostAssertInvalidModelAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttt", NewName = "!!!!" }); - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttttt", NewName = "tttttttt" }); - res.Should().HaveStatusCode(400).And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.TimelineController.NotExist); - } + await client.TestPostAssertInvalidModelAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttttt", NewName = "tttttttt" }); + await client.TestPostAssertInvalidModelAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "newt" }); - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "newt" }); - res.Should().HaveStatusCode(200).And.HaveJsonBody().Which.Name.Should().Be("newt"); - } - - { - var res = await client.GetAsync("timelines/t1"); - res.Should().HaveStatusCode(404); - } + await client.TestGetAsync("timelines/t1", expectedStatusCode: HttpStatusCode.NotFound); { - var res = await client.GetAsync("timelines/newt"); - res.Should().HaveStatusCode(200).And.HaveJsonBody().Which.Name.Should().Be("newt"); + var body = await client.TestGetAsync("timelines/newt"); + body.Name.Should().Be("newt"); } } } [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task PostDataETag(TimelineUrlGenerator urlGenerator) + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task PostDataETag(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); @@ -1091,7 +924,7 @@ namespace Timeline.Tests.IntegratedTests string etag; { - var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), new TimelinePostCreateRequest + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { @@ -1099,19 +932,17 @@ namespace Timeline.Tests.IntegratedTests Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 50)) } }); - res.Should().HaveStatusCode(200); - var body = await res.ReadBodyAsJsonAsync(); - body.Content.ETag.Should().NotBeNullOrEmpty(); + body.Content!.ETag.Should().NotBeNullOrEmpty(); id = body.Id; - etag = body.Content.ETag; + etag = body.Content.ETag!; } { - var res = await client.GetAsync(urlGenerator(1, $"posts/{id}/data")); - res.Should().HaveStatusCode(200); + var res = await client.GetAsync($"timelines/{generator(1)}/posts{id}/data"); + res.StatusCode.Should().Be(HttpStatusCode.OK); res.Headers.ETag.Should().NotBeNull(); - res.Headers.ETag.ToString().Should().Be(etag); + res.Headers.ETag!.ToString().Should().Be(etag); } } } -- cgit v1.2.3 From 8ec508054dbd436d4e3a2c494d046067b3af6bc2 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 15 Nov 2020 02:28:35 +0800 Subject: ... --- BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs | 2 -- 1 file changed, 2 deletions(-) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs index 44a5584e..1b7ed616 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -8,8 +8,6 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; -using System.Net.Http; -using System.Net.Http.Json; using System.Threading.Tasks; using Timeline.Entities; using Timeline.Models; -- cgit v1.2.3 From 8e9b32914a1bcfe3206c13816d89d4247483ab48 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 15 Nov 2020 17:27:18 +0800 Subject: ... --- .../IntegratedTests/HttpClientTestExtensions.cs | 8 +++++- .../Timeline.Tests/IntegratedTests/TimelineTest.cs | 32 ++++++++++------------ .../Timeline.Tests/IntegratedTests/TokenTest.cs | 2 +- .../IntegratedTests/UserAvatarTest.cs | 2 +- .../IntegratedTests/UserPermissionTest.cs | 2 +- BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs | 4 +-- .../Timeline.Tests/Services/DatabaseBasedTest.cs | 2 +- .../Services/UserPermissionServiceTest.cs | 2 +- 8 files changed, 29 insertions(+), 25 deletions(-) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs index 9abe4b6b..7cff0c39 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/HttpClientTestExtensions.cs @@ -85,9 +85,15 @@ namespace Timeline.Tests.IntegratedTests public static async Task TestDeleteAsync(this HttpClient client, string url, bool? delete = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK) { - var body = await client.TestJsonSendAsync(HttpMethod.Delete, url, expectedStatusCode: expectedStatusCode); if (delete.HasValue) + { + var body = await client.TestJsonSendAsync(HttpMethod.Delete, url, expectedStatusCode: expectedStatusCode); body.Data.Delete.Should().Be(delete.Value); + } + else + { + await client.TestJsonSendAsync(HttpMethod.Delete, url, expectedStatusCode: expectedStatusCode); + } } public static async Task TestSendAssertErrorAsync(this HttpClient client, HttpMethod method, string url, HttpContent? body = null, HttpStatusCode expectedStatusCode = HttpStatusCode.BadRequest, int? errorCode = null, HeaderSetup? headerSetup = null) diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs index 1b7ed616..9845e1b1 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -651,11 +651,11 @@ namespace Timeline.Tests.IntegratedTests } await CacheTestHelper.TestCache(client, $"timelines/{generator(1)}/posts/{postId}/data"); - await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}/data", true); - await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}/data", false); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}", true); + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}", false); { - var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts/{postId}/data"); + var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); body.Should().BeEmpty(); } @@ -673,7 +673,7 @@ namespace Timeline.Tests.IntegratedTests { using var client = await CreateClientAsUser(); - await client.TestGetAssertErrorAsync($"timelines/{generator(1)}/posts/11234/data", errorCode: ErrorCodes.TimelineController.PostNotExist); + await client.TestGetAssertNotFoundAsync($"timelines/{generator(1)}/posts/11234/data", errorCode: ErrorCodes.TimelineController.PostNotExist); long postId; { @@ -804,7 +804,7 @@ namespace Timeline.Tests.IntegratedTests [Theory] [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task Timeline_Get_IfModifiedSince_And_CheckUniqueId(TimelineNameGenerator urlGenerator) + public async Task Timeline_Get_IfModifiedSince_And_CheckUniqueId(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); @@ -813,14 +813,14 @@ namespace Timeline.Tests.IntegratedTests string uniqueId; { - var body = await client.GetTimelineAsync(urlGenerator(1)); + var body = await client.GetTimelineAsync(generator(1)); timeline = body; lastModifiedTime = body.LastModified; uniqueId = body.UniqueId; } { - await client.TestGetAsync($"timelines/{urlGenerator(1)}", + await client.TestGetAsync($"timelines/{generator(1)}", expectedStatusCode: HttpStatusCode.NotModified, headerSetup: (headers, _) => { @@ -830,8 +830,7 @@ namespace Timeline.Tests.IntegratedTests { - var body = await client.TestGetAsync($"timelines/{urlGenerator(1)}", - expectedStatusCode: HttpStatusCode.NotModified, + var body = await client.TestGetAsync($"timelines/{generator(1)}", headerSetup: (headers, _) => { headers.IfModifiedSince = lastModifiedTime.AddSeconds(-1); @@ -840,21 +839,21 @@ namespace Timeline.Tests.IntegratedTests } { - await client.TestGetAsync($"timelines/{urlGenerator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }", expectedStatusCode: HttpStatusCode.NotModified); + await client.TestGetAsync($"timelines/{generator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }", expectedStatusCode: HttpStatusCode.NotModified); } { - var body = await client.TestGetAsync($"timelines/{urlGenerator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(-1).ToString("s", CultureInfo.InvariantCulture) }"); + var body = await client.TestGetAsync($"timelines/{generator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(-1).ToString("s", CultureInfo.InvariantCulture) }"); body.Should().BeEquivalentTo(timeline); } { - await client.TestGetAsync($"timelines/{urlGenerator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }&checkUniqueId={uniqueId}", expectedStatusCode: HttpStatusCode.NotModified); + await client.TestGetAsync($"timelines/{generator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }&checkUniqueId={uniqueId}", expectedStatusCode: HttpStatusCode.NotModified); } { var testUniqueId = (uniqueId[0] == 'a' ? "b" : "a") + uniqueId[1..]; - var body = await client.TestGetAsync($"timelines/{urlGenerator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }&checkUniqueId={testUniqueId}", expectedStatusCode: HttpStatusCode.NotModified); + var body = await client.TestGetAsync($"timelines/{generator(1)}?ifModifiedSince={lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }&checkUniqueId={testUniqueId}"); body.Should().BeEquivalentTo(timeline); } } @@ -897,11 +896,10 @@ namespace Timeline.Tests.IntegratedTests using (var client = await CreateClientAsUser()) { await client.TestPostAssertInvalidModelAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "!!!", NewName = "tttttttt" }); - await client.TestPostAssertInvalidModelAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttt", NewName = "!!!!" }); + await client.TestPostAssertErrorAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttttt", NewName = "tttttttt" }, errorCode: ErrorCodes.TimelineController.NotExist); - await client.TestPostAssertInvalidModelAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttttt", NewName = "tttttttt" }); - await client.TestPostAssertInvalidModelAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "newt" }); + await client.TestPostAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "newt" }); await client.TestGetAsync("timelines/t1", expectedStatusCode: HttpStatusCode.NotFound); @@ -937,7 +935,7 @@ namespace Timeline.Tests.IntegratedTests } { - var res = await client.GetAsync($"timelines/{generator(1)}/posts{id}/data"); + var res = await client.GetAsync($"timelines/{generator(1)}/posts/{id}/data"); res.StatusCode.Should().Be(HttpStatusCode.OK); res.Headers.ETag.Should().NotBeNull(); res.Headers.ETag!.ToString().Should().Be(etag); diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TokenTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TokenTest.cs index 3c4a595d..c2f91eb1 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TokenTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TokenTest.cs @@ -144,7 +144,7 @@ namespace Timeline.Tests.IntegratedTests var createTokenResult = await CreateUserTokenAsync(client, "user1", "user1pw"); var body = await client.TestPostAsync(VerifyTokenUrl, new VerifyTokenRequest { Token = createTokenResult.Token }); - body.Should().BeEquivalentTo(await client.GetUserAsync("user1")); + body.User.Should().BeEquivalentTo(await client.GetUserAsync("user1")); } } } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs index 79a3c2fa..893a5d28 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs @@ -101,7 +101,7 @@ namespace Timeline.Tests.IntegratedTests { await client.TestPutByteArrayAssertErrorAsync("users/user1/avatar", new[] { (byte)0x00 }, "image/png", errorCode: ErrorCodes.UserAvatar.BadFormat_CantDecode); - await client.TestPutByteArrayAssertErrorAsync("users/user1/avatar", mockAvatar.Data, "image/png", errorCode: ErrorCodes.UserAvatar.BadFormat_UnmatchedFormat); + await client.TestPutByteArrayAssertErrorAsync("users/user1/avatar", mockAvatar.Data, "image/jpeg", errorCode: ErrorCodes.UserAvatar.BadFormat_UnmatchedFormat); await client.TestPutByteArrayAssertErrorAsync("users/user1/avatar", ImageHelper.CreatePngWithSize(100, 200), "image/png", errorCode: ErrorCodes.UserAvatar.BadFormat_BadSize); } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs index 418dd0f9..77cae590 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs @@ -50,7 +50,7 @@ namespace Timeline.Tests.IntegratedTests await client.TestPutAsync($"users/admin/permissions/{permission}"); { - var body = await client.GetUserAsync("users/admin"); + var body = await client.GetUserAsync("admin"); body.Permissions.Should().BeEquivalentTo(Enum.GetNames()); } } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs index d13f6579..0d65478b 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs @@ -84,7 +84,7 @@ namespace Timeline.Tests.IntegratedTests } { - var body = await client.GetUserAsync("users/newuser"); + var body = await client.GetUserAsync("newuser"); body.Nickname.Should().Be("aaa"); } @@ -215,7 +215,7 @@ namespace Timeline.Tests.IntegratedTests body.Username.Should().Be("aaa"); } { - var body = await client.GetUserAsync("users/aaa"); + var body = await client.GetUserAsync("aaa"); body.Username.Should().Be("aaa"); } { diff --git a/BackEnd/Timeline.Tests/Services/DatabaseBasedTest.cs b/BackEnd/Timeline.Tests/Services/DatabaseBasedTest.cs index 7c97158c..3bb6ebb5 100644 --- a/BackEnd/Timeline.Tests/Services/DatabaseBasedTest.cs +++ b/BackEnd/Timeline.Tests/Services/DatabaseBasedTest.cs @@ -8,7 +8,7 @@ namespace Timeline.Tests.Services public abstract class DatabaseBasedTest : IAsyncLifetime { protected TestDatabase TestDatabase { get; } - protected DatabaseContext Database { get; private set; } + protected DatabaseContext Database { get; private set; } = default!; protected DatabaseBasedTest(bool databaseCreateUsers = true) { diff --git a/BackEnd/Timeline.Tests/Services/UserPermissionServiceTest.cs b/BackEnd/Timeline.Tests/Services/UserPermissionServiceTest.cs index cea11b34..5a4e4954 100644 --- a/BackEnd/Timeline.Tests/Services/UserPermissionServiceTest.cs +++ b/BackEnd/Timeline.Tests/Services/UserPermissionServiceTest.cs @@ -9,7 +9,7 @@ namespace Timeline.Tests.Services { public class UserPermissionServiceTest : DatabaseBasedTest { - private UserPermissionService _service; + private UserPermissionService _service = default!; public UserPermissionServiceTest() { -- cgit v1.2.3