Skip to content
slandelle edited this page Mar 23, 2012 · 2 revisions

OBSOLETE!!! TO BE REWRITTEN FOR 1.1.0

Purpose of the API

The Check API was created to allow easy addition of new checks to Gatling. All the built-in checks were created on top of this API. For a better understanding of Checks, we encourage you to read the Check Reference.

How checks work

Checks are like information containers: they are made to be used by a request protocol. The life cycle of a check is managed by the protocol plugin/module that uses it.

To create a check plugin, there are at least 4 components to create:

  • A Check
  • A Check Builder
  • An Extractor
  • An Extractor Factory

Check Builder

The Check Builder is the class that will be used in Gatling's DSL to use the check. It basically adds one or more methods allowing users to declare the check (eg: the header(headerName: String) method).

Extractor

The Extractor is the component responsible for the extraction of the value(s) to be checked in the response of the server. For example, the HttpHeaderExtractor allows the extraction of the headers in an HTTP response.

Extractor Factory

This component is used to get an Extractor when applying a check. It was created to be able to get either a multi-valued extractor or a single-valued extractor.

Check

As said above, the Check is a container for all the information needed to run this check, it will contain:

  • The used Extractor Factory
  • The expression for the extraction of the values in the response (eg: an XPath expression if you want to create an XPath check)
  • The strategy used to verify the information (corresponds to eq, neq, etc.)
  • The expected value of what was extracted (if required)
  • The session attribute under which the extracted value should be saved

How to create a check

To help you understand the Check API, we will suppose that the Header checks do not exist yet, and we will create it from the ground up.

Extracting the headers

The first thing to do is to verify if we already have an HTTP Header Extractor. This is where everything starts: getting the header to check it.

To do so, we create an Extractor:

class HttpHeaderExtractor(response: Response) extends Extractor {
	def extract(headerName: String): List[String] = {
		response.getHeaders.get(headerName) match {
			case null => Nil
			case l => l.toList
		}
	}
}

This extractor takes an HttpResponse as attribute as we want to extract the headers from the response. The extract method takes the expression (as a String) that identifies the element that should be extracted, in our case: the header name.

Depending on whether the header has been found or not we return Nil or a list containing the value of the header.

Note: We tried hard to have single valued extractors return a String, but it would make the API much more complicated than it is now.

Getting the extractor

To get the extractor we will need an Extractor Factory:

object HttpHeaderExtractorFactory extends ExtractorFactory[Response] {
	def getExtractor(response: Response) = new HttpHeaderExtractor(response)
}

The generic type of ExtractorFactory[T] allows you to define from where the extraction should be made. It also determines the type of the argument that should be passed to the getExtractor method.

Creating the Check

We have defined the extractor needed to get the headers from the response, now we can create the Check that will use it:

class HttpHeaderCheck(what: Session => String, strategy: (List[String], List[String]) => Boolean, expected: List[Session => String], saveAs: Option[String])
	extends HttpCheck(what, HttpHeaderExtractorFactory, strategy, expected, saveAs, CompletePageReceived)

As you can see, here our check extends HttpCheck which extends Check. The inheritance is used to add an additionnal information to the Check: the phase on which it should be processed. In our example, the check should be executed when the response has been completely received so we can use the Response object.

Finally, you can see that we used ou HttpHeaderExtractorFactory in the declaration of our class.

Creating the Check Builder

Now that we have our check, it can be used by Gatling. The last step is to provide users with a way to declare it. To add a method in the DSL we use Check Builders:

object HttpHeaderCheckBuilder {
	def header(what: Session => String) = new HttpHeaderCheckBuilder(what, CheckBuilderVerify.exists, Nil, None) with CheckBuilderFind[HttpCheckBuilder[HttpHeaderCheckBuilder]]
	def header(headerName: String): HttpHeaderCheckBuilder with CheckBuilderFind[HttpCheckBuilder[HttpHeaderCheckBuilder]] = header(interpolate(headerName))
}

class HttpHeaderCheckBuilder(what: Session => String, strategy: (List[String], List[String]) => Boolean, expected: List[Session => String], saveAs: Option[String])
		extends HttpCheckBuilder[HttpHeaderCheckBuilder](what, None, strategy, expected, saveAs, HeadersReceived) {

	private[http] def newInstance(what: Session => String, occurrence: Option[Int], strategy: (List[String], List[String]) => Boolean, expected: List[Session => String], saveAs: Option[String], when: HttpPhase) =
		new HttpHeaderCheckBuilder(what, strategy, expected, saveAs)

	private[gatling] def newInstanceWithFindOne(occurrence: Int) =
		new HttpHeaderCheckBuilder(what, strategy, expected, saveAs) with CheckBuilderVerifyOne[HttpCheckBuilder[HttpHeaderCheckBuilder]]

	private[gatling] def newInstanceWithFindAll = throw new UnsupportedOperationException("Header checks are single valued")

	private[gatling] def newInstanceWithVerify(strategy: (List[String], List[String]) => Boolean, expected: List[Session => String] = Nil) =
		new HttpHeaderCheckBuilder(what, strategy, expected, saveAs) with CheckBuilderSave[HttpCheckBuilder[HttpHeaderCheckBuilder]]

	private[gatling] def build: HttpCheck = new HttpHeaderCheck(what, strategy, expected, saveAs)
}

This is the most complicated class to create at first sight. As a matter of fact, there are several new concepts in this piece of code.

Check DSL

The DSL for checks, explained here, is ordered: check.find.verify.saveAs. If you specify a verification method (or check strategy: eq, neq, etc.), you cannot specify the valuation of the check, it will be single-valued.

To achieve this goal, we used traits to force the order:

Schema with the hierarchy of the checkbuilderXXX

Clone this wiki locally