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