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