View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.shared.context.flash;
20  
21  import java.util.Arrays;
22  import java.util.Collections;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.Map;
26  
27  import javax.faces.application.FacesMessage;
28  import javax.faces.event.PhaseId;
29  import javax.servlet.ServletContext;
30  import javax.servlet.http.Cookie;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  
34  import org.apache.myfaces.test.base.AbstractViewControllerTestCase;
35  import org.apache.myfaces.test.mock.MockExternalContext20;
36  import org.apache.myfaces.test.mock.MockFacesContext20;
37  import org.apache.myfaces.test.mock.MockHttpServletRequest;
38  import org.apache.myfaces.test.mock.MockHttpServletResponse;
39  
40  /**
41   * Tests for FlashImpl.
42   * @author Jakob Korherr (latest modification by $Author: jakobk $)
43   * @version $Revision: 1136978 $ $Date: 2011-06-17 13:55:09 -0500 (Fri, 17 Jun 2011) $
44   */
45  public class FlashImplTest extends AbstractViewControllerTestCase
46  {
47      
48      private FlashImpl _flash;
49  
50      public FlashImplTest(String name)
51      {
52          super(name);
53      }
54  
55      @Override
56      protected void setUpFacesContext() throws Exception
57      {
58          super.setUpFacesContext();
59  
60          // Unfortunately, setUpExternalContext() does not work, b/c MockFacesContext20 overwrites it!
61          externalContext = new MockExternalContext21(servletContext, request, response);
62          facesContext.setExternalContext(externalContext);
63      }
64  
65      @Override
66      protected void setUp() throws Exception
67      {
68          super.setUp();
69          
70          _flash = (FlashImpl) FlashImpl.getCurrentInstance(externalContext);
71      }
72  
73      @Override
74      protected void tearDown() throws Exception
75      {
76          _flash = null;
77          
78          super.tearDown();
79      }
80  
81      /**
82       * Tests if FlashImpl uses the sessionMap as base for the SubKeyMap
83       * and correctly stores the values in it.
84       * @throws Exception
85       */
86      public void testSessionMapWrapperSubKeyMap() throws Exception
87      {
88          // set phase to RESTORE_VIEW to create the flash tokens on doPrePhaseActions()
89          facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
90          _flash.doPrePhaseActions(facesContext);
91          
92          // put the value in the scope an keep() it!
93          _flash.putNow("testkey1", "testvalue1");
94          _flash.keep("testkey1");
95          
96          // set phase to RENDER_RESPONSE --> now renderMap will be used
97          facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
98          
99          // get the token for the render FlashMap (FlashImpl internals)
100         final String renderToken = (String) externalContext
101                 .getRequestMap().get(FlashImpl.FLASH_RENDER_MAP_TOKEN);
102         final String sessionMapKey = FlashImpl.FLASH_SESSION_MAP_SUBKEY_PREFIX + 
103                 FlashImpl.SEPARATOR_CHAR + renderToken + "testkey1";
104         
105         // Assertion
106         assertEquals("The render FlashMap must use the session Map to store the values.",
107                 "testvalue1", session.getAttribute(sessionMapKey));     
108     }
109     
110     /**
111      * Tests the functionality of keep() in a normal postback scenario.
112      * @throws Exception
113      */
114     @SuppressWarnings("unchecked")
115     public void testKeepValueNormalPostback() throws Exception
116     {
117         // simulate JSF lifecycle:
118         // note that doPrePhaseActions() only performs tasks on RESTORE_VIEW
119         // and doPostPhaseActions() only on the last phase.
120         
121         // initial request ----------------------------------------------------
122         
123         // this request is a normal GET request, and thus not a postback
124         ((MockFacesContext20) facesContext).setPostback(false);
125         
126         // simulate JSF lifecycle
127         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
128         _flash.doPrePhaseActions(facesContext);
129         
130         // simulate JSF lifecycle
131         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
132         _flash.doPostPhaseActions(facesContext);
133         
134         // first postback -----------------------------------------------------
135         
136         // simulate a new request
137         _simulateNewRequest();
138         
139         // this request should be a postback
140         ((MockFacesContext20) facesContext).setPostback(true);
141         
142         // simulate JSF lifecycle
143         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
144         _flash.doPrePhaseActions(facesContext);
145         
146         // simulate JSF lifecycle
147         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
148         
149         // put the value in the scope an keep() it!
150         _flash.putNow("flashkey", "flashvalue");
151         _flash.keep("flashkey");
152         
153         // simulate JSF lifecycle
154         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
155         _flash.doPostPhaseActions(facesContext);
156         
157         // second postback ----------------------------------------------------
158         
159         // simulate a new request
160         _simulateNewRequest();
161         
162         // this request should be a postback
163         ((MockFacesContext20) facesContext).setPostback(true);
164         
165         // simulate JSF lifecycle
166         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
167         _flash.doPrePhaseActions(facesContext);
168         
169         // simulate JSF lifecycle
170         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
171         
172         // _flash.get() will ask the execute FlashMap for the value
173         // and this must be the render FlashMap of the previous request,
174         // thus it must contain the value from the previous request.
175         assertEquals("flashvalue", _flash.get("flashkey"));
176         
177         // simulate JSF lifecycle
178         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
179         _flash.doPostPhaseActions(facesContext);
180         
181         // _flash.get() also references to the execute FlashMap, but
182         // this one has to be cleared by now, thus it must be null.
183         assertNull("Execute FlashMap must have been cleared", _flash.get("flashkey"));
184         
185         // get the execute Map of the second postback (FlashImpl internals)
186         Map<String, Object> executeMap = (Map<String, Object>) externalContext
187                 .getRequestMap().get(FlashImpl.FLASH_EXECUTE_MAP);
188         
189         // must be empty
190         assertTrue("The execute Map of the second postback must have been cleared",
191                 executeMap.isEmpty());
192     }
193     
194     /**
195      * Tests the functionality of keep() in a POST-REDIRECT-GET scenario.
196      * @throws Exception
197      */
198     @SuppressWarnings("unchecked")
199     public void testKeepValuePostRedirectGet() throws Exception
200     {
201         // simulate JSF lifecycle:
202         // note that doPrePhaseActions() only performs tasks on RESTORE_VIEW
203         // and doPostPhaseActions() only on the last phase.
204         
205         // initial request ----------------------------------------------------
206         
207         // this request is a normal GET request, and thus not a postback
208         ((MockFacesContext20) facesContext).setPostback(false);
209         
210         // simulate JSF lifecycle
211         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
212         _flash.doPrePhaseActions(facesContext);
213         
214         // simulate JSF lifecycle
215         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
216         _flash.doPostPhaseActions(facesContext);
217         
218         // first postback (POST of POST-REDIRECT-GET) -------------------------
219         
220         // simulate a new request
221         _simulateNewRequest();
222         
223         // this request should be a postback
224         ((MockFacesContext20) facesContext).setPostback(true);
225         
226         // simulate JSF lifecycle
227         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
228         _flash.doPrePhaseActions(facesContext);
229         
230         // simulate JSF lifecycle
231         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
232         
233         // put the value in the scope an keep() it!
234         _flash.put("flashkey", "flashvalue");
235         _flash.keep("flashkey");
236         
237         // set redirect to true, this happens by the NavigationHandler in phase 5
238         _flash.setRedirect(true);
239         
240         assertTrue("setRedirect(true) was just called, thus isRedirect() must be true",
241                 _flash.isRedirect());
242         
243         // note that setRedirect(true) was called, thus the cleanup happens
244         // in phase 5, because doPostPhaseActions() won't be called on phase 6.
245         _flash.doPostPhaseActions(facesContext);
246         
247         // GET request of POST-REDIRECT-GET -----------------------------------
248         
249         // simulate a new request
250         _simulateNewRequest();
251         
252         // this request is not a postback
253         ((MockFacesContext20) facesContext).setPostback(false);
254         
255         // simulate JSF lifecycle
256         // Note that doPrePhaseActions() is called on RESTORE_VIEW even
257         // though this request is not a postback.
258         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
259         _flash.doPrePhaseActions(facesContext);
260         
261         // check isRedirect();
262         assertTrue("setRedirect(true) was called on the previous request, "
263                 + " and we are in the execute portion of the lifecycle, "
264                 + " thus isRedirect() must be true.",
265                 _flash.isRedirect());
266         
267         // simulate JSF lifecycle - JSF will immediately jump to phase 6
268         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
269         
270         // check isRedirect();
271         assertFalse("setRedirect(true) was called on the previous request, "
272                 + " but we are already in the render portion of the lifecycle, "
273                 + " thus isRedirect() must be false.",
274                 _flash.isRedirect());
275         
276         // _flash.get() will ask the execute FlashMap and this one
277         // must contain the key used in keep()
278         assertEquals("flashvalue", _flash.get("flashkey"));
279         
280         _flash.doPostPhaseActions(facesContext);
281         
282         // second postback (after POST-REDIRECT-GET) --------------------------
283         
284         // simulate a new request
285         _simulateNewRequest();
286         
287         // this request should be a postback
288         ((MockFacesContext20) facesContext).setPostback(true);
289         
290         // simulate JSF lifecycle
291         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
292         _flash.doPrePhaseActions(facesContext);
293         
294         // simulate JSF lifecycle
295         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
296         
297         // check isRedirect();
298         assertFalse("setRedirect(true) was called on the pre-previous request, "
299                 + " thus isRedirect() must be false again.",
300                 _flash.isRedirect());
301         
302         // _flash.get() will ask the execute FlashMap for the value
303         // and this must be the render FlashMap of the previous (GET) request,
304         // thus it must not contain the value from the previous request,
305         // because the value was on the previous request's execute FlashMap
306         // and not on the previous request's render FlashMap.
307         assertNull(_flash.get("flashkey"));
308         
309         // simulate JSF lifecycle
310         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
311         _flash.doPostPhaseActions(facesContext);
312         
313         // get the execute Map of the second postback (FlashImpl internals)
314         Map<String, Object> executeMap = (Map<String, Object>) externalContext
315                 .getRequestMap().get(FlashImpl.FLASH_EXECUTE_MAP);
316         
317         // must be empty
318         assertTrue("The execute Map of the second postback must have been cleared",
319                 executeMap.isEmpty());
320     }
321     
322     /**
323      * Tests the functionality of keepMessages in a normal postback scenario.
324      * @throws Exception
325      */
326     public void testKeepMessagesNormalPostback() throws Exception
327     {
328         // simulate JSF lifecycle:
329         // note that doPrePhaseActions() only performs tasks on RESTORE_VIEW
330         // and doPostPhaseActions() only on the last phase.
331         
332         // initial request ----------------------------------------------------
333         
334         // this request is a normal GET request, and thus not a postback
335         ((MockFacesContext20) facesContext).setPostback(false);
336         
337         // simulate JSF lifecycle
338         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
339         _flash.doPrePhaseActions(facesContext);
340         
341         // simulate JSF lifecycle
342         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
343         _flash.doPostPhaseActions(facesContext);
344         
345         // first postback -----------------------------------------------------
346         
347         // simulate a new request
348         _simulateNewRequest();
349         
350         // this request should be a postback
351         ((MockFacesContext20) facesContext).setPostback(true);
352         
353         // simulate JSF lifecycle
354         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
355         _flash.doPrePhaseActions(facesContext);
356         
357         // simulate JSF lifecycle
358         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
359         
360         // add FacesMessages to the facesContext
361         FacesMessage messageClientId = new FacesMessage("message for clientId");
362         facesContext.addMessage("clientId", messageClientId);
363         FacesMessage messageNoClientId = new FacesMessage("message without clientId");
364         facesContext.addMessage(null, messageNoClientId);
365         
366         // now the FacesContext must contain 2 messages
367         assertEquals(2, facesContext.getMessageList().size());
368         
369         // keep messages
370         _flash.setKeepMessages(true);
371         
372         assertTrue("setKeepMessages(true) was just called, thus isKeepMessages() "
373                 + "must be true.", _flash.isKeepMessages());
374         
375         // simulate JSF lifecycle
376         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
377         _flash.doPostPhaseActions(facesContext);
378         
379         // second postback ----------------------------------------------------
380         
381         // simulate a new request
382         _simulateNewRequest();
383         
384         // this request should be a postback
385         ((MockFacesContext20) facesContext).setPostback(true);
386         
387         // now the FacesContext must contain 0 messages (new request, new FacesContext)
388         assertEquals(0, facesContext.getMessageList().size());
389         
390         // simulate JSF lifecycle
391         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
392         _flash.doPrePhaseActions(facesContext);
393         
394         // now the messages must be here again
395         assertEquals(2, facesContext.getMessageList().size());
396         assertEquals(Arrays.asList(messageClientId), facesContext.getMessageList("clientId"));
397         assertEquals(Arrays.asList(messageNoClientId), facesContext.getMessageList(null));
398         
399         assertFalse("setKeepMessages(true) was not called on this request, thus "
400                 + "isKeepMessages() must be false.", _flash.isKeepMessages());
401         
402         // simulate JSF lifecycle
403         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
404         _flash.doPostPhaseActions(facesContext);
405         
406         // third postback ----------------------------------------------------
407         
408         // simulate a new request
409         _simulateNewRequest();
410         
411         // this request should be a postback
412         ((MockFacesContext20) facesContext).setPostback(true);
413         
414         // now the FacesContext must contain 0 messages (new request, new FacesContext)
415         assertEquals(0, facesContext.getMessageList().size());
416         
417         // simulate JSF lifecycle
418         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
419         _flash.doPrePhaseActions(facesContext);
420         
421         // the messages must still be gone here, because setKeepMessages(true)
422         // was not called on the previous request
423         assertEquals(0, facesContext.getMessageList().size());
424         
425         // simulate JSF lifecycle
426         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
427         _flash.doPostPhaseActions(facesContext); 
428     }
429     
430     /**
431      * Tests the functionality of keepMessages in a POST-REDIRECT-GET scenario.
432      * In this test case the messages are only shipped from the POST to the GET and
433      * then not from the GET to the next postback.
434      * @throws Exception
435      */
436     public void testKeepMessagesPostRedirectGet() throws Exception
437     {
438         // simulate JSF lifecycle:
439         // note that doPrePhaseActions() only performs tasks on RESTORE_VIEW
440         // and doPostPhaseActions() only on the last phase.
441         
442         // initial request ----------------------------------------------------
443         
444         // this request is a normal GET request, and thus not a postback
445         ((MockFacesContext20) facesContext).setPostback(false);
446         
447         // simulate JSF lifecycle
448         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
449         _flash.doPrePhaseActions(facesContext);
450         
451         // simulate JSF lifecycle
452         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
453         _flash.doPostPhaseActions(facesContext);
454         
455         // first postback (POST of POST-REDIRECT-GET) -------------------------
456         
457         // simulate a new request
458         _simulateNewRequest();
459         
460         // this request should be a postback
461         ((MockFacesContext20) facesContext).setPostback(true);
462         
463         // simulate JSF lifecycle
464         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
465         _flash.doPrePhaseActions(facesContext);
466         
467         // simulate JSF lifecycle
468         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
469         
470         // add FacesMessages to the facesContext
471         FacesMessage messageClientId = new FacesMessage("message for clientId");
472         facesContext.addMessage("clientId", messageClientId);
473         FacesMessage messageNoClientId = new FacesMessage("message without clientId");
474         facesContext.addMessage(null, messageNoClientId);
475         
476         // now the FacesContext must contain 2 messages
477         assertEquals(2, facesContext.getMessageList().size());
478         
479         // keep messages
480         _flash.setKeepMessages(true);
481         assertTrue("setKeepMessages(true) was just called, thus isKeepMessages() "
482                 + "must be true.", _flash.isKeepMessages());
483         
484         // set redirect to true, this happens by the NavigationHandler in phase 5
485         _flash.setRedirect(true);
486         assertTrue("setRedirect(true) was just called, thus isRedirect() must be true",
487                 _flash.isRedirect());
488         
489         // note that setRedirect(true) was called, thus the cleanup happens
490         // in phase 5, because doPostPhaseActions() won't be called on phase 6.
491         _flash.doPostPhaseActions(facesContext);
492         
493         // GET request of POST-REDIRECT-GET -----------------------------------
494         
495         // simulate a new request
496         _simulateNewRequest();
497         
498         // this request is not a postback
499         ((MockFacesContext20) facesContext).setPostback(false);
500         
501         // now the FacesContext must contain 0 messages (new request, new FacesContext)
502         assertEquals(0, facesContext.getMessageList().size());
503         
504         // simulate JSF lifecycle
505         // Note that doPrePhaseActions() is called on RESTORE_VIEW even
506         // though this request is not a postback.
507         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
508         _flash.doPrePhaseActions(facesContext);
509         
510         // simulate JSF lifecycle - JSF will immediately jump to phase 6
511         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
512         
513         // now the messages must be here again
514         assertEquals(2, facesContext.getMessageList().size());
515         assertEquals(Arrays.asList(messageClientId), facesContext.getMessageList("clientId"));
516         assertEquals(Arrays.asList(messageNoClientId), facesContext.getMessageList(null));
517         
518         // check isKeepMessages()
519         assertFalse("setKeepMessages(true) was not called on this request, thus "
520                 + "isKeepMessages() must be false.", _flash.isKeepMessages());
521         
522         _flash.doPostPhaseActions(facesContext);
523         
524         // second postback (after POST-REDIRECT-GET) --------------------------
525         
526         // simulate a new request
527         _simulateNewRequest();
528         
529         // this request should be a postback
530         ((MockFacesContext20) facesContext).setPostback(true);
531         
532         // now the FacesContext must contain 0 messages (new request, new FacesContext)
533         assertEquals(0, facesContext.getMessageList().size());
534         
535         // simulate JSF lifecycle
536         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
537         _flash.doPrePhaseActions(facesContext);
538         
539         // simulate JSF lifecycle
540         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
541         
542         // now the FacesContext must contain 0 messages, because 
543         // setKeepMessages(true) was not called on the GET-request
544         assertEquals(0, facesContext.getMessageList().size());
545         
546         // simulate JSF lifecycle
547         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
548         _flash.doPostPhaseActions(facesContext);
549     }
550     
551     /**
552      * Tests the functionality of keepMessages in a POST-REDIRECT-GET scenario.
553      * In this test case the messages are shipped from the POST to the GET and
554      * then also from the GET to the next postback.
555      * @throws Exception
556      */
557     public void testKeepMessagesPostRedirectGetTwoTimes() throws Exception
558     {
559         // simulate JSF lifecycle:
560         // note that doPrePhaseActions() only performs tasks on RESTORE_VIEW
561         // and doPostPhaseActions() only on the last phase.
562         
563         // initial request ----------------------------------------------------
564         
565         // this request is a normal GET request, and thus not a postback
566         ((MockFacesContext20) facesContext).setPostback(false);
567         
568         // simulate JSF lifecycle
569         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
570         _flash.doPrePhaseActions(facesContext);
571         
572         // simulate JSF lifecycle
573         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
574         _flash.doPostPhaseActions(facesContext);
575         
576         // first postback (POST of POST-REDIRECT-GET) -------------------------
577         
578         // simulate a new request
579         _simulateNewRequest();
580         
581         // this request should be a postback
582         ((MockFacesContext20) facesContext).setPostback(true);
583         
584         // simulate JSF lifecycle
585         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
586         _flash.doPrePhaseActions(facesContext);
587         
588         // simulate JSF lifecycle
589         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
590         
591         // add FacesMessages to the facesContext
592         FacesMessage messageClientId = new FacesMessage("message for clientId");
593         facesContext.addMessage("clientId", messageClientId);
594         FacesMessage messageNoClientId = new FacesMessage("message without clientId");
595         facesContext.addMessage(null, messageNoClientId);
596         
597         // now the FacesContext must contain 2 messages
598         assertEquals(2, facesContext.getMessageList().size());
599         
600         // keep messages
601         _flash.setKeepMessages(true);
602         assertTrue("setKeepMessages(true) was just called, thus isKeepMessages() "
603                 + "must be true.", _flash.isKeepMessages());
604         
605         // set redirect to true, this happens by the NavigationHandler in phase 5
606         _flash.setRedirect(true);
607         assertTrue("setRedirect(true) was just called, thus isRedirect() must be true",
608                 _flash.isRedirect());
609         
610         // note that setRedirect(true) was called, thus the cleanup happens
611         // in phase 5, because doPostPhaseActions() won't be called on phase 6.
612         _flash.doPostPhaseActions(facesContext);
613         
614         // GET request of POST-REDIRECT-GET -----------------------------------
615         
616         // simulate a new request
617         _simulateNewRequest();
618         
619         // this request is not a postback
620         ((MockFacesContext20) facesContext).setPostback(false);
621         
622         // now the FacesContext must contain 0 messages (new request, new FacesContext)
623         assertEquals(0, facesContext.getMessageList().size());
624         
625         // simulate JSF lifecycle
626         // Note that doPrePhaseActions() is called on RESTORE_VIEW even
627         // though this request is not a postback.
628         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
629         _flash.doPrePhaseActions(facesContext);
630         
631         // simulate JSF lifecycle - JSF will immediately jump to phase 6
632         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
633         
634         // now the messages must be here again
635         assertEquals(2, facesContext.getMessageList().size());
636         assertEquals(Arrays.asList(messageClientId), facesContext.getMessageList("clientId"));
637         assertEquals(Arrays.asList(messageNoClientId), facesContext.getMessageList(null));
638         
639         // check isKeepMessages()
640         assertFalse("setKeepMessages(true) was not called on this request, thus "
641                 + "isKeepMessages() must be false.", _flash.isKeepMessages());
642         
643         // keep messages - again
644         _flash.setKeepMessages(true);
645         assertTrue("setKeepMessages(true) was just called, thus isKeepMessages() "
646                 + "must be true.", _flash.isKeepMessages());
647         
648         _flash.doPostPhaseActions(facesContext);
649         
650         // second postback (after POST-REDIRECT-GET) --------------------------
651         
652         // simulate a new request
653         _simulateNewRequest();
654         
655         // this request should be a postback
656         ((MockFacesContext20) facesContext).setPostback(true);
657         
658         // now the FacesContext must contain 0 messages (new request, new FacesContext)
659         assertEquals(0, facesContext.getMessageList().size());
660         
661         // simulate JSF lifecycle
662         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
663         _flash.doPrePhaseActions(facesContext);
664         
665         // simulate JSF lifecycle
666         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
667         
668         // now the messages must be here again
669         assertEquals(2, facesContext.getMessageList().size());
670         assertEquals(Arrays.asList(messageClientId), facesContext.getMessageList("clientId"));
671         assertEquals(Arrays.asList(messageNoClientId), facesContext.getMessageList(null));
672         
673         // simulate JSF lifecycle
674         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
675         _flash.doPostPhaseActions(facesContext);
676         
677         // third postback -----------------------------------------------------
678         
679         // simulate a new request
680         _simulateNewRequest();
681         
682         // this request should be a postback
683         ((MockFacesContext20) facesContext).setPostback(true);
684         
685         // now the FacesContext must contain 0 messages (new request, new FacesContext)
686         assertEquals(0, facesContext.getMessageList().size());
687         
688         // simulate JSF lifecycle
689         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
690         _flash.doPrePhaseActions(facesContext);
691         
692         // simulate JSF lifecycle
693         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
694         
695         // now the FacesContext must contain 0 messages, because 
696         // setKeepMessages(true) was not called on the previous postback
697         assertEquals(0, facesContext.getMessageList().size());
698         
699         // simulate JSF lifecycle
700         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
701         _flash.doPostPhaseActions(facesContext);
702     }
703     
704     /**
705      * Test if setRedirect(true) works via _flash.put("redirect", true)
706      * and if isRedirect() is equal to _flash.get("redirect").
707      */
708     public void testSetRedirect()
709     {
710         assertFalse(_flash.isRedirect());
711         assertFalse((Boolean) _flash.get("redirect"));
712         
713         _flash.put("redirect", true);
714         
715         assertTrue(_flash.isRedirect());
716         assertTrue((Boolean) _flash.get("redirect"));
717     }
718     
719     /**
720      * Test if setKeepMessages(true) works via _flash.put("keepMessages", true)
721      * and if isKeepMessages() is equal to _flash.get("keepMessages").
722      */
723     public void testSetKeepMessages()
724     {
725         assertFalse(_flash.isKeepMessages());
726         assertFalse((Boolean) _flash.get("keepMessages"));
727         
728         _flash.put("keepMessages", true);
729         
730         assertTrue(_flash.isKeepMessages());
731         assertTrue((Boolean) _flash.get("keepMessages"));
732     }
733     
734     /**
735      * Tests the functionality of putNow().
736      */
737     @SuppressWarnings("unchecked")
738     public void testPutNow()
739     {
740         Map<String, Object> requestMap = externalContext.getRequestMap();
741         
742         // requestMap must NOT contain the key
743         assertNull(requestMap.get("flashkey"));
744         
745         _flash.putNow("flashkey", "flashvalue");
746         
747         // requestMap must contain the key
748         assertEquals("flashvalue", requestMap.get("flashkey"));
749     }
750     
751     /**
752      * Tests keep()
753      * @throws Exception
754      */
755     public void testKeep() throws Exception
756     {
757         // simulate JSF lifecycle:
758         // note that doPrePhaseActions() only performs tasks on RESTORE_VIEW
759         // and doPostPhaseActions() only on the last phase.
760         
761         // initial request ----------------------------------------------------
762         
763         // this request is a normal GET request, and thus not a postback
764         ((MockFacesContext20) facesContext).setPostback(false);
765         
766         // simulate JSF lifecycle
767         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
768         _flash.doPrePhaseActions(facesContext);
769         
770         // simulate JSF lifecycle
771         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
772         _flash.doPostPhaseActions(facesContext);
773         
774         // first postback -----------------------------------------------------
775         
776         // simulate a new request
777         _simulateNewRequest();
778         
779         // this request should be a postback
780         ((MockFacesContext20) facesContext).setPostback(true);
781         
782         // simulate JSF lifecycle
783         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
784         _flash.doPrePhaseActions(facesContext);
785         
786         // simulate JSF lifecycle
787         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
788         
789         // put a value into the request FlashMap
790         _flash.putNow("flashkey", "flashvalue");
791         
792         // and keep() it
793         _flash.keep("flashkey");
794         
795         // simulate JSF lifecycle
796         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
797         
798         // cleanup flash
799         _flash.doPostPhaseActions(facesContext);
800         
801         // second postback ----------------------------------------------------
802         
803         // simulate a new request
804         _simulateNewRequest();
805         
806         // this request should be a postback
807         ((MockFacesContext20) facesContext).setPostback(true);
808         
809         // simulate JSF lifecycle
810         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
811         _flash.doPrePhaseActions(facesContext);
812         
813         // simulate JSF lifecycle
814         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
815      
816         // the value must be in the executeMap
817         assertEquals("flashvalue", _flash.get("flashkey"));
818         
819         // simulate JSF lifecycle
820         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
821         
822         // cleanup flash
823         _flash.doPostPhaseActions(facesContext);
824     }
825     
826     /**
827      * Like testKeep(), but without calling keep() to keep the value.
828      * @throws Exception
829      */
830     public void testNotKeep() throws Exception
831     {
832         // simulate JSF lifecycle:
833         // note that doPrePhaseActions() only performs tasks on RESTORE_VIEW
834         // and doPostPhaseActions() only on RENDER_RESPONSE.
835         
836         // initial request ----------------------------------------------------
837         
838         // this request is a normal GET request, and thus not a postback
839         ((MockFacesContext20) facesContext).setPostback(false);
840         
841         // simulate JSF lifecycle
842         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
843         _flash.doPrePhaseActions(facesContext);
844         
845         // simulate JSF lifecycle
846         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
847         _flash.doPostPhaseActions(facesContext);
848         
849         // first postback -----------------------------------------------------
850         
851         // simulate a new request
852         _simulateNewRequest();
853         
854         // this request should be a postback
855         ((MockFacesContext20) facesContext).setPostback(true);
856         
857         // simulate JSF lifecycle
858         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
859         _flash.doPrePhaseActions(facesContext);
860         
861         // simulate JSF lifecycle
862         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
863         
864         // put a value into the request FlashMap
865         _flash.putNow("flashkey", "flashvalue");
866         
867         // and do NOT keep it.
868         
869         // simulate JSF lifecycle
870         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
871         
872         _flash.doPostPhaseActions(facesContext);
873         
874         // second postback ----------------------------------------------------
875         
876         // simulate a new request
877         _simulateNewRequest();
878         
879         // this request should be a postback
880         ((MockFacesContext20) facesContext).setPostback(true);
881         
882         // simulate JSF lifecycle
883         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
884         _flash.doPrePhaseActions(facesContext);
885         
886         // simulate JSF lifecycle
887         facesContext.setCurrentPhaseId(PhaseId.INVOKE_APPLICATION);
888      
889         // render FlashMap must be empty
890         assertNull(_flash.get("flashkey"));
891         
892         // simulate JSF lifecycle
893         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
894         
895         // cleanup flash
896         _flash.doPostPhaseActions(facesContext);
897     }
898     
899     /**
900      * Tests if the reading functions use _getFlashMapForReading()
901      * and if the writing functions use _getFlashMapForWriting().
902      */
903     public void testMapMethodsUseDifferentMaps() throws Exception
904     {
905         // simulate JSF lifecycle:
906         // note that doPrePhaseActions() only performs tasks on RESTORE_VIEW
907         // and doPostPhaseActions() only on RENDER_RESPONSE.
908         
909         // initial request ----------------------------------------------------
910         
911         // this request is a normal GET request, and thus not a postback
912         ((MockFacesContext20) facesContext).setPostback(false);
913         
914         // simulate JSF lifecycle
915         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
916         _flash.doPrePhaseActions(facesContext);
917         
918         // simulate JSF lifecycle
919         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
920         _flash.doPostPhaseActions(facesContext);
921         
922         // first postback -----------------------------------------------------
923         
924         // simulate a new request
925         _simulateNewRequest();
926         
927         // this request should be a postback
928         ((MockFacesContext20) facesContext).setPostback(true);
929         
930         // simulate JSF lifecycle
931         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
932         _flash.doPrePhaseActions(facesContext);
933         
934         // simulate JSF lifecycle
935         facesContext.setCurrentPhaseId(PhaseId.RENDER_RESPONSE);
936         
937         // in this configuration put() and get() are executed on different maps
938         
939         // there must not be a value with the key "flashkey"
940         assertNull(_flash.get("flashkey"));
941         
942         // put() always references the active FlashMap,
943         // which is the render FlashMap in this case (phase is render response)
944         _flash.put("flashkey", "flashvalue");
945         
946         // there must still not be a value with the key "flashkey"
947         // NOTE that get still references the execute FlashMap
948         assertNull(_flash.get("flashkey"));
949         
950         _flash.doPostPhaseActions(facesContext);
951     }
952     
953     /**
954      * Tests the implementation of the methods from the java.util.Map interface.
955      */
956     public void testMapMethods()
957     {
958         // ensure that _getActiveFlashMap() returns the execute FlashMap
959         facesContext.setCurrentPhaseId(PhaseId.RESTORE_VIEW);
960         
961         // run assertions for an empty FlashMap
962         _noElementAssertions();
963         
964         // use put() to put a value into the map
965         _flash.put("flashkey", "flashvalue");
966         
967         // run assertions for the FlashMap with one element
968         _oneElementAssertions();
969         
970         // remove the key using remove();
971         _flash.remove("flashkey");
972         
973         _noElementAssertions();
974 
975         // use putAll() to put a value into the map
976         Map<String, Object> map = new HashMap<String, Object>();
977         map.put("flashkey", "flashvalue");
978         _flash.putAll(map);
979         
980         _oneElementAssertions();
981         
982         // use clear() to remove the value from the map
983         _flash.clear();
984         
985         _noElementAssertions();
986         
987         // put the value into the map again
988         _flash.put("flashkey", "flashvalue");
989         
990         _oneElementAssertions();
991         
992         // use the keySet to clear the map
993         _flash.keySet().clear();
994         
995         _noElementAssertions();
996     }
997     
998     /**
999      * Utility method used by testMapMethods()
1000      */
1001     private void _noElementAssertions()
1002     {
1003         assertTrue(_flash.isEmpty());
1004         assertEquals(0, _flash.size());
1005         assertFalse(_flash.containsKey("flashkey"));
1006         assertFalse(_flash.containsValue("flashvalue"));
1007         assertEquals(Collections.emptySet(), _flash.keySet());
1008         assertNull(_flash.get("flashkey"));
1009         assertTrue(_flash.values().isEmpty());
1010     }
1011     
1012     /**
1013      * Utility method used by testMapMethods()
1014      */
1015     private void _oneElementAssertions()
1016     {
1017         assertFalse(_flash.isEmpty());
1018         assertEquals(1, _flash.size());
1019         assertTrue(_flash.containsKey("flashkey"));
1020         assertTrue(_flash.containsValue("flashvalue"));
1021         assertEquals(new HashSet<String>(Arrays.asList("flashkey")), _flash.keySet());
1022         assertEquals("flashvalue", _flash.get("flashkey"));
1023         assertTrue(_flash.values().contains("flashvalue"));
1024     }
1025     
1026     /**
1027      * Create new request, response, ExternalContext and FacesContext
1028      * to simulate a new request. Also resend any Cookies added to the
1029      * current request by the Flash implementation.
1030      * 
1031      * @throws Exception
1032      */
1033     private void _simulateNewRequest() throws Exception
1034     {
1035         // we will now have a cookie with the token for the new request
1036         Cookie renderTokenCookie = response.getCookie(FlashImpl.FLASH_RENDER_MAP_TOKEN);
1037         
1038         // the Cookie must exist
1039         assertNotNull(renderTokenCookie);
1040         
1041         // check for the redirect-cookie
1042         Cookie redirectCookie = response.getCookie(FlashImpl.FLASH_REDIRECT);
1043         
1044         // create new request, response, ExternalContext and FacesContext
1045         // to simulate a new request
1046         request = new MockHttpServletRequest(session);
1047         request.setServletContext(servletContext);
1048         response = new MockHttpServletResponse();
1049         setUpExternalContext();
1050         setUpFacesContext();
1051         
1052         // add the cookie to the new request
1053         request.addCookie(renderTokenCookie);
1054         
1055         // add the redirect-cookie to the new request, if exists
1056         if (redirectCookie != null)
1057         {
1058             // maxage == 0 means remove the cookie
1059             if (redirectCookie.getMaxAge() != 0)
1060             {
1061                 request.addCookie(redirectCookie);
1062             }
1063         }
1064     }
1065 
1066     /**
1067      * Adds isSecure() implementation to MockExternalContext20.
1068      *
1069      * TODO remove this one as soon as MyFaces-Test provides MockExternalContext21.
1070      */
1071     private static class MockExternalContext21 extends MockExternalContext20
1072     {
1073 
1074         private boolean secure = false;
1075 
1076         private MockExternalContext21(ServletContext context, HttpServletRequest request, HttpServletResponse response)
1077         {
1078             super(context, request, response);
1079         }
1080 
1081         @Override
1082         public boolean isSecure()
1083         {
1084             return secure;
1085         }
1086 
1087         public void setSecure(boolean secure)
1088         {
1089             this.secure = secure;
1090         }
1091     }
1092 
1093 }