func TestNewRemoteControl(t *testing.T) { Convey("Given a non-nil AMQP connection", t, func() { uri := os.Getenv("AMQP_URI") if len(uri) == 0 { uri = os.Getenv("PBOX_URI") } var amqpConn *amqp.Connection var err error Convey("The connection should be returned and err is nil", func() { amqpConn, err = amqp.Dial(uri) So(err, ShouldBeNil) So(amqpConn, ShouldNotBeNil) Convey("Given an exchange and routing key", func() { exchange := "amq.topic" rmtKey := []string{"testing.proc_box"} Convey("When agents.NewRemoteControl is invoked", func() { rc, err := NewRemoteControl(amqpConn, rmtKey, exchange) Convey("The handle should not be nil and the err is nil", func() { So(rc, ShouldNotBeNil) So(err, ShouldBeNil) }) }) rmtKey = []string{"key1", "key2"} Convey("Given multiple remote keys", func() { rc, err := NewRemoteControl(amqpConn, rmtKey, exchange) Convey("The handle should not be nil and the err is nil", func() { So(rc, ShouldNotBeNil) So(err, ShouldBeNil) }) }) }) Convey("Given a non-existent exchange", func() { exchange := "this.doesnt.exist" rmtKey := []string{"testing"} Convey("When agents.NewRemoteControl is invoked", func() { rc, err := NewRemoteControl(amqpConn, rmtKey, exchange) Convey("The handle should be nil and the error is not nil", func() { So(rc, ShouldBeNil) So(err, ShouldNotBeNil) }) }) }) }) }) Convey("When agents.NewRemoteControl is invoked with a nil AMQP connection", t, func() { rmtKey := []string{"testing"} rc, err := NewRemoteControl(nil, rmtKey, "amq.topic") Convey("The handle should be nil and the err is not nil", func() { So(rc, ShouldBeNil) So(err, ShouldNotBeNil) }) }) }
// TestIntegrationDialAMQP tests a connection to an AMQP broker and quits func TestDialAMQP(t *testing.T) { var amqpConn *amqp.Connection var err error Convey("Given an AMQP URI", t, func() { uri := os.Getenv("AMQP_URI") if len(uri) == 0 { uri = os.Getenv("PBOX_URI") } Convey("The connection should be returned and err is nil", func() { amqpConn, err = amqp.Dial(uri) So(err, ShouldBeNil) }) }) }
func publish(amqpURI, exchange, exchangeType, routingKey, body string, reliable bool) error { // This function dials, connects, declares, publishes, and tears down, // all in one go. In a real service, you probably want to maintain a // long-lived connection as state, and publish against that. log.Printf("dialing %q", amqpURI) connection, err := amqp.Dial(amqpURI) if err != nil { return fmt.Errorf("Dial: %s", err) } defer connection.Close() log.Printf("got Connection, getting Channel") channel, err := connection.Channel() if err != nil { return fmt.Errorf("Channel: %s", err) } log.Printf("got Channel, declaring %q Exchange (%q)", exchangeType, exchange) if err := channel.ExchangeDeclare( exchange, // name exchangeType, // type true, // durable false, // auto-deleted false, // internal false, // noWait nil, // arguments ); err != nil { return fmt.Errorf("Exchange Declare: %s", err) } // Reliable publisher confirms require confirm.select support from the // connection. if reliable { log.Printf("enabling publishing confirms.") if err := channel.Confirm(false); err != nil { return fmt.Errorf("Channel could not be put into confirm mode: %s", err) } ack, nack := channel.NotifyConfirm(make(chan uint64, 1), make(chan uint64, 1)) defer confirmOne(ack, nack) } log.Printf("declared Exchange, publishing %dB body (%q)", len(body), body) if err = channel.Publish( exchange, // publish to an exchange routingKey, // routing to 0 or more queues false, // mandatory false, // immediate amqp.Publishing{ Headers: amqp.Table{}, ContentType: "text/plain", ContentEncoding: "", Body: []byte(body), DeliveryMode: amqp.Transient, // 1=non-persistent, 2=persistent Priority: 0, // 0-9 // a bunch of application/implementation-specific fields }, ); err != nil { return fmt.Errorf("Exchange Publish: %s", err) } return nil }
func NewConsumer(amqpURI, exchange, exchangeType, queueName, key, ctag string) (*Consumer, error) { c := &Consumer{ conn: nil, channel: nil, tag: ctag, done: make(chan error), } var err error log.Printf("dialing %q", amqpURI) c.conn, err = amqp.Dial(amqpURI) if err != nil { return nil, fmt.Errorf("Dial: %s", err) } go func() { fmt.Printf("closing: %s", <-c.conn.NotifyClose(make(chan *amqp.Error))) }() log.Printf("got Connection, getting Channel") c.channel, err = c.conn.Channel() if err != nil { return nil, fmt.Errorf("Channel: %s", err) } log.Printf("got Channel, declaring Exchange (%q)", exchange) if err = c.channel.ExchangeDeclare( exchange, // name of the exchange exchangeType, // type true, // durable false, // delete when complete false, // internal false, // noWait nil, // arguments ); err != nil { return nil, fmt.Errorf("Exchange Declare: %s", err) } log.Printf("declared Exchange, declaring Queue %q", queueName) queue, err := c.channel.QueueDeclare( queueName, // name of the queue true, // durable false, // delete when usused false, // exclusive false, // noWait nil, // arguments ) if err != nil { return nil, fmt.Errorf("Queue Declare: %s", err) } log.Printf("declared Queue (%q %d messages, %d consumers), binding to Exchange (key %q)", queue.Name, queue.Messages, queue.Consumers, key) if err = c.channel.QueueBind( queue.Name, // name of the queue key, // bindingKey exchange, // sourceExchange false, // noWait nil, // arguments ); err != nil { return nil, fmt.Errorf("Queue Bind: %s", err) } log.Printf("Queue bound to Exchange, starting Consume (consumer tag %q)", c.tag) deliveries, err := c.channel.Consume( queue.Name, // name c.tag, // consumerTag, false, // noAck false, // exclusive false, // noLocal false, // noWait nil, // arguments ) if err != nil { return nil, fmt.Errorf("Queue Consume: %s", err) } go handle(deliveries, c.done) return c, nil }