Public Access
feat(account): tell Core about Steam ID and block changes
Sent on the task executor after the commit, and every user again in the nightly cleanup. A failed call only warns.
This commit is contained in:
1 parent
3336181cdb
commit
06f8089f5a
16 files changed
+286
-3
No files matched your search
@@ -1,5 +1,6 @@
|
||||
package auth_service.modules.account.repo;
|
||||
|
||||
import auth_service.modules.account.model.CoreAccountState;
|
||||
import auth_service.shared.test.AbstractPersistenceTest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -49,6 +50,16 @@ class AccountRepositoryTest extends AbstractPersistenceTest {
|
||||
bob = insertUser("bob@example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void findStates_CarryTheSteamIdAndTheBlock() {
|
||||
jdbc.update("update users set enabled = false, steam_id = 76561198000000001 where id = ?", alice);
|
||||
|
||||
assertThat(repository.findState(alice)).contains(new CoreAccountState(alice, 76561198000000001L, true));
|
||||
assertThat(repository.findAllStates()).containsExactly(new CoreAccountState(alice, 76561198000000001L, true),
|
||||
new CoreAccountState(bob, null, false));
|
||||
assertThat(repository.findState(-1L)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void flagDeleted_SetsTheFlagAndRevokesOnlyThatUsersTokens() {
|
||||
assertThat(repository.flagDeleted(alice, NOW)).isEqualTo(1);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package auth_service.modules.account.service;
|
||||
|
||||
import auth_service.modules.account.model.CoreAccountState;
|
||||
import auth_service.modules.account.model.CoreCleanupResult;
|
||||
import auth_service.modules.account.repo.AccountRepository;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
@@ -24,6 +25,8 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
class AccountCleanupServiceTest extends AbstractUnitTest {
|
||||
|
||||
private static final List<CoreAccountState> STATES = List.of(new CoreAccountState(1L, 76561198000000001L, true));
|
||||
|
||||
private static final Duration RETENTION = Duration.ofDays(30);
|
||||
|
||||
@Mock
|
||||
@@ -45,6 +48,7 @@ class AccountCleanupServiceTest extends AbstractUnitTest {
|
||||
lenient().when(accountRepository.findFlaggedIds()).thenReturn(List.of(7L, 8L));
|
||||
lenient().when(accountRepository.findFlaggedBefore(any())).thenReturn(List.of(7L));
|
||||
lenient().when(accountRepository.findAllIds()).thenReturn(List.of(1L, 7L, 8L));
|
||||
lenient().when(accountRepository.findAllStates()).thenReturn(STATES);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -55,9 +59,22 @@ class AccountCleanupServiceTest extends AbstractUnitTest {
|
||||
service(false).runNightly();
|
||||
|
||||
verify(coreAccountService).replaceDeleted(List.of(7L, 8L));
|
||||
verify(coreAccountService).replaceStates(STATES);
|
||||
verify(accountRepository).deleteUsers(List.of(7L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void runNightly_AFailedStateCallStillPurgesAndPrunes() {
|
||||
doThrow(new RestClientException("Core too old")).when(coreAccountService).replaceStates(any());
|
||||
when(coreAccountService.purge(eq(List.of(7L)), anyBoolean())).thenReturn(core(false));
|
||||
when(coreAccountService.prune(eq(List.of(1L, 7L, 8L)), anyBoolean())).thenReturn(core(false));
|
||||
|
||||
service(false).runNightly();
|
||||
|
||||
verify(accountRepository).deleteUsers(List.of(7L));
|
||||
verify(coreAccountService).prune(List.of(1L, 7L, 8L), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
void runNightly_InDryRunAsksCoreForADryRunAndDeletesNothingInAuth() {
|
||||
when(coreAccountService.purge(eq(List.of(7L)), anyBoolean())).thenReturn(core(true));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package auth_service.modules.account.service;
|
||||
|
||||
import auth_service.modules.account.model.CoreAccountState;
|
||||
import auth_service.modules.account.model.CoreCleanupResult;
|
||||
import auth_service.shared.security.ServiceTokenIssuer;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
@@ -65,6 +66,17 @@ class CoreAccountServiceTest extends AbstractUnitTest {
|
||||
core.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void applyAndReplaceStates_SendTheContractBodies() {
|
||||
expect("applyStates");
|
||||
expect("replaceStates");
|
||||
|
||||
service.applyStates(List.of(new CoreAccountState(42L, 76561198000000001L, true)));
|
||||
service.replaceStates(List.of(new CoreAccountState(42L, null, false)));
|
||||
|
||||
core.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
void purgeAndPrune_ReadTheContractResult() {
|
||||
expect("purge");
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package auth_service.modules.account.service;
|
||||
|
||||
import auth_service.modules.account.model.CoreAccountState;
|
||||
import auth_service.modules.account.repo.AccountRepository;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.springframework.transaction.support.TransactionSynchronization;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class CoreAccountStatePublisherTest extends AbstractUnitTest {
|
||||
|
||||
private static final CoreAccountState STATE = new CoreAccountState(7L, 76561198000000001L, true);
|
||||
|
||||
@Mock
|
||||
private AccountRepository accountRepository;
|
||||
|
||||
@Mock
|
||||
private CoreAccountService coreAccountService;
|
||||
|
||||
private CoreAccountStatePublisher publisher;
|
||||
|
||||
// Runs each task at once, so the test sees the call.
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
publisher = new CoreAccountStatePublisher(accountRepository, coreAccountService, Runnable::run);
|
||||
}
|
||||
|
||||
@Test
|
||||
void withoutATransaction_SendsAtOnce() {
|
||||
when(accountRepository.findState(7L)).thenReturn(Optional.of(STATE));
|
||||
|
||||
publisher.publish(7L);
|
||||
|
||||
verify(coreAccountService).applyStates(List.of(STATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void inATransaction_SendsOnlyAfterTheCommit() {
|
||||
when(accountRepository.findState(7L)).thenReturn(Optional.of(STATE));
|
||||
TransactionSynchronizationManager.initSynchronization();
|
||||
try {
|
||||
publisher.publish(7L);
|
||||
verify(coreAccountService, never()).applyStates(any());
|
||||
|
||||
TransactionSynchronizationManager.getSynchronizations().forEach(TransactionSynchronization::afterCommit);
|
||||
} finally {
|
||||
TransactionSynchronizationManager.clearSynchronization();
|
||||
}
|
||||
|
||||
verify(coreAccountService).applyStates(List.of(STATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void coreDown_OnlyWarns() {
|
||||
when(accountRepository.findState(7L)).thenReturn(Optional.of(STATE));
|
||||
doThrow(new RestClientException("Core down")).when(coreAccountService).applyStates(any());
|
||||
|
||||
assertDoesNotThrow(() -> publisher.publish(7L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void unknownUser_SendsNothing() {
|
||||
when(accountRepository.findState(7L)).thenReturn(Optional.empty());
|
||||
|
||||
publisher.publish(7L);
|
||||
|
||||
verify(coreAccountService, never()).applyStates(any());
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import auth_service.modules.admin.exception.TargetUserNotFoundException;
|
||||
import auth_service.modules.admin.model.TargetState;
|
||||
import auth_service.modules.admin.repo.AdminUserRepository;
|
||||
import auth_service.shared.account.AccountDeleter;
|
||||
import auth_service.shared.account.AccountStatePublisher;
|
||||
import auth_service.shared.audit.AdminAuditLog;
|
||||
import auth_service.shared.security.Role;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
@@ -39,11 +40,14 @@ class AdminUserServiceTest extends AbstractUnitTest {
|
||||
@Mock
|
||||
private AccountDeleter accountDeleter;
|
||||
|
||||
@Mock
|
||||
private AccountStatePublisher accountStatePublisher;
|
||||
|
||||
private AdminUserService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new AdminUserService(adminUserRepository, adminAuditLog, accountDeleter);
|
||||
service = new AdminUserService(adminUserRepository, adminAuditLog, accountDeleter, accountStatePublisher);
|
||||
}
|
||||
|
||||
private void target(Role role, boolean deleted) {
|
||||
@@ -67,6 +71,7 @@ class AdminUserServiceTest extends AbstractUnitTest {
|
||||
|
||||
verify(adminUserRepository).setBlocked(eq(TARGET), eq(true), any());
|
||||
verify(adminAuditLog).record(ADMIN, "BLOCK", TARGET, null);
|
||||
verify(accountStatePublisher).publish(TARGET);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -10,6 +10,7 @@ import auth_service.modules.user.model.SteamLinkOutcome;
|
||||
import auth_service.modules.user.model.User;
|
||||
import auth_service.modules.user.model.UserSettings;
|
||||
import auth_service.modules.user.persistence.UserRepository;
|
||||
import auth_service.shared.account.AccountStatePublisher;
|
||||
import auth_service.shared.security.TokenGenerator;
|
||||
import auth_service.shared.test.AbstractUnitTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -41,6 +42,9 @@ class UserServiceTest extends AbstractUnitTest {
|
||||
@Mock
|
||||
private TokenGenerator tokenGenerator;
|
||||
|
||||
@Mock
|
||||
private AccountStatePublisher accountStatePublisher;
|
||||
|
||||
@InjectMocks
|
||||
private UserService userService;
|
||||
|
||||
@@ -124,6 +128,7 @@ class UserServiceTest extends AbstractUnitTest {
|
||||
assertEquals(SteamLinkOutcome.LINKED, userService.linkVerifiedSteamId(1L, STEAM_ID));
|
||||
|
||||
verify(userRepository).setVerifiedSteamId(1L, STEAM_ID);
|
||||
verify(accountStatePublisher).publish(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -145,6 +150,8 @@ class UserServiceTest extends AbstractUnitTest {
|
||||
InOrder order = inOrder(userRepository);
|
||||
order.verify(userRepository).clearSteamId(2L);
|
||||
order.verify(userRepository).setVerifiedSteamId(1L, STEAM_ID);
|
||||
verify(accountStatePublisher).publish(2L);
|
||||
verify(accountStatePublisher).publish(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -155,6 +162,7 @@ class UserServiceTest extends AbstractUnitTest {
|
||||
|
||||
verify(userRepository, never()).clearSteamId(anyLong());
|
||||
verify(userRepository, never()).setVerifiedSteamId(anyLong(), anyLong());
|
||||
verifyNoInteractions(accountStatePublisher);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,6 +172,7 @@ class UserServiceTest extends AbstractUnitTest {
|
||||
assertEquals("token-without-steam", userService.unlinkSteamId(1L, Role.USER));
|
||||
|
||||
verify(userRepository).clearSteamId(1L);
|
||||
verify(accountStatePublisher).publish(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -55,6 +55,16 @@
|
||||
"path": "/internal/accounts/deleted",
|
||||
"request": {"userIds": []}
|
||||
},
|
||||
"applyStates": {
|
||||
"method": "POST",
|
||||
"path": "/internal/accounts/states",
|
||||
"request": {"accounts": [{"userId": 42, "steamId": 76561198000000001, "blocked": true}]}
|
||||
},
|
||||
"replaceStates": {
|
||||
"method": "PUT",
|
||||
"path": "/internal/accounts/states",
|
||||
"request": {"accounts": [{"userId": 42, "steamId": null, "blocked": false}]}
|
||||
},
|
||||
"purge": {
|
||||
"method": "POST",
|
||||
"path": "/internal/accounts/purge",
|
||||
|
||||
Reference in new issue
Block a user