package tv.dyndns.kishibe.qmaclone.server; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.List; import java.util.Set; import org.eclipse.jetty.server.Server; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import tv.dyndns.kishibe.qmaclone.client.game.ProblemGenre; import tv.dyndns.kishibe.qmaclone.client.game.ProblemType; import tv.dyndns.kishibe.qmaclone.client.game.RandomFlag; import tv.dyndns.kishibe.qmaclone.client.packet.PacketProblem; import tv.dyndns.kishibe.qmaclone.client.packet.PacketUserData; import tv.dyndns.kishibe.qmaclone.client.packet.ProblemIndicationEligibility; import tv.dyndns.kishibe.qmaclone.client.packet.RestrictionType; import tv.dyndns.kishibe.qmaclone.client.service.ServiceException; import tv.dyndns.kishibe.qmaclone.client.testing.TestDataProvider; import tv.dyndns.kishibe.qmaclone.server.database.Database; import tv.dyndns.kishibe.qmaclone.server.database.DatabaseException; import tv.dyndns.kishibe.qmaclone.server.handwriting.RecognizerZinnia; import tv.dyndns.kishibe.qmaclone.server.image.BrokenImageLinkDetector; import tv.dyndns.kishibe.qmaclone.server.image.ImageUtils; import tv.dyndns.kishibe.qmaclone.server.sns.SnsClient; @RunWith(MockitoJUnitRunner.class) public class ServiceServletStubTest { private static final String QUERY = "query"; private static final String CREATOR = "creator"; private static final boolean CREATOR_PERFECT_MATCHING = true; private static final Set<ProblemGenre> GENRES = ImmutableSet.of(ProblemGenre.Anige, ProblemGenre.Gakumon); private static final Set<ProblemType> TYPES = ImmutableSet.of(ProblemType.Click, ProblemType.Effect); private static final Set<RandomFlag> RANDOM_FLAGS = ImmutableSet.of(RandomFlag.Random1, RandomFlag.Random2); private static final int USER_CODE = 12345678; private static final RestrictionType RESTRICTION_TYPE = RestrictionType.BBS; private static final String REMOTE_ADDRESS = "1.2.3.4"; private static final int PROBLEM_ID = 11111; private static final String GOOGLE_PLUS_ID = "fake google plus id"; private ServiceServletStub service; @Mock private ChatManager mockChatManager; @Mock private NormalModeProblemManager mockNormalModeProblemManager; @Mock private ThemeModeProblemManager mockThemeModeProblemManager; @Mock private GameManager mockGameManager; @Mock private ServerStatusManager mockServerStatusManager; @Mock private PlayerHistoryManager mockPlayerHistoryManager; @Mock private VoteManager mockVoteManager; @Mock private RecognizerZinnia mockRecognizer; @Mock private ThemeModeEditorManager mockThemeModeEditorManager; @Mock private Server mockServer; @Mock private ImageUtils mockImageManager; @Mock private Database mockDatabase; @Mock private PrefectureRanking mockPrefectureRanking; @Mock private RatingDistribution mockRatingDistribution; @Mock private SnsClient mockSnsClient; @Mock private GameLogger mockGameLogger; @Mock private ThreadPool mockThreadPool; @Mock private BadUserDetector mockBadUserDetector; @Mock private RestrictedUserUtils mockRestrictedUserUtils; @Mock private ProblemCorrectCounterResetCounter mockProblemCorrectCounterResetCounter; @Mock private ProblemIndicationCounter mockProblemIndicationCounter; @Mock private BrokenImageLinkDetector mockBrokenImageLinkDetector; private PacketProblem problem1; private PacketProblem problem2; private PacketProblem problem3; @Before public void setUp() throws Exception { service = spy(new ServiceServletStub(mockChatManager, mockNormalModeProblemManager, mockThemeModeProblemManager, mockGameManager, mockServerStatusManager, mockPlayerHistoryManager, mockVoteManager, mockRecognizer, mockThemeModeEditorManager, mockServer, mockDatabase, mockPrefectureRanking, mockRatingDistribution, mockSnsClient, mockGameLogger, mockThreadPool, mockBadUserDetector, mockRestrictedUserUtils, mockProblemCorrectCounterResetCounter, mockProblemIndicationCounter, mockBrokenImageLinkDetector)); problem1 = TestDataProvider.getProblem(); problem1.id = 1; problem2 = TestDataProvider.getProblem(); problem2.id = 2; problem3 = TestDataProvider.getProblem(); problem3.id = 3; } @Test public void searchProblemShouldFilter() throws Exception { PacketProblem expected1 = TestDataProvider.getProblem(); expected1.id = 1; expected1.testing = true; PacketProblem expected2 = TestDataProvider.getProblem(); expected2.id = 2; expected2.testing = true; PacketProblem expected3 = TestDataProvider.getProblem(); expected3.id = 3; when(mockGameManager.getTestingProblemIds()).thenReturn(ImmutableSet.of(1, 2)); when( mockDatabase.searchProblem(QUERY, CREATOR, CREATOR_PERFECT_MATCHING, GENRES, TYPES, RANDOM_FLAGS)).thenReturn(ImmutableList.of(problem1, problem2, problem3)); List<PacketProblem> problems = service.searchProblem(QUERY, CREATOR, CREATOR_PERFECT_MATCHING, GENRES, TYPES, RANDOM_FLAGS); assertEquals(ImmutableList.of(expected1, expected2, expected3), problems); } @Test public void getProblemCorrectCounterResetEligibilityShouldDelegateToBadUserManager() throws Exception { PacketProblem fakeProblem = new PacketProblem(); when(mockProblemCorrectCounterResetCounter.isAbleToReset(USER_CODE)).thenReturn(true); when(mockDatabase.getProblem(ImmutableList.of(PROBLEM_ID))).thenReturn( ImmutableList.of(fakeProblem)); assertTrue(service.resetProblemCorrectCounter(USER_CODE, PROBLEM_ID)); verify(mockDatabase).updateProblem(fakeProblem); } @Test public void getProblemIndicationEligibilityShouldReturnOkForAvailableEligibile() throws Exception { PacketUserData userData = new PacketUserData(); userData.playerName = "プレイヤー名"; when(mockProblemIndicationCounter.isAbleToIndicate(USER_CODE)).thenReturn(true); when(mockDatabase.getUserData(USER_CODE)).thenReturn(userData); assertThat(service.getProblemIndicationEligibility(USER_CODE)).isEqualTo( ProblemIndicationEligibility.OK); } @Test public void getProblemIndicationEligibilityShouldRejectIfTooManyRequests() throws Exception { PacketUserData userData = new PacketUserData(); userData.playerName = "プレイヤー名"; when(mockProblemIndicationCounter.isAbleToIndicate(USER_CODE)).thenReturn(false); when(mockDatabase.getUserData(USER_CODE)).thenReturn(userData); assertThat(service.getProblemIndicationEligibility(USER_CODE)).isEqualTo( ProblemIndicationEligibility.REACHED_MAX_NUMBER_OF_REQUESTS_PER_UNIT_TIME); } @Test public void getProblemIndicationEligibilityShouldRejectIfPlayerNameUnchanged() throws Exception { PacketUserData userData = new PacketUserData(); userData.playerName = "未初期化です"; when(mockProblemIndicationCounter.isAbleToIndicate(USER_CODE)).thenReturn(true); when(mockDatabase.getUserData(USER_CODE)).thenReturn(userData); assertThat(service.getProblemIndicationEligibility(USER_CODE)).isEqualTo( ProblemIndicationEligibility.PLAYER_NAME_UNCHANGED); } @Test public void addRestrictedUserCodeShouldDelegateToDatabase() throws Exception { service.addRestrictedUserCode(USER_CODE, RESTRICTION_TYPE); verify(mockDatabase).addRestrictedUserCode(USER_CODE, RESTRICTION_TYPE); } @Test(expected = ServiceException.class) public void addRestrictedUserCodeShouldThrowExceptionOnError() throws Exception { doThrow(new DatabaseException()).when(mockDatabase).addRestrictedUserCode(USER_CODE, RESTRICTION_TYPE); service.addRestrictedUserCode(USER_CODE, RESTRICTION_TYPE); } @Test public void removeRestrictedUserCodeShouldDelegateToDatabase() throws Exception { service.removeRestrictedUserCode(USER_CODE, RESTRICTION_TYPE); verify(mockDatabase).removeRestrictedUserCode(USER_CODE, RESTRICTION_TYPE); } @Test(expected = ServiceException.class) public void removeRestrictedUserCodeShouldThrowExceptionOnError() throws Exception { doThrow(new DatabaseException()).when(mockDatabase).removeRestrictedUserCode(USER_CODE, RESTRICTION_TYPE); service.removeRestrictedUserCode(USER_CODE, RESTRICTION_TYPE); } @Test public void getRestrictedUserCodesShouldDelegateToDatabase() throws Exception { when(mockDatabase.getRestrictedUserCodes(RESTRICTION_TYPE)).thenReturn( ImmutableSet.of(USER_CODE)); assertEquals(ImmutableSet.of(USER_CODE), service.getRestrictedUserCodes(RESTRICTION_TYPE)); } @Test(expected = ServiceException.class) public void getRestrictedUserCodesShouldThrowExceptionOnError() throws Exception { when(mockDatabase.getRestrictedUserCodes(RESTRICTION_TYPE)).thenThrow(new DatabaseException()); service.getRestrictedUserCodes(RESTRICTION_TYPE); } @Test public void clearRestrictedUserCodesShouldDelegateToDatabase() throws Exception { service.clearRestrictedUserCodes(RESTRICTION_TYPE); verify(mockDatabase).clearRestrictedUserCodes(RESTRICTION_TYPE); } @Test(expected = ServiceException.class) public void clearRestrictedUserCodesShouldThrowExceptionOnError() throws Exception { doThrow(new DatabaseException()).when(mockDatabase).clearRestrictedUserCodes(RESTRICTION_TYPE); service.clearRestrictedUserCodes(RESTRICTION_TYPE); } @Test public void addRestrictedRemoteAddressShouldDelegateToDatabase() throws Exception { service.addRestrictedRemoteAddress(REMOTE_ADDRESS, RESTRICTION_TYPE); verify(mockDatabase).addRestrictedRemoteAddress(REMOTE_ADDRESS, RESTRICTION_TYPE); } @Test(expected = ServiceException.class) public void addRestrictedRemoteAddressShouldThrowExceptionOnError() throws Exception { doThrow(new DatabaseException()).when(mockDatabase).addRestrictedRemoteAddress(REMOTE_ADDRESS, RESTRICTION_TYPE); service.addRestrictedRemoteAddress(REMOTE_ADDRESS, RESTRICTION_TYPE); } @Test public void removeRestrictedRemoteAddressShouldDelegateToDatabase() throws Exception { service.removeRestrictedRemoteAddress(REMOTE_ADDRESS, RESTRICTION_TYPE); verify(mockDatabase).removeRestrictedRemoteAddress(REMOTE_ADDRESS, RESTRICTION_TYPE); } @Test(expected = ServiceException.class) public void removeRestrictedRemoteAddressShouldThrowExceptionOnError() throws Exception { doThrow(new DatabaseException()).when(mockDatabase).removeRestrictedRemoteAddress( REMOTE_ADDRESS, RESTRICTION_TYPE); service.removeRestrictedRemoteAddress(REMOTE_ADDRESS, RESTRICTION_TYPE); } @Test public void getRestrictedRemoteAddressesShouldDelegateToDatabase() throws Exception { when(mockDatabase.getRestrictedRemoteAddresses(RESTRICTION_TYPE)).thenReturn( ImmutableSet.of(REMOTE_ADDRESS)); assertEquals(ImmutableSet.of(REMOTE_ADDRESS), service.getRestrictedRemoteAddresses(RESTRICTION_TYPE)); } @Test(expected = ServiceException.class) public void getRestrictedRemoteAddressesShouldThrowExceptionOnError() throws Exception { when(mockDatabase.getRestrictedRemoteAddresses(RESTRICTION_TYPE)).thenThrow( new DatabaseException()); service.getRestrictedRemoteAddresses(RESTRICTION_TYPE); } @Test public void clearRestrictedRemoteAddressesShouldDelegateToDatabase() throws Exception { service.clearRestrictedRemoteAddresses(RESTRICTION_TYPE); verify(mockDatabase).clearRestrictedRemoteAddresses(RESTRICTION_TYPE); } @Test(expected = ServiceException.class) public void clearRestrictedRemoteAddressesShouldThrowExceptionOnError() throws Exception { doThrow(new DatabaseException()).when(mockDatabase).clearRestrictedRemoteAddresses( RESTRICTION_TYPE); service.clearRestrictedRemoteAddresses(RESTRICTION_TYPE); } @Test public void lookupUserCodeByGooglePlusIdShouldDelegateToDatabase() throws Exception { when(mockDatabase.lookupUserCodeByGooglePlusId(GOOGLE_PLUS_ID)).thenReturn( ImmutableList.of(TestDataProvider.getUserData())); assertEquals(ImmutableList.of(TestDataProvider.getUserData()), service.lookupUserDataByGooglePlusId(GOOGLE_PLUS_ID)); } @Test(expected = ServiceException.class) public void lookupUserCodeByGooglePlusIdShouldThrowExceptionOnError() throws Exception { when(mockDatabase.lookupUserCodeByGooglePlusId(GOOGLE_PLUS_ID)).thenThrow( new DatabaseException()); assertEquals(USER_CODE, service.lookupUserDataByGooglePlusId(GOOGLE_PLUS_ID)); } @Test public void disconnectUserCodeShouldDelegateToDatabase() throws Exception { service.disconnectUserCode(USER_CODE); verify(mockDatabase).disconnectUserCodeFromGooglePlus(USER_CODE); } @Test(expected = ServiceException.class) public void disconnectUserCodeShouldThrowExceptionOnError() throws Exception { doThrow(new DatabaseException()).when(mockDatabase).disconnectUserCodeFromGooglePlus(USER_CODE); service.disconnectUserCode(USER_CODE); } @Test public void canUploadProblemReturnsFalseIfNewProblemWithManyCreations() throws Exception { when(mockDatabase.getProblem(ImmutableList.of(PROBLEM_ID))).thenReturn( ImmutableList.of(createProblem(ProblemGenre.Anige))); when(mockDatabase.getNumberOfCreationLogWithMachineIp(isA(String.class), isA(Long.class))) .thenReturn(100); when(mockDatabase.getNumberOfCreationLogWithUserCode(isA(Integer.class), isA(Long.class))) .thenReturn(100); doReturn(REMOTE_ADDRESS).when(service).getRemoteAddress(); assertThat(service.canUploadProblem(USER_CODE, null)).isFalse(); } @Test public void canUploadProblemReturnsTrueIfFromAnigeWithManyCreations() throws Exception { when(mockDatabase.getProblem(ImmutableList.of(PROBLEM_ID))).thenReturn( ImmutableList.of(createProblem(ProblemGenre.Anige))); when(mockDatabase.getNumberOfCreationLogWithMachineIp(isA(String.class), isA(Long.class))) .thenReturn(100); when(mockDatabase.getNumberOfCreationLogWithUserCode(isA(Integer.class), isA(Long.class))) .thenReturn(100); doReturn(REMOTE_ADDRESS).when(service).getRemoteAddress(); assertThat(service.canUploadProblem(USER_CODE, PROBLEM_ID)).isTrue(); } @Test public void canUploadProblemReturnsFalseIfFromNonAnigeWithManyCreations() throws Exception { when(mockDatabase.getProblem(ImmutableList.of(PROBLEM_ID))).thenReturn( ImmutableList.of(createProblem(ProblemGenre.Gakumon))); when(mockDatabase.getNumberOfCreationLogWithMachineIp(isA(String.class), isA(Long.class))) .thenReturn(100); when(mockDatabase.getNumberOfCreationLogWithUserCode(isA(Integer.class), isA(Long.class))) .thenReturn(100); doReturn(REMOTE_ADDRESS).when(service).getRemoteAddress(); assertThat(service.canUploadProblem(USER_CODE, PROBLEM_ID)).isFalse(); } @Test public void canUploadProblemReturnsTrueIfFromAnigeWithSmallCreations() throws Exception { when(mockDatabase.getProblem(ImmutableList.of(PROBLEM_ID))).thenReturn( ImmutableList.of(createProblem(ProblemGenre.Anige))); when(mockDatabase.getNumberOfCreationLogWithMachineIp(isA(String.class), isA(Long.class))) .thenReturn(0); when(mockDatabase.getNumberOfCreationLogWithUserCode(isA(Integer.class), isA(Long.class))) .thenReturn(0); doReturn(REMOTE_ADDRESS).when(service).getRemoteAddress(); assertThat(service.canUploadProblem(USER_CODE, PROBLEM_ID)).isTrue(); } private static PacketProblem createProblem(ProblemGenre genre) { PacketProblem problem = new PacketProblem(); problem.genre = genre; return problem; } }