Refactoring: renamed package de.juplo.facebook.exceptions to errors
[facebook-utils] / src / test / java / de / juplo / facebook / errors / GraphApiErrorHandlerTest.java
diff --git a/src/test/java/de/juplo/facebook/errors/GraphApiErrorHandlerTest.java b/src/test/java/de/juplo/facebook/errors/GraphApiErrorHandlerTest.java
new file mode 100644 (file)
index 0000000..9fc7fc3
--- /dev/null
@@ -0,0 +1,802 @@
+package de.juplo.facebook.errors;
+
+
+import de.juplo.facebook.errors.GraphApiException.Type;
+import java.util.Date;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Resource;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.oauth2.client.OAuth2RestTemplate;
+import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
+import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
+import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
+import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
+import org.springframework.security.oauth2.client.token.AccessTokenProvider;
+import org.springframework.security.oauth2.client.token.AccessTokenRequest;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import static org.springframework.security.oauth2.common.OAuth2AccessToken.OAUTH2_TYPE;
+import org.springframework.security.oauth2.common.OAuth2RefreshToken;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.client.HttpClientErrorException;
+
+
+
+/**
+ *
+ * @author Kai Moritz
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(
+  locations = {
+    "classpath:/spring/test-facebook-error-handler.xml"
+    })
+public class GraphApiErrorHandlerTest
+{
+  private static final Logger log =
+      LoggerFactory.getLogger(GraphApiErrorHandlerTest.class);
+
+  @Resource
+  private OAuth2RestTemplate clientTemplate;
+
+  private MockClientHttpRequestFactory requestFactory;
+
+
+  @Test
+  public void testError1()
+  {
+    log.info("testError1");
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"An unknown error has occurred.\",\n" +
+        "    \"type\": \"OAuthException\",\n" +
+        "    \"code\": 1\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(UnknownErrorException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("invalid_request", e.getOAuth2ErrorCode());
+      assertEquals(new Integer(1), e.getCode());
+      assertEquals("An unknown error has occurred.", e.getMessage());
+      assertEquals(Type.OAuthException, e.getType());
+    }
+  }
+
+  @Test
+  public void testError2()
+  {
+    log.info("testError2");
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"An unexpected error has occurred. Please retry your request later.\",\n" +
+        "    \"type\": \"OAuthException\",\n" +
+        "    \"code\": 2\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(UnexpectedErrorException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("invalid_request", e.getOAuth2ErrorCode());
+      assertEquals(new Integer(2), e.getCode());
+      assertEquals("An unexpected error has occurred. Please retry your request later.", e.getMessage());
+      assertEquals(Type.OAuthException, e.getType());
+    }
+  }
+
+  @Test
+  public void testError21()
+  {
+    log.info("testError21");
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"(#21) Page ID 590408587650316 was migrated to page ID 1421620791415603.  Please update your API calls to the new ID\",\n" +
+        "    \"type\": \"OAuthException\",\n" +
+        "    \"code\": 21\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(PageMigratedException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("invalid_request", e.getOAuth2ErrorCode());
+      assertEquals(new Integer(21), e.getCode());
+      assertEquals("(#21) Page ID 590408587650316 was migrated to page ID 1421620791415603.  Please update your API calls to the new ID", e.getMessage());
+      assertEquals(Type.OAuthException, e.getType());
+    }
+  }
+
+  @Test
+  public void testError100()
+  {
+    log.info("testError100");
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"Unsupported get request.\",\n" +
+        "    \"type\": \"GraphMethodException\",\n" +
+        "    \"code\": 100\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(UnsupportedGetRequestException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("invalid_request", e.getOAuth2ErrorCode());
+      assertEquals(new Integer(100), e.getCode());
+      assertEquals("Unsupported get request.", e.getMessage());
+      assertEquals(Type.GraphMethodException, e.getType());
+    }
+  }
+
+  @Test
+  public void testError104()
+  {
+    log.info("testError104");
+
+    requestFactory.setBody("{\"error\":{\"message\":\"An access token is required to request this resource.\",\"type\":\"OAuthException\",\"code\":104,\"fbtrace_id\":\"E2Jjkj5++LL\"}}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(AccessTokenRequiredException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("invalid_request", e.getOAuth2ErrorCode());
+      assertEquals(new Integer(104), e.getCode());
+      assertEquals("An access token is required to request this resource.", e.getMessage());
+      assertEquals(Type.OAuthException, e.getType());
+      assertEquals("E2Jjkj5++LL", e.getTraceId());
+    }
+  }
+
+  @Test
+  public void testError613()
+  {
+    log.info("testError613");
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"(#613) Calls to stream have exceeded the rate of 600 calls per 600 seconds.\",\n" +
+        "    \"type\": \"OAuthException\",\n" +
+        "    \"code\": 613\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(RateExceededException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("invalid_request", e.getOAuth2ErrorCode());
+      assertEquals(new Integer(613), e.getCode());
+      assertEquals("(#613) Calls to stream have exceeded the rate of 600 calls per 600 seconds.", e.getMessage());
+      assertEquals(Type.OAuthException, e.getType());
+    }
+  }
+
+  @Test
+  public void testError2200()
+  {
+    requestFactory.setBody("{\"error\":{\"message\":\"(#2200) callback verification failed: \",\"type\":\"OAuthException\",\"code\":2200,\"fbtrace_id\":\"ESLjoZKvPXg\"}}");
+    
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(CallbackVerificationFailedException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("invalid_request", e.getOAuth2ErrorCode());
+      assertEquals(new Integer(2200), e.getCode());
+      assertEquals("(#2200) callback verification failed: ", e.getMessage());
+      assertEquals(Type.OAuthException, e.getType());
+      assertEquals("ESLjoZKvPXg", e.getTraceId());
+    }
+  }
+
+  @Test
+  public void testUnmappedError()
+  {
+    log.info("testUnmappedError");
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"This error does not exist.\",\n" +
+        "    \"type\": \"NonexistentTypeException\",\n" +
+        "    \"code\": 999999999\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(GraphApiException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("invalid_request", e.getOAuth2ErrorCode());
+      assertEquals(new Integer(999999999), e.getCode());
+      assertEquals("This error does not exist.", e.getMessage());
+      try
+      {
+        Type type = e.getType();
+        log.error("unknown type: {}", type);
+        fail("unmapped type was resolved by enum: " + type);
+      }
+      catch (IllegalArgumentException ee) {}
+    }
+  }
+
+  @Test
+  public void testUnmappedErrors()
+  {
+    log.info("testUnmappedErrors");
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": null,\n" +
+        "    \"type\": \"WhateverTypeException\",\n" +
+        "    \"code\": 999999999\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(UnmappedErrorException e)
+    {
+      log.debug("{}", e.toString());
+      assertNull(e.getMessage());
+      try
+      {
+        Type type = e.getType();
+        log.error("unknown type: {}", type);
+        fail("unmapped type was resolved by enum: " + type);
+      }
+      catch (IllegalArgumentException ee) {}
+      assertEquals(new Integer(999999999), e.getCode());
+      assertNull(e.getSubCode());
+      assertNull(e.getUserTitle());
+      assertNull(e.getUserMessage());
+      assertNull(e.getTraceId());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"type\": \"WhateverTypeException\",\n" +
+        "    \"code\": 999999999\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(UnmappedErrorException e)
+    {
+      log.debug("{}", e.toString());
+      assertNull(e.getMessage());
+      try
+      {
+        Type type = e.getType();
+        log.error("unknown type: {}", type);
+        fail("unmapped type was resolved by enum: " + type);
+      }
+      catch (IllegalArgumentException ee) {}
+      assertEquals(new Integer(999999999), e.getCode());
+      assertNull(e.getSubCode());
+      assertNull(e.getUserTitle());
+      assertNull(e.getUserMessage());
+      assertNull(e.getTraceId());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"An unmapped Graph-API-Exception.\",\n" +
+        "    \"type\": null,\n" +
+        "    \"code\": 999999999\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(UnmappedErrorException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("An unmapped Graph-API-Exception.", e.getMessage());
+      assertNull(e.getType());
+      assertEquals(new Integer(999999999), e.getCode());
+      assertNull(e.getSubCode());
+      assertNull(e.getUserTitle());
+      assertNull(e.getUserMessage());
+      assertNull(e.getTraceId());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"An unmapped Graph-API-Exception.\",\n" +
+        "    \"code\": 999999999\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(UnmappedErrorException e)
+    {
+      log.debug("{}", e.toString());
+      assertEquals("An unmapped Graph-API-Exception.", e.getMessage());
+      assertNull(e.getType());
+      assertEquals(new Integer(999999999), e.getCode());
+      assertNull(e.getSubCode());
+      assertNull(e.getUserTitle());
+      assertNull(e.getUserMessage());
+      assertNull(e.getTraceId());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+  }
+
+  @Test
+  public void testInvlalidErrors()
+  {
+    log.info("testInvalidErrors");
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"Not a Graph-Api-Exception.\",\n" +
+        "    \"type\": \"Whatever\",\n" +
+        "    \"code\": \"some string\"\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"Not a Graph-Api-Exception.\",\n" +
+        "    \"type\": \"Whatever\",\n" +
+        "    \"code\": 9.9\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"Not a Graph-Api-Exception.\",\n" +
+        "    \"type\": \"Whatever\",\n" +
+        "    \"code\": null\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody(
+        "{\n" +
+        "  \"error\":\n" +
+        "  {\n" +
+        "    \"message\": \"Not a Graph-Api-Exception.\",\n" +
+        "    \"type\": \"Whatever\"\n" +
+        "  }\n" +
+        "}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("{\"error\":{\"message\":null}}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("{\"error\":{\"type\":null}}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("{\"error\":{\"code\":null}}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("{\"error\":{}}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("{\"error\":\"some message\"}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("{\"error\":null}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("{\"some filed\":\"some message\"}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("{}");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+
+
+    requestFactory.setBody("");
+
+    try
+    {
+      clientTemplate.getForObject("ANY", SOME.class);
+      fail("The expected exception was not thrown");
+    }
+    catch(HttpClientErrorException e)
+    {
+      log.debug("{}", e.toString());
+    }
+    catch(Exception e)
+    {
+      fail("A wrong exception was thrown: " + e.toString());
+    }
+  }
+
+
+  @Before
+  public void setUp()
+  {
+    requestFactory = new MockClientHttpRequestFactory();
+    requestFactory.setStatus(HttpStatus.BAD_REQUEST);
+    requestFactory.addHeader("Content-Type", "application/json");
+    clientTemplate.setRequestFactory(requestFactory);
+
+    clientTemplate.setErrorHandler(
+        new GraphApiErrorHandler(
+            (OAuth2ErrorHandler)clientTemplate.getErrorHandler()
+            )
+        );
+
+    clientTemplate.setAccessTokenProvider(new AccessTokenProvider()
+    {
+      @Override
+      public OAuth2AccessToken obtainAccessToken(
+          OAuth2ProtectedResourceDetails details,
+          AccessTokenRequest parameters
+          )
+          throws
+            UserRedirectRequiredException,
+            UserApprovalRequiredException,
+            AccessDeniedException
+      {
+        return new OAuth2AccessToken() {
+
+          @Override
+          public Map<String, Object> getAdditionalInformation()
+          {
+            throw new UnsupportedOperationException("Not supported yet.");
+          }
+
+          @Override
+          public Set<String> getScope()
+          {
+            throw new UnsupportedOperationException("Not supported yet.");
+          }
+
+          @Override
+          public OAuth2RefreshToken getRefreshToken()
+          {
+            throw new UnsupportedOperationException("Not supported yet.");
+          }
+
+          @Override
+          public String getTokenType()
+          {
+            return OAUTH2_TYPE;
+          }
+
+          @Override
+          public boolean isExpired()
+          {
+            return false;
+          }
+
+          @Override
+          public Date getExpiration()
+          {
+            throw new UnsupportedOperationException("Not supported yet.");
+          }
+
+          @Override
+          public int getExpiresIn()
+          {
+            throw new UnsupportedOperationException("Not supported yet.");
+          }
+
+          @Override
+          public String getValue()
+          {
+            return "ANY";
+          }
+        };
+      }
+
+      @Override
+      public boolean supportsResource(OAuth2ProtectedResourceDetails resource)
+      {
+        return true;
+      }
+
+      @Override
+      public OAuth2AccessToken refreshAccessToken(
+          OAuth2ProtectedResourceDetails resource,
+          OAuth2RefreshToken refreshToken,
+          AccessTokenRequest request
+          )
+          throws
+            UserRedirectRequiredException
+      {
+        throw new UnsupportedOperationException("Not supported yet.");
+      }
+
+      @Override
+      public boolean supportsRefresh(OAuth2ProtectedResourceDetails resource)
+      {
+        return false;
+      }
+    });
+  }
+
+
+  static class SOME
+  {
+  }
+}