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