/** * (c) Copyright 2007-2010 by emarsys eMarketing Systems AG * * This file is part of dyson. * * dyson is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * dyson is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.emarsys.dyson; import static org.testng.Assert.assertNotNull; import java.io.IOException; import java.util.Properties; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.emarsys.ecommon.concurrent.Threads; import com.emarsys.ecommon.mail.test.SmtpBomber; import com.emarsys.ecommon.test.TestData; import com.emarsys.ecommon.time.Dates; /** * Load testing unit test case. * * @author <a href="mailto:kulovits@emarsys.com">Michael "kULO" Kulovits</a> */ @Test public class DysonLoadTest { public static final boolean CLEAN_STORAGE = true; private static Logger log = LoggerFactory.getLogger( DysonLoadTest.class ); private DysonServer server; private SmtpBomber bomber; protected void createBomberAndStartDyson( Properties props ) throws IOException { //overwrite existing system properties with passed props System.getProperties().putAll( props ); this.server = new DysonServer(); this.bomber = new SmtpBomber( this.server.getJMailSession(), props ); assertNotNull( this.server ); assertNotNull( this.bomber ); assert !this.server.isRunning(); this.cleanStorage(); this.server.start(); assert this.server.isRunning(); } @AfterMethod public void stopServer() throws IOException { if( this.server != null ) { this.cleanStorage(); this.server.stop(); //await termination of storage service this.server.getStorage().awaitTermination( 5, TimeUnit.SECONDS ); } } protected void cleanStorage() throws IOException { if( CLEAN_STORAGE ) { this.server.getStorage().clearIncomingDir(); this.server.getStorage().clearProcessedDir(); } } /** * provides {@link Properties} which configure * an {@link SmtpBomber} as well as a {@link DysonServer} * which should be bombed. */ @DataProvider( name = "dysonAndBomberProperties" ) public Object[][] getDysonAndBomberPropertiesData() { TestData data = new TestData(); Properties props; //#1 props = new Properties(); props.setProperty( DysonConfig.REST_SERVER_PORT, "11080" ); props.setProperty( DysonConfig.SMTP_PORT, "11025" ); props.setProperty( DysonConfig.SMTP_MAX_CONNECTIONS, "101" ); props.setProperty( DysonConfig.SMTP_DISCARD_RECIPIENTS_ENABLED, "false" ); props.setProperty( DysonConfig.STORAGE_DIR_INCOMING, "./tmp/1/incoming" ); props.setProperty( DysonConfig.STORAGE_DIR_PROCESSED, "./tmp/1/processed" ); props.setProperty( SmtpBomber.SMTP_BOMBER_NBR_OF_MAILS, "100" ); props.setProperty( SmtpBomber.SMTP_BOMBER_MAIL_TEXT_SIZE, "1000" ); props.setProperty( SmtpBomber.SMTP_BOMBER_SEND_DELAY_MILLIS, "0" ); data.addParams( props ); //#2 props = new Properties(); props.setProperty( DysonConfig.REST_SERVER_PORT, "12080" ); props.setProperty( DysonConfig.SMTP_PORT, "12025" ); props.setProperty( DysonConfig.SMTP_MAX_CONNECTIONS, "10" ); props.setProperty( DysonConfig.SMTP_DISCARD_RECIPIENTS_ENABLED, "false" ); props.setProperty( DysonConfig.STORAGE_DIR_INCOMING, "./tmp/2/incoming" ); props.setProperty( DysonConfig.STORAGE_DIR_PROCESSED, "./tmp/2/processed" ); props.setProperty( SmtpBomber.SMTP_BOMBER_NBR_OF_MAILS, "9" ); props.setProperty( SmtpBomber.SMTP_BOMBER_MAIL_TEXT_SIZE, "1000" ); props.setProperty( SmtpBomber.SMTP_BOMBER_SEND_DELAY_MILLIS, "0" ); data.addParams( props ); //#3 props = new Properties(); props.setProperty( DysonConfig.REST_SERVER_PORT, "13080" ); props.setProperty( DysonConfig.SMTP_PORT, "13025" ); props.setProperty( DysonConfig.SMTP_MAX_CONNECTIONS, "10000" ); props.setProperty( DysonConfig.STORAGE_DIR_INCOMING, "./tmp/3/incoming" ); props.setProperty( DysonConfig.STORAGE_DIR_PROCESSED, "./tmp/3/processed" ); props.setProperty( SmtpBomber.SMTP_BOMBER_NBR_OF_MAILS, "1000" ); props.setProperty( SmtpBomber.SMTP_BOMBER_MAIL_TEXT_SIZE, "10" ); props.setProperty( SmtpBomber.SMTP_BOMBER_SEND_DELAY_MILLIS, "0" ); data.addParams( props ); return data.toArray(); } @Test( dataProvider = "dysonAndBomberProperties", enabled = true, invocationCount = 1 ) public void testLoadScenario( Properties props ) throws IOException { //initialize dyson server and smtp bomber for this testrun this.createBomberAndStartDyson( props ); //send mails and await termination of sending sevice this.bomber.sendTestMails( true ); this.waitForMailsToBeProcessed(); //log runtime information log.info( "dyson runtime information:" ); for( Entry<String, String> entry : this.server.getRuntimeInformation().entrySet() ) { log.info( entry.toString() ); } //check number of files int processedFileCount = this.server.getStorage().getProcessedMailFiles().size(); int incomingFileCount = this.server.getStorage().getIncomingMailFiles().size(); log.info( "# incoming files = {}", incomingFileCount ); log.info( "# processed files = {}", processedFileCount ); log.info( "# mails produced = {}", this.bomber.getProducedMailCount() ); log.info( "# mails sent = {}", this.bomber.getSentMailCount() ); int nbrOfMails = this.bomber.getConfiguration().get( SmtpBomber.SMTP_BOMBER_NBR_OF_MAILS ).getIntValue(); Assert.assertEquals( this.bomber.getProducedMailCount(), nbrOfMails ); Assert.assertEquals( this.bomber.getSentMailCount(), nbrOfMails); Assert.assertEquals( incomingFileCount, 0 ); Assert.assertEquals( processedFileCount, this.bomber.getSentMailCount() ); } protected void waitForMailsToBeProcessed() { //TODO get proper state handling in dyson storage in order to be able to wait for it to finish processing int sleepTime = this.bomber.getConfiguration().get( SmtpBomber.SMTP_BOMBER_NBR_OF_MAILS ).getIntValue() * 10; if( sleepTime / Dates.SECOND_IN_MILLIS <= 3 ) { sleepTime = Dates.SECOND_IN_MILLIS * 3; } log.info( "waiting {} seconds for mails to be processed", sleepTime / Dates.SECOND_IN_MILLIS ); Threads.sleepSilently( sleepTime ); } }//class DysonLoadTest