/gatling-imap

IMAP Support for Gatling

Primary LanguageScalaGNU Affero General Public License v3.0AGPL-3.0

IMAP support for Gatling

The goal of this project is to be able to support IMAP protocol into Gatling.

Supported commands

For now only the following commands are supported:

  • APPEND

  • CAPABILITY

  • CHECK

  • CLOSE

  • ENABLE

  • EXPUNGE

  • FETCH

  • GETACL (RFC-4314)

  • GETQUOTAROOT (RFC-2087)

  • IDLE (RFC-2177)

  • LIST

  • LOGIN

  • LOGOUT

  • LSUB

  • MYRIGHTS (RFC-4314)

  • NAMESPACE (RFC-2342)

  • NOOP

  • SEARCH

  • SELECT

  • STATUS

  • STORE

  • UID FETCH

  • UID SEARCH

  • UNSELECT (RFC-3691)

  • SUBSCRIBE

  • UNSUBSCRIBE

  • CREATE FOLDER

  • DELETE FOLDER

  • RENAME FOLDER

  • EXAMINE FOLDER

  • MOVE (RFC-6851)

  • COPY

  • GETQUOTA (RFC-2087)

  • SETQUOTA (RFC-2087)

  • UID COPY

  • UID EXPUNGE

  • UID MOVE

  • UID STORE

  • COMPRESS (RFC-4978)

Supported checks

  • ok: last response is OK

  • no: last response is NO

  • bad: last response is BAD

  • hasFolder(String): one LIST response contains the folder

  • hasRecent(Int): one response contains xxx RECENT

  • hasNoRecent: one response contains 0 RECENT

  • hasUid(Uid): one response contains UID xxx

  • contains(String): one response contains the provided string

  • debug: print current responses on standard output

Example

You can find a full example into ImapAuthenticationScenario. Here is the interesting part:

  val feeder = Array(Map("username"->"user1", "password"->"password")).circular
  val UserCount: Int = 10

  val scn = scenario("ImapAuthentication").feed(feeder)
    .exec(imap("Connect").connect()).exitHereIfFailed
    .exec(imap("login").login("${username}","${password}").check(ok))
    .exec(imap("list").list("", "*").check(ok, hasFolder("INBOX")))
    .exec(imap("select").select("INBOX").check(ok, hasRecent(0)))
    .exec(imap("append").append("INBOX", Some(Seq("\\Flagged")), Option.empty[Calendar],
     """From: expeditor@example.com
       |To: recipient@example.com
       |Subject: test subject
       |
       |Test content""".stripMargin).check(ok))
    .exec(imap("fetch").fetch(Seq(One(1), One(2), Range(3,5), From(3), One(8), To(1)), AttributeList("BODY", "UID")).check(ok, hasUid(Uid(1)), contains("TEXT")))


  setUp(scn.inject(constantUsersPerSec(UserCount).during(2.seconds))).protocols(imap.host("localhost"))

Configuration

You can set up the following system properties:

  • TARGET_HOSTNAME which is set to localhost by default

  • IMAP_PORT which is set to 143 by default

  • IMAP_PROTOCOL (imap or imaps) which is set to imap by default.

Tests

Hint: quick cyrus installation

To easily launch provided integration tests and gatling test, you can run a Cyrus instance with the following commands.

First run Cyrus via Docker:

$ docker run -d --name cyrus -p 143:143 linagora/cyrus-imap

Then create a user:

$ docker exec -ti cyrus bash -c 'echo password | saslpasswd2 -u test -c user1 -p'

And create its INBOX:

$ telnet localhost 143
. LOGIN cyrus cyrus
A1 CREATE user.user1
A2 CREATE user.user1.INBOX

Then you can check all is fine with a new telnet session:

$ telnet localhost 143
. LOGIN user1 password
A1 SELECT INBOX

You should obtain the following result:

$ telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
* OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE AUTH=PLAIN SASL-IR] test Cyrus IMAP v2.4.17-caldav-beta10-Debian-2.4.17+caldav~beta10-18 server ready
. LOGIN user1 password
. OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxte QUOTA MAILBOX-REFERRALS NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE LIST-EXTENDED WITHIN QRESYNC SCAN XLIST X-REPLICATION URLAUTH URLAUTH=BINARY LOGINDISABLED COMPRESS=DEFLATE IDLE] User logged in SESSIONID=<cyrus-28-1478786954-1>
A1 SELECT INBOX
* 0 EXISTS
* 0 RECENT
* FLAGS (\Answered \Flagged \Draft \Deleted \Seen)
* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen \*)] Ok
* OK [UIDVALIDITY 1478786897] Ok
* OK [UIDNEXT 1] Ok
* OK [HIGHESTMODSEQ 1] Ok
* OK [URLMECH INTERNAL] Ok
A1 OK [READ-WRITE] Completed

Launch tests

Some simple integration tests are available via:

$ sbt GatlingIt/test

Finally, execute your gatling scenarios:

$ sbt gatling:test

Or only the specified one:

$ sbt "gatling:testOnly com.linagora.gatling.imap.scenario.ImapAuthenticationScenario"

You can also pass parameter to scenario that accept it like that:

$ JAVA_OPTS="-DnumberOfMailInInbox=15 -DpercentageOfMailToExpunge=30 -DmaxDuration=20" sbt "gatling:testOnly com.linagora.gatling.imap.scenario.ImapExpungeScenario"

In the case of expunge scenario the maxDuration parameter is in minutes

Building with a local jenkins runner

You can use a custom local jenkins runner with the Jenkinsfile at the root of this project to build the project. This will automatically do for you:

  • checkout and compile the latest code of Gatling-imap project

  • launch Gatling integration tests

To launch it you need to have docker installed. From the root of this project, you can build the Jenkins runner locally yourself:

docker build -t local-jenkins-runner dockerfiles/jenkins-runner

And then you need to launch it with the Jenkinsfile:

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -v ${PWD}/dockerfiles/jenkins-runner/Jenkinsfile:/workspace/Jenkinsfile
--network=host local-jenkins-runner

If you don’t want the build to redownload everytime all the sbt dependencies (it can be heavy) you can mount your local sbt repository as a volume by adding -v $HOME/.ivy2/cache:/root/.ivy2/cache to the above command.