Skip to content

Commit b2bc5dd

Browse files
authored
improve integration tests readability (#112)
1 parent 8fbc90e commit b2bc5dd

File tree

10 files changed

+1034
-1334
lines changed

10 files changed

+1034
-1334
lines changed
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
using System;
2+
using System.Net;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Hikkaba.Application.Contracts;
6+
using Hikkaba.Data.Context;
7+
using Hikkaba.Data.Entities;
8+
using Hikkaba.Shared.Constants;
9+
using Hikkaba.Shared.Enums;
10+
using Hikkaba.Tests.Integration.Utils;
11+
using Microsoft.Extensions.DependencyInjection;
12+
using Thread = Hikkaba.Data.Entities.Thread;
13+
14+
namespace Hikkaba.Tests.Integration.Builders;
15+
16+
internal sealed class BanTestDataBuilder
17+
{
18+
private static readonly GuidGenerator GuidGenerator = new();
19+
20+
private readonly ApplicationDbContext _dbContext;
21+
private readonly IHashService _hashService;
22+
private readonly TimeProvider _timeProvider;
23+
24+
private ApplicationUser? _admin;
25+
private Category? _category;
26+
private Thread? _thread;
27+
28+
public BanTestDataBuilder(IServiceScope scope)
29+
{
30+
_dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
31+
_hashService = scope.ServiceProvider.GetRequiredService<IHashService>();
32+
_timeProvider = scope.ServiceProvider.GetRequiredService<TimeProvider>();
33+
}
34+
35+
public ApplicationUser Admin => _admin ?? throw new InvalidOperationException("Admin not created. Call WithDefaultAdmin() first.");
36+
public Category Category => _category ?? throw new InvalidOperationException("Category not created. Call WithDefaultCategory() first.");
37+
public Thread Thread => _thread ?? throw new InvalidOperationException("Thread not created. Call WithDefaultThread() first.");
38+
39+
public BanTestDataBuilder WithDefaultAdmin()
40+
{
41+
_admin = new ApplicationUser
42+
{
43+
UserName = "admin",
44+
NormalizedUserName = "ADMIN",
45+
Email = "[email protected]",
46+
NormalizedEmail = "[email protected]",
47+
EmailConfirmed = true,
48+
SecurityStamp = "896e8014-c237-41f5-a925-dabf640ee4c4",
49+
ConcurrencyStamp = "43035b63-359d-4c23-8812-29bbc5affbf2",
50+
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
51+
};
52+
_dbContext.Users.Add(_admin);
53+
return this;
54+
}
55+
56+
public BanTestDataBuilder WithDefaultCategory()
57+
{
58+
EnsureAdminExists();
59+
60+
_category = new Category
61+
{
62+
IsDeleted = false,
63+
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
64+
ModifiedAt = null,
65+
Alias = "b",
66+
Name = "Random",
67+
IsHidden = false,
68+
DefaultBumpLimit = 500,
69+
ShowThreadLocalUserHash = false,
70+
ShowCountry = false,
71+
ShowOs = false,
72+
ShowBrowser = false,
73+
MaxThreadCount = Defaults.MaxThreadCountInCategory,
74+
CreatedBy = Admin,
75+
};
76+
_dbContext.Categories.Add(_category);
77+
return this;
78+
}
79+
80+
public BanTestDataBuilder WithDefaultThread()
81+
{
82+
EnsureCategoryExists();
83+
84+
var utcNow = _timeProvider.GetUtcNow().UtcDateTime;
85+
_thread = new Thread
86+
{
87+
CreatedAt = utcNow,
88+
LastBumpAt = utcNow,
89+
Title = "test thread 1",
90+
IsPinned = false,
91+
IsClosed = false,
92+
BumpLimit = 500,
93+
Salt = GuidGenerator.GenerateSeededGuid(),
94+
Category = Category,
95+
};
96+
_dbContext.Threads.Add(_thread);
97+
return this;
98+
}
99+
100+
public BanTestDataBuilder WithPost(Guid blobContainerId, string ipAddress, string userAgent, bool isOriginalPost = false)
101+
{
102+
EnsureThreadExists();
103+
104+
var ip = IPAddress.Parse(ipAddress);
105+
var post = new Post
106+
{
107+
IsOriginalPost = isOriginalPost,
108+
BlobContainerId = blobContainerId,
109+
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
110+
IsSageEnabled = false,
111+
MessageText = $"test post {userAgent}",
112+
MessageHtml = $"test post {userAgent}",
113+
UserIpAddress = ip.GetAddressBytes(),
114+
UserAgent = userAgent,
115+
ThreadLocalUserHash = _hashService.GetHashBytes(Thread.Salt, ip.GetAddressBytes()),
116+
Thread = Thread,
117+
};
118+
_dbContext.Posts.Add(post);
119+
return this;
120+
}
121+
122+
public BanTestDataBuilder WithExactBan(string ipAddress, string reason)
123+
{
124+
EnsureAdminExists();
125+
126+
var ip = IPAddress.Parse(ipAddress);
127+
var ipType = ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork
128+
? IpAddressType.IpV4
129+
: IpAddressType.IpV6;
130+
131+
var ban = new Ban
132+
{
133+
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
134+
EndsAt = _timeProvider.GetUtcNow().UtcDateTime.AddYears(99),
135+
IpAddressType = ipType,
136+
BannedIpAddress = ip.GetAddressBytes(),
137+
Reason = reason,
138+
CreatedBy = Admin,
139+
};
140+
_dbContext.Bans.Add(ban);
141+
return this;
142+
}
143+
144+
public BanTestDataBuilder WithRangeBan(
145+
string bannedIpAddress,
146+
string lowerIpAddress,
147+
string upperIpAddress,
148+
string reason)
149+
{
150+
EnsureAdminExists();
151+
152+
var ip = IPAddress.Parse(bannedIpAddress);
153+
var ipType = ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork
154+
? IpAddressType.IpV4
155+
: IpAddressType.IpV6;
156+
157+
var ban = new Ban
158+
{
159+
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
160+
EndsAt = _timeProvider.GetUtcNow().UtcDateTime.AddYears(99),
161+
IpAddressType = ipType,
162+
BannedIpAddress = ip.GetAddressBytes(),
163+
BannedCidrLowerIpAddress = IPAddress.Parse(lowerIpAddress).GetAddressBytes(),
164+
BannedCidrUpperIpAddress = IPAddress.Parse(upperIpAddress).GetAddressBytes(),
165+
Reason = reason,
166+
CreatedBy = Admin,
167+
};
168+
_dbContext.Bans.Add(ban);
169+
return this;
170+
}
171+
172+
public async Task SaveAsync(CancellationToken cancellationToken)
173+
{
174+
await _dbContext.SaveChangesAsync(cancellationToken);
175+
}
176+
177+
private void EnsureAdminExists()
178+
{
179+
if (_admin == null)
180+
{
181+
throw new InvalidOperationException("Admin must be created first. Call WithDefaultAdmin().");
182+
}
183+
}
184+
185+
private void EnsureCategoryExists()
186+
{
187+
if (_category == null)
188+
{
189+
throw new InvalidOperationException("Category must be created first. Call WithDefaultCategory().");
190+
}
191+
}
192+
193+
private void EnsureThreadExists()
194+
{
195+
if (_thread == null)
196+
{
197+
throw new InvalidOperationException("Thread must be created first. Call WithDefaultThread().");
198+
}
199+
}
200+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
using System;
2+
using System.Net;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using Hikkaba.Application.Contracts;
6+
using Hikkaba.Data.Context;
7+
using Hikkaba.Data.Entities;
8+
using Hikkaba.Shared.Constants;
9+
using Hikkaba.Tests.Integration.Utils;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using Thread = Hikkaba.Data.Entities.Thread;
12+
13+
namespace Hikkaba.Tests.Integration.Builders;
14+
15+
internal sealed class PostTestDataBuilder
16+
{
17+
private static readonly GuidGenerator GuidGenerator = new();
18+
19+
private readonly ApplicationDbContext _dbContext;
20+
private readonly IHashService _hashService;
21+
private readonly TimeProvider _timeProvider;
22+
23+
private ApplicationUser? _admin;
24+
private Category? _category;
25+
private Thread? _thread;
26+
27+
public PostTestDataBuilder(IServiceScope scope)
28+
{
29+
_dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
30+
_hashService = scope.ServiceProvider.GetRequiredService<IHashService>();
31+
_timeProvider = scope.ServiceProvider.GetRequiredService<TimeProvider>();
32+
}
33+
34+
public ApplicationUser Admin => _admin ?? throw new InvalidOperationException("Admin not created. Call WithDefaultAdmin() first.");
35+
public Category Category => _category ?? throw new InvalidOperationException("Category not created. Call WithCategory() first.");
36+
public Thread Thread => _thread ?? throw new InvalidOperationException("Thread not created. Call WithThread() first.");
37+
38+
public PostTestDataBuilder WithDefaultAdmin()
39+
{
40+
_admin = new ApplicationUser
41+
{
42+
UserName = "admin",
43+
NormalizedUserName = "ADMIN",
44+
Email = "[email protected]",
45+
NormalizedEmail = "[email protected]",
46+
EmailConfirmed = true,
47+
SecurityStamp = "896e8014-c237-41f5-a925-dabf640ee4c4",
48+
ConcurrencyStamp = "43035b63-359d-4c23-8812-29bbc5affbf2",
49+
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
50+
};
51+
_dbContext.Users.Add(_admin);
52+
return this;
53+
}
54+
55+
public PostTestDataBuilder WithCategory(string alias, string name)
56+
{
57+
EnsureAdminExists();
58+
59+
_category = new Category
60+
{
61+
IsDeleted = false,
62+
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
63+
ModifiedAt = null,
64+
Alias = alias,
65+
Name = name,
66+
IsHidden = false,
67+
DefaultBumpLimit = 500,
68+
ShowThreadLocalUserHash = false,
69+
MaxThreadCount = Defaults.MaxThreadCountInCategory,
70+
CreatedBy = Admin,
71+
};
72+
_dbContext.Categories.Add(_category);
73+
return this;
74+
}
75+
76+
public PostTestDataBuilder WithThread(string title)
77+
{
78+
EnsureCategoryExists();
79+
80+
var utcNow = _timeProvider.GetUtcNow().UtcDateTime;
81+
_thread = new Thread
82+
{
83+
CreatedAt = utcNow,
84+
LastBumpAt = utcNow,
85+
Title = title,
86+
IsPinned = false,
87+
IsClosed = false,
88+
BumpLimit = 500,
89+
Salt = GuidGenerator.GenerateSeededGuid(),
90+
Category = Category,
91+
};
92+
_dbContext.Threads.Add(_thread);
93+
return this;
94+
}
95+
96+
public PostTestDataBuilder WithPost(
97+
Guid blobContainerId,
98+
string messageText,
99+
string ipAddress,
100+
string userAgent,
101+
bool isOriginalPost = false,
102+
bool isDeleted = false)
103+
{
104+
EnsureThreadExists();
105+
106+
var ip = IPAddress.Parse(ipAddress);
107+
var post = new Post
108+
{
109+
IsOriginalPost = isOriginalPost,
110+
IsDeleted = isDeleted,
111+
BlobContainerId = blobContainerId,
112+
CreatedAt = _timeProvider.GetUtcNow().UtcDateTime,
113+
IsSageEnabled = false,
114+
MessageText = messageText,
115+
MessageHtml = messageText,
116+
UserIpAddress = ip.GetAddressBytes(),
117+
UserAgent = userAgent,
118+
ThreadLocalUserHash = _hashService.GetHashBytes(Thread.Salt, ip.GetAddressBytes()),
119+
Thread = Thread,
120+
};
121+
_dbContext.Posts.Add(post);
122+
return this;
123+
}
124+
125+
public async Task SaveAsync(CancellationToken cancellationToken)
126+
{
127+
await _dbContext.SaveChangesAsync(cancellationToken);
128+
}
129+
130+
private void EnsureAdminExists()
131+
{
132+
if (_admin == null)
133+
{
134+
throw new InvalidOperationException("Admin must be created first. Call WithDefaultAdmin().");
135+
}
136+
}
137+
138+
private void EnsureCategoryExists()
139+
{
140+
if (_category == null)
141+
{
142+
throw new InvalidOperationException("Category must be created first. Call WithCategory().");
143+
}
144+
}
145+
146+
private void EnsureThreadExists()
147+
{
148+
if (_thread == null)
149+
{
150+
throw new InvalidOperationException("Thread must be created first. Call WithThread().");
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)