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