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 {
|
||||
properties map[string]any
|
||||
featuresAvailable *featuresAvailable
|
||||
|
||||
azureConnection *amqp.Conn
|
||||
id string
|
||||
management *AmqpManagement
|
||||
|
|
@ -66,6 +69,11 @@ type AmqpConnection struct {
|
|||
entitiesTracker *entitiesTracker
|
||||
}
|
||||
|
||||
func (a *AmqpConnection) Properties() map[string]any {
|
||||
return a.properties
|
||||
|
||||
}
|
||||
|
||||
// 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.
|
||||
// See QueueAddress and ExchangeAddress for more information.
|
||||
|
|
@ -129,10 +137,11 @@ func Dial(ctx context.Context, addresses []string, connOptions *AmqpConnOptions,
|
|||
// create the connection
|
||||
|
||||
conn := &AmqpConnection{
|
||||
management: NewAmqpManagement(),
|
||||
lifeCycle: NewLifeCycle(),
|
||||
amqpConnOptions: connOptions,
|
||||
entitiesTracker: newEntitiesTracker(),
|
||||
management: NewAmqpManagement(),
|
||||
lifeCycle: NewLifeCycle(),
|
||||
amqpConnOptions: connOptions,
|
||||
entitiesTracker: newEntitiesTracker(),
|
||||
featuresAvailable: newFeaturesAvailable(),
|
||||
}
|
||||
tmp := make([]string, len(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)
|
||||
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))
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ var _ = Describe("AMQP connection Test", func() {
|
|||
SASLType: amqp.SASLTypePlain("guest", "guest")})
|
||||
|
||||
Expect(err).To(BeNil())
|
||||
Expect(connection.Properties()["product"]).To(Equal("RabbitMQ"))
|
||||
|
||||
err = connection.Close(context.Background())
|
||||
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