From 4ea535d93753826ec900879560d876cec4d58c38 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 10 Feb 2021 02:03:06 +0800 Subject: ... --- BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index 17c85f22..4caff416 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -108,7 +108,7 @@ namespace Timeline.Tests.IntegratedTests foreach (var content in postContentList) { var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); + new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostDataKind.Text } }); posts.Add(post); await Task.Delay(1000); } @@ -134,7 +134,7 @@ namespace Timeline.Tests.IntegratedTests foreach (var (content, index) in postContentList.Select((v, i) => (v, i))) { var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); + new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostDataKind.Text } }); posts.Add(post); await Task.Delay(1000); } @@ -162,7 +162,7 @@ namespace Timeline.Tests.IntegratedTests foreach (var content in postContentList) { var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostContentTypes.Text } }); + new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostDataKind.Text } }); posts.Add(body); } @@ -367,7 +367,7 @@ namespace Timeline.Tests.IntegratedTests void AssertPostContent(HttpTimelinePostContent content) { - content.Type.Should().Be(TimelinePostContentTypes.Image); + content.Type.Should().Be(TimelinePostDataKind.Image); content.Url.Should().EndWith($"timelines/{generator(1)}/posts/{postId}/data"); content.Text.Should().Be(null); } @@ -380,7 +380,7 @@ namespace Timeline.Tests.IntegratedTests { Content = new HttpTimelinePostCreateRequestContent { - Type = TimelinePostContentTypes.Image, + Type = TimelinePostDataKind.Image, Data = Convert.ToBase64String(imageData) } }); @@ -455,7 +455,7 @@ namespace Timeline.Tests.IntegratedTests { Content = new HttpTimelinePostCreateRequestContent { - Type = TimelinePostContentTypes.Image, + Type = TimelinePostDataKind.Image, Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 50)) } }); -- cgit v1.2.3 From b5376f71157f68f06aa04bde79389f9ab291d84a Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 11 Feb 2021 22:21:12 +0800 Subject: ... --- .../IntegratedTests/TimelinePostTest.cs | 338 ++++----------------- .../IntegratedTests/UserAvatarTest.cs | 17 +- .../Timeline/Controllers/UserAvatarController.cs | 4 +- BackEnd/Timeline/Entities/TimelinePostEntity.cs | 2 + .../Timeline/Formatters/ByteDataInputFormatter.cs | 6 + BackEnd/Timeline/Models/Http/HttpTimelinePost.cs | 5 + .../Models/Http/HttpTimelinePostCreateRequest.cs | 2 + BackEnd/Timeline/Models/Mapper/TimelineMapper.cs | 2 + BackEnd/Timeline/Services/TimelinePostService.cs | 4 +- 9 files changed, 87 insertions(+), 293 deletions(-) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index 4caff416..bd79ae18 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -1,44 +1,43 @@ 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.Text; using System.Threading.Tasks; -using Timeline.Entities; using Timeline.Models; using Timeline.Models.Http; -using Timeline.Tests.Helpers; using Xunit; +using Xunit.Abstractions; namespace Timeline.Tests.IntegratedTests { - public static class TimelineHelper + public class TimelinePostTest : BaseTimelineTest { - public static HttpTimelinePostContent TextPostContent(string text) + private static HttpTimelinePostCreateRequest CreateTextPostRequest(string text, DateTime? time = null, string? color = null) { - return new HttpTimelinePostContent("text", text, null, null); - } - - public static HttpTimelinePostCreateRequest TextPostCreateRequest(string text, DateTime? time = null) - { - return new HttpTimelinePostCreateRequest + return new HttpTimelinePostCreateRequest() { - Content = new HttpTimelinePostCreateRequestContent + Time = time, + Color = color, + DataList = new List() { - Type = "text", - Text = text - }, - Time = time + new HttpTimelinePostCreateRequestData() + { + ContentType = MimeTypes.TextPlain, + Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(text)) + } + } }; } - } - public class TimelinePostTest : BaseTimelineTest - { + private readonly ITestOutputHelper _outputHelper; + + public TimelinePostTest(ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + } + [Theory] [MemberData(nameof(TimelineNameGeneratorTestData))] public async Task GetPostsAndVisibility_Should_Work(TimelineNameGenerator generator) @@ -102,15 +101,13 @@ namespace Timeline.Tests.IntegratedTests { using var client = await CreateClientAsUser(); - var postContentList = new List { "a", "b", "c", "d" }; var posts = new List(); - foreach (var content in postContentList) + for (int i = 0; i < 4; i++) { - var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostDataKind.Text } }); + var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("a")); posts.Add(post); - await Task.Delay(1000); + await Task.Delay(TimeSpan.FromSeconds(1)); } await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{posts[2].Id}"); @@ -118,64 +115,57 @@ namespace Timeline.Tests.IntegratedTests { 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"); + .And.Subject.Select(p => p.Id).Should().Equal(posts[1].Id, posts[3].Id); } } [Theory] [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task Post_ModifiedSince_And_IncludeDeleted(TimelineNameGenerator generator) + public async Task PostList_IncludeDeleted(TimelineNameGenerator generator) { 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))) + for (int i = 0; i < 4; i++) { - var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostDataKind.Text } }); - posts.Add(post); - await Task.Delay(1000); + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("a")); + posts.Add(body); } - await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{posts[2].Id}"); - + foreach (var id in new long[] { posts[0].Id, posts[2].Id }) { + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{id}"); + } - 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); + { + 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); } } [Theory] [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task PostList_IncludeDeleted(TimelineNameGenerator generator) + public async Task Post_ModifiedSince_And_IncludeDeleted(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); - var postContentList = new List { "a", "b", "c", "d" }; var posts = new List(); - foreach (var content in postContentList) + for (int i = 0; i < 4; i++) { - var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Text = content, Type = TimelinePostDataKind.Text } }); - posts.Add(body); + var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("a")); + posts.Add(post); + await Task.Delay(TimeSpan.FromSeconds(1)); } - foreach (var id in new long[] { posts[0].Id, posts[2].Id }) - { - await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{id}"); - } + await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{posts[2].Id}"); { - 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); + 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); } } @@ -190,25 +180,25 @@ namespace Timeline.Tests.IntegratedTests using (var client = await CreateDefaultClient()) { // no auth should get 401 - await client.TestPostAssertUnauthorizedAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); + await client.TestPostAssertUnauthorizedAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("aaa")); } using (var client = await CreateClientAsUser()) { // post self's - await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); + await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("aaa")); // post other not as a member should get 403 - await client.TestPostAssertForbiddenAsync($"timelines/{generator(0)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); + await client.TestPostAssertForbiddenAsync($"timelines/{generator(0)}/posts", CreateTextPostRequest("aaa")); } using (var client = await CreateClientAsAdministrator()) { // post as admin - await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); + await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("aaa")); } using (var client = await CreateClientAs(2)) { // post as member - await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); + await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("aaa")); } } @@ -219,7 +209,7 @@ namespace Timeline.Tests.IntegratedTests async Task CreatePost(int userNumber) { using var client = await CreateClientAs(userNumber); - var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("aaa")); return body.Id; } @@ -265,57 +255,6 @@ namespace Timeline.Tests.IntegratedTests } } - [Theory] - [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task TextPost_Should_Work(TimelineNameGenerator generator) - { - using var client = await CreateClientAsUser(); - - { - var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); - body.Should().BeEmpty(); - } - - const string mockContent = "aaa"; - HttpTimelinePost 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); - HttpTimelinePost 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}"); - await client.TestDeleteAssertErrorAsync($"timelines/{generator(1)}/posts/{createRes.Id}"); - await client.TestDeleteAssertErrorAsync($"timelines/{generator(1)}/posts/30000"); - } - { - var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); - body.Should().BeEquivalentTo(createRes2); - } - } - [Theory] [MemberData(nameof(TimelineNameGeneratorTestData))] public async Task GetPost_Should_Ordered(TimelineNameGenerator generator) @@ -324,7 +263,7 @@ namespace Timeline.Tests.IntegratedTests async Task CreatePost(DateTime time) { - var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa", time)); + var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("aaa", time)); return body.Id; } @@ -339,166 +278,19 @@ namespace Timeline.Tests.IntegratedTests } } - [Theory] - [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task CreatePost_InvalidModel(TimelineNameGenerator generator) - { - using var client = await CreateClientAsUser(); - var postUrl = $"timelines/{generator(1)}/posts"; - await client.TestPostAssertInvalidModelAsync(postUrl, new HttpTimelinePostCreateRequest { Content = null! }); - await client.TestPostAssertInvalidModelAsync(postUrl, new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Type = null! } }); - await client.TestPostAssertInvalidModelAsync(postUrl, new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Type = "hahaha" } }); - await client.TestPostAssertInvalidModelAsync(postUrl, new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Type = "text", Text = null } }); - await client.TestPostAssertInvalidModelAsync(postUrl, new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Type = "image", Data = null } }); - // image not base64 - await client.TestPostAssertInvalidModelAsync(postUrl, new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Type = "image", Data = "!!!" } }); - // image base64 not image - await client.TestPostAssertInvalidModelAsync(postUrl, new HttpTimelinePostCreateRequest { Content = new HttpTimelinePostCreateRequestContent { Type = "image", Data = Convert.ToBase64String(new byte[] { 0x01, 0x02, 0x03 }) } }); - } - - [Theory] - [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task ImagePost_ShouldWork(TimelineNameGenerator generator) - { - var imageData = ImageHelper.CreatePngWithSize(100, 200); - - long postId; - string postImageUrl; - - void AssertPostContent(HttpTimelinePostContent content) - { - content.Type.Should().Be(TimelinePostDataKind.Image); - content.Url.Should().EndWith($"timelines/{generator(1)}/posts/{postId}/data"); - content.Text.Should().Be(null); - } - - using var client = await CreateClientAsUser(); - - { - var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest - { - Content = new HttpTimelinePostCreateRequestContent - { - Type = TimelinePostDataKind.Image, - Data = Convert.ToBase64String(imageData) - } - }); - postId = body.Id; - postImageUrl = body.Content!.Url!; - AssertPostContent(body.Content); - } - - { - 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!); - } - - { - 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); - image.Height.Should().Be(200); - format.Name.Should().Be(PngFormat.Instance.Name); - } - - await CacheTestHelper.TestCache(client, $"timelines/{generator(1)}/posts/{postId}/data"); - await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{postId}"); - await client.TestDeleteAssertErrorAsync($"timelines/{generator(1)}/posts/{postId}"); - - { - var body = await client.TestGetAsync>($"timelines/{generator(1)}/posts"); - body.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(TimelineNameGeneratorTestData))] - public async Task ImagePost_400(TimelineNameGenerator generator) - { - using var client = await CreateClientAsUser(); - - await client.TestGetAssertNotFoundAsync($"timelines/{generator(1)}/posts/11234/data", errorCode: ErrorCodes.TimelineController.PostNotExist); - - long postId; - { - var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", TimelineHelper.TextPostCreateRequest("aaa")); - postId = body.Id; - } - - await client.TestGetAssertErrorAsync($"timelines/{generator(1)}/posts/{postId}/data", errorCode: ErrorCodes.TimelineController.PostNoData); - } - - [Theory] - [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task PostDataETag(TimelineNameGenerator generator) - { - using var client = await CreateClientAsUser(); - - long id; - string etag; - - { - var body = await client.TestPostAsync($"timelines/{generator(1)}/posts", new HttpTimelinePostCreateRequest - { - Content = new HttpTimelinePostCreateRequestContent - { - Type = TimelinePostDataKind.Image, - Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 50)) - } - }); - body.Content!.ETag.Should().NotBeNullOrEmpty(); - - id = body.Id; - etag = body.Content.ETag!; - } - - { - var res = await client.GetAsync($"timelines/{generator(1)}/posts/{id}/data"); - res.StatusCode.Should().Be(200); - res.Headers.ETag.Should().NotBeNull(); - res.Headers.ETag!.ToString().Should().Be(etag); - } - } - [Theory] [MemberData(nameof(TimelineNameGeneratorTestData))] public async Task Color(TimelineNameGenerator generator) { using var client = await CreateClientAsUser(); - HttpTimelinePostCreateRequestContent CreateRequestContent() => new() - { - Type = "text", - Text = "aaa" - }; - - await client.TestPostAssertInvalidModelAsync($"timelines/{generator(1)}/posts", new HttpTimelinePostCreateRequest - { - Content = CreateRequestContent(), - Color = "#1" - }); + await client.TestPostAssertInvalidModelAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("a", color: "aa")); long id; { - var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", new HttpTimelinePostCreateRequest - { - Content = CreateRequestContent(), - Color = "#aabbcc" - }); + var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", + CreateTextPostRequest("a", color: "#aabbcc")); post.Color.Should().Be("#aabbcc"); id = post.Id; } @@ -515,18 +307,10 @@ namespace Timeline.Tests.IntegratedTests { using var client = await CreateClientAsUser(); - HttpTimelinePostCreateRequestContent CreateRequestContent() => new() - { - Type = "text", - Text = "aaa" - }; await client.TestGetAssertNotFoundAsync($"timelines/{generator(1)}/posts/1"); - var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", new HttpTimelinePostCreateRequest - { - Content = CreateRequestContent(), - }); + var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest("a")); var post2 = await client.TestGetAsync($"timelines/{generator(1)}/posts/{post.Id}"); post2.Should().BeEquivalentTo(post); @@ -542,14 +326,8 @@ namespace Timeline.Tests.IntegratedTests { using var client = await CreateClientAsUser(); - var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", new HttpTimelinePostCreateRequest - { - Content = new() - { - Type = "text", - Text = "aaa" - } - }); + var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", + CreateTextPostRequest("a")); var date = new DateTime(2000, 10, 1); diff --git a/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs index 893a5d28..708120b1 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs @@ -11,8 +11,8 @@ using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; +using Timeline.Models; using Timeline.Models.Http; -using Timeline.Services; using Timeline.Tests.Helpers; using Xunit; @@ -23,11 +23,10 @@ namespace Timeline.Tests.IntegratedTests [Fact] public async Task Test() { - Avatar mockAvatar = new Avatar - { - Data = ImageHelper.CreatePngWithSize(100, 100), - Type = PngFormat.Instance.DefaultMimeType - }; + ByteData mockAvatar = new ByteData( + ImageHelper.CreatePngWithSize(100, 100), + PngFormat.Instance.DefaultMimeType + ); using (var client = await CreateClientAsUser()) { @@ -106,7 +105,7 @@ namespace Timeline.Tests.IntegratedTests } { - await client.TestPutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.Type); + await client.TestPutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.ContentType); await TestAvatar("user1", mockAvatar.Data); } @@ -137,7 +136,7 @@ namespace Timeline.Tests.IntegratedTests // Authorization check. using (var client = await CreateClientAsAdministrator()) { - await client.TestPutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.Type); + await client.TestPutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.ContentType); await client.TestDeleteAsync("users/user1/avatar"); await client.TestPutByteArrayAssertErrorAsync("users/usernotexist/avatar", new[] { (byte)0x00 }, "image/png", errorCode: ErrorCodes.UserCommon.NotExist); await client.TestDeleteAssertErrorAsync("users/usernotexist/avatar", errorCode: ErrorCodes.UserCommon.NotExist); @@ -175,4 +174,4 @@ namespace Timeline.Tests.IntegratedTests } } } -} \ No newline at end of file +} diff --git a/BackEnd/Timeline/Controllers/UserAvatarController.cs b/BackEnd/Timeline/Controllers/UserAvatarController.cs index 8ac2d21a..180d1f9b 100644 --- a/BackEnd/Timeline/Controllers/UserAvatarController.cs +++ b/BackEnd/Timeline/Controllers/UserAvatarController.cs @@ -102,12 +102,12 @@ namespace Timeline.Controllers try { - var etag = await _service.SetAvatar(id, body); + var digest = await _service.SetAvatar(id, body); _logger.LogInformation(Log.Format(LogPutSuccess, ("Username", username), ("Mime Type", Request.ContentType))); - Response.Headers.Append("ETag", new EntityTagHeaderValue($"\"{etag}\"").ToString()); + Response.Headers.Append("ETag", new EntityTagHeaderValue($"\"{digest.ETag}\"").ToString()); return Ok(); } diff --git a/BackEnd/Timeline/Entities/TimelinePostEntity.cs b/BackEnd/Timeline/Entities/TimelinePostEntity.cs index c65ef929..1f0270cb 100644 --- a/BackEnd/Timeline/Entities/TimelinePostEntity.cs +++ b/BackEnd/Timeline/Entities/TimelinePostEntity.cs @@ -37,6 +37,8 @@ namespace Timeline.Entities [Column("last_updated")] public DateTime LastUpdated { get; set; } +#pragma warning disable CA2227 public List DataList { get; set; } = default!; +#pragma warning restore CA2227 } } diff --git a/BackEnd/Timeline/Formatters/ByteDataInputFormatter.cs b/BackEnd/Timeline/Formatters/ByteDataInputFormatter.cs index 2451ead6..49f8221a 100644 --- a/BackEnd/Timeline/Formatters/ByteDataInputFormatter.cs +++ b/BackEnd/Timeline/Formatters/ByteDataInputFormatter.cs @@ -44,6 +44,12 @@ namespace Timeline.Formatters var logger = context.HttpContext.RequestServices.GetRequiredService>(); + if (request.ContentType is null) + { + logger.LogInformation("Failed to read body as bytes. Content-Type is not set."); + return await InputFormatterResult.FailureAsync(); + } + if (contentLength == null) { logger.LogInformation("Failed to read body as bytes. Content-Length is not set."); diff --git a/BackEnd/Timeline/Models/Http/HttpTimelinePost.cs b/BackEnd/Timeline/Models/Http/HttpTimelinePost.cs index 165c92da..26e1a92d 100644 --- a/BackEnd/Timeline/Models/Http/HttpTimelinePost.cs +++ b/BackEnd/Timeline/Models/Http/HttpTimelinePost.cs @@ -26,7 +26,12 @@ namespace Timeline.Models.Http /// Post id. /// public long Id { get; set; } + /// + /// The data list. + /// +#pragma warning disable CA2227 public List DataList { get; set; } = default!; +#pragma warning restore CA2227 /// /// True if post is deleted. /// diff --git a/BackEnd/Timeline/Models/Http/HttpTimelinePostCreateRequest.cs b/BackEnd/Timeline/Models/Http/HttpTimelinePostCreateRequest.cs index 07d823ad..2a973c72 100644 --- a/BackEnd/Timeline/Models/Http/HttpTimelinePostCreateRequest.cs +++ b/BackEnd/Timeline/Models/Http/HttpTimelinePostCreateRequest.cs @@ -13,7 +13,9 @@ namespace Timeline.Models.Http [Required] [MinLength(1)] [MaxLength(100)] +#pragma warning disable CA2227 public List DataList { get; set; } = default!; +#pragma warning restore CA2227 /// /// Time of the post. If not set, current time will be used. diff --git a/BackEnd/Timeline/Models/Mapper/TimelineMapper.cs b/BackEnd/Timeline/Models/Mapper/TimelineMapper.cs index 33ee9593..1f10c123 100644 --- a/BackEnd/Timeline/Models/Mapper/TimelineMapper.cs +++ b/BackEnd/Timeline/Models/Mapper/TimelineMapper.cs @@ -66,6 +66,8 @@ namespace Timeline.Models.Mapper public async Task MapToHttp(TimelinePostEntity entity, string timelineName, IUrlHelper urlHelper) { + _ = timelineName; + await _database.Entry(entity).Collection(p => p.DataList).LoadAsync(); await _database.Entry(entity).Reference(e => e.Author).LoadAsync(); diff --git a/BackEnd/Timeline/Services/TimelinePostService.cs b/BackEnd/Timeline/Services/TimelinePostService.cs index 8afd0770..62bc43cc 100644 --- a/BackEnd/Timeline/Services/TimelinePostService.cs +++ b/BackEnd/Timeline/Services/TimelinePostService.cs @@ -1,6 +1,5 @@ using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -using SixLabors.ImageSharp; using System; using System.Collections.Generic; using System.Linq; @@ -12,7 +11,6 @@ using Timeline.Helpers.Cache; using Timeline.Models; using Timeline.Models.Validation; using Timeline.Services.Exceptions; -using static Timeline.Resources.Services.TimelineService; namespace Timeline.Services { @@ -37,7 +35,9 @@ namespace Timeline.Services /// If not set, current time is used. public DateTime? Time { get; set; } +#pragma warning disable CA2227 public List DataList { get; set; } = new List(); +#pragma warning restore CA2227 } public class TimelinePostPatchRequest -- cgit v1.2.3 From d30c011d70453029a7a5c27b00f7f33357c3a9c2 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 11 Feb 2021 23:22:50 +0800 Subject: test: Add create post invalid model test. --- .../IntegratedTests/TimelinePostTest.cs | 142 +++++++++++++++++++++ 1 file changed, 142 insertions(+) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index bd79ae18..08f88dfc 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using Timeline.Models; using Timeline.Models.Http; +using Timeline.Tests.Helpers; using Xunit; using Xunit.Abstractions; @@ -343,5 +344,146 @@ namespace Timeline.Tests.IntegratedTests post3.Time.Should().Be(date); post3.Color.Should().Be("#aabbcc"); } + + [Theory] + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task CreatePost_InvalidModel(TimelineNameGenerator generator) + { + using var client = await CreateClientAsUser(); + + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest { DataList = null! } + ); + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest { DataList = new List() } + ); + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = Enumerable.Repeat(new HttpTimelinePostCreateRequestData + { + ContentType = "text/plain", + Data = Convert.ToBase64String(Encoding.UTF8.GetBytes("a")) + }, 200).ToList() + } + ); + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List() + { + new HttpTimelinePostCreateRequestData + { + ContentType = null!, + Data = Convert.ToBase64String(Encoding.UTF8.GetBytes("a")) + } + } + } + ); + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List() + { + new HttpTimelinePostCreateRequestData + { + ContentType = "text/plain", + Data = null! + } + } + } + ); + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List() + { + new HttpTimelinePostCreateRequestData + { + ContentType = "text/xxxxxxx", + Data = Convert.ToBase64String(Encoding.UTF8.GetBytes("a")) + } + } + } + ); + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List() + { + new HttpTimelinePostCreateRequestData + { + ContentType = "text/plain", + Data = "aaa" + } + } + } + ); + } + + [Theory] + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task CreatePost_InvalidModel_NonUtf8(TimelineNameGenerator generator) + { + using var client = await CreateClientAsUser(); + + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List() + { + new HttpTimelinePostCreateRequestData + { + ContentType = "text/plain", + Data = Convert.ToBase64String(new byte[] {0xE4, 0x1, 0xA0}) + } + } + } + ); + } + + [Theory] + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task CreatePost_InvalidModel_Image(TimelineNameGenerator generator) + { + using var client = await CreateClientAsUser(); + + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List() + { + new HttpTimelinePostCreateRequestData + { + ContentType = "image/jpeg", + Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 100)) + } + } + } + ); + await client.TestPostAssertInvalidModelAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List() + { + new HttpTimelinePostCreateRequestData + { + ContentType = "image/jpeg", + Data = Convert.ToBase64String(new byte[] { 100, 200 }) + } + } + } + ); + } } } -- cgit v1.2.3 From 3b60ec8b8fe13710f954338c27ed98b46e1ed1fd Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 12 Feb 2021 16:42:56 +0800 Subject: ... --- .../IntegratedTests/TimelinePostTest.cs | 171 +++++++-------------- .../Timeline/Controllers/TimelinePostController.cs | 4 + 2 files changed, 59 insertions(+), 116 deletions(-) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index 08f88dfc..0f264774 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -345,114 +345,74 @@ namespace Timeline.Tests.IntegratedTests post3.Color.Should().Be("#aabbcc"); } - [Theory] - [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task CreatePost_InvalidModel(TimelineNameGenerator generator) + public static IEnumerable CreatePost_InvalidModelTest_TestData() { - using var client = await CreateClientAsUser(); - - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest { DataList = null! } - ); - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest { DataList = new List() } - ); - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest - { - DataList = Enumerable.Repeat(new HttpTimelinePostCreateRequestData + var testDataList = new List?>() + { + null, + new List(), + Enumerable.Repeat(new HttpTimelinePostCreateRequestData { ContentType = "text/plain", Data = Convert.ToBase64String(Encoding.UTF8.GetBytes("a")) - }, 200).ToList() - } - ); - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest + }, 200).ToList(), + }; + + var testData = new List() + { + null, + new HttpTimelinePostCreateRequestData { - DataList = new List() - { - new HttpTimelinePostCreateRequestData - { - ContentType = null!, - Data = Convert.ToBase64String(Encoding.UTF8.GetBytes("a")) - } - } - } - ); - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest + ContentType = null!, + Data = Convert.ToBase64String(Encoding.UTF8.GetBytes("a")) + }, + new HttpTimelinePostCreateRequestData { - DataList = new List() - { - new HttpTimelinePostCreateRequestData - { - ContentType = "text/plain", - Data = null! - } - } - } - ); - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest + ContentType = "text/plain", + Data = null! + }, + new HttpTimelinePostCreateRequestData { - DataList = new List() - { - new HttpTimelinePostCreateRequestData - { - ContentType = "text/xxxxxxx", - Data = Convert.ToBase64String(Encoding.UTF8.GetBytes("a")) - } - } - } - ); - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest + ContentType = "text/xxxxxxx", + Data = Convert.ToBase64String(Encoding.UTF8.GetBytes("a")) + }, + new HttpTimelinePostCreateRequestData { - DataList = new List() - { - new HttpTimelinePostCreateRequestData - { - ContentType = "text/plain", - Data = "aaa" - } - } + ContentType = "text/plain", + Data = "aaa" + }, + new HttpTimelinePostCreateRequestData + { + ContentType = "text/plain", + Data = Convert.ToBase64String(new byte[] {0xE4, 0x1, 0xA0}) + }, + new HttpTimelinePostCreateRequestData + { + ContentType = "image/jpeg", + Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 100)) + }, + new HttpTimelinePostCreateRequestData + { + ContentType = "image/jpeg", + Data = Convert.ToBase64String(new byte[] { 100, 200 }) } - ); - } - [Theory] - [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task CreatePost_InvalidModel_NonUtf8(TimelineNameGenerator generator) - { - using var client = await CreateClientAsUser(); + }; - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest - { - DataList = new List() - { - new HttpTimelinePostCreateRequestData - { - ContentType = "text/plain", - Data = Convert.ToBase64String(new byte[] {0xE4, 0x1, 0xA0}) - } - } - } - ); + testDataList.AddRange(testData.Select(d => new List() { d! })); + + foreach (var generatorTestData in TimelineNameGeneratorTestData()) + { + var generator = generatorTestData[0]; + + foreach (var d in testDataList) + yield return new object?[] { generator, d }; + } } [Theory] - [MemberData(nameof(TimelineNameGeneratorTestData))] - public async Task CreatePost_InvalidModel_Image(TimelineNameGenerator generator) + [MemberData(nameof(CreatePost_InvalidModelTest_TestData))] + public async Task CreatePost_InvalidModel(TimelineNameGenerator generator, List dataList) { using var client = await CreateClientAsUser(); @@ -460,28 +420,7 @@ namespace Timeline.Tests.IntegratedTests $"timelines/{generator(1)}/posts", new HttpTimelinePostCreateRequest { - DataList = new List() - { - new HttpTimelinePostCreateRequestData - { - ContentType = "image/jpeg", - Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 100)) - } - } - } - ); - await client.TestPostAssertInvalidModelAsync( - $"timelines/{generator(1)}/posts", - new HttpTimelinePostCreateRequest - { - DataList = new List() - { - new HttpTimelinePostCreateRequestData - { - ContentType = "image/jpeg", - Data = Convert.ToBase64String(new byte[] { 100, 200 }) - } - } + DataList = dataList } ); } diff --git a/BackEnd/Timeline/Controllers/TimelinePostController.cs b/BackEnd/Timeline/Controllers/TimelinePostController.cs index 06082f0f..6904e28d 100644 --- a/BackEnd/Timeline/Controllers/TimelinePostController.cs +++ b/BackEnd/Timeline/Controllers/TimelinePostController.cs @@ -171,6 +171,10 @@ namespace Timeline.Controllers for (int i = 0; i < body.DataList.Count; i++) { var data = body.DataList[i]; + + if (data is null) + return BadRequest(new CommonResponse(ErrorCodes.Common.InvalidModel, $"Data at index {i} is null.")); + try { var d = Convert.FromBase64String(data.Data); -- cgit v1.2.3 From 31e467d72bc9b3cc7a7bb8c5bec4d2998ca49916 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 12 Feb 2021 17:08:54 +0800 Subject: test: Add some helper function. --- .../IntegratedTests/TimelinePostTest.cs | 8 +--- BackEnd/Timeline.Tests/XUnitHelper.cs | 44 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 BackEnd/Timeline.Tests/XUnitHelper.cs (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index 0f264774..85db0908 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -401,13 +401,7 @@ namespace Timeline.Tests.IntegratedTests testDataList.AddRange(testData.Select(d => new List() { d! })); - foreach (var generatorTestData in TimelineNameGeneratorTestData()) - { - var generator = generatorTestData[0]; - - foreach (var d in testDataList) - yield return new object?[] { generator, d }; - } + return TimelineNameGeneratorTestData().AppendTestData(testDataList); } [Theory] diff --git a/BackEnd/Timeline.Tests/XUnitHelper.cs b/BackEnd/Timeline.Tests/XUnitHelper.cs new file mode 100644 index 00000000..a2812ad3 --- /dev/null +++ b/BackEnd/Timeline.Tests/XUnitHelper.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Timeline.Tests +{ + public static class XUnitHelper + { + public static IEnumerable ComposeTestData(params IEnumerable[] testDatas) + { + return ComposeTestData(new ArraySegment>(testDatas)); + } + + public static IEnumerable ComposeTestData(ArraySegment> testDatas) + { + if (testDatas.Count == 0) + throw new ArgumentException("Test data list can't be empty.", nameof(testDatas)); + + if (testDatas.Count == 1) + { + foreach (var d in testDatas[0]) + yield return d; + } + else + { + foreach (var head in testDatas[0]) + foreach (var rest in ComposeTestData(testDatas.Slice(1))) + yield return head.Concat(rest).ToArray(); + } + } + + public static IEnumerable AppendTestData(this IEnumerable origin, params IEnumerable[] toAppend) + { + IEnumerable result = origin; + + foreach (var oneToAppend in toAppend) + { + result = ComposeTestData(result, oneToAppend.Select(testData => new object?[] { testData })); + } + + return result; + } + } +} -- cgit v1.2.3 From b5b758c41a01ab7f78f0711debe92f6add470c64 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 12 Feb 2021 17:45:09 +0800 Subject: test: Add create post integrated tests. --- .../IntegratedTests/TimelinePostTest.cs | 70 ++++++++++++++++++++++ .../Timeline/Controllers/UserAvatarController.cs | 2 +- BackEnd/Timeline/Helpers/Cache/DataCacheHelper.cs | 2 +- BackEnd/Timeline/Models/Mapper/TimelineMapper.cs | 2 +- 4 files changed, 73 insertions(+), 3 deletions(-) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index 85db0908..4563db3a 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -10,6 +10,10 @@ using Timeline.Models.Http; using Timeline.Tests.Helpers; using Xunit; using Xunit.Abstractions; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Jpeg; +using System.Net; namespace Timeline.Tests.IntegratedTests { @@ -418,5 +422,71 @@ namespace Timeline.Tests.IntegratedTests } ); } + + public static IEnumerable CreatePost_ShouldWork_TestData() + { + var testByteDatas = new List() + { + new ByteData(Encoding.UTF8.GetBytes("aaa"), MimeTypes.TextPlain), + new ByteData(Encoding.UTF8.GetBytes("aaa"), MimeTypes.TextMarkdown), + new ByteData(ImageHelper.CreateImageWithSize(100, 50, PngFormat.Instance), MimeTypes.ImagePng), + new ByteData(ImageHelper.CreateImageWithSize(100, 50, JpegFormat.Instance), MimeTypes.ImageJpeg), + new ByteData(ImageHelper.CreateImageWithSize(100, 50, GifFormat.Instance), MimeTypes.ImageGif), + }; + + return TimelineNameGeneratorTestData().AppendTestData(testByteDatas); + } + + [Theory] + [MemberData(nameof(CreatePost_ShouldWork_TestData))] + public async Task CreatePost_ShouldWork(TimelineNameGenerator generator, ByteData data) + { + using var client = await CreateClientAsUser(); + + var post = await client.TestPostAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List + { + new HttpTimelinePostCreateRequestData + { + ContentType = data.ContentType, + Data = Convert.ToBase64String(data.Data) + } + } + } + ); + + post.DataList.Should().NotBeNull().And.HaveCount(1); + var postData = post.DataList[0]; + postData.Should().NotBeNull(); + var postDataEtag = postData.ETag; + postDataEtag.Should().NotBeNullOrEmpty(); + + { + var response = await client.GetAsync($"timelines/{generator(1)}/posts/{post.Id}/data"); + response.StatusCode.Should().Be(HttpStatusCode.OK); + response.Headers.ETag.Should().NotBeNull(); + response.Headers.ETag!.Tag.Should().Be(postDataEtag); + response.Content.Headers.ContentType.Should().NotBeNull(); + response.Content.Headers.ContentType!.MediaType.Should().Be(data.ContentType); + + var body = await response.Content.ReadAsByteArrayAsync(); + body.Should().Equal(data.Data); + } + + { + var response = await client.GetAsync($"timelines/{generator(1)}/posts/{post.Id}/data/0"); + response.StatusCode.Should().Be(HttpStatusCode.OK); + response.Headers.ETag.Should().NotBeNull(); + response.Headers.ETag!.Tag.Should().Be(postDataEtag); + response.Content.Headers.ContentType.Should().NotBeNull(); + response.Content.Headers.ContentType!.MediaType.Should().Be(data.ContentType); + + var body = await response.Content.ReadAsByteArrayAsync(); + body.Should().Equal(data.Data); + } + } } } diff --git a/BackEnd/Timeline/Controllers/UserAvatarController.cs b/BackEnd/Timeline/Controllers/UserAvatarController.cs index 180d1f9b..fa13f0f6 100644 --- a/BackEnd/Timeline/Controllers/UserAvatarController.cs +++ b/BackEnd/Timeline/Controllers/UserAvatarController.cs @@ -107,7 +107,7 @@ namespace Timeline.Controllers _logger.LogInformation(Log.Format(LogPutSuccess, ("Username", username), ("Mime Type", Request.ContentType))); - Response.Headers.Append("ETag", new EntityTagHeaderValue($"\"{digest.ETag}\"").ToString()); + Response.Headers.Append("ETag", $"\"{digest.ETag}\""); return Ok(); } diff --git a/BackEnd/Timeline/Helpers/Cache/DataCacheHelper.cs b/BackEnd/Timeline/Helpers/Cache/DataCacheHelper.cs index c26bdddc..b7d86b18 100644 --- a/BackEnd/Timeline/Helpers/Cache/DataCacheHelper.cs +++ b/BackEnd/Timeline/Helpers/Cache/DataCacheHelper.cs @@ -33,7 +33,7 @@ namespace Timeline.Helpers.Cache } var digest = await provider.GetDigest(); - var eTagValue = '"' + digest.ETag + '"'; + var eTagValue = $"\"{digest.ETag}\""; var eTag = new EntityTagHeaderValue(eTagValue); ActionResult Generate304Result() diff --git a/BackEnd/Timeline/Models/Mapper/TimelineMapper.cs b/BackEnd/Timeline/Models/Mapper/TimelineMapper.cs index 1f10c123..5c46fa81 100644 --- a/BackEnd/Timeline/Models/Mapper/TimelineMapper.cs +++ b/BackEnd/Timeline/Models/Mapper/TimelineMapper.cs @@ -71,7 +71,7 @@ namespace Timeline.Models.Mapper await _database.Entry(entity).Collection(p => p.DataList).LoadAsync(); await _database.Entry(entity).Reference(e => e.Author).LoadAsync(); - List dataDigestList = entity.DataList.OrderBy(d => d.Index).Select(d => new HttpTimelinePostDataDigest(d.Kind, d.DataTag, d.LastUpdated)).ToList(); + List dataDigestList = entity.DataList.OrderBy(d => d.Index).Select(d => new HttpTimelinePostDataDigest(d.Kind, $"\"{d.DataTag}\"", d.LastUpdated)).ToList(); HttpUser? author = null; if (entity.Author is not null) -- cgit v1.2.3 From 65c2c772d6625d8a793b6174b554b6c6943f41ad Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 12 Feb 2021 18:27:41 +0800 Subject: test: Add multiple data post test. --- .../IntegratedTests/TimelinePostTest.cs | 78 ++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index 4563db3a..c5ff507f 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -488,5 +488,83 @@ namespace Timeline.Tests.IntegratedTests body.Should().Equal(data.Data); } } + + [Theory] + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task CreatePost_MultipleData_ShouldWork(TimelineNameGenerator generator) + { + using var client = await CreateClientAsUser(); + + var textData = Encoding.UTF8.GetBytes("aaa"); + var imageData = ImageHelper.CreatePngWithSize(100, 50); + + var post = await client.TestPostAsync( + $"timelines/{generator(1)}/posts", + new HttpTimelinePostCreateRequest + { + DataList = new List + { + new HttpTimelinePostCreateRequestData + { + ContentType = MimeTypes.TextMarkdown, + Data = Convert.ToBase64String(textData) + }, + new HttpTimelinePostCreateRequestData + { + ContentType = MimeTypes.ImagePng, + Data = Convert.ToBase64String(imageData) + } + } + } + ); + + post.DataList.Should().NotBeNull().And.HaveCount(2); + + var postData0 = post.DataList[0]; + postData0.Should().NotBeNull(); + var postDataEtag0 = postData0.ETag; + postDataEtag0.Should().NotBeNullOrEmpty(); + + var postData1 = post.DataList[1]; + postData1.Should().NotBeNull(); + var postDataEtag1 = postData1.ETag; + postDataEtag1.Should().NotBeNullOrEmpty(); + + { + var response = await client.GetAsync($"timelines/{generator(1)}/posts/{post.Id}/data"); + response.StatusCode.Should().Be(HttpStatusCode.OK); + response.Headers.ETag.Should().NotBeNull(); + response.Headers.ETag!.Tag.Should().Be(postDataEtag0); + response.Content.Headers.ContentType.Should().NotBeNull(); + response.Content.Headers.ContentType!.MediaType.Should().Be(MimeTypes.TextMarkdown); + + var body = await response.Content.ReadAsByteArrayAsync(); + body.Should().Equal(textData); + } + + { + var response = await client.GetAsync($"timelines/{generator(1)}/posts/{post.Id}/data/0"); + response.StatusCode.Should().Be(HttpStatusCode.OK); + response.Headers.ETag.Should().NotBeNull(); + response.Headers.ETag!.Tag.Should().Be(postDataEtag0); + response.Content.Headers.ContentType.Should().NotBeNull(); + response.Content.Headers.ContentType!.MediaType.Should().Be(MimeTypes.TextMarkdown); + + var body = await response.Content.ReadAsByteArrayAsync(); + body.Should().Equal(textData); + } + + { + var response = await client.GetAsync($"timelines/{generator(1)}/posts/{post.Id}/data/1"); + response.StatusCode.Should().Be(HttpStatusCode.OK); + response.Headers.ETag.Should().NotBeNull(); + response.Headers.ETag!.Tag.Should().Be(postDataEtag1); + response.Content.Headers.ContentType.Should().NotBeNull(); + response.Content.Headers.ContentType!.MediaType.Should().Be(MimeTypes.ImagePng); + + var body = await response.Content.ReadAsByteArrayAsync(); + body.Should().Equal(imageData); + } + } } } -- cgit v1.2.3