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.mc.test.core.mock;
20  
21  import java.util.HashMap;
22  import java.util.Map;
23  import javax.faces.FacesException;
24  
25  import javax.faces.component.UICommand;
26  import javax.faces.component.UIComponent;
27  import javax.faces.component.UIForm;
28  import javax.faces.component.UIInput;
29  import javax.faces.component.html.HtmlCommandButton;
30  import javax.faces.component.visit.VisitCallback;
31  import javax.faces.component.visit.VisitContext;
32  import javax.faces.component.visit.VisitResult;
33  import javax.faces.context.FacesContext;
34  import javax.faces.render.ResponseStateManager;
35  import javax.servlet.http.Cookie;
36  import javax.servlet.http.HttpServletRequest;
37  import javax.servlet.http.HttpServletResponse;
38  import org.apache.myfaces.mc.test.core.AbstractMyFacesRequestTestCase;
39  
40  import org.apache.myfaces.shared.renderkit.RendererUtils;
41  import org.apache.myfaces.test.mock.MockHttpServletRequest;
42  import org.apache.myfaces.test.mock.MockHttpServletResponse;
43  import org.junit.Assert;
44  
45  /**
46   * Client that keep track and "translate" the commands done in a JSF component.
47   * It simulates the effect of a browser, but without execute any javascript
48   * or check the html output. If that level of detail is required, use an
49   * in-container alternative like Arquillian and others. This strategy is designed
50   * for server-side testing. 
51   * 
52   * @author Leonardo Uribe
53   *
54   */
55  public class MockMyFacesClient
56  {
57      private Map<String, String> parameters = new HashMap<String, String>();
58      private Map<String, Cookie> cookies = new HashMap<String, Cookie>();
59      private Map<String, Object> headers = new HashMap<String, Object>();
60      
61      // It has sense the client has a reference over the test, because 
62      // after all this class encapsulate some automatic operations
63      private ServletMockContainer testCase;
64      
65      public MockMyFacesClient(FacesContext facesContext, ServletMockContainer testCase)
66      {
67          this.testCase = testCase;
68      }
69      
70      public void processRedirect()
71      {
72          HttpServletResponse response = testCase.getResponse();
73          HttpServletRequest request = testCase.getRequest();
74          if (response.getStatus() == HttpServletResponse.SC_FOUND)
75          {
76              testCase.processRemainingPhases(); //testCase.processRemainingPhases();
77              testCase.endRequest();
78              String location = response.getHeader("Location");
79              String contextPath = request.getContextPath() == null ? "" : request.getContextPath();
80              String servletPath = request.getServletPath() == null ? "" : request.getServletPath();
81              int cpi = location.indexOf(contextPath);
82              int spi = cpi < 0 ? -1 : location.indexOf(servletPath, cpi+contextPath.length());
83              String viewId;
84              if (spi >= 0)
85              {
86                  viewId = location.substring(spi+servletPath.length());
87              }
88              else
89              {
90                  viewId = location;
91              }
92              testCase.startViewRequest(viewId);
93          }
94          else
95          {
96              Assert.fail("Expected redirect not found");
97          }
98      }
99      
100     public void inputText(UIInput input, String text)
101     {
102         parameters.put(input.getClientId(), text);
103     }
104     
105     public void inputText(String clientId, String text)
106     {
107         UIComponent input = getTestCase().getFacesContext().
108             getViewRoot().findComponent(clientId);
109         if (input == null)
110         {
111             throw new FacesException("input with clientId:"+clientId+" not found");
112         }
113         else
114         {
115             parameters.put(input.getClientId(), text);
116         }
117     }
118     
119     /**
120      * Simulate a submit, processing the remaining phases and setting up the new request.
121      * It delegates to client.submit, where the necessary data is gathered to be applied
122      * later on client.apply method.
123      * 
124      * @param component
125      * @throws Exception
126      */
127     public void submit(UIComponent component)
128     {
129         testCase.processRemainingPhases();
130         this.internalSubmit((UICommand)component);
131         String viewId = testCase.getFacesContext().getViewRoot().getViewId();
132         testCase.endRequest();
133         testCase.startViewRequest(viewId);
134     }
135     
136     public void submit(String clientId)
137     {
138         UIComponent button = getTestCase().getFacesContext().
139             getViewRoot().findComponent(clientId);
140         if (button == null)
141         {
142             throw new FacesException("button with clientId:"+clientId+" not found");
143         }
144         else
145         {
146             submit(button);
147         }
148     }
149     
150     protected void internalSubmit(UICommand command)
151     {
152         if (command instanceof HtmlCommandButton)
153         {
154             final FacesContext facesContext = testCase.getFacesContext();
155             UIForm form = getParentForm(command);
156             VisitContext visitContext = VisitContext.createVisitContext(facesContext);
157             form.visitTree(visitContext, new VisitCallback(){
158 
159                 public VisitResult visit(VisitContext context,
160                         UIComponent target)
161                 {
162                     if (target instanceof UIInput)
163                     {
164                         if (!parameters.containsKey(target.getClientId(facesContext)))
165                         {
166                             parameters.put(target.getClientId(facesContext), 
167                                 RendererUtils.getStringValue(facesContext, target));
168                         }
169                     }
170                     return VisitResult.ACCEPT;
171                 }
172                 
173             });
174             parameters.put(form.getClientId(facesContext)+"_SUBMIT", "1");
175             Object value = command.getValue();
176             parameters.put(command.getClientId(), value == null ? "" : value.toString());
177             
178             applyStateFromPreviousRequest();
179             /*
180             parameters.put(ResponseStateManager.VIEW_STATE_PARAM, 
181                 facesContext.getApplication().getStateManager().getViewState(facesContext));
182             if (facesContext.getExternalContext().getClientWindow() != null)
183             {
184                 parameters.put(ResponseStateManager.CLIENT_WINDOW_URL_PARAM, 
185                 facesContext.getExternalContext().getClientWindow().getId());
186             }
187             MockHttpServletResponse response = (MockHttpServletResponse) 
188                 facesContext.getExternalContext().getResponse(); 
189             Cookie cookie = response.getCookie("oam.Flash.RENDERMAP.TOKEN");
190             getCookies().put("oam.Flash.RENDERMAP.TOKEN", cookie);*/
191         }
192     }
193     
194     public void ajax(UIComponent source, String event, String execute, String render, boolean submit) throws Exception
195     {
196         ajax(source, event, execute, render, submit, false);
197     }
198     
199     public void ajax(String sourceClientId, String event, String execute, String render, boolean submit) throws Exception
200     {
201         ajax(sourceClientId, event, execute, render, submit, false);
202     }    
203             
204     public void ajax(UIComponent source, String event, String execute, String render, 
205         boolean submit, boolean resetValues)
206     {
207         testCase.processRemainingPhases();
208         this.internalAjax(source.getClientId(testCase.getFacesContext()), event, execute, render, submit, resetValues);
209         String viewId = testCase.getFacesContext().getViewRoot().getViewId();
210         testCase.endRequest();
211         testCase.startViewRequest(viewId);
212     }
213     
214     public void ajax(String sourceClientId, String event, String execute, String render, 
215         boolean submit, boolean resetValues)
216     {
217         testCase.processRemainingPhases();
218         this.internalAjax(sourceClientId, event, execute, render, submit, resetValues);
219         String viewId = testCase.getFacesContext().getViewRoot().getViewId();
220         testCase.endRequest();
221         testCase.startViewRequest(viewId);
222     }
223     
224     protected void internalAjax(String source, String event, String execute, String render, 
225         boolean submit, boolean resetValues)
226     {
227         parameters.put("javax.faces.partial.ajax", "true");
228         parameters.put("javax.faces.behavior.event", event);
229         parameters.put("javax.faces.partial.event", "action".equals(event) ? "click" : event);
230         applyStateFromPreviousRequest();
231         //parameters.put(ResponseStateManager.VIEW_STATE_PARAM, 
232         //    facesContext.getApplication().getStateManager().getViewState(facesContext));
233         parameters.put("javax.faces.source", source);
234         if (execute == null)
235         {
236             parameters.put("javax.faces.partial.execute", source);
237         }
238         else
239         {
240             parameters.put("javax.faces.partial.execute", execute);
241         }
242         if (render != null)
243         {
244             parameters.put("javax.faces.partial.render", render);
245         }
246         
247         if (submit)
248         {
249             parameters.put(source+"_SUBMIT", "1");
250             parameters.put(source, source);
251         }
252         
253         if (resetValues)
254         {
255             parameters.put("javax.faces.partial.resetValues", "true");
256         }
257         
258         headers.put("Faces-Request", "partial/ajax");
259         headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
260     }
261     
262     protected void applyStateFromPreviousRequest()
263     {
264         FacesContext facesContext = testCase.getFacesContext();
265         
266         parameters.put(ResponseStateManager.VIEW_STATE_PARAM, 
267             facesContext.getApplication().getStateManager().getViewState(facesContext));
268         if (facesContext.getExternalContext().getClientWindow() != null)
269         {
270             parameters.put(ResponseStateManager.CLIENT_WINDOW_URL_PARAM, 
271                 facesContext.getExternalContext().getClientWindow().getId());
272         }
273         
274         applyCookiesFromPreviousRequest();
275     }
276     
277     protected void applyCookiesFromPreviousRequest()
278     {
279         MockHttpServletResponse response = (MockHttpServletResponse) testCase.getResponse();
280         if (response.getCookies() != null && !response.getCookies().isEmpty())
281         {
282             for (Map.Entry<String, Cookie> entry : response.getCookies().entrySet())
283             {
284                 getCookies().put(entry.getKey(), entry.getValue());
285             }
286         }
287     }
288     
289     public Map<String, String> getParameters()
290     {
291         return parameters;
292     }
293     
294     public Map<String, Object> getHeaders()
295     {
296         return headers;
297     }
298     
299     public Map<String, Cookie> getCookies()
300     {
301         return cookies;
302     }
303     
304     private UIForm getParentForm(UIComponent component)
305     {
306         UIComponent parent = component.getParent();
307         while ( parent != null)
308         {
309             if (parent instanceof UIForm)
310             {
311                 return (UIForm) parent;
312             }
313             parent = parent.getParent();
314         }
315         return null;
316     }
317     
318     /**
319      * Apply all params, headers and cookies into the request.
320      * 
321      * @param request
322      */
323     public void apply(MockHttpServletRequest request)
324     {
325         Map<String, String> inputFields = getParameters();
326         for (Map.Entry<String, String> entry : inputFields.entrySet())
327         {
328             request.addParameter(entry.getKey(), entry.getValue());
329         }
330         Map<String, Object> headerFields = getHeaders();
331         for (Map.Entry<String, Object> entry : headerFields.entrySet())
332         {
333             if (entry.getValue() instanceof String)
334             {
335                 request.addHeader(entry.getKey(), (String) entry.getValue());
336             }
337             else if (entry.getValue() instanceof Integer)
338             {
339                 request.addIntHeader(entry.getKey(), (Integer) entry.getValue());
340             }
341             else if (entry.getValue() instanceof java.util.Date)
342             {
343                 request.addDateHeader(entry.getKey(), ((java.util.Date) entry.getValue()).getTime());
344             }
345         }
346         Map<String, Cookie> cookies = getCookies();
347         for (Map.Entry<String, Cookie> entry : cookies.entrySet())
348         {
349             request.addCookie(entry.getValue());
350         }
351     }
352     
353     public void reset(FacesContext facesContext)
354     {
355         this.parameters.clear();
356         this.headers.clear();
357         this.cookies.clear();
358     }
359 
360     public ServletMockContainer getTestCase()
361     {
362         return testCase;
363     }
364 
365     public void setTestCase(AbstractMyFacesRequestTestCase testCase)
366     {
367         this.testCase = testCase;
368     }
369 }