diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml index 79ee123c2..6e6eec114 100644 --- a/.idea/codeStyles/codeStyleConfig.xml +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,6 @@ \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 43c5b3f62..5c1ddbeb2 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -5,6 +5,9 @@ + + + diff --git a/.idea/modules.xml b/.idea/modules.xml index ddfe56ffb..5bf195a1f 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,6 +2,10 @@ + + + + diff --git a/src/main/java/com/faforever/api/clan/ClanService.java b/src/main/java/com/faforever/api/clan/ClanService.java index 67971c44d..86087baf6 100644 --- a/src/main/java/com/faforever/api/clan/ClanService.java +++ b/src/main/java/com/faforever/api/clan/ClanService.java @@ -22,7 +22,6 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; -import java.util.Collections; import java.util.List; @Service @@ -67,35 +66,15 @@ public void preCreate(Clan clan) { @SneakyThrows @Transactional @Deprecated - // use preCreate instead + // use POST via Elide instead Clan create(String name, String tag, String description) { - Player creator = playerService.getCurrentPlayer(); - - if (creator.getClanMembership() != null) { - throw ApiException.of(ErrorCode.CLAN_CREATE_FOUNDER_IS_IN_A_CLAN); - } - if (clanRepository.findOneByName(name).isPresent()) { - throw ApiException.of(ErrorCode.CLAN_NAME_EXISTS, name); - } - if (clanRepository.findOneByTag(tag).isPresent()) { - throw ApiException.of(ErrorCode.CLAN_TAG_EXISTS, tag); - } - Clan clan = new Clan(); clan.setName(name); clan.setTag(tag); clan.setDescription(description); + clan.setFounder(playerService.getCurrentPlayer()); - clan.setFounder(creator); - clan.setLeader(creator); - - ClanMembership membership = new ClanMembership(); - membership.setClan(clan); - membership.setPlayer(creator); - - clan.setMemberships(Collections.singletonList(membership)); - - // clan membership is saved over cascading, otherwise validation will fail + // validation is done at preCreate() called by ClanListener clanRepository.save(clan); return clan; } diff --git a/src/test/java/com/faforever/api/clan/ClanServiceTest.java b/src/test/java/com/faforever/api/clan/ClanServiceTest.java index c856873fe..1696f3845 100644 --- a/src/test/java/com/faforever/api/clan/ClanServiceTest.java +++ b/src/test/java/com/faforever/api/clan/ClanServiceTest.java @@ -17,11 +17,9 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.security.jwt.Jwt; -import java.io.IOException; import java.util.Optional; import static com.faforever.api.error.ApiExceptionMatcher.hasErrorCode; @@ -29,11 +27,15 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; @ExtendWith({MockitoExtension.class}) @@ -150,306 +152,227 @@ void success() { } - @Test - void createClanWhereLeaderIsAlreadyInAClan() { - String clanName = "My cool Clan"; - String tag = "123"; - String description = "A cool clan for testing"; - Player creator = new Player(); - creator.setId(1); - creator.setClanMembership(new ClanMembership()); - when(playerService.getCurrentPlayer()).thenReturn(creator); - - ApiException e = assertThrows(ApiException.class, () -> instance.create(clanName, tag, description)); - - assertThat(e, hasErrorCode(ErrorCode.CLAN_CREATE_FOUNDER_IS_IN_A_CLAN)); - verify(clanRepository, Mockito.never()).save(any(Clan.class)); - } - - @Test - void createClanWithSameName() { - String clanName = "My cool Clan"; - String tag = "123"; - String description = "A cool clan for testing"; - - Player creator = new Player(); - creator.setId(1); - when(playerService.getCurrentPlayer()).thenReturn(creator); - - when(clanRepository.findOneByName(clanName)).thenReturn(Optional.of(new Clan())); - - ApiException e = assertThrows(ApiException.class, () -> instance.create(clanName, tag, description)); + @Nested + class TestGeneratePlayerInvitationToken { + @Mock + Player player; - assertThat(e, hasErrorCode(ErrorCode.CLAN_NAME_EXISTS)); + @BeforeEach + void setUp() { + when(player.getId()).thenReturn(1); + when(playerService.getCurrentPlayer()).thenReturn(player); + } - ArgumentCaptor clanCaptor = ArgumentCaptor.forClass(Clan.class); - verify(clanRepository, Mockito.times(0)).save(clanCaptor.capture()); - } + @Test + void invalidClan() throws Exception { + reset(player); - @Test - void createClanWithSameTag() { - String clanName = "My cool Clan"; - String tag = "123"; - String description = "A cool clan for testing"; + ApiException e = assertThrows(ApiException.class, () -> instance.generatePlayerInvitationToken(45, 42)); - Player creator = new Player(); - creator.setId(1); - when(playerService.getCurrentPlayer()).thenReturn(creator); + assertThat(e, hasErrorCode(ErrorCode.CLAN_NOT_EXISTS)); + verify(jwtService, never()).sign(any()); + } - when(clanRepository.findOneByName(clanName)).thenReturn(Optional.empty()); - when(clanRepository.findOneByTag(tag)).thenReturn(Optional.of(new Clan())); + @Test + void generateTokenAsNonLeader() throws Exception { + Player newMember = new Player(); + newMember.setId(2); - ApiException e = assertThrows(ApiException.class, () -> instance.create(clanName, tag, description)); + Player leader = new Player(); + leader.setId(3); - assertThat(e, hasErrorCode(ErrorCode.CLAN_TAG_EXISTS)); + Clan clan = ClanFactory.builder().id(42).leader(leader).build(); - ArgumentCaptor clanCaptor = ArgumentCaptor.forClass(Clan.class); - verify(clanRepository, Mockito.times(0)).save(clanCaptor.capture()); - } + when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); - @Test - void createClanSuccessful() { - String clanName = "My cool Clan"; - String tag = "123"; - String description = "A cool clan for testing"; + ApiException e = assertThrows(ApiException.class, () -> instance.generatePlayerInvitationToken(45, 42)); - Player creator = new Player(); - creator.setId(1); - when(playerService.getCurrentPlayer()).thenReturn(creator); + assertThat(e, hasErrorCode(ErrorCode.CLAN_NOT_LEADER)); + verify(jwtService, never()).sign(any()); + } - when(clanRepository.findOneByName(clanName)).thenReturn(Optional.empty()); - when(clanRepository.findOneByTag(tag)).thenReturn(Optional.empty()); + @Test + void invalidPlayer() throws Exception { + Clan clan = ClanFactory.builder().id(42).leader(player).build(); + when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); + when(playerService.getById(45)).thenThrow(ApiException.of(ErrorCode.PLAYER_NOT_FOUND)); - instance.create(clanName, tag, description); - ArgumentCaptor clanCaptor = ArgumentCaptor.forClass(Clan.class); - verify(clanRepository, Mockito.times(1)).save(clanCaptor.capture()); - assertEquals(clanName, clanCaptor.getValue().getName()); - assertEquals(tag, clanCaptor.getValue().getTag()); - assertEquals(description, clanCaptor.getValue().getDescription()); - assertEquals(creator, clanCaptor.getValue().getLeader()); - assertEquals(creator, clanCaptor.getValue().getFounder()); - assertEquals(1, clanCaptor.getValue().getMemberships().size()); - assertEquals(creator, clanCaptor.getValue().getMemberships().get(0).getPlayer()); - } + ApiException e = assertThrows(ApiException.class, () -> instance.generatePlayerInvitationToken(45, 42)); - @Test - void generatePlayerInvitationTokenWithInvalidClan() throws IOException { - Player requester = new Player(); - requester.setId(1); - when(playerService.getCurrentPlayer()).thenReturn(requester); + assertThat(e, hasErrorCode(ErrorCode.PLAYER_NOT_FOUND)); + verify(jwtService, never()).sign(any()); + } - ApiException e = assertThrows(ApiException.class, () -> instance.generatePlayerInvitationToken(45, 42)); + @Test + void success() throws Exception { + Player newMember = new Player(); + newMember.setId(2); + + Clan clan = ClanFactory.builder().leader(player).build(); + + FafApiProperties props = new FafApiProperties(); + + when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); + when(playerService.getById(newMember.getId())).thenReturn(newMember); + when(fafApiProperties.getClan()).thenReturn(props.getClan()); + + instance.generatePlayerInvitationToken(newMember.getId(), clan.getId()); + ArgumentCaptor captor = ArgumentCaptor.forClass(InvitationResult.class); + verify(jwtService).sign(captor.capture()); + assertThat("expire", + captor.getValue().getExpire(), + greaterThan(System.currentTimeMillis())); + assertEquals(newMember.getId(), captor.getValue().getNewMember().getId()); + assertEquals(newMember.getLogin(), captor.getValue().getNewMember().getLogin()); + assertEquals(clan.getId(), captor.getValue().getClan().getId()); + assertEquals(clan.getTag(), captor.getValue().getClan().getTag()); + assertEquals(clan.getName(), captor.getValue().getClan().getName()); + } - assertThat(e, hasErrorCode(ErrorCode.CLAN_NOT_EXISTS)); - verify(jwtService, Mockito.never()).sign(any()); } - @Test - void generatePlayerInvitationTokenFromNonLeader() throws IOException { - Player requester = new Player(); - requester.setId(1); - when(playerService.getCurrentPlayer()).thenReturn(requester); - - Player newMember = new Player(); - newMember.setId(2); - - Player leader = new Player(); - leader.setId(3); - - Clan clan = ClanFactory.builder().id(42).leader(leader).build(); - - when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); + @Nested + class TestAcceptPlayerInvitationToken { + @Mock + private Jwt jwtToken; - ApiException e = assertThrows(ApiException.class, () -> instance.generatePlayerInvitationToken(45, 42)); + private final String STRING_TOKEN = "1234"; - assertThat(e, hasErrorCode(ErrorCode.CLAN_NOT_LEADER)); - verify(jwtService, Mockito.never()).sign(any()); - } + private long expire; - @Test - void generatePlayerInvitationTokenInvalidPlayer() throws IOException { - Player requester = new Player(); - requester.setId(1); - when(playerService.getCurrentPlayer()).thenReturn(requester); + private Clan clan; - Clan clan = ClanFactory.builder().id(42).leader(requester).build(); + @BeforeEach + void setUp() { + expire = System.currentTimeMillis() + 1000 * 3; + clan = ClanFactory.builder().build(); + when(jwtService.decodeAndVerify(any())).thenReturn(jwtToken); + } - when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); - when(playerService.getById(45)).thenThrow(ApiException.of(ErrorCode.PLAYER_NOT_FOUND)); + @Test + void expired() { + expire = System.currentTimeMillis(); - ApiException e = assertThrows(ApiException.class, () -> instance.generatePlayerInvitationToken(45, 42)); + when(jwtToken.getClaims()).thenReturn(String.format("{\"expire\":%s}", expire)); - assertThat(e, hasErrorCode(ErrorCode.PLAYER_NOT_FOUND)); - verify(jwtService, Mockito.never()).sign(any()); - } + ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(STRING_TOKEN)); - @Test - void generatePlayerInvitationToken() throws IOException { - Player requester = new Player(); - requester.setId(1); - when(playerService.getCurrentPlayer()).thenReturn(requester); - - Player newMember = new Player(); - newMember.setId(2); - - Clan clan = ClanFactory.builder().leader(requester).build(); - - FafApiProperties props = new FafApiProperties(); - - when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); - when(playerService.getById(newMember.getId())).thenReturn(newMember); - when(fafApiProperties.getClan()).thenReturn(props.getClan()); - - instance.generatePlayerInvitationToken(newMember.getId(), clan.getId()); - ArgumentCaptor captor = ArgumentCaptor.forClass(InvitationResult.class); - verify(jwtService, Mockito.times(1)).sign(captor.capture()); - assertThat("expire", - captor.getValue().getExpire(), - greaterThan(System.currentTimeMillis())); - assertEquals(newMember.getId(), captor.getValue().getNewMember().getId()); - assertEquals(newMember.getLogin(), captor.getValue().getNewMember().getLogin()); - assertEquals(clan.getId(), captor.getValue().getClan().getId()); - assertEquals(clan.getTag(), captor.getValue().getClan().getTag()); - assertEquals(clan.getName(), captor.getValue().getClan().getName()); - } + assertThat(e, hasErrorCode(ErrorCode.CLAN_ACCEPT_TOKEN_EXPIRE)); + verifyZeroInteractions(clanMembershipRepository); + } - @Test - void acceptPlayerInvitationTokenExpire() throws IOException { - String stringToken = "1234"; - long expire = System.currentTimeMillis(); - Jwt jwtToken = mock(Jwt.class); + @Test + void invalidClan() { + when(jwtToken.getClaims()).thenReturn(String.format("{\"expire\":%s,\"clan\":{\"id\":42}}", expire)); - when(jwtToken.getClaims()).thenReturn( - String.format("{\"expire\":%s}", expire)); - when(jwtService.decodeAndVerify(any())).thenReturn(jwtToken); + ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(STRING_TOKEN)); - ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(stringToken)); + assertThat(e, hasErrorCode(ErrorCode.CLAN_NOT_EXISTS)); + verifyZeroInteractions(clanMembershipRepository); + } - assertThat(e, hasErrorCode(ErrorCode.CLAN_ACCEPT_TOKEN_EXPIRE)); - verify(clanMembershipRepository, Mockito.never()).save(any(ClanMembership.class)); - } + @Test + void invalidPlayer() { + Player requester = new Player(); + requester.setId(1); + when(playerService.getCurrentPlayer()).thenReturn(requester); - @Test - void acceptPlayerInvitationTokenInvalidClan() throws IOException { - String stringToken = "1234"; + when(jwtToken.getClaims()).thenReturn( + String.format("{\"expire\":%s,\"newMember\":{\"id\":2},\"clan\":{\"id\":%s}}", + expire, clan.getId())); + when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); + when(playerService.getById(2)).thenThrow(ApiException.of(ErrorCode.PLAYER_NOT_FOUND)); - long expire = System.currentTimeMillis() + 1000 * 3; - Jwt jwtToken = mock(Jwt.class); + ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(STRING_TOKEN)); - when(jwtToken.getClaims()).thenReturn( - String.format("{\"expire\":%s,\"clan\":{\"id\":42}}", expire)); - when(jwtService.decodeAndVerify(any())).thenReturn(jwtToken); + assertThat(e, hasErrorCode(ErrorCode.PLAYER_NOT_FOUND)); + verifyZeroInteractions(clanMembershipRepository); + } - ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(stringToken)); + @Test + void playerInTokenNotLoggedInPlayer() { + Player newMember = new Player(); + newMember.setId(2); - assertThat(e, hasErrorCode(ErrorCode.CLAN_NOT_EXISTS)); - verify(clanMembershipRepository, Mockito.never()).save(any(ClanMembership.class)); - } + Player loggedInPlayer = new Player(); + loggedInPlayer.setId(3); - @Test - void acceptPlayerInvitationTokenInvalidPlayer() throws IOException { - Player requester = new Player(); - requester.setId(1); - when(playerService.getCurrentPlayer()).thenReturn(requester); + when(jwtToken.getClaims()).thenReturn( + String.format("{\"expire\":%s,\"newMember\":{\"id\":%s},\"clan\":{\"id\":%s}}", + expire, newMember.getId(), clan.getId())); + when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); + when(playerService.getById(newMember.getId())).thenReturn(newMember); + when(playerService.getCurrentPlayer()).thenReturn(loggedInPlayer); - String stringToken = "1234"; - Clan clan = ClanFactory.builder().build(); + ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(STRING_TOKEN)); - long expire = System.currentTimeMillis() + 1000 * 3; - Jwt jwtToken = mock(Jwt.class); + assertThat(e, hasErrorCode(ErrorCode.CLAN_ACCEPT_WRONG_PLAYER)); + verifyZeroInteractions(clanMembershipRepository); + } - when(jwtToken.getClaims()).thenReturn( - String.format("{\"expire\":%s,\"newMember\":{\"id\":2},\"clan\":{\"id\":%s}}", - expire, clan.getId())); - when(jwtService.decodeAndVerify(any())).thenReturn(jwtToken); - when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); - when(playerService.getById(2)).thenThrow(ApiException.of(ErrorCode.PLAYER_NOT_FOUND)); + @Test + void playerIsAlreadyInClan() { + Player newMember = new Player(); + newMember.setId(2); + newMember.setClanMembership(new ClanMembership().setClan(clan).setPlayer(newMember)); - ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(stringToken)); + when(jwtToken.getClaims()).thenReturn( + String.format("{\"expire\":%s,\"newMember\":{\"id\":%s},\"clan\":{\"id\":%s}}", + expire, newMember.getId(), clan.getId())); - assertThat(e, hasErrorCode(ErrorCode.PLAYER_NOT_FOUND)); - verify(clanMembershipRepository, Mockito.never()).save(any(ClanMembership.class)); - } + when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); + when(playerService.getById(newMember.getId())).thenReturn(newMember); + when(playerService.getCurrentPlayer()).thenReturn(newMember); - @Test - void acceptPlayerInvitationTokenWrongPlayer() throws IOException { - String stringToken = "1234"; + ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(STRING_TOKEN)); - Player newMember = new Player(); - newMember.setId(2); + assertThat(e, hasErrorCode(ErrorCode.CLAN_ACCEPT_PLAYER_IN_A_CLAN)); + verifyZeroInteractions(clanMembershipRepository); + } - Clan clan = ClanFactory.builder().build(); + @Test + void success() { + Player newMember = new Player(); + newMember.setId(2); - Player otherPlayer = new Player(); - otherPlayer.setId(3); + when(jwtToken.getClaims()).thenReturn( + String.format("{\"expire\":%s,\"newMember\":{\"id\":%s},\"clan\":{\"id\":%s}}", + expire, newMember.getId(), clan.getId())); - long expire = System.currentTimeMillis() + 1000 * 3; - Jwt jwtToken = mock(Jwt.class); + when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); + when(playerService.getById(newMember.getId())).thenReturn(newMember); + when(playerService.getCurrentPlayer()).thenReturn(newMember); - when(jwtToken.getClaims()).thenReturn( - String.format("{\"expire\":%s,\"newMember\":{\"id\":%s},\"clan\":{\"id\":%s}}", - expire, newMember.getId(), clan.getId())); - when(jwtService.decodeAndVerify(any())).thenReturn(jwtToken); - when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); - when(playerService.getById(newMember.getId())).thenReturn(newMember); - when(playerService.getCurrentPlayer()).thenReturn(otherPlayer); + instance.acceptPlayerInvitationToken(STRING_TOKEN); - ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(stringToken)); + ArgumentCaptor captor = ArgumentCaptor.forClass(ClanMembership.class); + verify(clanMembershipRepository).save(captor.capture()); - assertThat(e, hasErrorCode(ErrorCode.CLAN_ACCEPT_WRONG_PLAYER)); - verify(clanMembershipRepository, Mockito.never()).save(any(ClanMembership.class)); + assertEquals(newMember.getId(), captor.getValue().getPlayer().getId()); + assertEquals(clan.getId(), captor.getValue().getClan().getId()); + } } @Test - void acceptPlayerInvitationTokenPlayerIAlreadyInAClan() throws IOException { - String stringToken = "1234"; - - Clan clan = ClanFactory.builder().build(); - - Player newMember = new Player(); - newMember.setId(2); - newMember.setClanMembership(new ClanMembership().setClan(clan).setPlayer(newMember)); - - long expire = System.currentTimeMillis() + 1000 * 3; - Jwt jwtToken = mock(Jwt.class); + @Deprecated + void testCreate() { + Player player = mock(Player.class); + when(playerService.getCurrentPlayer()).thenReturn(player); - when(jwtToken.getClaims()).thenReturn( - String.format("{\"expire\":%s,\"newMember\":{\"id\":%s},\"clan\":{\"id\":%s}}", - expire, newMember.getId(), clan.getId())); - when(jwtService.decodeAndVerify(any())).thenReturn(jwtToken); - when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); - when(playerService.getById(newMember.getId())).thenReturn(newMember); - when(playerService.getCurrentPlayer()).thenReturn(newMember); + String clanName = "My cool Clan"; + String tag = "123"; + String description = "A cool clan for testing"; - ApiException e = assertThrows(ApiException.class, () -> instance.acceptPlayerInvitationToken(stringToken)); + Clan clan = instance.create(clanName, tag, description); - assertThat(e, hasErrorCode(ErrorCode.CLAN_ACCEPT_PLAYER_IN_A_CLAN)); - verify(clanMembershipRepository, Mockito.never()).save(any(ClanMembership.class)); - } + assertAll( + () -> assertThat(clan.getName(), is(clanName)), + () -> assertThat(clan.getTag(), is(tag)), + () -> assertThat(clan.getDescription(), is(description)), + () -> assertThat(clan.getFounder(), is(player)) + ); - @Test - void acceptPlayerInvitationToken() throws IOException { - String stringToken = "1234"; - Clan clan = ClanFactory.builder().build(); - Player newMember = new Player(); - newMember.setId(2); - long expire = System.currentTimeMillis() + 1000 * 3; - Jwt jwtToken = mock(Jwt.class); - - when(jwtToken.getClaims()).thenReturn( - String.format("{\"expire\":%s,\"newMember\":{\"id\":%s},\"clan\":{\"id\":%s}}", - expire, newMember.getId(), clan.getId())); - when(jwtService.decodeAndVerify(any())).thenReturn(jwtToken); - when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); - when(playerService.getById(newMember.getId())).thenReturn(newMember); - when(playerService.getCurrentPlayer()).thenReturn(newMember); - - instance.acceptPlayerInvitationToken(stringToken); - - ArgumentCaptor captor = ArgumentCaptor.forClass(ClanMembership.class); - verify(clanMembershipRepository, Mockito.times(1)).save(captor.capture()); - assertEquals(newMember.getId(), captor.getValue().getPlayer().getId()); - assertEquals(clan.getId(), captor.getValue().getClan().getId()); + verify(clanRepository).save(eq(clan)); } }