示例#1
0
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
}
示例#2
0
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")
	}
}
示例#6
0
func dbPath() string {
	return "/tmp/" + util.RandomId() + ".dispatchd.test.db"
}
示例#7
0
func (tc *testClient) wait(ch *amqpclient.Channel) {
	ch.QueueDeclare(util.RandomId(), false, false, false, false, NO_ARGS)
}
示例#8
0
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
}