Skip to content

Commit 44bd259

Browse files
quantranhong1999chibenwa
authored andcommitted
ISSUE-133 Adding UID STORE command
1 parent c6be8cf commit 44bd259

File tree

8 files changed

+152
-1
lines changed

8 files changed

+152
-1
lines changed

README.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ For now only the following commands are supported:
4343
- UID COPY
4444
- UID EXPUNGE
4545
- UID MOVE
46+
- UID STORE
4647

4748
== Supported checks
4849

src/it/scala-2.12/com/linagora/gatling/imap/scenario/it/ImapAuthenticationScenarioIT.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.linagora.gatling.imap.scenario.it
22

33
import com.linagora.gatling.imap.Fixture.bart
44
import com.linagora.gatling.imap.PreDef.imap
5-
import com.linagora.gatling.imap.scenario.{ImapAuthenticationScenario, ImapCapabilityScenario, ImapCheckScenario, ImapCloseScenario, ImapCopyMessageScenario, ImapCreateFolderScenario, ImapDeleteFolderScenario, ImapEnableScenario, ImapExamineFolderScenario, ImapExpungeScenario, ImapGetAclScenario, ImapGetQuotaRootScenario, ImapGetQuotaScenario, ImapIdleScenario, ImapLogoutScenario, ImapLsubScenario, ImapMoveMessageScenario, ImapMyRightsScenario, ImapNamespaceScenario, ImapNoopScenario, ImapRenameFolderScenario, ImapSearchScenario, ImapSimpleScenario, ImapStatusScenario, ImapSubscribeScenario, ImapUIDFetchScenario, ImapUidCopyMessageScenario, ImapUidExpungeMessageScenario, ImapUidMoveMessageScenario, ImapUnselectScenario, ImapUnsubscribeScenario}
5+
import com.linagora.gatling.imap.scenario.{ImapAuthenticationScenario, ImapCapabilityScenario, ImapCheckScenario, ImapCloseScenario, ImapCopyMessageScenario, ImapCreateFolderScenario, ImapDeleteFolderScenario, ImapEnableScenario, ImapExamineFolderScenario, ImapExpungeScenario, ImapGetAclScenario, ImapGetQuotaRootScenario, ImapGetQuotaScenario, ImapIdleScenario, ImapLogoutScenario, ImapLsubScenario, ImapMoveMessageScenario, ImapMyRightsScenario, ImapNamespaceScenario, ImapNoopScenario, ImapRenameFolderScenario, ImapSearchScenario, ImapSimpleScenario, ImapStatusScenario, ImapSubscribeScenario, ImapUIDFetchScenario, ImapUidCopyMessageScenario, ImapUidExpungeMessageScenario, ImapUidMoveMessageScenario, ImapUidStoreScenario, ImapUnselectScenario, ImapUnsubscribeScenario}
66
import com.linagora.gatling.imap.{CyrusServer, Fixture, JamesServer, RunningServer}
77
import io.gatling.core.feeder.FeederBuilder
88
import io.gatling.core.funspec.GatlingFunSpec
@@ -43,6 +43,9 @@ class ImapUIDFetchScenarioIT extends BaseIt(CyrusServer.start()) {
4343
scenario(ImapUIDFetchScenario(_))
4444
}
4545

46+
class ImapUidStoreScenarioIT extends BaseIt(CyrusServer.start()) {
47+
scenario(ImapUidStoreScenario(_))
48+
}
4649

4750
class ImapAuthenticationScenarioJamesIT extends BaseIt(JamesServer.start()) {
4851
scenario(ImapAuthenticationScenario(_))

src/main/scala-2.12/com/linagora/gatling/imap/action/ImapActionBuilder.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ class ImapActionBuilder(requestName: String) {
118118
def store(sequence: Expression[MessageRanges], flags: Expression[StoreFlags]): ImapStoreActionBuilder =
119119
ImapStoreActionBuilder(requestName, sequence, flags, Seq.empty)
120120

121+
def uidStore(sequence: Expression[MessageRanges], flags: Expression[StoreFlags]): ImapUidStoreActionBuilder =
122+
ImapUidStoreActionBuilder(requestName, sequence, flags, Seq.empty)
123+
121124
def status(mailbox: Expression[String], items: Expression[StatusItems]): ImapStatusActionBuilder =
122125
ImapStatusActionBuilder(requestName, mailbox, items, Seq.empty)
123126

@@ -462,6 +465,15 @@ case class ImapStoreActionBuilder(requestName: String, sequence: Expression[Mess
462465
override val actionName: String = "store-action"
463466
}
464467

468+
case class ImapUidStoreActionBuilder(requestName: String, sequence: Expression[MessageRanges], flags: Expression[StoreFlags], private val checks: Seq[ImapCheck]) extends ImapCommandActionBuilder {
469+
def check(checks: ImapCheck*): ImapUidStoreActionBuilder = copy(checks = this.checks ++ checks)
470+
471+
override def props(ctx: ImapActionContext): Props =
472+
UidStoreAction.props(ctx, requestName, checks, sequence, flags)
473+
474+
override val actionName: String = "uid-store-action"
475+
}
476+
465477
case class ImapExpungeActionBuilder(requestName: String, private val checks: Seq[ImapCheck]) extends ImapCommandActionBuilder {
466478
def check(checks: ImapCheck*): ImapExpungeActionBuilder = copy(checks = this.checks ++ checks)
467479

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.linagora.gatling.imap.action
2+
3+
import akka.actor.Props
4+
import com.linagora.gatling.imap.check.ImapCheck
5+
import com.linagora.gatling.imap.protocol.command.{MessageRanges, StoreFlags}
6+
import com.linagora.gatling.imap.protocol.{Command, UserId}
7+
import io.gatling.commons.validation.Validation
8+
import io.gatling.core.action.ValidatedActionActor
9+
import io.gatling.core.session._
10+
11+
import scala.collection.immutable.Seq
12+
13+
object UidStoreAction {
14+
def props(imapContext: ImapActionContext, requestname: String, checks: Seq[ImapCheck], sequence: Expression[MessageRanges], flags: Expression[StoreFlags]) =
15+
Props(new UidStoreAction(imapContext, requestname, checks, sequence, flags))
16+
}
17+
18+
class UidStoreAction(val imapContext: ImapActionContext, val requestName: String, override val checks: Seq[ImapCheck], sequence: Expression[MessageRanges], flags: Expression[StoreFlags]) extends ValidatedActionActor with ImapActionActor {
19+
20+
override protected def executeOrFail(session: Session): Validation[_] = {
21+
for {
22+
sequence <- sequence(session)
23+
flags <- flags(session)
24+
} yield {
25+
val id: Long = session.userId
26+
val handler = handleResponse(session, imapContext.clock.nowMillis)
27+
sessions.tell(Command.UidStore(UserId(id), sequence, flags), handler)
28+
}
29+
}
30+
}

src/main/scala-2.12/com/linagora/gatling/imap/protocol/ImapSessions.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,9 @@ private class ImapSession(client: => ImapAsyncClient, protocol: ImapProtocol) ex
192192
case cmd@Command.Store(_, _, _) =>
193193
val handler = context.actorOf(StoreHandler.props(session), genName("store"))
194194
handler forward cmd
195+
case cmd@Command.UidStore(_, _, _) =>
196+
val handler = context.actorOf(UidStoreHandler.props(session), genName("uidStore"))
197+
handler forward cmd
195198
case cmd@Command.Expunge(_) =>
196199
val handler = context.actorOf(ExpungeHandler.props(session), genName("expunge"))
197200
handler forward cmd
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.linagora.gatling.imap.protocol.command
2+
3+
import java.util.function.Consumer
4+
5+
import akka.actor.{ActorRef, Props}
6+
import com.linagora.gatling.imap.protocol.{Command, ImapResponses, Response}
7+
import com.yahoo.imapnio.async.client.ImapAsyncSession
8+
import com.yahoo.imapnio.async.request.UidStoreFlagsCommand
9+
import com.yahoo.imapnio.async.response.ImapAsyncResponse
10+
import io.gatling.core.akka.BaseActor
11+
12+
import scala.collection.immutable.Seq
13+
14+
object UidStoreHandler {
15+
def props(session: ImapAsyncSession) = Props(new UidStoreHandler(session))
16+
}
17+
18+
class UidStoreHandler(session: ImapAsyncSession) extends BaseActor {
19+
override def receive: Receive = {
20+
case Command.UidStore(userId, sequence, flags) =>
21+
logger.trace(s"UidStoreHandler for user : ${userId.value}, on actor ${self.path} responding to ${sender.path}")
22+
context.become(waitCallback(sender()))
23+
24+
val responseCallback: Consumer[ImapAsyncResponse] = responses => {
25+
import collection.JavaConverters._
26+
27+
val responsesList = ImapResponses(responses.getResponseLines.asScala.to[Seq])
28+
logger.trace(s"On response for $userId :\n ${responsesList.mkString("\n")}")
29+
self ! Response.UidStoreResult(responsesList)
30+
}
31+
32+
val errorCallback: Consumer[Exception] = e => {
33+
logger.trace(s"${getClass.getSimpleName} command failed", e)
34+
logger.error(s"${getClass.getSimpleName} command failed")
35+
sender ! e
36+
context.stop(self)
37+
}
38+
39+
val future = session.execute(new UidStoreFlagsCommand(sequence.asImap, flags.asImap, flags.action, true))
40+
future.setDoneCallback(responseCallback)
41+
future.setExceptionCallback(errorCallback)
42+
}
43+
44+
def waitCallback(sender: ActorRef): Receive = {
45+
case msg@Response.UidStoreResult(_) =>
46+
logger.trace(s"UidStoreHandler respond to ${sender.path} with $msg")
47+
sender ! msg
48+
context.stop(self)
49+
}
50+
}

src/main/scala-2.12/com/linagora/gatling/imap/protocol/package.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ package object protocol {
118118
case class Status(userId: UserId, mailbox: String, items: StatusItems) extends Command
119119

120120
case class Store(userId: UserId, sequence: MessageRanges, flags: StoreFlags) extends Command
121+
122+
case class UidStore(userId: UserId, sequence: MessageRanges, flags: StoreFlags) extends Command
121123
}
122124

123125
sealed trait Response {
@@ -199,6 +201,8 @@ package object protocol {
199201

200202
case class Stored(responses: ImapResponses) extends Response
201203

204+
case class UidStoreResult(responses: ImapResponses) extends Response
205+
202206
case class Appended(responses: ImapResponses) extends Response
203207

204208
case class Disconnected(message: String)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.linagora.gatling.imap.scenario
2+
3+
import java.util.Calendar
4+
5+
import com.linagora.gatling.imap.PreDef._
6+
import com.linagora.gatling.imap.protocol.command.FetchAttributes.AttributeList
7+
import com.linagora.gatling.imap.protocol.command.MessageRange._
8+
import com.linagora.gatling.imap.protocol.command.{MessageRanges, Silent, StoreFlags}
9+
import io.gatling.core.Predef._
10+
import io.gatling.core.feeder.FeederBuilder
11+
import io.gatling.core.scenario.Simulation
12+
import io.gatling.core.structure.ScenarioBuilder
13+
14+
import scala.collection.immutable.Seq
15+
import scala.concurrent.duration._
16+
17+
object ImapUidStoreScenario extends Simulation {
18+
private val receiveEmail = exec(imap("append").append("INBOX", Some(Seq("\\Flagged")), Option.empty[Calendar],
19+
20+
21+
|Subject: test subject
22+
|
23+
|Test content
24+
|abcdefghijklmnopqrstuvwxyz
25+
|0123456789""".stripMargin).check(ok))
26+
27+
def apply(feeder: FeederBuilder): ScenarioBuilder = scenario("Imap")
28+
.feed(feeder)
29+
.pause(1 second)
30+
.exec(imap("Connect").connect()).exitHereIfFailed
31+
.exec(imap("login").login("${username}", "${password}").check(ok))
32+
.during(1 minute) {
33+
exec(imap("list").list("", "*").check(ok, hasFolder("INBOX")))
34+
.pause(200 milli)
35+
.exec(imap("select").select("INBOX").check(ok))
36+
.pause(200 milli)
37+
.exec(receiveEmail)
38+
.pause(200 milli)
39+
.exec(imap("fetch").fetch(MessageRanges(Last()), AttributeList("BODY[HEADER]", "UID", "BODY[TEXT]")).check(ok))
40+
.pause(200 milli)
41+
.exec(imap("uidStore").uidStore(MessageRanges(Last()), StoreFlags.add(Silent.Disable(), "\\Deleted")).check(ok))
42+
.pause(200 milli)
43+
.exec(imap("expunge").expunge().check(ok))
44+
.pause(200 milli)
45+
.exec(imap("select check is empty").select("INBOX").check(hasNoExists))
46+
}
47+
48+
}

0 commit comments

Comments
 (0)