Initial commit

parents
This diff is collapsed.
package br.ufpr.inf.rp09.controller;
/**
* Classe abstrata do controlador de testes para testes com clientes JMeter.
* O teste e integralmente centralizado nesta classe.
* Esta classe e responsavel por:<ul>
* <li>configurar o plano de teste,</li>
* <li>aguardar pelo encerramento da iteracao de teste em todos os clientes</li>
* <li>direcionar os resultados para avaliacao</li>
* <li>verificar se houve transicao de estado na maquina de estados</li>
* </ul>
* @author Rodrigo Piassetta / GRR20094994
*/
public abstract class AbstractTestController {
/**
* Algoritmo obrigatorio para instanciamento de uma classe filha
*/
protected AbstractTestController() {
//cria maquina de estados
createStateMachine();
//define step inicial
initTestStep();
//cria monitor de resultados
createMonitorLogResults();
//cria o objeto que agrupa os resultados
createTestResultAggregator();
}
/**
* Cria a maquina de estados que controla o estado do sistema em teste
*/
protected abstract void createStateMachine();
/**
* Configura para a iteracao de teste inicial
*/
protected abstract void initTestStep();
/**
* Cria o monitor dos logs de resultados
*/
protected abstract void createMonitorLogResults();
/**
* Cria o objeto responsável por agrupar os resultados dos testes
*/
protected abstract void createTestResultAggregator();
/**
* Rotina de execucao de uma iteracao de teste.
*
* @throws Exception Se nao for possivel executar o plano de testes por qualquer motivo
*/
public void executeTest() throws Exception {
//configura plano de teste
configureTestPlan();
//configura monitor do log de resultados
configureMonitorLogResults();
//timestamp de inicio do teste
long testStartTime = System.currentTimeMillis();
//executa clientes de teste
runTestClients();
while(isTestRunning()); //aguarda pelo encerramento dos testes
//timestamp de encerramento do teste
long testEndTime = System.currentTimeMillis();
//processa resultados do teste
processTestResults();
//avalia e armazena resultados
evaluateTestResults(testStartTime, testEndTime);
//verifica se ha transicao de estado
checkStateTransition();
//configura para proxima iteracao
nextTestStep();
}
/**
* Configura o plano de testes
*/
protected abstract void configureTestPlan();
/**
* Configura monitor do log de resultados
*/
protected abstract void configureMonitorLogResults();
/**
* Executa o plano de testes nos clientes de teste
*
* @throws Exception Se nao for possivel executar o plano de testes por qualquer motivo
*/
protected abstract void runTestClients() throws Exception;
/**
* Verifica se o teste esta em execucao
*
* @return true se o plano de testes esta em execucao, senao false
*/
protected abstract boolean isTestRunning();
/**
* Processa os resultados dos testes
*/
protected abstract void processTestResults();
/**
* Avalia os resultados do teste
*
* @param testStartTime timestamp do inicio da iteracao
* @param testEndTime timestamp do final da iteracao
*/
protected abstract void evaluateTestResults(long testStartTime, long testEndTime);
/**
* Verifica se houve transicao de estado
*/
protected abstract void checkStateTransition();
/**
* Configura o controlado de teste para a proxima iteracao
*/
protected abstract void nextTestStep();
}
This diff is collapsed.
This diff is collapsed.
package br.ufpr.inf.rp09.exceptions;
/**
* Trata as excecoes relacionadas a argumentos de linha de comando
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public class CommandLineArgumentException extends Exception {
private static final long serialVersionUID = -7509847998279863263L;
public CommandLineArgumentException() {
super();
}
public CommandLineArgumentException(String message) {
super(message);
}
public CommandLineArgumentException(Throwable cause) {
super(cause);
}
public CommandLineArgumentException(String message, Throwable cause) {
super(message, cause);
}
public CommandLineArgumentException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package br.ufpr.inf.rp09.exceptions;
/**
* Trata as excecoes relacionadas as configuracoes do JMeter
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public class JMeterPropertiesException extends Exception {
private static final long serialVersionUID = 6037801132157343452L;
public JMeterPropertiesException() {
super();
}
public JMeterPropertiesException(String message) {
super(message);
}
public JMeterPropertiesException(Throwable cause) {
super(cause);
}
public JMeterPropertiesException(String message, Throwable cause) {
super(message, cause);
}
public JMeterPropertiesException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package br.ufpr.inf.rp09.exceptions;
/**
* Trata as excecoes relacionadas aos clientes de teste
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public class TestClientException extends Exception {
private static final long serialVersionUID = -4128752797918636012L;
public TestClientException() {
super();
}
public TestClientException(String message) {
super(message);
}
public TestClientException(Throwable cause) {
super(cause);
}
public TestClientException(String message, Throwable cause) {
super(message, cause);
}
public TestClientException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package br.ufpr.inf.rp09.statemachine;
import br.ufpr.inf.rp09.statemachine.enumerations.ModastStateEnum;
/**
* Avalia o estado do banco de dados a partir de variaveis de desempenho
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public class ModastStateEvaluator {
final static double WARMUP_THRESHOLD = 0.1;
final static double STEADY_THRESHOLD = 0.9;
final static double STRESS_THRESHOLD = 0.1;
final static double THRASHING_THRESHOLD = 1.0;
/**
* Verifica o estado no qual o banco de dados deve se encontrar
* de acordo com as variaveis de desempenho e seu estado atual
*
* @param currentState
* @param performanceVariation
* @param transactionThroughput
* @param performanceTrend
*
* @return estado do banco de dados definido pela analise das variaveis de desempenho
*/
public static ModastStateEnum getNextState(ModastStateEnum currentState, double performanceVariation, double transactionThroughput,
double performanceTrend, double transactionsTreated) {
ModastStateEnum nextState;
switch(currentState) {
case WARMUP_STATE:
nextState = warmUpStateDecision(performanceVariation);
break;
case STEADY_STATE:
nextState = steadyStateDecision(transactionThroughput);
break;
case UNDER_PRESSURE_STATE:
nextState = underPressureStateDecision(performanceVariation, transactionThroughput, transactionsTreated);
break;
case STRESS_STATE:
nextState = stressStateDecision(performanceVariation, transactionThroughput, performanceTrend);
break;
case THRASHING_STATE:
default:
nextState = currentState;
break;
}
return nextState;
}
/**
* Verifica se ha mudanca de estado quando o banco de dados se encontra em WarmUp State
*
* @param performanceVariation
*
* @return O novo estado do banco de dados definido pela analise das variaveis
*/
private static ModastStateEnum warmUpStateDecision(double performanceVariation) {
return (performanceVariation < WARMUP_THRESHOLD)?ModastStateEnum.STEADY_STATE:ModastStateEnum.WARMUP_STATE;
}
/**
* Verifica se ha mudanca de estado quando o banco de dados se encontra em Steady State
*
* @param transactionThroughput
*
* @return O novo estado do banco de dados definido pela analise das variaveis
*/
private static ModastStateEnum steadyStateDecision(double transactionThroughput) {
return (transactionThroughput > STEADY_THRESHOLD)?ModastStateEnum.STEADY_STATE:ModastStateEnum.UNDER_PRESSURE_STATE;
}
/**
* Verifica se ha mudanca de estado quando o banco de dados se encontra em Under Pressure State
*
* @param performanceVariation
* @param transactionThroughput
*
* @return O novo estado do banco de dados definido pela analise das variaveis
*/
private static ModastStateEnum underPressureStateDecision(double performanceVariation, double transactionThroughput, double transactionsTreated) {
if(performanceVariation > STRESS_THRESHOLD*transactionsTreated)
return ModastStateEnum.STRESS_STATE;
if(transactionThroughput > STEADY_THRESHOLD)
return ModastStateEnum.STEADY_STATE;
return ModastStateEnum.UNDER_PRESSURE_STATE;
}
/**
* Verifica se ha mudanca de estado quando o banco de dados se encontra em Stress State
*
* @param performanceVariation
* @param transactionThroughput
* @param performanceTrend
*
* @return O novo estado do banco de dados definido pela analise das variaveis
*/
private static ModastStateEnum stressStateDecision(double performanceVariation, double transactionThroughput, double performanceTrend) {
if(performanceTrend < THRASHING_THRESHOLD*transactionThroughput)
return ModastStateEnum.THRASHING_STATE;
if(performanceVariation <= STRESS_THRESHOLD)
return ModastStateEnum.UNDER_PRESSURE_STATE;
return ModastStateEnum.STRESS_STATE;
}
}
package br.ufpr.inf.rp09.statemachine;
import java.util.ArrayDeque;
import java.util.Deque;
import br.ufpr.inf.rp09.statemachine.enumerations.ModastStateEnum;
/**
* Implementa a maquina de estados que reflete o estado do banco de dados
* sob uma rotina de testes de stress.
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public class ModastStateMachine {
final static ModastStateEnum INITIAL_STATE = ModastStateEnum.WARMUP_STATE; //estado inicial
final static ModastStateEnum FINAL_STATE = ModastStateEnum.THRASHING_STATE; //estado final
private ModastStateEnum state; //estado atual da maquina
private Deque<Long> stackTimestampTransitions; //pilha de timestamps das transicoes de estado
private Deque<ModastStateEnum> stackStateTransitions; //pilha dos estados anteriores a transicoes
public ModastStateMachine() {
this.stackTimestampTransitions = new ArrayDeque<Long>();
this.stackStateTransitions = new ArrayDeque<ModastStateEnum>();
}
/**
* Configura a maquina de estados para seu estado inicial
*/
public void set2InitialState() {
setStateTransition(INITIAL_STATE);
}
public void setStateTransition(ModastStateEnum state) {
setStateTransition(state, System.currentTimeMillis());
}
public void setStateTransition(ModastStateEnum state, long transitionTimestamp) {
setState(state);
pushTransition(state, transitionTimestamp);
}
private void pushTransition(ModastStateEnum state, long timestamp) {
this.stackStateTransitions.push(state);
this.stackTimestampTransitions.push(timestamp);
}
public ModastStateEnum getState() {
return state;
}
private void setState(ModastStateEnum state) {
this.state = state;
}
public ModastStateEnum getFinalState() {
return FINAL_STATE;
}
}
package br.ufpr.inf.rp09.statemachine.enumerations;
/**
* Enumeracao dos possiveis estados da maquina de estados usada para os testes MoDasT
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public enum ModastStateEnum {
WARMUP_STATE,
STEADY_STATE,
UNDER_PRESSURE_STATE,
STRESS_STATE,
THRASHING_STATE;
}
package br.ufpr.inf.rp09.testdefinitions;
import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
import org.apache.jmeter.protocol.jdbc.sampler.JDBCSampler;
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jorphan.collections.HashTree;
import br.ufpr.inf.rp09.testresults.TestResultCollector;
/**
* Implementa o plano de teste a ser executado por um cliente de teste JMeter
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public final class ModastTestPlan extends HashTree {
private static final long serialVersionUID = 5441352222408389956L;
private ThreadGroup threadGroup; //controla o numero de threads executadas pelo plano de teste
private LoopController loopController; //controla o numero de iteracoes executadas por cada thread
private AbstractTestElement sampler; //executa as amostras de testes/requisicoes
private TestResultCollector testResultCollector; //recebe os resultados das amostras
public ModastTestPlan() {
super();
}
public ModastTestPlan(HashTree hashTree) {
super(hashTree);
}
public TestResultCollector getTestResultCollector() {
return this.testResultCollector;
}
public void setTestResultCollector(TestResultCollector dBTestResultCollector) {
this.testResultCollector = dBTestResultCollector;
}
public void setThreadGroup(ThreadGroup threadGroup) {
this.threadGroup = threadGroup;
}
public void setLoopController(LoopController loopController) {
this.loopController = loopController;
}
public void setSampler(JDBCSampler jdbcSampler) {
this.sampler = jdbcSampler;
}
public void setSampler(HTTPSampler httpSampler) {
this.sampler = httpSampler;
}
public void setNumThreads(int numThreads) {
this.threadGroup.setNumThreads(numThreads);
}
public int getNumThreads() {
return this.threadGroup.getNumThreads();
}
public void setNumLoops(int numLoops) {
this.loopController.setLoops(numLoops);
}
public int getNumLoops() {
return this.loopController.getLoops();
}
public void setSampleName(String name) {
this.sampler.setName(name);
}
}
package br.ufpr.inf.rp09.testdefinitions.enumerations;
/**
* Enumeracao dos possiveis casos de teste usados para os testes MoDasT
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public enum TestCaseEnum {
CONNECTIONS_STRESS_TESTCASE,
TRANSACTIONS_STRESS_TESTCASE
}
package br.ufpr.inf.rp09.testresults;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* Classe responsavel por monitorar o numero de resultados impressos no arquivo de log
* das amostras executadas durante o teste, determinando se o teste esta em andamento
* ou foi finalizado.
*
* @author Rodrigo Piassetta / GRR20094994
*/
public class MonitorLogResults {
private String logFilePath; //caminho do arquivo de log de resultados
private String sampleLabel; //rotulo identificador das amostras
private int expectedTotalRequests; //expetativa do total de amostras a serem executadas
private List<String> sampleRequesteds; //lista com o resultado de cada amostra executada
public MonitorLogResults() {
this.sampleLabel = "";
this.expectedTotalRequests = 0;
this.sampleRequesteds = new ArrayList<String>();
}
public void setLogFilePath(String filepath) {
this.logFilePath = filepath;
}
public String getLogFilePath() {
return this.logFilePath;
}
public void setSampleLabel(String label) {
this.sampleLabel = label;
}
public String getSampleLabel() {
return this.sampleLabel;
}
public void setExpectedTotalRequests(int expectedTotalRequests) {
this.expectedTotalRequests = expectedTotalRequests;
}
/**
* Verifica se o numero esperado de requisicoes foram registradas
* no arquivo de logo de resultados
*
* @return true se todas requisicoes foram registradas, senao retorna false
*/
public boolean isAllRequestsLogged() {
boolean allRequestsLogged = false;
String strNewLine;
Scanner scannerLog;
this.sampleRequesteds = new ArrayList<String>();
try {
scannerLog = new Scanner(new File(logFilePath));
while(scannerLog.hasNextLine()) {
strNewLine = scannerLog.nextLine();
if(strNewLine.contains(this.sampleLabel))
this.sampleRequesteds.add(strNewLine);
}
scannerLog.close();
} catch (FileNotFoundException e) {
return allRequestsLogged;
}
allRequestsLogged = sampleRequesteds.size() >= expectedTotalRequests;
return allRequestsLogged;
}
public List<String> getSampleRequesteds () {
return this.sampleRequesteds;
}
}
package br.ufpr.inf.rp09.testresults;
import java.util.List;
/**
* Classe responsavel por calcular as variaveis de desempenho
* a partir dos resultados dos testes
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public class PerformanceInputsCalculator {
public static double calculatePerformanceVariation(int iteration, List<Double> listTransactionsTreatedAvg) {
if((iteration - 1) == 0)
return 0.0;
double micro = 0.0;
for(double d : listTransactionsTreatedAvg) {
micro += d;
}
micro = micro / iteration;
double sum = 0.0;
for(int i = 0; i < listTransactionsTreatedAvg.size(); i++) {
double x = listTransactionsTreatedAvg.get(i) - micro;
sum += Math.pow(x, 2);
}
double delta = Math.sqrt(sum / (iteration - 1));
return delta;
}
public static double calculateTransactionTroughput(double transactionsTreatedAvg, double transactionsRequestedAvg) {
if(transactionsRequestedAvg == 0)
return 0.0;
return transactionsTreatedAvg / transactionsRequestedAvg;
}
public static double calculatePerformanceTrend() {
// TODO fix futuro
return 0.0;
}
}
package br.ufpr.inf.rp09.testresults;
import java.util.ArrayList;
import java.util.List;
import br.ufpr.inf.rp09.statemachine.enumerations.ModastStateEnum;
/**
* Classe responsavel por agrupar os resultados de cada iteracao de teste
*
* @author Rodrigo Piassetta / GRR20094994
*
*/
public class TestResultAggregator {
private List<Long> listTestStartTime; //lista com o timestamp do inicio das iteracoes do teste (indexados pela iteracao - 0-based)
private List<Long> listTestEndTime; //lista com o timestamp do encerramento das iteracoes do teste (indexados pela iteracao - 0-based)
private List<ModastStateEnum> listTestState; //lista com o estado do BD em cada iteracao do teste (indexados pela iteracao - 0-based)
private List<Long> listTransactionsRequestedTotal; //transacoes requisitadas em cada iteracao do teste (indexados pela iteracao - 0-based)
private List<Long> listTransactionsTreatedTotal; //transacoes tratadas em cada iteracao do teste (indexados pela iteracao - 0-based)
private List<Double> listTransactionsRequestedRate; //transacoes requisitadas por segundo em cada iteracao do teste (indexados pela iteracao - 0-based)
private List<Double> listTransactionsTreatedRate; //transacoes tratadas por segundo em cada iteracao do teste (indexados pela iteracao - 0-based)
private List<Double> listPerformanceVariation; //variacao de desempenho em cada iteracao do teste (indexados pela iteracao - 0-based)
private List<Double> listTransactionsThroughput; //rendimento de transacoes em cada iteracao do teste (indexados pela iteracao - 0-based)
private List<Double> listPerformanceTrend; //tendencia de desempenho em cada iteracao do teste (indexados pela iteracao - 0-based)
public TestResultAggregator() {
this.listTestStartTime = new ArrayList<Long>();
this.listTestEndTime = new ArrayList<Long>();
this.listTestState = new ArrayList<ModastStateEnum>();
this.listTransactionsRequestedTotal = new ArrayList<Long>();
this.listTransactionsTreatedTotal = new ArrayList<Long>();
this.listTransactionsRequestedRate = new ArrayList<Double>();
this.listTransactionsTreatedRate = new ArrayList<Double>();
this.listPerformanceVariation = new ArrayList<Double>();
this.listTransactionsThroughput = new ArrayList<Double>();
this.listPerformanceTrend = new ArrayList<Double>();
}
public void setTestStartTime(int index, long startTime) {
this.listTestStartTime.add(index, startTime);
}
public long getTestStartTime(int index) {
return this.listTestStartTime.get(index);
}
public List<Long> getAllTestStartTime() {
return this.listTestStartTime;
}