10
10
package main
11
11
12
12
import (
13
+ "fmt"
13
14
"strconv"
15
+ "strings"
14
16
"testing"
15
17
16
18
"github.com/ibm-messaging/mq-golang-jms20/jms20subset"
@@ -19,10 +21,10 @@ import (
19
21
)
20
22
21
23
/*
22
- * Test the ability to send a message asynchronously, which can give a higher
24
+ * Minimal example showing how to send a message asynchronously, which can give a higher
23
25
* rate of sending non-persistent messages, in exchange for less/no checking for errors.
24
26
*/
25
- func TestAsyncPut (t * testing.T ) {
27
+ func TestAsyncPutSample (t * testing.T ) {
26
28
27
29
// Loads CF parameters from connection_info.json and applicationApiKey.json in the Downloads directory
28
30
cf , cfErr := mqjms .CreateConnectionFactoryFromDefaultJSONFiles ()
@@ -36,6 +38,55 @@ func TestAsyncPut(t *testing.T) {
36
38
defer context .Close ()
37
39
}
38
40
41
+ // Set up a Producer for NonPersistent messages and Destination the PutAsyncAllowed=true
42
+ producer := context .CreateProducer ().SetDeliveryMode (jms20subset .DeliveryMode_NON_PERSISTENT )
43
+ asyncQueue := context .CreateQueue ("DEV.QUEUE.1" ).SetPutAsyncAllowed (jms20subset .Destination_PUT_ASYNC_ALLOWED_ENABLED )
44
+
45
+ // Send a message (asynchronously)
46
+ msg := context .CreateTextMessageWithString ("some text" )
47
+ errSend := producer .Send (asyncQueue , msg )
48
+ assert .Nil (t , errSend )
49
+
50
+ // Tidy up the message to leave the test clean.
51
+ consumer , errCons := context .CreateConsumer (asyncQueue )
52
+ assert .Nil (t , errCons )
53
+ if consumer != nil {
54
+ defer consumer .Close ()
55
+ }
56
+ _ , errRvc := consumer .ReceiveStringBodyNoWait ()
57
+ assert .Nil (t , errRvc )
58
+
59
+ }
60
+
61
+ /*
62
+ * Compare the performance benefit of sending messages non-persistent, non-transational
63
+ * messages asynchronously - which can give a higher message rate, in exchange for
64
+ * less/no checking for errors.
65
+ *
66
+ * The test checks that async put is at least 10% faster than synchronous put.
67
+ * (in testing against a remote queue manager it was actually 30% faster)
68
+ */
69
+ func TestAsyncPutComparison (t * testing.T ) {
70
+
71
+ // Loads CF parameters from connection_info.json and applicationApiKey.json in the Downloads directory
72
+ cf , cfErr := mqjms .CreateConnectionFactoryFromDefaultJSONFiles ()
73
+ assert .Nil (t , cfErr )
74
+
75
+ // Check the default value for SendCheckCount, which means never check for errors.
76
+ assert .Equal (t , 0 , cf .SendCheckCount )
77
+
78
+ // Creates a connection to the queue manager, using defer to close it automatically
79
+ // at the end of the function (if it was created successfully)
80
+ context , ctxErr := cf .CreateContext ()
81
+ assert .Nil (t , ctxErr )
82
+ if context != nil {
83
+ defer context .Close ()
84
+ }
85
+
86
+ // --------------------------------------------------------
87
+ // Start by sending a set of messages using the normal synchronous approach, in
88
+ // order that we can get a baseline timing.
89
+
39
90
// Set up the producer and consumer with the SYNCHRONOUS (not async yet) queue
40
91
syncQueue := context .CreateQueue ("DEV.QUEUE.1" )
41
92
producer := context .CreateProducer ().SetDeliveryMode (jms20subset .DeliveryMode_NON_PERSISTENT ).SetTimeToLive (60000 )
@@ -53,7 +104,7 @@ func TestAsyncPut(t *testing.T) {
53
104
numberMessages := 50
54
105
55
106
// First get a baseline for how long it takes us to send the batch of messages
56
- // WITHOUT async put.
107
+ // WITHOUT async put (i.e. using normal synchronous put)
57
108
syncStartTime := currentTimeMillis ()
58
109
for i := 0 ; i < numberMessages ; i ++ {
59
110
@@ -68,7 +119,7 @@ func TestAsyncPut(t *testing.T) {
68
119
syncSendTime := syncEndTime - syncStartTime
69
120
//fmt.Println("Took " + strconv.FormatInt(syncSendTime, 10) + "ms to send " + strconv.Itoa(numberMessages) + " synchronous messages.")
70
121
71
- // Receive the messages back again
122
+ // Receive the messages back again to tidy the queue back to a clean state
72
123
finishedReceiving := false
73
124
rcvCount := 0
74
125
@@ -103,7 +154,7 @@ func TestAsyncPut(t *testing.T) {
103
154
asyncSendTime := asyncEndTime - asyncStartTime
104
155
//fmt.Println("Took " + strconv.FormatInt(asyncSendTime, 10) + "ms to send " + strconv.Itoa(numberMessages) + " ASYNC messages.")
105
156
106
- // Receive the messages back again
157
+ // Receive the messages back again to tidy the queue back to a clean state
107
158
finishedReceiving = false
108
159
rcvCount = 0
109
160
@@ -128,6 +179,193 @@ func TestAsyncPut(t *testing.T) {
128
179
129
180
}
130
181
182
+ /*
183
+ * Test the ability to successfully send async messages with checking enabled.
184
+ *
185
+ * This test is checking that no failures are reported when the interval checking
186
+ * is enabled.
187
+ */
188
+ func TestAsyncPutCheckCount (t * testing.T ) {
189
+
190
+ // Loads CF parameters from connection_info.json and applicationApiKey.json in the Downloads directory
191
+ cf , cfErr := mqjms .CreateConnectionFactoryFromDefaultJSONFiles ()
192
+ assert .Nil (t , cfErr )
193
+
194
+ // Set the CF flag to enable checking for errors after a certain number of messages
195
+ cf .SendCheckCount = 10
196
+
197
+ // Check the default value for SendCheckCount
198
+ assert .Equal (t , 10 , cf .SendCheckCount )
199
+
200
+ // Creates a connection to the queue manager, using defer to close it automatically
201
+ // at the end of the function (if it was created successfully)
202
+ context , ctxErr := cf .CreateContext ()
203
+ assert .Nil (t , ctxErr )
204
+ if context != nil {
205
+ defer context .Close ()
206
+ }
207
+
208
+ // Set up the producer and consumer with the async queue.
209
+ asyncQueue := context .CreateQueue ("DEV.QUEUE.1" ).SetPutAsyncAllowed (jms20subset .Destination_PUT_ASYNC_ALLOWED_ENABLED )
210
+ producer := context .CreateProducer ().SetDeliveryMode (jms20subset .DeliveryMode_NON_PERSISTENT )
211
+
212
+ // Create a unique message prefix representing this execution of the test case.
213
+ testcasePrefix := strconv .FormatInt (currentTimeMillis (), 10 )
214
+ msgPrefix := "checkCount_" + testcasePrefix + "_"
215
+ numberMessages := 50
216
+
217
+ // --------------------------------------------------------
218
+ // Do ASYNC message put
219
+ for i := 0 ; i < numberMessages ; i ++ {
220
+
221
+ // Create a TextMessage and send it.
222
+ msg := context .CreateTextMessageWithString (msgPrefix + strconv .Itoa (i ))
223
+
224
+ errSend := producer .Send (asyncQueue , msg )
225
+ assert .Nil (t , errSend )
226
+ }
227
+
228
+ // ----------------------------------
229
+ // Receive the messages back again to tidy the queue back to a clean state
230
+ consumer , errCons := context .CreateConsumer (asyncQueue )
231
+ assert .Nil (t , errCons )
232
+ if consumer != nil {
233
+ defer consumer .Close ()
234
+ }
235
+
236
+ finishedReceiving := false
237
+
238
+ for ! finishedReceiving {
239
+ rcvMsg , errRvc := consumer .ReceiveNoWait ()
240
+ assert .Nil (t , errRvc )
241
+
242
+ if rcvMsg == nil {
243
+ finishedReceiving = true
244
+ }
245
+ }
246
+ }
247
+
248
+ /*
249
+ * Validate that errors are reported at the correct interval when a problem occurs.
250
+ *
251
+ * This test case forces a failure to occur by sending 50 messages to a queue that has had its
252
+ * maximum depth set to 25. With SendCheckCount of 10 we will not receive an error until message 30,
253
+ * which is the first time the error check is made after the point at which the queue has filled up.
254
+ */
255
+ func TestAsyncPutCheckCountWithFailure (t * testing.T ) {
256
+
257
+ // Loads CF parameters from connection_info.json and applicationApiKey.json in the Downloads directory
258
+ cf , cfErr := mqjms .CreateConnectionFactoryFromDefaultJSONFiles ()
259
+ assert .Nil (t , cfErr )
260
+
261
+ // Set the CF flag to enable checking for errors after a certain number of messages
262
+ cf .SendCheckCount = 10
263
+
264
+ // Check the value for SendCheckCount was stored correctly.
265
+ assert .Equal (t , 10 , cf .SendCheckCount )
266
+
267
+ // Creates a connection to the queue manager, using defer to close it automatically
268
+ // at the end of the function (if it was created successfully)
269
+ context , ctxErr := cf .CreateContext ()
270
+ assert .Nil (t , ctxErr )
271
+ if context != nil {
272
+ defer context .Close ()
273
+ }
274
+
275
+ // Set up the producer and consumer with the async queue.
276
+ QUEUE_25_NAME := "DEV.MAXDEPTH25"
277
+ asyncQueue := context .CreateQueue (QUEUE_25_NAME ).SetPutAsyncAllowed (jms20subset .Destination_PUT_ASYNC_ALLOWED_ENABLED )
278
+ producer := context .CreateProducer ().SetDeliveryMode (jms20subset .DeliveryMode_NON_PERSISTENT )
279
+
280
+ // Create a unique message prefix representing this execution of the test case.
281
+ testcasePrefix := strconv .FormatInt (currentTimeMillis (), 10 )
282
+ msgPrefix := "checkCount_" + testcasePrefix + "_"
283
+ numberMessages := 50
284
+
285
+ // Variable to track whether the queue exists or not.
286
+ queueExists := true
287
+
288
+ // --------------------------------------------------------
289
+ // Send ASYNC message put
290
+ for i := 0 ; i < numberMessages ; i ++ {
291
+
292
+ // Create a TextMessage and send it.
293
+ msg := context .CreateTextMessageWithString (msgPrefix + strconv .Itoa (i ))
294
+
295
+ errSend := producer .Send (asyncQueue , msg )
296
+
297
+ // Messages will start to fail at number 25 but we don't get an error until
298
+ // the next check which takes place at 30.
299
+ if i == 0 && errSend != nil && errSend .GetReason () == "MQRC_UNKNOWN_OBJECT_NAME" {
300
+
301
+ fmt .Println ("Skipping TestAsyncPutCheckCountWithFailure as " + QUEUE_25_NAME + " is not defined." )
302
+ queueExists = false
303
+ break // Stop the loop at this point as we know it won't change.
304
+
305
+ } else if i < 30 {
306
+ assert .Nil (t , errSend )
307
+ } else if i == 30 {
308
+
309
+ assert .NotNil (t , errSend )
310
+ assert .Equal (t , "AsyncPutFailure" , errSend .GetErrorCode ())
311
+
312
+ // Message should be "N failures"
313
+ assert .True (t , strings .Contains (errSend .GetReason (), "6 failures" ))
314
+ assert .True (t , strings .Contains (errSend .GetReason (), "0 warnings" ))
315
+
316
+ // Linked message should have reason of MQRC_Q_FULL
317
+ linkedErr := errSend .GetLinkedError ()
318
+ assert .NotNil (t , linkedErr )
319
+ linkedReason := linkedErr .(jms20subset.JMSExceptionImpl ).GetReason ()
320
+ assert .Equal (t , "MQRC_Q_FULL" , linkedReason )
321
+
322
+ } else if i == 40 {
323
+
324
+ assert .NotNil (t , errSend )
325
+ assert .Equal (t , "AsyncPutFailure" , errSend .GetErrorCode ())
326
+
327
+ // Message should be "N failures"
328
+ assert .True (t , strings .Contains (errSend .GetReason (), "10 failures" )) // all of these failed
329
+ assert .True (t , strings .Contains (errSend .GetReason (), "0 warnings" ))
330
+
331
+ // Linked message should have reason of MQRC_Q_FULL
332
+ linkedErr := errSend .GetLinkedError ()
333
+ assert .NotNil (t , linkedErr )
334
+ linkedReason := linkedErr .(jms20subset.JMSExceptionImpl ).GetReason ()
335
+ assert .Equal (t , "MQRC_Q_FULL" , linkedReason )
336
+
337
+ } else {
338
+ // Messages 31, 32, ... 39, 41, 42, ...
339
+ // do not give an error because we don't make an error check.
340
+ assert .Nil (t , errSend )
341
+ }
342
+ }
343
+
344
+ // If the queue exists then tidy up the messages we sent.
345
+ if queueExists {
346
+
347
+ // ----------------------------------
348
+ // Receive the messages back again to tidy the queue back to a clean state
349
+ consumer , errCons := context .CreateConsumer (asyncQueue )
350
+ assert .Nil (t , errCons )
351
+ if consumer != nil {
352
+ defer consumer .Close ()
353
+ }
354
+
355
+ // Receive the messages back again
356
+ finishedReceiving := false
357
+
358
+ for ! finishedReceiving {
359
+ rcvMsg , errRvc := consumer .ReceiveNoWait ()
360
+ assert .Nil (t , errRvc )
361
+
362
+ if rcvMsg == nil {
363
+ finishedReceiving = true
364
+ }
365
+ }
366
+ }
367
+ }
368
+
131
369
/*
132
370
* Test the getter/setter functions for controlling async put.
133
371
*/
0 commit comments