fix(cache): one cache config that expires after the write

publicStats is evicted on registration and Steam link/unlink. The cached user no longer holds the password hash. Tests no longer run with a 1 s TTL.
This commit is contained in:
lobo committed 2026-09-30 13:41:56 +02:00
1 parent cf21f4a654
commit 509280da14
9 files changed
+56 -62

No files matched your search

@@ -93,8 +93,26 @@ class DeletedAccountFlowTest extends AbstractIntegrationTest {
}
private long totalUsers() throws Exception {
return publicStat("totalUsers");
}
private long publicStat(String name) throws Exception {
String body = mockMvc.perform(get("/api/stats/public")).andReturn().getResponse().getContentAsString();
return JsonPath.<Number>read(body, "$.totalUsers").longValue();
return JsonPath.<Number>read(body, "$." + name).longValue();
}
@Test
void steamLinkAndUnlink_CountInThePublicStatsAtOnce() throws Exception {
long userId = jdbc.queryForObject("SELECT id FROM users WHERE email = ?", Long.class, EMAIL);
long before = publicStat("usersWithSteamLinked");
userService.linkVerifiedSteamId(userId, 76561198099990002L);
assertThat(publicStat("usersWithSteamLinked")).isEqualTo(before + 1);
mockMvc.perform(delete("/api/users/steam-link").header(ClientHeaderFilter.CLIENT_HEADER, "web")
.cookie(login().getCookie(AuthCookies.ACCESS_COOKIE)))
.andExpect(status().is2xxSuccessful());
assertThat(publicStat("usersWithSteamLinked")).isEqualTo(before);
}
@Test
@@ -154,6 +172,26 @@ class DeletedAccountFlowTest extends AbstractIntegrationTest {
assertThat(totalUsers()).isEqualTo(usersBefore - 1);
}
@Test
void registration_CountsInThePublicStatsAtOnce() throws Exception {
String newEmail = "delete-flow-registered@example.com";
jdbc.update("DELETE FROM users WHERE email = ?", newEmail);
long before = totalUsers();
try {
mockMvc.perform(post("/api/registration/new")
.header(ClientHeaderFilter.CLIENT_HEADER, "web")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"email\":\"" + newEmail + "\",\"password\":\"" + PASSWORD
+ "\",\"inviteCode\":\"test-invite-code\"}"))
.andExpect(status().is2xxSuccessful());
assertThat(totalUsers()).isEqualTo(before + 1);
} finally {
jdbc.update("DELETE FROM users WHERE email = ?", newEmail);
}
}
@Test
void registration_WithTheEmailOfAFlaggedUser_IsStillRefused() throws Exception {
jdbc.update("UPDATE users SET deleted_at = NOW() WHERE email = ?", EMAIL);
@@ -4,7 +4,6 @@ import org.junit.jupiter.api.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
@@ -23,7 +22,6 @@ import java.util.Base64;
// The account cleanup must not run by itself, and Core is never reachable in tests.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = {"app.account-cleanup.cron=-", "app.core.internal-url=http://127.0.0.1:1"})
@ActiveProfiles("dev")
public abstract class AbstractIntegrationTest {
// One container per JVM, not per class: Spring caches the context across test classes,