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.Collections;
17  import java.util.List;
18  import java.util.Map;
19  
20  import javax.swing.ImageIcon;
21  import javax.xml.namespace.QName;
22  
23  import org.apache.log4j.Logger;
24  
25  import com.eviware.soapui.config.HttpRequestConfig;
26  import com.eviware.soapui.config.RequestStepConfig;
27  import com.eviware.soapui.config.TestStepConfig;
28  import com.eviware.soapui.impl.rest.support.RestParamProperty;
29  import com.eviware.soapui.impl.rest.support.RestRequestConverter;
30  import com.eviware.soapui.impl.support.AbstractHttpRequest;
31  import com.eviware.soapui.impl.support.http.HttpRequest;
32  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
33  import com.eviware.soapui.impl.wsdl.WsdlSubmit;
34  import com.eviware.soapui.impl.wsdl.submit.transports.http.HttpResponse;
35  import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
36  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
37  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
38  import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry.AssertableType;
39  import com.eviware.soapui.model.ModelItem;
40  import com.eviware.soapui.model.iface.Interface;
41  import com.eviware.soapui.model.iface.Submit;
42  import com.eviware.soapui.model.iface.Request.SubmitException;
43  import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
44  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
45  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult;
46  import com.eviware.soapui.model.support.TestPropertyListenerAdapter;
47  import com.eviware.soapui.model.support.TestStepBeanProperty;
48  import com.eviware.soapui.model.testsuite.AssertionError;
49  import com.eviware.soapui.model.testsuite.AssertionsListener;
50  import com.eviware.soapui.model.testsuite.TestAssertion;
51  import com.eviware.soapui.model.testsuite.TestCaseRunContext;
52  import com.eviware.soapui.model.testsuite.TestCaseRunner;
53  import com.eviware.soapui.model.testsuite.TestProperty;
54  import com.eviware.soapui.model.testsuite.TestStep;
55  import com.eviware.soapui.model.testsuite.TestStepProperty;
56  import com.eviware.soapui.model.testsuite.TestStepResult;
57  import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
58  import com.eviware.soapui.support.resolver.ResolveContext;
59  import com.eviware.soapui.support.types.StringToStringMap;
60  
61  public class HttpTestRequestStep extends WsdlTestStepWithProperties implements HttpTestRequestStepInterface
62  {
63  	@SuppressWarnings("unused")
64  	private final static Logger log = Logger.getLogger( HttpTestRequestStep.class );
65  	private HttpRequestConfig httpRequestConfig;
66  	private HttpTestRequest testRequest;
67  	private WsdlSubmit<HttpRequest> submit;
68  
69  	public HttpTestRequestStep( WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest )
70  	{
71  		super( testCase, config, true, forLoadTest );
72  
73  		if( getConfig().getConfig() != null )
74  		{
75  			// httpRequestConfig = (HttpRequestConfig)
76  			// getConfig().getConfig().changeType( HttpRequestConfig.type );
77  			httpRequestConfig = RestRequestConverter.updateIfNeeded( getConfig().getConfig() );
78  			if( httpRequestConfig != getConfig().getConfig() )
79  				getConfig().setConfig( httpRequestConfig );
80  			testRequest = buildTestRequest( forLoadTest );
81  			// testRequest = new RestTestRequest( null,
82  			// requestStepConfig.getRestRequest(), this, forLoadTest );
83  			testRequest.addPropertyChangeListener( this );
84  			testRequest.addTestPropertyListener( new InternalTestPropertyListener() );
85  
86  			if( config.isSetName() )
87  				testRequest.setName( config.getName() );
88  			else
89  				config.setName( testRequest.getName() );
90  
91  			// testRequest.setEndpoint( testRequest.getEndpoint() );
92  		}
93  		else
94  		{
95  			httpRequestConfig = ( HttpRequestConfig )getConfig().addNewConfig().changeType( HttpRequestConfig.type );
96  		}
97  
98  		for( TestProperty property : testRequest.getProperties().values() )
99  		{
100 			addProperty( new RestTestStepProperty( ( RestParamProperty )property ) );
101 		}
102 
103 		// init default properties
104 		addProperty( new TestStepBeanProperty( "Endpoint", false, testRequest, "endpoint", this ) );
105 		addProperty( new TestStepBeanProperty( "Username", false, testRequest, "username", this ) );
106 		addProperty( new TestStepBeanProperty( "Password", false, testRequest, "password", this ) );
107 		addProperty( new TestStepBeanProperty( "Domain", false, testRequest, "domain", this ) );
108 		
109 
110 		// init properties
111 		addProperty( new TestStepBeanProperty( "Request", false, testRequest, "requestContent", this )
112 		{
113 			@Override
114 			public String getDefaultValue()
115 			{
116 				return createDefaultRequestContent();
117 			}
118 		} );
119 
120 		addProperty( new TestStepBeanProperty( "ResponseAsXml", true, testRequest, "responseContentAsXml", this )
121 		{
122 			@Override
123 			public String getDefaultValue()
124 			{
125 				return createDefaultResponseXmlContent();
126 			}
127 		} );
128 
129 		addProperty( new TestStepBeanProperty( "Response", true, testRequest, "responseContentAsString", this )
130 		{
131 			@Override
132 			public String getDefaultValue()
133 			{
134 				return createDefaultRawResponseContent();
135 			}
136 		} );
137 	}
138 
139 	protected HttpTestRequest buildTestRequest( boolean forLoadTest )
140 	{
141 		return new HttpTestRequest( httpRequestConfig, this, forLoadTest );
142 	}
143 
144 	protected String createDefaultRawResponseContent()
145 	{
146 		return "";
147 	}
148 
149 	protected String createDefaultResponseXmlContent()
150 	{
151 		return "";
152 	}
153 
154 	protected String createDefaultRequestContent()
155 	{
156 		return "";
157 	}
158 
159 	public HttpRequestConfig getRequestStepConfig()
160 	{
161 		return httpRequestConfig;
162 	}
163 
164 	@Override
165 	public WsdlTestStep clone( WsdlTestCase targetTestCase, String name )
166 	{
167 		beforeSave();
168 
169 		TestStepConfig config = ( TestStepConfig )getConfig().copy();
170 		RequestStepConfig stepConfig = ( RequestStepConfig )config.getConfig().changeType( RequestStepConfig.type );
171 
172 		while( stepConfig.getRequest().sizeOfAttachmentArray() > 0 )
173 			stepConfig.getRequest().removeAttachment( 0 );
174 
175 		config.setName( name );
176 		stepConfig.getRequest().setName( name );
177 
178 		WsdlTestRequestStep result = ( WsdlTestRequestStep )targetTestCase.addTestStep( config );
179 		testRequest.copyAttachmentsTo( result.getTestRequest() );
180 
181 		return result;
182 	}
183 
184 	@Override
185 	public void release()
186 	{
187 		super.release();
188 
189 		// could be null if initialization failed..
190 		if( testRequest != null )
191 		{
192 			testRequest.removePropertyChangeListener( this );
193 			testRequest.release();
194 		}
195 	}
196 
197 	@Override
198 	public void resetConfigOnMove( TestStepConfig config )
199 	{
200 		super.resetConfigOnMove( config );
201 
202 		httpRequestConfig = ( HttpRequestConfig )config.getConfig().changeType( HttpRequestConfig.type );
203 		testRequest.updateConfig( httpRequestConfig );
204 	}
205 
206 	@Override
207 	public ImageIcon getIcon()
208 	{
209 		return testRequest == null ? null : testRequest.getIcon();
210 	}
211 
212 	public HttpTestRequest getTestRequest()
213 	{
214 		return testRequest;
215 	}
216 
217 	@Override
218 	public void setName( String name )
219 	{
220 		super.setName( name );
221 		testRequest.setName( name );
222 	}
223 
224 	public void propertyChange( PropertyChangeEvent evt )
225 	{
226 		if( evt.getPropertyName().equals( TestAssertion.CONFIGURATION_PROPERTY )
227 				|| evt.getPropertyName().equals( TestAssertion.DISABLED_PROPERTY ) )
228 		{
229 			if( getTestRequest().getResponse() != null )
230 			{
231 				getTestRequest().assertResponse( new WsdlTestRunContext( this ) );
232 			}
233 		}
234 		else
235 		{
236 			if( evt.getSource() == testRequest && evt.getPropertyName().equals( WsdlTestRequest.NAME_PROPERTY ) )
237 			{
238 				if( !super.getName().equals( ( String )evt.getNewValue() ) )
239 					super.setName( ( String )evt.getNewValue() );
240 			}
241 
242 			notifyPropertyChanged( evt.getPropertyName(), evt.getOldValue(), evt.getNewValue() );
243 		}
244 	}
245 
246 	public TestStepResult run( TestCaseRunner runner, TestCaseRunContext runContext )
247 	{
248 		RestRequestStepResult testStepResult = new RestRequestStepResult( this );
249 
250 		try
251 		{
252 			submit = testRequest.submit( runContext, false );
253 			HttpResponse response = ( HttpResponse )submit.getResponse();
254 
255 			if( submit.getStatus() != Submit.Status.CANCELED )
256 			{
257 				if( submit.getStatus() == Submit.Status.ERROR )
258 				{
259 					testStepResult.setStatus( TestStepStatus.FAILED );
260 					testStepResult.addMessage( submit.getError().toString() );
261 
262 					testRequest.setResponse( null, runContext );
263 				}
264 				else if( response == null )
265 				{
266 					testStepResult.setStatus( TestStepStatus.FAILED );
267 					testStepResult.addMessage( "Request is missing response" );
268 
269 					testRequest.setResponse( null, runContext );
270 				}
271 				else
272 				{
273 					runContext.setProperty( AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult );
274 					testRequest.setResponse( response, runContext );
275 
276 					testStepResult.setTimeTaken( response.getTimeTaken() );
277 					testStepResult.setSize( response.getContentLength() );
278 					testStepResult.setResponse( response );
279 
280 					switch( testRequest.getAssertionStatus() )
281 					{
282 					case FAILED :
283 						testStepResult.setStatus( TestStepStatus.FAILED );
284 						break;
285 					case VALID :
286 						testStepResult.setStatus( TestStepStatus.OK );
287 						break;
288 					case UNKNOWN :
289 						testStepResult.setStatus( TestStepStatus.UNKNOWN );
290 						break;
291 					}
292 				}
293 			}
294 			else
295 			{
296 				testStepResult.setStatus( TestStepStatus.CANCELED );
297 				testStepResult.addMessage( "Request was canceled" );
298 			}
299 
300 			if( response != null )
301 			{
302 				testStepResult.setRequestContent( response.getRequestContent() );
303 				testStepResult.addProperty( "URL", response.getURL() == null ? "<missing>" : response.getURL().toString() );
304 				testStepResult.addProperty( "Method", String.valueOf( response.getMethod() ) );
305 				testStepResult.addProperty( "StatusCode", String.valueOf( response.getStatusCode() ) );
306 				testStepResult.addProperty( "HTTP Version", response.getHttpVersion() );
307 			}
308 			else
309 			{
310 				testStepResult.addMessage( "Missing Response" );
311 				testStepResult.setRequestContent( testRequest.getRequestContent() );
312 		}
313 		}
314 		catch( SubmitException e )
315 		{
316 			testStepResult.setStatus( TestStepStatus.FAILED );
317 			testStepResult.addMessage( "SubmitException: " + e );
318 		}
319 		finally
320 		{
321 			submit = null;
322 		}
323 
324 		testStepResult.setDomain( PropertyExpander.expandProperties( runContext, testRequest.getDomain() ) );
325 		testStepResult.setUsername( PropertyExpander.expandProperties( runContext, testRequest.getUsername() ) );
326 		testStepResult.setEndpoint( PropertyExpander.expandProperties( runContext, testRequest.getEndpoint() ) );
327 		testStepResult.setPassword( PropertyExpander.expandProperties( runContext, testRequest.getPassword() ) );
328 		testStepResult.setEncoding( PropertyExpander.expandProperties( runContext, testRequest.getEncoding() ) );
329 
330 		if( testStepResult.getStatus() != TestStepStatus.CANCELED )
331 		{
332 			AssertionStatus assertionStatus = testRequest.getAssertionStatus();
333 			switch( assertionStatus )
334 			{
335 			case FAILED :
336 			{
337 				testStepResult.setStatus( TestStepStatus.FAILED );
338 				if( getAssertionCount() == 0 )
339 				{
340 					testStepResult.addMessage( "Invalid/empty response" );
341 				}
342 				else
343 					for( int c = 0; c < getAssertionCount(); c++ )
344 					{
345 						WsdlMessageAssertion assertion = getAssertionAt( c );
346 						AssertionError[] errors = assertion.getErrors();
347 						if( errors != null )
348 						{
349 							for( AssertionError error : errors )
350 							{
351 								testStepResult.addMessage( "[" + assertion.getName() + "] " + error.getMessage() );
352 							}
353 						}
354 					}
355 
356 				break;
357 			}
358 			}
359 		}
360 
361 		return testStepResult;
362 	}
363 
364 	public WsdlMessageAssertion getAssertionAt( int index )
365 	{
366 		return testRequest.getAssertionAt( index );
367 	}
368 
369 	public int getAssertionCount()
370 	{
371 		return testRequest == null ? 0 : testRequest.getAssertionCount();
372 	}
373 
374 	@Override
375 	public boolean cancel()
376 	{
377 		if( submit == null )
378 			return false;
379 
380 		submit.cancel();
381 
382 		return true;
383 	}
384 
385 	@Override
386 	public boolean dependsOn( AbstractWsdlModelItem<?> modelItem )
387 	{
388 		return false;
389 	}
390 
391 	@Override
392 	public void beforeSave()
393 	{
394 		super.beforeSave();
395 
396 		if( testRequest != null )
397 			testRequest.beforeSave();
398 	}
399 
400 	@Override
401 	public String getDescription()
402 	{
403 		return testRequest == null ? "<missing>" : testRequest.getDescription();
404 	}
405 
406 	@Override
407 	public void setDescription( String description )
408 	{
409 		if( testRequest != null )
410 			testRequest.setDescription( description );
411 	}
412 
413 	@SuppressWarnings("unchecked")
414 	@Override
415 	public List<? extends ModelItem> getChildren()
416 	{
417 		return testRequest == null ? Collections.EMPTY_LIST : testRequest.getAssertionList();
418 	}
419 
420 	public PropertyExpansion[] getPropertyExpansions()
421 	{
422 		if( testRequest == null )
423 			return new PropertyExpansion[0];
424 
425 		PropertyExpansionsResult result = new PropertyExpansionsResult( this, testRequest );
426 
427 		result.extractAndAddAll( "requestContent" );
428 		result.extractAndAddAll( "endpoint" );
429 		result.extractAndAddAll( "username" );
430 		result.extractAndAddAll( "password" );
431 		result.extractAndAddAll( "domain" );
432 
433 		StringToStringMap requestHeaders = testRequest.getRequestHeaders();
434 		for( String key : requestHeaders.keySet() )
435 		{
436 			result.extractAndAddAll( new RequestHeaderHolder( requestHeaders, key ), "value" );
437 		}
438 
439 		for( String key : testRequest.getParams().getPropertyNames() )
440 		{
441 			result.extractAndAddAll( new RequestParamHolder( key ), "value" );
442 		}
443 
444 		return result.toArray( new PropertyExpansion[result.size()] );
445 	}
446 
447 	public AbstractHttpRequest<?> getHttpRequest()
448 	{
449 		return testRequest;
450 	}
451 
452 	public class RequestHeaderHolder
453 	{
454 		private final StringToStringMap valueMap;
455 		private final String key;
456 
457 		public RequestHeaderHolder( StringToStringMap valueMap, String key )
458 		{
459 			this.valueMap = valueMap;
460 			this.key = key;
461 		}
462 
463 		public String getValue()
464 		{
465 			return valueMap.get( key );
466 		}
467 
468 		public void setValue( String value )
469 		{
470 			valueMap.put( key, value );
471 			testRequest.setRequestHeaders( valueMap );
472 		}
473 	}
474 
475 	public class RequestParamHolder
476 	{
477 		private final String name;
478 
479 		public RequestParamHolder( String name )
480 		{
481 			this.name = name;
482 		}
483 
484 		public String getValue()
485 		{
486 			return testRequest.getParams().getPropertyValue( name );
487 		}
488 
489 		public void setValue( String value )
490 		{
491 			testRequest.setPropertyValue( name, value );
492 		}
493 	}
494 
495 	public TestAssertion addAssertion( String type )
496 	{
497 		WsdlMessageAssertion result = testRequest.addAssertion( type );
498 		return result;
499 	}
500 
501 	public void addAssertionsListener( AssertionsListener listener )
502 	{
503 		testRequest.addAssertionsListener( listener );
504 	}
505 
506 	public TestAssertion cloneAssertion( TestAssertion source, String name )
507 	{
508 		return testRequest.cloneAssertion( source, name );
509 	}
510 
511 	public String getAssertableContent()
512 	{
513 		return testRequest.getAssertableContent();
514 	}
515 
516 	public AssertableType getAssertableType()
517 	{
518 		return testRequest.getAssertableType();
519 	}
520 
521 	public TestAssertion getAssertionByName( String name )
522 	{
523 		return testRequest.getAssertionByName( name );
524 	}
525 
526 	public List<TestAssertion> getAssertionList()
527 	{
528 		return testRequest.getAssertionList();
529 	}
530 
531 	public AssertionStatus getAssertionStatus()
532 	{
533 		return testRequest.getAssertionStatus();
534 	}
535 
536 	public Interface getInterface()
537 	{
538 		return null;
539 	}
540 
541 	public TestStep getTestStep()
542 	{
543 		return this;
544 	}
545 
546 	public void removeAssertion( TestAssertion assertion )
547 	{
548 		testRequest.removeAssertion( assertion );
549 	}
550 
551 	public void removeAssertionsListener( AssertionsListener listener )
552 	{
553 		testRequest.removeAssertionsListener( listener );
554 	}
555 
556 	public TestAssertion moveAssertion( int ix, int offset )
557 	{
558 		return testRequest.moveAssertion( ix, offset );
559 	}
560 
561 	public Map<String, TestAssertion> getAssertions()
562 	{
563 		return testRequest.getAssertions();
564 	}
565 
566 	@Override
567 	public void prepare( TestCaseRunner testRunner, TestCaseRunContext testRunContext ) throws Exception
568 	{
569 		super.prepare( testRunner, testRunContext );
570 
571 		testRequest.setResponse( null, testRunContext );
572 		
573 		for( TestAssertion assertion : testRequest.getAssertionList() )
574 		{
575 			assertion.prepare( testRunner, testRunContext );
576 		}
577 	}
578 
579 	public String getDefaultSourcePropertyName()
580 	{
581 		return "ResponseAsXml";
582 	}
583 
584 	public String getDefaultTargetPropertyName()
585 	{
586 		return "Request";
587 	}
588 
589 	public String getDefaultAssertableContent()
590 	{
591 		return testRequest.getDefaultAssertableContent();
592 	}
593 
594 	public void resolve( ResolveContext<?> context )
595 	{
596 		super.resolve( context );
597 
598 		testRequest.resolve( context );
599 	}
600 
601 	private class InternalTestPropertyListener extends TestPropertyListenerAdapter
602 	{
603 		@Override
604 		public void propertyAdded( String name )
605 		{
606 			HttpTestRequestStep.this.addProperty( new RestTestStepProperty( getTestRequest().getProperty( name ) ), true );
607 		}
608 
609 		@Override
610 		public void propertyRemoved( String name )
611 		{
612 			HttpTestRequestStep.this.deleteProperty( name, true );
613 		}
614 
615 		@Override
616 		public void propertyRenamed( String oldName, String newName )
617 		{
618 			HttpTestRequestStep.this.propertyRenamed( oldName );
619 		}
620 
621 		@Override
622 		public void propertyValueChanged( String name, String oldValue, String newValue )
623 		{
624 			HttpTestRequestStep.this.firePropertyValueChanged( name, oldValue, newValue );
625 		}
626 
627 		@Override
628 		public void propertyMoved( String name, int oldIndex, int newIndex )
629 		{
630 			HttpTestRequestStep.this.firePropertyMoved( name, oldIndex, newIndex );
631 		}
632 	}
633 
634 	private class RestTestStepProperty implements TestStepProperty
635 	{
636 		private RestParamProperty property;
637 
638 		public RestTestStepProperty( RestParamProperty property )
639 		{
640 			this.property = property;
641 		}
642 
643 		public TestStep getTestStep()
644 		{
645 			return HttpTestRequestStep.this;
646 		}
647 
648 		public String getName()
649 		{
650 			return property.getName();
651 		}
652 
653 		public String getDescription()
654 		{
655 			return property.getDescription();
656 		}
657 
658 		public String getValue()
659 		{
660 			return property.getValue();
661 		}
662 
663 		public String getDefaultValue()
664 		{
665 			return property.getDefaultValue();
666 		}
667 
668 		public void setValue( String value )
669 		{
670 			property.setValue( value );
671 		}
672 
673 		public boolean isReadOnly()
674 		{
675 			return false;
676 		}
677 
678 		public QName getType()
679 		{
680 			return property.getType();
681 		}
682 
683 		public ModelItem getModelItem()
684 		{
685 			return getTestRequest();
686 		}
687 	}
688 
689 }