Implement publisher (#16)
* Implement publisher * API refactor --------- Signed-off-by: Gabriele Santomaggio <G.santomaggio@gmail.com>
This commit is contained in:
parent
60e006b2a3
commit
1a6679a201
|
|
@ -3,38 +3,51 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/Azure/go-amqp"
|
||||||
"github.com/rabbitmq/rabbitmq-amqp-go-client/rabbitmq_amqp"
|
"github.com/rabbitmq/rabbitmq-amqp-go-client/rabbitmq_amqp"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Printf("Getting started with AMQP Go AMQP 1.0 Client\n")
|
|
||||||
chStatusChanged := make(chan *rabbitmq_amqp.StatusChanged, 1)
|
|
||||||
|
|
||||||
|
exchangeName := "getting-started-exchange"
|
||||||
|
queueName := "getting-started-queue"
|
||||||
|
routingKey := "routing-key"
|
||||||
|
|
||||||
|
fmt.Printf("Getting started with AMQP Go AMQP 1.0 Client\n")
|
||||||
|
|
||||||
|
/// Create a channel to receive status change notifications
|
||||||
|
chStatusChanged := make(chan *rabbitmq_amqp.StatusChanged, 1)
|
||||||
go func(ch chan *rabbitmq_amqp.StatusChanged) {
|
go func(ch chan *rabbitmq_amqp.StatusChanged) {
|
||||||
for statusChanged := range ch {
|
for statusChanged := range ch {
|
||||||
fmt.Printf("%s\n", statusChanged)
|
fmt.Printf("%s\n", statusChanged)
|
||||||
}
|
}
|
||||||
}(chStatusChanged)
|
}(chStatusChanged)
|
||||||
|
|
||||||
amqpConnection := rabbitmq_amqp.NewAmqpConnectionNotifyStatusChanged(chStatusChanged)
|
// Open a connection to the AMQP 1.0 server
|
||||||
err := amqpConnection.Open(context.Background(), rabbitmq_amqp.NewConnectionSettings())
|
amqpConnection, err := rabbitmq_amqp.Dial(context.Background(), "amqp://", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error opening connection: %v\n", err)
|
fmt.Printf("Error opening connection: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Register the channel to receive status change notifications
|
||||||
|
amqpConnection.NotifyStatusChange(chStatusChanged)
|
||||||
|
|
||||||
fmt.Printf("AMQP Connection opened.\n")
|
fmt.Printf("AMQP Connection opened.\n")
|
||||||
|
// Create the management interface for the connection
|
||||||
|
// so we can declare exchanges, queues, and bindings
|
||||||
management := amqpConnection.Management()
|
management := amqpConnection.Management()
|
||||||
exchangeInfo, err := management.DeclareExchange(context.TODO(), &rabbitmq_amqp.ExchangeSpecification{
|
exchangeInfo, err := management.DeclareExchange(context.TODO(), &rabbitmq_amqp.ExchangeSpecification{
|
||||||
Name: "getting-started-exchange",
|
Name: exchangeName,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error declaring exchange: %v\n", err)
|
fmt.Printf("Error declaring exchange: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Declare a Quorum queue
|
||||||
queueInfo, err := management.DeclareQueue(context.TODO(), &rabbitmq_amqp.QueueSpecification{
|
queueInfo, err := management.DeclareQueue(context.TODO(), &rabbitmq_amqp.QueueSpecification{
|
||||||
Name: "getting-started-queue",
|
Name: queueName,
|
||||||
QueueType: rabbitmq_amqp.QueueType{Type: rabbitmq_amqp.Quorum},
|
QueueType: rabbitmq_amqp.QueueType{Type: rabbitmq_amqp.Quorum},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -43,10 +56,11 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bind the queue to the exchange
|
||||||
bindingPath, err := management.Bind(context.TODO(), &rabbitmq_amqp.BindingSpecification{
|
bindingPath, err := management.Bind(context.TODO(), &rabbitmq_amqp.BindingSpecification{
|
||||||
SourceExchange: exchangeInfo.Name(),
|
SourceExchange: exchangeName,
|
||||||
DestinationQueue: queueInfo.Name(),
|
DestinationQueue: queueName,
|
||||||
BindingKey: "routing-key",
|
BindingKey: routingKey,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -54,6 +68,33 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addr, err := rabbitmq_amqp.ExchangeAddress(&exchangeName, &routingKey)
|
||||||
|
|
||||||
|
publisher, err := amqpConnection.Publisher(context.Background(), addr, "getting-started-publisher")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error creating publisher: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish a message to the exchange
|
||||||
|
err = publisher.Publish(context.Background(), amqp.NewMessage([]byte("Hello, World!")))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error publishing message: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
println("press any key to close the connection")
|
||||||
|
|
||||||
|
var input string
|
||||||
|
_, _ = fmt.Scanln(&input)
|
||||||
|
|
||||||
|
// Close the publisher
|
||||||
|
err = publisher.Close(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Unbind the queue from the exchange
|
||||||
|
|
||||||
err = management.Unbind(context.TODO(), bindingPath)
|
err = management.Unbind(context.TODO(), bindingPath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -67,6 +108,14 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Purge the queue
|
||||||
|
purged, err := management.PurgeQueue(context.TODO(), queueInfo.Name())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error purging queue: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("Purged %d messages from the queue.\n", purged)
|
||||||
|
|
||||||
err = management.DeleteQueue(context.TODO(), queueInfo.Name())
|
err = management.DeleteQueue(context.TODO(), queueInfo.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error deleting queue: %v\n", err)
|
fmt.Printf("Error deleting queue: %v\n", err)
|
||||||
|
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
package rabbitmq_amqp
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
|
||||||
. "github.com/onsi/gomega"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ = Describe("Address builder test ", func() {
|
|
||||||
It("With exchange, queue and key should raise and error", func() {
|
|
||||||
addressBuilder := NewAddressBuilder()
|
|
||||||
Expect(addressBuilder).NotTo(BeNil())
|
|
||||||
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
|
||||||
addressBuilder.Queue("queue").Exchange("exchange").Key("key")
|
|
||||||
_, err := addressBuilder.Address()
|
|
||||||
Expect(err).NotTo(BeNil())
|
|
||||||
Expect(err.Error()).To(Equal("exchange and queue cannot be set together"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("Without exchange and queue should raise and error", func() {
|
|
||||||
addressBuilder := NewAddressBuilder()
|
|
||||||
Expect(addressBuilder).NotTo(BeNil())
|
|
||||||
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
|
||||||
_, err := addressBuilder.Address()
|
|
||||||
Expect(err).NotTo(BeNil())
|
|
||||||
Expect(err.Error()).To(Equal("exchange or queue must be set"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("With exchange and key should return address", func() {
|
|
||||||
addressBuilder := NewAddressBuilder()
|
|
||||||
Expect(addressBuilder).NotTo(BeNil())
|
|
||||||
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
|
||||||
addressBuilder.Exchange("my_exchange").Key("my_key")
|
|
||||||
address, err := addressBuilder.Address()
|
|
||||||
Expect(err).To(BeNil())
|
|
||||||
Expect(address).To(Equal("/exchanges/my_exchange/my_key"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("With exchange should return address", func() {
|
|
||||||
addressBuilder := NewAddressBuilder()
|
|
||||||
Expect(addressBuilder).NotTo(BeNil())
|
|
||||||
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
|
||||||
addressBuilder.Exchange("my_exchange")
|
|
||||||
address, err := addressBuilder.Address()
|
|
||||||
Expect(err).To(BeNil())
|
|
||||||
Expect(address).To(Equal("/exchanges/my_exchange"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("With exchange and key with names to encode should return the encoded address", func() {
|
|
||||||
addressBuilder := NewAddressBuilder()
|
|
||||||
Expect(addressBuilder).NotTo(BeNil())
|
|
||||||
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
|
||||||
addressBuilder.Exchange("my_ exchange/()").Key("my_key ")
|
|
||||||
address, err := addressBuilder.Address()
|
|
||||||
Expect(err).To(BeNil())
|
|
||||||
Expect(address).To(Equal("/exchanges/my_%20exchange%2F%28%29/my_key%20"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("With queue should return address", func() {
|
|
||||||
addressBuilder := NewAddressBuilder()
|
|
||||||
Expect(addressBuilder).NotTo(BeNil())
|
|
||||||
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
|
||||||
addressBuilder.Queue("my_queue>")
|
|
||||||
address, err := addressBuilder.Address()
|
|
||||||
Expect(err).To(BeNil())
|
|
||||||
Expect(address).To(Equal("/queues/my_queue%3E"))
|
|
||||||
})
|
|
||||||
|
|
||||||
It("With queue and append should return address", func() {
|
|
||||||
addressBuilder := NewAddressBuilder()
|
|
||||||
Expect(addressBuilder).NotTo(BeNil())
|
|
||||||
Expect(addressBuilder).To(BeAssignableToTypeOf(&AddressBuilder{}))
|
|
||||||
addressBuilder.Queue("my_queue").Append("/messages")
|
|
||||||
address, err := addressBuilder.Address()
|
|
||||||
Expect(err).To(BeNil())
|
|
||||||
Expect(address).To(Equal("/queues/my_queue/messages"))
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
@ -7,66 +7,56 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AddressBuilder struct {
|
// Address Creates the address for the exchange or queue following the RabbitMQ conventions.
|
||||||
queue *string
|
// see: https://www.rabbitmq.com/docs/next/amqp#address-v2
|
||||||
exchange *string
|
func Address(exchange, key, queue *string, urlParameters *string) (string, error) {
|
||||||
key *string
|
if exchange == nil && queue == nil {
|
||||||
append *string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAddressBuilder() *AddressBuilder {
|
|
||||||
return &AddressBuilder{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AddressBuilder) Queue(queue string) *AddressBuilder {
|
|
||||||
a.queue = &queue
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AddressBuilder) Exchange(exchange string) *AddressBuilder {
|
|
||||||
a.exchange = &exchange
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AddressBuilder) Key(key string) *AddressBuilder {
|
|
||||||
a.key = &key
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AddressBuilder) Append(append string) *AddressBuilder {
|
|
||||||
a.append = &append
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *AddressBuilder) Address() (string, error) {
|
|
||||||
if a.exchange == nil && a.queue == nil {
|
|
||||||
return "", errors.New("exchange or queue must be set")
|
return "", errors.New("exchange or queue must be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
urlAppend := ""
|
urlAppend := ""
|
||||||
if !isStringNilOrEmpty(a.append) {
|
if !isStringNilOrEmpty(urlParameters) {
|
||||||
urlAppend = *a.append
|
urlAppend = *urlParameters
|
||||||
}
|
}
|
||||||
if !isStringNilOrEmpty(a.exchange) && !isStringNilOrEmpty(a.queue) {
|
if !isStringNilOrEmpty(exchange) && !isStringNilOrEmpty(queue) {
|
||||||
return "", errors.New("exchange and queue cannot be set together")
|
return "", errors.New("exchange and queue cannot be set together")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isStringNilOrEmpty(a.exchange) {
|
if !isStringNilOrEmpty(exchange) {
|
||||||
if !isStringNilOrEmpty(a.key) {
|
if !isStringNilOrEmpty(key) {
|
||||||
return "/" + exchanges + "/" + encodePathSegments(*a.exchange) + "/" + encodePathSegments(*a.key) + urlAppend, nil
|
return "/" + exchanges + "/" + encodePathSegments(*exchange) + "/" + encodePathSegments(*key) + urlAppend, nil
|
||||||
}
|
}
|
||||||
return "/" + exchanges + "/" + encodePathSegments(*a.exchange) + urlAppend, nil
|
return "/" + exchanges + "/" + encodePathSegments(*exchange) + urlAppend, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.queue == nil {
|
if queue == nil {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if isStringNilOrEmpty(a.queue) {
|
if isStringNilOrEmpty(queue) {
|
||||||
return "", errors.New("queue must be set")
|
return "", errors.New("queue must be set")
|
||||||
}
|
}
|
||||||
|
|
||||||
return "/" + queues + "/" + encodePathSegments(*a.queue) + urlAppend, nil
|
return "/" + queues + "/" + encodePathSegments(*queue) + urlAppend, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExchangeAddress Creates the address for the exchange
|
||||||
|
// See Address for more information
|
||||||
|
func ExchangeAddress(exchange, key *string) (string, error) {
|
||||||
|
return Address(exchange, key, nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueueAddress Creates the address for the queue.
|
||||||
|
// See Address for more information
|
||||||
|
func QueueAddress(queue *string) (string, error) {
|
||||||
|
return Address(nil, nil, queue, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PurgeQueueAddress Creates the address for purging the queue.
|
||||||
|
// See Address for more information
|
||||||
|
func PurgeQueueAddress(queue *string) (string, error) {
|
||||||
|
parameter := "/messages"
|
||||||
|
return Address(nil, nil, queue, ¶meter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodePathSegments takes a string and returns its percent-encoded representation.
|
// encodePathSegments takes a string and returns its percent-encoded representation.
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Address builder test ", func() {
|
||||||
|
It("With exchange, queue and key should raise and error", func() {
|
||||||
|
queue := "my_queue"
|
||||||
|
exchange := "my_exchange"
|
||||||
|
|
||||||
|
_, err := Address(&exchange, nil, &queue, nil)
|
||||||
|
Expect(err).NotTo(BeNil())
|
||||||
|
Expect(err.Error()).To(Equal("exchange and queue cannot be set together"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Without exchange and queue should raise and error", func() {
|
||||||
|
_, err := Address(nil, nil, nil, nil)
|
||||||
|
Expect(err).NotTo(BeNil())
|
||||||
|
Expect(err.Error()).To(Equal("exchange or queue must be set"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With exchange and key should return address", func() {
|
||||||
|
exchange := "my_exchange"
|
||||||
|
key := "my_key"
|
||||||
|
|
||||||
|
address, err := Address(&exchange, &key, nil, nil)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/exchanges/my_exchange/my_key"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With exchange should return address", func() {
|
||||||
|
exchange := "my_exchange"
|
||||||
|
address, err := Address(&exchange, nil, nil, nil)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/exchanges/my_exchange"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With exchange and key with names to encode should return the encoded address", func() {
|
||||||
|
|
||||||
|
exchange := "my_ exchange/()"
|
||||||
|
key := "my_key "
|
||||||
|
|
||||||
|
address, err := Address(&exchange, &key, nil, nil)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/exchanges/my_%20exchange%2F%28%29/my_key%20"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With queue should return address", func() {
|
||||||
|
queue := "my_queue>"
|
||||||
|
address, err := Address(nil, nil, &queue, nil)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/queues/my_queue%3E"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("With queue and urlParameters should return address", func() {
|
||||||
|
queue := "my_queue"
|
||||||
|
address, err := PurgeQueueAddress(&queue)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(address).To(Equal("/queues/my_queue/messages"))
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
@ -10,14 +10,9 @@ var _ = Describe("AMQP Bindings test ", func() {
|
||||||
var connection IConnection
|
var connection IConnection
|
||||||
var management IManagement
|
var management IManagement
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
connection = NewAmqpConnection()
|
conn, err := Dial(context.TODO(), "amqp://", nil)
|
||||||
Expect(connection).NotTo(BeNil())
|
|
||||||
Expect(connection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
connectionSettings := NewConnectionSettings()
|
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
err := connection.Open(context.TODO(), connectionSettings)
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
connection = conn
|
||||||
management = connection.Management()
|
management = connection.Management()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@ package rabbitmq_amqp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"github.com/Azure/go-amqp"
|
"github.com/Azure/go-amqp"
|
||||||
)
|
)
|
||||||
|
|
||||||
//func (c *ConnectionSettings) UseSsl(value bool) {
|
//func (c *ConnUrlHelper) UseSsl(value bool) {
|
||||||
// c.UseSsl = value
|
// c.UseSsl = value
|
||||||
// if value {
|
// if value {
|
||||||
// c.Scheme = "amqps"
|
// c.Scheme = "amqps"
|
||||||
|
|
@ -18,6 +19,15 @@ type AmqpConnection struct {
|
||||||
Connection *amqp.Conn
|
Connection *amqp.Conn
|
||||||
management IManagement
|
management IManagement
|
||||||
lifeCycle *LifeCycle
|
lifeCycle *LifeCycle
|
||||||
|
session *amqp.Session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AmqpConnection) Publisher(ctx context.Context, destinationAdd string, linkName string) (IPublisher, error) {
|
||||||
|
sender, err := a.session.NewSender(ctx, destinationAdd, createSenderLinkOptions(destinationAdd, linkName))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newPublisher(sender), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Management returns the management interface for the connection.
|
// Management returns the management interface for the connection.
|
||||||
|
|
@ -26,58 +36,61 @@ func (a *AmqpConnection) Management() IManagement {
|
||||||
return a.management
|
return a.management
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAmqpConnection creates a new AmqpConnection
|
// Dial creates a new AmqpConnection
|
||||||
// with a new AmqpManagement and a new LifeCycle.
|
// with a new AmqpManagement and a new LifeCycle.
|
||||||
// Returns a pointer to the new AmqpConnection
|
// Returns a pointer to the new AmqpConnection
|
||||||
func NewAmqpConnection() IConnection {
|
func Dial(ctx context.Context, addr string, connOptions *amqp.ConnOptions) (IConnection, error) {
|
||||||
return &AmqpConnection{
|
conn := &AmqpConnection{
|
||||||
management: NewAmqpManagement(),
|
management: NewAmqpManagement(),
|
||||||
lifeCycle: NewLifeCycle(),
|
lifeCycle: NewLifeCycle(),
|
||||||
}
|
}
|
||||||
}
|
err := conn.open(ctx, addr, connOptions)
|
||||||
|
if err != nil {
|
||||||
// NewAmqpConnectionNotifyStatusChanged creates a new AmqpConnection
|
return nil, err
|
||||||
// with a new AmqpManagement and a new LifeCycle
|
|
||||||
// and sets the channel for status changes.
|
|
||||||
// Returns a pointer to the new AmqpConnection
|
|
||||||
func NewAmqpConnectionNotifyStatusChanged(channel chan *StatusChanged) IConnection {
|
|
||||||
lifeCycle := NewLifeCycle()
|
|
||||||
lifeCycle.chStatusChanged = channel
|
|
||||||
return &AmqpConnection{
|
|
||||||
management: NewAmqpManagement(),
|
|
||||||
lifeCycle: lifeCycle,
|
|
||||||
}
|
}
|
||||||
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open opens a connection to the AMQP 1.0 server.
|
// Open opens a connection to the AMQP 1.0 server.
|
||||||
// using the provided connectionSettings and the AMQPLite library.
|
// using the provided connectionSettings and the AMQPLite library.
|
||||||
// Setups the connection and the management interface.
|
// Setups the connection and the management interface.
|
||||||
func (a *AmqpConnection) Open(ctx context.Context, connectionSettings *ConnectionSettings) error {
|
func (a *AmqpConnection) open(ctx context.Context, addr string, connOptions *amqp.ConnOptions) error {
|
||||||
sASLType := amqp.SASLTypeAnonymous()
|
|
||||||
switch connectionSettings.SaslMechanism {
|
if connOptions == nil {
|
||||||
case Plain:
|
connOptions = &amqp.ConnOptions{
|
||||||
sASLType = amqp.SASLTypePlain(connectionSettings.User, connectionSettings.Password)
|
// RabbitMQ requires SASL security layer
|
||||||
case External:
|
// to be enabled for AMQP 1.0 connections.
|
||||||
sASLType = amqp.SASLTypeExternal("")
|
// So this is mandatory and default in case not defined.
|
||||||
|
SASLType: amqp.SASLTypeAnonymous(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := amqp.Dial(ctx, connectionSettings.BuildAddress(), &amqp.ConnOptions{
|
//connOptions.HostName is the way to set the virtual host
|
||||||
ContainerID: connectionSettings.ContainerId,
|
// so we need to pre-parse the URI to get the virtual host
|
||||||
SASLType: sASLType,
|
// the PARSE is copied from go-amqp091 library
|
||||||
HostName: connectionSettings.VirtualHost,
|
// the URI will be parsed is parsed again in the amqp lite library
|
||||||
TLSConfig: connectionSettings.TlsConfig,
|
uri, err := ParseURI(addr)
|
||||||
})
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
connOptions.HostName = fmt.Sprintf("vhost:%s", uri.Vhost)
|
||||||
|
|
||||||
|
conn, err := amqp.Dial(ctx, addr, connOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
a.Connection = conn
|
a.Connection = conn
|
||||||
a.lifeCycle.SetStatus(Open)
|
a.session, err = a.Connection.NewSession(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
err = a.Management().Open(ctx, a)
|
err = a.Management().Open(ctx, a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO close connection?
|
// TODO close connection?
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.lifeCycle.SetStatus(Open)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package rabbitmq_amqp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/Azure/go-amqp"
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -9,94 +10,51 @@ import (
|
||||||
|
|
||||||
var _ = Describe("AMQP Connection Test", func() {
|
var _ = Describe("AMQP Connection Test", func() {
|
||||||
It("AMQP SASLTypeAnonymous Connection should succeed", func() {
|
It("AMQP SASLTypeAnonymous Connection should succeed", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
|
|
||||||
connectionSettings := NewConnectionSettings()
|
connection, err := Dial(context.Background(), "amqp://", &amqp.ConnOptions{
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
SASLType: amqp.SASLTypeAnonymous()})
|
||||||
connectionSettings.SaslMechanism = Anonymous
|
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = amqpConnection.Close(context.Background())
|
err = connection.Close(context.Background())
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP SASLTypePlain Connection should succeed", func() {
|
It("AMQP SASLTypePlain Connection should succeed", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
|
|
||||||
connectionSettings := NewConnectionSettings()
|
connection, err := Dial(context.Background(), "amqp://", &amqp.ConnOptions{
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
SASLType: amqp.SASLTypePlain("guest", "guest")})
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
connectionSettings.SaslMechanism = Plain
|
|
||||||
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = amqpConnection.Close(context.Background())
|
err = connection.Close(context.Background())
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Connection should fail due of wrong Port", func() {
|
It("AMQP Connection should fail due of wrong Port", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
_, err := Dial(context.Background(), "amqp://localhost:1234", nil)
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
connectionSettings := &ConnectionSettings{
|
|
||||||
Host: "localhost",
|
|
||||||
Port: 1234,
|
|
||||||
}
|
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Connection should fail due of wrong Host", func() {
|
It("AMQP Connection should fail due of wrong Host", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
_, err := Dial(context.Background(), "amqp://wrong_host:5672", nil)
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
|
|
||||||
connectionSettings := &ConnectionSettings{
|
|
||||||
Host: "wronghost",
|
|
||||||
Port: 5672,
|
|
||||||
}
|
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Connection should fail due to context cancellation", func() {
|
It("AMQP Connection should fail due to context cancellation", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||||
cancel()
|
cancel()
|
||||||
err := amqpConnection.Open(ctx, NewConnectionSettings())
|
_, err := Dial(ctx, "amqp://", nil)
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Connection should receive events", func() {
|
It("AMQP Connection should receive events", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
ch := make(chan *StatusChanged, 1)
|
ch := make(chan *StatusChanged, 1)
|
||||||
amqpConnection.NotifyStatusChange(ch)
|
connection, err := Dial(context.Background(), "amqp://", nil)
|
||||||
err := amqpConnection.Open(context.Background(), NewConnectionSettings())
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
connection.NotifyStatusChange(ch)
|
||||||
|
err = connection.Close(context.Background())
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
recv := <-ch
|
recv := <-ch
|
||||||
Expect(recv).NotTo(BeNil())
|
Expect(recv).NotTo(BeNil())
|
||||||
Expect(recv.From).To(Equal(Closed))
|
|
||||||
Expect(recv.To).To(Equal(Open))
|
|
||||||
|
|
||||||
err = amqpConnection.Close(context.Background())
|
|
||||||
Expect(err).To(BeNil())
|
|
||||||
recv = <-ch
|
|
||||||
Expect(recv).NotTo(BeNil())
|
|
||||||
|
|
||||||
Expect(recv.From).To(Equal(Open))
|
Expect(recv.From).To(Equal(Open))
|
||||||
Expect(recv.To).To(Equal(Closed))
|
Expect(recv.To).To(Equal(Closed))
|
||||||
})
|
})
|
||||||
|
|
@ -106,13 +64,13 @@ var _ = Describe("AMQP Connection Test", func() {
|
||||||
// Expect(amqpConnection).NotTo(BeNil())
|
// Expect(amqpConnection).NotTo(BeNil())
|
||||||
// Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
// Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
||||||
//
|
//
|
||||||
// connectionSettings := NewConnectionSettings().
|
// connectionSettings := NewConnUrlHelper().
|
||||||
// UseSsl(true).Port(5671).TlsConfig(&tls.Config{
|
// UseSsl(true).Port(5671).TlsConfig(&tls.Config{
|
||||||
// //ServerName: "localhost",
|
// //ServerName: "localhost",
|
||||||
// InsecureSkipVerify: true,
|
// InsecureSkipVerify: true,
|
||||||
// })
|
// })
|
||||||
// Expect(connectionSettings).NotTo(BeNil())
|
// Expect(connectionSettings).NotTo(BeNil())
|
||||||
// Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
// Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnUrlHelper{}))
|
||||||
// err := amqpConnection.Open(context.Background(), connectionSettings)
|
// err := amqpConnection.Open(context.Background(), connectionSettings)
|
||||||
// Expect(err).To(BeNil())
|
// Expect(err).To(BeNil())
|
||||||
//})
|
//})
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ func newAmqpExchange(management *AmqpManagement, name string) *AmqpExchange {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) Declare(ctx context.Context) (IExchangeInfo, error) {
|
func (e *AmqpExchange) Declare(ctx context.Context) (IExchangeInfo, error) {
|
||||||
path, err := NewAddressBuilder().Exchange(e.name).Address()
|
path, err := ExchangeAddress(&e.name, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +59,7 @@ func (e *AmqpExchange) IsAutoDelete() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AmqpExchange) Delete(ctx context.Context) error {
|
func (e *AmqpExchange) Delete(ctx context.Context) error {
|
||||||
path, err := NewAddressBuilder().Exchange(e.name).Address()
|
path, err := ExchangeAddress(&e.name, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,8 @@ var _ = Describe("AMQP Exchange test ", func() {
|
||||||
var connection IConnection
|
var connection IConnection
|
||||||
var management IManagement
|
var management IManagement
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
connection = NewAmqpConnection()
|
conn, err := Dial(context.TODO(), "amqp://", nil)
|
||||||
Expect(connection).NotTo(BeNil())
|
connection = conn
|
||||||
Expect(connection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
connectionSettings := NewConnectionSettings()
|
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
err := connection.Open(context.TODO(), connectionSettings)
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
management = connection.Management()
|
management = connection.Management()
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Azure/go-amqp"
|
"github.com/Azure/go-amqp"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrPreconditionFailed = errors.New("precondition Failed")
|
var ErrPreconditionFailed = errors.New("precondition Failed")
|
||||||
|
|
@ -30,18 +29,7 @@ func NewAmqpManagement() *AmqpManagement {
|
||||||
|
|
||||||
func (a *AmqpManagement) ensureReceiverLink(ctx context.Context) error {
|
func (a *AmqpManagement) ensureReceiverLink(ctx context.Context) error {
|
||||||
if a.receiver == nil {
|
if a.receiver == nil {
|
||||||
prop := make(map[string]any)
|
opts := createReceiverLinkOptions(managementNodeAddress, linkPairName)
|
||||||
prop["paired"] = true
|
|
||||||
opts := &amqp.ReceiverOptions{
|
|
||||||
DynamicAddress: false,
|
|
||||||
Name: linkPairName,
|
|
||||||
Properties: prop,
|
|
||||||
RequestedSenderSettleMode: amqp.SenderSettleModeSettled.Ptr(),
|
|
||||||
SettlementMode: amqp.ReceiverSettleModeFirst.Ptr(),
|
|
||||||
TargetAddress: managementNodeAddress,
|
|
||||||
ExpiryPolicy: amqp.ExpiryPolicyLinkDetach,
|
|
||||||
Credit: 100,
|
|
||||||
}
|
|
||||||
receiver, err := a.session.NewReceiver(ctx, managementNodeAddress, opts)
|
receiver, err := a.session.NewReceiver(ctx, managementNodeAddress, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -54,19 +42,8 @@ func (a *AmqpManagement) ensureReceiverLink(ctx context.Context) error {
|
||||||
|
|
||||||
func (a *AmqpManagement) ensureSenderLink(ctx context.Context) error {
|
func (a *AmqpManagement) ensureSenderLink(ctx context.Context) error {
|
||||||
if a.sender == nil {
|
if a.sender == nil {
|
||||||
prop := make(map[string]any)
|
sender, err := a.session.NewSender(ctx, managementNodeAddress,
|
||||||
prop["paired"] = true
|
createSenderLinkOptions(managementNodeAddress, linkPairName))
|
||||||
opts := &amqp.SenderOptions{
|
|
||||||
DynamicAddress: false,
|
|
||||||
ExpiryPolicy: amqp.ExpiryPolicyLinkDetach,
|
|
||||||
ExpiryTimeout: 0,
|
|
||||||
Name: linkPairName,
|
|
||||||
Properties: prop,
|
|
||||||
SettlementMode: amqp.SenderSettleModeSettled.Ptr(),
|
|
||||||
RequestedReceiverSettleMode: amqp.ReceiverSettleModeFirst.Ptr(),
|
|
||||||
SourceAddress: managementNodeAddress,
|
|
||||||
}
|
|
||||||
sender, err := a.session.NewSender(ctx, managementNodeAddress, opts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -248,7 +225,7 @@ func (a *AmqpManagement) Unbind(ctx context.Context, bindingPath string) error {
|
||||||
return bind.Unbind(ctx, bindingPath)
|
return bind.Unbind(ctx, bindingPath)
|
||||||
}
|
}
|
||||||
func (a *AmqpManagement) QueueInfo(ctx context.Context, queueName string) (IQueueInfo, error) {
|
func (a *AmqpManagement) QueueInfo(ctx context.Context, queueName string) (IQueueInfo, error) {
|
||||||
path, err := NewAddressBuilder().Queue(queueName).Address()
|
path, err := QueueAddress(&queueName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,51 +11,37 @@ import (
|
||||||
|
|
||||||
var _ = Describe("Management tests", func() {
|
var _ = Describe("Management tests", func() {
|
||||||
It("AMQP Management should fail due to context cancellation", func() {
|
It("AMQP Management should fail due to context cancellation", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
connection, err := Dial(context.Background(), "amqp://", nil)
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
err := amqpConnection.Open(context.Background(), NewConnectionSettings())
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
|
||||||
cancel()
|
cancel()
|
||||||
err = amqpConnection.Management().Open(ctx, amqpConnection)
|
err = connection.Management().Open(ctx, connection)
|
||||||
Expect(err).NotTo(BeNil())
|
Expect(err).NotTo(BeNil())
|
||||||
Expect(amqpConnection.Close(context.Background())).To(BeNil())
|
Expect(connection.Close(context.Background())).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("AMQP Management should receive events", func() {
|
It("AMQP Management should receive events", func() {
|
||||||
ch := make(chan *StatusChanged, 1)
|
ch := make(chan *StatusChanged, 1)
|
||||||
amqpConnection := NewAmqpConnectionNotifyStatusChanged(ch)
|
connection, err := Dial(context.Background(), "amqp://", nil)
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err := amqpConnection.Open(context.Background(), NewConnectionSettings())
|
connection.NotifyStatusChange(ch)
|
||||||
|
err = connection.Close(context.Background())
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
recv := <-ch
|
recv := <-ch
|
||||||
Expect(recv).NotTo(BeNil())
|
Expect(recv).NotTo(BeNil())
|
||||||
Expect(recv.From).To(Equal(Closed))
|
|
||||||
Expect(recv.To).To(Equal(Open))
|
|
||||||
|
|
||||||
err = amqpConnection.Close(context.Background())
|
|
||||||
Expect(err).To(BeNil())
|
|
||||||
recv = <-ch
|
|
||||||
Expect(recv).NotTo(BeNil())
|
|
||||||
|
|
||||||
Expect(recv.From).To(Equal(Open))
|
Expect(recv.From).To(Equal(Open))
|
||||||
Expect(recv.To).To(Equal(Closed))
|
Expect(recv.To).To(Equal(Closed))
|
||||||
Expect(amqpConnection.Close(context.Background())).To(BeNil())
|
Expect(connection.Close(context.Background())).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Request", func() {
|
It("Request", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
|
|
||||||
connectionSettings := NewConnectionSettings()
|
connection, err := Dial(context.Background(), "amqp://", nil)
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
management := amqpConnection.Management()
|
management := connection.Management()
|
||||||
kv := make(map[string]any)
|
kv := make(map[string]any)
|
||||||
kv["durable"] = true
|
kv["durable"] = true
|
||||||
kv["auto_delete"] = false
|
kv["auto_delete"] = false
|
||||||
|
|
@ -67,21 +53,15 @@ var _ = Describe("Management tests", func() {
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(result).NotTo(BeNil())
|
Expect(result).NotTo(BeNil())
|
||||||
Expect(management.Close(context.Background())).To(BeNil())
|
Expect(management.Close(context.Background())).To(BeNil())
|
||||||
Expect(amqpConnection.Close(context.Background())).To(BeNil())
|
Expect(connection.Close(context.Background())).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("GET on non-existing queue returns ErrDoesNotExist", func() {
|
It("GET on non-existing queue returns ErrDoesNotExist", func() {
|
||||||
amqpConnection := NewAmqpConnection()
|
|
||||||
Expect(amqpConnection).NotTo(BeNil())
|
|
||||||
Expect(amqpConnection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
|
|
||||||
connectionSettings := NewConnectionSettings()
|
connection, err := Dial(context.Background(), "amqp://", nil)
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
err := amqpConnection.Open(context.Background(), connectionSettings)
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
management := amqpConnection.Management()
|
management := connection.Management()
|
||||||
path := "/queues/i-do-not-exist"
|
path := "/queues/i-do-not-exist"
|
||||||
result, err := management.Request(context.Background(), amqp.Null{}, path, commandGet, []int{responseCode200, responseCode404})
|
result, err := management.Request(context.Background(), amqp.Null{}, path, commandGet, []int{responseCode200, responseCode404})
|
||||||
Expect(err).To(Equal(ErrDoesNotExist))
|
Expect(err).To(Equal(ErrDoesNotExist))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/Azure/go-amqp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Publisher struct {
|
||||||
|
sender *amqp.Sender
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPublisher(sender *amqp.Sender) *Publisher {
|
||||||
|
return &Publisher{sender: sender}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Publisher) Publish(ctx context.Context, message *amqp.Message) error {
|
||||||
|
|
||||||
|
/// for the outcome of the message delivery, see https://github.com/Azure/go-amqp/issues/347
|
||||||
|
//RELEASED
|
||||||
|
///**
|
||||||
|
// * The broker could not route the message to any queue.
|
||||||
|
// *
|
||||||
|
// * <p>This is likely to be due to a topology misconfiguration.
|
||||||
|
// */
|
||||||
|
// so at the moment we don't have access on this information
|
||||||
|
// TODO: remove this comment when the issue is resolved
|
||||||
|
|
||||||
|
err := m.sender.Send(ctx, message, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Publisher) Close(ctx context.Context) error {
|
||||||
|
return m.sender.Close(ctx)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/Azure/go-amqp"
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("AMQP publisher ", func() {
|
||||||
|
It("Send a message to a queue with a Message Target Publisher", func() {
|
||||||
|
qName := generateNameWithDateTime("Send a message to a queue with a Message Target Publisher")
|
||||||
|
connection, err := Dial(context.Background(), "amqp://", nil)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(connection).NotTo(BeNil())
|
||||||
|
queueInfo, err := connection.Management().DeclareQueue(context.Background(), &QueueSpecification{
|
||||||
|
Name: qName,
|
||||||
|
})
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(queueInfo).NotTo(BeNil())
|
||||||
|
dest, _ := QueueAddress(&qName)
|
||||||
|
publisher, err := connection.Publisher(context.Background(), dest, "test")
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(publisher).NotTo(BeNil())
|
||||||
|
Expect(publisher).To(BeAssignableToTypeOf(&Publisher{}))
|
||||||
|
|
||||||
|
err = publisher.Publish(context.Background(), amqp.NewMessage([]byte("hello")))
|
||||||
|
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
nMessages, err := connection.Management().PurgeQueue(context.Background(), qName)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(nMessages).To(Equal(1))
|
||||||
|
Expect(connection.Management().DeleteQueue(context.Background(), qName)).To(BeNil())
|
||||||
|
Expect(publisher.Close(context.Background())).To(BeNil())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
@ -149,7 +149,7 @@ func (a *AmqpQueue) Declare(ctx context.Context) (IQueueInfo, error) {
|
||||||
a.name = generateNameWithDefaultPrefix()
|
a.name = generateNameWithDefaultPrefix()
|
||||||
}
|
}
|
||||||
|
|
||||||
path, err := NewAddressBuilder().Queue(a.name).Address()
|
path, err := QueueAddress(&a.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +166,7 @@ func (a *AmqpQueue) Declare(ctx context.Context) (IQueueInfo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) Delete(ctx context.Context) error {
|
func (a *AmqpQueue) Delete(ctx context.Context) error {
|
||||||
path, err := NewAddressBuilder().Queue(a.name).Address()
|
path, err := QueueAddress(&a.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -175,7 +175,7 @@ func (a *AmqpQueue) Delete(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AmqpQueue) Purge(ctx context.Context) (int, error) {
|
func (a *AmqpQueue) Purge(ctx context.Context) (int, error) {
|
||||||
path, err := NewAddressBuilder().Queue(a.name).Append("/messages").Address()
|
path, err := PurgeQueueAddress(&a.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,9 @@ var _ = Describe("AMQP Queue test ", func() {
|
||||||
var connection IConnection
|
var connection IConnection
|
||||||
var management IManagement
|
var management IManagement
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
connection = NewAmqpConnection()
|
conn, err := Dial(context.TODO(), "amqp://", nil)
|
||||||
Expect(connection).NotTo(BeNil())
|
|
||||||
Expect(connection).To(BeAssignableToTypeOf(&AmqpConnection{}))
|
|
||||||
connectionSettings := NewConnectionSettings()
|
|
||||||
Expect(connectionSettings).NotTo(BeNil())
|
|
||||||
Expect(connectionSettings).To(BeAssignableToTypeOf(&ConnectionSettings{}))
|
|
||||||
err := connection.Open(context.TODO(), connectionSettings)
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
connection = conn
|
||||||
management = connection.Management()
|
management = connection.Management()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
@ -224,7 +219,7 @@ func publishMessages(queueName string, count int) {
|
||||||
Fail(err.Error())
|
Fail(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
address, err := NewAddressBuilder().Queue(queueName).Address()
|
address, err := QueueAddress(&queueName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fail(err.Error())
|
Fail(err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import "github.com/Azure/go-amqp"
|
||||||
|
|
||||||
|
// senderLinkOptions returns the options for a sender link
|
||||||
|
// with the given address and link name.
|
||||||
|
// That should be the same for all the links.
|
||||||
|
func createSenderLinkOptions(address string, linkName string) *amqp.SenderOptions {
|
||||||
|
prop := make(map[string]any)
|
||||||
|
prop["paired"] = true
|
||||||
|
return &amqp.SenderOptions{
|
||||||
|
SourceAddress: address,
|
||||||
|
DynamicAddress: false,
|
||||||
|
ExpiryPolicy: amqp.ExpiryPolicyLinkDetach,
|
||||||
|
ExpiryTimeout: 0,
|
||||||
|
Name: linkName,
|
||||||
|
Properties: prop,
|
||||||
|
SettlementMode: amqp.SenderSettleModeSettled.Ptr(),
|
||||||
|
RequestedReceiverSettleMode: amqp.ReceiverSettleModeFirst.Ptr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// receiverLinkOptions returns the options for a receiver link
|
||||||
|
// with the given address and link name.
|
||||||
|
// That should be the same for all the links.
|
||||||
|
func createReceiverLinkOptions(address string, linkName string) *amqp.ReceiverOptions {
|
||||||
|
prop := make(map[string]any)
|
||||||
|
prop["paired"] = true
|
||||||
|
return &amqp.ReceiverOptions{
|
||||||
|
TargetAddress: address,
|
||||||
|
DynamicAddress: false,
|
||||||
|
Name: linkName,
|
||||||
|
Properties: prop,
|
||||||
|
RequestedSenderSettleMode: amqp.SenderSettleModeSettled.Ptr(),
|
||||||
|
SettlementMode: amqp.ReceiverSettleModeFirst.Ptr(),
|
||||||
|
ExpiryPolicy: amqp.ExpiryPolicyLinkDetach,
|
||||||
|
Credit: 100,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,57 +2,10 @@ package rabbitmq_amqp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"github.com/Azure/go-amqp"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TSaslMechanism string
|
|
||||||
|
|
||||||
const (
|
|
||||||
Plain TSaslMechanism = "plain"
|
|
||||||
External TSaslMechanism = "external"
|
|
||||||
Anonymous TSaslMechanism = "anonymous"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SaslMechanism struct {
|
|
||||||
Type TSaslMechanism
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConnectionSettings struct {
|
|
||||||
Host string
|
|
||||||
Port int
|
|
||||||
User string
|
|
||||||
Password string
|
|
||||||
VirtualHost string
|
|
||||||
Scheme string
|
|
||||||
ContainerId string
|
|
||||||
UseSsl bool
|
|
||||||
TlsConfig *tls.Config
|
|
||||||
SaslMechanism TSaslMechanism
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ConnectionSettings) BuildAddress() string {
|
|
||||||
return c.Scheme + "://" + c.Host + ":" + fmt.Sprint(c.Port)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConnectionSettings creates a new ConnectionSettings struct with default values.
|
|
||||||
func NewConnectionSettings() *ConnectionSettings {
|
|
||||||
return &ConnectionSettings{
|
|
||||||
Host: "localhost",
|
|
||||||
Port: 5672,
|
|
||||||
User: "guest",
|
|
||||||
Password: "guest",
|
|
||||||
VirtualHost: "/",
|
|
||||||
Scheme: "amqp",
|
|
||||||
ContainerId: "amqp-go-client",
|
|
||||||
UseSsl: false,
|
|
||||||
TlsConfig: nil,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type IConnection interface {
|
type IConnection interface {
|
||||||
// Open opens a connection to the AMQP 1.0 server.
|
|
||||||
Open(ctx context.Context, connectionSettings *ConnectionSettings) error
|
|
||||||
|
|
||||||
// Close closes the connection to the AMQP 1.0 server.
|
// Close closes the connection to the AMQP 1.0 server.
|
||||||
Close(ctx context.Context) error
|
Close(ctx context.Context) error
|
||||||
|
|
@ -66,4 +19,14 @@ type IConnection interface {
|
||||||
// Status returns the current status of the connection.
|
// Status returns the current status of the connection.
|
||||||
// See LifeCycle struct for more information.
|
// See LifeCycle struct for more information.
|
||||||
Status() int
|
Status() int
|
||||||
|
|
||||||
|
// Publisher returns a new IPublisher interface for the connection.
|
||||||
|
Publisher(ctx context.Context, destinationAddr string, linkName string) (IPublisher, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPublisher is an interface for publishers messages based.
|
||||||
|
// on the AMQP 1.0 protocol.
|
||||||
|
type IPublisher interface {
|
||||||
|
Publish(ctx context.Context, message *amqp.Message) error
|
||||||
|
Close(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateNameWithDateTime(name string) string {
|
||||||
|
return fmt.Sprintf("%s_%s", name, strconv.FormatInt(time.Now().Unix(), 10))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errURIScheme = errors.New("AMQP scheme must be either 'amqp://' or 'amqps://'")
|
||||||
|
errURIWhitespace = errors.New("URI must not contain whitespace")
|
||||||
|
)
|
||||||
|
|
||||||
|
var schemePorts = map[string]int{
|
||||||
|
"amqp": 5672,
|
||||||
|
"amqps": 5671,
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultURI = URI{
|
||||||
|
Scheme: "amqp",
|
||||||
|
Host: "localhost",
|
||||||
|
Port: 5672,
|
||||||
|
Username: "guest",
|
||||||
|
Password: "guest",
|
||||||
|
Vhost: "/",
|
||||||
|
}
|
||||||
|
|
||||||
|
// URI represents a parsed AMQP URI string.
|
||||||
|
type URI struct {
|
||||||
|
Scheme string
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Vhost string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseURI attempts to parse the given AMQP URI according to the spec.
|
||||||
|
// See http://www.rabbitmq.com/uri-spec.html.
|
||||||
|
//
|
||||||
|
// Default values for the fields are:
|
||||||
|
//
|
||||||
|
// Scheme: amqp
|
||||||
|
// Host: localhost
|
||||||
|
// Port: 5672
|
||||||
|
// Username: guest
|
||||||
|
// Password: guest
|
||||||
|
// Vhost: /
|
||||||
|
func ParseURI(uri string) (URI, error) {
|
||||||
|
builder := defaultURI
|
||||||
|
|
||||||
|
if strings.Contains(uri, " ") {
|
||||||
|
return builder, errURIWhitespace
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(uri)
|
||||||
|
if err != nil {
|
||||||
|
return builder, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultPort, okScheme := schemePorts[u.Scheme]
|
||||||
|
|
||||||
|
if okScheme {
|
||||||
|
builder.Scheme = u.Scheme
|
||||||
|
} else {
|
||||||
|
return builder, errURIScheme
|
||||||
|
}
|
||||||
|
|
||||||
|
host := u.Hostname()
|
||||||
|
port := u.Port()
|
||||||
|
|
||||||
|
if host != "" {
|
||||||
|
builder.Host = host
|
||||||
|
}
|
||||||
|
|
||||||
|
if port != "" {
|
||||||
|
port32, err := strconv.ParseInt(port, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return builder, err
|
||||||
|
}
|
||||||
|
builder.Port = int(port32)
|
||||||
|
} else {
|
||||||
|
builder.Port = defaultPort
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.User != nil {
|
||||||
|
builder.Username = u.User.Username()
|
||||||
|
if password, ok := u.User.Password(); ok {
|
||||||
|
builder.Password = password
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Path != "" {
|
||||||
|
if strings.HasPrefix(u.Path, "/") {
|
||||||
|
if u.Host == "" && strings.HasPrefix(u.Path, "///") {
|
||||||
|
// net/url doesn't handle local context authorities and leaves that up
|
||||||
|
// to the scheme handler. In our case, we translate amqp:/// into the
|
||||||
|
// default host and whatever the vhost should be
|
||||||
|
if len(u.Path) > 3 {
|
||||||
|
builder.Vhost = u.Path[3:]
|
||||||
|
}
|
||||||
|
} else if len(u.Path) > 1 {
|
||||||
|
builder.Vhost = u.Path[1:]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
builder.Vhost = u.Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,260 @@
|
||||||
|
// Copyright (c) 2021 VMware, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
// Copyright (c) 2012-2021, Sean Treadway, SoundCloud Ltd.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package rabbitmq_amqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test matrix defined on http://www.rabbitmq.com/uri-spec.html
|
||||||
|
type testURI struct {
|
||||||
|
url string
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
host string
|
||||||
|
port int
|
||||||
|
vhost string
|
||||||
|
canon string
|
||||||
|
}
|
||||||
|
|
||||||
|
var uriTests = []testURI{
|
||||||
|
{
|
||||||
|
url: "amqp://user:pass@host:10000/vhost",
|
||||||
|
username: "user",
|
||||||
|
password: "pass",
|
||||||
|
host: "host",
|
||||||
|
port: 10000,
|
||||||
|
vhost: "vhost",
|
||||||
|
canon: "amqp://user:pass@host:10000/vhost",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: defaultURI.Host,
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://localhost/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://:@/",
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
host: defaultURI.Host,
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://:@localhost/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://user@",
|
||||||
|
username: "user",
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: defaultURI.Host,
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://user@localhost/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://user:pass@",
|
||||||
|
username: "user",
|
||||||
|
password: "pass",
|
||||||
|
host: defaultURI.Host,
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://user:pass@localhost/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://guest:pass@",
|
||||||
|
username: "guest",
|
||||||
|
password: "pass",
|
||||||
|
host: defaultURI.Host,
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://guest:pass@localhost/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://host",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "host",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://host/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://:10000",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: defaultURI.Host,
|
||||||
|
port: 10000,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://localhost:10000/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp:///vhost",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: defaultURI.Host,
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: "vhost",
|
||||||
|
canon: "amqp://localhost/vhost",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://host/",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "host",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://host/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://host/%2F",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "host",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: "/",
|
||||||
|
canon: "amqp://host/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://host/%2F%2F",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "host",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: "//",
|
||||||
|
canon: "amqp://host/%2F%2F",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://host/%2Fslash%2F",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "host",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: "/slash/",
|
||||||
|
canon: "amqp://host/%2Fslash%2F",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://192.168.1.1:1000/",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "192.168.1.1",
|
||||||
|
port: 1000,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://192.168.1.1:1000/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://[::1]",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "::1",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://[::1]/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://[::1]:1000",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "::1",
|
||||||
|
port: 1000,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://[::1]:1000/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://[fe80::1]",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "fe80::1",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://[fe80::1]/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://[fe80::1]",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "fe80::1",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://[fe80::1]/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://[fe80::1%25en0]",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "fe80::1%en0",
|
||||||
|
port: defaultURI.Port,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://[fe80::1%25en0]/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqp://[fe80::1]:5671",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "fe80::1",
|
||||||
|
port: 5671,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqp://[fe80::1]:5671/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqps:///",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: defaultURI.Host,
|
||||||
|
port: schemePorts["amqps"],
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqps://localhost/",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
url: "amqps://host:1000/",
|
||||||
|
username: defaultURI.Username,
|
||||||
|
password: defaultURI.Password,
|
||||||
|
host: "host",
|
||||||
|
port: 1000,
|
||||||
|
vhost: defaultURI.Vhost,
|
||||||
|
canon: "amqps://host:1000/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = Describe("Parse Test ", func() {
|
||||||
|
It("ParseURI", func() {
|
||||||
|
|
||||||
|
for _, test := range uriTests {
|
||||||
|
uri, err := ParseURI(test.url)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(uri.Username).To(Equal(test.username))
|
||||||
|
Expect(uri.Password).To(Equal(test.password))
|
||||||
|
Expect(uri.Host).To(Equal(test.host))
|
||||||
|
Expect(uri.Port).To(Equal(test.port))
|
||||||
|
Expect(uri.Vhost).To(Equal(test.vhost))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue