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