View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.teststeps;
14  
15  import java.beans.PropertyChangeEvent;
16  import java.beans.PropertyChangeListener;
17  import java.beans.PropertyChangeSupport;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.apache.log4j.Logger;
22  import org.apache.xmlbeans.XmlBoolean;
23  import org.apache.xmlbeans.XmlObject;
24  
25  import com.eviware.soapui.config.GotoConditionConfig;
26  import com.eviware.soapui.config.GotoConditionTypeConfig;
27  import com.eviware.soapui.config.GotoStepConfig;
28  import com.eviware.soapui.config.TestStepConfig;
29  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
30  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
31  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
32  import com.eviware.soapui.model.support.XPathReference;
33  import com.eviware.soapui.model.support.XPathReferenceContainer;
34  import com.eviware.soapui.model.support.XPathReferenceImpl;
35  import com.eviware.soapui.model.testsuite.TestProperty;
36  import com.eviware.soapui.model.testsuite.TestRunContext;
37  import com.eviware.soapui.model.testsuite.TestRunner;
38  import com.eviware.soapui.model.testsuite.TestStep;
39  import com.eviware.soapui.model.testsuite.TestStepResult;
40  import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
41  import com.eviware.soapui.support.StringUtils;
42  import com.eviware.soapui.support.UISupport;
43  
44  /***
45   * TestStep that moves execution to another step based on the contents of a XML Property
46   * 
47   * @author ole.matzura
48   */
49  
50  public class WsdlGotoTestStep extends WsdlTestStepWithProperties implements XPathReferenceContainer
51  {
52  	private GotoStepConfig gotoStepConfig;
53  	private List<GotoCondition> conditions = new ArrayList<GotoCondition>();
54  	private boolean canceled;
55  	
56  	private final static Logger log = Logger.getLogger( WsdlGotoTestStep.class );
57  	
58  	public WsdlGotoTestStep(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest)
59  	{
60  		super(testCase, config, true, forLoadTest);
61  		
62  		if( !forLoadTest )
63  		{
64  			setIcon( UISupport.createImageIcon("/goto.gif"));
65  		}
66  	}
67  
68  	public void postInit( TestStepConfig config )
69  	{
70  		if( config.getConfig() == null )
71  		{
72  			gotoStepConfig = (GotoStepConfig) config.addNewConfig().changeType( GotoStepConfig.type );
73  		}
74  		else
75  		{
76  			gotoStepConfig = (GotoStepConfig) config.getConfig().changeType(GotoStepConfig.type);
77  			for( int c = 0; c < gotoStepConfig.sizeOfConditionArray(); c++ )
78  			{
79  				conditions.add( new GotoCondition( gotoStepConfig.getConditionArray( c )));
80  			}	
81  		}
82  	}
83  
84  	public void resetConfigOnMove(TestStepConfig config)
85  	{
86  		super.resetConfigOnMove( config );
87  		
88  		gotoStepConfig = (GotoStepConfig) config.getConfig().changeType(GotoStepConfig.type);
89  		for( int c = 0; c < gotoStepConfig.sizeOfConditionArray(); c++ )
90  		{
91  			conditions.get( c ).setConfig( gotoStepConfig.getConditionArray( c ));
92  		}	
93  	}
94  
95  	public TestStepResult run(TestRunner runner, TestRunContext context)
96  	{
97  		WsdlTestStepResult result = new WsdlTestStepResult( this );
98  		canceled = false;
99  		
100 		result.startTimer();
101 		
102 		WsdlTestRequestStep previousStep = (WsdlTestRequestStep) getTestCase().findPreviousStepOfType( 
103 				this, WsdlTestRequestStep.class );
104 		
105 		if( previousStep == null )
106 		{
107 			result.stopTimer();
108 			result.addMessage( "Failed to find previous request step from [" + getName() + "]" );
109 			result.setStatus( TestStepStatus.FAILED );
110 			return result;
111 		}
112 		
113 		GotoCondition target = runConditions( previousStep, context );
114 		if( target == null )
115 		{
116 			result.addMessage( "Missing matching condition, moving on." );
117 		}
118 		else
119 		{
120 			String targetStepName = target.getTargetStep();
121 			result.addMessage( "Matched condition [" + targetStepName + "], transferring to [" + targetStepName + "]" );
122 			runner.gotoStep( runner.getTestCase().getTestStepIndexByName( targetStepName ) );
123 		}
124 		
125 		result.stopTimer();
126 		result.setStatus( TestStepStatus.OK );
127 		return result;
128 	}
129 
130 	public GotoCondition runConditions(WsdlTestRequestStep previousStep, TestRunContext context)
131 	{
132 		for( GotoCondition condition : conditions )
133 		{
134 			if( canceled )
135 				break;
136 			
137 			try
138 			{
139 				if( condition.evaluate( previousStep, context ))
140 				{
141 					return condition;
142 				}
143 			}
144 			catch (Exception e)
145 			{
146 				log.error( "Error making condition " + condition.getName() + "; " + e );
147 			}
148 		}
149 		
150 		return null;
151 	}
152 
153 	public boolean cancel()
154 	{
155 		canceled = true;
156 		return canceled;
157 	}
158 	
159 	public int getConditionCount()
160 	{
161 		return conditions.size();
162 	}
163 	
164 	public GotoCondition getConditionAt( int index )
165 	{
166 		return conditions.get( index );
167 	}
168 	
169 	public GotoCondition addCondition( String name )
170 	{
171 		GotoCondition condition = new GotoCondition( gotoStepConfig.addNewCondition());
172 		condition.setName( name );
173 		condition.setType( GotoConditionTypeConfig.XPATH.toString() );
174 		conditions.add( condition );
175 		return condition;
176 	}
177 	
178 	public void removeConditionAt( int index )
179 	{
180 		conditions.remove( index );
181 		gotoStepConfig.removeCondition( index );
182 	}
183 	
184 	public void release()
185 	{
186 		super.release(); 
187 		
188 		for( GotoCondition condition : conditions )
189 		{
190 			condition.release();
191 		}
192 	}
193 
194 	public class GotoCondition implements PropertyChangeListener
195 	{
196 		public final static String TARGET_STEP_PROPERTY = "target_step";
197 		
198 		private GotoConditionConfig conditionConfig;
199 		private TestStep currentStep;
200 		private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this );
201 
202 		public GotoCondition(GotoConditionConfig conditionConfig)
203 		{
204 			this.conditionConfig = conditionConfig;
205 			initListeners();
206 		}
207 		
208 		public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener )
209 		{
210 			propertyChangeSupport.addPropertyChangeListener( propertyName, listener );
211 		}
212 
213 		public void addPropertyChangeListener( PropertyChangeListener listener )
214 		{
215 			propertyChangeSupport.addPropertyChangeListener( listener );
216 		}
217 		
218 		public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener )
219 		{
220 			propertyChangeSupport.removePropertyChangeListener( propertyName, listener );
221 		}
222 
223 		public void removePropertyChangeListener( PropertyChangeListener listener )
224 		{
225 			propertyChangeSupport.removePropertyChangeListener( listener );
226 		}
227 		
228 		private void initListeners()
229 		{
230 			release();
231 			
232 			if( getTargetStep() != null )
233 			{
234 				int index = getTestCase().getTestStepIndexByName( getTargetStep() );
235 				if( index != -1 )
236 				{
237 					currentStep = getTestCase().getTestStepAt( index );
238 					currentStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, this );
239 				}
240 			}
241 		}
242 		
243 		public void release()
244 		{
245 			if( currentStep != null )
246 				currentStep.removePropertyChangeListener( this );
247 		}
248 	
249 		public boolean evaluate(WsdlTestRequestStep previousStep, TestRunContext context) throws Exception
250 		{
251 			if( getExpression() == null || getExpression().trim().length() == 0 )
252 				throw new Exception( "Missing expression in condition [" + getName() + "]" );
253 			
254 			if( getTargetStep() == null || getTargetStep().trim().length() == 0 )
255 				throw new Exception( "Missing target step in condition [" + getName() + "]" );
256 			
257 			if( getType().equals( GotoConditionTypeConfig.XPATH.toString() ))
258 			{
259 				XmlObject xmlObject = XmlObject.Factory.parse( previousStep.getTestRequest().getResponse().getContentAsString());
260 				
261 				String expression = PropertyExpansionUtils.expandProperties( context, getExpression() );
262 				XmlObject[] selectPath = xmlObject.selectPath( expression );
263 				if( selectPath.length == 1 && selectPath[0] instanceof XmlBoolean )
264 				{
265 					if( ((XmlBoolean)selectPath[0]).getBooleanValue() )
266 					{
267 						return true;
268 					}
269 				}
270 			}
271 			else
272 			{
273 				log.error( "Unkown condition type: " + getType() );
274 			}
275 			
276 			return false;
277 		}
278 
279 		protected void setConfig(GotoConditionConfig conditionConfig)
280 		{
281 			this.conditionConfig = conditionConfig;
282 		}
283 
284 		public String getType()
285 		{
286 			return conditionConfig.getType();
287 		}
288 		
289 		public String getName()
290 		{
291 			return conditionConfig.getName();
292 		}
293 
294 		public String getExpression()
295 		{
296 			return conditionConfig.getExpression();
297 		}
298 		
299 		public String getTargetStep()
300 		{
301 			return conditionConfig.getTargetStep();
302 		}
303 		
304 		public void setType( String type )
305 		{
306 			conditionConfig.setType( type );
307 		}
308 
309 		public void setName( String name )
310 		{
311 			conditionConfig.setName( name );
312 		}
313 		
314 		public void setExpression( String expression )
315 		{
316 			conditionConfig.setExpression( expression );
317 		}
318 		
319 		public void setTargetStep( String targetStep )
320 		{
321 			String oldStep = getTargetStep();
322 			conditionConfig.setTargetStep( targetStep );
323 			initListeners();
324 			propertyChangeSupport.firePropertyChange( TARGET_STEP_PROPERTY, oldStep, targetStep );
325 		}
326 
327 		public void propertyChange(PropertyChangeEvent evt)
328 		{
329 			conditionConfig.setTargetStep( evt.getNewValue().toString() );
330 			propertyChangeSupport.firePropertyChange( TARGET_STEP_PROPERTY, evt.getOldValue(), evt.getNewValue() );
331 		}
332 
333 		public TestProperty getSourceProperty()
334 		{
335 			WsdlTestRequestStep previousStep = (WsdlTestRequestStep) getTestCase().findPreviousStepOfType( 
336 						WsdlGotoTestStep.this, WsdlTestRequestStep.class );
337 			return previousStep == null ? null : previousStep.getProperty( "Response" );
338 		}
339 	}
340 	
341 	public boolean hasProperties()
342 	{
343 		return false;
344 	}
345 	
346 	public PropertyExpansion[] getPropertyExpansions()
347 	{
348 		List<PropertyExpansion> result = new ArrayList<PropertyExpansion>();
349 		
350 		for( GotoCondition condition : conditions )
351 		{
352 			result.addAll( PropertyExpansionUtils.extractPropertyExpansions( this, condition, "expression") );
353 		}
354 		
355 		return result.toArray( new PropertyExpansion[result.size()] );
356 	}
357 	
358 	public XPathReference[] getXPathReferences()
359 	{
360 		List<XPathReference> result = new ArrayList<XPathReference>();
361 		
362 		for( GotoCondition condition : conditions )
363 		{
364 			if( StringUtils.hasContent( condition.getExpression() ))
365 				result.add( new XPathReferenceImpl( "Condition for " + condition.getName() + " GotoCondition in " + getName(), 
366 							condition.getSourceProperty(), condition, "expression" ));
367 		}
368 		
369 		return result.toArray( new XPathReference[result.size()] );
370 	}
371 }