Validate Version (#32)
and product. Version should be >= 4.0 and product should be RabbitMQ. closes: https://github.com/rabbitmq/rabbitmq-amqp-go-client/issues/26 Signed-off-by: Gabriele Santomaggio <G.santomaggio@gmail.com>
This commit is contained in:
parent
4f689b7546
commit
db3f233aef
|
|
@ -56,6 +56,9 @@ type AmqpConnOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AmqpConnection struct {
|
type AmqpConnection struct {
|
||||||
|
properties map[string]any
|
||||||
|
featuresAvailable *featuresAvailable
|
||||||
|
|
||||||
azureConnection *amqp.Conn
|
azureConnection *amqp.Conn
|
||||||
id string
|
id string
|
||||||
management *AmqpManagement
|
management *AmqpManagement
|
||||||
|
|
@ -66,6 +69,11 @@ type AmqpConnection struct {
|
||||||
entitiesTracker *entitiesTracker
|
entitiesTracker *entitiesTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AmqpConnection) Properties() map[string]any {
|
||||||
|
return a.properties
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// NewPublisher creates a new Publisher that sends messages to the provided destination.
|
// NewPublisher creates a new Publisher that sends messages to the provided destination.
|
||||||
// The destination is a TargetAddress that can be a Queue or an Exchange with a routing key.
|
// The destination is a TargetAddress that can be a Queue or an Exchange with a routing key.
|
||||||
// See QueueAddress and ExchangeAddress for more information.
|
// See QueueAddress and ExchangeAddress for more information.
|
||||||
|
|
@ -129,10 +137,11 @@ func Dial(ctx context.Context, addresses []string, connOptions *AmqpConnOptions,
|
||||||
// create the connection
|
// create the connection
|
||||||
|
|
||||||
conn := &AmqpConnection{
|
conn := &AmqpConnection{
|
||||||
management: NewAmqpManagement(),
|
management: NewAmqpManagement(),
|
||||||
lifeCycle: NewLifeCycle(),
|
lifeCycle: NewLifeCycle(),
|
||||||
amqpConnOptions: connOptions,
|
amqpConnOptions: connOptions,
|
||||||
entitiesTracker: newEntitiesTracker(),
|
entitiesTracker: newEntitiesTracker(),
|
||||||
|
featuresAvailable: newFeaturesAvailable(),
|
||||||
}
|
}
|
||||||
tmp := make([]string, len(addresses))
|
tmp := make([]string, len(addresses))
|
||||||
copy(tmp, addresses)
|
copy(tmp, addresses)
|
||||||
|
|
@ -188,6 +197,20 @@ func (a *AmqpConnection) open(ctx context.Context, addresses []string, connOptio
|
||||||
Error("Failed to open connection", ExtractWithoutPassword(addr), err)
|
Error("Failed to open connection", ExtractWithoutPassword(addr), err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
a.properties = azureConnection.Properties()
|
||||||
|
err = a.featuresAvailable.ParseProperties(a.properties)
|
||||||
|
if err != nil {
|
||||||
|
Warn("Validate properties Error.", ExtractWithoutPassword(addr), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.featuresAvailable.is4OrMore {
|
||||||
|
Warn("The server version is less than 4.0.0", ExtractWithoutPassword(addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.featuresAvailable.isRabbitMQ {
|
||||||
|
Warn("The server is not RabbitMQ", ExtractWithoutPassword(addr))
|
||||||
|
}
|
||||||
|
|
||||||
Debug("Connected to", ExtractWithoutPassword(addr))
|
Debug("Connected to", ExtractWithoutPassword(addr))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ var _ = Describe("AMQP connection Test", func() {
|
||||||
SASLType: amqp.SASLTypePlain("guest", "guest")})
|
SASLType: amqp.SASLTypePlain("guest", "guest")})
|
||||||
|
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
Expect(connection.Properties()["product"]).To(Equal("RabbitMQ"))
|
||||||
|
|
||||||
err = connection.Close(context.Background())
|
err = connection.Close(context.Background())
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
package rabbitmqamqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Version struct {
|
||||||
|
Major int
|
||||||
|
Minor int
|
||||||
|
Patch int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Version) Compare(other Version) int {
|
||||||
|
if v.Major != other.Major {
|
||||||
|
return v.Major - other.Major
|
||||||
|
}
|
||||||
|
if v.Minor != other.Minor {
|
||||||
|
return v.Minor - other.Minor
|
||||||
|
}
|
||||||
|
return v.Patch - other.Patch
|
||||||
|
}
|
||||||
|
|
||||||
|
type featuresAvailable struct {
|
||||||
|
is4OrMore bool
|
||||||
|
is41OrMore bool
|
||||||
|
isRabbitMQ bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFeaturesAvailable() *featuresAvailable {
|
||||||
|
return &featuresAvailable{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *featuresAvailable) ParseProperties(properties map[string]any) error {
|
||||||
|
if properties["version"] == nil {
|
||||||
|
return fmt.Errorf("missing version property")
|
||||||
|
}
|
||||||
|
|
||||||
|
version := extractVersion(properties["version"].(string))
|
||||||
|
if version == "" {
|
||||||
|
return fmt.Errorf("invalid version format: %s", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.is4OrMore = isVersionGreaterOrEqual(version, "4.0.0")
|
||||||
|
f.is41OrMore = isVersionGreaterOrEqual(version, "4.1.0")
|
||||||
|
f.isRabbitMQ = strings.EqualFold(properties["product"].(string), "RabbitMQ")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractVersion(fullVersion string) string {
|
||||||
|
pattern := `(\d+\.\d+\.\d+)`
|
||||||
|
regex := regexp.MustCompile(pattern)
|
||||||
|
match := regex.FindStringSubmatch(fullVersion)
|
||||||
|
|
||||||
|
if len(match) > 1 {
|
||||||
|
return match[1]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseVersion(version string) (Version, error) {
|
||||||
|
parts := strings.Split(version, ".")
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return Version{}, fmt.Errorf("invalid version format: %s", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
major, err := strconv.Atoi(parts[0])
|
||||||
|
if err != nil {
|
||||||
|
return Version{}, fmt.Errorf("invalid major version: %s", parts[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
minor, err := strconv.Atoi(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return Version{}, fmt.Errorf("invalid minor version: %s", parts[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
patch, err := strconv.Atoi(parts[2])
|
||||||
|
if err != nil {
|
||||||
|
return Version{}, fmt.Errorf("invalid patch version: %s", parts[2])
|
||||||
|
}
|
||||||
|
|
||||||
|
return Version{Major: major, Minor: minor, Patch: patch}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isVersionGreaterOrEqual(version, target string) bool {
|
||||||
|
v1, err := parseVersion(version)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
v2, err := parseVersion(target)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return v1.Compare(v2) >= 0
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
package rabbitmqamqp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Available Features", func() {
|
||||||
|
|
||||||
|
It("Parse Version", func() {
|
||||||
|
v, err := parseVersion("1.2.3")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(v).To(Equal(Version{Major: 1, Minor: 2, Patch: 3}))
|
||||||
|
|
||||||
|
_, err = parseVersion("1.2")
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("invalid version format: 1.2"))
|
||||||
|
|
||||||
|
_, err = parseVersion("error.3.3")
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("invalid major version: error"))
|
||||||
|
|
||||||
|
_, err = parseVersion("1.error.3")
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("invalid minor version: error"))
|
||||||
|
|
||||||
|
_, err = parseVersion("1.2.error")
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(fmt.Sprintf("%s", err)).To(ContainSubstring("invalid patch version: error"))
|
||||||
|
|
||||||
|
v, err = parseVersion(extractVersion("3.12.1-rc1"))
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(v).To(Equal(Version{Major: 3, Minor: 12, Patch: 1}))
|
||||||
|
|
||||||
|
v, err = parseVersion(extractVersion("3.13.1-alpha.234"))
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(v).To(Equal(Version{Major: 3, Minor: 13, Patch: 1}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Is Version Greater Or Equal", func() {
|
||||||
|
Expect(isVersionGreaterOrEqual("1.2.3", "1.2.3")).To(BeTrue())
|
||||||
|
Expect(isVersionGreaterOrEqual("1.2.3", "1.2.2")).To(BeTrue())
|
||||||
|
Expect(isVersionGreaterOrEqual("1.2.3", "1.2.4")).To(BeFalse())
|
||||||
|
Expect(isVersionGreaterOrEqual("1.2.3", "1.3.3")).To(BeFalse())
|
||||||
|
Expect(isVersionGreaterOrEqual("1.2.3", "2.2.3")).To(BeFalse())
|
||||||
|
Expect(isVersionGreaterOrEqual("3.1.3-alpha.1", "2.2.3")).To(BeFalse())
|
||||||
|
Expect(isVersionGreaterOrEqual("3.3.3-rc.1", "2.2.3")).To(BeFalse())
|
||||||
|
|
||||||
|
Expect(isVersionGreaterOrEqual("error.3.2", "2.2.3")).To(BeFalse())
|
||||||
|
Expect(isVersionGreaterOrEqual("4.3.2", "2.error.3")).To(BeFalse())
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Available Features check Version", func() {
|
||||||
|
var availableFeatures = newFeaturesAvailable()
|
||||||
|
Expect(availableFeatures).NotTo(BeNil())
|
||||||
|
Expect(availableFeatures.ParseProperties(map[string]any{})).NotTo(BeNil())
|
||||||
|
|
||||||
|
Expect(availableFeatures.ParseProperties(map[string]any{
|
||||||
|
"version": "3.9.0",
|
||||||
|
"product": "RabbitMQ",
|
||||||
|
})).To(BeNil())
|
||||||
|
Expect(availableFeatures.is4OrMore).To(BeFalse())
|
||||||
|
Expect(availableFeatures.is41OrMore).To(BeFalse())
|
||||||
|
Expect(availableFeatures.isRabbitMQ).To(BeTrue())
|
||||||
|
|
||||||
|
Expect(availableFeatures.ParseProperties(map[string]any{
|
||||||
|
"version": "3.11.0",
|
||||||
|
"product": "RabbitMQ",
|
||||||
|
})).To(BeNil())
|
||||||
|
Expect(availableFeatures.is4OrMore).To(BeFalse())
|
||||||
|
Expect(availableFeatures.is41OrMore).To(BeFalse())
|
||||||
|
Expect(availableFeatures.isRabbitMQ).To(BeTrue())
|
||||||
|
|
||||||
|
Expect(availableFeatures.ParseProperties(map[string]any{
|
||||||
|
"version": "4.0.6-rc.1",
|
||||||
|
"product": "RabbitMQ",
|
||||||
|
})).To(BeNil())
|
||||||
|
|
||||||
|
Expect(availableFeatures.is4OrMore).To(BeTrue())
|
||||||
|
Expect(availableFeatures.is41OrMore).To(BeFalse())
|
||||||
|
Expect(availableFeatures.isRabbitMQ).To(BeTrue())
|
||||||
|
|
||||||
|
Expect(availableFeatures.ParseProperties(map[string]any{
|
||||||
|
"version": "4.1.0",
|
||||||
|
"product": "RabbitMQ",
|
||||||
|
})).To(BeNil())
|
||||||
|
|
||||||
|
Expect(availableFeatures.is4OrMore).To(BeTrue())
|
||||||
|
Expect(availableFeatures.is41OrMore).To(BeTrue())
|
||||||
|
Expect(availableFeatures.isRabbitMQ).To(BeTrue())
|
||||||
|
|
||||||
|
Expect(availableFeatures.ParseProperties(map[string]any{
|
||||||
|
"version": "4.1.0-beta.1",
|
||||||
|
"product": "Boh",
|
||||||
|
})).To(BeNil())
|
||||||
|
|
||||||
|
Expect(availableFeatures.is4OrMore).To(BeTrue())
|
||||||
|
Expect(availableFeatures.is41OrMore).To(BeTrue())
|
||||||
|
Expect(availableFeatures.isRabbitMQ).To(BeFalse())
|
||||||
|
|
||||||
|
Expect(availableFeatures.ParseProperties(map[string]any{
|
||||||
|
"version": "4.1.0-rc.8",
|
||||||
|
"product": "rabbitmq",
|
||||||
|
})).To(BeNil())
|
||||||
|
|
||||||
|
Expect(availableFeatures.is4OrMore).To(BeTrue())
|
||||||
|
Expect(availableFeatures.is41OrMore).To(BeTrue())
|
||||||
|
Expect(availableFeatures.isRabbitMQ).To(BeTrue())
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue