All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.gatling.http.action.async.AsyncProtocolActor.scala Maven / Gradle / Ivy

There is a newer version: 3.13.1
Show newest version
/**
 * Copyright 2011-2016 GatlingCorp (http://gatling.io)
 *
 * 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.http.action.async

import io.gatling.commons.stats.{ KO, OK, Status }
import io.gatling.commons.util.Maps._
import io.gatling.commons.util.ClockSingleton._
import io.gatling.core.action.Action
import io.gatling.core.akka.BaseActor
import io.gatling.core.check.CheckResult
import io.gatling.core.session.Session
import io.gatling.core.stats.StatsEngine
import io.gatling.core.stats.message.ResponseTimings
import io.gatling.http.check.async.AsyncCheck

abstract class AsyncProtocolActor(statsEngine: StatsEngine) extends BaseActor {

  protected type NextTxBasedBehaviour = AsyncTx => this.Receive

  protected def failPendingCheck(tx: AsyncTx, message: String): AsyncTx = {
    tx.check match {
      case Some(c) =>
        logResponse(tx.session, tx.requestName, KO, tx.start, nowMillis, Some(message))
        tx.copy(updates = Session.MarkAsFailedUpdate :: tx.updates, pendingCheckSuccesses = Nil, check = None)

      case _ => tx
    }
  }

  protected def setCheck(tx: AsyncTx, requestName: String, check: AsyncCheck,
                         next: Action, session: Session, nextState: NextTxBasedBehaviour): Unit = {
    logger.debug(s"setCheck blocking=${check.blocking} timeout=${check.timeout}")

    // schedule timeout
    scheduler.scheduleOnce(check.timeout) {
      self ! CheckTimeout(check)
    }

    val newTx = failPendingCheck(tx, "Check didn't succeed by the time a new one was set up")
      .applyUpdates(session)
      .copy(requestName = requestName, start = nowMillis, check = Some(check), pendingCheckSuccesses = Nil, next = next)
    context.become(nextState(newTx))

    if (!check.blocking)
      next ! newTx.session
  }

  protected def succeedPendingCheck(tx: AsyncTx, results: List[CheckResult], nextState: NextTxBasedBehaviour): Unit = {
    tx.check match {
      case Some(check) =>
        // expected count met, let's stop the check
        logResponse(tx.session, tx.requestName, OK, tx.start, nowMillis, None)

        val checkResults = results.filter(_.hasUpdate)

        val newUpdates = checkResults match {
          case Nil =>
            // nothing to save, no update
            tx.updates

          case List(checkResult) =>
            // one single value to save
            checkResult.update.getOrElse(Session.Identity) :: tx.updates

          case _ =>
            // multiple values, let's pile them up
            val mergedCaptures = checkResults
              .collect { case CheckResult(Some(value), Some(saveAs)) => saveAs -> value }
              .groupBy(_._1)
              .forceMapValues(_.flatMap(_._2 match {
                case s: Seq[Any] => s
                case v           => Seq(v)
              }))

            val newUpdates = (session: Session) => session.setAll(mergedCaptures)
            newUpdates :: tx.updates
        }

        if (check.blocking) {
          // apply updates and release blocked flow
          val newSession = tx.session.update(newUpdates)

          tx.next ! newSession
          val newTx = tx.copy(session = newSession, updates = Nil, check = None, pendingCheckSuccesses = Nil)
          context.become(nextState(newTx))

        } else {
          // add to pending updates
          val newTx = tx.copy(updates = newUpdates, check = None, pendingCheckSuccesses = Nil)
          context.become(nextState(newTx))
        }

      case _ =>
    }
  }

  protected def reconciliate(tx: AsyncTx, next: Action, session: Session, nextState: NextTxBasedBehaviour): Unit = {
    val newTx = tx.applyUpdates(session)
    context.become(nextState(newTx))
    next ! newTx.session
  }

  protected def logResponse(session: Session, requestName: String, status: Status,
                            startDate: Long, endDate: Long, errorMessage: Option[String] = None): Unit =
    statsEngine.logResponse(session, requestName, ResponseTimings(startDate, endDate), status, None, errorMessage)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy