Skip to content

Commit

Permalink
Merge with pro
Browse files Browse the repository at this point in the history
  • Loading branch information
slandelle committed Nov 1, 2015
1 parent 8c9ff71 commit 946dfa4
Show file tree
Hide file tree
Showing 28 changed files with 197 additions and 183 deletions.
Expand Up @@ -15,82 +15,48 @@
*/
package io.gatling.app

import scala.concurrent.{ Future, Await }
import scala.concurrent.duration._
import scala.util.{ Failure, Success }

import io.gatling.commons.util.ReflectionHelper._
import io.gatling.core.CoreComponents
import io.gatling.core.action.Exit
import io.gatling.core.config.GatlingConfiguration
import io.gatling.core.controller.Controller
import io.gatling.core.controller.throttle.Throttler
import io.gatling.core.scenario.SimulationParams
import io.gatling.core.stats.{ DefaultStatsEngine, StatsEngine }
import io.gatling.core.stats.writer.{ Init, ShortScenarioDescription, RunMessage }
import io.gatling.core.stats.DataWritersStatsEngine
import io.gatling.core.stats.writer.RunMessage

import akka.actor.{ Props, Actor, ActorSystem }
import akka.pattern._
import akka.util.Timeout
import akka.actor.ActorSystem

private[gatling] object CoreComponentsFactory {

val CoreComponentsFactorySystemProperty = "gatling.coreComponentsFactory"

def apply(configuration: GatlingConfiguration): CoreComponentsFactory =
sys.props.get(CoreComponentsFactorySystemProperty).map(newInstance[CoreComponentsFactory])
.getOrElse(new DefaultCoreComponentsFactory)
def apply(configuration: GatlingConfiguration): CoreComponentsFactory = {
//
//
//
//
//
//
new DefaultCoreComponentsFactory()(configuration)
}
}

private[gatling] trait CoreComponentsFactory {

def coreComponents(system: ActorSystem, simulationParams: SimulationParams, runMessage: RunMessage)(implicit configuration: GatlingConfiguration): CoreComponents
def coreComponents(system: ActorSystem, simulationParams: SimulationParams, runMessage: RunMessage): CoreComponents

def resultsProcessor(implicit configuration: GatlingConfiguration): ResultsProcessor
def runResultProcessor: RunResultProcessor
}

private[gatling] class DefaultCoreComponentsFactory extends CoreComponentsFactory {

private def newStatsEngine(system: ActorSystem, simulationParams: SimulationParams, runMessage: RunMessage)(implicit configuration: GatlingConfiguration): StatsEngine = {

implicit val dataWriterTimeOut = Timeout(5 seconds)

val dataWriters = configuration.data.dataWriters.map { dw =>
val clazz = Class.forName(dw.className).asInstanceOf[Class[Actor]]
system.actorOf(Props(clazz), clazz.getName)
}

val shortScenarioDescriptions = simulationParams.populationBuilders.map(pb => ShortScenarioDescription(pb.scenarioBuilder.name, pb.injectionProfile.userCount))

val responses = dataWriters.map(_ ? Init(configuration, simulationParams.assertions, runMessage, shortScenarioDescriptions))

def allSucceeded(responses: Seq[Any]): Boolean =
responses.map {
case b: Boolean => b
case _ => false
}.forall(identity)

implicit val dispatcher = system.dispatcher

val statsEngineF = Future.sequence(responses)
.map(allSucceeded)
.map {
case true => Success(new DefaultStatsEngine(system, dataWriters))
case false => Failure(new Exception("DataWriters didn't initialize properly"))
}

Await.result(statsEngineF, 5 seconds).get
}

def coreComponents(system: ActorSystem, simulationParams: SimulationParams, runMessage: RunMessage)(implicit configuration: GatlingConfiguration): CoreComponents = {
val statsEngine = newStatsEngine(system, simulationParams, runMessage)
private[gatling] class DefaultCoreComponentsFactory(implicit configuration: GatlingConfiguration) extends CoreComponentsFactory {

def coreComponents(system: ActorSystem, simulationParams: SimulationParams, runMessage: RunMessage): CoreComponents = {
val statsEngine = DataWritersStatsEngine(system, simulationParams, runMessage, configuration)
val throttler = Throttler(system, simulationParams)
val controller = system.actorOf(Controller.props(statsEngine, throttler, simulationParams, configuration), Controller.ControllerActorName)
val exit = system.actorOf(Exit.props(controller, statsEngine), Exit.ExitActorName)

CoreComponents(controller, throttler, statsEngine, exit)
}

def resultsProcessor(implicit configuration: GatlingConfiguration): ResultsProcessor = new DefaultResultsProcessor()
def runResultProcessor: RunResultProcessor =
new LogFileProcessor
}
15 changes: 6 additions & 9 deletions gatling-app/src/main/scala/io/gatling/app/Gatling.scala
Expand Up @@ -54,26 +54,23 @@ object Gatling {

private[app] class Gatling(selectedSimulationClass: SelectedSimulationClass)(implicit configuration: GatlingConfiguration) {

val coreComponentsFactory = CoreComponentsFactory(configuration)

def start: StatusCode = {

StringHelper.checkSupportedJavaVersion()

val runResult = runIfNecessary
coreComponentsFactory.resultsProcessor.processResults(runResult)
val coreComponentsFactory = CoreComponentsFactory(configuration)
val runResult = runIfNecessary(coreComponentsFactory)
coreComponentsFactory.runResultProcessor.processRunResult(runResult)
}

private def runIfNecessary: RunResult =
private def runIfNecessary(coreComponentsFactory: CoreComponentsFactory): RunResult =
configuration.core.directory.reportsOnly match {
case Some(reportsOnly) => RunResult(reportsOnly, hasAssertions = true)
case _ =>
if (configuration.http.enableGA) Ga.send(configuration.core.version)
// -- Run Gatling -- //
run(Selection(selectedSimulationClass))
run(Selection(selectedSimulationClass), coreComponentsFactory)
}

private def run(selection: Selection): RunResult = {
private def run(selection: Selection, coreComponentsFactory: CoreComponentsFactory): RunResult = {

// start actor system before creating simulation instance, some components might need it (e.g. shutdown hook)
val system = ActorSystem("GatlingSystem", GatlingConfiguration.loadActorSystemConfiguration())
Expand Down
Expand Up @@ -19,21 +19,21 @@ import java.lang.System.currentTimeMillis

import io.gatling.app.cli.StatusCode
import io.gatling.charts.report.{ ReportsGenerator, ReportsGenerationInputs }
import io.gatling.charts.stats.FileDataReader
import io.gatling.charts.stats.LogFileReader
import io.gatling.commons.stats.assertion.{ AssertionValidator, AssertionResult }
import io.gatling.core.config.GatlingConfiguration

trait ResultsProcessor {
trait RunResultProcessor {

def processResults(runResult: RunResult): StatusCode
def processRunResult(runResult: RunResult): StatusCode
}

class DefaultResultsProcessor(implicit configuration: GatlingConfiguration) extends ResultsProcessor {
class LogFileProcessor(implicit configuration: GatlingConfiguration) extends RunResultProcessor {

override def processResults(runResult: RunResult): StatusCode = {
override def processRunResult(runResult: RunResult): StatusCode = {
val start = currentTimeMillis

initDataReader(runResult) match {
initLogFileReader(runResult) match {
case Some(reader) =>
val assertionResults = AssertionValidator.validateAssertions(reader)

Expand All @@ -49,9 +49,9 @@ class DefaultResultsProcessor(implicit configuration: GatlingConfiguration) exte
}
}

private def initDataReader(runResult: RunResult): Option[FileDataReader] =
private def initLogFileReader(runResult: RunResult): Option[LogFileReader] =
if (reportsGenerationEnabled || runResult.hasAssertions)
Some(new FileDataReader(runResult.runId))
Some(new LogFileReader(runResult.runId))
else
None

Expand Down
Expand Up @@ -27,9 +27,9 @@ private[charts] class AllSessionsReportGenerator(reportsGenerationInputs: Report
def generate(): Unit = {
import reportsGenerationInputs._

val series = new Series[IntVsTimePlot]("All Users", dataReader.numberOfActiveSessionsPerSecond(None), List(Orange))
val series = new Series[IntVsTimePlot]("All Users", logFileReader.numberOfActiveSessionsPerSecond(None), List(Orange))

val javascript = componentLibrary.getAllUsersJs(dataReader.runStart, series)
val javascript = componentLibrary.getAllUsersJs(logFileReader.runStart, series)

new TemplateWriter(allSessionsFile(reportFolderName)).writeToFile(javascript)
}
Expand Down
Expand Up @@ -25,7 +25,7 @@ private[charts] class AssertionsReportGenerator(reportsGenerationInputs: Reports
import reportsGenerationInputs._

def generate(): Unit = {
new TemplateWriter(assertionsJUnitFile(reportFolderName)).writeToFile(new AssertionsJUnitTemplate(dataReader.runMessage, assertionResults).getOutput)
new TemplateWriter(assertionsJsonFile(reportFolderName)).writeToFile(new AssertionsJsonTemplate(dataReader.runMessage, dataReader.scenarioNames, assertionResults).getOutput)
new TemplateWriter(assertionsJUnitFile(reportFolderName)).writeToFile(new AssertionsJUnitTemplate(logFileReader.runMessage, assertionResults).getOutput)
new TemplateWriter(assertionsJsonFile(reportFolderName)).writeToFile(new AssertionsJsonTemplate(logFileReader.runMessage, logFileReader.scenarioNames, assertionResults).getOutput)
}
}
Expand Up @@ -32,28 +32,28 @@ private[charts] class GlobalReportGenerator(reportsGenerationInputs: ReportsGene
def activeSessionsChartComponent = {

val baseColors = List(Blue, Green, Red, Yellow, Cyan, Lime, Purple, Pink, LightBlue, LightOrange, LightRed, LightLime, LightPurple, LightPink)
val seriesColors = Iterator.continually(baseColors).flatten.take(dataReader.scenarioNames.size).toList
val seriesColors = Iterator.continually(baseColors).flatten.take(logFileReader.scenarioNames.size).toList

val activeSessionsSeries: Seq[Series[IntVsTimePlot]] = dataReader
val activeSessionsSeries: Seq[Series[IntVsTimePlot]] = logFileReader
.scenarioNames
.map { scenarioName => scenarioName -> dataReader.numberOfActiveSessionsPerSecond(Some(scenarioName)) }
.map { scenarioName => scenarioName -> logFileReader.numberOfActiveSessionsPerSecond(Some(scenarioName)) }
.reverse
.zip(seriesColors)
.map { case ((scenarioName, data), color) => new Series[IntVsTimePlot](scenarioName, data, List(color)) }

componentLibrary.getActiveSessionsChartComponent(dataReader.runStart, activeSessionsSeries)
componentLibrary.getActiveSessionsChartComponent(logFileReader.runStart, activeSessionsSeries)
}

def responseTimeDistributionChartComponent: Component = {
val (okDistribution, koDistribution) = dataReader.responseTimeDistribution(100, None, None)
val (okDistribution, koDistribution) = logFileReader.responseTimeDistribution(100, None, None)
val okDistributionSeries = new Series(Series.OK, okDistribution, List(Blue))
val koDistributionSeries = new Series(Series.KO, koDistribution, List(Red))

componentLibrary.getRequestDetailsResponseTimeDistributionChartComponent(okDistributionSeries, koDistributionSeries)
}

def responseTimeChartComponent: Component =
percentilesChartComponent(dataReader.responseTimePercentilesOverTime, componentLibrary.getRequestDetailsResponseTimeChartComponent, "Response Time Percentiles over Time")
percentilesChartComponent(logFileReader.responseTimePercentilesOverTime, componentLibrary.getRequestDetailsResponseTimeChartComponent, "Response Time Percentiles over Time")

def percentilesChartComponent(
dataSource: (Status, Option[String], Option[Group]) => Iterable[PercentilesVsTimePlot],
Expand All @@ -63,14 +63,14 @@ private[charts] class GlobalReportGenerator(reportsGenerationInputs: ReportsGene
val successData = dataSource(OK, None, None)
val successSeries = new Series[PercentilesVsTimePlot](s"$title (${Series.OK})", successData, ReportGenerator.PercentilesColors)

componentFactory(dataReader.runStart, successSeries)
componentFactory(logFileReader.runStart, successSeries)
}

def requestsChartComponent: Component =
countsChartComponent(dataReader.numberOfRequestsPerSecond, componentLibrary.getRequestsChartComponent)
countsChartComponent(logFileReader.numberOfRequestsPerSecond, componentLibrary.getRequestsChartComponent)

def responsesChartComponent: Component =
countsChartComponent(dataReader.numberOfResponsesPerSecond, componentLibrary.getResponsesChartComponent)
countsChartComponent(logFileReader.numberOfResponsesPerSecond, componentLibrary.getResponsesChartComponent)

def countsChartComponent(
dataSource: (Option[String], Option[Group]) => Seq[CountsVsTimePlot],
Expand All @@ -83,15 +83,15 @@ private[charts] class GlobalReportGenerator(reportsGenerationInputs: ReportsGene
val koPieSlice = PieSlice(Series.KO, count(counts, KO))
val pieRequestsSeries = new Series[PieSlice](Series.Distribution, Seq(okPieSlice, koPieSlice), List(Green, Red))

componentFactory(dataReader.runStart, countsSeries, pieRequestsSeries)
componentFactory(logFileReader.runStart, countsSeries, pieRequestsSeries)
}

val template = new GlobalPageTemplate(
componentLibrary.getNumberOfRequestsChartComponent(dataReader.requestNames.size),
componentLibrary.getNumberOfRequestsChartComponent(logFileReader.requestNames.size),
componentLibrary.getRequestDetailsIndicatorChartComponent,
new AssertionsTableComponent(assertionResults),
new StatisticsTableComponent,
new ErrorsTableComponent(dataReader.errors(None, None)),
new ErrorsTableComponent(logFileReader.errors(None, None)),
activeSessionsChartComponent,
responseTimeDistributionChartComponent,
responseTimeChartComponent,
Expand Down
Expand Up @@ -32,29 +32,29 @@ private[charts] class GroupDetailsReportGenerator(reportsGenerationInputs: Repor

def generateDetailPage(path: String, group: Group): Unit = {
def cumulatedResponseTimeChartComponent: Component = {
val dataSuccess = dataReader.groupCumulatedResponseTimePercentilesOverTime(OK, group)
val dataSuccess = logFileReader.groupCumulatedResponseTimePercentilesOverTime(OK, group)
val seriesSuccess = new Series[PercentilesVsTimePlot]("Group Cumulated Response Time Percentiles over Time (success)", dataSuccess, ReportGenerator.PercentilesColors)

componentLibrary.getGroupDetailsDurationChartComponent("cumulatedResponseTimeChartContainer", "Cumulated Response Time (ms)", dataReader.runStart, seriesSuccess)
componentLibrary.getGroupDetailsDurationChartComponent("cumulatedResponseTimeChartContainer", "Cumulated Response Time (ms)", logFileReader.runStart, seriesSuccess)
}

def cumulatedResponseTimeDistributionChartComponent: Component = {
val (distributionSuccess, distributionFailure) = dataReader.groupCumulatedResponseTimeDistribution(100, group)
val (distributionSuccess, distributionFailure) = logFileReader.groupCumulatedResponseTimeDistribution(100, group)
val distributionSeriesSuccess = new Series("Group cumulated response time (success)", distributionSuccess, List(Blue))
val distributionSeriesFailure = new Series("Group cumulated response time (failure)", distributionFailure, List(Red))

componentLibrary.getGroupDetailsDurationDistributionChartComponent("Group Cumulated Response Time Distribution", "cumulatedResponseTimeDistributionContainer", distributionSeriesSuccess, distributionSeriesFailure)
}

def durationChartComponent: Component = {
val dataSuccess = dataReader.groupDurationPercentilesOverTime(OK, group)
val dataSuccess = logFileReader.groupDurationPercentilesOverTime(OK, group)
val seriesSuccess = new Series[PercentilesVsTimePlot]("Group Duration Percentiles over Time (success)", dataSuccess, ReportGenerator.PercentilesColors)

componentLibrary.getGroupDetailsDurationChartComponent("durationContainer", "Duration (ms)", dataReader.runStart, seriesSuccess)
componentLibrary.getGroupDetailsDurationChartComponent("durationContainer", "Duration (ms)", logFileReader.runStart, seriesSuccess)
}

def durationDistributionChartComponent: Component = {
val (distributionSuccess, distributionFailure) = dataReader.groupDurationDistribution(100, group)
val (distributionSuccess, distributionFailure) = logFileReader.groupDurationDistribution(100, group)
val distributionSeriesSuccess = new Series("Group duration (success)", distributionSuccess, List(Blue))
val distributionSeriesFailure = new Series("Group duration (failure)", distributionFailure, List(Red))

Expand All @@ -69,7 +69,7 @@ private[charts] class GroupDetailsReportGenerator(reportsGenerationInputs: Repor
group,
statisticsComponent,
indicatorChartComponent,
new ErrorsTableComponent(dataReader.errors(None, Some(group))),
new ErrorsTableComponent(logFileReader.errors(None, Some(group))),
cumulatedResponseTimeChartComponent,
cumulatedResponseTimeDistributionChartComponent,
durationChartComponent,
Expand All @@ -79,7 +79,7 @@ private[charts] class GroupDetailsReportGenerator(reportsGenerationInputs: Repor
new TemplateWriter(groupFile(reportFolderName, path)).writeToFile(template.getOutput(configuration.core.charset))
}

dataReader.statsPaths.foreach {
logFileReader.statsPaths.foreach {
case GroupStatsPath(group) => generateDetailPage(RequestPath.path(group), group)
case _ =>
}
Expand Down
Expand Up @@ -15,11 +15,11 @@
*/
package io.gatling.charts.report

import io.gatling.charts.stats.FileDataReader
import io.gatling.charts.stats.LogFileReader
import io.gatling.commons.stats.assertion.AssertionResult

private[gatling] case class ReportsGenerationInputs(
reportFolderName: String,
dataReader: FileDataReader,
logFileReader: LogFileReader,
assertionResults: List[AssertionResult]
)
Expand Up @@ -31,7 +31,7 @@ private[gatling] class ReportsGenerator(implicit configuration: GatlingConfigura
import reportsGenerationInputs._

def hasAtLeastOneRequestReported: Boolean =
dataReader.statsPaths.exists(_.isInstanceOf[RequestStatsPath])
logFileReader.statsPaths.exists(_.isInstanceOf[RequestStatsPath])

def generateMenu(): Unit = new TemplateWriter(menuFile(reportFolderName)).writeToFile(new MenuTemplate().getOutput)

Expand All @@ -57,7 +57,7 @@ private[gatling] class ReportsGenerator(implicit configuration: GatlingConfigura

copyAssets()
generateMenu()
PageTemplate.setRunInfo(dataReader.runMessage, dataReader.runEnd)
PageTemplate.setRunInfo(logFileReader.runMessage, logFileReader.runEnd)
reportGenerators.foreach(_.generate())
generateStats()
generateAssertions()
Expand Down

0 comments on commit 946dfa4

Please sign in to comment.