<commit_before>/**
 * Copyright 2011-2014 eBusiness Information, Groupe Excilys (www.ebusinessinformation.fr)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 		http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gatling.core.scenario

import io.gatling.core.action.UserEnd

import scala.concurrent.duration.{ Duration, FiniteDuration }

import io.gatling.core.assertion.Assertion
import io.gatling.core.config.Protocol
import io.gatling.core.controller.throttle.{ ThrottlingProfile, Throttling }
import io.gatling.core.pause.{ Constant, Custom, Disabled, Exponential, PauseType, UniformDuration, UniformPercentage }
import io.gatling.core.session.Expression
import io.gatling.core.structure.PopulatedScenarioBuilder

abstract class Simulation {

  private var _scenarios: List[PopulatedScenarioBuilder] = Nil
  private var _globalProtocols: List[Protocol] = Nil
  private var _assertions = Seq.empty[Assertion]
  private var _maxDuration: Option[FiniteDuration] = None
  private var _globalPauseType: PauseType = Constant
  private var _globalThrottling: Option[ThrottlingProfile] = None
  private[core] var _beforeSteps: List[() => Unit] = Nil
  private[core] var _afterSteps: List[() => Unit] = Nil

  def before(step: => Unit): Unit =
    _beforeSteps = _beforeSteps ::: List(() => step)

  def setUp(scenarios: PopulatedScenarioBuilder*): SetUp = setUp(scenarios.toList)

  def setUp(scenarios: List[PopulatedScenarioBuilder]): SetUp = {
    if (_scenarios.nonEmpty)
      throw new UnsupportedOperationException("setUp can only be called once")
    _scenarios = scenarios
    new SetUp
  }

  def after(step: => Unit): Unit =
    _afterSteps = _afterSteps ::: List(() => step)

  class SetUp {

    def protocols(ps: Protocol*): SetUp = protocols(ps.toIterable)

    def protocols(ps: Iterable[Protocol]): SetUp = {
      _globalProtocols = _globalProtocols ++ ps
      this
    }

    def assertions(asserts: Assertion*): SetUp = assertions(asserts.toIterable)

    def assertions(asserts: Iterable[Assertion]): SetUp = {
      _assertions = _assertions ++ asserts
      this
    }

    def maxDuration(duration: FiniteDuration): SetUp = {
      _maxDuration = Some(duration)
      this
    }

    def throttle(throttlingBuilders: Throttling*): SetUp = throttle(throttlingBuilders.toIterable)

    def throttle(throttlingBuilders: Iterable[Throttling]): SetUp = {

      val steps = throttlingBuilders.toList.map(_.steps).reverse.flatten
      val throttling = Throttling(steps).profile
      _globalThrottling = Some(throttling)
      this
    }

    def disablePauses = pauses(Disabled)
    def constantPauses = pauses(Constant)
    def exponentialPauses = pauses(Exponential)
    def customPauses(custom: Expression[Long]) = pauses(Custom(custom))
    def uniformPauses(plusOrMinus: Double) = pauses(UniformPercentage(plusOrMinus))
    def uniformPauses(plusOrMinus: Duration) = pauses(UniformDuration(plusOrMinus))
    def pauses(pauseType: PauseType): SetUp = {
      _globalPauseType = pauseType
      this
    }
  }

  private[core] def build: SimulationDef = {

    require(_scenarios.nonEmpty, "No scenario set up")
    require(_scenarios.map(_.scenarioBuilder.name).toSet.size == _scenarios.size, s"Scenario names must be unique but found a duplicate")
    _scenarios.foreach(scn => require(scn.scenarioBuilder.actionBuilders.nonEmpty, s"Scenario ${scn.scenarioBuilder.name} is empty"))

    // FIXME ugly: has to be started in order to build the scenario<commit_msg>Log scenario name duplicates, close #2531<commit_after>/**
 * Copyright 2011-2014 eBusiness Information, Groupe Excilys (www.ebusinessinformation.fr)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 		http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.gatling.core.scenario

import io.gatling.core.action.UserEnd

import scala.concurrent.duration.{ Duration, FiniteDuration }

import io.gatling.core.assertion.Assertion
import io.gatling.core.config.Protocol
import io.gatling.core.controller.throttle.{ ThrottlingProfile, Throttling }
import io.gatling.core.pause.{ Constant, Custom, Disabled, Exponential, PauseType, UniformDuration, UniformPercentage }
import io.gatling.core.session.Expression
import io.gatling.core.structure.PopulatedScenarioBuilder

abstract class Simulation {

  private var _scenarios: List[PopulatedScenarioBuilder] = Nil
  private var _globalProtocols: List[Protocol] = Nil
  private var _assertions = Seq.empty[Assertion]
  private var _maxDuration: Option[FiniteDuration] = None
  private var _globalPauseType: PauseType = Constant
  private var _globalThrottling: Option[ThrottlingProfile] = None
  private[core] var _beforeSteps: List[() => Unit] = Nil
  private[core] var _afterSteps: List[() => Unit] = Nil

  def before(step: => Unit): Unit =
    _beforeSteps = _beforeSteps ::: List(() => step)

  def setUp(scenarios: PopulatedScenarioBuilder*): SetUp = setUp(scenarios.toList)

  def setUp(scenarios: List[PopulatedScenarioBuilder]): SetUp = {
    if (_scenarios.nonEmpty)
      throw new UnsupportedOperationException("setUp can only be called once")
    _scenarios = scenarios
    new SetUp
  }

  def after(step: => Unit): Unit =
    _afterSteps = _afterSteps ::: List(() => step)

  class SetUp {

    def protocols(ps: Protocol*): SetUp = protocols(ps.toIterable)

    def protocols(ps: Iterable[Protocol]): SetUp = {
      _globalProtocols = _globalProtocols ++ ps
      this
    }

    def assertions(asserts: Assertion*): SetUp = assertions(asserts.toIterable)

    def assertions(asserts: Iterable[Assertion]): SetUp = {
      _assertions = _assertions ++ asserts
      this
    }

    def maxDuration(duration: FiniteDuration): SetUp = {
      _maxDuration = Some(duration)
      this
    }

    def throttle(throttlingBuilders: Throttling*): SetUp = throttle(throttlingBuilders.toIterable)

    def throttle(throttlingBuilders: Iterable[Throttling]): SetUp = {

      val steps = throttlingBuilders.toList.map(_.steps).reverse.flatten
      val throttling = Throttling(steps).profile
      _globalThrottling = Some(throttling)
      this
    }

    def disablePauses = pauses(Disabled)
    def constantPauses = pauses(Constant)
    def exponentialPauses = pauses(Exponential)
    def customPauses(custom: Expression[Long]) = pauses(Custom(custom))
    def uniformPauses(plusOrMinus: Double) = pauses(UniformPercentage(plusOrMinus))
    def uniformPauses(plusOrMinus: Duration) = pauses(UniformDuration(plusOrMinus))
    def pauses(pauseType: PauseType): SetUp = {
      _globalPauseType = pauseType
      this
    }
  }

  private[core] def build: SimulationDef = {

    require(_scenarios.nonEmpty, "No scenario set up")
    val duplicates = _scenarios.groupBy(_.scenarioBuilder.name).collect { case (name, scns) if scns.size > 1 => name }
    require(duplicates.isEmpty, s"Scenario names must be unique but found duplicates: $duplicates")
    _scenarios.foreach(scn => require(scn.scenarioBuilder.actionBuilders.nonEmpty, s"Scenario ${scn.scenarioBuilder.name} is empty"))

    // FIXME ugly: has to be started in order to build the scenario
{'fraction_non_alphanumeric': 0.09621864470235866, 'fraction_numerical': 0.003619118931735929, 'mean_word_length': 4.3462308205470315, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4231102', 'n_tokens_mistral': 2506, 'n_tokens_neox': 2394, 'n_words': 647}