func (channel *Channel) basicConsume(method *amqp.BasicConsume) *amqp.AMQPError { var classId, methodId = method.MethodIdentifier() // Check queue if len(method.Queue) == 0 { if len(channel.lastQueueName) == 0 { return amqp.NewSoftError(404, "Queue not found", classId, methodId) } else { method.Queue = channel.lastQueueName } } // TODO: do not directly access channel.conn.server.queues var queue, found = channel.conn.server.queues[method.Queue] if !found { // Spec doesn't say, but seems like a 404? return amqp.NewSoftError(404, "Queue not found", classId, methodId) } if len(method.ConsumerTag) == 0 { method.ConsumerTag = util.RandomId() } amqpErr := channel.addConsumer(queue, method) if amqpErr != nil { return amqpErr } if !method.NoWait { channel.SendMethod(&amqp.BasicConsumeOk{method.ConsumerTag}) } return nil }
func TestTxRollbackAckNack(t *testing.T) { // // Setup // tc := newTestClient(t) defer tc.cleanup() conn := tc.connect() ch, _, _ := channelHelper(tc, conn) ch.QueueDeclare("q1", false, false, false, false, NO_ARGS) ch.QueueBind("q1", "abc", "amq.direct", false, NO_ARGS) ch.Tx() ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) ch.TxCommit() cTag := util.RandomId() deliveries, _ := ch.Consume("q1", cTag, false, false, false, false, NO_ARGS) <-deliveries <-deliveries lastMsg := <-deliveries lastMsg.Nack(true, true) tc.wait(ch) if len(tc.connFromServer().channels[1].awaitingAcks) != 3 { t.Fatalf("Messages were acked despite rollback") } }
func TestImmediate(t *testing.T) { tc := newTestClient(t) defer tc.cleanup() conn := tc.connect() ch, _, _ := channelHelper(tc, conn) ch.QueueDeclare("q1", false, false, false, false, NO_ARGS) ch.QueueBind("q1", "abc", "amq.direct", false, NO_ARGS) deliveries, err := ch.Consume("q1", util.RandomId(), false, false, false, false, NO_ARGS) if err != nil { t.Fatalf("Failed to consume") } ch.Publish("amq.direct", "abc", false, true, TEST_TRANSIENT_MSG) <-deliveries }
func TestRecover(t *testing.T) { // // Setup // tc := newTestClient(t) defer tc.cleanup() conn := tc.connect() ch, _, _ := channelHelper(tc, conn) cTag := util.RandomId() ch.QueueDeclare("q1", false, false, false, false, NO_ARGS) ch.QueueBind("q1", "abc", "amq.direct", false, NO_ARGS) // Recover - no requeue // Publish two messages, consume them, call recover, consume them again // deliveries, err := ch.Consume("q1", cTag, false, false, false, false, NO_ARGS) if err != nil { t.Fatalf("Failed to consume") } ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) tc.wait(ch) <-deliveries lastMsg := <-deliveries ch.Recover(false) <-deliveries <-deliveries lastMsg.Ack(true) // Recover - requeue // Publish two messages, consume them, call recover, check that they are // requeued // ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) tc.wait(ch) <-deliveries <-deliveries ch.Cancel(cTag, false) ch.Recover(true) tc.wait(ch) msgCount := tc.s.queues["q1"].Len() if msgCount != 2 { t.Fatalf("Should have 2 message in queue. Found", msgCount) } }
func TestAckNackMany(t *testing.T) { // // Setup // tc := newTestClient(t) defer tc.cleanup() conn := tc.connect() ch, _, _ := channelHelper(tc, conn) ch.QueueDeclare("q1", false, false, false, false, NO_ARGS) ch.QueueBind("q1", "abc", "amq.direct", false, NO_ARGS) var consumerId = util.RandomId() // Ack Many // Publish and consume two messages. Acck-multiple the second one and // check that both are acked // deliveries, err := ch.Consume("q1", consumerId, false, false, false, false, NO_ARGS) if err != nil { t.Fatalf("Failed to consume") } ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) _ = <-deliveries msg2 := <-deliveries msg2.Ack(true) tc.wait(ch) if len(tc.connFromServer().channels[1].awaitingAcks) != 0 { t.Fatalf("No awaiting ack for message just received") } // Nack Many (no requeue) // Publish and consume two messages. Nack-multiple the second one and // check that both are acked and the queue is empty // ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) _ = <-deliveries msg2 = <-deliveries // Stop consuming so we can check requeue ch.Cancel(consumerId, false) msg2.Nack(true, false) tc.wait(ch) if tc.s.queues["q1"].Len() != 0 { t.Fatalf("Should have 0 message in queue") } // Nack Many (no requeue) // Publish and consume two messages. Nack-multiple the second one and // check that both are acked and the queue is empty // consumerId = util.RandomId() deliveries, err = ch.Consume("q1", consumerId, false, false, false, false, NO_ARGS) ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) ch.Publish("amq.direct", "abc", false, false, TEST_TRANSIENT_MSG) _ = <-deliveries msg2 = <-deliveries // Stop consuming so we can check requeue ch.Cancel(consumerId, false) msg2.Nack(true, true) tc.wait(ch) if tc.s.queues["q1"].Len() != 2 { t.Fatalf("Should have 2 message in queue") } }
func dbPath() string { return "/tmp/" + util.RandomId() + ".dispatchd.test.db" }
func (tc *testClient) wait(ch *amqpclient.Channel) { ch.QueueDeclare(util.RandomId(), false, false, false, false, NO_ARGS) }
func (channel *Channel) queueDeclare(method *amqp.QueueDeclare) *amqp.AMQPError { var classId, methodId = method.MethodIdentifier() // No name means generate a name if len(method.Queue) == 0 { method.Queue = util.RandomId() } // Check the name format var err = amqp.CheckExchangeOrQueueName(method.Queue) if err != nil { return amqp.NewSoftError(406, err.Error(), classId, methodId) } // If this is a passive request, do the appropriate checks and return if method.Passive { queue, found := channel.conn.server.queues[method.Queue] if found { if !method.NoWait { var qsize = uint32(queue.Len()) var csize = queue.ActiveConsumerCount() channel.SendMethod(&amqp.QueueDeclareOk{method.Queue, qsize, csize}) } channel.lastQueueName = method.Queue return nil } return amqp.NewSoftError(404, "Queue not found", classId, methodId) } // Create the new queue var connId = channel.conn.id if !method.Exclusive { connId = -1 } var queue = queue.NewQueue( method.Queue, method.Durable, method.Exclusive, method.AutoDelete, method.Arguments, connId, channel.server.msgStore, channel.server.queueDeleter, ) // If the new queue exists already, ensure the settings are the same. If it // doesn't, add it and optionally persist it existing, hasKey := channel.server.queues[queue.Name] if hasKey { if existing.ConnId != -1 && existing.ConnId != channel.conn.id { return amqp.NewSoftError(405, "Queue is locked to another connection", classId, methodId) } if !existing.EquivalentQueues(queue) { return amqp.NewSoftError(406, "Queue exists and is not equivalent to existing", classId, methodId) } } else { err = channel.server.addQueue(queue) if err != nil { // pragma: nocover return amqp.NewSoftError(500, "Error creating queue", classId, methodId) } // Persist if queue.Durable { queue.Persist(channel.server.db) } } channel.lastQueueName = method.Queue if !method.NoWait { channel.SendMethod(&amqp.QueueDeclareOk{queue.Name, uint32(0), uint32(0)}) } return nil }