Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.gatling.http.action.ws.fsm.WsPerformingCheckState.scala Maven / Gradle / Ivy
/*
* Copyright 2011-2021 GatlingCorp (https://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.ws.fsm
import io.gatling.commons.stats.{ KO, OK, Status }
import io.gatling.commons.util.Throwables._
import io.gatling.commons.validation.{ Failure, Success }
import io.gatling.core.action.Action
import io.gatling.core.check.Check
import io.gatling.core.session.Session
import io.gatling.http.check.ws.{ WsFrameCheck, WsFrameCheckSequence }
import io.gatling.http.client.WebSocket
import com.typesafe.scalalogging.StrictLogging
final case class WsPerformingCheckState(
fsm: WsFsm,
webSocket: WebSocket,
currentCheck: WsFrameCheck,
remainingChecks: List[WsFrameCheck],
checkSequenceStart: Long,
remainingCheckSequences: List[WsFrameCheckSequence[WsFrameCheck]],
remainingReconnects: Int,
session: Session,
next: Either[Action, SendFrame]
) extends WsState(fsm)
with StrictLogging {
import fsm._
override def onTimeout(): NextWsState = {
logger.debug(s"Check timeout")
// check timeout
// fail check, send next and goto Idle
val errorMessage = s"Check ${currentCheck.resolvedName} timeout"
val newSession = logCheckResult(session, clock.nowMillis, KO, None, Some(errorMessage))
val nextAction = next match {
case Left(n) =>
logger.debug("Check timeout, failing it and performing next action")
n
case Right(sendFrame) =>
// logging crash
logger.debug("Check timeout while trying to reconnect, failing pending send message and performing next action")
statsEngine.logCrash(session.scenario, session.groups, sendFrame.actionName, s"Couldn't reconnect: $errorMessage")
sendFrame.next
}
NextWsState(
new WsIdleState(
fsm,
newSession,
webSocket,
remainingReconnects
),
() => nextAction ! newSession
)
}
override def onTextFrameReceived(message: String, timestamp: Long): NextWsState =
if (autoReplyTextFrames(message, webSocket)) {
NextWsState(this)
} else {
currentCheck match {
case WsFrameCheck.Text(_, matchConditions, checks, _, _) =>
tryApplyingChecks(message, timestamp, matchConditions, checks)
case _ =>
logger.debug(s"Received unmatched text frame $message")
// server unmatched message, just log
logUnmatchedServerMessage(session)
NextWsState(this)
}
}
override def onBinaryFrameReceived(message: Array[Byte], timestamp: Long): NextWsState =
currentCheck match {
case WsFrameCheck.Binary(_, matchConditions, checks, _, _) =>
tryApplyingChecks(message, timestamp, matchConditions, checks)
case _ =>
logger.debug("Received unmatched binary frame")
// server unmatched message, just log
logUnmatchedServerMessage(session)
NextWsState(this)
}
override def onWebSocketClosed(code: Int, reason: String, timestamp: Long): NextWsState = {
// unexpected close, fail check
logger.debug(s"WebSocket remotely closed while in $stateName state")
cancelTimeout()
handleWebSocketCheckCrash(session, next, Some(Integer.toString(code)), reason)
}
override def onWebSocketCrashed(t: Throwable, timestamp: Long): NextWsState = {
logger.debug(s"WebSocket crashed by the server while in $stateName state", t)
cancelTimeout()
handleWebSocketCheckCrash(session, next, None, t.rootMessage)
}
private def logCheckResult(sessionWithCheckUpdate: Session, end: Long, status: Status, code: Option[String], reason: Option[String]): Session =
if (currentCheck.isSilent) {
sessionWithCheckUpdate
} else {
logResponse(sessionWithCheckUpdate, currentCheck.resolvedName, checkSequenceStart, end, status, code, reason)
}
private def tryApplyingChecks[T](message: T, timestamp: Long, matchConditions: List[Check[T]], checks: List[Check[T]]): NextWsState = {
// cache is used for both matching and checking
val preparedCache = Check.newPreparedCache
// if matchConditions isEmpty, all messages are considered to be matching
val messageMatches = matchConditions.forall {
_.check(message, session, preparedCache) match {
case _: Success[_] => true
case _ => false
}
}
if (messageMatches) {
logger.debug(s"Received matching message $message")
cancelTimeout()
// matching message, apply checks
val (sessionWithCheckUpdate, checkError) = Check.check(message, session, checks, preparedCache)
checkError match {
case Some(Failure(errorMessage)) =>
logger.debug("Check failure")
val newSession = logCheckResult(sessionWithCheckUpdate, timestamp, KO, None, Some(errorMessage))
val nextAction = next match {
case Left(n) =>
logger.debug("Check failed, performing next action")
n
case Right(sendMessage) =>
// failed to reconnect, logging crash
logger.debug("Check failed while trying to reconnect, failing pending send message and performing next action")
statsEngine.logCrash(session.scenario, session.groups, sendMessage.actionName, s"Couldn't reconnect: $errorMessage")
sendMessage.next
}
NextWsState(
new WsIdleState(fsm, newSession, webSocket, remainingReconnects),
() => nextAction ! newSession
)
case _ =>
logger.debug("Current check success")
// check success
val newSession = logCheckResult(sessionWithCheckUpdate, timestamp, OK, None, None)
remainingChecks match {
case nextCheck :: nextRemainingChecks =>
// perform next check
logger.debug("Perform next check of current check sequence")
//[fl]
//
//[fl]
NextWsState(this.copy(currentCheck = nextCheck, remainingChecks = nextRemainingChecks, session = newSession))
case _ =>
remainingCheckSequences match {
case WsFrameCheckSequence(timeout, nextCheck :: nextRemainingChecks) :: nextRemainingCheckSequences =>
logger.debug("Perform next check sequence")
// perform next CheckSequence
scheduleTimeout(timeout)
//[fl]
//
//[fl]
NextWsState(
this.copy(
currentCheck = nextCheck,
remainingChecks = nextRemainingChecks,
checkSequenceStart = timestamp,
remainingCheckSequences = nextRemainingCheckSequences,
session = newSession
)
)
case _ =>
// all check sequences complete
logger.debug("Check sequences completed successfully")
val nextStateAction =
next match {
case Left(nextAction) => () => nextAction ! newSession
case Right(sendFrame) => () => sendFrameNextAction(newSession, sendFrame)
}
NextWsState(
new WsIdleState(fsm, newSession, webSocket, remainingReconnects),
nextStateAction
)
}
}
}
} else {
logger.debug(s"Received non-matching message $message")
// server unmatched message, just log
logUnmatchedServerMessage(session)
NextWsState(this)
}
}
private def handleWebSocketCheckCrash(
session: Session,
next: Either[Action, SendFrame],
code: Option[String],
errorMessage: String
): NextWsState = {
cancelTimeout()
val fullMessage = s"WebSocket crashed while waiting for check: $errorMessage"
val newSession = logCheckResult(session, clock.nowMillis, KO, code, Some(fullMessage))
val nextAction = next match {
case Left(n) =>
// failed to connect
logger.debug("WebSocket crashed, performing next action")
n
case Right(sendTextMessage) =>
// failed to reconnect, logging crash
logger.debug("WebSocket crashed while trying to reconnect, failing pending send message and performing next action")
statsEngine.logCrash(session.scenario, session.groups, sendTextMessage.actionName, s"Couldn't reconnect: $errorMessage")
sendTextMessage.next
}
NextWsState(
new WsCrashedState(fsm, Some(errorMessage), remainingReconnects),
() => nextAction ! newSession
)
}
}