/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wsdl.loadtest.data; import com.eviware.soapui.model.support.LoadTestRunListenerAdapter; import com.eviware.soapui.model.support.TestSuiteListenerAdapter; import com.eviware.soapui.model.testsuite.LoadTest; import com.eviware.soapui.model.testsuite.LoadTestRunContext; import com.eviware.soapui.model.testsuite.LoadTestRunner; import com.eviware.soapui.model.testsuite.TestCase; import com.eviware.soapui.model.testsuite.TestCaseRunContext; import com.eviware.soapui.model.testsuite.TestCaseRunner; import com.eviware.soapui.model.testsuite.TestStep; import com.eviware.soapui.model.testsuite.TestStepResult; import org.apache.log4j.Logger; import javax.swing.table.AbstractTableModel; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * TableModel holding loadtest samples */ public class SamplesModel extends AbstractTableModel { private final LoadTest loadTest; private List<TestSample[]> samples = new ArrayList<TestSample[]>(); private InternalTestRunListener testRunListener; private InternalTestSuiteListener testSuiteListener; private InternalPropertyChangeListener propertyChangeListener; private TestCase testCase; private final static Logger log = Logger.getLogger(SamplesModel.class); public SamplesModel(LoadTest loadTest) { this.loadTest = loadTest; testRunListener = new InternalTestRunListener(); testSuiteListener = new InternalTestSuiteListener(); propertyChangeListener = new InternalPropertyChangeListener(); testCase = loadTest.getTestCase(); loadTest.addLoadTestRunListener(testRunListener); testCase.getTestSuite().addTestSuiteListener(testSuiteListener); for (TestStep testStep : testCase.getTestStepList()) { testStep.addPropertyChangeListener(TestStep.NAME_PROPERTY, propertyChangeListener); } } public int getRowCount() { return samples.size(); } public int getColumnCount() { return testCase.getTestStepCount(); } public Object getValueAt(int rowIndex, int columnIndex) { TestSample[] testSamples = samples.get(rowIndex); return testSamples == null ? "discarded" : testSamples[columnIndex]; } public void addSamples(TestSample[] newSamples) { if (newSamples.length != getColumnCount()) { throw new RuntimeException("Invalid number of samples reported: " + newSamples.length + ", expected " + getColumnCount()); } samples.add(newSamples); fireTableRowsInserted(samples.size() - 1, samples.size() - 1); } public Class<?> getColumnClass(int columnIndex) { return TestSample.class; } public String getColumnName(int column) { return testCase.getTestStepAt(column).getName(); } public void clear() { int size = samples.size(); if (size > 0) { samples.clear(); fireTableRowsDeleted(0, size); } } /** * Listener for collecting samples * * @author Ole.Matzura */ private class InternalTestRunListener extends LoadTestRunListenerAdapter { public void afterTestCase(LoadTestRunner loadTestRunner, LoadTestRunContext context, TestCaseRunner testRunner, TestCaseRunContext runContext) { Map<TestStep, TestSample> samplesMap = new HashMap<TestStep, TestSample>(); List<TestStepResult> results = testRunner.getResults(); for (int c = 0; c < results.size(); c++) { TestStepResult result = results.get(c); if (result == null) { log.warn("Result [" + c + "] is null in TestCase [" + testCase.getName() + "]"); continue; } TestStep testStep = result.getTestStep(); if (!samplesMap.containsKey(testStep)) { samplesMap.put(testStep, new TestSample(testStep)); } samplesMap.get(testStep).addTestStepResult(result); } TestCase testCase = loadTest.getTestCase(); TestSample[] samples = new TestSample[testCase.getTestStepCount()]; for (int c = 0; c < samples.length; c++) { samples[c] = samplesMap.get(testCase.getTestStepAt(c)); } addSamples(samples); } } public List<TestSample[]> getSamples() { return samples; } public void release() { loadTest.removeLoadTestRunListener(testRunListener); loadTest.getTestCase().getTestSuite().removeTestSuiteListener(testSuiteListener); for (TestStep testStep : loadTest.getTestCase().getTestStepList()) { testStep.removePropertyChangeListener(propertyChangeListener); } } /** * Holder for a TestSample * * @author ole.matzura */ public static final class TestSample { private final TestStep testStep; private List<TestStepResult> results; public TestSample(TestStep testStep) { this.testStep = testStep; } public void addTestStepResult(TestStepResult result) { if (result.getTestStep() != testStep) { throw new RuntimeException("Trying to add sample for false testStep [" + result.getTestStep().getName() + "], " + "expecting [" + testStep.getName() + "]"); } if (results == null) { results = new ArrayList<TestStepResult>(); } results.add(result); } public List<TestStepResult> getResults() { return results; } public int getResultCount() { return results == null ? 0 : results.size(); } public long getResultAverage() { if (results == null) { return 0; } if (results.size() == 1) { return results.get(0).getTimeTaken(); } long sum = 0; for (TestStepResult result : results) { sum += result.getTimeTaken(); } return sum / results.size(); } } private class InternalTestSuiteListener extends TestSuiteListenerAdapter { public void testStepAdded(TestStep testStep, int index) { if (testStep.getTestCase() == testCase) { testStep.addPropertyChangeListener(TestStep.NAME_PROPERTY, propertyChangeListener); // insert null entry in existing samples for (int i = 0; i < samples.size(); i++) { TestSample[] testSamples = samples.get(i); TestSample[] newSamples = new TestSample[testSamples.length + 1]; for (int c = 0; c < testSamples.length; c++) { if (c < index) { newSamples[c] = testSamples[c]; } else { newSamples[c + 1] = testSamples[c]; } } samples.set(i, newSamples); } fireTableStructureChanged(); } } public void testStepRemoved(TestStep testStep, int index) { if (testStep.getTestCase() == testCase) { testStep.removePropertyChangeListener(propertyChangeListener); // remove from samples for (int i = 0; i < samples.size(); i++) { TestSample[] testSamples = samples.get(i); TestSample[] newSamples = new TestSample[testSamples.length - 1]; for (int c = 0; c < testSamples.length; c++) { if (c < index) { newSamples[c] = testSamples[c]; } else if (c > index) { newSamples[c - 1] = testSamples[c]; } } samples.set(i, newSamples); } fireTableStructureChanged(); } } } private class InternalPropertyChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { fireTableStructureChanged(); } } }