From ac769e656b122ff569c3f1534701b71e00fed586 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 27 Oct 2020 19:21:35 +0800 Subject: Split front and back end. --- .../IntegratedTests/AuthorizationTest.cs | 52 - Timeline.Tests/IntegratedTests/FrontEndTest.cs | 29 - .../IntegratedTests/IntegratedTestBase.cs | 164 --- Timeline.Tests/IntegratedTests/TimelineTest.cs | 1523 -------------------- Timeline.Tests/IntegratedTests/TokenTest.cs | 165 --- .../IntegratedTests/UnknownEndpointTest.cs | 21 - Timeline.Tests/IntegratedTests/UserAvatarTest.cs | 251 ---- Timeline.Tests/IntegratedTests/UserTest.cs | 447 ------ 8 files changed, 2652 deletions(-) delete mode 100644 Timeline.Tests/IntegratedTests/AuthorizationTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/FrontEndTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/IntegratedTestBase.cs delete mode 100644 Timeline.Tests/IntegratedTests/TimelineTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/TokenTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/UnknownEndpointTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/UserAvatarTest.cs delete mode 100644 Timeline.Tests/IntegratedTests/UserTest.cs (limited to 'Timeline.Tests/IntegratedTests') diff --git a/Timeline.Tests/IntegratedTests/AuthorizationTest.cs b/Timeline.Tests/IntegratedTests/AuthorizationTest.cs deleted file mode 100644 index 38071394..00000000 --- a/Timeline.Tests/IntegratedTests/AuthorizationTest.cs +++ /dev/null @@ -1,52 +0,0 @@ -using FluentAssertions; -using System.Net; -using System.Threading.Tasks; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class AuthorizationTest : IntegratedTestBase - { - private const string BaseUrl = "testing/auth/"; - private const string AuthorizeUrl = BaseUrl + "Authorize"; - private const string UserUrl = BaseUrl + "User"; - private const string AdminUrl = BaseUrl + "Admin"; - - [Fact] - public async Task UnauthenticationTest() - { - using var client = await CreateDefaultClient(); - var response = await client.GetAsync(AuthorizeUrl); - response.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - [Fact] - public async Task AuthenticationTest() - { - using var client = await CreateClientAsUser(); - var response = await client.GetAsync(AuthorizeUrl); - response.Should().HaveStatusCode(HttpStatusCode.OK); - } - - [Fact] - public async Task UserAuthorizationTest() - { - using var client = await CreateClientAsUser(); - var response1 = await client.GetAsync(UserUrl); - response1.Should().HaveStatusCode(HttpStatusCode.OK); - var response2 = await client.GetAsync(AdminUrl); - response2.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task AdminAuthorizationTest() - { - using var client = await CreateClientAsAdministrator(); - var response1 = await client.GetAsync(UserUrl); - response1.Should().HaveStatusCode(HttpStatusCode.OK); - var response2 = await client.GetAsync(AdminUrl); - response2.Should().HaveStatusCode(HttpStatusCode.OK); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/FrontEndTest.cs b/Timeline.Tests/IntegratedTests/FrontEndTest.cs deleted file mode 100644 index 39a6e545..00000000 --- a/Timeline.Tests/IntegratedTests/FrontEndTest.cs +++ /dev/null @@ -1,29 +0,0 @@ -using FluentAssertions; -using System.Net.Mime; -using System.Threading.Tasks; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class FrontEndTest : IntegratedTestBase - { - [Fact] - public async Task Index() - { - using var client = await CreateDefaultClient(false); - var res = await client.GetAsync("index.html"); - res.Should().HaveStatusCode(200); - res.Content.Headers.ContentType.MediaType.Should().Be(MediaTypeNames.Text.Html); - } - - [Fact] - public async Task Fallback() - { - using var client = await CreateDefaultClient(false); - var res = await client.GetAsync("aaaaaaaaaaaaaaa"); - res.Should().HaveStatusCode(200); - res.Content.Headers.ContentType.MediaType.Should().Be(MediaTypeNames.Text.Html); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs b/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs deleted file mode 100644 index 7cf27297..00000000 --- a/Timeline.Tests/IntegratedTests/IntegratedTestBase.cs +++ /dev/null @@ -1,164 +0,0 @@ -using FluentAssertions; -using Microsoft.AspNetCore.TestHost; -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; -using Timeline.Models.Converters; -using Timeline.Models.Http; -using Timeline.Services; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public abstract class IntegratedTestBase : IAsyncLifetime - { - protected TestApplication TestApp { get; } - - public IReadOnlyList UserInfos { get; private set; } - - private readonly int _userCount; - - public IntegratedTestBase() : this(1) - { - - } - - public IntegratedTestBase(int userCount) - { - if (userCount < 0) - throw new ArgumentOutOfRangeException(nameof(userCount), userCount, "User count can't be negative."); - - _userCount = userCount; - - TestApp = new TestApplication(); - } - - protected virtual Task OnInitializeAsync() - { - return Task.CompletedTask; - } - - protected virtual Task OnDisposeAsync() - { - return Task.CompletedTask; - } - - protected virtual void OnDispose() - { - - } - - public async Task InitializeAsync() - { - await TestApp.InitializeAsync(); - - using (var scope = TestApp.Host.Services.CreateScope()) - { - var users = new List() - { - new User - { - Username = "admin", - Password = "adminpw", - Administrator = true, - Nickname = "administrator" - } - }; - - for (int i = 1; i <= _userCount; i++) - { - users.Add(new User - { - Username = $"user{i}", - Password = $"user{i}pw", - Administrator = false, - Nickname = $"imuser{i}" - }); - } - - var userInfoList = new List(); - - var userService = scope.ServiceProvider.GetRequiredService(); - foreach (var user in users) - { - await userService.CreateUser(user); - } - - using var client = await CreateDefaultClient(); - var options = new JsonSerializerOptions - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase - }; - options.Converters.Add(new JsonStringEnumConverter()); - options.Converters.Add(new JsonDateTimeConverter()); - foreach (var user in users) - { - var s = await client.GetStringAsync($"users/{user.Username}"); - userInfoList.Add(JsonSerializer.Deserialize(s, options)); - } - - UserInfos = userInfoList; - } - - await OnInitializeAsync(); - } - - public async Task DisposeAsync() - { - await OnDisposeAsync(); - OnDispose(); - await TestApp.DisposeAsync(); - } - - public Task CreateDefaultClient(bool setApiBase = true) - { - var client = TestApp.Host.GetTestServer().CreateClient(); - if (setApiBase) - { - client.BaseAddress = new Uri(client.BaseAddress, "api/"); - } - return Task.FromResult(client); - } - - public async Task CreateClientWithCredential(string username, string password, bool setApiBase = true) - { - var client = TestApp.Host.GetTestServer().CreateClient(); - if (setApiBase) - { - client.BaseAddress = new Uri(client.BaseAddress, "api/"); - } - var response = await client.PostAsJsonAsync("token/create", - new CreateTokenRequest { Username = username, Password = password }); - var token = response.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Token; - client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); - return client; - } - - public Task CreateClientAs(int userNumber, bool setApiBase = true) - { - if (userNumber < 0) - return CreateDefaultClient(setApiBase); - if (userNumber == 0) - return CreateClientWithCredential("admin", "adminpw", setApiBase); - else - return CreateClientWithCredential($"user{userNumber}", $"user{userNumber}pw", setApiBase); - } - - public Task CreateClientAsAdministrator(bool setApiBase = true) - { - return CreateClientAs(0, setApiBase); - } - - public Task CreateClientAsUser(bool setApiBase = true) - { - return CreateClientAs(1, setApiBase); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/TimelineTest.cs b/Timeline.Tests/IntegratedTests/TimelineTest.cs deleted file mode 100644 index ec46b96a..00000000 --- a/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ /dev/null @@ -1,1523 +0,0 @@ -using FluentAssertions; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using Timeline.Entities; -using Timeline.Models; -using Timeline.Models.Http; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public static class TimelineHelper - { - public static TimelinePostContentInfo TextPostContent(string text) - { - return new TimelinePostContentInfo - { - Type = "text", - Text = text - }; - } - - public static TimelinePostCreateRequest TextPostCreateRequest(string text, DateTime? time = null) - { - return new TimelinePostCreateRequest - { - Content = new TimelinePostCreateRequestContent - { - Type = "text", - Text = text - }, - Time = time - }; - } - } - - public class TimelineTest : IntegratedTestBase - { - public TimelineTest() : base(3) - { - } - - protected override async Task OnInitializeAsync() - { - 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); - } - } - - private static string CalculateUrlTail(string subpath, ICollection> query) - { - StringBuilder result = new StringBuilder(); - if (subpath != null) - { - if (!subpath.StartsWith("/", StringComparison.OrdinalIgnoreCase)) - result.Append('/'); - result.Append(subpath); - } - - 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('&'); - } - } - - 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 = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Owner.Should().BeEquivalentTo(UserInfos[1]); - body.Visibility.Should().Be(TimelineVisibility.Register); - body.Description.Should().Be(""); - body.Members.Should().NotBeNull().And.BeEmpty(); - var links = body._links; - links.Should().NotBeNull(); - links.Self.Should().EndWith("timelines/@user1"); - links.Posts.Should().EndWith("timelines/@user1/posts"); - } - - { - var res = await client.GetAsync("timelines/t1"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Owner.Should().BeEquivalentTo(UserInfos[1]); - body.Visibility.Should().Be(TimelineVisibility.Register); - body.Description.Should().Be(""); - body.Members.Should().NotBeNull().And.BeEmpty(); - var links = body._links; - links.Should().NotBeNull(); - links.Self.Should().EndWith("timelines/t1"); - links.Posts.Should().EndWith("timelines/t1/posts"); - } - } - - [Fact] - public async Task TimelineList() - { - TimelineInfo user1Timeline; - - var client = await CreateDefaultClient(); - - { - var res = await client.GetAsync("timelines/@user1"); - user1Timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - } - - { - 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); - } - } - - [Fact] - public async Task TimelineList_WithQuery() - { - var testResultRelate = new List(); - var testResultOwn = new List(); - var testResultJoin = new List(); - var testResultOwnPrivate = new List(); - var testResultRelatePublic = new List(); - var testResultRelateRegister = new List(); - var testResultJoinPrivate = new List(); - 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); - } - - { - var res = await client.PatchAsJsonAsync("timelines/@user1", new TimelinePatchRequest { Visibility = TimelineVisibility.Public }); - res.Should().HaveStatusCode(200); - } - - { - 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; - testResultRelate.Add(timeline); - testResultJoin.Add(timeline); - testResultRelatePublic.Add(timeline); - testResultPublic.Add(timeline); - } - - { - var res = await client.GetAsync("timelines/t1"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - testResultRelate.Add(timeline); - testResultJoin.Add(timeline); - testResultRelateRegister.Add(timeline); - } - } - - { - 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); - } - - { - var res = await client.PatchAsJsonAsync("timelines/t2", new TimelinePatchRequest { Visibility = TimelineVisibility.Private }); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.GetAsync("timelines/@user2"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - 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; - testResultRelate.Add(timeline); - testResultJoin.Add(timeline); - testResultJoinPrivate.Add(timeline); - } - } - - { - 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); - } - - { - var res = await client.GetAsync("timelines/@user3"); - var timeline = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - 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; - testResultRelate.Add(timeline); - testResultOwn.Add(timeline); - testResultRelateRegister.Add(timeline); - } - } - - { - 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); - } - - { - 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("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(); - } - } - - [Fact] - public async Task TimelineCreate_Should_Work() - { - { - using var client = await CreateDefaultClient(); - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - using (var client = await CreateClientAsUser()) - { - { - var res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "!!!" }); - res.Should().BeInvalidModel(); - } - - 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 res = await client.PostAsJsonAsync("timelines", new TimelineCreateRequest { Name = "aaa" }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.TimelineController.NameConflict); - } - } - } - - [Fact] - public async Task TimelineDelete_Should_Work() - { - { - using var client = await CreateDefaultClient(); - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - { - using var client = await CreateClientAs(2); - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - { - using var client = await CreateClientAsAdministrator(); - - { - var res = await client.DeleteAsync("timelines/!!!"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.DeleteAsync("timelines/t2"); - res.Should().BeDelete(true); - } - - { - var res = await client.DeleteAsync("timelines/t2"); - res.Should().BeDelete(false); - } - } - - { - using var client = await CreateClientAs(1); - - { - var res = await client.DeleteAsync("timelines/!!!"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.DeleteAsync("timelines/t1"); - res.Should().BeDelete(true); - } - - { - var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(400); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlByNameGeneratorData))] - public async Task InvalidModel_BadName(Func generator) - { - 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(); - } - { - var res = await client.GetAsync(generator("aaa!!!", "posts/123/data")); - res.Should().BeInvalidModel(); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlByNameGeneratorData))] - public async Task Ordinary_NotFound(Func generator) - { - var errorCode = generator == GenerateOrdinaryTimelineUrlByName ? ErrorCodes.TimelineController.NotExist : ErrorCodes.UserCommon.NotExist; - - 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 res = await client.GetAsync(generator("notexist", "posts/123/data")); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); - } - } - - [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); - } - - 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 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 res = await client.PatchAsJsonAsync(generator(1, null), - new TimelinePatchRequest { Description = "" }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which.Description.Should().Be(""); - await AssertDescription(""); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Member_Should_Work(TimelineUrlGenerator generator) - { - var getUrl = generator(1, null); - using var client = await CreateClientAsUser(); - - async Task AssertMembers(IList members) - { - var res = await client.GetAsync(getUrl); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.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(); - } - - await AssertEmptyMembers(); - { - var res = await client.PutAsync(generator(1, "members/usernotexist"), null); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(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 AssertEmptyMembers(); - { - var res = await client.DeleteAsync(generator(1, "members/aaa")); - res.Should().BeDelete(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) - { - 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); - } - - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(200); - } - } - - { // 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); - } - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(200); - } - } - - { // 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); - } - } - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(403); - } - { // user can't read admin's - using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(403); - } - { // admin can read user's - using var client = await CreateClientAsAdministrator(); - var res = await client.GetAsync(userUrl); - res.Should().HaveStatusCode(200); - } - { // add member - using var client = await CreateClientAsAdministrator(); - var res = await client.PutAsync(generator(0, "members/user1"), null); - res.Should().HaveStatusCode(200); - } - { // now user can read admin's - using var client = await CreateClientAsUser(); - var res = await client.GetAsync(adminUrl); - res.Should().HaveStatusCode(200); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Permission_Post_Create(TimelineUrlGenerator generator) - { - using (var client = await CreateClientAsUser()) - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } - - 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); - } - } - - 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); - } - } - - using (var client = await CreateClientAsAdministrator()) - { - { // post as admin - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(200); - } - } - - using (var client = await CreateClientAs(2)) - { - { // post as member - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(200); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Permission_Post_Delete(TimelineUrlGenerator 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; - } - - 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); - } - } - - { // no auth should get 401 - using var client = await CreateDefaultClient(); - var res = await client.DeleteAsync(generator(1, "posts/12")); - res.Should().HaveStatusCode(401); - } - - { // 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); - } - - { // 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); - } - - { // 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); - } - - { // 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); - } - - { // 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); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task TextPost_ShouldWork(TimelineUrlGenerator generator) - { - { - 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); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task GetPost_Should_Ordered(TimelineUrlGenerator 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 now = DateTime.UtcNow; - var id0 = await CreatePost(now.AddDays(1)); - var id1 = await CreatePost(now.AddDays(-1)); - 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); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task CreatePost_InvalidModel(TimelineUrlGenerator 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(); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task ImagePost_ShouldWork(TimelineUrlGenerator generator) - { - var imageData = ImageHelper.CreatePngWithSize(100, 200); - - long postId; - string postImageUrl; - - void AssertPostContent(TimelinePostContentInfo content) - { - content.Type.Should().Be(TimelinePostContentTypes.Image); - content.Url.Should().EndWith(generator(1, $"posts/{postId}/data")); - content.Text.Should().Be(null); - } - - using var client = await CreateClientAsUser(); - - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - new TimelinePostCreateRequest - { - Content = new TimelinePostCreateRequestContent - { - Type = TimelinePostContentTypes.Image, - Data = Convert.ToBase64String(imageData) - } - }); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - postId = body.Id; - postImageUrl = body.Content.Url; - AssertPostContent(body.Content); - } - - { - var res = await client.GetAsync(generator(1, "posts")); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Should().HaveCount(1); - var post = body[0]; - post.Id.Should().Be(postId); - AssertPostContent(post.Content); - } - - { - var res = await client.GetAsync(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); - image.Height.Should().Be(200); - format.Name.Should().Be(PngFormat.Instance.Name); - } - - { - await CacheTestHelper.TestCache(client, generator(1, $"posts/{postId}/data")); - } - - { - 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(); - } - - { - using var scope = TestApp.Host.Services.CreateScope(); - var database = scope.ServiceProvider.GetRequiredService(); - var count = await database.Data.CountAsync(); - count.Should().Be(0); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task ImagePost_400(TimelineUrlGenerator 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); - } - - long postId; - { - var res = await client.PostAsJsonAsync(generator(1, "posts"), - TimelineHelper.TextPostCreateRequest("aaa")); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - postId = body.Id; - } - - { - var res = await client.GetAsync(generator(1, $"posts/{postId}/data")); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.TimelineController.PostNoData); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Timeline_LastModified(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - - DateTime lastModified; - - { - var res = await client.GetAsync(generator(1)); - lastModified = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.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 res = await client.GetAsync(generator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified.Should().Be(lastModified); - } - - await Task.Delay(1000); - - { - var res = await client.PutAsync(generator(1, "members/user2"), null); - res.Should().HaveStatusCode(200); - } - - { - var res = await client.GetAsync(generator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.LastModified.Should().BeAfter(lastModified); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Post_ModifiedSince(TimelineUrlGenerator generator) - { - using var client = await CreateClientAsUser(); - - var postContentList = new List { "a", "b", "c", "d" }; - var posts = new List(); - - foreach (var content in postContentList) - { - var res = await client.PostAsJsonAsync(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); - } - - { - 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"); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task PostList_IncludeDeleted(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - var postContentList = new List { "a", "b", "c", "d" }; - var posts = new List(); - - foreach (var content in postContentList) - { - var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), - new TimelinePostCreateRequest { Content = new TimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); - posts.Add(res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which); - } - - 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); - } - - { - var res = await client.GetAsync(urlGenerator(1, "posts", new Dictionary { ["includeDeleted"] = "true" })); - posts = res.Should().HaveStatusCode(200) - .And.HaveJsonBody>() - .Which; - 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); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Post_ModifiedSince_And_IncludeDeleted(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - var postContentList = new List { "a", "b", "c", "d" }; - var posts = new List(); - - foreach (var (content, index) in postContentList.Select((v, i) => (v, i))) - { - var res = await client.PostAsJsonAsync(urlGenerator(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); - } - - { - - 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.Should().HaveCount(3); - posts.Select(p => p.Deleted).Should().Equal(false, true, false); - posts.Select(p => p.Content == null).Should().Equal(false, true, false); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Timeline_Get_IfModifiedSince_And_CheckUniqueId(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - DateTime lastModifiedTime; - TimelineInfo timeline; - string uniqueId; - - { - var res = await client.GetAsync(urlGenerator(1)); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - 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); - } - - { - 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 res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) } })); - res.Should().HaveStatusCode(304); - } - - { - 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 res = await client.GetAsync(urlGenerator(1, null, - new Dictionary { { "ifModifiedSince", lastModifiedTime.AddSeconds(1).ToString("s", CultureInfo.InvariantCulture) }, - {"checkUniqueId", uniqueId } })); - res.Should().HaveStatusCode(304); - } - - { - 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); - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task Title(TimelineUrlGenerator urlGenerator) - { - 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 res = await client.PatchAsJsonAsync(urlGenerator(1), new TimelinePatchRequest { Title = "atitle" }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Title.Should().Be("atitle"); - } - - { - var res = await client.GetAsync(urlGenerator(1)); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Title.Should().Be("atitle"); - } - } - - [Fact] - public async Task ChangeName() - { - { - using var client = await CreateDefaultClient(); - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); - res.Should().HaveStatusCode(401); - } - - { - using var client = await CreateClientAs(2); - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); - res.Should().HaveStatusCode(403); - } - - using (var client = await CreateClientAsUser()) - { - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "!!!", NewName = "tttttttt" }); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttt", NewName = "!!!!" }); - res.Should().BeInvalidModel(); - } - - { - 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); - } - - { - 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); - } - - { - var res = await client.GetAsync("timelines/newt"); - res.Should().HaveStatusCode(200).And.HaveJsonBody().Which.Name.Should().Be("newt"); - } - } - } - - [Theory] - [MemberData(nameof(TimelineUrlGeneratorData))] - public async Task PostDataETag(TimelineUrlGenerator urlGenerator) - { - using var client = await CreateClientAsUser(); - - long id; - string etag; - - { - var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), new TimelinePostCreateRequest - { - Content = new TimelinePostCreateRequestContent - { - Type = TimelinePostContentTypes.Image, - Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 50)) - } - }); - res.Should().HaveStatusCode(200); - var body = await res.ReadBodyAsJsonAsync(); - body.Content.ETag.Should().NotBeNullOrEmpty(); - - id = body.Id; - etag = body.Content.ETag; - } - - { - var res = await client.GetAsync(urlGenerator(1, $"posts/{id}/data")); - res.Should().HaveStatusCode(200); - res.Headers.ETag.Should().NotBeNull(); - res.Headers.ETag.ToString().Should().Be(etag); - } - } - } -} diff --git a/Timeline.Tests/IntegratedTests/TokenTest.cs b/Timeline.Tests/IntegratedTests/TokenTest.cs deleted file mode 100644 index 480d66cd..00000000 --- a/Timeline.Tests/IntegratedTests/TokenTest.cs +++ /dev/null @@ -1,165 +0,0 @@ -using FluentAssertions; -using Microsoft.Extensions.DependencyInjection; -using System.Collections.Generic; -using System.Net.Http; -using System.Threading.Tasks; -using Timeline.Models; -using Timeline.Models.Http; -using Timeline.Services; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class TokenTest : IntegratedTestBase - { - private const string CreateTokenUrl = "token/create"; - private const string VerifyTokenUrl = "token/verify"; - - private static async Task CreateUserTokenAsync(HttpClient client, string username, string password, int? expireOffset = null) - { - var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = username, Password = password, Expire = expireOffset }); - return response.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - } - - public static IEnumerable CreateToken_InvalidModel_Data() - { - yield return new[] { null, "p", null }; - yield return new[] { "u", null, null }; - yield return new object[] { "u", "p", 2000 }; - yield return new object[] { "u", "p", -1 }; - } - - [Theory] - [MemberData(nameof(CreateToken_InvalidModel_Data))] - public async Task CreateToken_InvalidModel(string username, string password, int expire) - { - using var client = await CreateDefaultClient(); - (await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest - { - Username = username, - Password = password, - Expire = expire - })).Should().BeInvalidModel(); - } - - public static IEnumerable CreateToken_UserCredential_Data() - { - yield return new[] { "usernotexist", "p" }; - yield return new[] { "user1", "???" }; - } - - [Theory] - [MemberData(nameof(CreateToken_UserCredential_Data))] - public async void CreateToken_UserCredential(string username, string password) - { - using var client = await CreateDefaultClient(); - var response = await client.PostAsJsonAsync(CreateTokenUrl, - new CreateTokenRequest { Username = username, Password = password }); - response.Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.TokenController.Create_BadCredential); - } - - [Fact] - public async Task CreateToken_Success() - { - using var client = await CreateDefaultClient(); - var response = await client.PostAsJsonAsync(CreateTokenUrl, - new CreateTokenRequest { Username = "user1", Password = "user1pw" }); - var body = response.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Token.Should().NotBeNullOrWhiteSpace(); - body.User.Should().BeEquivalentTo(UserInfos[1]); - } - - [Fact] - public async Task VerifyToken_InvalidModel() - { - using var client = await CreateDefaultClient(); - (await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = null })).Should().BeInvalidModel(); - } - - [Fact] - public async Task VerifyToken_BadFormat() - { - using var client = await CreateDefaultClient(); - var response = await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = "bad token hahaha" }); - response.Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.TokenController.Verify_BadFormat); - } - - [Fact] - public async Task VerifyToken_OldVersion() - { - using var client = await CreateDefaultClient(); - var token = (await CreateUserTokenAsync(client, "user1", "user1pw")).Token; - - using (var scope = TestApp.Host.Services.CreateScope()) // UserService is scoped. - { - // create a user for test - var userService = scope.ServiceProvider.GetRequiredService(); - await userService.ModifyUser("user1", new User { Password = "user1pw" }); - } - - (await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = token })) - .Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.TokenController.Verify_OldVersion); - } - - [Fact] - public async Task VerifyToken_UserNotExist() - { - using var client = await CreateDefaultClient(); - var token = (await CreateUserTokenAsync(client, "user1", "user1pw")).Token; - - using (var scope = TestApp.Host.Services.CreateScope()) // UserDeleteService is scoped. - { - var userService = scope.ServiceProvider.GetRequiredService(); - await userService.DeleteUser("user1"); - } - - (await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = token })) - .Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.TokenController.Verify_UserNotExist); - } - - //[Fact] - //public async Task VerifyToken_Expired() - //{ - // using (var client = await CreateClientWithNoAuth()) - // { - // // I can only control the token expired time but not current time - // // because verify logic is encapsuled in other library. - // var mockClock = _factory.GetTestClock(); - // mockClock.MockCurrentTime = DateTime.Now - TimeSpan.FromDays(2); - // var token = (await client.CreateUserTokenAsync(MockUsers.UserUsername, MockUsers.UserPassword, 1)).Token; - // var response = await client.PostAsJsonAsync(VerifyTokenUrl, - // new VerifyTokenRequest { Token = token }); - // response.Should().HaveStatusCodeBadRequest() - // .And.Should().HaveBodyAsCommonResponseWithCode(TokenController.ErrorCodes.Verify_Expired); - // mockClock.MockCurrentTime = null; - // } - //} - - [Fact] - public async Task VerifyToken_Success() - { - using var client = await CreateDefaultClient(); - var createTokenResult = await CreateUserTokenAsync(client, "user1", "user1pw"); - var response = await client.PostAsJsonAsync(VerifyTokenUrl, - new VerifyTokenRequest { Token = createTokenResult.Token }); - response.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.User.Should().BeEquivalentTo(UserInfos[1]); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/UnknownEndpointTest.cs b/Timeline.Tests/IntegratedTests/UnknownEndpointTest.cs deleted file mode 100644 index 732232e2..00000000 --- a/Timeline.Tests/IntegratedTests/UnknownEndpointTest.cs +++ /dev/null @@ -1,21 +0,0 @@ -using FluentAssertions; -using System.Threading.Tasks; -using Timeline.Models.Http; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class UnknownEndpointTest : IntegratedTestBase - { - [Fact] - public async Task UnknownEndpoint() - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync("unknownEndpoint"); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.Common.UnknownEndpoint); - } - } -} diff --git a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs b/Timeline.Tests/IntegratedTests/UserAvatarTest.cs deleted file mode 100644 index f2796005..00000000 --- a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs +++ /dev/null @@ -1,251 +0,0 @@ -using FluentAssertions; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Gif; -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.Formats.Png; -using System.Collections.Generic; -using System.IO; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Mime; -using System.Threading.Tasks; -using Timeline.Models.Http; -using Timeline.Services; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class UserAvatarTest : IntegratedTestBase - { - [Fact] - public async Task Test() - { - Avatar mockAvatar = new Avatar - { - Data = ImageHelper.CreatePngWithSize(100, 100), - Type = PngFormat.Instance.DefaultMimeType - }; - - using (var client = await CreateClientAsUser()) - { - { - var res = await client.GetAsync("users/usernotexist/avatar"); - res.Should().HaveStatusCode(404) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.UserCommon.NotExist); - } - - var env = TestApp.Host.Services.GetRequiredService(); - var defaultAvatarData = await File.ReadAllBytesAsync(Path.Combine(env.ContentRootPath, "default-avatar.png")); - - async Task GetReturnDefault(string username = "user1") - { - var res = await client.GetAsync($"users/{username}/avatar"); - res.Should().HaveStatusCode(200); - res.Content.Headers.ContentType.MediaType.Should().Be("image/png"); - var body = await res.Content.ReadAsByteArrayAsync(); - body.Should().Equal(defaultAvatarData); - } - - { - var res = await client.GetAsync("users/user1/avatar"); - res.Should().HaveStatusCode(200); - res.Content.Headers.ContentType.MediaType.Should().Be("image/png"); - var body = await res.Content.ReadAsByteArrayAsync(); - body.Should().Equal(defaultAvatarData); - } - - await CacheTestHelper.TestCache(client, "users/user1/avatar"); - - await GetReturnDefault("admin"); - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentLength = 1; - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentLength = 0; - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", new[] { (byte)0x00 }, "image/notaccept"); - res.Should().HaveStatusCode(HttpStatusCode.UnsupportedMediaType); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentLength = 1000 * 1000 * 11; - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Common.Content.TooBig); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00 }); - content.Headers.ContentLength = 2; - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - using var content = new ByteArrayContent(new[] { (byte)0x00, (byte)0x01 }); - content.Headers.ContentLength = 1; - content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); - var res = await client.PutAsync("users/user1/avatar", content); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", new[] { (byte)0x00 }, "image/png"); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.UserAvatar.BadFormat_CantDecode); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", mockAvatar.Data, "image/jpeg"); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.UserAvatar.BadFormat_UnmatchedFormat); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", ImageHelper.CreatePngWithSize(100, 200), "image/png"); - res.Should().HaveStatusCode(HttpStatusCode.BadRequest) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.UserAvatar.BadFormat_BadSize); - } - - { - var res = await client.PutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.Type); - res.Should().HaveStatusCode(HttpStatusCode.OK); - - var res2 = await client.GetAsync("users/user1/avatar"); - res2.Should().HaveStatusCode(200); - res2.Content.Headers.ContentType.MediaType.Should().Be(mockAvatar.Type); - var body = await res2.Content.ReadAsByteArrayAsync(); - body.Should().Equal(mockAvatar.Data); - } - - IEnumerable<(string, IImageFormat)> formats = new (string, IImageFormat)[] - { - ("image/jpeg", JpegFormat.Instance), - ("image/gif", GifFormat.Instance), - ("image/png", PngFormat.Instance), - }; - - foreach ((var mimeType, var format) in formats) - { - var res = await client.PutByteArrayAsync("users/user1/avatar", ImageHelper.CreateImageWithSize(100, 100, format), mimeType); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } - - { - var res = await client.PutByteArrayAsync("users/admin/avatar", new[] { (byte)0x00 }, "image/png"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Common.Forbid); - } - - { - var res = await client.DeleteAsync("users/admin/avatar"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.Common.Forbid); - } - - for (int i = 0; i < 2; i++) // double delete should work. - { - var res = await client.DeleteAsync("users/user1/avatar"); - res.Should().HaveStatusCode(200); - await GetReturnDefault(); - } - } - - // Authorization check. - using (var client = await CreateClientAsAdministrator()) - { - { - var res = await client.PutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.Type); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } - - { - var res = await client.DeleteAsync("users/user1/avatar"); - res.Should().HaveStatusCode(HttpStatusCode.OK); - } - - { - var res = await client.PutByteArrayAsync("users/usernotexist/avatar", new[] { (byte)0x00 }, "image/png"); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.UserCommon.NotExist); - } - - { - var res = await client.DeleteAsync("users/usernotexist/avatar"); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.UserCommon.NotExist); - } - } - - // bad username check - using (var client = await CreateClientAsAdministrator()) - { - { - var res = await client.GetAsync("users/u!ser/avatar"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.PutByteArrayAsync("users/u!ser/avatar", ImageHelper.CreatePngWithSize(100, 100), "image/png"); - res.Should().BeInvalidModel(); - } - - { - var res = await client.DeleteAsync("users/u!ser/avatar"); - res.Should().BeInvalidModel(); - } - } - } - - [Fact] - public async Task AvatarPutReturnETag() - { - using var client = await CreateClientAsUser(); - - EntityTagHeaderValue etag; - - { - var image = ImageHelper.CreatePngWithSize(100, 100); - var res = await client.PutByteArrayAsync("users/user1/avatar", image, PngFormat.Instance.DefaultMimeType); - res.Should().HaveStatusCode(200); - etag = res.Headers.ETag; - etag.Should().NotBeNull(); - etag.Tag.Should().NotBeNullOrEmpty(); - } - - { - var res = await client.GetAsync("users/user1/avatar"); - res.Should().HaveStatusCode(200); - res.Headers.ETag.Should().Be(etag); - res.Headers.ETag.Tag.Should().Be(etag.Tag); - } - } - } -} \ No newline at end of file diff --git a/Timeline.Tests/IntegratedTests/UserTest.cs b/Timeline.Tests/IntegratedTests/UserTest.cs deleted file mode 100644 index 9dfcc6a5..00000000 --- a/Timeline.Tests/IntegratedTests/UserTest.cs +++ /dev/null @@ -1,447 +0,0 @@ -using FluentAssertions; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Threading.Tasks; -using Timeline.Models.Http; -using Timeline.Tests.Helpers; -using Xunit; - -namespace Timeline.Tests.IntegratedTests -{ - public class UserTest : IntegratedTestBase - { - [Fact] - public void UserListShouldHaveUniqueId() - { - foreach (var user in UserInfos) - { - user.UniqueId.Should().NotBeNullOrWhiteSpace(); - } - } - - [Fact] - public async Task GetList_NoAuth() - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync("users"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos); - } - - [Fact] - public async Task GetList_User() - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync("users"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos); - } - - [Fact] - public async Task GetList_Admin() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.GetAsync("users"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos); - } - - [Fact] - public async Task Get_NoAuth() - { - using var client = await CreateDefaultClient(); - var res = await client.GetAsync($"users/admin"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos[0]); - } - - [Fact] - public async Task Get_User() - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync($"users/admin"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos[0]); - } - - [Fact] - public async Task Get_Admin() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.GetAsync($"users/user1"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Should().BeEquivalentTo(UserInfos[1]); - } - - [Fact] - public async Task Get_InvalidModel() - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync("users/aaa!a"); - res.Should().BeInvalidModel(); - } - - [Fact] - public async Task Get_404() - { - using var client = await CreateClientAsUser(); - var res = await client.GetAsync("users/usernotexist"); - res.Should().HaveStatusCode(404) - .And.HaveCommonBody(ErrorCodes.UserCommon.NotExist); - } - - [Fact] - public async Task Patch_User() - { - using var client = await CreateClientAsUser(); - { - var res = await client.PatchAsJsonAsync("users/user1", - new UserPatchRequest { Nickname = "aaa" }); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Nickname.Should().Be("aaa"); - } - - { - var res = await client.GetAsync("users/user1"); - res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which.Nickname.Should().Be("aaa"); - } - } - - [Fact] - public async Task Patch_Admin() - { - using var client = await CreateClientAsAdministrator(); - using var userClient = await CreateClientAsUser(); - - { - var res = await client.PatchAsJsonAsync("users/user1", - new UserPatchRequest - { - Username = "newuser", - Password = "newpw", - Administrator = true, - Nickname = "aaa" - }); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - body.Administrator.Should().Be(true); - body.Nickname.Should().Be("aaa"); - } - - { - var res = await client.GetAsync("users/newuser"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody() - .Which; - body.Administrator.Should().Be(true); - body.Nickname.Should().Be("aaa"); - } - - { - // Token should expire. - var res = await userClient.GetAsync("testing/auth/Authorize"); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - { - // Check password. - (await CreateClientWithCredential("newuser", "newpw")).Dispose(); - } - } - - [Fact] - public async Task Patch_NotExist() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.PatchAsJsonAsync("users/usernotexist", new UserPatchRequest { }); - res.Should().HaveStatusCode(404) - .And.HaveCommonBody() - .Which.Code.Should().Be(ErrorCodes.UserCommon.NotExist); - } - - [Fact] - public async Task Patch_InvalidModel() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.PatchAsJsonAsync("users/aaa!a", new UserPatchRequest { }); - res.Should().BeInvalidModel(); - } - - public static IEnumerable Patch_InvalidModel_Body_Data() - { - yield return new[] { new UserPatchRequest { Username = "aaa!a" } }; - yield return new[] { new UserPatchRequest { Password = "" } }; - yield return new[] { new UserPatchRequest { Nickname = new string('a', 50) } }; - } - - [Theory] - [MemberData(nameof(Patch_InvalidModel_Body_Data))] - public async Task Patch_InvalidModel_Body(UserPatchRequest body) - { - using var client = await CreateClientAsAdministrator(); - var res = await client.PatchAsJsonAsync("users/user1", body); - res.Should().BeInvalidModel(); - } - - [Fact] - public async Task Patch_UsernameConflict() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Username = "admin" }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.UserController.UsernameConflict); - } - - [Fact] - public async Task Patch_NoAuth_Unauthorized() - { - using var client = await CreateDefaultClient(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Nickname = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - [Fact] - public async Task Patch_User_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync("users/admin", new UserPatchRequest { Nickname = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task Patch_Username_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Username = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task Patch_Password_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Password = "aaa" }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task Patch_Administrator_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { Administrator = true }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - [Fact] - public async Task Delete_Deleted() - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.DeleteAsync("users/user1"); - res.Should().BeDelete(true); - } - - { - var res = await client.GetAsync("users/user1"); - res.Should().HaveStatusCode(404); - } - } - - [Fact] - public async Task Delete_NotExist() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.DeleteAsync("users/usernotexist"); - res.Should().BeDelete(false); - } - - [Fact] - public async Task Delete_InvalidModel() - { - using var client = await CreateClientAsAdministrator(); - var res = await client.DeleteAsync("users/aaa!a"); - res.Should().BeInvalidModel(); - } - - [Fact] - public async Task Delete_NoAuth_Unauthorized() - { - using var client = await CreateDefaultClient(); - var res = await client.DeleteAsync("users/aaa!a"); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - - [Fact] - public async Task Delete_User_Forbid() - { - using var client = await CreateClientAsUser(); - var res = await client.DeleteAsync("users/aaa!a"); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - - private const string createUserUrl = "userop/createuser"; - - [Fact] - public async Task Op_CreateUser() - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.PostAsJsonAsync(createUserUrl, new CreateUserRequest - { - Username = "aaa", - Password = "bbb", - Administrator = true, - Nickname = "ccc" - }); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Username.Should().Be("aaa"); - body.Nickname.Should().Be("ccc"); - body.Administrator.Should().BeTrue(); - } - { - var res = await client.GetAsync("users/aaa"); - var body = res.Should().HaveStatusCode(200) - .And.HaveJsonBody().Which; - body.Username.Should().Be("aaa"); - body.Nickname.Should().Be("ccc"); - body.Administrator.Should().BeTrue(); - } - { - // Test password. - (await CreateClientWithCredential("aaa", "bbb")).Dispose(); - } - } - - public static IEnumerable Op_CreateUser_InvalidModel_Data() - { - yield return new[] { new CreateUserRequest { Username = "aaa", Password = "bbb" } }; - yield return new[] { new CreateUserRequest { Username = "aaa", Administrator = true } }; - yield return new[] { new CreateUserRequest { Password = "bbb", Administrator = true } }; - yield return new[] { new CreateUserRequest { Username = "a!a", Password = "bbb", Administrator = true } }; - yield return new[] { new CreateUserRequest { Username = "aaa", Password = "", Administrator = true } }; - yield return new[] { new CreateUserRequest { Username = "aaa", Password = "bbb", Administrator = true, Nickname = new string('a', 40) } }; - } - - [Theory] - [MemberData(nameof(Op_CreateUser_InvalidModel_Data))] - public async Task Op_CreateUser_InvalidModel(CreateUserRequest body) - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.PostAsJsonAsync(createUserUrl, body); - res.Should().BeInvalidModel(); - } - } - - [Fact] - public async Task Op_CreateUser_UsernameConflict() - { - using var client = await CreateClientAsAdministrator(); - { - var res = await client.PostAsJsonAsync(createUserUrl, new CreateUserRequest - { - Username = "user1", - Password = "bbb", - Administrator = false - }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.UserController.UsernameConflict); - } - } - - [Fact] - public async Task Op_CreateUser_NoAuth_Unauthorized() - { - using var client = await CreateDefaultClient(); - { - var res = await client.PostAsJsonAsync(createUserUrl, new CreateUserRequest - { - Username = "aaa", - Password = "bbb", - Administrator = false - }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - } - - [Fact] - public async Task Op_CreateUser_User_Forbid() - { - using var client = await CreateClientAsUser(); - { - var res = await client.PostAsJsonAsync(createUserUrl, new CreateUserRequest - { - Username = "aaa", - Password = "bbb", - Administrator = false - }); - res.Should().HaveStatusCode(HttpStatusCode.Forbidden); - } - } - - private const string changePasswordUrl = "userop/changepassword"; - - [Fact] - public async Task Op_ChangePassword() - { - using var client = await CreateClientAsUser(); - { - var res = await client.PostAsJsonAsync(changePasswordUrl, - new ChangePasswordRequest { OldPassword = "user1pw", NewPassword = "newpw" }); - res.Should().HaveStatusCode(200); - } - { - var res = await client.PatchAsJsonAsync("users/user1", new UserPatchRequest { }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - { - (await CreateClientWithCredential("user1", "newpw")).Dispose(); - } - } - - public static IEnumerable Op_ChangePassword_InvalidModel_Data() - { - yield return new[] { null, "ppp" }; - yield return new[] { "ppp", null }; - } - - [Theory] - [MemberData(nameof(Op_ChangePassword_InvalidModel_Data))] - public async Task Op_ChangePassword_InvalidModel(string oldPassword, string newPassword) - { - using var client = await CreateClientAsUser(); - var res = await client.PostAsJsonAsync(changePasswordUrl, - new ChangePasswordRequest { OldPassword = oldPassword, NewPassword = newPassword }); - res.Should().BeInvalidModel(); - } - - [Fact] - public async Task Op_ChangePassword_BadOldPassword() - { - using var client = await CreateClientAsUser(); - var res = await client.PostAsJsonAsync(changePasswordUrl, new ChangePasswordRequest { OldPassword = "???", NewPassword = "???" }); - res.Should().HaveStatusCode(400) - .And.HaveCommonBody(ErrorCodes.UserController.ChangePassword_BadOldPassword); - } - - [Fact] - public async Task Op_ChangePassword_NoAuth_Unauthorized() - { - using var client = await CreateDefaultClient(); - var res = await client.PostAsJsonAsync(changePasswordUrl, new ChangePasswordRequest { OldPassword = "???", NewPassword = "???" }); - res.Should().HaveStatusCode(HttpStatusCode.Unauthorized); - } - } -} -- cgit v1.2.3