1010package main
1111
1212import (
13+ "fmt"
1314 "strconv"
15+ "strings"
1416 "testing"
1517
1618 "github.com/ibm-messaging/mq-golang-jms20/jms20subset"
@@ -19,10 +21,10 @@ import (
1921)
2022
2123/*
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
2325 * rate of sending non-persistent messages, in exchange for less/no checking for errors.
2426 */
25- func TestAsyncPut (t * testing.T ) {
27+ func TestAsyncPutSample (t * testing.T ) {
2628
2729 // Loads CF parameters from connection_info.json and applicationApiKey.json in the Downloads directory
2830 cf , cfErr := mqjms .CreateConnectionFactoryFromDefaultJSONFiles ()
@@ -36,6 +38,55 @@ func TestAsyncPut(t *testing.T) {
3638 defer context .Close ()
3739 }
3840
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+
3990 // Set up the producer and consumer with the SYNCHRONOUS (not async yet) queue
4091 syncQueue := context .CreateQueue ("DEV.QUEUE.1" )
4192 producer := context .CreateProducer ().SetDeliveryMode (jms20subset .DeliveryMode_NON_PERSISTENT ).SetTimeToLive (60000 )
@@ -53,7 +104,7 @@ func TestAsyncPut(t *testing.T) {
53104 numberMessages := 50
54105
55106 // 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)
57108 syncStartTime := currentTimeMillis ()
58109 for i := 0 ; i < numberMessages ; i ++ {
59110
@@ -68,7 +119,7 @@ func TestAsyncPut(t *testing.T) {
68119 syncSendTime := syncEndTime - syncStartTime
69120 //fmt.Println("Took " + strconv.FormatInt(syncSendTime, 10) + "ms to send " + strconv.Itoa(numberMessages) + " synchronous messages.")
70121
71- // Receive the messages back again
122+ // Receive the messages back again to tidy the queue back to a clean state
72123 finishedReceiving := false
73124 rcvCount := 0
74125
@@ -103,7 +154,7 @@ func TestAsyncPut(t *testing.T) {
103154 asyncSendTime := asyncEndTime - asyncStartTime
104155 //fmt.Println("Took " + strconv.FormatInt(asyncSendTime, 10) + "ms to send " + strconv.Itoa(numberMessages) + " ASYNC messages.")
105156
106- // Receive the messages back again
157+ // Receive the messages back again to tidy the queue back to a clean state
107158 finishedReceiving = false
108159 rcvCount = 0
109160
@@ -128,6 +179,193 @@ func TestAsyncPut(t *testing.T) {
128179
129180}
130181
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+
131369/*
132370 * Test the getter/setter functions for controlling async put.
133371 */
0 commit comments