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