View Javadoc

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