1   /*
2    * $Id: TestActionConfig.java 480593 2006-11-29 15:17:52Z niallp $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.struts.config;
22  
23  import junit.framework.Test;
24  import junit.framework.TestCase;
25  import junit.framework.TestSuite;
26  
27  import java.lang.reflect.InvocationTargetException;
28  
29  /**
30   * Unit tests for the <code>org.apache.struts.config.ActionConfig</code>
31   * class.  Currently only contains code to test the methods that support
32   * configuration inheritance.
33   *
34   * @version $Rev: 480593 $ $Date: 2005-05-25 19:35:00 -0400 (Wed, 25 May 2005)
35   *          $
36   */
37  public class TestActionConfig extends TestCase {
38      // ----------------------------------------------------- Instance Variables
39  
40      /**
41       * The ModuleConfig we'll use.
42       */
43      protected ModuleConfig config = null;
44  
45      /**
46       * The common base we'll use.
47       */
48      protected ActionConfig baseConfig = null;
49  
50      // ----------------------------------------------------------- Constructors
51  
52      /**
53       * Construct a new instance of this test case.
54       *
55       * @param name Name of the test case
56       */
57      public TestActionConfig(String name) {
58          super(name);
59      }
60  
61      // --------------------------------------------------------- Public Methods
62  
63      /**
64       * Set up instance variables required by this test case.
65       */
66      public void setUp() {
67          ModuleConfigFactory factoryObject = ModuleConfigFactory.createFactory();
68  
69          config = factoryObject.createModuleConfig("");
70  
71          // setup the base form
72          baseConfig = new ActionConfig();
73          baseConfig.setPath("/base");
74          baseConfig.setType("org.apache.struts.actions.DummyAction");
75  
76          // set up success and failure forward
77          ForwardConfig forward =
78              new ForwardConfig("success", "/success.jsp", false);
79  
80          baseConfig.addForwardConfig(forward);
81  
82          forward = new ForwardConfig("failure", "/failure.jsp", false);
83          forward.setProperty("forwardCount", "10");
84          baseConfig.addForwardConfig(forward);
85  
86          // setup an exception handler
87          ExceptionConfig exceptionConfig = new ExceptionConfig();
88  
89          exceptionConfig.setType("java.sql.SQLException");
90          exceptionConfig.setKey("msg.exception.sql");
91          exceptionConfig.setProperty("exceptionCount", "10");
92          baseConfig.addExceptionConfig(exceptionConfig);
93  
94          // set some arbitrary properties
95          baseConfig.setProperty("label", "base");
96          baseConfig.setProperty("version", "1a");
97  
98          // register it to our config
99          config.addActionConfig(baseConfig);
100     }
101 
102     /**
103      * Return the tests included in this test suite.
104      */
105     public static Test suite() {
106         return (new TestSuite(TestActionConfig.class));
107     }
108 
109     /**
110      * Tear down instance variables required by this test case.
111      */
112     public void tearDown() {
113         config = null;
114         baseConfig = null;
115     }
116 
117     // ------------------------------------------------------- Individual Tests
118 
119     /**
120      * Basic check that shouldn't detect circular inheritance.
121      */
122     public void testCheckCircularInheritance() {
123         ActionConfig child = new ActionConfig();
124 
125         child.setPath("/child");
126         child.setExtends("/base");
127 
128         ActionConfig grandChild = new ActionConfig();
129 
130         grandChild.setPath("/grandChild");
131         grandChild.setExtends("/child");
132 
133         config.addActionConfig(child);
134         config.addActionConfig(grandChild);
135 
136         assertTrue("Circular inheritance shouldn't have been detected",
137             !grandChild.checkCircularInheritance(config));
138     }
139 
140     /**
141      * Basic check that should detect circular inheritance.
142      */
143     public void testCheckCircularInheritanceError() {
144         ActionConfig child = new ActionConfig();
145 
146         child.setPath("/child");
147         child.setExtends("/base");
148 
149         ActionConfig grandChild = new ActionConfig();
150 
151         grandChild.setPath("/grandChild");
152         grandChild.setExtends("/child");
153 
154         // establish the circular relationship with base
155         baseConfig.setExtends("/grandChild");
156 
157         config.addActionConfig(child);
158         config.addActionConfig(grandChild);
159 
160         assertTrue("Circular inheritance should've been detected",
161             grandChild.checkCircularInheritance(config));
162     }
163 
164     /**
165      * Test that processExtends() makes sure that a base action's own
166      * extension has been processed.
167      */
168     public void testProcessExtendsActionExtends()
169         throws Exception {
170         CustomActionConfig first = new CustomActionConfig();
171 
172         first.setPath("/first");
173 
174         CustomActionConfig second = new CustomActionConfig();
175 
176         second.setPath("/second");
177         second.setExtends("/first");
178 
179         config.addActionConfig(first);
180         config.addActionConfig(second);
181 
182         // set baseConfig to extend second
183         baseConfig.setExtends("/second");
184 
185         baseConfig.processExtends(config);
186 
187         assertTrue("The first action's processExtends() wasn't called",
188             first.processExtendsCalled);
189         assertTrue("The second action's processExtends() wasn't called",
190             second.processExtendsCalled);
191     }
192 
193     /**
194      * Make sure that correct exception is thrown if a base action can't be
195      * found.
196      */
197     public void testProcessExtendsMissingAction()
198         throws Exception {
199         baseConfig.setExtends("/someMissingAction");
200 
201         try {
202             baseConfig.processExtends(config);
203             fail(
204                 "An exception should be thrown if a super form can't be found.");
205         } catch (NullPointerException e) {
206             // succeed
207         } catch (InstantiationException e) {
208             fail("Unrecognized exception thrown.");
209         }
210     }
211 
212     /**
213      * Test a typical form bean configuration extension where various forwards
214      * and exception handlers should be inherited from a base form. This
215      * method checks all the subelements.
216      */
217     public void testInheritFrom()
218         throws Exception {
219         // create a basic subform
220         ActionConfig subConfig = new ActionConfig();
221         String subConfigPath = "subConfig";
222 
223         subConfig.setPath(subConfigPath);
224         subConfig.setExtends("/base");
225 
226         // override success
227         ForwardConfig forward = new ForwardConfig();
228 
229         forward.setName("success");
230         forward.setPath("/newSuccess.jsp");
231         forward.setRedirect(true);
232         subConfig.addForwardConfig(forward);
233 
234         // add an exception handler
235         ExceptionConfig handler = new ExceptionConfig();
236 
237         handler.setType("java.lang.NullPointerException");
238         handler.setKey("msg.exception.npe");
239         subConfig.addExceptionConfig(handler);
240 
241         // override arbitrary "label" property
242         subConfig.setProperty("label", "sub");
243 
244         config.addActionConfig(subConfig);
245 
246         subConfig.inheritFrom(baseConfig);
247 
248         // check that our subConfig is still the one in the config
249         assertSame("subConfig no longer in ModuleConfig", subConfig,
250             config.findActionConfig("subConfig"));
251 
252         // check our configured sub config
253         assertNotNull("Action type was not inherited", subConfig.getType());
254         assertEquals("Wrong config path", subConfigPath, subConfig.getPath());
255         assertEquals("Wrong config type", baseConfig.getType(),
256             subConfig.getType());
257 
258         // check our forwards
259         ForwardConfig[] forwards = subConfig.findForwardConfigs();
260 
261         assertEquals("Wrong forwards count", 2, forwards.length);
262 
263         forward = subConfig.findForwardConfig("success");
264         assertNotNull("'success' forward was not found", forward);
265         assertEquals("Wrong path for success", "/newSuccess.jsp",
266             forward.getPath());
267 
268         forward = subConfig.findForwardConfig("failure");
269 
270         ForwardConfig origForward = baseConfig.findForwardConfig("failure");
271 
272         assertNotNull("'failure' forward was not inherited", forward);
273         assertEquals("Wrong type for 'failure'", origForward.getPath(),
274             forward.getPath());
275         assertEquals("Arbitrary property not copied",
276             origForward.getProperty("forwardCount"),
277             forward.getProperty("forwardCount"));
278 
279         // check our exceptions
280         ExceptionConfig[] handlers = subConfig.findExceptionConfigs();
281 
282         assertEquals("Wrong exception config count", 2, handlers.length);
283 
284         handler = subConfig.findExceptionConfig("java.sql.SQLException");
285 
286         ExceptionConfig origHandler =
287             baseConfig.findExceptionConfig("java.sql.SQLException");
288 
289         assertNotNull("'SQLException' handler was not found", handler);
290         assertEquals("Wrong key for 'SQLException'", origHandler.getKey(),
291             handler.getKey());
292         assertEquals("Arbitrary property not copied",
293             origHandler.getProperty("exceptionCount"),
294             handler.getProperty("exceptionCount"));
295 
296         handler =
297             subConfig.findExceptionConfig("java.lang.NullPointerException");
298         assertNotNull("'NullPointerException' handler disappeared", handler);
299 
300         // check the arbitrary properties
301         String version = subConfig.getProperty("version");
302 
303         assertEquals("Arbitrary property 'version' wasn't inherited", "1a",
304             version);
305 
306         String label = subConfig.getProperty("label");
307 
308         assertEquals("Arbitrary property 'label' shouldn't have changed",
309             "sub", label);
310     }
311 
312     /**
313      * Make sure that correct exception is thrown if a base action can't be
314      * found.
315      */
316     public void testInheritBoolean()
317         throws Exception {
318 
319         ActionConfig parentConfig = new ActionConfig();
320         parentConfig.setPath("/parent");
321         ActionConfig childConfig  = null;
322 
323         // Test if boolean is NOT set it IS inherited
324         parentConfig.setValidate(true);
325         parentConfig.setCancellable(true);
326         childConfig = new ActionConfig();
327         childConfig.inheritFrom(parentConfig);
328         assertEquals("default validate inherit true", true, childConfig.getValidate());
329         assertEquals("default cancellable inherit true", true, childConfig.getValidate());
330 
331         // Test if boolean is NOT set it IS inherited
332         parentConfig.setValidate(false);
333         parentConfig.setCancellable(false);
334         childConfig = new ActionConfig();
335         childConfig.inheritFrom(parentConfig);
336         assertEquals("default validate inherit false", false, childConfig.getValidate());
337         assertEquals("default cancellable inherit false", false, childConfig.getValidate());
338 
339         // Test if boolean IS set it is NOT inherited
340         parentConfig.setValidate(true);
341         parentConfig.setCancellable(true);
342         childConfig = new ActionConfig();
343         childConfig.setValidate(false);
344         childConfig.setCancellable(false);
345         childConfig.inheritFrom(parentConfig);
346         assertEquals("set validate (not inherit true)", false, childConfig.getValidate());
347         assertEquals("set cancellable (not inherit false)", false, childConfig.getValidate());
348 
349         // Test if boolean IS set it is NOT inherited
350         parentConfig.setValidate(false);
351         parentConfig.setCancellable(false);
352         childConfig = new ActionConfig();
353         childConfig.setValidate(true);
354         childConfig.setCancellable(true);
355         childConfig.inheritFrom(parentConfig);
356         assertEquals("set validate (not inherit false)", true, childConfig.getValidate());
357         assertEquals("set cancellable (not inherit false)", true, childConfig.getValidate());
358 
359     }
360 
361     /**
362      * Used to detect that ActionConfig is making the right calls.
363      */
364     public static class CustomActionConfig extends ActionConfig {
365         boolean processExtendsCalled = false;
366 
367         public void processExtends(ModuleConfig moduleConfig)
368             throws ClassNotFoundException, IllegalAccessException,
369                 InstantiationException, InvocationTargetException {
370             super.processExtends(moduleConfig);
371             processExtendsCalled = true;
372         }
373     }
374 }