Gatling 3.4 bug with timeout after silent check - websocket

I experience a very weird behavior of Gatling with websocket silent check:
The .await(600 seconds)(check) fails with timeout after some milliseconds.
At first I explain my situation. The limitation of Gatling websocket does not allow to handle ping requests from server. So I have to cheat and invented a fancy protocol. The code with comments is below:
client may send an INITIAL event or NON-INITIAL event (not first in a sequence).
the minimum interval between INITIAL events is 3 seconds
each request initialized by client results with 2 responses: "calculation started" and "calculation result"
ping request from server may come at any time. When we pause between client events, we still may receive ping request
when we receive a ping request, we must respond.
the usual sequence of events does not depend on ping, so if ping arrived, then we must wait for one more message
exec(session => dump(session, s"The spin action: event=$eventType oneRound=$oneRound" )).
exec(_.remove(ATTR_PING_SEQ_ID))
.doIfOrElse("CLIENT_INITIAL_EVENT".equals(eventType)) {
exec(session => dump(session, s"Sending CLIENT_INITIAL_EVENT and expect 2 or 3 responses. 3 responses mean that one of them is a ping. wait for each response for ${Config.waitForResponseSec} seconds" )).
exec(
clientActionBuilder
// first response: "started calculation"
.await(Config.waitForResponseSec seconds)(check1)
// second response: "calculated result"
.await(Config.waitForResponseSec seconds)(check2)
// wait for the delay between client initial events.
// We cannot just wait because PING may come within this time and we must handle it!
// Most probably the ping will not come, so we ignore the timeout and make the check silent
.await(Config.minTimeBetweenClientInitialEventsMillis milliseconds)(check3.silent)
)
.exec(session => dump(session, s"SPIN 2 or 3 responses got" ))
// we waited for 3 messages, so if the ping came, we just send pong and do not wait for anything else
.doIf(session => Utils.getStringSessionAttribute(session, ATTR_PING_SEQ_ID, "0") != "0"){
exec(session => dump(session, s"Sending PONG for CLIENT_INITIAL_EVENT" )).
exec(pongBuilder)
}
} {
exec(session => dump(session, s"Sending NON-INITIAL_CLIENT_EVENT and expect 2 responses" )).
exec(
clientActionBuilder
// first response: "started calculation"
.await(Config.waitForResponseSec seconds)(check4)
// second response: "calculation result"
.await(Config.waitForResponseSec seconds)(check5)
)
.exec(session => dump(session, s"NON-INITIAL_CLIENT_EVENT 2 responses got" ))
// we waited for 2 messages. If ping came, then it came instead of a
// "started calculation" or "calculation result", so we have to wait for one more message
.doIf(session => Utils.getStringSessionAttribute(session, ATTR_PING_SEQ_ID, "0") != "0"){
exec(session => dump(session, s"Sending PONG for NON-INITIAL_CLIENT_EVENT" )).
exec(pongBuilder.await(Config.waitForResponseSec seconds)(check6))
.exec(session => dump(session, s"NON-INITIAL_CLIENT_EVENT PONG response got" ))
}
}
.exitHereIfFailed
.exec(_.remove(ATTR_PING_SEQ_ID))
The check for each message is the same. It is cloned because I want to see in logs which concrete check has timed out:
val checkX = ws.checkTextMessage("myCheckX")
.matching(jsonPath(matchingCondition).exists)
jsonPath("$.body.data.nextActions[0]").optional.saveAs(ATTR_NEXT_ACTION),
).check(regex("\"cId\":(.*?),(\"name\":\"Ping\")").optional.saveAs(ATTR_PING_SEQ_ID))
the actual messages are very simple:
val clientActionBuilder = ws("requestClientAction").sendText(
"""{
| "header":
| {
| "name": "Action",
| "cId": ${cId},
| "dType": 2
| },
| "body":
| {
| "type": "#TYPE#",
| "seqId":${seqId},
| "data":{
| }
| }
|}
""".stripMargin.replaceAll("[\\s\n\r]", "").replace("#TYPE#", eventType)
)
val pongBuilder = ws("requestPong").sendText(
"""{
| "header":
| {
| "name": "Ping",
| "cId": ${pingSeqId},
| "dType": 1
| },
| "body": {}
|}
""".stripMargin.replaceAll("[\\s\n\r]", "")
)
the client actions are sent in a loop untill timeout:
asLongAs(
session =>
!timeoutIsOver(startTime, testDurationMillis)
) {
exec(doClientAction())
}
The logic works as expected until the ping request comes from server. After that the ws await timeout breaks. Here is what I see in logs:
DUMP---> The client action: event=INITIAL_EVENT oneRound=false
DUMP---> Sending CLIENT_INITIAL_EVENT and expect 2 or 3 responses. wait for each response for 600 seconds
20:33:18.772 [INFO ] i.g.h.a.w.WsSendTextFrame - Sending text frame {"header":{"name":"Action","cId":103,"dType":2},"body":{}} with websocket 'gatling.http.webSocket': Scenario 'doUntilTimeout', UserId #1
20:33:18.773 [DEBUG] i.g.h.a.w.f.WsIdleState - Send text frame requestClientAction {"header":{"name":"Action","cId":103,"dType":2},"body":{}}
20:33:18.773 [DEBUG] i.g.h.c.i.WebSocketHandler - ctx.write msg=TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 164, cap: 512))
20:33:18.773 [TRACE] i.n.h.c.h.w.WebSocket08FrameEncoder - Encoding WebSocket Frame opCode=1 length=164
20:33:18.773 [DEBUG] i.g.h.a.w.f.WsIdleState - Trigger check after sending text frame
20:33:18.787 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=1
20:33:18.787 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame length=80
20:33:18.787 [DEBUG] i.g.h.c.i.WebSocketHandler - Read msg=TextWebSocketFrame(data: PooledUnsafeDirectByteBuf(ridx: 0, widx: 80, cap: 80))
20:33:18.788 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Received matching message {"header":{"cId":103,"name":"ClientAction","code":1,"dType":2}}
20:33:18.789 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Current check success
20:33:18.789 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Perform next check sequence
20:33:19.233 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=1
20:33:19.233 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame length=1480
20:33:19.233 [DEBUG] i.g.h.c.i.WebSocketHandler - Read msg=TextWebSocketFrame(data: PooledUnsafeDirectByteBuf(ridx: 0, widx: 1480, cap: 1480))
20:33:19.235 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Received matching message {"header":{"cId":37,"name":"ClientEvent","dType":2,"dId":1270},"body":{...}}
20:33:19.237 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Current check success
20:33:19.238 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Perform next check sequence
20:33:20.871 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=1
20:33:20.871 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame length=65
20:33:20.871 [DEBUG] i.g.h.c.i.WebSocketHandler - Read msg=TextWebSocketFrame(data: PooledUnsafeDirectByteBuf(ridx: 0, widx: 65, cap: 65))
20:33:20.872 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Received matching message {"header":{"cId":38,"name":"Ping","dType":2}}
20:33:20.872 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Current check success
20:33:20.872 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Check sequences completed successfully
DUMP---> 2 or 3 responses got
DUMP---> Sending PONG for CLIENT_INITIAL_EVENT
20:33:20.873 [INFO ] i.g.h.a.w.WsSendTextFrame - Sending text frame {"header":{"name":"Ping","cId":38,"dType":1},"body":{}} with websocket 'gatling.http.webSocket': Scenario 'doUntilTimeout', UserId #1
20:33:20.873 [DEBUG] i.g.h.a.w.f.WsIdleState - Send text frame requestPong {"header":{"name":"Ping","cId":38,"dType":1},"body":{}}
20:33:20.873 [DEBUG] i.g.h.c.i.WebSocketHandler - ctx.write msg=TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 65, cap: 256))
20:33:20.873 [TRACE] i.n.h.c.h.w.WebSocket08FrameEncoder - Encoding WebSocket Frame opCode=1 length=65
....
20:33:20.876 [INFO ] i.g.h.a.w.WsSendTextFrame - Sending text frame {"header":{"name":"ClientAction","cId":104,"dType":2},"body":{"type":"NON-INITIAL_CLIENT_EVENT","seqId":304,"data":{...}}} with websocket 'gatling.http.webSocket': Scenario 'doUntilTimeout', UserId #1
20:33:20.876 [DEBUG] i.g.h.a.w.f.WsIdleState - Send text frame requestClientAction {"header":{"name":"CLientAction","cId":104,"dType":2},"body":{"type":"NON-INITIAL_CLIENT_EVENT","seqId":304,"data":{...}}}
20:33:20.876 [DEBUG] i.g.h.c.i.WebSocketHandler - ctx.write msg=TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 167, cap: 512))
20:33:20.876 [TRACE] i.n.h.c.h.w.WebSocket08FrameEncoder - Encoding WebSocket Frame opCode=1 length=167
20:33:20.877 [DEBUG] i.g.h.a.w.f.WsIdleState - Trigger check after sending text frame
20:33:20.897 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=1
20:33:20.897 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame length=81
20:33:20.897 [DEBUG] i.g.h.c.i.WebSocketHandler - Read msg=TextWebSocketFrame(data: PooledUnsafeDirectByteBuf(ridx: 0, widx: 81, cap: 81))
20:33:20.898 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Received matching message {"header":{"cId":104,"name":"ClientAction","code":1,"dType":2}}
20:33:20.899 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Current check success
20:33:20.899 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Perform next check sequence
....
20:33:21.535 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=1
20:33:21.535 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame length=2275
20:33:21.535 [DEBUG] i.g.h.c.i.WebSocketHandler - Read msg=TextWebSocketFrame(data: PooledUnsafeDirectByteBuf(ridx: 0, widx: 2275, cap: 2275))
20:33:21.537 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Received matching message {"header":{"cId":39,"name":"ClientEvent","dType":2},"body":{...}}
20:33:21.540 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Current check success
20:33:21.540 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Check sequences completed successfully
DUMP---> NON-INITIAL_CLIENT_EVENT 2 responses got
....
DUMP---> Sending CLIENT_INITIAL_EVENT and expect 2 or 3 responses. wait for each response for 600 seconds
20:33:21.542 [INFO ] i.g.h.a.w.WsSendTextFrame - Sending text frame {"header":{"name":"ClientAction","cId":105,"dType":2},"body":{...}}} with websocket 'gatling.http.webSocket': Scenario 'doUntilTimeout', UserId #1
20:33:21.542 [DEBUG] i.g.h.a.w.f.WsIdleState - Send text frame requestClientAction {"header":{"name":"ClientAction","cId":105,"dType":2},"body":{...}}}
20:33:21.542 [DEBUG] i.g.h.c.i.WebSocketHandler - ctx.write msg=TextWebSocketFrame(data: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 164, cap: 512))
20:33:21.542 [TRACE] i.n.h.c.h.w.WebSocket08FrameEncoder - Encoding WebSocket Frame opCode=1 length=164
20:33:21.543 [DEBUG] i.g.h.a.w.f.WsIdleState - Trigger check after sending text frame
20:33:21.558 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame opCode=1
20:33:21.559 [TRACE] i.n.h.c.h.w.WebSocket08FrameDecoder - Decoding WebSocket Frame length=81
20:33:21.559 [DEBUG] i.g.h.c.i.WebSocketHandler - Read msg=TextWebSocketFrame(data: PooledUnsafeDirectByteBuf(ridx: 0, widx: 81, cap: 81))
20:33:21.560 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Received matching message {"header":,"cId":105,"name":"ClientAction","code":1,"dType":2}}
20:33:21.560 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Current check success
20:33:21.561 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Perform next check sequence
20:33:21.742 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Check timeout
20:33:21.743 [DEBUG] i.g.h.a.w.f.WsPerformingCheckState - Check timeout, failing it and performing next action
DUMP---> 2 or 3 responses got
20:33:21.744 [DEBUG] i.g.c.a.Exit - End user #1
20:33:21.748 [DEBUG] i.g.c.c.i.Injector - End user #doUntilTimeout
20:33:21.748 [INFO ] i.g.c.c.i.Injector - All users of scenario doUntilTimeout are stopped
20:33:21.749 [INFO ] i.g.c.c.i.Injector - Stopping
20:33:21.749 [INFO ] i.g.c.c.Controller - Injector has stopped, initiating graceful stop
I received the first message from web socket at 20:33:21.560
Then the second "await" started. It should timeout after 600 seconds,
but in fact I see the timeout right away at 20:33:21.743
I looks like a bug in Gatling. Something like timeout property reset to zero
Thanks in advance!
Andrei

Related

Nomad Artifact download issue

Operating system
Windows 10
Working on nomad - 0.11.3
Nomad Java SDK - 0.11.3.0
Nomad runs as dev mode
I am trying to download git repo using nomad job. But getting the error after loading the repo in job's allocation folder.
Error ::
2 errors occurred:
* failed to parse config:
* Root value must be object: The root value in a JSON-based configuration must be either a JSON object or a JSON array of objects.
Job file (if appropriate)
{
"id": "get_git_job",
"name": "get_git_job",
"datacenters": [
"dc1"
],
"taskGroups": [
{
"name": "get_git_group",
"tasks": [
{
"name": "get_git_task",
"driver": "raw_exec",
"resources": {
"cpu": 500,
"memoryMb": 2000
},
"artifacts": [
{
"getterSource": "github.com/hashicorp/nomad",
"relativeDest": "local/repo"
}
],
"leader": false,
"shutdownDelay": 0
}
]
}
],
"dispatched": false
}
Nomad Client logs (if appropriate)
[INFO] client.alloc_runner.task_runner.task_hook.logmon.nomad.exe: opening fifo: alloc_id=10becf73-7abc-39c6-2114-38eea708103b task=get_git_task #module=logmon path=//./pipe/get_git_task-48748a1a.stdout timestamp=2020-12-02T16:32:33.755+0530
[DEBUG] client.alloc_runner.task_runner.task_hook.artifacts: downloading artifact: alloc_id=10becf73-7abc-39c6-2114-38eea708103b task=get_git_task artifact=github.com/hashicorp/nomad
[INFO] client.alloc_runner.task_runner.task_hook.logmon.nomad.exe: opening fifo: alloc_id=10becf73-7abc-39c6-2114-38eea708103b task=get_git_task #module=logmon path=//./pipe/get_git_task-48748a1a.stderr timestamp=2020-12-02T16:32:33.761+0530
[DEBUG] client: updated allocations: index=518 total=25 pulled=22 filtered=3
[DEBUG] client: allocation updates: added=0 removed=0 updated=22 ignored=3
[DEBUG] client: allocation updates applied: added=0 removed=0 updated=22 ignored=3 errors=0
[DEBUG] nomad.deployments_watcher: deadline hit: deployment_id=64d58e2c-d695-27a8-3daa-134d90e10807 job="<ns: "default", id: "get_git_job">" rollback=false
[DEBUG] worker: dequeued evaluation: eval_id=0aa4f715-be9c-91de-e1ed-a1d9b41093bc
[DEBUG] worker.service_sched: reconciled current state with desired state: eval_id=0aa4f715-be9c-91de-e1ed-a1d9b41093bc job_id=get_git_job namespace=default results="Total changes: (place 0) (destructive 0) (inplace 0) (stop 0)
Desired Changes for "get_git_group": (place 0) (inplace 0) (destructive 0) (stop 0) (migrate 0) (ignore 1) (canary 0)"
[DEBUG] worker.service_sched: setting eval status: eval_id=0aa4f715-be9c-91de-e1ed-a1d9b41093bc job_id=get_git_job namespace=default status=complete
[DEBUG] worker: updated evaluation: eval="<Eval "0aa4f715-be9c-91de-e1ed-a1d9b41093bc" JobID: "get_git_job" Namespace: "default">"
[DEBUG] worker: ack evaluation: eval_id=0aa4f715-be9c-91de-e1ed-a1d9b41093bc
[WARN] client.alloc_runner.task_runner: some environment variables not available for rendering: alloc_id=10becf73-7abc-39c6-2114-38eea708103b task=get_git_task keys=
[ERROR] client.alloc_runner.task_runner: running driver failed: alloc_id=10becf73-7abc-39c6-2114-38eea708103b task=get_git_task error="2 errors occurred:
* failed to parse config:
* Root value must be object: The root value in a JSON-based configuration must be either a JSON object or a JSON array of objects.
"
[INFO] client.alloc_runner.task_runner: not restarting task: alloc_id=10becf73-7abc-39c6-2114-38eea708103b task=get_git_task reason="Error was unrecoverable"
[INFO] client.gc: marking allocation for GC: alloc_id=10becf73-7abc-39c6-2114-38eea708103b
[DEBUG] nomad.client: adding evaluations for rescheduling failed allocations: num_evals=1
[DEBUG] worker: dequeued evaluation: eval_id=0490184c-d395-3e65-d38b-8dabd70b9b9d
[DEBUG] worker.service_sched: reconciled current state with desired state: eval_id=0490184c-d395-3e65-d38b-8dabd70b9b9d job_id=get_git_job namespace=default results="Total changes: (place 0) (destructive 0) (inplace 0) (stop 0)
anyone can help with this.
The question is resolved with the help of the Nomad team. And the solvation is that I need to add a command configuration Bcz of the driver is raw_exec.

Apache Camel https4 client not using the same tcp port for multiple requests with keepAlive=true

Hi I am using Apache camel http4 component to send a https request with keepAlive=true but when i see the netstat after sending multiple requests I see each request opens a new TCP port to the peer.
I feel this should not be the usual behavior of keepAlive transactions, why the same TCP port is not being reused for communicating with the server and how can that be achieved if at all it can be.
Turns out this is not a keep alive problem; connections are in fact kept alive properly. The problem is that the connections as part of the pool managed by default PoolingHttpClientConnectionManager were not being reused. Both things could've been easily seen by enabling the logging for Apache's HttpClient (that's used under the hood):
Keep-Alive is being used:
2018/12/19 07:59:17:470 CET [DEBUG] wire - http-outgoing-7 << "HTTP/1.1 200 OK[\r][\n]"
2018/12/19 07:59:17:470 CET [DEBUG] wire - http-outgoing-7 << "Keep-Alive: timeout=5, max=300[\r][\n]"
2018/12/19 07:59:17:470 CET [DEBUG] wire - http-outgoing-7 << "Server: Apache-Coyote/1.1[\r][\n]"
2018/12/19 07:59:17:470 CET [DEBUG] wire - http-outgoing-7 << "Content-Encoding: gzip[\r][\n]"
2018/12/19 07:59:17:470 CET [DEBUG] wire - http-outgoing-7 << "Vary: Accept-Encoding[\r][\n]"
2018/12/19 07:59:17:470 CET [DEBUG] wire - http-outgoing-7 << "Cluster-Id: A[\r][\n]"
2018/12/19 07:59:17:470 CET [DEBUG] wire - http-outgoing-7 << "Date: Wed, 19 Dec 2018 06:59:17 GMT[\r][\n]"
2018/12/19 07:59:17:470 CET [DEBUG] wire - http-outgoing-7 << "Content-Type: text/xml[\r][\n]"
2018/12/19 07:59:17:471 CET [DEBUG] wire - http-outgoing-7 << "Content-Length: 239[\r][\n]"
2018/12/19 07:59:17:471 CET [DEBUG] wire - http-outgoing-7 << "[\r][\n]"
Connections not being reused:
2018/12/19 08:00:08:240 CET [DEBUG] PoolingHttpClientConnectionManager - Connection request: [route: {s}->https://someurl.com:443][total kept alive: 1; route allocated: 1 of 1; total allocated: 1 of 1]
2018/12/19 08:00:08:240 CET [DEBUG] DefaultManagedHttpClientConnection - http-outgoing-7: Close connection
2018/12/19 08:00:08:242 CET [DEBUG] PoolingHttpClientConnectionManager - Connection leased: [id: 8][route: {s}->https://someurl.com:443][total kept alive: 0; route allocated: 1 of 1; total allocated: 1 of 1]
Note that one can easily enable logging for HttpClient by passing some arguments to JVM at startup.
So, why are connections not being reused then? This is due to the fact that SSL is being used and the PoolingHttpClientConnectionManager used by Apache's HttpClient not allowing reuse of a connection in case the user principal from the existing connection differs from the requested connection (facilitated by DefaultUserTokenHandler). See also e.g. this Stackoverflow post. Solution is to implement a custom UserTokenHandler (or use the NullTokenHandler if that's sufficient) and configure the HttpClientBuilder accordingly.
Did you already analyze the HTTP response headers in order to check whether KeepAlive is being taken into account and with which timeout value.
Example of expected response:
HTTP/1.1 200 OK
Connection: Keep-Alive
Keep-Alive: timeout=10, max=20
Content-Type: text/html; charset=UTF-8
Date: ...
Content-Length: ...

What is the best practice to create a mock service with Citrus Automation Framework for multiple responses?

I've got Component Integration Test suite setup with Citrus Framework. In order to create a mock service for different components. I've been using simple mapping strategy with the help of XPathPayloadMappingKeyExtractor.
The challenge I've got is to create a multiple responses for different soap requests.
I've been struggling to understand the way it's responding. Any experienced person who can help me out on Citrus and Spring please ?
My Context file:
<citrus-ws:client id="ClientEndpoint"
request-url="http://localhost:8085/"/>
<citrus-ws:server id="BS_Customer_Information"
port="8085"
auto-start="true"/>
My Test Method:
#CitrusTest
public void testingServer() {
soap().client(ClientEndpoint)
.send()
.soapAction("urn:RetrieveAddressBookOP_01")
.payload(new ClassPathResource("Requests/Sample1.xml"));
soap().server(BS_Customer_Information)
.receive()
.soapAction("urn:RetrieveAddressBookOP_01");
soap().server(BS_Customer_Information)
.send()
.payload(new ClassPathResource("AtomicResponses/Response1.xml"));
soap().client(ClientEndpoint)
.receive()
.messageType(MessageType.XML);
}
Issue 1: My Soap Client times out and could not get the response
Question 1: Should the server response be parsed into Soap Env and Body ?
Question 2: Why Would it still call go to Channel Endpoint.inbound when I've already defined my response?
Console Log:
2521 DEBUG gEndpointInterceptor| Received SOAP request:
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<RetrieveAddressBookOP_01"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
2527 DEBUG r.WebServiceEndpoint| Received SOAP request:
SOAPMESSAGE [payload: <?xml version="1.0" encoding="UTF-8"?><au:RetrieveAddressBookOP_01 xmlns:au="au.com.teysau.dataservice"/>][headers: {citrus_message_id=e1311140-6ee3-415a-815e-0d162cbc03c1, citrus_message_timestamp=1490649843807, citrus_soap_action=urn:RetrieveAddressBookOP_01, citrus_http_request_uri=/, citrus_http_context_path=, citrus_http_query_params=, citrus_http_method=POST}][header-data: [<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>]][attachments: []]
2527 DEBUG annelEndpointAdapter| Forwarding request to message channel ...
2527 DEBUG t.TestContextFactory| Created new test context - using global variables: '{}'
2527 DEBUG ltCorrelationManager| Saving correlation key for 'citrus_message_correlator_ChannelEndpointAdapter:producer'
2527 DEBUG context.TestContext| Setting variable: citrus_message_correlator_ChannelEndpointAdapter:producer with value: 'citrus_message_id = 'e1311140-6ee3-415a-815e-0d162cbc03c1''
2527 DEBUG .ChannelSyncProducer| Sending message to channel: 'BS_Customer_Information.inbound'
2527 DEBUG .ChannelSyncProducer| Message to send is:
SOAPMESSAGE [payload: <?xml version="1.0" encoding="UTF-8"?><RetrieveAddressBookOP_01"/>][headers: {citrus_message_id=e1311140-6ee3-415a-815e-0d162cbc03c1, citrus_message_timestamp=1490649843807, citrus_soap_action=urn:RetrieveAddressBookOP_01, citrus_http_request_uri=/, citrus_http_context_path=, citrus_http_query_params=, citrus_http_method=POST}][header-data: [<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>]][attachments: []]
2527 INFO .ChannelSyncProducer| Message was sent to channel: 'BS_Customer_Information.inbound'
3539 WARN annelEndpointAdapter| Reply timed out after 1000ms. Did not receive reply message on reply channel
3540 DEBUG annelEndpointAdapter| Did not receive reply message - no response is simulated
3540 DEBUG r.WebServiceEndpoint| No reply message from endpoint adapter 'com.consol.citrus.channel.ChannelEndpointAdapter#6dbd0a41'
3540 WARN r.WebServiceEndpoint| No SOAP response for calling client
3542 DEBUG ageDispatcherServlet| Successfully completed request
3546 DEBUG server.Server| RESPONSE / 202 handled=true
3546 DEBUG ver.HttpChannelState| HttpChannelState#244a4722{s=DISPATCHED i=true a=null} unhandle DISPATCHED
3553 DEBUG erver.HttpConnection| org.eclipse.jetty.server.HttpConnection$SendCallback#27d2cb2e[PROCESSING][i=ResponseInfo{HTTP/1.1 202 null,-1,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback#2f1ea019] generate: NEED_HEADER (null,[p=0,l=0,c=0,r=0],true)#START
3556 DEBUG erver.HttpConnection| org.eclipse.jetty.server.HttpConnection$SendCallback#27d2cb2e[PROCESSING][i=ResponseInfo{HTTP/1.1 202 null,-1,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback#2f1ea019] generate: FLUSH ([p=0,l=114,c=8192,r=114],[p=0,l=0,c=0,r=0],true)#COMPLETING
3556 DEBUG io.WriteFlusher| write: WriteFlusher#76f08437{IDLE} [HeapByteBuffer#2c34f7c0[p=0,l=114,c=8192,r=114]={<<<HTTP/1.1 202 Acce....v20160210)\r\n\r\n>>>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}]
3557 DEBUG io.WriteFlusher| update WriteFlusher#76f08437{WRITING}:IDLE-->WRITING
3562 INFO ent.WebServiceClient| SOAP message was sent to endpoint: 'http://localhost:8085/'
3562 INFO ent.WebServiceClient| Received no SOAP response from endpoint: 'http://localhost:8085/'
3562 INFO citrus.Citrus|
3562 DEBUG citrus.Citrus| TEST STEP 1/4 SUCCESS
3562 INFO citrus.Citrus|
3562 DEBUG citrus.Citrus| TEST STEP 2/4: receive
3563 DEBUG io.ChannelEndPoint| flushed 114 SelectChannelEndPoint#1c2a40b4{/127.0.0.1:54924<->8085,Open,in,out,-,W,1092/30000,HttpConnection}{io=0,kio=0,kro=1}
3566 DEBUG nnel.ChannelConsumer| Receiving message from: BS_Customer_Information.inbound
3567 DEBUG nnel.ChannelConsumer| Received message from: BS_Customer_Information.inbound
3567 DEBUG ltCorrelationManager| Saving correlation key for 'citrus_message_correlator_BS_Customer_Information:consumer'
3567 DEBUG context.TestContext| Setting variable: citrus_message_correlator_BS_Customer_Information:consumer with value: 'citrus_message_id = 'e1311140-6ee3-415a-815e-0d162cbc03c1''
3567 DEBUG ltCorrelationManager| Saving correlated object for 'citrus_message_id = 'e1311140-6ee3-415a-815e-0d162cbc03c1''
3567 DEBUG ageValidatorRegistry| Found 3 message validators for message type: XML
3567 DEBUG mXmlMessageValidator| Start message validation ...
3567 DEBUG mXmlMessageValidator| Start XML message validation
3569 DEBUG mXmlMessageValidator| Starting XML schema validation ...
3569 WARN mXmlMessageValidator| Neither schema instance nor schema repository defined - skipping XML schema validation
3569 INFO mXmlMessageValidator| XML message validation successful: All values OK
3569 DEBUG mXmlMessageValidator| Start message header validation ...
3570 DEBUG io.WriteFlusher| update WriteFlusher#76f08437{IDLE}:WRITING-->IDLE
3570 DEBUG erver.HttpConnection| org.eclipse.jetty.server.HttpConnection$SendCallback#27d2cb2e[PROCESSING][i=ResponseInfo{HTTP/1.1 202 null,-1,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback#2f1ea019] generate: DONE ([p=114,l=114,c=8192,r=0],[p=0,l=0,c=0,r=0],true)#END
3570 DEBUG mXmlMessageValidator| Validating header element: citrus_soap_action='urn:RetrieveAddressBookOP_01': OK.
3571 INFO mXmlMessageValidator| Message header validation successful: All properties OK
3571 INFO mXmlMessageValidator| Message validation successful: All values OK
3571 INFO citrus.Citrus|
3571 DEBUG citrus.Citrus| TEST STEP 2/4 SUCCESS
3571 INFO citrus.Citrus|
3571 DEBUG citrus.Citrus| TEST STEP 3/4: send
3571 DEBUG ngCorrelationManager| Get correlation key for 'citrus_message_correlator_BS_Customer_Information:consumer'
3571 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = 'e1311140-6ee3-415a-815e-0d162cbc03c1''
3571 DEBUG .ChannelSyncConsumer| Sending message to reply channel: 'org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#66f66866'
3571 DEBUG .ChannelSyncConsumer| Message to send is:
SOAPMESSAGE [payload: <AddressBook>
<Address>
<Address_Number>14</Address_Number>
<Long_Address>Willis Street</Long_Address>
<Tax_ID>7987398</Tax_ID>
<Alpha_Name>what is alpha</Alpha_Name>
<Code>UN_</Code>
<Mailing_Name>James Bond</Mailing_Name>
<Address_Line1>take the first part of the long address</Address_Line1>
<Address_Line2>You may take the second part not</Address_Line2>
<Postal_Code>8900</Postal_Code>
<City>WLN</City>
<Country>NZ</Country>
<Prefix>233</Prefix>
<Phone_Number>025364</Phone_Number>
<Prefix_2 xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<Phone_Number2 xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<userID>s3b9d</userID>
<BatchNumber>jkdhj59</BatchNumber>
<Tansaction_Number>jkd3j29</Tansaction_Number>
<Line_Number>291597</Line_Number>
</Address>
</AddressBook>][headers: {citrus_message_id=fd946a46-f67a-405d-b118-b1b6b3d562c1, citrus_message_timestamp=1490649843443}][attachments: []]
3572 WARN emporaryReplyChannel| Reply message received but the receiving thread has exited due to a timeout:GenericMessage [payload=SOAPMESSAGE [payload: <AddressBook>
<Address>
<Address_Number>14</Address_Number>
<Long_Address>Willis Street</Long_Address>
<Tax_ID>7987398</Tax_ID>
<Alpha_Name>what is alpha</Alpha_Name>
<Code>UN_</Code>
<Mailing_Name>James Bond</Mailing_Name>
<Address_Line1>take the first part of the long address</Address_Line1>
<Address_Line2>You may take the second part not</Address_Line2>
<Postal_Code>8900</Postal_Code>
<City>WLN</City>
<Country>NZ</Country>
<Prefix>233</Prefix>
<Phone_Number>025364</Phone_Number>
<Prefix_2 xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<Phone_Number2 xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
<userID>s3b9d</userID>
<BatchNumber>jkdhj59</BatchNumber>
<Tansaction_Number>jkd3j29</Tansaction_Number>
<Line_Number>291597</Line_Number>
</Address>
</AddressBook>][headers: {citrus_message_id=fd946a46-f67a-405d-b118-b1b6b3d562c1, citrus_message_timestamp=1490649843443}][attachments: []], headers={id=cfc4eeaa-eac8-8f00-2f45-2e3fcb16fdb6, timestamp=1490649844854}]
3572 INFO .ChannelSyncConsumer| Message was sent to reply channel: 'org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel#66f66866'
3572 INFO citrus.Citrus|
3572 DEBUG citrus.Citrus| TEST STEP 3/4 SUCCESS
3572 INFO citrus.Citrus|
3572 DEBUG citrus.Citrus| TEST STEP 4/4: receive
3572 DEBUG ngCorrelationManager| Get correlation key for 'citrus_message_correlator_ClientEndpoint'
3572 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
3572 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
3575 DEBUG http.HttpParser| reset HttpParser{s=END,214 of 214}
3576 DEBUG http.HttpParser| END --> START
3576 DEBUG server.HttpChannel| HttpChannelOverHttp#4820529f{r=1,c=false,a=IDLE,uri=} handle exit, result COMPLETE
3576 DEBUG io.ChannelEndPoint| filled 0 SelectChannelEndPoint#1c2a40b4{/127.0.0.1:54924<->8085,Open,in,out,-,-,13/30000,HttpConnection}{io=0,kio=0,kro=1}
3576 DEBUG io.ChannelEndPoint| filled 0 SelectChannelEndPoint#1c2a40b4{/127.0.0.1:54924<->8085,Open,in,out,-,-,13/30000,HttpConnection}{io=0,kio=0,kro=1}
3576 DEBUG http.HttpParser| parseNext s=START HeapByteBuffer#6b681750[p=0,l=0,c=16384,r=0]={<<<>>>POST / HTTP/1.1\r\n...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}
3576 DEBUG o.AbstractConnection| fillInterested HttpConnection#2c01adea[FILLING,SelectChannelEndPoint#1c2a40b4{/127.0.0.1:54924<->8085,Open,in,out,-,-,13/30000,HttpConnection}{io=0,kio=0,kro=1}][p=HttpParser{s=START,0 of -1},g=HttpGenerator{s=START},c=HttpChannelOverHttp#4820529f{r=1,c=false,a=IDLE,uri=}]
3576 DEBUG o.AbstractConnection| FILLING-->FILLING_FILL_INTERESTED HttpConnection#2c01adea[FILLING_FILL_INTERESTED,SelectChannelEndPoint#1c2a40b4{/127.0.0.1:54924<->8085,Open,in,out,-,-,13/30000,HttpConnection}{io=0,kio=0,kro=1}][p=HttpParser{s=START,0 of -1},g=HttpGenerator{s=START},c=HttpChannelOverHttp#4820529f{r=1,c=false,a=IDLE,uri=}]
3577 DEBUG o.AbstractConnection| FILLING_FILL_INTERESTED-->FILL_INTERESTED HttpConnection#2c01adea[FILL_INTERESTED,SelectChannelEndPoint#1c2a40b4{/127.0.0.1:54924<->8085,Open,in,out,-,-,13/30000,HttpConnection}{io=0,kio=0,kro=1}][p=HttpParser{s=START,0 of -1},g=HttpGenerator{s=START},c=HttpChannelOverHttp#4820529f{r=1,c=false,a=IDLE,uri=}]
3577 DEBUG electChannelEndPoint| Local interests updating 0 -> 1 for SelectChannelEndPoint#1c2a40b4{/127.0.0.1:54924<->8085,Open,in,out,R,-,0/30000,HttpConnection}{io=1,kio=0,kro=1}
3577 DEBUG io.SelectorManager| Queued change org.eclipse.jetty.io.SelectChannelEndPoint$1#67e66c5c
3578 DEBUG io.SelectorManager| Selector loop woken up from select, 0/1 selected
3578 DEBUG io.SelectorManager| Running change org.eclipse.jetty.io.SelectChannelEndPoint$1#67e66c5c
3578 DEBUG electChannelEndPoint| Key interests updated 0 -> 1 on SelectChannelEndPoint#1c2a40b4{/127.0.0.1:54924<->8085,Open,in,out,R,-,1/30000,HttpConnection}{io=1,kio=1,kro=1}
3578 DEBUG io.SelectorManager| Selector loop waiting on select
4072 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
4072 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
4573 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
4573 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
5073 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
5073 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
5574 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
5574 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
6075 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
6075 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
6575 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
6575 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
7075 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
7075 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
7576 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
7576 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
8076 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
8076 DEBUG citrus.RetryLogger| Reply message did not arrive yet - retrying in 500ms
8576 DEBUG ltCorrelationManager| Finding correlated object for 'citrus_message_id = '69b4056a-cae6-4004-a837-41de069865b8''
8580 INFO report.JIRAConsumer| Invoking JIRA API...
works.integration.jira.exceptions.ServiceBindingException: Missing Required Properties - SUMMARY, EXMESSAGE, DETAILEDEXCEPTION, PROJECT
You have to add a fork(true) option to the first `soap().client().send()' action because the Http SOAP protocol is synchronous by nature. The first action in your test waits for a synchronous response and blocks the rest of the test case execution.
Obviously your test needs to receive some other messages before that client response with soap().server(). That is why you need to fork the client send action in the first place so the server actions can perform before the client response has arrived.
In general the SOAP components in Citrus automatically handle SOAP Envelope and SOAP body. So you just need to define the pure body content as payload. SOAP Envelope is added automatically.
Hope this is more clear now.

Gradle transforms https maven repository to http 443 request

My build.gradle is configured as:
repositories {
mavenLocal()
mavenCentral()
jcenter()
maven {
url "https://<myrepo>/repo"
}
}
However,
$ gradle build --debug
gives me:
[...]
12:01:58.487 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.IvyLoggingAdaper] setting 'https.proxyHost' to '<myrepo>'
[...]
12:01:59.070 [DEBUG] [org.gradle.internal.resource.transport.http.HttpClientHelper] Performing HTTP GET: https://repo1.maven.org/maven2/org/xbib/archive/maven-metadata.xml
12:01:59.316 [DEBUG] [org.apache.http.client.protocol.RequestAddCookies] CookieSpec selected: default
12:01:59.324 [DEBUG] [org.apache.http.client.protocol.RequestAuthCache] Auth cache not set in the context
12:01:59.325 [DEBUG] [org.apache.http.impl.conn.PoolingHttpClientConnectionManager] Connection request: [route: {tls}->http://<myrepo>:443->https://repo1.maven.org:443][total kept alive: 0; route allocated: 0 of 2; total allocated: 0 of 20]
12:01:59.336 [DEBUG] [org.apache.http.impl.conn.PoolingHttpClientConnectionManager] Connection leased: [id: 0][route: {tls}->http://<myrepo>:443->https://repo1.maven.org:443][total kept alive: 0; route allocated: 1 of 2; total allocated: 1 of 20]
12:01:59.337 [DEBUG] [org.apache.http.impl.execchain.MainClientExec] Opening connection {tls}->http://<myrepo>:443->https://repo1.maven.org:443
12:01:59.340 [DEBUG] [org.apache.http.impl.conn.DefaultHttpClientConnectionOperator] Connecting to <myrepo>/<reposerverIP>:443
12:01:59.342 [DEBUG] [org.apache.http.impl.conn.DefaultHttpClientConnectionOperator] Connection established <localIP>:49298<-><reposerverIP>:443
12:01:59.346 [DEBUG] [org.apache.http.impl.conn.DefaultHttpResponseParser] Garbage in response:
[...]
12:01:59.347 [DEBUG] [org.apache.http.impl.conn.DefaultManagedHttpClientConnection] http-outgoing-0: Close connection
12:01:59.347 [DEBUG] [org.apache.http.impl.conn.DefaultManagedHttpClientConnection] http-outgoing-0: Shutdown connection
12:01:59.348 [DEBUG] [org.apache.http.impl.execchain.MainClientExec] Connection discarded
12:01:59.348 [DEBUG] [org.apache.http.impl.conn.DefaultManagedHttpClientConnection] http-outgoing-0: Close connection
[...]
...though I don't know, why Gradle feels motivated to transform "https" configuration into "http: ... :443". Anyone having a configuration idea?
As I wasn't able to find the configuration error itself, I am happy to have the problem solved by simply
uninstalling Gradle completely
restarting Ubuntu and
installing Gradle 2.14 again.

Tuning #JmsListener

Does #JmsListener use a poller under the hood, or is it message-driven? When testing with concurrency=1, it seems to read one message per second:
2016-06-23 09:09:46.117 INFO 13044 --- [enerContainer-1] c.s.s.core.service.PolicyChangedHandler : Received: 1: This is a test
2016-06-23 09:09:46.922 INFO 13044 --- [enerContainer-1] c.s.s.core.service.PolicyChangedHandler : Received: 2: This is a test
2016-06-23 09:09:47.730 INFO 13044 --- [enerContainer-1] c.s.s.core.service.PolicyChangedHandler : Received: 3: This is a test
2016-06-23 09:09:48.535 INFO 13044 --- [enerContainer-1] c.s.s.core.service.PolicyChangedHandler : Received: 4: This is a test
2016-06-23 09:09:49.338 INFO 13044 --- [enerContainer-1] c.s.s.core.service.PolicyChangedHandler : Received: 5: This is a test
2016-06-23 09:09:50.155 INFO 13044 --- [enerContainer-1] c.s.s.core.service.PolicyChangedHandler : Received: 6: This is a test
If it is polling, how do I adjust the polling rate or increase the number of messages read per poll?
If it is message-driven, I don't why it is so slow???
Yes Spring JMSListener uses polling under the hood by default.
See DefaultMessageListenerContainer
See also the default receiveTimeout which is 1s.
The receive timeout for each attempt can be configured through the "receiveTimeout" property. setReceiveTimeout
Set the timeout to use for receive calls, in milliseconds. The default is 1000 ms, that is, 1 second.
NOTE: This value needs to be smaller than the transaction timeout used by the transaction manager (in the appropriate unit, of course). 0 indicates no timeout at all; however, this is only feasible if not running within a transaction manager and generally discouraged since such a listener container cannot cleanly shut down. A negative value such as -1 indicates a no-wait receive operation.

Resources