1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.loadtest.data;
14
15 import java.awt.Color;
16 import java.beans.PropertyChangeEvent;
17 import java.beans.PropertyChangeListener;
18 import java.util.EmptyStackException;
19 import java.util.HashMap;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Stack;
23
24 import javax.swing.table.AbstractTableModel;
25
26 import org.apache.log4j.Logger;
27
28 import com.eviware.soapui.SoapUI;
29 import com.eviware.soapui.impl.wsdl.loadtest.ColorPalette;
30 import com.eviware.soapui.impl.wsdl.loadtest.WsdlLoadTest;
31 import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
32 import com.eviware.soapui.model.support.LoadTestRunListenerAdapter;
33 import com.eviware.soapui.model.support.TestSuiteListenerAdapter;
34 import com.eviware.soapui.model.testsuite.LoadTestRunContext;
35 import com.eviware.soapui.model.testsuite.LoadTestRunner;
36 import com.eviware.soapui.model.testsuite.TestCase;
37 import com.eviware.soapui.model.testsuite.TestCaseRunContext;
38 import com.eviware.soapui.model.testsuite.TestCaseRunner;
39 import com.eviware.soapui.model.testsuite.TestRunner;
40 import com.eviware.soapui.model.testsuite.TestStep;
41 import com.eviware.soapui.model.testsuite.TestStepResult;
42 import com.eviware.soapui.support.types.StringList;
43
44 /***
45 * Model holding statistics.. should be refactored into interface for different
46 * statistic models
47 *
48 * @author Ole.Matzura
49 */
50
51 public final class LoadTestStatistics extends AbstractTableModel implements Runnable
52 {
53 public final static String NO_STATS_TESTCASE_CANCEL_REASON = "NO_STATS_TESTCASE_CANCEL_REASON";
54 private final static Logger log = Logger.getLogger( LoadTestStatistics.class );
55
56 private final WsdlLoadTest loadTest;
57 private long[][] data;
58
59 private final static int MIN_COLUMN = 0;
60 private final static int MAX_COLUMN = 1;
61 private final static int AVG_COLUMN = 2;
62 private final static int LAST_COLUMN = 3;
63 private final static int CNT_COLUMN = 4;
64 private final static int TPS_COLUMN = 5;
65 private final static int BYTES_COLUMN = 6;
66 private final static int BPS_COLUMN = 7;
67 private final static int ERR_COLUMN = 8;
68 private final static int SUM_COLUMN = 9;
69 private final static int CURRENT_CNT_COLUMN = 10;
70 private final static int RATIO_COLUMN = 11;
71
72 public static final int TOTAL = -1;
73
74 public static final int DEFAULT_SAMPLE_INTERVAL = 250;
75
76 private InternalTestRunListener testRunListener;
77 private InternalTestSuiteListener testSuiteListener;
78 private InternalPropertyChangeListener propertyChangeListener;
79
80 private StatisticsHistory history;
81
82 private boolean changed;
83 private long updateFrequency = DEFAULT_SAMPLE_INTERVAL;
84 private Stack<SamplesHolder> samplesStack = new Stack<SamplesHolder>();
85 private long currentThreadCountStartTime;
86 private long totalAverageSum;
87 private boolean resetStatistics;
88 private boolean running;
89 private boolean adding;
90
91 public LoadTestStatistics( WsdlLoadTest loadTest )
92 {
93 this.loadTest = loadTest;
94
95 testRunListener = new InternalTestRunListener();
96 testSuiteListener = new InternalTestSuiteListener();
97 propertyChangeListener = new InternalPropertyChangeListener();
98
99 WsdlTestCase testCase = loadTest.getTestCase();
100 loadTest.addPropertyChangeListener( propertyChangeListener );
101 loadTest.addLoadTestRunListener( testRunListener );
102 testCase.getTestSuite().addTestSuiteListener( testSuiteListener );
103
104 for( TestStep testStep : testCase.getTestStepList() )
105 {
106 testStep.addPropertyChangeListener( propertyChangeListener );
107 }
108
109 history = new StatisticsHistory( this );
110
111 init();
112 }
113
114 private void init()
115 {
116 data = new long[getRowCount()][11];
117 }
118
119 public StatisticsHistory getHistory()
120 {
121 return history;
122 }
123
124 public int getRowCount()
125 {
126 return loadTest.getTestCase().getTestStepCount() + 1;
127 }
128
129 public WsdlLoadTest getLoadTest()
130 {
131 return loadTest;
132 }
133
134 public int getColumnCount()
135 {
136 return 12;
137 }
138
139 public String getColumnName( int columnIndex )
140 {
141 switch( columnIndex )
142 {
143 case 0 :
144 return " ";
145 case 1 :
146 return "Test Step";
147 case 2 :
148 return Statistic.MININMUM.getName();
149 case 3 :
150 return Statistic.MAXIMUM.getName();
151 case 4 :
152 return Statistic.AVERAGE.getName();
153 case 5 :
154 return Statistic.LAST.getName();
155 case 6 :
156 return Statistic.COUNT.getName();
157 case 7 :
158 return Statistic.TPS.getName();
159 case 8 :
160 return Statistic.BYTES.getName();
161 case 9 :
162 return Statistic.BPS.getName();
163 case 10 :
164 return Statistic.ERRORS.getName();
165 case 11 :
166 return Statistic.ERRORRATIO.getName();
167 }
168 return null;
169 }
170
171 public Class<?> getColumnClass( int columnIndex )
172 {
173 switch( columnIndex )
174 {
175 case 0 :
176 return Color.class;
177 case 1 :
178 return String.class;
179 case 4 :
180 case 7 :
181 return Float.class;
182 default :
183 return Long.class;
184 }
185 }
186
187 public boolean isCellEditable( int rowIndex, int columnIndex )
188 {
189 return false;
190 }
191
192 public long getStatistic( int stepIndex, Statistic statistic )
193 {
194 if( stepIndex == TOTAL )
195 stepIndex = data.length - 1;
196
197 switch( statistic )
198 {
199 case TPS :
200 case AVERAGE :
201 return data[stepIndex][statistic.getIndex()] / 100;
202 case ERRORRATIO :
203 return data[stepIndex][Statistic.COUNT.getIndex()] == 0 ? 0 :
204 (long)(((float)data[stepIndex][Statistic.ERRORS.getIndex()] / (float)data[stepIndex][Statistic.COUNT.getIndex()])*100);
205 default :
206 return data[stepIndex][statistic.getIndex()];
207 }
208 }
209
210 public Object getValueAt( int rowIndex, int columnIndex )
211 {
212 WsdlTestCase testCase = loadTest.getTestCase();
213
214 switch( columnIndex )
215 {
216 case 0 :
217 return rowIndex == testCase.getTestStepCount() ? null : ColorPalette.getColor( testCase
218 .getTestStepAt( rowIndex ) );
219 case 1 :
220 {
221 if( rowIndex == testCase.getTestStepCount() )
222 {
223 return "TestCase:";
224 }
225 else
226 {
227 return testCase.getTestStepAt( rowIndex ).getLabel();
228 }
229 }
230 case 4 :
231 case 7 :
232 return new Float( ( float )data[rowIndex][columnIndex - 2] / 100 );
233 case 11 :
234 return data[rowIndex][Statistic.COUNT.getIndex()] == 0 ? 0 :
235 (long)(((float)data[rowIndex][Statistic.ERRORS.getIndex()] / (float)data[rowIndex][Statistic.COUNT.getIndex()])*100);
236 default :
237 {
238 return data == null || rowIndex >= data.length ? new Long( 0 ) : new Long( data[rowIndex][columnIndex - 2] );
239 }
240 }
241 }
242
243 public void pushSamples( long[] samples, long[] sizes, long[] sampleCounts, long startTime, long timeTaken,
244 boolean complete )
245 {
246 if( !running || samples.length == 0 || sizes.length == 0 )
247 return;
248
249 samplesStack.push( new SamplesHolder( samples, sizes, sampleCounts, startTime, timeTaken, complete ) );
250 }
251
252 public void run()
253 {
254 while( running || !samplesStack.isEmpty() )
255 {
256 try
257 {
258 while( !samplesStack.isEmpty() )
259 {
260 SamplesHolder holder = samplesStack.pop();
261 if( holder != null )
262 addSamples( holder );
263 }
264
265 Thread.sleep( 200 );
266 }
267 catch( EmptyStackException e )
268 {
269 }
270 catch( Exception e )
271 {
272 SoapUI.logError( e );
273 }
274 }
275 }
276
277 private synchronized void addSamples( SamplesHolder holder )
278 {
279 if( adding )
280 throw new RuntimeException( "Already adding!" );
281
282 adding = true;
283
284 int totalIndex = data.length - 1;
285 if( holder.samples.length != totalIndex || holder.sizes.length != totalIndex )
286 {
287 adding = false;
288 throw new RuntimeException( "Unexpected number of samples: " + holder.samples.length + ", exptected "
289 + ( totalIndex ) );
290 }
291
292
293 if( holder.startTime < currentThreadCountStartTime )
294 {
295 adding = false;
296 return;
297 }
298
299
300 long timePassed = ( holder.startTime + holder.timeTaken ) - currentThreadCountStartTime;
301
302 if( resetStatistics )
303 {
304 for( int c = 0; c < data.length; c++ )
305 {
306 data[c][CURRENT_CNT_COLUMN] = 0;
307 data[c][AVG_COLUMN] = 0;
308 data[c][SUM_COLUMN] = 0;
309 data[c][TPS_COLUMN] = 0;
310 data[c][BYTES_COLUMN] = 0;
311 }
312
313 totalAverageSum = 0;
314 resetStatistics = false;
315 }
316
317 long totalMin = 0;
318 long totalMax = 0;
319 long totalBytes = 0;
320 long totalAvg = 0;
321 long totalSum = 0;
322 long totalLast = 0;
323
324 long threadCount = loadTest.getThreadCount();
325
326 for( int c = 0; c < holder.samples.length; c++ )
327 {
328 if( holder.sampleCounts[c] > 0 )
329 {
330
331 if( holder.complete != loadTest.getUpdateStatisticsPerTestStep() )
332 {
333 long sampleAvg = holder.samples[c] / holder.sampleCounts[c];
334
335 data[c][LAST_COLUMN] = sampleAvg;
336 data[c][CNT_COLUMN] += holder.sampleCounts[c];
337 data[c][CURRENT_CNT_COLUMN] += holder.sampleCounts[c];
338 data[c][SUM_COLUMN] += holder.samples[c];
339
340 if( sampleAvg > 0 && ( sampleAvg < data[c][MIN_COLUMN] || data[c][MIN_COLUMN] == 0 ) )
341 data[c][MIN_COLUMN] = sampleAvg;
342
343 if( sampleAvg > data[c][MAX_COLUMN] )
344 data[c][MAX_COLUMN] = sampleAvg;
345
346 float average = ( float )data[c][SUM_COLUMN] / ( float )data[c][CURRENT_CNT_COLUMN];
347
348 data[c][AVG_COLUMN] = ( long )( average * 100 );
349 data[c][BYTES_COLUMN] += holder.sizes[c];
350
351 if( timePassed > 0 )
352 {
353 if( loadTest.getCalculateTPSOnTimePassed() )
354 {
355 data[c][TPS_COLUMN] = ( data[c][CURRENT_CNT_COLUMN] * 100000 ) / timePassed;
356 data[c][BPS_COLUMN] = ( data[c][BYTES_COLUMN] * 1000 ) / timePassed;
357 }
358 else
359 {
360 data[c][TPS_COLUMN] = ( long )( data[c][AVG_COLUMN] > 0 ? ( 100000F / average ) * threadCount : 0 );
361
362 long avgBytes = data[c][CNT_COLUMN] == 0 ? 0 : data[c][BYTES_COLUMN] / data[c][CNT_COLUMN];
363 data[c][BPS_COLUMN] = ( avgBytes * data[c][TPS_COLUMN] ) / 100;
364 }
365 }
366 }
367
368 totalMin += data[c][MIN_COLUMN] * holder.sampleCounts[c];
369 totalMax += data[c][MAX_COLUMN] * holder.sampleCounts[c];
370 totalBytes += data[c][BYTES_COLUMN] * holder.sampleCounts[c];
371 totalAvg += data[c][AVG_COLUMN] * holder.sampleCounts[c];
372 totalSum += data[c][SUM_COLUMN] * holder.sampleCounts[c];
373 totalLast += data[c][LAST_COLUMN] * holder.sampleCounts[c];
374 }
375 else
376 {
377 totalMin += data[c][MIN_COLUMN];
378 totalMax += data[c][MAX_COLUMN];
379 totalBytes += data[c][BYTES_COLUMN];
380 }
381 }
382
383 if( holder.complete )
384 {
385 data[totalIndex][CNT_COLUMN]++ ;
386 data[totalIndex][CURRENT_CNT_COLUMN]++ ;
387
388 totalAverageSum += totalLast * 100;
389 data[totalIndex][AVG_COLUMN] = ( long )( ( float )totalAverageSum / ( float )data[totalIndex][CURRENT_CNT_COLUMN] );
390 data[totalIndex][BYTES_COLUMN] = totalBytes;
391
392 if( timePassed > 0 )
393 {
394 if( loadTest.getCalculateTPSOnTimePassed() )
395 {
396 data[totalIndex][TPS_COLUMN] = ( data[totalIndex][CURRENT_CNT_COLUMN] * 100000 ) / timePassed;
397 data[totalIndex][BPS_COLUMN] = ( data[totalIndex][BYTES_COLUMN] * 1000 ) / timePassed;
398 }
399 else
400 {
401 data[totalIndex][TPS_COLUMN] = ( long )( data[totalIndex][AVG_COLUMN] > 0 ? ( 10000000F / data[totalIndex][AVG_COLUMN] )
402 * threadCount
403 : 0 );
404
405 long avgBytes = data[totalIndex][CNT_COLUMN] == 0 ? 0 : data[totalIndex][BYTES_COLUMN]
406 / data[totalIndex][CNT_COLUMN];
407
408 data[totalIndex][BPS_COLUMN] = ( avgBytes * data[totalIndex][TPS_COLUMN] ) / 100;
409 }
410 }
411
412 data[totalIndex][MIN_COLUMN] = totalMin;
413 data[totalIndex][MAX_COLUMN] = totalMax;
414 data[totalIndex][SUM_COLUMN] = totalSum;
415 data[totalIndex][LAST_COLUMN] = totalLast;
416 }
417
418 if( updateFrequency == 0 )
419 fireTableDataChanged();
420 else
421 changed = true;
422
423 adding = false;
424 }
425
426 private final class Updater implements Runnable
427 {
428 public void run()
429 {
430
431 while( running || changed || !samplesStack.isEmpty() )
432 {
433 if( changed )
434 {
435 fireTableDataChanged();
436 changed = false;
437 }
438
439 if( !running && samplesStack.isEmpty() )
440 break;
441
442 try
443 {
444 Thread.sleep( updateFrequency < 1 ? 1000 : updateFrequency );
445 }
446 catch( InterruptedException e )
447 {
448 SoapUI.logError( e );
449 }
450 }
451 }
452 }
453
454 private void stop()
455 {
456 running = false;
457 }
458
459 /***
460 * Collect testresult samples
461 *
462 * @author Ole.Matzura
463 */
464
465 private class InternalTestRunListener extends LoadTestRunListenerAdapter
466 {
467 public void beforeLoadTest( LoadTestRunner loadTestRunner, LoadTestRunContext context )
468 {
469 running = true;
470 new Thread( updater, loadTestRunner.getLoadTest().getName() + " LoadTestStatistics Updater" ).start();
471 new Thread( LoadTestStatistics.this ).start();
472
473 currentThreadCountStartTime = System.currentTimeMillis();
474 totalAverageSum = 0;
475 }
476
477 @Override
478 public void afterTestStep( LoadTestRunner loadTestRunner, LoadTestRunContext context, TestCaseRunner testRunner,
479 TestCaseRunContext runContext, TestStepResult testStepResult )
480 {
481 if( loadTest.getUpdateStatisticsPerTestStep() )
482 {
483 TestCase testCase = testRunner.getTestCase();
484
485 if( testStepResult == null )
486 {
487 log.warn( "Result is null in TestCase [" + testCase.getName() + "]" );
488 return;
489 }
490
491 long[] samples = new long[testCase.getTestStepCount()];
492 long[] sizes = new long[samples.length];
493 long[] sampleCounts = new long[samples.length];
494
495 int index = testCase.getIndexOfTestStep( testStepResult.getTestStep() );
496 sampleCounts[index]++ ;
497
498 samples[index] += testStepResult.getTimeTaken();
499 sizes[index] += testStepResult.getSize();
500
501 pushSamples( samples, sizes, sampleCounts, testRunner.getStartTime(), testRunner.getTimeTaken(), false );
502 }
503 }
504
505 public void afterTestCase( LoadTestRunner loadTestRunner, LoadTestRunContext context, TestCaseRunner testRunner,
506 TestCaseRunContext runContext )
507 {
508 if(testRunner.getStatus() == TestRunner.Status.CANCELED && testRunner.getReason().equals( NO_STATS_TESTCASE_CANCEL_REASON ))
509 return;
510
511 List<TestStepResult> results = testRunner.getResults();
512 TestCase testCase = testRunner.getTestCase();
513
514 long[] samples = new long[testCase.getTestStepCount()];
515 long[] sizes = new long[samples.length];
516 long[] sampleCounts = new long[samples.length];
517
518 for( int c = 0; c < results.size(); c++ )
519 {
520 TestStepResult testStepResult = results.get( c );
521 if( testStepResult == null )
522 {
523 log.warn( "Result [" + c + "] is null in TestCase [" + testCase.getName() + "]" );
524 continue;
525 }
526
527 int index = testCase.getIndexOfTestStep( testStepResult.getTestStep() );
528 sampleCounts[index]++ ;
529
530 samples[index] += testStepResult.getTimeTaken();
531 sizes[index] += testStepResult.getSize();
532 }
533
534 pushSamples( samples, sizes, sampleCounts, testRunner.getStartTime(), testRunner.getTimeTaken(), true );
535 }
536
537 @Override
538 public void afterLoadTest( LoadTestRunner loadTestRunner, LoadTestRunContext context )
539 {
540 stop();
541 }
542 }
543
544 public int getStepCount()
545 {
546 return loadTest.getTestCase().getTestStepCount();
547 }
548
549 public void reset()
550 {
551 init();
552 fireTableDataChanged();
553 }
554
555 public void release()
556 {
557 reset();
558
559 loadTest.removeLoadTestRunListener( testRunListener );
560 loadTest.getTestCase().getTestSuite().removeTestSuiteListener( testSuiteListener );
561
562 for( TestStep testStep : loadTest.getTestCase().getTestStepList() )
563 {
564 testStep.removePropertyChangeListener( propertyChangeListener );
565 }
566 }
567
568 private class InternalTestSuiteListener extends TestSuiteListenerAdapter
569 {
570 public void testStepAdded( TestStep testStep, int index )
571 {
572 if( testStep.getTestCase() == loadTest.getTestCase() )
573 {
574 init();
575 testStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, propertyChangeListener );
576 fireTableDataChanged();
577
578 history.reset();
579 }
580 }
581
582 public void testStepRemoved( TestStep testStep, int index )
583 {
584 if( testStep.getTestCase() == loadTest.getTestCase() )
585 {
586 init();
587 testStep.removePropertyChangeListener( propertyChangeListener );
588 fireTableDataChanged();
589
590 history.reset();
591 }
592 }
593 }
594
595 private class InternalPropertyChangeListener implements PropertyChangeListener
596 {
597 public void propertyChange( PropertyChangeEvent evt )
598 {
599 if( evt.getSource() == loadTest && evt.getPropertyName().equals( WsdlLoadTest.THREADCOUNT_PROPERTY ) )
600 {
601 if( loadTest.getResetStatisticsOnThreadCountChange() )
602 {
603 resetStatistics = true;
604 currentThreadCountStartTime = System.currentTimeMillis();
605 }
606 }
607 else if( evt.getPropertyName().equals( TestStep.NAME_PROPERTY )
608 || evt.getPropertyName().equals( TestStep.DISABLED_PROPERTY ) )
609 {
610 if( evt.getSource() instanceof TestStep )
611 fireTableCellUpdated( loadTest.getTestCase().getIndexOfTestStep( ( TestStep )evt.getSource() ), 1 );
612 }
613 else if( evt.getPropertyName().equals( WsdlLoadTest.HISTORYLIMIT_PROPERTY ) )
614 {
615 if( loadTest.getHistoryLimit() == 0 )
616 history.reset();
617 }
618 }
619 }
620
621 public TestStep getTestStepAtRow( int selectedRow )
622 {
623 if( selectedRow < getRowCount() - 1 )
624 return loadTest.getTestCase().getTestStepAt( selectedRow );
625 else
626 return null;
627 }
628
629 public long getUpdateFrequency()
630 {
631 return updateFrequency;
632 }
633
634 public void setUpdateFrequency( long updateFrequency )
635 {
636 this.updateFrequency = updateFrequency;
637 }
638
639 public void addError( int stepIndex )
640 {
641 if( stepIndex != -1 )
642 {
643 data[stepIndex][ERR_COLUMN]++ ;
644 }
645
646 data[data.length - 1][ERR_COLUMN]++ ;
647 changed = true;
648 }
649
650 public synchronized StringList[] getSnapshot()
651 {
652 long[][] clone = data.clone();
653
654 StringList[] result = new StringList[getRowCount()];
655
656 for( int c = 0; c < clone.length; c++ )
657 {
658 StringList values = new StringList();
659
660 for( int columnIndex = 2; columnIndex < getColumnCount(); columnIndex++ )
661 {
662 switch( columnIndex )
663 {
664 case 4 :
665 case 7 :
666 values.add( String.valueOf( ( float )data[c][columnIndex - 2] / 100 ) );
667 break;
668 default :
669 values.add( String.valueOf( data[c][columnIndex - 2] ) );
670 }
671 }
672
673 result[c] = values;
674 }
675
676 return result;
677 }
678
679 private final static Map<Integer, Statistic> statisticIndexMap = new HashMap<Integer, Statistic>();
680
681 private Updater updater = new Updater();
682
683 public enum Statistic
684 {
685 MININMUM( MIN_COLUMN, "min", "the minimum measured teststep time" ),
686 MAXIMUM( MAX_COLUMN, "max", "the maximum measured testste time" ),
687 AVERAGE( AVG_COLUMN, "avg", "the average measured teststep time" ),
688 LAST( LAST_COLUMN, "last", "the last measured teststep time" ),
689 COUNT( CNT_COLUMN, "cnt", "the number of teststep samples measured" ),
690 TPS( TPS_COLUMN, "tps", "the number of transactions per second for this teststep" ),
691 BYTES( BYTES_COLUMN, "bytes", "the total number of bytes returned by this teststep" ),
692 BPS( BPS_COLUMN, "bps", "the number of bytes per second returned by this teststep" ),
693 ERRORS( ERR_COLUMN, "err", "the total number of assertion errors for this teststep" ),
694 SUM( SUM_COLUMN, "sum", "internal sum"),
695 CURRENT_CNT( CURRENT_CNT_COLUMN, "ccnt", "internal cnt"),
696 ERRORRATIO( RATIO_COLUMN, "rat", "the ratio between exections and failures");
697
698 private final String description;
699 private final String name;
700 private final int index;
701
702 Statistic( int index, String name, String description )
703 {
704 this.index = index;
705 this.name = name;
706 this.description = description;
707
708 statisticIndexMap.put( index, this );
709 }
710
711 public String getDescription()
712 {
713 return description;
714 }
715
716 public int getIndex()
717 {
718 return index;
719 }
720
721 public String getName()
722 {
723 return name;
724 }
725
726 public static Statistic forIndex( int column )
727 {
728 return statisticIndexMap.get( column );
729 }
730 }
731
732 /***
733 * Holds all sample values for a testcase run
734 *
735 * @author ole.matzura
736 */
737
738 private static final class SamplesHolder
739 {
740 private final long[] samples;
741 private final long[] sizes;
742 private final long[] sampleCounts;
743
744 private final long startTime;
745 private final long timeTaken;
746 private final boolean complete;
747
748 public SamplesHolder( long[] samples, long[] sizes, long[] sampleCounts, long startTime, long timeTaken,
749 boolean complete )
750 {
751 this.samples = samples;
752 this.sizes = sizes;
753 this.startTime = startTime;
754 this.timeTaken = timeTaken;
755 this.sampleCounts = sampleCounts;
756 this.complete = complete;
757 }
758 }
759
760 public synchronized void finish()
761 {
762 int sz = samplesStack.size();
763 while( sz > 0 )
764 {
765 log.info( "Waiting for " + sz + " samples.." );
766 try
767 {
768 Thread.sleep( 500 );
769 }
770 catch( InterruptedException e )
771 {
772 SoapUI.logError( e );
773 }
774 sz = samplesStack.size();
775 }
776 }
777 }