View Javadoc

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