static check (#36)

* static check
* remove duplication
* add tests

---------

Signed-off-by: Gabriele Santomaggio <G.santomaggio@gmail.com>
This commit is contained in:
Gabriele Santomaggio 2025-02-24 15:04:19 +01:00 committed by GitHub
parent a0dbb5594d
commit 8ffd1e6fc3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 262 additions and 164 deletions

View File

@ -1,3 +1,10 @@
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN = $(shell go env GOPATH)/bin
else
GOBIN = $(shell go env GOBIN)
endif
all: test all: test
format: format:
@ -6,7 +13,18 @@ format:
vet: vet:
go vet ./pkg/rabbitmqamqp go vet ./pkg/rabbitmqamqp
test: format vet STATICCHECK ?= $(GOBIN)/staticcheck
STATICCHECK_VERSION ?= latest
$(STATICCHECK):
go install honnef.co/go/tools/cmd/staticcheck@$(STATICCHECK_VERSION)
check: $(STATICCHECK)
$(STATICCHECK) ./pkg/rabbitmqamqp
test: format vet check
cd ./pkg/rabbitmqamqp && go run -mod=mod github.com/onsi/ginkgo/v2/ginkgo \ cd ./pkg/rabbitmqamqp && go run -mod=mod github.com/onsi/ginkgo/v2/ginkgo \
--randomize-all --randomize-suites \ --randomize-all --randomize-suites \
--cover --coverprofile=coverage.txt --covermode=atomic \ --cover --coverprofile=coverage.txt --covermode=atomic \

View File

@ -61,9 +61,9 @@ func address(exchange, key, queue *string, urlParameters *string) (string, error
if !isStringNilOrEmpty(exchange) { if !isStringNilOrEmpty(exchange) {
if !isStringNilOrEmpty(key) { if !isStringNilOrEmpty(key) {
return "/" + exchanges + "/" + encodePathSegments(*exchange) + "/" + encodePathSegments(*key) + urlAppend, nil return fmt.Sprintf("/%s/%s/%s%s", exchanges, encodePathSegments(*exchange), encodePathSegments(*key), urlAppend), nil
} }
return "/" + exchanges + "/" + encodePathSegments(*exchange) + urlAppend, nil return fmt.Sprintf("/%s/%s%s", exchanges, encodePathSegments(*exchange), urlAppend), nil
} }
if queue == nil { if queue == nil {
@ -73,8 +73,7 @@ func address(exchange, key, queue *string, urlParameters *string) (string, error
if isStringNilOrEmpty(queue) { if isStringNilOrEmpty(queue) {
return "", errors.New("queue must be set") return "", errors.New("queue must be set")
} }
return fmt.Sprintf("/%s/%s%s", queues, encodePathSegments(*queue), urlAppend), nil
return "/" + queues + "/" + encodePathSegments(*queue) + urlAppend, nil
} }
// exchangeAddress Creates the address for the exchange // exchangeAddress Creates the address for the exchange

View File

@ -6,59 +6,62 @@ import (
) )
var _ = Describe("address builder test ", func() { var _ = Describe("address builder test ", func() {
It("With exchange, queue and key should raise and error", func() { // Error cases
queue := "my_queue" Describe("Error cases", func() {
exchange := "my_exchange" DescribeTable("should return appropriate errors",
func(exchange, key, queue *string, expectedErr string) {
_, err := address(&exchange, nil, &queue, nil) _, err := address(exchange, key, queue, nil)
Expect(err).NotTo(BeNil()) Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("exchange and queue cannot be set together")) Expect(err.Error()).To(Equal(expectedErr))
},
Entry("when both exchange and queue are set",
stringPtr("my_exchange"), nil, stringPtr("my_queue"),
"exchange and queue cannot be set together"),
Entry("when neither exchange nor queue is set",
nil, nil, nil,
"exchange or queue must be set"),
)
}) })
It("Without exchange and queue should raise and error", func() { // Exchange-related cases
_, err := address(nil, nil, nil, nil) Describe("Exchange addresses", func() {
Expect(err).NotTo(BeNil()) DescribeTable("should generate correct exchange addresses",
Expect(err.Error()).To(Equal("exchange or queue must be set")) func(exchange, key *string, expected string) {
address, err := address(exchange, key, nil, nil)
Expect(err).NotTo(HaveOccurred())
Expect(address).To(Equal(expected))
},
Entry("with exchange and key",
stringPtr("my_exchange"), stringPtr("my_key"),
"/exchanges/my_exchange/my_key"),
Entry("with exchange only",
stringPtr("my_exchange"), nil,
"/exchanges/my_exchange"),
Entry("with special characters",
stringPtr("my_ exchange/()"), stringPtr("my_key "),
"/exchanges/my_%20exchange%2F%28%29/my_key%20"),
)
}) })
It("With exchange and key should return address", func() { // Queue-related cases
exchange := "my_exchange" Describe("Queue addresses", func() {
key := "my_key" It("should generate correct queue address with special characters", func() {
queue := "my_queue>"
address, err := address(nil, nil, &queue, nil)
Expect(err).NotTo(HaveOccurred())
Expect(address).To(Equal("/queues/my_queue%3E"))
})
address, err := address(&exchange, &key, nil, nil) It("should generate correct purge queue address", func() {
Expect(err).To(BeNil()) queue := "my_queue"
Expect(address).To(Equal("/exchanges/my_exchange/my_key")) address, err := purgeQueueAddress(&queue)
Expect(err).NotTo(HaveOccurred())
Expect(address).To(Equal("/queues/my_queue/messages"))
})
}) })
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"))
})
}) })
// Helper function to create string pointers
func stringPtr(s string) *string {
return &s
}

View File

@ -228,19 +228,18 @@ func (a *AmqpConnection) open(ctx context.Context, addresses []string, connOptio
var err error var err error
a.session, err = a.azureConnection.NewSession(ctx, nil) a.session, err = a.azureConnection.NewSession(ctx, nil)
go func() { go func() {
select { <-azureConnection.Done()
case <-azureConnection.Done(): {
{ a.lifeCycle.SetState(&StateClosed{error: azureConnection.Err()})
a.lifeCycle.SetState(&StateClosed{error: azureConnection.Err()}) if azureConnection.Err() != nil {
if azureConnection.Err() != nil { Error("connection closed unexpectedly", "error", azureConnection.Err())
Error("connection closed unexpectedly", "error", azureConnection.Err()) a.maybeReconnect()
a.maybeReconnect()
return return
}
Debug("connection closed successfully")
} }
Debug("connection closed successfully")
} }
}() }()
if err != nil { if err != nil {
@ -261,67 +260,74 @@ func (a *AmqpConnection) maybeReconnect() {
return return
} }
a.lifeCycle.SetState(&StateReconnecting{}) a.lifeCycle.SetState(&StateReconnecting{})
numberOfAttempts := 1 // Add exponential backoff with jitter
waitTime := a.amqpConnOptions.RecoveryConfiguration.BackOffReconnectInterval baseDelay := a.amqpConnOptions.RecoveryConfiguration.BackOffReconnectInterval
reconnected := false maxDelay := 1 * time.Minute
for numberOfAttempts <= a.amqpConnOptions.RecoveryConfiguration.MaxReconnectAttempts {
for attempt := 1; attempt <= a.amqpConnOptions.RecoveryConfiguration.MaxReconnectAttempts; attempt++ {
///wait for before reconnecting ///wait for before reconnecting
// add some random milliseconds to the wait time to avoid thundering herd // add some random milliseconds to the wait time to avoid thundering herd
// the random time is between 0 and 500 milliseconds // the random time is between 0 and 500 milliseconds
waitTime = waitTime + time.Duration(rand.Intn(500))*time.Millisecond // Calculate delay with exponential backoff and jitter
jitter := time.Duration(rand.Intn(500)) * time.Millisecond
delay := baseDelay + jitter
if delay > maxDelay {
delay = maxDelay
}
Info("Waiting before reconnecting", "in", waitTime, "attempt", numberOfAttempts) Info("Attempting reconnection", "attempt", attempt, "delay", delay)
time.Sleep(waitTime) time.Sleep(delay)
// context with timeout // context with timeout
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
// try to createSender // try to createSender
err := a.open(ctx, a.amqpConnOptions.addresses, a.amqpConnOptions) err := a.open(ctx, a.amqpConnOptions.addresses, a.amqpConnOptions)
cancel() cancel()
if err != nil { if err == nil {
numberOfAttempts++ a.restartEntities()
waitTime = waitTime * 2 a.lifeCycle.SetState(&StateOpen{})
Error("Failed to connection. ", "id", a.Id(), "error", err) return
} else {
reconnected = true
break
} }
baseDelay *= 2
Error("Reconnection attempt failed", "attempt", attempt, "error", err)
} }
if reconnected { }
var fails int32
Info("Reconnected successfully, restarting publishers and consumers")
a.entitiesTracker.publishers.Range(func(key, value any) bool {
publisher := value.(*Publisher)
// try to createSender
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
err := publisher.createSender(ctx)
if err != nil {
atomic.AddInt32(&fails, 1)
Error("Failed to createSender publisher", "ID", publisher.Id(), "error", err)
}
cancel()
return true
})
Info("Restarted publishers", "number of fails", fails)
fails = 0
a.entitiesTracker.consumers.Range(func(key, value any) bool {
consumer := value.(*Consumer)
// try to createSender
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
err := consumer.createReceiver(ctx)
if err != nil {
atomic.AddInt32(&fails, 1)
Error("Failed to createReceiver consumer", "ID", consumer.Id(), "error", err)
}
cancel()
return true
})
Info("Restarted consumers", "number of fails", fails)
a.lifeCycle.SetState(&StateOpen{}) // restartEntities attempts to restart all publishers and consumers after a reconnection
} func (a *AmqpConnection) restartEntities() {
var publisherFails, consumerFails int32
// Restart publishers
a.entitiesTracker.publishers.Range(func(key, value any) bool {
publisher := value.(*Publisher)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
if err := publisher.createSender(ctx); err != nil {
atomic.AddInt32(&publisherFails, 1)
Error("Failed to restart publisher", "ID", publisher.Id(), "error", err)
}
return true
})
// Restart consumers
a.entitiesTracker.consumers.Range(func(key, value any) bool {
consumer := value.(*Consumer)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
if err := consumer.createReceiver(ctx); err != nil {
atomic.AddInt32(&consumerFails, 1)
Error("Failed to restart consumer", "ID", consumer.Id(), "error", err)
}
return true
})
Info("Entity restart complete",
"publisherFails", publisherFails,
"consumerFails", consumerFails)
} }
func (a *AmqpConnection) close() { func (a *AmqpConnection) close() {

View File

@ -53,14 +53,6 @@ func (e *entitiesTracker) storeOrReplaceProducer(entity entityIdentifier) {
e.publishers.Store(entity.Id(), entity) e.publishers.Store(entity.Id(), entity)
} }
func (e *entitiesTracker) getProducer(id string) (*Publisher, bool) {
producer, ok := e.publishers.Load(id)
if !ok {
return nil, false
}
return producer.(*Publisher), true
}
func (e *entitiesTracker) removeProducer(entity entityIdentifier) { func (e *entitiesTracker) removeProducer(entity entityIdentifier) {
e.publishers.Delete(entity.Id()) e.publishers.Delete(entity.Id())
} }
@ -69,14 +61,6 @@ func (e *entitiesTracker) storeOrReplaceConsumer(entity entityIdentifier) {
e.consumers.Store(entity.Id(), entity) e.consumers.Store(entity.Id(), entity)
} }
func (e *entitiesTracker) getConsumer(id string) (*Consumer, bool) {
consumer, ok := e.consumers.Load(id)
if !ok {
return nil, false
}
return consumer.(*Consumer), true
}
func (e *entitiesTracker) removeConsumer(entity entityIdentifier) { func (e *entitiesTracker) removeConsumer(entity entityIdentifier) {
e.consumers.Delete(entity.Id()) e.consumers.Delete(entity.Id())
} }

View File

@ -2,11 +2,12 @@ package rabbitmqamqp
import ( import (
"context" "context"
"time"
"github.com/Azure/go-amqp" "github.com/Azure/go-amqp"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
testhelper "github.com/rabbitmq/rabbitmq-amqp-go-client/pkg/test-helper" testhelper "github.com/rabbitmq/rabbitmq-amqp-go-client/pkg/test-helper"
"time"
) )
var _ = Describe("Recovery connection test", func() { var _ = Describe("Recovery connection test", func() {
@ -45,6 +46,7 @@ var _ = Describe("Recovery connection test", func() {
consumer, err := connection.NewConsumer(context.Background(), consumer, err := connection.NewConsumer(context.Background(),
qName, nil) qName, nil)
Expect(err).To(BeNil())
publisher, err := connection.NewPublisher(context.Background(), &QueueAddress{ publisher, err := connection.NewPublisher(context.Background(), &QueueAddress{
Queue: qName, Queue: qName,
@ -113,6 +115,23 @@ var _ = Describe("Recovery connection test", func() {
// from reconnecting to open // from reconnecting to open
// from open to closed (without error) // from open to closed (without error)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(consumer.Close(context.Background())).NotTo(BeNil())
Expect(publisher.Close(context.Background())).NotTo(BeNil())
entLen := 0
connection.entitiesTracker.consumers.Range(func(key, value interface{}) bool {
entLen++
return true
})
Expect(entLen).To(Equal(0))
entLen = 0
connection.entitiesTracker.publishers.Range(func(key, value interface{}) bool {
entLen++
return true
})
Expect(entLen).To(Equal(0))
}) })
It("connection should not reconnect producers and consumers if the auto-recovery is disabled", func() { It("connection should not reconnect producers and consumers if the auto-recovery is disabled", func() {

View File

@ -10,7 +10,6 @@ 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() {
connection, err := Dial(context.Background(), []string{"amqp://"}, &AmqpConnOptions{ connection, err := Dial(context.Background(), []string{"amqp://"}, &AmqpConnOptions{
SASLType: amqp.SASLTypeAnonymous()}) SASLType: amqp.SASLTypeAnonymous()})
Expect(err).To(BeNil()) Expect(err).To(BeNil())
@ -72,6 +71,64 @@ var _ = Describe("AMQP connection Test", func() {
Expect(recv.To).To(Equal(&StateClosed{})) Expect(recv.To).To(Equal(&StateClosed{}))
}) })
It("Entity tracker should be aligned with consumers and publishers ", func() {
connection, err := Dial(context.Background(), []string{"amqp://"}, &AmqpConnOptions{
SASLType: amqp.SASLTypeAnonymous()})
Expect(err).To(BeNil())
Expect(connection).NotTo(BeNil())
queueName := generateNameWithDateTime("Entity tracker should be aligned with consumers and publishers")
_, err = connection.Management().DeclareQueue(context.Background(), &QuorumQueueSpecification{
Name: queueName,
})
Expect(err).To(BeNil())
publisher, err := connection.NewPublisher(context.Background(), &QueueAddress{Queue: queueName}, "test")
Expect(err).To(BeNil())
Expect(publisher).NotTo(BeNil())
consumer, err := connection.NewConsumer(context.Background(), queueName, nil)
Expect(err).To(BeNil())
Expect(consumer).NotTo(BeNil())
// check the entity tracker
Expect(connection.entitiesTracker).NotTo(BeNil())
entLen := 0
connection.entitiesTracker.consumers.Range(func(key, value interface{}) bool {
entLen++
return true
})
Expect(entLen).To(Equal(1))
entLen = 0
connection.entitiesTracker.publishers.Range(func(key, value interface{}) bool {
entLen++
return true
})
Expect(entLen).To(Equal(1))
Expect(consumer.Close(context.Background())).To(BeNil())
Expect(publisher.Close(context.Background())).To(BeNil())
entLen = 0
connection.entitiesTracker.consumers.Range(func(key, value interface{}) bool {
entLen++
return true
})
Expect(entLen).To(Equal(0))
entLen = 0
connection.entitiesTracker.publishers.Range(func(key, value interface{}) bool {
entLen++
return true
})
Expect(entLen).To(Equal(0))
err = connection.Management().DeleteQueue(context.Background(), queueName)
Expect(err).To(BeNil())
Expect(connection.Close(context.Background())).To(BeNil())
})
//It("AMQP TLS connection should success with SASLTypeAnonymous ", func() { //It("AMQP TLS connection should success with SASLTypeAnonymous ", func() {
// amqpConnection := NewAmqpConnection() // amqpConnection := NewAmqpConnection()
// Expect(amqpConnection).NotTo(BeNil()) // Expect(amqpConnection).NotTo(BeNil())

View File

@ -25,17 +25,23 @@ func (dc *DeliveryContext) Discard(ctx context.Context, e *amqp.Error) error {
return dc.receiver.RejectMessage(ctx, dc.message, e) return dc.receiver.RejectMessage(ctx, dc.message, e)
} }
func (dc *DeliveryContext) DiscardWithAnnotations(ctx context.Context, annotations amqp.Annotations) error { // copyAnnotations helper function to copy annotations
func copyAnnotations(annotations amqp.Annotations) (amqp.Annotations, error) {
if err := validateMessageAnnotations(annotations); err != nil { if err := validateMessageAnnotations(annotations); err != nil {
return nil, err
}
destination := make(amqp.Annotations)
for key, value := range annotations {
destination[key] = value
}
return destination, nil
}
func (dc *DeliveryContext) DiscardWithAnnotations(ctx context.Context, annotations amqp.Annotations) error {
destination, err := copyAnnotations(annotations)
if err != nil {
return err return err
} }
// copy the rabbitmq annotations to amqp annotations
destination := make(amqp.Annotations)
for keyA, value := range annotations {
destination[keyA] = value
}
return dc.receiver.ModifyMessage(ctx, dc.message, &amqp.ModifyMessageOptions{ return dc.receiver.ModifyMessage(ctx, dc.message, &amqp.ModifyMessageOptions{
DeliveryFailed: true, DeliveryFailed: true,
UndeliverableHere: true, UndeliverableHere: true,
@ -48,15 +54,10 @@ func (dc *DeliveryContext) Requeue(ctx context.Context) error {
} }
func (dc *DeliveryContext) RequeueWithAnnotations(ctx context.Context, annotations amqp.Annotations) error { func (dc *DeliveryContext) RequeueWithAnnotations(ctx context.Context, annotations amqp.Annotations) error {
if err := validateMessageAnnotations(annotations); err != nil { destination, err := copyAnnotations(annotations)
if err != nil {
return err return err
} }
// copy the rabbitmq annotations to amqp annotations
destination := make(amqp.Annotations)
for key, value := range annotations {
destination[key] = value
}
return dc.receiver.ModifyMessage(ctx, dc.message, &amqp.ModifyMessageOptions{ return dc.receiver.ModifyMessage(ctx, dc.message, &amqp.ModifyMessageOptions{
DeliveryFailed: false, DeliveryFailed: false,
UndeliverableHere: false, UndeliverableHere: false,
@ -144,5 +145,6 @@ func (c *Consumer) Receive(ctx context.Context) (*DeliveryContext, error) {
} }
func (c *Consumer) Close(ctx context.Context) error { func (c *Consumer) Close(ctx context.Context) error {
c.connection.entitiesTracker.removeConsumer(c)
return c.receiver.Load().Close(ctx) return c.receiver.Load().Close(ctx)
} }

View File

@ -73,7 +73,7 @@ var _ = Describe("Consumer stream test", func() {
dc, err := consumerOffsetValue.Receive(context.Background()) dc, err := consumerOffsetValue.Receive(context.Background())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("Message #%d", i+5))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("Message #%d", i+5)))
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
} }
@ -88,7 +88,7 @@ var _ = Describe("Consumer stream test", func() {
dc, err := consumerFirst.Receive(context.Background()) dc, err := consumerFirst.Receive(context.Background())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("Message #%d", i))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("Message #%d", i)))
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
} }
@ -107,7 +107,7 @@ var _ = Describe("Consumer stream test", func() {
dc, err := consumerLast.Receive(context.Background()) dc, err := consumerLast.Receive(context.Background())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
Expect(fmt.Sprintf("%s", dc.Message().GetData())).NotTo(Equal(fmt.Sprintf("Message #%d", 0))) Expect(string(dc.Message().GetData())).NotTo(Equal(fmt.Sprintf("Message #%d", 0)))
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
consumerNext, err := connection.NewConsumer(context.Background(), qName, &StreamConsumerOptions{ consumerNext, err := connection.NewConsumer(context.Background(), qName, &StreamConsumerOptions{
@ -125,7 +125,7 @@ var _ = Describe("Consumer stream test", func() {
dc, err = consumerNext.Receive(context.Background()) dc, err = consumerNext.Receive(context.Background())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal("the next message")) Expect(string(dc.Message().GetData())).To(Equal("the next message"))
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
signal <- struct{}{} signal <- struct{}{}
}() }()
@ -179,7 +179,7 @@ var _ = Describe("Consumer stream test", func() {
dc, err := consumer.Receive(context.Background()) dc, err := consumer.Receive(context.Background())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("Message #%d", i))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("Message #%d", i)))
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
} }
@ -200,7 +200,7 @@ var _ = Describe("Consumer stream test", func() {
dc, err := consumer.Receive(context.Background()) dc, err := consumer.Receive(context.Background())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("Message #%d", i))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("Message #%d", i)))
} }
Expect(consumer.Close(context.Background())).To(BeNil()) Expect(consumer.Close(context.Background())).To(BeNil())
@ -235,7 +235,7 @@ var _ = Describe("Consumer stream test", func() {
dc, err := consumerBanana.Receive(context.Background()) dc, err := consumerBanana.Receive(context.Background())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("banana #%d", i))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("banana #%d", i)))
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
} }
@ -254,7 +254,7 @@ var _ = Describe("Consumer stream test", func() {
dc, err := consumerApple.Receive(context.Background()) dc, err := consumerApple.Receive(context.Background())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("apple #%d", i))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("apple #%d", i)))
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
} }
@ -273,9 +273,9 @@ var _ = Describe("Consumer stream test", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
if i < 10 { if i < 10 {
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("banana #%d", i))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("banana #%d", i)))
} else { } else {
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("apple #%d", i-10))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("apple #%d", i-10)))
} }
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
} }
@ -296,10 +296,9 @@ var _ = Describe("Consumer stream test", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(dc.Message()).NotTo(BeNil()) Expect(dc.Message()).NotTo(BeNil())
if i < 10 { if i < 10 {
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf("apple #%d", i))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf("apple #%d", i)))
} else { } else {
Expect(fmt.Sprintf("%s", dc.Message().GetData())).To(Equal(fmt.Sprintf(" #%d", i-10))) Expect(string(dc.Message().GetData())).To(Equal(fmt.Sprintf(" #%d", i-10)))
} }
Expect(dc.Accept(context.Background())).To(BeNil()) Expect(dc.Accept(context.Background())).To(BeNil())
} }

View File

@ -81,6 +81,7 @@ var _ = Describe("NewConsumer tests", func() {
Expect(consumer.Close(context.Background())).To(BeNil()) Expect(consumer.Close(context.Background())).To(BeNil())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
nMessages, err := connection.Management().PurgeQueue(context.Background(), qName) nMessages, err := connection.Management().PurgeQueue(context.Background(), qName)
Expect(err).To(BeNil())
Expect(nMessages).To(Equal(1)) Expect(nMessages).To(Equal(1))
Expect(connection.Management().DeleteQueue(context.Background(), qName)).To(BeNil()) Expect(connection.Management().DeleteQueue(context.Background(), qName)).To(BeNil())
Expect(connection.Close(context.Background())).To(BeNil()) Expect(connection.Close(context.Background())).To(BeNil())
@ -116,6 +117,7 @@ var _ = Describe("NewConsumer tests", func() {
Expect(consumer.Close(context.Background())).To(BeNil()) Expect(consumer.Close(context.Background())).To(BeNil())
Expect(err).To(BeNil()) Expect(err).To(BeNil())
nMessages, err := connection.Management().PurgeQueue(context.Background(), qName) nMessages, err := connection.Management().PurgeQueue(context.Background(), qName)
Expect(err).To(BeNil())
Expect(nMessages).To(Equal(1)) Expect(nMessages).To(Equal(1))
Expect(connection.Management().DeleteQueue(context.Background(), qName)).To(BeNil()) Expect(connection.Management().DeleteQueue(context.Background(), qName)).To(BeNil())
Expect(connection.Close(context.Background())).To(BeNil()) Expect(connection.Close(context.Background())).To(BeNil())
@ -153,6 +155,7 @@ var _ = Describe("NewConsumer tests", func() {
Info: nil, Info: nil,
})).To(BeNil()) })).To(BeNil())
nMessages, err := connection.Management().PurgeQueue(context.Background(), qName) nMessages, err := connection.Management().PurgeQueue(context.Background(), qName)
Expect(err).To(BeNil())
Expect(nMessages).To(Equal(0)) Expect(nMessages).To(Equal(0))
Expect(consumer.Close(context.Background())).To(BeNil()) Expect(consumer.Close(context.Background())).To(BeNil())
Expect(connection.Management().DeleteQueue(context.Background(), qName)).To(BeNil()) Expect(connection.Management().DeleteQueue(context.Background(), qName)).To(BeNil())

View File

@ -4,10 +4,11 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/Azure/go-amqp"
"github.com/google/uuid"
"strconv" "strconv"
"time" "time"
"github.com/Azure/go-amqp"
"github.com/google/uuid"
) )
var ErrPreconditionFailed = errors.New("precondition Failed") var ErrPreconditionFailed = errors.New("precondition Failed")
@ -22,7 +23,6 @@ type AmqpManagement struct {
sender *amqp.Sender sender *amqp.Sender
receiver *amqp.Receiver receiver *amqp.Receiver
lifeCycle *LifeCycle lifeCycle *LifeCycle
cancel context.CancelFunc
} }
func NewAmqpManagement() *AmqpManagement { func NewAmqpManagement() *AmqpManagement {

View File

@ -91,6 +91,7 @@ var _ = Describe("AMQP publisher ", func() {
err = connection.management.DeleteQueue(context.Background(), qName) err = connection.management.DeleteQueue(context.Background(), qName)
Expect(err).To(BeNil()) Expect(err).To(BeNil())
publishResult, err = publisher.Publish(context.Background(), NewMessage([]byte("hello"))) publishResult, err = publisher.Publish(context.Background(), NewMessage([]byte("hello")))
Expect(publishResult).To(BeNil())
Expect(err).NotTo(BeNil()) Expect(err).NotTo(BeNil())
Expect(connection.Close(context.Background())) Expect(connection.Close(context.Background()))
}) })
@ -146,6 +147,8 @@ var _ = Describe("AMQP publisher ", func() {
Name: name, Name: name,
IsAutoDelete: false, IsAutoDelete: false,
}) })
Expect(err).To(BeNil())
msg = NewMessage([]byte("hello")) msg = NewMessage([]byte("hello"))
Expect(MessagePropertyToAddress(msg, &ExchangeAddress{Exchange: name})).To(BeNil()) Expect(MessagePropertyToAddress(msg, &ExchangeAddress{Exchange: name})).To(BeNil())
// the status should be StateReleased since the exchange does not have any binding // the status should be StateReleased since the exchange does not have any binding

View File

@ -37,6 +37,7 @@ var _ = Describe("AMQP Queue test ", func() {
// validate GET (query queue info) // validate GET (query queue info)
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName) queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
Expect(err).To(BeNil())
Expect(queueInfoReceived).To(Equal(queueInfo)) Expect(queueInfoReceived).To(Equal(queueInfo))
err = management.DeleteQueue(context.TODO(), queueName) err = management.DeleteQueue(context.TODO(), queueName)
@ -84,6 +85,7 @@ var _ = Describe("AMQP Queue test ", func() {
// validate GET (query queue info) // validate GET (query queue info)
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName) queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
Expect(err).To(BeNil())
Expect(queueInfoReceived).To(Equal(queueInfo)) Expect(queueInfoReceived).To(Equal(queueInfo))
err = management.DeleteQueue(context.TODO(), queueName) err = management.DeleteQueue(context.TODO(), queueName)
@ -108,6 +110,7 @@ var _ = Describe("AMQP Queue test ", func() {
Expect(queueInfo.Type()).To(Equal(Quorum)) Expect(queueInfo.Type()).To(Equal(Quorum))
// validate GET (query queue info) // validate GET (query queue info)
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName) queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
Expect(err).To(BeNil())
Expect(queueInfoReceived).To(Equal(queueInfo)) Expect(queueInfoReceived).To(Equal(queueInfo))
err = management.DeleteQueue(context.TODO(), queueName) err = management.DeleteQueue(context.TODO(), queueName)
@ -134,6 +137,7 @@ var _ = Describe("AMQP Queue test ", func() {
Expect(queueInfo.Type()).To(Equal(Classic)) Expect(queueInfo.Type()).To(Equal(Classic))
// validate GET (query queue info) // validate GET (query queue info)
queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName) queueInfoReceived, err := management.QueueInfo(context.TODO(), queueName)
Expect(err).To(BeNil())
Expect(queueInfoReceived).To(Equal(queueInfo)) Expect(queueInfoReceived).To(Equal(queueInfo))
err = management.DeleteQueue(context.TODO(), queueName) err = management.DeleteQueue(context.TODO(), queueName)

View File

@ -2,9 +2,10 @@ package rabbitmqamqp
import ( import (
"fmt" "fmt"
"github.com/Azure/go-amqp"
"math/rand" "math/rand"
"time" "time"
"github.com/Azure/go-amqp"
) )
const AtMostOnce = 0 const AtMostOnce = 0
@ -74,7 +75,7 @@ func random(max int) int {
} }
func validateMessageAnnotations(annotations amqp.Annotations) error { func validateMessageAnnotations(annotations amqp.Annotations) error {
for k, _ := range annotations { for k := range annotations {
switch tp := k.(type) { switch tp := k.(type) {
case string: case string:
if err := validateMessageAnnotationKey(tp); err != nil { if err := validateMessageAnnotationKey(tp); err != nil {

View File

@ -34,15 +34,15 @@ var _ = Describe("Converters", func() {
}) })
It("Converts from string logError", func() { It("Converts from string logError", func() {
v, err := CapacityFrom("10LL") _, err := CapacityFrom("10LL")
Expect(fmt.Sprintf("%s", err)). Expect(fmt.Sprintf("%s", err)).
To(ContainSubstring("Invalid unit size format")) To(ContainSubstring("Invalid unit size format"))
v, err = CapacityFrom("aGB") _, err = CapacityFrom("aGB")
Expect(fmt.Sprintf("%s", err)). Expect(fmt.Sprintf("%s", err)).
To(ContainSubstring("Invalid number format")) To(ContainSubstring("Invalid number format"))
v, err = CapacityFrom("") v, err := CapacityFrom("")
Expect(v).To(Equal(int64(0))) Expect(v).To(Equal(int64(0)))
Expect(err).To(BeNil()) Expect(err).To(BeNil())