Refactoring: moved FacebookErrorMessage in its own file/class
[facebook-utils] / src / test / java / de / juplo / facebook / client / GraphApiErrorHandlerTest.java
1 package de.juplo.facebook.client;
2
3 import de.juplo.facebook.exceptions.AccessTokenRequiredException;
4 import de.juplo.facebook.exceptions.CallbackVerificationFailedException;
5 import de.juplo.facebook.exceptions.UnsupportedGetRequestException;
6 import de.juplo.facebook.exceptions.UnexpectedErrorException;
7 import de.juplo.facebook.exceptions.RateExceededException;
8 import de.juplo.facebook.exceptions.GraphApiException;
9 import de.juplo.facebook.exceptions.GraphApiException.Type;
10 import de.juplo.facebook.exceptions.UnknownErrorException;
11 import de.juplo.facebook.exceptions.PageMigratedException;
12 import de.juplo.facebook.exceptions.UnmappedErrorException;
13 import java.util.Date;
14 import java.util.Map;
15 import java.util.Set;
16 import javax.annotation.Resource;
17 import static org.junit.Assert.*;
18 import org.junit.Before;
19 import org.junit.Test;
20 import org.junit.runner.RunWith;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23 import org.springframework.http.HttpStatus;
24 import org.springframework.security.access.AccessDeniedException;
25 import org.springframework.security.oauth2.client.OAuth2RestTemplate;
26 import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
27 import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
28 import org.springframework.security.oauth2.client.resource.UserApprovalRequiredException;
29 import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
30 import org.springframework.security.oauth2.client.token.AccessTokenProvider;
31 import org.springframework.security.oauth2.client.token.AccessTokenRequest;
32 import org.springframework.security.oauth2.common.OAuth2AccessToken;
33 import static org.springframework.security.oauth2.common.OAuth2AccessToken.OAUTH2_TYPE;
34 import org.springframework.security.oauth2.common.OAuth2RefreshToken;
35 import org.springframework.test.context.ContextConfiguration;
36 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
37 import org.springframework.web.client.HttpClientErrorException;
38
39
40
41 /**
42  *
43  * @author kai
44  */
45 @RunWith(SpringJUnit4ClassRunner.class)
46 @ContextConfiguration(
47   locations = {
48     "classpath:/spring/test-facebook-error-handler.xml"
49     })
50 public class GraphApiErrorHandlerTest
51 {
52   private static final Logger log =
53       LoggerFactory.getLogger(GraphApiErrorHandlerTest.class);
54
55   @Resource
56   private OAuth2RestTemplate clientTemplate;
57
58   private MockClientHttpRequestFactory requestFactory;
59
60
61   @Test
62   public void testError1()
63   {
64     log.info("testError1");
65
66
67     requestFactory.setBody(
68         "{\n" +
69         "  \"error\":\n" +
70         "  {\n" +
71         "    \"message\": \"An unknown error has occurred.\",\n" +
72         "    \"type\": \"OAuthException\",\n" +
73         "    \"code\": 1\n" +
74         "  }\n" +
75         "}");
76
77     try
78     {
79       clientTemplate.getForObject("ANY", SOME.class);
80       fail("The expected exception was not thrown");
81     }
82     catch(UnknownErrorException e)
83     {
84       log.debug("{}", e.toString());
85       assertEquals("invalid_request", e.getOAuth2ErrorCode());
86       assertEquals(new Integer(1), e.getCode());
87       assertEquals("An unknown error has occurred.", e.getMessage());
88       assertEquals(Type.OAuthException, e.getType());
89     }
90   }
91
92   @Test
93   public void testError2()
94   {
95     log.info("testError2");
96
97
98     requestFactory.setBody(
99         "{\n" +
100         "  \"error\":\n" +
101         "  {\n" +
102         "    \"message\": \"An unexpected error has occurred. Please retry your request later.\",\n" +
103         "    \"type\": \"OAuthException\",\n" +
104         "    \"code\": 2\n" +
105         "  }\n" +
106         "}");
107
108     try
109     {
110       clientTemplate.getForObject("ANY", SOME.class);
111       fail("The expected exception was not thrown");
112     }
113     catch(UnexpectedErrorException e)
114     {
115       log.debug("{}", e.toString());
116       assertEquals("invalid_request", e.getOAuth2ErrorCode());
117       assertEquals(new Integer(2), e.getCode());
118       assertEquals("An unexpected error has occurred. Please retry your request later.", e.getMessage());
119       assertEquals(Type.OAuthException, e.getType());
120     }
121   }
122
123   @Test
124   public void testError21()
125   {
126     log.info("testError21");
127
128
129     requestFactory.setBody(
130         "{\n" +
131         "  \"error\":\n" +
132         "  {\n" +
133         "    \"message\": \"(#21) Page ID 590408587650316 was migrated to page ID 1421620791415603.  Please update your API calls to the new ID\",\n" +
134         "    \"type\": \"OAuthException\",\n" +
135         "    \"code\": 21\n" +
136         "  }\n" +
137         "}");
138
139     try
140     {
141       clientTemplate.getForObject("ANY", SOME.class);
142       fail("The expected exception was not thrown");
143     }
144     catch(PageMigratedException e)
145     {
146       log.debug("{}", e.toString());
147       assertEquals("invalid_request", e.getOAuth2ErrorCode());
148       assertEquals(new Integer(21), e.getCode());
149       assertEquals("(#21) Page ID 590408587650316 was migrated to page ID 1421620791415603.  Please update your API calls to the new ID", e.getMessage());
150       assertEquals(Type.OAuthException, e.getType());
151     }
152   }
153
154   @Test
155   public void testError100()
156   {
157     log.info("testError100");
158
159
160     requestFactory.setBody(
161         "{\n" +
162         "  \"error\":\n" +
163         "  {\n" +
164         "    \"message\": \"Unsupported get request.\",\n" +
165         "    \"type\": \"GraphMethodException\",\n" +
166         "    \"code\": 100\n" +
167         "  }\n" +
168         "}");
169
170     try
171     {
172       clientTemplate.getForObject("ANY", SOME.class);
173       fail("The expected exception was not thrown");
174     }
175     catch(UnsupportedGetRequestException e)
176     {
177       log.debug("{}", e.toString());
178       assertEquals("invalid_request", e.getOAuth2ErrorCode());
179       assertEquals(new Integer(100), e.getCode());
180       assertEquals("Unsupported get request.", e.getMessage());
181       assertEquals(Type.GraphMethodException, e.getType());
182     }
183   }
184
185   @Test
186   public void testError104()
187   {
188     log.info("testError104");
189
190     requestFactory.setBody("{\"error\":{\"message\":\"An access token is required to request this resource.\",\"type\":\"OAuthException\",\"code\":104,\"fbtrace_id\":\"E2Jjkj5++LL\"}}");
191
192     try
193     {
194       clientTemplate.getForObject("ANY", SOME.class);
195       fail("The expected exception was not thrown");
196     }
197     catch(AccessTokenRequiredException e)
198     {
199       log.debug("{}", e.toString());
200       assertEquals("invalid_request", e.getOAuth2ErrorCode());
201       assertEquals(new Integer(104), e.getCode());
202       assertEquals("An access token is required to request this resource.", e.getMessage());
203       assertEquals(Type.OAuthException, e.getType());
204       assertEquals("E2Jjkj5++LL", e.getTraceId());
205     }
206   }
207
208   @Test
209   public void testError613()
210   {
211     log.info("testError613");
212
213
214     requestFactory.setBody(
215         "{\n" +
216         "  \"error\":\n" +
217         "  {\n" +
218         "    \"message\": \"(#613) Calls to stream have exceeded the rate of 600 calls per 600 seconds.\",\n" +
219         "    \"type\": \"OAuthException\",\n" +
220         "    \"code\": 613\n" +
221         "  }\n" +
222         "}");
223
224     try
225     {
226       clientTemplate.getForObject("ANY", SOME.class);
227       fail("The expected exception was not thrown");
228     }
229     catch(RateExceededException e)
230     {
231       log.debug("{}", e.toString());
232       assertEquals("invalid_request", e.getOAuth2ErrorCode());
233       assertEquals(new Integer(613), e.getCode());
234       assertEquals("(#613) Calls to stream have exceeded the rate of 600 calls per 600 seconds.", e.getMessage());
235       assertEquals(Type.OAuthException, e.getType());
236     }
237   }
238
239   @Test
240   public void testError2200()
241   {
242     requestFactory.setBody("{\"error\":{\"message\":\"(#2200) callback verification failed: \",\"type\":\"OAuthException\",\"code\":2200,\"fbtrace_id\":\"ESLjoZKvPXg\"}}");
243     
244     try
245     {
246       clientTemplate.getForObject("ANY", SOME.class);
247       fail("The expected exception was not thrown");
248     }
249     catch(CallbackVerificationFailedException e)
250     {
251       log.debug("{}", e.toString());
252       assertEquals("invalid_request", e.getOAuth2ErrorCode());
253       assertEquals(new Integer(2200), e.getCode());
254       assertEquals("(#2200) callback verification failed: ", e.getMessage());
255       assertEquals(Type.OAuthException, e.getType());
256       assertEquals("ESLjoZKvPXg", e.getTraceId());
257     }
258   }
259
260   @Test
261   public void testUnmappedError()
262   {
263     log.info("testUnmappedError");
264
265
266     requestFactory.setBody(
267         "{\n" +
268         "  \"error\":\n" +
269         "  {\n" +
270         "    \"message\": \"This error does not exist.\",\n" +
271         "    \"type\": \"NonexistentTypeException\",\n" +
272         "    \"code\": 999999999\n" +
273         "  }\n" +
274         "}");
275
276     try
277     {
278       clientTemplate.getForObject("ANY", SOME.class);
279       fail("The expected exception was not thrown");
280     }
281     catch(GraphApiException e)
282     {
283       log.debug("{}", e.toString());
284       assertEquals("invalid_request", e.getOAuth2ErrorCode());
285       assertEquals(new Integer(999999999), e.getCode());
286       assertEquals("This error does not exist.", e.getMessage());
287       try
288       {
289         Type type = e.getType();
290         log.error("unknown type: {}", type);
291         fail("unmapped type was resolved by enum: " + type);
292       }
293       catch (IllegalArgumentException ee) {}
294     }
295   }
296
297   @Test
298   public void testUnmappedErrors()
299   {
300     log.info("testUnmappedErrors");
301
302
303     requestFactory.setBody(
304         "{\n" +
305         "  \"error\":\n" +
306         "  {\n" +
307         "    \"message\": null,\n" +
308         "    \"type\": \"WhateverTypeException\",\n" +
309         "    \"code\": 999999999\n" +
310         "  }\n" +
311         "}");
312
313     try
314     {
315       clientTemplate.getForObject("ANY", SOME.class);
316       fail("The expected exception was not thrown");
317     }
318     catch(UnmappedErrorException e)
319     {
320       log.debug("{}", e.toString());
321       assertNull(e.getMessage());
322       try
323       {
324         Type type = e.getType();
325         log.error("unknown type: {}", type);
326         fail("unmapped type was resolved by enum: " + type);
327       }
328       catch (IllegalArgumentException ee) {}
329       assertEquals(new Integer(999999999), e.getCode());
330       assertNull(e.getSubCode());
331       assertNull(e.getUserTitle());
332       assertNull(e.getUserMessage());
333       assertNull(e.getTraceId());
334     }
335     catch(Exception e)
336     {
337       fail("A wrong exception was thrown: " + e.toString());
338     }
339
340
341     requestFactory.setBody(
342         "{\n" +
343         "  \"error\":\n" +
344         "  {\n" +
345         "    \"type\": \"WhateverTypeException\",\n" +
346         "    \"code\": 999999999\n" +
347         "  }\n" +
348         "}");
349
350     try
351     {
352       clientTemplate.getForObject("ANY", SOME.class);
353       fail("The expected exception was not thrown");
354     }
355     catch(UnmappedErrorException e)
356     {
357       log.debug("{}", e.toString());
358       assertNull(e.getMessage());
359       try
360       {
361         Type type = e.getType();
362         log.error("unknown type: {}", type);
363         fail("unmapped type was resolved by enum: " + type);
364       }
365       catch (IllegalArgumentException ee) {}
366       assertEquals(new Integer(999999999), e.getCode());
367       assertNull(e.getSubCode());
368       assertNull(e.getUserTitle());
369       assertNull(e.getUserMessage());
370       assertNull(e.getTraceId());
371     }
372     catch(Exception e)
373     {
374       fail("A wrong exception was thrown: " + e.toString());
375     }
376
377
378     requestFactory.setBody(
379         "{\n" +
380         "  \"error\":\n" +
381         "  {\n" +
382         "    \"message\": \"An unmapped Graph-API-Exception.\",\n" +
383         "    \"type\": null,\n" +
384         "    \"code\": 999999999\n" +
385         "  }\n" +
386         "}");
387
388     try
389     {
390       clientTemplate.getForObject("ANY", SOME.class);
391       fail("The expected exception was not thrown");
392     }
393     catch(UnmappedErrorException e)
394     {
395       log.debug("{}", e.toString());
396       assertEquals("An unmapped Graph-API-Exception.", e.getMessage());
397       assertNull(e.getType());
398       assertEquals(new Integer(999999999), e.getCode());
399       assertNull(e.getSubCode());
400       assertNull(e.getUserTitle());
401       assertNull(e.getUserMessage());
402       assertNull(e.getTraceId());
403     }
404     catch(Exception e)
405     {
406       fail("A wrong exception was thrown: " + e.toString());
407     }
408
409
410     requestFactory.setBody(
411         "{\n" +
412         "  \"error\":\n" +
413         "  {\n" +
414         "    \"message\": \"An unmapped Graph-API-Exception.\",\n" +
415         "    \"code\": 999999999\n" +
416         "  }\n" +
417         "}");
418
419     try
420     {
421       clientTemplate.getForObject("ANY", SOME.class);
422       fail("The expected exception was not thrown");
423     }
424     catch(UnmappedErrorException e)
425     {
426       log.debug("{}", e.toString());
427       assertEquals("An unmapped Graph-API-Exception.", e.getMessage());
428       assertNull(e.getType());
429       assertEquals(new Integer(999999999), e.getCode());
430       assertNull(e.getSubCode());
431       assertNull(e.getUserTitle());
432       assertNull(e.getUserMessage());
433       assertNull(e.getTraceId());
434     }
435     catch(Exception e)
436     {
437       fail("A wrong exception was thrown: " + e.toString());
438     }
439   }
440
441   @Test
442   public void testInvlalidErrors()
443   {
444     log.info("testInvalidErrors");
445
446
447     requestFactory.setBody(
448         "{\n" +
449         "  \"error\":\n" +
450         "  {\n" +
451         "    \"message\": \"Not a Graph-Api-Exception.\",\n" +
452         "    \"type\": \"Whatever\",\n" +
453         "    \"code\": \"some string\"\n" +
454         "  }\n" +
455         "}");
456
457     try
458     {
459       clientTemplate.getForObject("ANY", SOME.class);
460       fail("The expected exception was not thrown");
461     }
462     catch(HttpClientErrorException e)
463     {
464       log.debug("{}", e.toString());
465     }
466     catch(Exception e)
467     {
468       fail("A wrong exception was thrown: " + e.toString());
469     }
470
471
472     requestFactory.setBody(
473         "{\n" +
474         "  \"error\":\n" +
475         "  {\n" +
476         "    \"message\": \"Not a Graph-Api-Exception.\",\n" +
477         "    \"type\": \"Whatever\",\n" +
478         "    \"code\": 9.9\n" +
479         "  }\n" +
480         "}");
481
482     try
483     {
484       clientTemplate.getForObject("ANY", SOME.class);
485       fail("The expected exception was not thrown");
486     }
487     catch(HttpClientErrorException e)
488     {
489       log.debug("{}", e.toString());
490     }
491     catch(Exception e)
492     {
493       fail("A wrong exception was thrown: " + e.toString());
494     }
495
496
497     requestFactory.setBody(
498         "{\n" +
499         "  \"error\":\n" +
500         "  {\n" +
501         "    \"message\": \"Not a Graph-Api-Exception.\",\n" +
502         "    \"type\": \"Whatever\",\n" +
503         "    \"code\": null\n" +
504         "  }\n" +
505         "}");
506
507     try
508     {
509       clientTemplate.getForObject("ANY", SOME.class);
510       fail("The expected exception was not thrown");
511     }
512     catch(HttpClientErrorException e)
513     {
514       log.debug("{}", e.toString());
515     }
516     catch(Exception e)
517     {
518       fail("A wrong exception was thrown: " + e.toString());
519     }
520
521
522     requestFactory.setBody(
523         "{\n" +
524         "  \"error\":\n" +
525         "  {\n" +
526         "    \"message\": \"Not a Graph-Api-Exception.\",\n" +
527         "    \"type\": \"Whatever\"\n" +
528         "  }\n" +
529         "}");
530
531     try
532     {
533       clientTemplate.getForObject("ANY", SOME.class);
534       fail("The expected exception was not thrown");
535     }
536     catch(HttpClientErrorException e)
537     {
538       log.debug("{}", e.toString());
539     }
540     catch(Exception e)
541     {
542       fail("A wrong exception was thrown: " + e.toString());
543     }
544
545
546     requestFactory.setBody("{\"error\":{\"message\":null}}");
547
548     try
549     {
550       clientTemplate.getForObject("ANY", SOME.class);
551       fail("The expected exception was not thrown");
552     }
553     catch(HttpClientErrorException e)
554     {
555       log.debug("{}", e.toString());
556     }
557     catch(Exception e)
558     {
559       fail("A wrong exception was thrown: " + e.toString());
560     }
561
562
563     requestFactory.setBody("{\"error\":{\"type\":null}}");
564
565     try
566     {
567       clientTemplate.getForObject("ANY", SOME.class);
568       fail("The expected exception was not thrown");
569     }
570     catch(HttpClientErrorException e)
571     {
572       log.debug("{}", e.toString());
573     }
574     catch(Exception e)
575     {
576       fail("A wrong exception was thrown: " + e.toString());
577     }
578
579
580     requestFactory.setBody("{\"error\":{\"code\":null}}");
581
582     try
583     {
584       clientTemplate.getForObject("ANY", SOME.class);
585       fail("The expected exception was not thrown");
586     }
587     catch(HttpClientErrorException e)
588     {
589       log.debug("{}", e.toString());
590     }
591     catch(Exception e)
592     {
593       fail("A wrong exception was thrown: " + e.toString());
594     }
595
596
597     requestFactory.setBody("{\"error\":{}}");
598
599     try
600     {
601       clientTemplate.getForObject("ANY", SOME.class);
602       fail("The expected exception was not thrown");
603     }
604     catch(HttpClientErrorException e)
605     {
606       log.debug("{}", e.toString());
607     }
608     catch(Exception e)
609     {
610       fail("A wrong exception was thrown: " + e.toString());
611     }
612
613
614     requestFactory.setBody("{\"error\":\"some message\"}");
615
616     try
617     {
618       clientTemplate.getForObject("ANY", SOME.class);
619       fail("The expected exception was not thrown");
620     }
621     catch(HttpClientErrorException e)
622     {
623       log.debug("{}", e.toString());
624     }
625     catch(Exception e)
626     {
627       fail("A wrong exception was thrown: " + e.toString());
628     }
629
630
631     requestFactory.setBody("{\"error\":null}");
632
633     try
634     {
635       clientTemplate.getForObject("ANY", SOME.class);
636       fail("The expected exception was not thrown");
637     }
638     catch(HttpClientErrorException e)
639     {
640       log.debug("{}", e.toString());
641     }
642     catch(Exception e)
643     {
644       fail("A wrong exception was thrown: " + e.toString());
645     }
646
647
648     requestFactory.setBody("{\"some filed\":\"some message\"}");
649
650     try
651     {
652       clientTemplate.getForObject("ANY", SOME.class);
653       fail("The expected exception was not thrown");
654     }
655     catch(HttpClientErrorException e)
656     {
657       log.debug("{}", e.toString());
658     }
659     catch(Exception e)
660     {
661       fail("A wrong exception was thrown: " + e.toString());
662     }
663
664
665     requestFactory.setBody("{}");
666
667     try
668     {
669       clientTemplate.getForObject("ANY", SOME.class);
670       fail("The expected exception was not thrown");
671     }
672     catch(HttpClientErrorException e)
673     {
674       log.debug("{}", e.toString());
675     }
676     catch(Exception e)
677     {
678       fail("A wrong exception was thrown: " + e.toString());
679     }
680
681
682     requestFactory.setBody("");
683
684     try
685     {
686       clientTemplate.getForObject("ANY", SOME.class);
687       fail("The expected exception was not thrown");
688     }
689     catch(HttpClientErrorException e)
690     {
691       log.debug("{}", e.toString());
692     }
693     catch(Exception e)
694     {
695       fail("A wrong exception was thrown: " + e.toString());
696     }
697   }
698
699
700   @Before
701   public void setUp()
702   {
703     requestFactory = new MockClientHttpRequestFactory();
704     requestFactory.setStatus(HttpStatus.BAD_REQUEST);
705     requestFactory.addHeader("Content-Type", "application/json");
706     clientTemplate.setRequestFactory(requestFactory);
707
708     clientTemplate.setErrorHandler(
709         new GraphApiErrorHandler(
710             (OAuth2ErrorHandler)clientTemplate.getErrorHandler()
711             )
712         );
713
714     clientTemplate.setAccessTokenProvider(new AccessTokenProvider()
715     {
716       @Override
717       public OAuth2AccessToken obtainAccessToken(
718           OAuth2ProtectedResourceDetails details,
719           AccessTokenRequest parameters
720           )
721           throws
722             UserRedirectRequiredException,
723             UserApprovalRequiredException,
724             AccessDeniedException
725       {
726         return new OAuth2AccessToken() {
727
728           @Override
729           public Map<String, Object> getAdditionalInformation()
730           {
731             throw new UnsupportedOperationException("Not supported yet.");
732           }
733
734           @Override
735           public Set<String> getScope()
736           {
737             throw new UnsupportedOperationException("Not supported yet.");
738           }
739
740           @Override
741           public OAuth2RefreshToken getRefreshToken()
742           {
743             throw new UnsupportedOperationException("Not supported yet.");
744           }
745
746           @Override
747           public String getTokenType()
748           {
749             return OAUTH2_TYPE;
750           }
751
752           @Override
753           public boolean isExpired()
754           {
755             return false;
756           }
757
758           @Override
759           public Date getExpiration()
760           {
761             throw new UnsupportedOperationException("Not supported yet.");
762           }
763
764           @Override
765           public int getExpiresIn()
766           {
767             throw new UnsupportedOperationException("Not supported yet.");
768           }
769
770           @Override
771           public String getValue()
772           {
773             return "ANY";
774           }
775         };
776       }
777
778       @Override
779       public boolean supportsResource(OAuth2ProtectedResourceDetails resource)
780       {
781         return true;
782       }
783
784       @Override
785       public OAuth2AccessToken refreshAccessToken(
786           OAuth2ProtectedResourceDetails resource,
787           OAuth2RefreshToken refreshToken,
788           AccessTokenRequest request
789           )
790           throws
791             UserRedirectRequiredException
792       {
793         throw new UnsupportedOperationException("Not supported yet.");
794       }
795
796       @Override
797       public boolean supportsRefresh(OAuth2ProtectedResourceDetails resource)
798       {
799         return false;
800       }
801     });
802   }
803
804
805   static class SOME
806   {
807   }
808 }