View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 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 com.eviware.soapui.config.RequestStepConfig;
16  import com.eviware.soapui.config.TestStepConfig;
17  import com.eviware.soapui.impl.support.AbstractHttpRequest;
18  import com.eviware.soapui.impl.support.http.HttpRequestTestStep;
19  import com.eviware.soapui.impl.wsdl.*;
20  import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse;
21  import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
22  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
23  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
24  import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry.AssertableType;
25  import com.eviware.soapui.model.ModelItem;
26  import com.eviware.soapui.model.iface.Interface;
27  import com.eviware.soapui.model.iface.Operation;
28  import com.eviware.soapui.model.iface.Request.SubmitException;
29  import com.eviware.soapui.model.iface.Submit;
30  import com.eviware.soapui.model.project.Project;
31  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
32  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContainer;
33  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
34  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult;
35  import com.eviware.soapui.model.support.InterfaceListenerAdapter;
36  import com.eviware.soapui.model.support.ProjectListenerAdapter;
37  import com.eviware.soapui.model.support.TestStepBeanProperty;
38  import com.eviware.soapui.model.testsuite.*;
39  import com.eviware.soapui.model.testsuite.AssertionError;
40  import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
41  import com.eviware.soapui.support.resolver.ChangeOperationResolver;
42  import com.eviware.soapui.support.resolver.ImportInterfaceResolver;
43  import com.eviware.soapui.support.resolver.RemoveTestStepResolver;
44  import com.eviware.soapui.support.resolver.ResolveContext;
45  import com.eviware.soapui.support.resolver.ResolveContext.PathToResolve;
46  import com.eviware.soapui.support.types.StringToStringMap;
47  import org.apache.log4j.Logger;
48  
49  import javax.swing.*;
50  import java.beans.PropertyChangeEvent;
51  import java.beans.PropertyChangeListener;
52  import java.util.*;
53  
54  /***
55   * WsdlTestStep that executes a WsdlTestRequest
56   *
57   * @author Ole.Matzura
58   */
59  
60  public class WsdlTestRequestStep extends WsdlTestStepWithProperties implements OperationTestStep,
61          PropertyChangeListener, PropertyExpansionContainer, Assertable, HttpRequestTestStep
62  {
63     private final static Logger log = Logger.getLogger( WsdlTestRequestStep.class );
64     private RequestStepConfig requestStepConfig;
65     private WsdlTestRequest testRequest;
66     private WsdlOperation wsdlOperation;
67     private final InternalProjectListener projectListener = new InternalProjectListener();
68     private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
69     private WsdlSubmit<WsdlRequest> submit;
70  
71     public WsdlTestRequestStep( WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest )
72     {
73        super( testCase, config, true, forLoadTest );
74  
75        if( getConfig().getConfig() != null )
76        {
77           requestStepConfig = (RequestStepConfig) getConfig().getConfig().changeType( RequestStepConfig.type );
78  
79           wsdlOperation = findWsdlOperation();
80           if( wsdlOperation == null )
81           {
82              log.error( "Could not find operation [" + requestStepConfig.getOperation() + "] in interface ["
83                      + requestStepConfig.getInterface() + "] for test request [" + getName() + "] in TestCase ["
84                      + getTestCase().getTestSuite().getName() + "/" + getTestCase().getName() + "]" );
85              // requestStepConfig.setRequest(null);
86              setDisabled( true );
87           }
88           else
89           {
90              initTestRequest( config, forLoadTest );
91           }
92        }
93        else
94        {
95           requestStepConfig = (RequestStepConfig) getConfig().addNewConfig().changeType( RequestStepConfig.type );
96        }
97  
98        // init properties
99        if( testRequest != null )
100       {
101          initRequestProperties();
102       }
103    }
104 
105    private void initRequestProperties()
106    {
107       addProperty( new TestStepBeanProperty( "Endpoint", false, testRequest, "endpoint", this ) );
108       addProperty( new TestStepBeanProperty( "Username", false, testRequest, "username", this ) );
109       addProperty( new TestStepBeanProperty( "Password", false, testRequest, "password", this ) );
110       addProperty( new TestStepBeanProperty( "Domain", false, testRequest, "domain", this ) );
111       addProperty( new TestStepBeanProperty( "Request", false, testRequest, "requestContent", this )
112       {
113          @Override
114          public String getDefaultValue()
115          {
116             return getOperation().createRequest( true );
117          }
118       } );
119       addProperty( new TestStepBeanProperty( "Response", true, testRequest, "responseContent", this )
120       {
121          @Override
122          public String getDefaultValue()
123          {
124             return getOperation().createResponse( true );
125          }
126       } );
127    }
128 
129    private void initTestRequest( TestStepConfig config, boolean forLoadTest )
130    {
131       if( !forLoadTest )
132       {
133          wsdlOperation.getInterface().getProject().addProjectListener( projectListener );
134          wsdlOperation.getInterface().addInterfaceListener( interfaceListener );
135 
136          // we need to listen for name changes which happen when
137          // interfaces are updated..
138          wsdlOperation.getInterface().addPropertyChangeListener( this );
139          wsdlOperation.addPropertyChangeListener( this );
140       }
141 
142       testRequest = new WsdlTestRequest( wsdlOperation, requestStepConfig.getRequest(), this, forLoadTest );
143       testRequest.addPropertyChangeListener( this );
144 
145       if( config.isSetName() )
146          testRequest.setName( config.getName() );
147       else
148          config.setName( testRequest.getName() );
149    }
150 
151    @Override
152    public WsdlTestStep clone( WsdlTestCase targetTestCase, String name )
153    {
154       beforeSave();
155 
156       TestStepConfig config = (TestStepConfig) getConfig().copy();
157       RequestStepConfig stepConfig = (RequestStepConfig) config.getConfig().changeType( RequestStepConfig.type );
158 
159       while( stepConfig.getRequest().sizeOfAttachmentArray() > 0 )
160          stepConfig.getRequest().removeAttachment( 0 );
161 
162       config.setName( name );
163       stepConfig.getRequest().setName( name );
164 
165       WsdlTestRequestStep result = (WsdlTestRequestStep) targetTestCase.addTestStep( config );
166       testRequest.copyAttachmentsTo( result.getTestRequest() );
167 
168       return result;
169    }
170 
171    private WsdlOperation findWsdlOperation()
172    {
173       WsdlTestCase testCase = getTestCase();
174       if( testCase == null || testCase.getTestSuite() == null )
175          return null;
176 
177       Project project = testCase.getTestSuite().getProject();
178       WsdlOperation operation = null;
179       for( int c = 0; c < project.getInterfaceCount(); c++ )
180       {
181          if( project.getInterfaceAt( c ).getName().equals( requestStepConfig.getInterface() ) )
182          {
183             WsdlInterface iface = (WsdlInterface) project.getInterfaceAt( c );
184             for( int i = 0; i < iface.getOperationCount(); i++ )
185             {
186                if( iface.getOperationAt( i ).getName().equals( requestStepConfig.getOperation() ) )
187                {
188                   operation = iface.getOperationAt( i );
189                   break;
190                }
191             }
192 
193             if( operation != null )
194                break;
195          }
196       }
197       return operation;
198    }
199 
200    public String getInterfaceName()
201    {
202       return requestStepConfig.getInterface();
203    }
204 
205    public String getOperationName()
206    {
207       return requestStepConfig.getOperation();
208    }
209 
210    @Override
211    public void release()
212    {
213       super.release();
214 
215       if( wsdlOperation == null )
216          wsdlOperation = findWsdlOperation();
217 
218       if( wsdlOperation != null )
219       {
220          wsdlOperation.removePropertyChangeListener( this );
221          wsdlOperation.getInterface().getProject().removeProjectListener( projectListener );
222          wsdlOperation.getInterface().removeInterfaceListener( interfaceListener );
223          wsdlOperation.getInterface().removePropertyChangeListener( this );
224       }
225 
226       // could be null if initialization failed..
227       if( testRequest != null )
228       {
229          testRequest.removePropertyChangeListener( this );
230          testRequest.release();
231       }
232    }
233 
234    @Override
235    public void resetConfigOnMove( TestStepConfig config )
236    {
237       super.resetConfigOnMove( config );
238 
239       requestStepConfig = (RequestStepConfig) config.getConfig().changeType( RequestStepConfig.type );
240       testRequest.updateConfig( requestStepConfig.getRequest() );
241    }
242 
243    @Override
244    public ImageIcon getIcon()
245    {
246       return testRequest == null ? null : testRequest.getIcon();
247    }
248 
249    public WsdlTestRequest getTestRequest()
250    {
251       return testRequest;
252    }
253 
254    @Override
255    public void setName( String name )
256    {
257       super.setName( name );
258       testRequest.setName( name );
259    }
260 
261    public void propertyChange( PropertyChangeEvent arg0 )
262    {
263       if( arg0.getSource() == wsdlOperation )
264       {
265          if( arg0.getPropertyName().equals( Operation.NAME_PROPERTY ) )
266          {
267             requestStepConfig.setOperation( (String) arg0.getNewValue() );
268          }
269       }
270       else if( arg0.getSource() == wsdlOperation.getInterface() )
271       {
272          if( arg0.getPropertyName().equals( Interface.NAME_PROPERTY ) )
273          {
274             requestStepConfig.setInterface( (String) arg0.getNewValue() );
275          }
276       }
277       else if( arg0.getPropertyName().equals( TestAssertion.CONFIGURATION_PROPERTY )
278               || arg0.getPropertyName().equals( TestAssertion.DISABLED_PROPERTY ) )
279       {
280          if( getTestRequest().getResponse() != null )
281          {
282             getTestRequest().assertResponse( new WsdlTestRunContext( this ) );
283          }
284       }
285       else
286       {
287          if( arg0.getSource() == testRequest && arg0.getPropertyName().equals( WsdlTestRequest.NAME_PROPERTY ) )
288          {
289             if( !super.getName().equals( (String) arg0.getNewValue() ) )
290                super.setName( (String) arg0.getNewValue() );
291          }
292 
293          notifyPropertyChanged( arg0.getPropertyName(), arg0.getOldValue(), arg0.getNewValue() );
294       }
295    }
296 
297    public TestStepResult run( TestRunner runner, TestRunContext runContext )
298    {
299       WsdlTestRequestStepResult testStepResult = new WsdlTestRequestStepResult( this );
300 
301       try
302       {
303          submit = testRequest.submit( runContext, false );
304          WsdlResponse response = (WsdlResponse) submit.getResponse();
305 
306          if( submit.getStatus() != Submit.Status.CANCELED )
307          {
308             if( submit.getStatus() == Submit.Status.ERROR )
309             {
310                testStepResult.setStatus( TestStepStatus.FAILED );
311                testStepResult.addMessage( submit.getError().toString() );
312 
313                testRequest.setResponse( null, runContext );
314             }
315             else if( response == null )
316             {
317                testStepResult.setStatus( TestStepStatus.FAILED );
318                testStepResult.addMessage( "Request is missing response" );
319 
320                testRequest.setResponse( null, runContext );
321             }
322             else
323             {
324                runContext.setProperty( AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult );
325                testRequest.setResponse( response, runContext );
326 
327                testStepResult.setTimeTaken( response.getTimeTaken() );
328                testStepResult.setSize( response.getContentLength() );
329                testStepResult.setResponse( response );
330 
331                switch( testRequest.getAssertionStatus() )
332                {
333                   case FAILED:
334                      testStepResult.setStatus( TestStepStatus.FAILED );
335                      break;
336                   case VALID:
337                      testStepResult.setStatus( TestStepStatus.OK );
338                      break;
339                   case UNKNOWN:
340                      testStepResult.setStatus( TestStepStatus.UNKNOWN );
341                      break;
342                }
343             }
344          }
345          else
346          {
347             testStepResult.setStatus( TestStepStatus.CANCELED );
348             testStepResult.addMessage( "Request was canceled" );
349          }
350 
351          if( response != null )
352             testStepResult.setRequestContent( response.getRequestContent() );
353          else
354             testStepResult.setRequestContent( testRequest.getRequestContent() );
355       }
356       catch( SubmitException e )
357       {
358          testStepResult.setStatus( TestStepStatus.FAILED );
359          testStepResult.addMessage( "SubmitException: " + e );
360       }
361       finally
362       {
363          submit = null;
364       }
365 
366       testStepResult.setDomain( PropertyExpansionUtils.expandProperties( runContext, testRequest.getDomain() ) );
367       testStepResult.setUsername( PropertyExpansionUtils.expandProperties( runContext, testRequest.getUsername() ) );
368       testStepResult.setPassword( PropertyExpansionUtils.expandProperties( runContext, testRequest.getPassword() ) );
369       testStepResult.setEndpoint( PropertyExpansionUtils.expandProperties( runContext, testRequest.getEndpoint() ) );
370       testStepResult.setEncoding( PropertyExpansionUtils.expandProperties( runContext, testRequest.getEncoding() ) );
371 
372       if( testStepResult.getStatus() != TestStepStatus.CANCELED )
373       {
374          AssertionStatus assertionStatus = testRequest.getAssertionStatus();
375          switch( assertionStatus )
376          {
377             case FAILED:
378             {
379                testStepResult.setStatus( TestStepStatus.FAILED );
380                if( getAssertionCount() == 0 )
381                {
382                   testStepResult.addMessage( "Invalid/empty response" );
383                }
384                else
385                   for( int c = 0; c < getAssertionCount(); c++ )
386                   {
387                      AssertionError[] errors = getAssertionAt( c ).getErrors();
388                      if( errors != null )
389                      {
390                         for( AssertionError error : errors )
391                         {
392                            testStepResult.addMessage( error.getMessage() );
393                         }
394                      }
395                   }
396 
397                break;
398             }
399             // default : testStepResult.setStatus( TestStepStatus.OK ); break;
400          }
401       }
402 
403       return testStepResult;
404    }
405 
406    public WsdlMessageAssertion getAssertionAt( int index )
407    {
408       return testRequest.getAssertionAt( index );
409    }
410 
411    public int getAssertionCount()
412    {
413       return testRequest == null ? 0 : testRequest.getAssertionCount();
414    }
415 
416    public AbstractHttpRequest<?> getHttpRequest()
417    {
418       return testRequest;
419    }
420 
421    public class InternalProjectListener extends ProjectListenerAdapter
422    {
423       @Override
424       public void interfaceRemoved( Interface iface )
425       {
426          if( wsdlOperation != null && wsdlOperation.getInterface().equals( iface ) )
427          {
428             log.debug( "Removing test step due to removed interface" );
429             ( getTestCase() ).removeTestStep( WsdlTestRequestStep.this );
430          }
431       }
432    }
433 
434    public class InternalInterfaceListener extends InterfaceListenerAdapter
435    {
436       @Override
437       public void operationRemoved( Operation operation )
438       {
439          if( operation == wsdlOperation )
440          {
441             log.debug( "Removing test step due to removed operation" );
442             ( getTestCase() ).removeTestStep( WsdlTestRequestStep.this );
443          }
444       }
445 
446       @Override
447       public void operationUpdated( Operation operation )
448       {
449          if( operation == wsdlOperation )
450          {
451             requestStepConfig.setOperation( operation.getName() );
452          }
453       }
454    }
455 
456    @Override
457    public boolean cancel()
458    {
459       if( submit == null )
460          return false;
461 
462       submit.cancel();
463 
464       return true;
465    }
466 
467    @Override
468    public Collection<WsdlInterface> getRequiredInterfaces()
469    {
470       ArrayList<WsdlInterface> result = new ArrayList<WsdlInterface>();
471       result.add( findWsdlOperation().getInterface() );
472       return result;
473    }
474 
475    public String getDefaultSourcePropertyName()
476    {
477       return "Response";
478    }
479 
480    public String getDefaultTargetPropertyName()
481    {
482       return "Request";
483    }
484 
485    @Override
486    public boolean dependsOn( AbstractWsdlModelItem<?> modelItem )
487    {
488       if( modelItem instanceof Interface && testRequest.getOperation().getInterface() == modelItem )
489       {
490          return true;
491       }
492       else if( modelItem instanceof Operation && testRequest.getOperation() == modelItem )
493       {
494          return true;
495       }
496 
497       return false;
498    }
499 
500    @Override
501    public void beforeSave()
502    {
503       super.beforeSave();
504 
505       if( testRequest != null )
506          testRequest.beforeSave();
507    }
508 
509    @Override
510    public String getDescription()
511    {
512       return testRequest == null ? "<missing>" : testRequest.getDescription();
513    }
514 
515    @Override
516    public void setDescription( String description )
517    {
518       if( testRequest != null )
519          testRequest.setDescription( description );
520    }
521 
522    public void setOperation( WsdlOperation operation )
523    {
524       if( wsdlOperation == operation )
525          return;
526 
527       WsdlOperation oldOperation = wsdlOperation;
528       wsdlOperation = operation;
529       requestStepConfig.setInterface( operation.getInterface().getName() );
530       requestStepConfig.setOperation( operation.getName() );
531 
532       if( oldOperation != null )
533          oldOperation.removePropertyChangeListener( this );
534 
535       wsdlOperation.addPropertyChangeListener( this );
536 
537       testRequest.setOperation( wsdlOperation );
538    }
539 
540    @SuppressWarnings( "unchecked" )
541    @Override
542    public List<? extends ModelItem> getChildren()
543    {
544       return testRequest == null ? Collections.EMPTY_LIST : testRequest.getAssertionList();
545    }
546 
547    public PropertyExpansion[] getPropertyExpansions()
548    {
549       PropertyExpansionsResult result = new PropertyExpansionsResult( this, testRequest );
550 
551       result.extractAndAddAll( "requestContent" );
552       result.extractAndAddAll( "endpoint" );
553       result.extractAndAddAll( "username" );
554       result.extractAndAddAll( "password" );
555       result.extractAndAddAll( "domain" );
556 
557       StringToStringMap requestHeaders = testRequest.getRequestHeaders();
558       for( String key : requestHeaders.keySet() )
559       {
560          result.extractAndAddAll( new RequestHeaderHolder( requestHeaders, key ), "value" );
561       }
562 
563       // result.addAll( testRequest.getWssContainer().getPropertyExpansions() );
564 
565       return result.toArray( new PropertyExpansion[result.size()] );
566    }
567 
568    public class RequestHeaderHolder
569    {
570       private final StringToStringMap valueMap;
571       private final String key;
572 
573       public RequestHeaderHolder( StringToStringMap valueMap, String key )
574       {
575          this.valueMap = valueMap;
576          this.key = key;
577       }
578 
579       public String getValue()
580       {
581          return valueMap.get( key );
582       }
583 
584       public void setValue( String value )
585       {
586          valueMap.put( key, value );
587          testRequest.setRequestHeaders( valueMap );
588       }
589    }
590 
591    public TestAssertion addAssertion( String type )
592    {
593       WsdlMessageAssertion result = testRequest.addAssertion( type );
594       return result;
595    }
596 
597    public void addAssertionsListener( AssertionsListener listener )
598    {
599       testRequest.addAssertionsListener( listener );
600    }
601 
602    public TestAssertion cloneAssertion( TestAssertion source, String name )
603    {
604       return testRequest.cloneAssertion( source, name );
605    }
606 
607    public String getAssertableContent()
608    {
609       return testRequest.getAssertableContent();
610    }
611 
612    public AssertableType getAssertableType()
613    {
614       return testRequest.getAssertableType();
615    }
616 
617    public TestAssertion getAssertionByName( String name )
618    {
619       return testRequest.getAssertionByName( name );
620    }
621 
622    public List<TestAssertion> getAssertionList()
623    {
624       return testRequest.getAssertionList();
625    }
626 
627    public AssertionStatus getAssertionStatus()
628    {
629       return testRequest.getAssertionStatus();
630    }
631 
632    public Interface getInterface()
633    {
634       return getOperation().getInterface();
635    }
636 
637    public WsdlOperation getOperation()
638    {
639       return wsdlOperation;
640    }
641 
642    public TestStep getTestStep()
643    {
644       return this;
645    }
646 
647    public void removeAssertion( TestAssertion assertion )
648    {
649       testRequest.removeAssertion( assertion );
650    }
651 
652    public void removeAssertionsListener( AssertionsListener listener )
653    {
654       testRequest.removeAssertionsListener( listener );
655    }
656 
657    public Map<String, TestAssertion> getAssertions()
658    {
659       return testRequest.getAssertions();
660    }
661 
662    @Override
663    public void prepare( TestRunner testRunner, TestRunContext testRunContext ) throws Exception
664    {
665       super.prepare( testRunner, testRunContext );
666 
667       for( TestAssertion assertion : testRequest.getAssertionList() )
668       {
669          assertion.prepare( testRunner, testRunContext );
670       }
671    }
672 
673    public String getDefaultAssertableContent()
674    {
675       return testRequest.getDefaultAssertableContent();
676    }
677 
678    @SuppressWarnings( "unchecked" )
679    public void resolve( ResolveContext context )
680    {
681       super.resolve( context );
682 
683       if( wsdlOperation == null )
684       {
685          // not solved and we have it in list do not add it.
686          if( context.hasThisModelItem( this, "Missing SOAP Operation in Project", requestStepConfig.getInterface() + "/"
687                  + requestStepConfig.getOperation() ) )
688             return;
689 
690          context.addPathToResolve( this, "Missing SOAP Operation in Project",
691                  requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation() ).addResolvers(
692                  new RemoveTestStepResolver( this ), new ImportInterfaceResolver( this )
693                  {
694 
695                     @Override
696                     protected boolean update()
697                     {
698                        wsdlOperation = findWsdlOperation();
699                        if( wsdlOperation == null )
700                           return false;
701 
702                        initTestRequest( getConfig(), false );
703                        initRequestProperties();
704                        setDisabled( false );
705                        return true;
706                     }
707                  }, new ChangeOperationResolver( this )
708                  {
709 
710                     @Override
711                     public boolean update()
712                     {
713                        wsdlOperation = (WsdlOperation) getPickedOperation();
714                        if( wsdlOperation == null )
715                           return false;
716 
717                        initTestRequest( getConfig(), false );
718                        initRequestProperties();
719                        setDisabled( false );
720                        return true;
721                     }
722 
723                  } );
724       }
725       else
726       {
727          testRequest.resolve( context );
728          if( context.hasThisModelItem( this, "Missing SOAP Operation in Project", requestStepConfig.getInterface() + "/"
729                  + requestStepConfig.getOperation() ) )
730          {
731             PathToResolve path = context.getPath( this, "Missing SOAP Operation in Project", requestStepConfig
732                     .getInterface()
733                     + "/" + requestStepConfig.getOperation() );
734             path.setSolved( true );
735          }
736       }
737    }
738 }