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 }