View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2009 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.util.ArrayList;
17  import java.util.Collection;
18  import java.util.List;
19  import java.util.Map;
20  
21  import javax.swing.ImageIcon;
22  import javax.xml.namespace.QName;
23  
24  import org.apache.log4j.Logger;
25  
26  import com.eviware.soapui.config.RestRequestStepConfig;
27  import com.eviware.soapui.config.TestStepConfig;
28  import com.eviware.soapui.impl.rest.RestMethod;
29  import com.eviware.soapui.impl.rest.RestRequest;
30  import com.eviware.soapui.impl.rest.RestResource;
31  import com.eviware.soapui.impl.rest.RestService;
32  import com.eviware.soapui.impl.rest.support.RestParamProperty;
33  import com.eviware.soapui.impl.rest.support.RestRequestConverter;
34  import com.eviware.soapui.impl.support.AbstractHttpRequest;
35  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
36  import com.eviware.soapui.impl.wsdl.WsdlProject;
37  import com.eviware.soapui.impl.wsdl.WsdlSubmit;
38  import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse;
39  import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
40  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
41  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
42  import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry.AssertableType;
43  import com.eviware.soapui.impl.wsdl.teststeps.registry.RestRequestStepFactory.ItemDeletedException;
44  import com.eviware.soapui.model.ModelItem;
45  import com.eviware.soapui.model.iface.Interface;
46  import com.eviware.soapui.model.iface.Operation;
47  import com.eviware.soapui.model.iface.Submit;
48  import com.eviware.soapui.model.iface.Request.SubmitException;
49  import com.eviware.soapui.model.project.Project;
50  import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
51  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
52  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult;
53  import com.eviware.soapui.model.support.InterfaceListenerAdapter;
54  import com.eviware.soapui.model.support.ModelSupport;
55  import com.eviware.soapui.model.support.ProjectListenerAdapter;
56  import com.eviware.soapui.model.support.TestPropertyListenerAdapter;
57  import com.eviware.soapui.model.support.TestStepBeanProperty;
58  import com.eviware.soapui.model.testsuite.AssertionError;
59  import com.eviware.soapui.model.testsuite.AssertionsListener;
60  import com.eviware.soapui.model.testsuite.TestAssertion;
61  import com.eviware.soapui.model.testsuite.TestCaseRunContext;
62  import com.eviware.soapui.model.testsuite.TestCaseRunner;
63  import com.eviware.soapui.model.testsuite.TestProperty;
64  import com.eviware.soapui.model.testsuite.TestStep;
65  import com.eviware.soapui.model.testsuite.TestStepProperty;
66  import com.eviware.soapui.model.testsuite.TestStepResult;
67  import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
68  import com.eviware.soapui.support.resolver.ChangeRestMethodResolver;
69  import com.eviware.soapui.support.resolver.ImportInterfaceResolver;
70  import com.eviware.soapui.support.resolver.RemoveTestStepResolver;
71  import com.eviware.soapui.support.resolver.ResolveContext;
72  import com.eviware.soapui.support.resolver.ResolveContext.PathToResolve;
73  import com.eviware.soapui.support.types.StringToStringMap;
74  
75  public class RestTestRequestStep extends WsdlTestStepWithProperties implements RestTestRequestStepInterface
76  {
77  	private final static Logger log = Logger.getLogger( RestTestRequestStep.class );
78  	private RestRequestStepConfig restRequestStepConfig;
79  	private RestTestRequest testRequest;
80  	private RestResource restResource;
81  	private RestMethod restMethod;
82  	private final InternalProjectListener projectListener = new InternalProjectListener();
83  	private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
84  	private WsdlSubmit<RestRequest> submit;
85  
86  	public RestTestRequestStep( WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest )
87  			throws ItemDeletedException
88  	{
89  		super( testCase, config, true, forLoadTest );
90  
91  		if( getConfig().getConfig() != null )
92  		{
93  			restRequestStepConfig = ( RestRequestStepConfig )getConfig().getConfig().changeType(
94  					RestRequestStepConfig.type );
95  
96  			testRequest = buildTestRequest( forLoadTest );
97  			if( testRequest == null )
98  				throw new ItemDeletedException();
99  
100 			// testRequest = new RestTestRequest( null,
101 			// requestStepConfig.getRestRequest(), this, forLoadTest );
102 			testRequest.addPropertyChangeListener( this );
103 			testRequest.addTestPropertyListener( new InternalTestPropertyListener() );
104 
105 			if( config.isSetName() )
106 				testRequest.setName( config.getName() );
107 			else
108 				config.setName( testRequest.getName() );
109 		}
110 		else
111 		{
112 			restRequestStepConfig = ( RestRequestStepConfig )getConfig().addNewConfig().changeType(
113 					RestRequestStepConfig.type );
114 		}
115 
116 		for( TestProperty property : testRequest.getProperties().values() )
117 		{
118 			addProperty( new RestTestStepProperty( ( RestParamProperty )property ) );
119 		}
120 
121 		// init default properties
122 		addProperty( new TestStepBeanProperty( "Endpoint", false, testRequest, "endpoint", this ) );
123 		addProperty( new TestStepBeanProperty( "Username", false, testRequest, "username", this ) );
124 		addProperty( new TestStepBeanProperty( "Password", false, testRequest, "password", this ) );
125 		addProperty( new TestStepBeanProperty( "Domain", false, testRequest, "domain", this ) );
126 
127 		// init properties
128 		addProperty( new TestStepBeanProperty( "Request", false, testRequest, "requestContent", this )
129 		{
130 			@Override
131 			public String getDefaultValue()
132 			{
133 				return createDefaultRequestContent();
134 			}
135 		} );
136 
137 		addProperty( new TestStepBeanProperty( "ResponseAsXml", true, testRequest, "responseContentAsXml", this )
138 		{
139 			@Override
140 			public String getDefaultValue()
141 			{
142 				return createDefaultResponseXmlContent();
143 			}
144 		} );
145 
146 		addProperty( new TestStepBeanProperty( "Response", true, testRequest, "responseContentAsString", this )
147 		{
148 			@Override
149 			public String getDefaultValue()
150 			{
151 				return createDefaultRawResponseContent();
152 			}
153 		} );
154 
155 		initRestTestRequest();
156 
157 		if( !forLoadTest && restResource != null )
158 		{
159 			getResource().getInterface().getProject().addProjectListener( projectListener );
160 			getResource().getInterface().addInterfaceListener( interfaceListener );
161 
162 			// we need to listen for name changes which happen when interfaces
163 			// are
164 			getResource().getInterface().addPropertyChangeListener( this );
165 			getResource().addPropertyChangeListener( this );
166 		}
167 
168 		if( getRestMethod() != null )
169 		{
170 			getRestMethod().addPropertyChangeListener( this );
171 		}
172 	}
173 
174 	public void beforeSave()
175 	{
176 		super.beforeSave();
177 
178 		if( testRequest != null )
179 			testRequest.beforeSave();
180 	}
181 
182 	public RestRequestStepConfig getRequestStepConfig()
183 	{
184 		return restRequestStepConfig;
185 	}
186 
187 	protected RestTestRequest buildTestRequest( boolean forLoadTest )
188 	{
189 		if( getRestMethod() == null )
190 			return null;
191 		return new RestTestRequest( getRestMethod(), getRequestStepConfig().getRestRequest(), this, forLoadTest );
192 	}
193 
194 	private void initRestTestRequest()
195 	{
196 		if( getRestMethod() == null )
197 			setDisabled( true );
198 		else
199 			getTestRequest().setRestMethod( getRestMethod() );
200 	}
201 
202 	public String getService()
203 	{
204 		return getRequestStepConfig().getService();
205 	}
206 
207 	public String getResourcePath()
208 	{
209 		return getRequestStepConfig().getResourcePath();
210 	}
211 
212 	protected String createDefaultRawResponseContent()
213 	{
214 		return getResource() == null ? null : getResource().createResponse( true );
215 	}
216 
217 	protected String createDefaultResponseXmlContent()
218 	{
219 		return getResource() == null ? null : getResource().createResponse( true );
220 	}
221 
222 	protected String createDefaultRequestContent()
223 	{
224 		return getResource() == null ? null : getResource().createRequest( true );
225 	}
226 
227 	@Override
228 	public Collection<Interface> getRequiredInterfaces()
229 	{
230 		ArrayList<Interface> result = new ArrayList<Interface>();
231 		result.add( findRestResource().getInterface() );
232 		return result;
233 	}
234 
235 	private RestResource findRestResource()
236 	{
237 		Project project = ModelSupport.getModelItemProject( this );
238 		RestService restService = ( RestService )project.getInterfaceByName( getRequestStepConfig().getService() );
239 		if( restService != null )
240 		{
241 			return restService.getResourceByFullPath( getRequestStepConfig().getResourcePath() );
242 		}
243 		return null;
244 	}
245 
246 	private RestMethod findRestMethod()
247 	{
248 		if( !restRequestStepConfig.isSetMethodName() )
249 		{
250 			RestRequestConverter.updateRestTestRequest( this );
251 			
252 			// Must be an old version RestRequest...
253 			if( getResource() == null )
254 			{
255 				restResource = RestRequestConverter.resolveResource( this );
256 				if( restResource == null )
257 					return null;
258 				getRequestStepConfig().setService( restResource.getInterface().getName() );
259 				getRequestStepConfig().setResourcePath( restResource.getFullPath() );
260 			}
261 			RestMethod method = RestRequestConverter.getMethod( getResource(), getRequestStepConfig().getRestRequest()
262 					.selectAttribute( null, "method" ).newCursor().getTextValue(), getRequestStepConfig().getRestRequest()
263 					.getName() );
264 			restRequestStepConfig.setMethodName( method.getName() );
265 			return method;
266 		}
267 		return ( RestMethod )getWsdlModelItemByName( getResource().getRestMethodList(), getRequestStepConfig()
268 				.getMethodName() );
269 	}
270 
271 	public RestMethod getRestMethod()
272 	{
273 		if( restMethod == null )
274 			restMethod = findRestMethod();
275 		return restMethod;
276 	}
277 
278 	public RestResource getResource()
279 	{
280 		if( restResource == null )
281 			restResource = findRestResource();
282 		return restResource;
283 	}
284 
285 	public Operation getOperation()
286 	{
287 		return getResource();
288 	}
289 
290 	@Override
291 	public void release()
292 	{
293 		super.release();
294 
295 		if( restResource != null )
296 		{
297 			restResource.removePropertyChangeListener( this );
298 			restResource.getInterface().getProject().removeProjectListener( projectListener );
299 			restResource.getInterface().removeInterfaceListener( interfaceListener );
300 			restResource.getInterface().removePropertyChangeListener( this );
301 		}
302 	}
303 
304 	@Override
305 	public void resetConfigOnMove( TestStepConfig config )
306 	{
307 		super.resetConfigOnMove( config );
308 
309 		restRequestStepConfig = ( RestRequestStepConfig )config.getConfig().changeType( RestRequestStepConfig.type );
310 		testRequest.updateConfig( restRequestStepConfig.getRestRequest() );
311 	}
312 
313 	public void propertyChange( PropertyChangeEvent evt )
314 	{
315 		if( evt.getSource() == restResource )
316 		{
317 			if( evt.getPropertyName().equals( RestResource.PATH_PROPERTY ) )
318 			{
319 				getRequestStepConfig().setResourcePath( restResource.getFullPath() );
320 			}
321 			else if( evt.getPropertyName().equals( "childMethods" ) && restMethod == evt.getOldValue() )
322 			{
323 				// TODO: Convert to HttpTestRequestStep
324 				log.debug( "Removing test step due to removed Rest method" );
325 				getTestCase().removeTestStep( RestTestRequestStep.this );
326 			}
327 		}
328 		else if( restResource != null && evt.getSource() == restResource.getInterface() )
329 		{
330 			if( evt.getPropertyName().equals( Interface.NAME_PROPERTY ) )
331 			{
332 				getRequestStepConfig().setService( ( String )evt.getNewValue() );
333 			}
334 		}
335 		else if( evt.getSource() == restMethod )
336 		{
337 			if( evt.getPropertyName().equals( RestMethod.NAME_PROPERTY ) )
338 			{
339 				getRequestStepConfig().setMethodName( ( String )evt.getNewValue() );
340 			}
341 		}
342 		if( evt.getPropertyName().equals( TestAssertion.CONFIGURATION_PROPERTY )
343 				|| evt.getPropertyName().equals( TestAssertion.DISABLED_PROPERTY ) )
344 		{
345 			if( getTestRequest().getResponse() != null )
346 			{
347 				getTestRequest().assertResponse( new WsdlTestRunContext( this ) );
348 			}
349 		}
350 		else
351 		{
352 			if( evt.getSource() == testRequest && evt.getPropertyName().equals( WsdlTestRequest.NAME_PROPERTY ) )
353 			{
354 				if( !super.getName().equals( ( String )evt.getNewValue() ) )
355 					super.setName( ( String )evt.getNewValue() );
356 			}
357 
358 			notifyPropertyChanged( evt.getPropertyName(), evt.getOldValue(), evt.getNewValue() );
359 		}
360 
361 		// TODO copy from HttpTestRequestStep super.propertyChange( evt );
362 	}
363 
364 	public class InternalProjectListener extends ProjectListenerAdapter
365 	{
366 		@Override
367 		public void interfaceRemoved( Interface iface )
368 		{
369 			if( restResource != null && restResource.getInterface().equals( iface ) )
370 			{
371 				log.debug( "Removing test step due to removed interface" );
372 				( getTestCase() ).removeTestStep( RestTestRequestStep.this );
373 			}
374 		}
375 	}
376 
377 	public class InternalInterfaceListener extends InterfaceListenerAdapter
378 	{
379 		@Override
380 		public void operationRemoved( Operation operation )
381 		{
382 			if( operation == restResource )
383 			{
384 				log.debug( "Removing test step due to removed operation" );
385 				( getTestCase() ).removeTestStep( RestTestRequestStep.this );
386 			}
387 		}
388 
389 		@Override
390 		public void operationUpdated( Operation operation )
391 		{
392 			if( operation == restResource )
393 			{
394 				// requestStepConfig.setResourcePath( operation.get );
395 			}
396 		}
397 	}
398 
399 	@Override
400 	public boolean dependsOn( AbstractWsdlModelItem<?> modelItem )
401 	{
402 		if( modelItem instanceof Interface && getTestRequest().getOperation() != null
403 				&& getTestRequest().getOperation().getInterface() == modelItem )
404 		{
405 			return true;
406 		}
407 		else if( modelItem instanceof Operation && getTestRequest().getOperation() == modelItem )
408 		{
409 			return true;
410 		}
411 
412 		return false;
413 	}
414 
415 	public void setRestMethod( RestMethod method )
416 	{
417 		if( restMethod == method )
418 			return;
419 
420 		RestMethod oldMethod = restMethod;
421 		restMethod = method;
422 		getRequestStepConfig().setService( method.getInterface().getName() );
423 		getRequestStepConfig().setResourcePath( method.getResource().getFullPath() );
424 		getRequestStepConfig().setMethodName( method.getName() );
425 
426 		if( oldMethod != null )
427 			oldMethod.removePropertyChangeListener( this );
428 
429 		restMethod.addPropertyChangeListener( this );
430 		getTestRequest().setRestMethod( restMethod );
431 	}
432 
433 	public RestTestRequest getTestRequest()
434 	{
435 		return testRequest;
436 	}
437 
438 	public Interface getInterface()
439 	{
440 		return getResource() == null ? null : getResource().getInterface();
441 	}
442 
443 	@Override
444 	public ImageIcon getIcon()
445 	{
446 		return testRequest == null ? null : testRequest.getIcon();
447 	}
448 
449 	public TestStep getTestStep()
450 	{
451 		return this;
452 	}
453 
454 	@SuppressWarnings( "unchecked" )
455 	public void resolve( ResolveContext<?> context )
456 	{
457 		super.resolve( context );
458 
459 		if( getRestMethod() == null )
460 		{
461 			if( context.hasThisModelItem( this, "Missing REST Method in Project", getRequestStepConfig().getService()
462 					+ "/" + getRequestStepConfig().getMethodName() ) )
463 				return;
464 			context.addPathToResolve( this, "Missing REST Method in Project",
465 					getRequestStepConfig().getService() + "/" + getRequestStepConfig().getMethodName() ).addResolvers(
466 					new RemoveTestStepResolver( this ), new ImportInterfaceResolver( this )
467 					{
468 						@Override
469 						protected boolean update()
470 						{
471 							RestMethod restMethod = findRestMethod();
472 							if( restMethod == null )
473 								return false;
474 
475 							setRestMethod( restMethod );
476 							initRestTestRequest();
477 							setDisabled( false );
478 							return true;
479 						}
480 
481 					}, new ChangeRestMethodResolver( this )
482 					{
483 						@Override
484 						public boolean update()
485 						{
486 							RestMethod restMethod = getSelectedRestMethod();
487 							if( restMethod == null )
488 								return false;
489 
490 							setRestMethod( restMethod );
491 							initRestTestRequest();
492 							setDisabled( false );
493 							return true;
494 						}
495 
496 						protected Interface[] getInterfaces( WsdlProject project )
497 						{
498 							List<RestService> interfaces = ModelSupport.getChildren( project, RestService.class );
499 							return interfaces.toArray( new Interface[interfaces.size()] );
500 						}
501 					} );
502 		}
503 		else
504 		{
505 			getRestMethod().resolve( context );
506 			if( context.hasThisModelItem( this, "Missing REST Method in Project", getRequestStepConfig().getService()
507 					+ "/" + getRequestStepConfig().getMethodName() ) )
508 			{
509 				PathToResolve path = context.getPath( this, "Missing REST Method in Project", getRequestStepConfig()
510 						.getService()
511 						+ "/" + getRequestStepConfig().getMethodName() );
512 				path.setSolved( true );
513 			}
514 		}
515 	}
516 	
517 	@Override
518 	public void prepare( TestCaseRunner testRunner, TestCaseRunContext testRunContext ) throws Exception
519 	{
520 		super.prepare( testRunner, testRunContext );
521 
522 		testRequest.setResponse( null, testRunContext );
523 
524 		for( TestAssertion assertion : testRequest.getAssertionList() )
525 		{
526 			assertion.prepare( testRunner, testRunContext );
527 		}
528 	}
529 
530 	/*
531 	 * @SuppressWarnings("unchecked") public void resolve(ResolveContext<?> context)
532 	 * { super.resolve(context);
533 	 * 
534 	 * if (getResource() == null) { if (context.hasThisModelItem(this,
535 	 * "Missing REST Resource in Project", getRequestStepConfig() .getService() +
536 	 * "/" + getRequestStepConfig().getResourcePath())) return;
537 	 * context.addPathToResolve( this, "Missing REST Resource in Project",
538 	 * getRequestStepConfig().getService() + "/" +
539 	 * getRequestStepConfig().getResourcePath()) .addResolvers(new
540 	 * RemoveTestStepResolver(this), new ImportInterfaceResolver(this) {
541 	 * 
542 	 * @Override protected boolean update() { RestResource restResource =
543 	 * findRestResource(); if (restResource == null) return false;
544 	 * 
545 	 * setResource(restResource); initRestTestRequest(); setDisabled(false);
546 	 * return true; }
547 	 * 
548 	 * }, new ChangeOperationResolver(this, "Resource") {
549 	 * 
550 	 * @Override public boolean update() { RestResource restResource =
551 	 * (RestResource) getSelectedOperation(); if (restResource == null) return
552 	 * false;
553 	 * 
554 	 * setResource(restResource); initRestTestRequest(); setDisabled(false);
555 	 * return true; }
556 	 * 
557 	 * protected Interface[] getInterfaces( WsdlProject project) {
558 	 * List<RestService> interfaces = ModelSupport .getChildren(project,
559 	 * RestService.class); return interfaces .toArray(new Interface[interfaces
560 	 * .size()]); } }); } else { getResource().resolve(context); if
561 	 * (context.hasThisModelItem(this, "Missing REST Resource in Project",
562 	 * getRequestStepConfig() .getService() + "/" +
563 	 * getRequestStepConfig().getResourcePath())) { PathToResolve path =
564 	 * context.getPath(this, "Missing REST Resource in Project",
565 	 * getRequestStepConfig().getService() + "/" +
566 	 * getRequestStepConfig().getResourcePath()); path.setSolved(true); } } }
567 	 */
568 
569 	public PropertyExpansion[] getPropertyExpansions()
570 	{
571 		PropertyExpansionsResult result = new PropertyExpansionsResult( this, testRequest );
572 
573 		result.extractAndAddAll( "requestContent" );
574 		result.extractAndAddAll( "endpoint" );
575 		result.extractAndAddAll( "username" );
576 		result.extractAndAddAll( "password" );
577 		result.extractAndAddAll( "domain" );
578 
579 		StringToStringMap requestHeaders = testRequest.getRequestHeaders();
580 		for( String key : requestHeaders.keySet() )
581 		{
582 			result.extractAndAddAll( new RequestHeaderHolder( requestHeaders, key ), "value" );
583 		}
584 
585 		// result.addAll( testRequest.getWssContainer().getPropertyExpansions()
586 		// );
587 
588 		return result.toArray( new PropertyExpansion[result.size()] );
589 	}
590 
591 	public class RequestHeaderHolder
592 	{
593 		private final StringToStringMap valueMap;
594 		private final String key;
595 
596 		public RequestHeaderHolder( StringToStringMap valueMap, String key )
597 		{
598 			this.valueMap = valueMap;
599 			this.key = key;
600 		}
601 
602 		public String getValue()
603 		{
604 			return valueMap.get( key );
605 		}
606 
607 		public void setValue( String value )
608 		{
609 			valueMap.put( key, value );
610 			testRequest.setRequestHeaders( valueMap );
611 		}
612 	}
613 
614 	public AbstractHttpRequest<?> getHttpRequest()
615 	{
616 		return testRequest;
617 	}
618 
619 	public TestAssertion addAssertion( String type )
620 	{
621 		WsdlMessageAssertion result = testRequest.addAssertion( type );
622 		return result;
623 	}
624 
625 	public void addAssertionsListener( AssertionsListener listener )
626 	{
627 		testRequest.addAssertionsListener( listener );
628 	}
629 
630 	public TestAssertion cloneAssertion( TestAssertion source, String name )
631 	{
632 		return testRequest.cloneAssertion( source, name );
633 	}
634 
635 	public String getAssertableContent()
636 	{
637 		return testRequest.getAssertableContent();
638 	}
639 
640 	public AssertableType getAssertableType()
641 	{
642 		return testRequest.getAssertableType();
643 	}
644 
645 	public TestAssertion getAssertionByName( String name )
646 	{
647 		return testRequest.getAssertionByName( name );
648 	}
649 
650 	public List<TestAssertion> getAssertionList()
651 	{
652 		return testRequest.getAssertionList();
653 	}
654 
655 	public AssertionStatus getAssertionStatus()
656 	{
657 		return testRequest.getAssertionStatus();
658 	}
659 
660 	public void removeAssertion( TestAssertion assertion )
661 	{
662 		testRequest.removeAssertion( assertion );
663 	}
664 
665 	public void removeAssertionsListener( AssertionsListener listener )
666 	{
667 		testRequest.removeAssertionsListener( listener );
668 	}
669 
670 	public TestAssertion moveAssertion( int ix, int offset )
671 	{
672 		return testRequest.moveAssertion( ix, offset );
673 	}
674 
675 	public Map<String, TestAssertion> getAssertions()
676 	{
677 		return testRequest.getAssertions();
678 	}
679 
680 	public WsdlMessageAssertion getAssertionAt( int index )
681 	{
682 		return testRequest.getAssertionAt( index );
683 	}
684 
685 	public int getAssertionCount()
686 	{
687 		return testRequest == null ? 0 : testRequest.getAssertionCount();
688 	}
689 
690 	public String getDefaultAssertableContent()
691 	{
692 		return testRequest.getDefaultAssertableContent();
693 	}
694 
695 	public TestStepResult run( TestCaseRunner runner, TestCaseRunContext runContext )
696 	{
697 		RestRequestStepResult testStepResult = new RestRequestStepResult( this );
698 
699 		try
700 		{
701 			submit = testRequest.submit( runContext, false );
702 			HttpResponse response = ( HttpResponse )submit.getResponse();
703 
704 			if( submit.getStatus() != Submit.Status.CANCELED )
705 			{
706 				if( submit.getStatus() == Submit.Status.ERROR )
707 				{
708 					testStepResult.setStatus( TestStepStatus.FAILED );
709 					testStepResult.addMessage( submit.getError().toString() );
710 
711 					testRequest.setResponse( null, runContext );
712 				}
713 				else if( response == null )
714 				{
715 					testStepResult.setStatus( TestStepStatus.FAILED );
716 					testStepResult.addMessage( "Request is missing response" );
717 
718 					testRequest.setResponse( null, runContext );
719 				}
720 				else
721 				{
722 					runContext.setProperty( AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult );
723 					testRequest.setResponse( response, runContext );
724 
725 					testStepResult.setTimeTaken( response.getTimeTaken() );
726 					testStepResult.setSize( response.getContentLength() );
727 					testStepResult.setResponse( response );
728 
729 					switch( testRequest.getAssertionStatus() )
730 					{
731 					case FAILED :
732 						testStepResult.setStatus( TestStepStatus.FAILED );
733 						break;
734 					case VALID :
735 						testStepResult.setStatus( TestStepStatus.OK );
736 						break;
737 					case UNKNOWN :
738 						testStepResult.setStatus( TestStepStatus.UNKNOWN );
739 						break;
740 					}
741 				}
742 			}
743 			else
744 			{
745 				testStepResult.setStatus( TestStepStatus.CANCELED );
746 				testStepResult.addMessage( "Request was canceled" );
747 			}
748 
749 			if( response != null )
750 			{
751 				testStepResult.setRequestContent( response.getRequestContent() );
752 				testStepResult.addProperty( "URL", response.getURL() == null ? "<missing>" : response.getURL().toString() );
753 				testStepResult.addProperty( "Method", String.valueOf( response.getMethod() ) );
754 				testStepResult.addProperty( "StatusCode", String.valueOf( response.getStatusCode() ) );
755 				testStepResult.addProperty( "HTTP Version", response.getHttpVersion() );
756 			}
757 			else
758 				testStepResult.setRequestContent( testRequest.getRequestContent() );
759 		}
760 		catch( SubmitException e )
761 		{
762 			testStepResult.setStatus( TestStepStatus.FAILED );
763 			testStepResult.addMessage( "SubmitException: " + e );
764 		}
765 		finally
766 		{
767 			submit = null;
768 		}
769 
770 		testStepResult.setDomain( PropertyExpander.expandProperties( runContext, testRequest.getDomain() ) );
771 		testStepResult.setUsername( PropertyExpander.expandProperties( runContext, testRequest.getUsername() ) );
772 		testStepResult.setEndpoint( PropertyExpander.expandProperties( runContext, testRequest.getEndpoint() ) );
773 		testStepResult.setPassword( PropertyExpander.expandProperties( runContext, testRequest.getPassword() ) );
774 		testStepResult.setEncoding( PropertyExpander.expandProperties( runContext, testRequest.getEncoding() ) );
775 
776 		if( testStepResult.getStatus() != TestStepStatus.CANCELED )
777 		{
778 			AssertionStatus assertionStatus = testRequest.getAssertionStatus();
779 			switch( assertionStatus )
780 			{
781 			case FAILED :
782 			{
783 				testStepResult.setStatus( TestStepStatus.FAILED );
784 				if( getAssertionCount() == 0 )
785 				{
786 					testStepResult.addMessage( "Invalid/empty response" );
787 				}
788 				else
789 					for( int c = 0; c < getAssertionCount(); c++ )
790 					{
791 						WsdlMessageAssertion assertion = getAssertionAt( c );
792 						AssertionError[] errors = assertion.getErrors();
793 						if( errors != null )
794 						{
795 							for( AssertionError error : errors )
796 							{
797 								testStepResult.addMessage( "[" + assertion.getName() + "] " +  error.getMessage() );
798 							}
799 						}
800 					}
801 
802 				break;
803 			}
804 			}
805 		}
806 
807 		return testStepResult;
808 	}
809 
810 	private class InternalTestPropertyListener extends TestPropertyListenerAdapter
811 	{
812 		@Override
813 		public void propertyAdded( String name )
814 		{
815 			RestTestRequestStep.this.addProperty( new RestTestStepProperty( getTestRequest().getProperty( name ) ), true );
816 		}
817 
818 		@Override
819 		public void propertyRemoved( String name )
820 		{
821 			RestTestRequestStep.this.deleteProperty( name, true );
822 		}
823 
824 		@Override
825 		public void propertyRenamed( String oldName, String newName )
826 		{
827 			RestTestRequestStep.this.propertyRenamed( oldName );
828 		}
829 
830 		@Override
831 		public void propertyValueChanged( String name, String oldValue, String newValue )
832 		{
833 			RestTestRequestStep.this.firePropertyValueChanged( name, oldValue, newValue );
834 		}
835 
836 		@Override
837 		public void propertyMoved( String name, int oldIndex, int newIndex )
838 		{
839 			RestTestRequestStep.this.firePropertyMoved( name, oldIndex, newIndex );
840 		}
841 	}
842 
843 	private class RestTestStepProperty implements TestStepProperty
844 	{
845 		private RestParamProperty property;
846 
847 		public RestTestStepProperty( RestParamProperty property )
848 		{
849 			this.property = property;
850 		}
851 
852 		public TestStep getTestStep()
853 		{
854 			return RestTestRequestStep.this;
855 		}
856 
857 		public String getName()
858 		{
859 			return property.getName();
860 		}
861 
862 		public String getDescription()
863 		{
864 			return property.getDescription();
865 		}
866 
867 		public String getValue()
868 		{
869 			return property.getValue();
870 		}
871 
872 		public String getDefaultValue()
873 		{
874 			return property.getDefaultValue();
875 		}
876 
877 		public void setValue( String value )
878 		{
879 			property.setValue( value );
880 		}
881 
882 		public boolean isReadOnly()
883 		{
884 			return false;
885 		}
886 
887 		public QName getType()
888 		{
889 			return property.getType();
890 		}
891 
892 		public ModelItem getModelItem()
893 		{
894 			return getTestRequest();
895 		}
896 	}
897 }