package com.github.jreddit.oauth; 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.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.apache.commons.validator.routines.UrlValidator; import org.apache.oltu.oauth2.client.OAuthClient; import org.apache.oltu.oauth2.client.request.OAuthClientRequest; import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse; import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.github.jreddit.oauth.app.RedditApp; import com.github.jreddit.oauth.app.RedditInstalledApp; import com.github.jreddit.oauth.app.RedditScriptApp; import com.github.jreddit.oauth.app.RedditWebApp; import com.github.jreddit.oauth.exception.RedditOAuthException; import com.github.jreddit.oauth.param.RedditDuration; import com.github.jreddit.oauth.param.RedditScope; import com.github.jreddit.oauth.param.RedditScopeBuilder; @RunWith(MockitoJUnitRunner.class) public class RedditOAuthAgentTest { @Mock private OAuthClient mockOAuthClient; @Mock private OAuthJSONAccessTokenResponse jsonToken; @Mock private OAuthJSONAccessTokenResponse jsonTokenNonRefreshable; @Mock private RedditToken mockRedditToken; @Mock private RedditToken mockRedditTokenRefreshable; private final String userAgent = "Test User Agent / 2.0"; private final String clientID = "35_398598298592"; private final String clientSecret = "dsuf9a8f92"; private final String redirectURI = "http://www.example.com/"; private String accessToken = "djsaf98s9fasjofjkasjdf9"; private String refreshToken = "89sd89fafjdajiofafsfasf"; private String tokenType = "bearer"; private long expiresIn = 1; private String scope = "edit,flair"; private String code = "dioua97f98f9a893oa98fa098093805aklajlaa_"; private RedditOAuthAgent subject; @Before public void setup() { RedditScriptApp app = new RedditScriptApp(clientID, clientSecret, redirectURI); subject = new RedditOAuthAgent(userAgent, app, mockOAuthClient); when(jsonToken.getAccessToken()).thenReturn(accessToken); when(jsonToken.getRefreshToken()).thenReturn(refreshToken); when(jsonToken.getParam(RedditToken.PARAM_TOKEN_TYPE)).thenReturn(tokenType); when(jsonToken.getExpiresIn()).thenReturn(expiresIn); when(jsonToken.getScope()).thenReturn(scope); when(jsonTokenNonRefreshable.getAccessToken()).thenReturn(accessToken); when(jsonTokenNonRefreshable.getRefreshToken()).thenReturn(null); when(jsonTokenNonRefreshable.getParam(RedditToken.PARAM_TOKEN_TYPE)).thenReturn(tokenType); when(jsonTokenNonRefreshable.getExpiresIn()).thenReturn(expiresIn); when(jsonTokenNonRefreshable.getScope()).thenReturn(scope); when(mockRedditToken.isRefreshable()).thenReturn(false); when(mockRedditTokenRefreshable.isRefreshable()).thenReturn(true); } @Test public void testDefaultConstructor() { RedditApp app = new RedditWebApp(clientID, clientSecret, redirectURI); new RedditOAuthAgent(userAgent, app); app = new RedditScriptApp(clientID, clientSecret, redirectURI); new RedditOAuthAgent(userAgent, app); app = new RedditInstalledApp(clientID, redirectURI); new RedditOAuthAgent(userAgent, app); } @Test public void testGenerateCodeFlowURI() { RedditScopeBuilder builder = new RedditScopeBuilder(); builder.addScope(RedditScope.EDIT); String url = subject.generateCodeFlowURI(builder, RedditDuration.PERMANENT); UrlValidator urlValidator = new UrlValidator(); assertTrue(urlValidator.isValid(url)); } @Test public void testGenerateImplicitFlowURI() { RedditScopeBuilder builder = new RedditScopeBuilder(); builder.addScope(RedditScope.FLAIR); String url = subject.generateImplicitFlowURI(builder); UrlValidator urlValidator = new UrlValidator(); assertTrue(urlValidator.isValid(url)); } @Test public void testTokenFromInfo() { RedditToken token = subject.tokenFromInfo(accessToken, tokenType, expiresIn, scope); assertEquals(accessToken, token.getAccessToken()); assertEquals(tokenType, token.getTokenType()); assertEquals(expiresIn, token.getExpirationSpan()); assertTrue(token.hasScope(RedditScope.EDIT)); assertTrue(token.hasScope(RedditScope.FLAIR)); assertFalse(token.hasScope(RedditScope.PRIVATEMESSAGE)); } @Test public void testToken() throws RedditOAuthException, OAuthSystemException, OAuthProblemException { // Captor for the request that is executed ArgumentCaptor<OAuthClientRequest> clientCaptor = ArgumentCaptor.forClass(OAuthClientRequest.class); when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenReturn(jsonToken); // Run subject RedditToken token = subject.token(code); // Verify and capture verify(mockOAuthClient).accessToken(clientCaptor.capture()); OAuthClientRequest request = clientCaptor.getValue(); assertNotNull(request.getHeader("Authorization")); // This is Base64 encoded assertEquals(request.getHeader("User-Agent"), userAgent); assertEquals(accessToken, token.getAccessToken()); assertEquals(refreshToken, token.getRefreshToken()); assertEquals(tokenType, token.getTokenType()); assertEquals(expiresIn, token.getExpirationSpan()); assertTrue(token.hasScope(RedditScope.EDIT)); assertTrue(token.hasScope(RedditScope.FLAIR)); assertFalse(token.hasScope(RedditScope.PRIVATEMESSAGE)); } @Test(expected=RedditOAuthException.class) public void testTokenOAuthSystemException() throws OAuthSystemException, OAuthProblemException, RedditOAuthException { when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenThrow(new OAuthSystemException()); subject.token(code); } @Test(expected=RedditOAuthException.class) public void testTokenOAuthProblemException() throws OAuthSystemException, OAuthProblemException, RedditOAuthException { when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenThrow(OAuthProblemException.error("Error")); subject.token(code); } @Test public void testRefreshTokenFailure() throws RedditOAuthException, OAuthSystemException, OAuthProblemException { assertFalse(subject.refreshToken(mockRedditToken)); } @Test public void testRefreshTokenSuccess() throws RedditOAuthException, OAuthSystemException, OAuthProblemException { assertTrue(subject.refreshToken(mockRedditTokenRefreshable)); verify(mockOAuthClient).accessToken(any(OAuthClientRequest.class)); verify(mockRedditTokenRefreshable).refresh(null); } @Test(expected=RedditOAuthException.class) public void testRefreshTokenOAuthSystemException() throws OAuthSystemException, OAuthProblemException, RedditOAuthException { when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenThrow(new OAuthSystemException()); subject.refreshToken(mockRedditTokenRefreshable); } @Test(expected=RedditOAuthException.class) public void testRefreshTokenOAuthProblemException() throws OAuthSystemException, OAuthProblemException, RedditOAuthException { when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenThrow(OAuthProblemException.error("Error")); subject.refreshToken(mockRedditTokenRefreshable); } @Test public void testTokenAppOnlyConfidential() throws RedditOAuthException, OAuthSystemException, OAuthProblemException { // Captor for the request that is executed ArgumentCaptor<OAuthClientRequest> clientCaptor = ArgumentCaptor.forClass(OAuthClientRequest.class); when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenReturn(jsonTokenNonRefreshable); // Run subject RedditToken token = subject.tokenAppOnly(true); // Verify and capture verify(mockOAuthClient).accessToken(clientCaptor.capture()); OAuthClientRequest request = clientCaptor.getValue(); assertNotNull(request.getHeader("Authorization")); // This is Base64 encoded assertEquals(request.getHeader("User-Agent"), userAgent); assertEquals(accessToken, token.getAccessToken()); assertNull(token.getRefreshToken()); assertEquals(tokenType, token.getTokenType()); assertEquals(expiresIn, token.getExpirationSpan()); assertTrue(token.hasScope(RedditScope.EDIT)); assertTrue(token.hasScope(RedditScope.FLAIR)); assertFalse(token.hasScope(RedditScope.PRIVATEMESSAGE)); } @Test public void testTokenAppOnly() throws RedditOAuthException, OAuthSystemException, OAuthProblemException { // Captor for the request that is executed ArgumentCaptor<OAuthClientRequest> clientCaptor = ArgumentCaptor.forClass(OAuthClientRequest.class); when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenReturn(jsonTokenNonRefreshable); // Run subject RedditToken token = subject.tokenAppOnly(false); // Verify and capture verify(mockOAuthClient).accessToken(clientCaptor.capture()); OAuthClientRequest request = clientCaptor.getValue(); assertNotNull(request.getHeader("Authorization")); // This is Base64 encoded assertEquals(request.getHeader("User-Agent"), userAgent); assertEquals(accessToken, token.getAccessToken()); assertNull(token.getRefreshToken()); assertEquals(tokenType, token.getTokenType()); assertEquals(expiresIn, token.getExpirationSpan()); assertTrue(token.hasScope(RedditScope.EDIT)); assertTrue(token.hasScope(RedditScope.FLAIR)); assertFalse(token.hasScope(RedditScope.PRIVATEMESSAGE)); } @Test(expected=RedditOAuthException.class) public void testTokenAppOnlyOAuthSystemException() throws OAuthSystemException, OAuthProblemException, RedditOAuthException { when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenThrow(new OAuthSystemException()); subject.tokenAppOnly(false); } @Test(expected=RedditOAuthException.class) public void testTokenAppOnlyOAuthProblemException() throws OAuthSystemException, OAuthProblemException, RedditOAuthException { when(mockOAuthClient.accessToken(any(OAuthClientRequest.class))).thenThrow(OAuthProblemException.error("Error")); subject.tokenAppOnly(false); } @Test public void testRevoke() throws RedditOAuthException, OAuthSystemException, OAuthProblemException { assertTrue(subject.revoke(null, false)); } }