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.SoapUI;
16  import com.eviware.soapui.config.*;
17  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
18  import com.eviware.soapui.impl.wsdl.WsdlInterface;
19  import com.eviware.soapui.impl.wsdl.WsdlOperation;
20  import com.eviware.soapui.impl.wsdl.WsdlSubmitContext;
21  import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
22  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
23  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult;
24  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
25  import com.eviware.soapui.impl.wsdl.mock.dispatch.QueryMatchMockOperationDispatcher;
26  import com.eviware.soapui.impl.wsdl.panels.mockoperation.WsdlMockResultMessageExchange;
27  import com.eviware.soapui.impl.wsdl.support.ModelItemIconAnimator;
28  import com.eviware.soapui.impl.wsdl.support.assertions.AssertableConfig;
29  import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
30  import com.eviware.soapui.impl.wsdl.support.assertions.AssertionsSupport;
31  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
32  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
33  import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry;
34  import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry.AssertableType;
35  import com.eviware.soapui.model.ModelItem;
36  import com.eviware.soapui.model.iface.Interface;
37  import com.eviware.soapui.model.iface.Operation;
38  import com.eviware.soapui.model.iface.SubmitContext;
39  import com.eviware.soapui.model.mock.MockResult;
40  import com.eviware.soapui.model.mock.MockRunner;
41  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
42  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
43  import com.eviware.soapui.model.support.*;
44  import com.eviware.soapui.model.testsuite.*;
45  import com.eviware.soapui.model.testsuite.AssertionError;
46  import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
47  import com.eviware.soapui.support.StringUtils;
48  import com.eviware.soapui.support.resolver.ChangeOperationResolver;
49  import com.eviware.soapui.support.resolver.ImportInterfaceResolver;
50  import com.eviware.soapui.support.resolver.RemoveTestStepResolver;
51  import com.eviware.soapui.support.resolver.ResolveContext;
52  import com.eviware.soapui.support.resolver.ResolveContext.PathToResolve;
53  import com.eviware.soapui.support.types.StringToStringMap;
54  import org.apache.log4j.Logger;
55  
56  import javax.swing.*;
57  import java.beans.PropertyChangeEvent;
58  import java.beans.PropertyChangeListener;
59  import java.util.*;
60  
61  public class WsdlMockResponseTestStep extends WsdlTestStepWithProperties implements OperationTestStep,
62          PropertyChangeListener, Assertable
63  {
64     private final static Logger log = Logger.getLogger( WsdlMockResponseTestStep.class );
65  
66     public static final String STATUS_PROPERTY = WsdlMockResponseTestStep.class.getName() + "@status";
67     public static final String TIMEOUT_PROPERTY = WsdlMockResponseTestStep.class.getName() + "@timeout";
68  
69     private MockResponseStepConfig mockResponseStepConfig;
70     private MockResponseConfig mockResponseConfig;
71     private WsdlMockOperation mockOperation;
72     private WsdlTestMockService mockService;
73     private WsdlMockRunner mockRunner;
74     private WsdlMockResponse mockResponse;
75  
76     private AssertionsSupport assertionsSupport;
77     private InternalMockRunListener mockRunListener;
78  
79     private final InternalProjectListener projectListener = new InternalProjectListener();
80     private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener();
81     private final InternalTestRunListener testRunListener = new InternalTestRunListener();
82     private WsdlInterface iface;
83     private AssertionStatus oldStatus;
84  
85     private ModelItemIconAnimator<WsdlMockResponseTestStep> iconAnimator;
86     private WsdlMockResponse testMockResponse;
87     private WsdlTestStep startTestStep;
88  
89     public WsdlMockResponseTestStep( WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest )
90     {
91        super( testCase, config, true, forLoadTest );
92  
93        if( config.getConfig() != null )
94        {
95           mockResponseStepConfig = (MockResponseStepConfig) config.getConfig().changeType( MockResponseStepConfig.type );
96           mockResponseConfig = mockResponseStepConfig.getResponse();
97        }
98        else
99        {
100          mockResponseStepConfig = (MockResponseStepConfig) config.addNewConfig()
101                  .changeType( MockResponseStepConfig.type );
102          mockResponseConfig = mockResponseStepConfig.addNewResponse();
103       }
104 
105       initAssertions();
106       initMockObjects( testCase );
107 
108       if( !forLoadTest )
109       {
110          if( iface != null )
111          {
112             iface.getProject().addProjectListener( projectListener );
113             iface.addInterfaceListener( interfaceListener );
114          }
115 
116          iconAnimator = new ModelItemIconAnimator<WsdlMockResponseTestStep>( this, "/mockResponseStep.gif",
117                  "/exec_mockResponse", 4, "gif" );
118       }
119 
120       // init properties
121       initProperties();
122 
123       testCase.addTestRunListener( testRunListener );
124 
125       startTestStep = testCase.getTestStepByName( getStartStep() );
126       if( startTestStep != null )
127       {
128          startTestStep.addPropertyChangeListener( this );
129       }
130 
131       testCase.addPropertyChangeListener( this );
132    }
133 
134    private void initProperties()
135    {
136       if( mockResponse != null )
137       {
138          addProperty( new TestStepBeanProperty( "Response", false, mockResponse, "responseContent", this ) );
139       }
140 
141       addProperty( new DefaultTestStepProperty( "Request", true, new DefaultTestStepProperty.PropertyHandlerAdapter()
142       {
143          public String getValue( DefaultTestStepProperty property )
144          {
145             WsdlMockResult mockResult = mockResponse == null ? null : mockResponse.getMockResult();
146             return mockResult == null ? null : mockResult.getMockRequest().getRequestContent();
147          }
148       }, this ) );
149    }
150 
151    @Override
152    public ImageIcon getIcon()
153    {
154       return iconAnimator == null ? null : iconAnimator.getIcon();
155    }
156 
157    private void initAssertions()
158    {
159       assertionsSupport = new AssertionsSupport( this, new AssertableConfig()
160       {
161 
162          public TestAssertionConfig addNewAssertion()
163          {
164             return mockResponseStepConfig.addNewAssertion();
165          }
166 
167          public List<TestAssertionConfig> getAssertionList()
168          {
169             return mockResponseStepConfig.getAssertionList();
170          }
171 
172          public void removeAssertion( int ix )
173          {
174             mockResponseStepConfig.removeAssertion( ix );
175          }
176       } );
177    }
178 
179    private void initMockObjects( WsdlTestCase testCase )
180    {
181       MockServiceConfig mockServiceConfig = MockServiceConfig.Factory.newInstance();
182       mockServiceConfig.setPath( mockResponseStepConfig.getPath() );
183       mockServiceConfig.setPort( mockResponseStepConfig.getPort() );
184 
185       mockService = new WsdlTestMockService( this, mockServiceConfig );
186       mockService.setName( getName() );
187 
188       iface = (WsdlInterface) testCase.getTestSuite().getProject().getInterfaceByName(
189               mockResponseStepConfig.getInterface() );
190       if( iface == null )
191       {
192       }
193       else
194       {
195          iface.addInterfaceListener( interfaceListener );
196 
197          mockOperation = mockService.addNewMockOperation( iface
198                  .getOperationByName( mockResponseStepConfig.getOperation() ) );
199 
200          if( mockResponseStepConfig.getHandleFault() )
201             mockService.setFaultMockOperation( mockOperation );
202 
203          if( mockResponseStepConfig.getHandleResponse() )
204             mockService.setDispatchResponseMessages( true );
205 
206          mockResponse = mockOperation.addNewMockResponse( "MockResponse", false );
207          mockResponse.setConfig( mockResponseConfig );
208 
209          mockOperation.setDefaultResponse( mockResponse.getName() );
210 
211          mockResponse.addPropertyChangeListener( this );
212       }
213    }
214 
215    public void resetConfigOnMove( TestStepConfig config )
216    {
217       super.resetConfigOnMove( config );
218 
219       mockResponseStepConfig = (MockResponseStepConfig) config.getConfig().changeType( MockResponseStepConfig.type );
220       mockResponseConfig = mockResponseStepConfig.getResponse();
221       mockResponse.setConfig( mockResponseConfig );
222       assertionsSupport.refresh();
223    }
224 
225    @Override
226    public boolean cancel()
227    {
228       if( mockRunner != null )
229       {
230          mockRunner.stop();
231          mockRunner = null;
232       }
233 
234       if( mockRunListener != null )
235          mockRunListener.cancel();
236 
237       return true;
238    }
239 
240    @Override
241    public void prepare( TestRunner testRunner, TestRunContext testRunContext ) throws Exception
242    {
243       super.prepare( testRunner, testRunContext );
244 
245       LoadTestRunner loadTestRunner = (LoadTestRunner) testRunContext.getProperty( TestRunContext.LOAD_TEST_RUNNER );
246       mockRunListener = new InternalMockRunListener();
247 
248       if( loadTestRunner == null )
249       {
250          mockService.addMockRunListener( mockRunListener );
251          mockRunner = mockService.start( (WsdlTestRunContext) testRunContext );
252       }
253       else
254       {
255          synchronized( STATUS_PROPERTY )
256          {
257             mockRunner = (WsdlMockRunner) testRunContext.getProperty( "sharedMockServiceRunner" );
258             if( mockRunner == null )
259             {
260                mockService.addMockRunListener( mockRunListener );
261                mockRunner = mockService.start( (WsdlTestRunContext) testRunContext );
262             }
263             else
264             {
265                mockRunner.getMockService().addMockRunListener( mockRunListener );
266             }
267          }
268       }
269    }
270 
271    protected void initTestMockResponse( TestRunContext testRunContext )
272    {
273       if( StringUtils.hasContent( getQuery() ) && StringUtils.hasContent( getMatch() ) )
274       {
275          testMockResponse = mockOperation.addNewMockResponse( "MockResponse" + Math.random(), false );
276          testMockResponse.setConfig( mockResponse.getConfig() );
277 
278          QueryMatchMockOperationDispatcher dispatcher = (QueryMatchMockOperationDispatcher) mockOperation.setDispatchStyle( MockOperationDispatchStyleConfig.QUERY_MATCH.toString() );
279          QueryMatchMockOperationDispatcher.Query query = dispatcher.addQuery( "Match" );
280          query.setQuery( PropertyExpansionUtils.expandProperties( testRunContext, getQuery() ) );
281          query.setMatch( PropertyExpansionUtils.expandProperties( testRunContext, getMatch() ) );
282          query.setResponse( testMockResponse.getName() );
283       }
284       else
285       {
286          testMockResponse = mockResponse;
287       }
288    }
289 
290    public TestStepResult run( TestRunner testRunner, TestRunContext context )
291    {
292       LoadTestRunner loadTestRunner = (LoadTestRunner) context.getProperty( TestRunContext.LOAD_TEST_RUNNER );
293       if( loadTestRunner == null )
294       {
295          return internalRun( (WsdlTestRunContext) context );
296       }
297       else
298       {
299          // block other threads during loadtesting -> this should be improved!
300          synchronized( STATUS_PROPERTY )
301          {
302             if( loadTestRunner.getStatus() == LoadTestRunner.Status.RUNNING )
303             {
304                return internalRun( (WsdlTestRunContext) context );
305             }
306             else
307             {
308                WsdlSingleMessageExchangeTestStepResult result = new WsdlSingleMessageExchangeTestStepResult( this );
309                result.setStatus( TestStepStatus.UNKNOWN );
310                return result;
311             }
312          }
313       }
314    }
315 
316    private TestStepResult internalRun( WsdlTestRunContext context )
317    {
318       iconAnimator.start();
319       WsdlSingleMessageExchangeTestStepResult result = new WsdlSingleMessageExchangeTestStepResult( this );
320 
321       try
322       {
323          if( !mockRunListener.hasResult() )
324          {
325             if( testMockResponse == null )
326                initTestMockResponse( context );
327 
328             result.startTimer();
329 
330             long timeout = getTimeout();
331             synchronized( mockRunListener )
332             {
333                mockRunListener.waitForRequest( timeout );
334             }
335          }
336 
337          result.stopTimer();
338 
339          AssertedWsdlMockResultMessageExchange messageExchange = new AssertedWsdlMockResultMessageExchange( mockRunListener
340                  .getResult() );
341          result.setMessageExchange( messageExchange );
342 
343          if( mockRunListener.getResult() != null )
344          {
345             context.setProperty( AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, messageExchange );
346             assertResult( mockRunListener.getResult(), context );
347          }
348 
349          if( mockRunListener.getResult() == null )
350          {
351             if( mockRunListener.isCanceled() )
352             {
353                result.setStatus( TestStepStatus.CANCELED );
354             }
355             else
356             {
357                result.setStatus( TestStepStatus.FAILED );
358                result.addMessage( "Timeout occured after " + getTimeout() + " milliseconds" );
359             }
360          }
361          else
362          {
363             AssertionStatus status = getAssertionStatus();
364             if( status == AssertionStatus.FAILED )
365             {
366                result.setStatus( TestStepStatus.FAILED );
367 
368                if( getAssertionCount() == 0 )
369                {
370                   result.addMessage( "Invalid/empty request" );
371                }
372                else
373                   for( int c = 0; c < getAssertionCount(); c++ )
374                   {
375                      AssertionError[] errors = getAssertionAt( c ).getErrors();
376                      if( errors != null )
377                      {
378                         for( AssertionError error : errors )
379                         {
380                            result.addMessage( error.getMessage() );
381                         }
382                      }
383                   }
384             }
385             else
386             {
387                result.setStatus( TestStepStatus.OK );
388             }
389 
390             mockRunListener.setResult( null );
391          }
392       }
393       catch( Exception e )
394       {
395          result.stopTimer();
396          result.setStatus( TestStepStatus.FAILED );
397          result.setError( e );
398          SoapUI.logError( e );
399       }
400       finally
401       {
402          iconAnimator.stop();
403       }
404 
405       return result;
406    }
407 
408    private void assertResult( WsdlMockResult result, SubmitContext context )
409    {
410       if( oldStatus == null )
411          oldStatus = getAssertionStatus();
412 
413       for( int c = 0; c < getAssertionCount(); c++ )
414       {
415          WsdlMessageAssertion assertion = getAssertionAt( c );
416          if( !assertion.isDisabled() )
417          {
418             assertion.assertRequest( new WsdlMockResultMessageExchange( result, getMockResponse() ), context );
419          }
420       }
421 
422       AssertionStatus newStatus = getAssertionStatus();
423       if( newStatus != oldStatus )
424       {
425          notifyPropertyChanged( STATUS_PROPERTY, oldStatus, newStatus );
426          oldStatus = newStatus;
427       }
428    }
429 
430    @Override
431    public void finish( TestRunner testRunner, TestRunContext testRunContext )
432    {
433       if( mockRunListener != null )
434       {
435          mockService.removeMockRunListener( mockRunListener );
436          mockRunListener = null;
437       }
438 
439       if( testMockResponse != null )
440       {
441          if( testMockResponse != mockResponse )
442          {
443             mockOperation.removeMockResponse( testMockResponse );
444          }
445          
446          testMockResponse = null;
447       }
448 
449       if( mockRunner != null )
450       {
451          if( mockRunner.isRunning() )
452          {
453             mockRunner.stop();
454          }
455 
456          mockRunner = null;
457       }
458    }
459 
460    public class InternalMockRunListener extends MockRunListenerAdapter
461    {
462       private WsdlMockResult result;
463       private boolean canceled;
464       private boolean waiting;
465 
466       public void onMockResult( MockResult result )
467       {
468          // is this for us?
469          if( this.result == null && waiting && result.getMockResponse() == testMockResponse )
470          {
471             // save
472             this.setResult( (WsdlMockResult) result );
473 
474             // stop runner
475             mockRunner.stop();
476 
477             if( waiting )
478             {
479                synchronized( this )
480                {
481                   notifyAll();
482                }
483             }
484          }
485       }
486 
487       public void cancel()
488       {
489          canceled = true;
490         // mockRunListener.onMockResult( null );
491       }
492 
493       private void setResult( WsdlMockResult result )
494       {
495          this.result = result;
496       }
497 
498       public WsdlMockResult getResult()
499       {
500          return result;
501       }
502 
503       public boolean isCanceled()
504       {
505          return canceled;
506       }
507 
508       public boolean hasResult()
509       {
510          return result != null;
511       }
512 
513       public boolean isWaiting()
514       {
515          return waiting;
516       }
517 
518       public void setWaiting( boolean waiting )
519       {
520          this.waiting = waiting;
521       }
522 
523       public void waitForRequest( long timeout ) throws InterruptedException
524       {
525          waiting = true;
526          wait( timeout );
527       }
528 
529       @Override
530       public void onMockRunnerStart( MockRunner mockRunner )
531       {
532          waiting = false;
533          result = null;
534          canceled = false;
535       }
536    }
537 
538    public WsdlMockResponse getMockResponse()
539    {
540       return mockResponse;
541    }
542 
543    public void setPort( int port )
544    {
545       int old = getPort();
546       mockService.setPort( port );
547       mockResponseStepConfig.setPort( port );
548       notifyPropertyChanged( "port", old, port );
549    }
550 
551    public String getPath()
552    {
553       return mockResponseStepConfig.getPath();
554    }
555 
556    public long getContentLength()
557    {
558       return mockResponse == null ? 0 : mockResponse.getContentLength();
559    }
560 
561    public int getPort()
562    {
563       return mockResponseStepConfig.getPort();
564    }
565 
566    public String getEncoding()
567    {
568       return mockResponse.getEncoding();
569    }
570 
571    public void setEncoding( String encoding )
572    {
573       String old = getEncoding();
574       mockResponse.setEncoding( encoding );
575       notifyPropertyChanged( "encoding", old, encoding );
576    }
577 
578    public boolean isMtomEnabled()
579    {
580       return mockResponse.isMtomEnabled();
581    }
582 
583    public void setMtomEnabled( boolean enabled )
584    {
585       if( isMtomEnabled() == enabled )
586          return;
587       mockResponse.setMtomEnabled( enabled );
588 
589       notifyPropertyChanged( "mtomEnabled", !enabled, enabled );
590    }
591 
592    public String getOutgoingWss()
593    {
594       return mockResponse.getOutgoingWss();
595    }
596 
597    public void setOutgoingWss( String outgoingWss )
598    {
599       String old = getOutgoingWss();
600       mockResponse.setOutgoingWss( outgoingWss );
601       notifyPropertyChanged( "outgoingWss", old, outgoingWss );
602    }
603 
604    public void setQuery( String s )
605    {
606       String old = getQuery();
607       mockResponseStepConfig.setQuery( s );
608       notifyPropertyChanged( "query", old, s );
609    }
610 
611    public String getQuery()
612    {
613       return mockResponseStepConfig.getQuery();
614    }
615 
616    public String getMatch()
617    {
618       return mockResponseStepConfig.getMatch();
619    }
620 
621    public void setMatch( String s )
622    {
623       String old = getMatch();
624       mockResponseStepConfig.setMatch( s );
625       notifyPropertyChanged( "match", old, s );
626    }
627 
628    public boolean isForceMtom()
629    {
630       return mockResponse.isForceMtom();
631    }
632 
633    public void setForceMtom( boolean forceMtom )
634    {
635       mockResponse.setForceMtom( forceMtom );
636    }
637 
638    public boolean isInlineFilesEnabled()
639    {
640       return mockResponse.isInlineFilesEnabled();
641    }
642 
643    public void setInlineFilesEnabled( boolean inlineFilesEnabled )
644    {
645       mockResponse.setInlineFilesEnabled( inlineFilesEnabled );
646    }
647 
648    public String getStartStep()
649    {
650       return startTestStep == null ? "" : startTestStep.getName();
651    }
652 
653    public void setStartStep( String startStep )
654    {
655       String old = getStartStep();
656       if( startTestStep != null )
657       {
658          startTestStep.removePropertyChangeListener( this );
659          startTestStep = null;
660       }
661 
662       if( startStep != null )
663       {
664          startTestStep = getTestCase().getTestStepByName( startStep );
665          if( startTestStep != null )
666          {
667             startTestStep.addPropertyChangeListener( this );
668          }
669       }
670 
671       mockResponseStepConfig.setStartStep( startStep );
672       notifyPropertyChanged( "startStep", old, startStep );
673    }
674 
675    public boolean isMultipartEnabled()
676    {
677       return mockResponse.isMultipartEnabled();
678    }
679 
680    public void setMultipartEnabled( boolean enabled )
681    {
682       mockResponse.setMultipartEnabled( enabled );
683    }
684 
685    public boolean isHandleFault()
686    {
687       return mockResponseStepConfig.getHandleFault();
688    }
689 
690    public void setHandleFault( boolean handleFault )
691    {
692       mockResponseStepConfig.setHandleFault( handleFault );
693       if( mockService != null )
694          mockService.setFaultMockOperation( handleFault ? mockOperation : null );
695    }
696 
697    public boolean isHandleResponse()
698    {
699       return mockResponseStepConfig.getHandleResponse();
700    }
701 
702    public void setHandleResponse( boolean handleResponse )
703    {
704       mockResponseStepConfig.setHandleResponse( handleResponse );
705       if( mockService != null )
706          mockService.setDispatchResponseMessages( handleResponse );
707    }
708 
709    public long getResponseDelay()
710    {
711       return mockResponse.getResponseDelay();
712    }
713 
714    public void setResponseDelay( long delay )
715    {
716       mockResponse.setResponseDelay( delay );
717    }
718 
719    public String getResponseHttpStatus()
720    {
721       return mockResponse.getResponseHttpStatus();
722    }
723 
724    public void setResponseHttpStatus( String httpStatus )
725    {
726       mockResponse.setResponseHttpStatus( httpStatus );
727    }
728 
729    public boolean isEncodeAttachments()
730    {
731       return mockResponse.isEncodeAttachments();
732    }
733 
734    public boolean isRemoveEmptyContent()
735    {
736       return mockResponse.isRemoveEmptyContent();
737    }
738 
739    public boolean isStripWhitespaces()
740    {
741       return mockResponse.isStripWhitespaces();
742    }
743 
744    public void setEncodeAttachments( boolean encodeAttachments )
745    {
746       mockResponse.setEncodeAttachments( encodeAttachments );
747    }
748 
749    public void setRemoveEmptyContent( boolean removeEmptyContent )
750    {
751       mockResponse.setRemoveEmptyContent( removeEmptyContent );
752    }
753 
754    public void setStripWhitespaces( boolean stripWhitespaces )
755    {
756       mockResponse.setStripWhitespaces( stripWhitespaces );
757    }
758 
759    public void setPath( String path )
760    {
761       mockService.setPath( path );
762       mockResponseStepConfig.setPath( path );
763    }
764 
765    public void propertyChange( PropertyChangeEvent evt )
766    {
767       if( evt.getSource() == mockResponse )
768       {
769          mockResponseConfig.set( mockResponse.getConfig() );
770          notifyPropertyChanged( evt.getPropertyName(), evt.getOldValue(), evt.getNewValue() );
771       }
772       else if( evt.getSource() == getTestCase() && evt.getPropertyName().equals( "testSteps" ) &&
773               evt.getNewValue() == null && evt.getOldValue() == startTestStep && startTestStep != null )
774       {
775          setStartStep( null );
776       }
777       else if( evt.getSource() == startTestStep && evt.getPropertyName().equals( WsdlTestStep.NAME_PROPERTY ))
778       {
779          mockResponseStepConfig.setStartStep( String.valueOf( evt.getNewValue() ) );
780       }
781    }
782 
783    public WsdlMessageAssertion addAssertion( String assertionName )
784    {
785       PropertyChangeNotifier notifier = new PropertyChangeNotifier();
786 
787       try
788       {
789          TestAssertionConfig assertionConfig = mockResponseStepConfig.addNewAssertion();
790          assertionConfig.setType( TestAssertionRegistry.getInstance().getAssertionTypeForName( assertionName ) );
791 
792          WsdlMessageAssertion assertion = assertionsSupport.addWsdlAssertion( assertionConfig );
793          assertionsSupport.fireAssertionAdded( assertion );
794 
795          if( getMockResponse().getMockResult() != null )
796          {
797             assertion.assertRequest( new WsdlMockResultMessageExchange( getMockResponse().getMockResult(),
798                     getMockResponse() ), new WsdlSubmitContext( this ) );
799             notifier.notifyChange();
800          }
801 
802          return assertion;
803       }
804       catch( Exception e )
805       {
806          SoapUI.logError( e );
807          return null;
808       }
809    }
810 
811    public void addAssertionsListener( AssertionsListener listener )
812    {
813       assertionsSupport.addAssertionsListener( listener );
814    }
815 
816    public WsdlMessageAssertion getAssertionAt( int c )
817    {
818       return assertionsSupport.getAssertionAt( c );
819    }
820 
821    public int getAssertionCount()
822    {
823       return assertionsSupport.getAssertionCount();
824    }
825 
826    public void removeAssertionsListener( AssertionsListener listener )
827    {
828       assertionsSupport.removeAssertionsListener( listener );
829    }
830 
831    public AssertionStatus getAssertionStatus()
832    {
833       AssertionStatus currentStatus = AssertionStatus.UNKNOWN;
834       int cnt = getAssertionCount();
835       if( cnt == 0 )
836          return currentStatus;
837 
838       for( int c = 0; c < cnt; c++ )
839       {
840          WsdlMessageAssertion assertion = getAssertionAt( c );
841          if( assertion.isDisabled() )
842             continue;
843 
844          if( assertion.getStatus() == AssertionStatus.FAILED )
845          {
846             currentStatus = AssertionStatus.FAILED;
847             break;
848          }
849       }
850 
851       if( currentStatus == AssertionStatus.UNKNOWN )
852          currentStatus = AssertionStatus.VALID;
853 
854       return currentStatus;
855    }
856 
857    public void removeAssertion( TestAssertion assertion )
858    {
859       PropertyChangeNotifier notifier = new PropertyChangeNotifier();
860 
861       try
862       {
863          assertionsSupport.removeAssertion( (WsdlMessageAssertion) assertion );
864       }
865       finally
866       {
867          ( (WsdlMessageAssertion) assertion ).release();
868          notifier.notifyChange();
869       }
870    }
871 
872    public String getAssertableContent()
873    {
874       WsdlMockResult mockResult = getMockResponse().getMockResult();
875       return mockResult == null ? null : mockResult.getMockRequest().getRequestContent();
876    }
877 
878    public TestStep getTestStep()
879    {
880       return this;
881    }
882 
883    @Override
884    public void setName( String name )
885    {
886       super.setName( name );
887       if( mockService != null )
888          mockService.setName( getName() );
889    }
890 
891    public WsdlInterface getInterface()
892    {
893       return getOperation().getInterface();
894    }
895 
896    public WsdlOperation getOperation()
897    {
898       return getMockResponse().getMockOperation().getOperation();
899    }
900 
901    public void setInterface( String string )
902    {
903       WsdlInterface iface = (WsdlInterface) getTestCase().getTestSuite().getProject().getInterfaceByName( string );
904       if( iface != null )
905       {
906          mockResponseStepConfig.setInterface( iface.getName() );
907          WsdlOperation operation = iface.getOperationAt( 0 );
908          mockResponseStepConfig.setOperation( operation.getName() );
909          mockOperation.setOperation( operation );
910       }
911    }
912 
913    public void setOperation( String string )
914    {
915       WsdlOperation operation = getInterface().getOperationByName( string );
916       if( operation != null )
917       {
918          mockResponseStepConfig.setOperation( string );
919          mockOperation.setOperation( operation );
920       }
921    }
922 
923    private class PropertyChangeNotifier
924    {
925       private AssertionStatus oldStatus;
926       private ImageIcon oldIcon;
927 
928       public PropertyChangeNotifier()
929       {
930          oldStatus = getAssertionStatus();
931          oldIcon = getIcon();
932       }
933 
934       public void notifyChange()
935       {
936          AssertionStatus newStatus = getAssertionStatus();
937          ImageIcon newIcon = getIcon();
938 
939          if( oldStatus != newStatus )
940             notifyPropertyChanged( STATUS_PROPERTY, oldStatus, newStatus );
941 
942          if( oldIcon != newIcon )
943             notifyPropertyChanged( ICON_PROPERTY, oldIcon, getIcon() );
944       }
945    }
946 
947    @Override
948    public void release()
949    {
950       super.release();
951       assertionsSupport.release();
952 
953       if( mockResponse != null )
954          mockResponse.removePropertyChangeListener( this );
955 
956       if( mockService != null )
957          mockService.release();
958 
959       if( iface != null )
960       {
961          iface.getProject().removeProjectListener( projectListener );
962          iface.removeInterfaceListener( interfaceListener );
963       }
964 
965       getTestCase().removeTestRunListener( testRunListener );
966       getTestCase().removePropertyChangeListener( this );
967    }
968 
969    public AssertableType getAssertableType()
970    {
971       return AssertableType.REQUEST;
972    }
973 
974    @Override
975    public Collection<WsdlInterface> getRequiredInterfaces()
976    {
977       ArrayList<WsdlInterface> result = new ArrayList<WsdlInterface>();
978       result.add( getInterface() );
979       return result;
980    }
981 
982    public String getDefaultSourcePropertyName()
983    {
984       return "Response";
985    }
986 
987    public String getDefaultTargetPropertyName()
988    {
989       return "Request";
990    }
991 
992    @Override
993    public void beforeSave()
994    {
995       super.beforeSave();
996 
997       if( mockResponse != null )
998       {
999          mockResponse.beforeSave();
1000          mockResponseConfig.set( mockResponse.getConfig() );
1001       }
1002    }
1003 
1004    public long getTimeout()
1005    {
1006       return mockResponseStepConfig.getTimeout();
1007    }
1008 
1009    public void setTimeout( long timeout )
1010    {
1011       long old = getTimeout();
1012       mockResponseStepConfig.setTimeout( timeout );
1013       notifyPropertyChanged( TIMEOUT_PROPERTY, old, timeout );
1014    }
1015 
1016    @Override
1017    public boolean dependsOn( AbstractWsdlModelItem<?> modelItem )
1018    {
1019       return modelItem == getOperation().getInterface();
1020    }
1021 
1022    public class InternalProjectListener extends ProjectListenerAdapter
1023    {
1024       public void interfaceRemoved( Interface iface )
1025       {
1026          if( getOperation() != null && getOperation().getInterface().equals( iface ) )
1027          {
1028             log.debug( "Removing test step due to removed interface" );
1029             ( getTestCase() ).removeTestStep( WsdlMockResponseTestStep.this );
1030          }
1031       }
1032    }
1033 
1034    public class InternalInterfaceListener extends InterfaceListenerAdapter
1035    {
1036       public void operationRemoved( Operation operation )
1037       {
1038          if( operation == getOperation() )
1039          {
1040             log.debug( "Removing test step due to removed operation" );
1041             ( getTestCase() ).removeTestStep( WsdlMockResponseTestStep.this );
1042          }
1043       }
1044 
1045       @Override
1046       public void operationUpdated( Operation operation )
1047       {
1048          if( operation == getOperation() )
1049          {
1050             setOperation( operation.getName() );
1051          }
1052       }
1053    }
1054 
1055    public WsdlMessageAssertion cloneAssertion( TestAssertion source, String name )
1056    {
1057       TestAssertionConfig conf = mockResponseStepConfig.addNewAssertion();
1058       conf.set( ( (WsdlMessageAssertion) source ).getConfig() );
1059       conf.setName( name );
1060 
1061       WsdlMessageAssertion result = assertionsSupport.addWsdlAssertion( conf );
1062       assertionsSupport.fireAssertionAdded( result );
1063       return result;
1064    }
1065 
1066    public List<TestAssertion> getAssertionList()
1067    {
1068       return new ArrayList<TestAssertion>( assertionsSupport.getAssertionList() );
1069    }
1070 
1071    @Override
1072    public List<? extends ModelItem> getChildren()
1073    {
1074       return assertionsSupport.getAssertionList();
1075    }
1076 
1077    public PropertyExpansion[] getPropertyExpansions()
1078    {
1079       List<PropertyExpansion> result = new ArrayList<PropertyExpansion>();
1080 
1081       result.addAll( PropertyExpansionUtils.extractPropertyExpansions( this, mockResponse, "responseContent" ) );
1082 
1083       StringToStringMap responseHeaders = mockResponse.getResponseHeaders();
1084       for( String key : responseHeaders.keySet() )
1085       {
1086          result.addAll( PropertyExpansionUtils.extractPropertyExpansions( this, new ResponseHeaderHolder( responseHeaders,
1087                  key ), "value" ) );
1088       }
1089 
1090       return result.toArray( new PropertyExpansion[result.size()] );
1091    }
1092 
1093    public class ResponseHeaderHolder
1094    {
1095       private final StringToStringMap valueMap;
1096       private final String key;
1097 
1098       public ResponseHeaderHolder( StringToStringMap valueMap, String key )
1099       {
1100          this.valueMap = valueMap;
1101          this.key = key;
1102       }
1103 
1104       public String getValue()
1105       {
1106          return valueMap.get( key );
1107       }
1108 
1109       public void setValue( String value )
1110       {
1111          valueMap.put( key, value );
1112          mockResponse.setResponseHeaders( valueMap );
1113       }
1114    }
1115 
1116    public WsdlMessageAssertion getAssertionByName( String name )
1117    {
1118       return assertionsSupport.getAssertionByName( name );
1119    }
1120 
1121    public Map<String, TestAssertion> getAssertions()
1122    {
1123       Map<String, TestAssertion> result = new HashMap<String, TestAssertion>();
1124 
1125       for( TestAssertion assertion : getAssertionList() )
1126          result.put( assertion.getName(), assertion );
1127 
1128       return result;
1129    }
1130 
1131    private class AssertedWsdlMockResultMessageExchange extends WsdlMockResultMessageExchange implements
1132            RequestAssertedMessageExchange, AssertedXPathsContainer
1133    {
1134       private List<AssertedXPath> assertedXPaths;
1135 
1136       public AssertedWsdlMockResultMessageExchange( WsdlMockResult mockResult )
1137       {
1138          super( mockResult, mockResult == null ? null : mockResult.getMockResponse() );
1139       }
1140 
1141       public AssertedXPath[] getAssertedXPathsForRequest()
1142       {
1143          return assertedXPaths == null ? new AssertedXPath[0] : assertedXPaths.toArray( new AssertedXPath[assertedXPaths
1144                  .size()] );
1145       }
1146 
1147       public void addAssertedXPath( AssertedXPath assertedXPath )
1148       {
1149          if( assertedXPaths == null )
1150             assertedXPaths = new ArrayList<AssertedXPath>();
1151 
1152          assertedXPaths.add( assertedXPath );
1153       }
1154    }
1155 
1156    public String getDefaultAssertableContent()
1157    {
1158       return getOperation().createRequest( true );
1159    }
1160 
1161    @SuppressWarnings( "unchecked" )
1162    @Override
1163    public void resolve( ResolveContext context )
1164    {
1165       super.resolve( context );
1166 
1167       if( mockOperation == null )
1168       {
1169          if( context.hasThisModelItem( this, "Missing Operation in Project", mockResponseStepConfig.getInterface() + "/"
1170                  + mockResponseStepConfig.getOperation() ) )
1171             return;
1172          context.addPathToResolve( this, "Missing Operation in Project",
1173                  mockResponseStepConfig.getInterface() + "/" + mockResponseStepConfig.getOperation() ).addResolvers(
1174                  new RemoveTestStepResolver( this ), new ImportInterfaceResolver( this )
1175                  {
1176 
1177                     @Override
1178                     protected boolean update()
1179                     {
1180                        initMockObjects( getTestCase() );
1181                        initProperties();
1182                        setDisabled( false );
1183                        return true;
1184                     }
1185                  }, new ChangeOperationResolver( this )
1186                  {
1187 
1188                     @Override
1189                     public boolean update()
1190                     {
1191                        WsdlOperation operation = (WsdlOperation) getPickedOperation();
1192                        setInterface( operation.getInterface().getName() );
1193                        setOperation( operation.getName() );
1194                        initMockObjects( getTestCase() );
1195                        initProperties();
1196                        setDisabled( false );
1197                        return true;
1198                     }
1199 
1200                  } );
1201       }
1202       else
1203       {
1204          mockOperation.resolve( context );
1205          if( context.hasThisModelItem( this, "Missing Operation in Project", mockResponseStepConfig.getInterface() + "/"
1206                  + mockResponseStepConfig.getOperation() ) )
1207          {
1208             PathToResolve path = context.getPath( this, "Missing Operation in Project", mockResponseStepConfig.getInterface() + "/"
1209                     + mockResponseStepConfig.getOperation() );
1210             path.setSolved( true );
1211          }
1212       }
1213    }
1214 
1215    private class InternalTestRunListener extends TestRunListenerAdapter
1216    {
1217       @Override
1218       public void beforeStep( TestRunner testRunner, TestRunContext runContext )
1219       {
1220          if( runContext.getCurrentStep() == startTestStep && testMockResponse == null )
1221          {
1222             initTestMockResponse( runContext );
1223             mockRunListener.setWaiting( true );
1224          }
1225       }
1226    }
1227 
1228 }