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;
20  
21  import java.util.HashMap;
22  import java.util.Map;
23  
24  import javax.faces.component.UICommand;
25  import javax.faces.component.UIComponent;
26  import javax.faces.component.UIForm;
27  import javax.faces.component.UIInput;
28  import javax.faces.component.html.HtmlCommandButton;
29  import javax.faces.component.visit.VisitCallback;
30  import javax.faces.component.visit.VisitContext;
31  import javax.faces.component.visit.VisitResult;
32  import javax.faces.context.FacesContext;
33  import javax.faces.render.ResponseStateManager;
34  import javax.servlet.http.Cookie;
35  
36  import org.apache.myfaces.shared.renderkit.RendererUtils;
37  import org.apache.myfaces.test.mock.MockHttpServletRequest;
38  import org.apache.myfaces.test.mock.MockHttpServletResponse;
39  
40  /**
41   * Client that keep track and "translate" the commands done in a JSF component.
42   * It simulates the effect of a browser, but without execute any javascript
43   * or check the html output. If that level of detail is required, use an
44   * in-container alternative like Arquillian and others. This strategy is designed
45   * for server-side testing. 
46   * 
47   * @author Leonardo Uribe
48   *
49   */
50  public class MockMyFacesClient
51  {
52      private Map<String, String> parameters = new HashMap<String, String>();
53      private Map<String, Cookie> cookies = new HashMap<String, Cookie>();
54      private Map<String, Object> headers = new HashMap<String, Object>();
55      
56      private final FacesContext facesContext;
57      
58      // It has sense the client has a reference over the test, because 
59      // after all this class encapsulate some automatic operations
60      private AbstractMyFacesRequestTestCase testCase;
61      
62      public MockMyFacesClient(FacesContext facesContext, AbstractMyFacesRequestTestCase testCase)
63      {
64          this.facesContext = facesContext;
65          this.testCase = testCase;
66      }
67      
68      public void inputText(UIInput input, String text)
69      {
70          parameters.put(input.getClientId(), text);
71      }
72      
73      public void submit(UIComponent component) throws Exception
74      {
75          testCase.processRemainingPhases();
76          this.internalSubmit((UICommand)component);
77          String viewId = facesContext.getViewRoot().getViewId();
78          testCase.tearDownRequest();
79          testCase.setupRequest(viewId);
80      }
81      
82      protected void internalSubmit(UICommand command)
83      {
84          if (command instanceof HtmlCommandButton)
85          {
86              UIForm form = getParentForm(command);
87              VisitContext visitContext = VisitContext.createVisitContext(facesContext);
88              form.visitTree(visitContext, new VisitCallback(){
89  
90                  public VisitResult visit(VisitContext context,
91                          UIComponent target)
92                  {
93                      if (target instanceof UIInput)
94                      {
95                          if (!parameters.containsKey(target.getClientId(facesContext)))
96                          {
97                              parameters.put(target.getClientId(facesContext), RendererUtils.getStringValue(facesContext, target));
98                          }
99                      }
100                     return VisitResult.ACCEPT;
101                 }
102                 
103             });
104             parameters.put(form.getClientId(facesContext)+"_SUBMIT", "1");
105             parameters.put(ResponseStateManager.VIEW_STATE_PARAM, facesContext.getApplication().getStateManager().getViewState(facesContext));
106             Object value = command.getValue();
107             parameters.put(command.getClientId(), value == null ? "" : value.toString());
108             MockHttpServletResponse response = (MockHttpServletResponse) facesContext.getExternalContext().getResponse(); 
109             Cookie cookie = response.getCookie("oam.Flash.RENDERMAP.TOKEN");
110             getCookies().put("oam.Flash.RENDERMAP.TOKEN", cookie);
111         }
112     }
113     
114     public void ajax(UIComponent source, String event, String execute, String render, boolean submit) throws Exception
115     {
116         testCase.processRemainingPhases();
117         this.internalAjax(source, event, execute, render, submit);
118         String viewId = facesContext.getViewRoot().getViewId();
119         testCase.tearDownRequest();
120         testCase.setupRequest(viewId);
121     }
122     
123     public void internalAjax(UIComponent source, String event, String execute, String render, boolean submit)
124     {
125         parameters.put("javax.faces.partial.ajax", "true");
126         parameters.put("javax.faces.behavior.event", event);
127         parameters.put("javax.faces.partial.event", "action".equals(event) ? "click" : event);
128         parameters.put(ResponseStateManager.VIEW_STATE_PARAM, facesContext.getApplication().getStateManager().getViewState(facesContext));
129         parameters.put("javax.faces.source", source.getClientId(facesContext));
130         if (execute == null)
131         {
132             parameters.put("javax.faces.partial.execute", source.getClientId(facesContext));
133         }
134         else
135         {
136             parameters.put("javax.faces.partial.execute", execute);
137         }
138         if (render != null)
139         {
140             parameters.put("javax.faces.partial.render", render);
141         }
142         
143         if (submit)
144         {
145             parameters.put(source.getClientId(facesContext)+"_SUBMIT", "1");
146             parameters.put(source.getClientId(facesContext), source.getClientId(facesContext));
147         }
148         
149         MockHttpServletResponse response = (MockHttpServletResponse) facesContext.getExternalContext().getResponse(); 
150         Cookie cookie = response.getCookie("oam.Flash.RENDERMAP.TOKEN");
151         getCookies().put("oam.Flash.RENDERMAP.TOKEN", cookie);
152         
153         headers.put("Faces-Request", "partial/ajax");
154         headers.put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
155     }
156     
157     public Map<String, String> getParameters()
158     {
159         return parameters;
160     }
161     
162     public Map<String, Object> getHeaders()
163     {
164         return headers;
165     }
166     
167     public Map<String, Cookie> getCookies()
168     {
169         return cookies;
170     }
171     
172     private UIForm getParentForm(UIComponent component)
173     {
174         UIComponent parent = component.getParent();
175         while ( parent != null)
176         {
177             if (parent instanceof UIForm)
178             {
179                 return (UIForm) parent;
180             }
181             parent = parent.getParent();
182         }
183         return null;
184     }
185     
186     /**
187      * Apply all params, headers and cookies into the request.
188      * 
189      * @param request
190      */
191     public void apply(MockHttpServletRequest request)
192     {
193         Map<String, String> inputFields = getParameters();
194         for (Map.Entry<String, String> entry : inputFields.entrySet())
195         {
196             request.addParameter(entry.getKey(), entry.getValue());
197         }
198         Map<String, Object> headerFields = getHeaders();
199         for (Map.Entry<String, Object> entry : headerFields.entrySet())
200         {
201             if (entry.getValue() instanceof String)
202             {
203                 request.addHeader(entry.getKey(), (String) entry.getValue());
204             }
205             else if (entry.getValue() instanceof Integer)
206             {
207                 request.addIntHeader(entry.getKey(), (Integer) entry.getValue());
208             }
209             else if (entry.getValue() instanceof java.util.Date)
210             {
211                 request.addDateHeader(entry.getKey(), ((java.util.Date) entry.getValue()).getTime());
212             }
213         }
214         Map<String, Cookie> cookies = getCookies();
215         for (Map.Entry<String, Cookie> entry : cookies.entrySet())
216         {
217             request.addCookie(entry.getValue());
218         }
219     }
220 
221     public AbstractMyFacesRequestTestCase getTestCase()
222     {
223         return testCase;
224     }
225 
226     public void setTestCase(AbstractMyFacesRequestTestCase testCase)
227     {
228         this.testCase = testCase;
229     }
230 }