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