package com.linecorp.linesdk.api.internal; import android.net.Uri; import com.linecorp.linesdk.BuildConfig; import com.linecorp.linesdk.LineAccessToken; import com.linecorp.linesdk.LineApiError; import com.linecorp.linesdk.LineApiResponse; import com.linecorp.linesdk.LineApiResponseCode; import com.linecorp.linesdk.LineCredential; import com.linecorp.linesdk.LineFriendshipStatus; import com.linecorp.linesdk.LineProfile; import com.linecorp.linesdk.Scope; import com.linecorp.linesdk.TestConfig; import com.linecorp.linesdk.TestStringCipher; import com.linecorp.linesdk.api.LineApiClient; import com.linecorp.linesdk.internal.AccessTokenCache; import com.linecorp.linesdk.internal.AccessTokenVerificationResult; import com.linecorp.linesdk.internal.InternalAccessToken; import com.linecorp.linesdk.internal.RefreshTokenResult; import com.linecorp.linesdk.internal.nwclient.LineAuthenticationApiClient; import com.linecorp.linesdk.internal.nwclient.TalkApiClient; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.Arrays; import java.util.Collections; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; /** * Test for {@link LineApiClient}. */ @RunWith(RobolectricTestRunner.class) @Config(sdk = TestConfig.TARGET_SDK_VERSION) public class LineApiClientImplTest { private static final String CHANNEL_ID = "123"; private static final InternalAccessToken ACCESS_TOKEN = new InternalAccessToken("accessToken", 10L, 100L, "refreshToken"); private static final LineProfile PROFILE = new LineProfile( "mid", "displayName", Uri.parse("https://picture.url"), "statusMessage"); private static final LineFriendshipStatus FRIENDSHIP_STATUS = new LineFriendshipStatus(true); @Mock private LineAuthenticationApiClient internalOauthApiClient; @Mock private TalkApiClient internalTalkApiClient; private AccessTokenCache accessTokenCache; private LineApiClient target; @Before public void setUp() { MockitoAnnotations.initMocks(this); accessTokenCache = new AccessTokenCache( RuntimeEnvironment.application, CHANNEL_ID, new TestStringCipher()); target = new LineApiClientImpl( CHANNEL_ID, internalOauthApiClient, internalTalkApiClient, accessTokenCache); } @Test public void testLogout() { LineApiResponse<?> expectedResponse = LineApiResponse.createAsSuccess(new Object()); doReturn(expectedResponse) .when(internalOauthApiClient) .revokeRefreshToken(anyString(), any(InternalAccessToken.class)); accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<?> actualResponse = target.logout(); assertSame(expectedResponse, actualResponse); verify(internalOauthApiClient, times(1)).revokeRefreshToken(CHANNEL_ID, ACCESS_TOKEN); assertNull(accessTokenCache.getAccessToken()); } @Test public void testLogoutWithApiCallError() { LineApiResponse<?> expectedResponse = LineApiResponse.createAsError( LineApiResponseCode.INTERNAL_ERROR, LineApiError.DEFAULT); doReturn(expectedResponse) .when(internalOauthApiClient) .revokeRefreshToken(anyString(), any(InternalAccessToken.class)); accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<?> actualResponse = target.logout(); assertSame(expectedResponse, actualResponse); verify(internalOauthApiClient, times(1)).revokeRefreshToken(CHANNEL_ID, ACCESS_TOKEN); assertEquals(ACCESS_TOKEN, accessTokenCache.getAccessToken()); } @Test public void testLogoutWithNoAccessToken() { LineApiResponse<?> response = target.logout(); assertFalse(response.isSuccess()); assertSame(response.getResponseCode(), LineApiResponseCode.INTERNAL_ERROR); } @Test public void testRefreshToken() { accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<RefreshTokenResult> refreshTokenResponse = LineApiResponse.createAsSuccess(new RefreshTokenResult( "newAccessToken", 999L, "newRefreshToken", Collections.emptyList())); doReturn(refreshTokenResponse) .when(internalOauthApiClient) .refreshToken(anyString(), any(InternalAccessToken.class)); LineApiResponse<LineAccessToken> actualResponse = target.refreshAccessToken(); verify(internalOauthApiClient, times(1)).refreshToken(CHANNEL_ID, ACCESS_TOKEN); assertTrue(actualResponse.isSuccess()); assertNotNull(actualResponse.getResponseData()); assertEquals("newAccessToken", actualResponse.getResponseData().getTokenString()); assertEquals(999L, actualResponse.getResponseData().getExpiresInMillis()); InternalAccessToken newAccessToken = accessTokenCache.getAccessToken(); assertNotNull(newAccessToken); assertEquals("newAccessToken", newAccessToken.getAccessToken()); assertEquals(999L, newAccessToken.getExpiresInMillis()); assertTrue(newAccessToken.getIssuedClientTimeMillis() > 0); assertEquals("newRefreshToken", newAccessToken.getRefreshToken()); } @Test public void testRefreshTokenWithNoRefreshToken() { accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<RefreshTokenResult> refreshTokenResponse = LineApiResponse.createAsSuccess(new RefreshTokenResult( "newAccessToken", 999L, null, Collections.emptyList())); doReturn(refreshTokenResponse) .when(internalOauthApiClient) .refreshToken(anyString(), any(InternalAccessToken.class)); LineApiResponse<LineAccessToken> actualResponse = target.refreshAccessToken(); verify(internalOauthApiClient, times(1)).refreshToken(CHANNEL_ID, ACCESS_TOKEN); assertTrue(actualResponse.isSuccess()); assertNotNull(actualResponse.getResponseData()); assertEquals("newAccessToken", actualResponse.getResponseData().getTokenString()); assertEquals(999L, actualResponse.getResponseData().getExpiresInMillis()); assertTrue(actualResponse.getResponseData().getIssuedClientTimeMillis() > 0); InternalAccessToken newAccessToken = accessTokenCache.getAccessToken(); assertNotNull(newAccessToken); assertEquals("newAccessToken", newAccessToken.getAccessToken()); assertEquals(999L, newAccessToken.getExpiresInMillis()); assertTrue(newAccessToken.getIssuedClientTimeMillis() > 0); assertEquals(ACCESS_TOKEN.getRefreshToken(), newAccessToken.getRefreshToken()); } @Test public void testRefreshTokenWithApiError() { accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<RefreshTokenResult> refreshTokenResponse = LineApiResponse.createAsError( LineApiResponseCode.INTERNAL_ERROR, LineApiError.DEFAULT); doReturn(refreshTokenResponse) .when(internalOauthApiClient) .refreshToken(anyString(), any(InternalAccessToken.class)); LineApiResponse<LineAccessToken> actualResponse = target.refreshAccessToken(); verify(internalOauthApiClient, times(1)).refreshToken(CHANNEL_ID, ACCESS_TOKEN); assertFalse(actualResponse.isSuccess()); assertEquals(ACCESS_TOKEN, accessTokenCache.getAccessToken()); } @Test public void testGetProfile() { LineApiResponse<LineProfile> expectedResponse = LineApiResponse.createAsSuccess(PROFILE); doReturn(expectedResponse) .when(internalTalkApiClient) .getProfile(any(InternalAccessToken.class)); accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<LineProfile> actualResponse = target.getProfile(); assertSame(expectedResponse, actualResponse); verify(internalTalkApiClient, times(1)).getProfile(ACCESS_TOKEN); } @Test public void testGetProfileWithApiCallError() { LineApiResponse<LineProfile> expectedResponse = LineApiResponse.createAsError( LineApiResponseCode.INTERNAL_ERROR, LineApiError.DEFAULT); doReturn(expectedResponse) .when(internalTalkApiClient) .getProfile(any(InternalAccessToken.class)); accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<LineProfile> actualResponse = target.getProfile(); assertSame(expectedResponse, actualResponse); verify(internalTalkApiClient, times(1)).getProfile(ACCESS_TOKEN); } @Test public void testGetProfileWithNoAccessToken() { LineApiResponse<?> response = target.getProfile(); assertFalse(response.isSuccess()); assertSame(response.getResponseCode(), LineApiResponseCode.INTERNAL_ERROR); } @Test public void testGetFriendshipStatus() { LineApiResponse<LineFriendshipStatus> expectedResponse = LineApiResponse.createAsSuccess(FRIENDSHIP_STATUS); doReturn(expectedResponse) .when(internalTalkApiClient) .getFriendshipStatus(any(InternalAccessToken.class)); accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<LineFriendshipStatus> actualResponse = target.getFriendshipStatus(); assertSame(expectedResponse, actualResponse); verify(internalTalkApiClient, times(1)).getFriendshipStatus(ACCESS_TOKEN); } @Test public void testGetFriendshipStatusWithApiCallError() { LineApiResponse<LineFriendshipStatus> expectedResponse = LineApiResponse.createAsError( LineApiResponseCode.INTERNAL_ERROR, LineApiError.DEFAULT); doReturn(expectedResponse) .when(internalTalkApiClient) .getFriendshipStatus(any(InternalAccessToken.class)); accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<LineFriendshipStatus> actualResponse = target.getFriendshipStatus(); assertSame(expectedResponse, actualResponse); verify(internalTalkApiClient, times(1)).getFriendshipStatus(ACCESS_TOKEN); } @Test public void testGetFriendshipStatusWithNoAccessToken() { LineApiResponse<?> response = target.getFriendshipStatus(); assertFalse(response.isSuccess()); assertSame(response.getResponseCode(), LineApiResponseCode.INTERNAL_ERROR); } @Test public void testVerifyToken() { LineApiResponse<AccessTokenVerificationResult> expectedResponse = LineApiResponse.createAsSuccess(new AccessTokenVerificationResult( "1234", 3L, Arrays.asList(Scope.FRIEND, Scope.GROUP))); doReturn(expectedResponse) .when(internalOauthApiClient) .verifyAccessToken(any(InternalAccessToken.class)); accessTokenCache.saveAccessToken(ACCESS_TOKEN); LineApiResponse<LineCredential> actualResponse = target.verifyToken(); assertTrue(actualResponse.isSuccess()); verify(internalOauthApiClient, times(1)).verifyAccessToken(ACCESS_TOKEN); LineAccessToken verifiedAccessToken = actualResponse.getResponseData().getAccessToken(); assertEquals(ACCESS_TOKEN.getAccessToken(), verifiedAccessToken.getTokenString()); assertEquals(3L, verifiedAccessToken.getExpiresInMillis()); assertTrue(ACCESS_TOKEN.getIssuedClientTimeMillis() != verifiedAccessToken.getIssuedClientTimeMillis()); assertEquals(3L, verifiedAccessToken.getExpiresInMillis()); assertEquals(Arrays.asList(Scope.FRIEND, Scope.GROUP), actualResponse.getResponseData().getScopes()); InternalAccessToken newAccessToken = accessTokenCache.getAccessToken(); assertEquals(ACCESS_TOKEN.getAccessToken(), newAccessToken.getAccessToken()); assertEquals(3L, newAccessToken.getExpiresInMillis()); assertTrue(newAccessToken.getIssuedClientTimeMillis() != ACCESS_TOKEN.getIssuedClientTimeMillis()); assertEquals(ACCESS_TOKEN.getRefreshToken(), newAccessToken.getRefreshToken()); } @Test public void testVerifyTokenWithNoAccessToken() { LineApiResponse<LineCredential> response = target.verifyToken(); assertFalse(response.isSuccess()); assertSame(response.getResponseCode(), LineApiResponseCode.INTERNAL_ERROR); } @Test public void testGetCurrentAccessToken() { LineApiResponse<LineAccessToken> response; LineAccessToken actualAccessToken; // the cached access token is null. response = target.getCurrentAccessToken(); assertFalse(response.isSuccess()); // the cached access token is not null. accessTokenCache.saveAccessToken(ACCESS_TOKEN); response = target.getCurrentAccessToken(); assertTrue(response.isSuccess()); actualAccessToken = response.getResponseData(); assertNotNull(actualAccessToken); assertEquals(ACCESS_TOKEN.getAccessToken(), actualAccessToken.getTokenString()); assertEquals(ACCESS_TOKEN.getExpiresInMillis(), actualAccessToken.getExpiresInMillis()); assertEquals(ACCESS_TOKEN.getIssuedClientTimeMillis(), actualAccessToken.getIssuedClientTimeMillis()); } }