From 4112bb937483956855f31cf6a888d5d7f110ec1a Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 15:35:35 +0100 Subject: [PATCH 01/22] add idea folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fcb046b..7695a62 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ bin/* src coverage* +.idea From 96172163d7f84bc03d4029cc8db050491f0f7c90 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 15:35:52 +0100 Subject: [PATCH 02/22] redeclare module --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c71085c..a432fa7 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/michaelklishin/rabbit-hole/v2 +module github.com/Serviceware/rabbit-hole/v2 require ( github.com/kr/pretty v0.1.0 // indirect From 0941b92361d25cdcc0bc9615b0bb5c461ca34dd8 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 15:36:09 +0100 Subject: [PATCH 03/22] add aliveness endpoint --- misc.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/misc.go b/misc.go index 6c64e07..aa80ffe 100644 --- a/misc.go +++ b/misc.go @@ -64,3 +64,21 @@ func (c *Client) Overview() (rec *Overview, err error) { return rec, nil } + +type Aliveness struct { + Status string `json:"status"` +} + +// Aliveness ... +func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) { + req, err := newGETRequest(c, "overview") + if err != nil { + return nil, err + } + + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err + } + + return rec, nil +} \ No newline at end of file From de83739a24c3a1c14ef550194dc9c9743896c6b1 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 15:52:37 +0100 Subject: [PATCH 04/22] fixed path for alivness request --- misc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc.go b/misc.go index aa80ffe..9ccfa44 100644 --- a/misc.go +++ b/misc.go @@ -71,7 +71,7 @@ type Aliveness struct { // Aliveness ... func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) { - req, err := newGETRequest(c, "overview") + req, err := newGETRequest(c, "aliveness-test/" + vhost) if err != nil { return nil, err } From a5acc29dd9e3a5bb6d4d5900e8f42e9edc838259 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 17:39:00 +0100 Subject: [PATCH 05/22] add aliveness check --- aliveness.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 aliveness.go diff --git a/aliveness.go b/aliveness.go new file mode 100644 index 0000000..cff0eed --- /dev/null +++ b/aliveness.go @@ -0,0 +1,20 @@ +package rabbithole + +// Aliveness represents response from aliveness-test endpoint +type Aliveness struct { + Status string `json:"status"` +} + +// Aliveness endpoint declares a test queue, then publishes a message and consumes a message +func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) { + req, err := newGETRequest(c, "aliveness-test/"+vhost) + if err != nil { + return nil, err + } + + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err + } + + return rec, nil +} From 8567baa79dc25e4d0ddd9050e3be21958387afaa Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 17:39:08 +0100 Subject: [PATCH 06/22] add health check --- health.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 health.go diff --git a/health.go b/health.go new file mode 100644 index 0000000..20dd687 --- /dev/null +++ b/health.go @@ -0,0 +1,37 @@ +package rabbithole + +// Health represents response from healthchecks endpoint +type Health struct { + Status string `json:"status"` + Reason string `json:"reason"` +} + +// HealthChecks endpoint checks if the application is running, +// channels and queues can be listed, and that no alarms are raised +func (c *Client) HealthCheck() (rec *Health, err error) { + req, err := newGETRequest(c, "healthchecks/node") + if err != nil { + return nil, err + } + + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err + } + + return rec, nil +} + +// HealthChecks endpoint checks for a given node if the application is running, +// channels and queues can be listed, and that no alarms are raised +func (c *Client) HealthCheckFor(node string) (rec *Health, err error) { + req, err := newGETRequest(c, "healthchecks/node/"+node) + if err != nil { + return nil, err + } + + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err + } + + return rec, nil +} From 680857d9e1f1d21a920f4ffebbf099e8ec57a2ee Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 17:39:20 +0100 Subject: [PATCH 07/22] moved code to dedicated file --- misc.go | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/misc.go b/misc.go index 9ccfa44..6c64e07 100644 --- a/misc.go +++ b/misc.go @@ -64,21 +64,3 @@ func (c *Client) Overview() (rec *Overview, err error) { return rec, nil } - -type Aliveness struct { - Status string `json:"status"` -} - -// Aliveness ... -func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) { - req, err := newGETRequest(c, "aliveness-test/" + vhost) - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil -} \ No newline at end of file From 84705b24919baf13f57042a3c4428003f34fddc1 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 17:39:30 +0100 Subject: [PATCH 08/22] add test --- rabbithole_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/rabbithole_test.go b/rabbithole_test.go index 7d2ac7f..8bbb930 100644 --- a/rabbithole_test.go +++ b/rabbithole_test.go @@ -91,6 +91,44 @@ var _ = Describe("Rabbithole", func() { rmqc, _ = NewClient("http://127.0.0.1:15672", "guest", "guest") }) + Context("GET /aliveness-test/%2F", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + + ensureNonZeroMessageRate(ch) + + res, err := rmqc.Aliveness("%2F") + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + + ch.Close() + }) + }) + + Context("GET /healthchecks/nodes", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + + ensureNonZeroMessageRate(ch) + + res, err := rmqc.HealthCheck() + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + + ch.Close() + }) + }) + Context("GET /overview", func() { It("returns decoded response", func() { conn := openConnection("/") From 09dbdc98a433ca34d0c1badc8abb17b28e5453fb Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 17:39:43 +0100 Subject: [PATCH 09/22] add documentation --- README.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 84653ec..5f43868 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,32 @@ RabbitMQ HTTP API has to be [configured to use TLS](http://www.rabbitmq.com/mana ### Getting Overview ``` go -res, err := rmqc.Overview() +resp, err := rmqc.Overview() ``` + +### Aliveness Check + +``` go +// declares a queue, then publishes and consumes a message +resp, err := rmqc.Aliveness("%2F") +// => Aliveness, err +``` + + +### Health Check + +``` go +// checks if application is running, channels and queues can be listed and no alarms are in effect +resp, err := rmqc.HealthCheck() +// => Health, err + +// checks for node +resp, err := rmqc.HealthCheck("rabbit@mercurio") +// => Health, err +``` + + ### Node and Cluster Status ``` go From b602ef1271d585f026b26e141cd9f6d645fdffdd Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 17:52:03 +0100 Subject: [PATCH 10/22] removed entry from gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7695a62..fcb046b 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,3 @@ bin/* src coverage* -.idea From 8a6ff2d61e53d8f08e9926d549c7368dc4c006ad Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Thu, 14 Jan 2021 17:52:43 +0100 Subject: [PATCH 11/22] changed module name --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index a432fa7..c71085c 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/Serviceware/rabbit-hole/v2 +module github.com/michaelklishin/rabbit-hole/v2 require ( github.com/kr/pretty v0.1.0 // indirect From a6991a09efbe56996efa23c5f1a6f0cab9c909c4 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Mon, 18 Jan 2021 13:35:47 +0100 Subject: [PATCH 12/22] moved checks to single file --- README.md | 22 ---------------------- aliveness.go | 20 -------------------- health.go => health_checks.go | 19 +++++++++++++++++++ 3 files changed, 19 insertions(+), 42 deletions(-) delete mode 100644 aliveness.go rename health.go => health_checks.go (66%) diff --git a/README.md b/README.md index 5f43868..b239559 100644 --- a/README.md +++ b/README.md @@ -86,28 +86,6 @@ resp, err := rmqc.Overview() ``` -### Aliveness Check - -``` go -// declares a queue, then publishes and consumes a message -resp, err := rmqc.Aliveness("%2F") -// => Aliveness, err -``` - - -### Health Check - -``` go -// checks if application is running, channels and queues can be listed and no alarms are in effect -resp, err := rmqc.HealthCheck() -// => Health, err - -// checks for node -resp, err := rmqc.HealthCheck("rabbit@mercurio") -// => Health, err -``` - - ### Node and Cluster Status ``` go diff --git a/aliveness.go b/aliveness.go deleted file mode 100644 index cff0eed..0000000 --- a/aliveness.go +++ /dev/null @@ -1,20 +0,0 @@ -package rabbithole - -// Aliveness represents response from aliveness-test endpoint -type Aliveness struct { - Status string `json:"status"` -} - -// Aliveness endpoint declares a test queue, then publishes a message and consumes a message -func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) { - req, err := newGETRequest(c, "aliveness-test/"+vhost) - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil -} diff --git a/health.go b/health_checks.go similarity index 66% rename from health.go rename to health_checks.go index 20dd687..d8f396c 100644 --- a/health.go +++ b/health_checks.go @@ -35,3 +35,22 @@ func (c *Client) HealthCheckFor(node string) (rec *Health, err error) { return rec, nil } + +// Aliveness represents response from aliveness-test endpoint +type Aliveness struct { + Status string `json:"status"` +} + +// Aliveness endpoint declares a test queue, then publishes a message and consumes a message +func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) { + req, err := newGETRequest(c, "aliveness-test/"+vhost) + if err != nil { + return nil, err + } + + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err + } + + return rec, nil +} From eecf2dca94a88aae54eee2187f10396ba8b98fde Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Mon, 18 Jan 2021 14:28:33 +0100 Subject: [PATCH 13/22] added health checks --- health_checks.go | 143 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/health_checks.go b/health_checks.go index d8f396c..2f1b3a0 100644 --- a/health_checks.go +++ b/health_checks.go @@ -1,5 +1,148 @@ package rabbithole +import "strconv" + +type TimeUnit string + +const ( + DAYS TimeUnit = "days" + WEEKS TimeUnit = "weeks" + MONTHS TimeUnit = "months" + YEARS TimeUnit = "years" +) + +type Protocol string + +const ( + AMQP091 Protocol = "amqp091" + AMQP10 Protocol = "amqp10" + MQTT Protocol = "mqtt" + STOMP Protocol = "stomp" + WEB_MQTT Protocol = "web-mqtt" + WEB_STOMP Protocol = "web-stomp" +) + +// Responds a 200 OK if there are no alarms in effect in the cluster, otherwise responds with a 503 Service Unavailable. +func (c *Client) HealthCheckAlarms() error { + req, err := newGETRequest(c, "health/checks/alarms") + if err != nil { + return err + } + + if _, err = executeRequest(c, req); err != nil { + return err + } + + return nil +} + +// Responds a 200 OK if there are no local alarms in effect on the target node, otherwise responds with a 503 Service Unavailable. +func (c *Client) HealthCheckLocalAlarms() error { + req, err := newGETRequest(c, "health/checks/local-alarms") + if err != nil { + return err + } + + if _, err = executeRequest(c, req); err != nil { + return err + } + + return nil +} + + +// Checks the expiration date on the certificates for every listener configured to use TLS. +// Responds a 200 OK if all certificates are valid (have not expired), otherwise responds with a 503 Service Unavailable. +// Valid units: days, weeks, months, years. The value of the within argument is the number of units. +// So, when within is 2 and unit is "months", the expiration period used by the check will be the next two months. +func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (rec *Health, err error) { + req, err := newGETRequest(c, "health/checks/certificate-expiration/"+strconv.Itoa(int(within))+"/"+string(unit)) + if err != nil { + return nil, err + } + + if _, err = executeRequest(c, req); err != nil { + return nil, err + } + + return rec, nil +} + +// Responds a 200 OK if there is an active listener on the give port, otherwise responds with a 503 Service Unavailable. +func (c *Client) HealthCheckPortListenerListener(port uint) error { + req, err := newGETRequest(c, "health/checks/port-listener/"+strconv.Itoa(int(port))) + if err != nil { + return err + } + + if _, err = executeRequest(c, req); err != nil { + return err + } + + return nil +} + +// Responds a 200 OK if there is an active listener for the given protocol, otherwise responds with a 503 Service Unavailable. +// Valid protocol names are: amqp091, amqp10, mqtt, stomp, web-mqtt, web-stomp. +func (c *Client) HealthCheckProtocolListener(protocol Protocol) error { + req, err := newGETRequest(c, "health/checks/protocol-listener/"+string(protocol)) + if err != nil { + return err + } + + if _, err = executeRequest(c, req); err != nil { + return err + } + + return nil +} + +// Responds a 200 OK if all virtual hosts and running on the target node, otherwise responds with a 503 Service Unavailable. +func (c *Client) HealthCheckVirtualHosts() error { + req, err := newGETRequest(c, "health/checks/virtual-hosts") + if err != nil { + return err + } + + if _, err = executeRequest(c, req); err != nil { + return err + } + + return nil +} + +// Checks if there are classic mirrored queues without synchronised mirrors online (queues that would potentially lose data if the target node is shut down). +// Responds a 200 OK if there are no such classic mirrored queues, otherwise responds with a 503 Service Unavailable. +func (c *Client) HealthCheckNodeIsMirrorSyncCritical() error { + req, err := newGETRequest(c, "health/checks/node-is-mirror-sync-critical") + if err != nil { + return err + } + + if _, err = executeRequest(c, req); err != nil { + return err + } + + return nil +} + +// Checks if there are quorum queues with minimum online quorum (queues that would lose their quorum and availability if the target node is shut down). +// Responds a 200 OK if there are no such quorum queues, otherwise responds with a 503 Service Unavailable. +func (c *Client) HealthCheckNodeIsQuorumCritical() error { + req, err := newGETRequest(c, "health/checks/node-is-quorum-critical") + if err != nil { + return err + } + + if _, err = executeRequest(c, req); err != nil { + return err + } + + return nil +} + +// Deprecated health check api + // Health represents response from healthchecks endpoint type Health struct { Status string `json:"status"` From 38f174d3d02ad4a32a06c13142b352661f24e887 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Mon, 18 Jan 2021 15:08:57 +0100 Subject: [PATCH 14/22] return response from health checks --- health_checks.go | 96 ++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/health_checks.go b/health_checks.go index 2f1b3a0..58b37f3 100644 --- a/health_checks.go +++ b/health_checks.go @@ -5,10 +5,10 @@ import "strconv" type TimeUnit string const ( - DAYS TimeUnit = "days" - WEEKS TimeUnit = "weeks" - MONTHS TimeUnit = "months" - YEARS TimeUnit = "years" + SECONDS TimeUnit = "seconds" + DAYS TimeUnit = "days" + MONTHS TimeUnit = "months" + YEARS TimeUnit = "years" ) type Protocol string @@ -22,35 +22,43 @@ const ( WEB_STOMP Protocol = "web-stomp" ) +// Health represents response from healthchecks endpoint +type Health struct { + Status string `json:"status"` + Reason string `json:"reason"` + Missing string `json:"missing"` + Ports []string `json:"ports"` + Protocols []string `json:"protocols"` +} + // Responds a 200 OK if there are no alarms in effect in the cluster, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckAlarms() error { +func (c *Client) HealthCheckAlarms() (rec *Health, err error) { req, err := newGETRequest(c, "health/checks/alarms") if err != nil { - return err + return nil, err } - if _, err = executeRequest(c, req); err != nil { - return err + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err } - return nil + return rec, nil } // Responds a 200 OK if there are no local alarms in effect on the target node, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckLocalAlarms() error { +func (c *Client) HealthCheckLocalAlarms() (rec *Health, err error) { req, err := newGETRequest(c, "health/checks/local-alarms") if err != nil { - return err + return nil, err } - if _, err = executeRequest(c, req); err != nil { - return err + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err } - return nil + return rec, nil } - // Checks the expiration date on the certificates for every listener configured to use TLS. // Responds a 200 OK if all certificates are valid (have not expired), otherwise responds with a 503 Service Unavailable. // Valid units: days, weeks, months, years. The value of the within argument is the number of units. @@ -61,7 +69,7 @@ func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (r return nil, err } - if _, err = executeRequest(c, req); err != nil { + if err = executeAndParseRequest(c, req, &rec); err != nil { return nil, err } @@ -69,86 +77,80 @@ func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (r } // Responds a 200 OK if there is an active listener on the give port, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckPortListenerListener(port uint) error { +func (c *Client) HealthCheckPortListenerListener(port uint) (rec *Health, err error) { req, err := newGETRequest(c, "health/checks/port-listener/"+strconv.Itoa(int(port))) if err != nil { - return err + return nil, err } - if _, err = executeRequest(c, req); err != nil { - return err + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err } - return nil + return rec, nil } // Responds a 200 OK if there is an active listener for the given protocol, otherwise responds with a 503 Service Unavailable. // Valid protocol names are: amqp091, amqp10, mqtt, stomp, web-mqtt, web-stomp. -func (c *Client) HealthCheckProtocolListener(protocol Protocol) error { +func (c *Client) HealthCheckProtocolListener(protocol Protocol) (rec *Health, err error) { req, err := newGETRequest(c, "health/checks/protocol-listener/"+string(protocol)) if err != nil { - return err + return nil, err } - if _, err = executeRequest(c, req); err != nil { - return err + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err } - return nil + return rec, nil } // Responds a 200 OK if all virtual hosts and running on the target node, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckVirtualHosts() error { +func (c *Client) HealthCheckVirtualHosts() (rec *Health, err error) { req, err := newGETRequest(c, "health/checks/virtual-hosts") if err != nil { - return err + return nil, err } - if _, err = executeRequest(c, req); err != nil { - return err + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err } - return nil + return rec, nil } // Checks if there are classic mirrored queues without synchronised mirrors online (queues that would potentially lose data if the target node is shut down). // Responds a 200 OK if there are no such classic mirrored queues, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckNodeIsMirrorSyncCritical() error { +func (c *Client) HealthCheckNodeIsMirrorSyncCritical() (rec *Health, err error) { req, err := newGETRequest(c, "health/checks/node-is-mirror-sync-critical") if err != nil { - return err + return nil, err } - if _, err = executeRequest(c, req); err != nil { - return err + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err } - return nil + return rec, nil } // Checks if there are quorum queues with minimum online quorum (queues that would lose their quorum and availability if the target node is shut down). // Responds a 200 OK if there are no such quorum queues, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckNodeIsQuorumCritical() error { +func (c *Client) HealthCheckNodeIsQuorumCritical() (rec *Health, err error) { req, err := newGETRequest(c, "health/checks/node-is-quorum-critical") if err != nil { - return err + return nil, err } - if _, err = executeRequest(c, req); err != nil { - return err + if err = executeAndParseRequest(c, req, &rec); err != nil { + return nil, err } - return nil + return rec, nil } // Deprecated health check api -// Health represents response from healthchecks endpoint -type Health struct { - Status string `json:"status"` - Reason string `json:"reason"` -} - // HealthChecks endpoint checks if the application is running, // channels and queues can be listed, and that no alarms are raised func (c *Client) HealthCheck() (rec *Health, err error) { From 7577e8f75bceb15bc50c561813cf9bc413f364be Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Mon, 18 Jan 2021 15:09:12 +0100 Subject: [PATCH 15/22] implemented tests for health checks --- rabbithole_test.go | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/rabbithole_test.go b/rabbithole_test.go index 8bbb930..59a3dd7 100644 --- a/rabbithole_test.go +++ b/rabbithole_test.go @@ -91,6 +91,102 @@ var _ = Describe("Rabbithole", func() { rmqc, _ = NewClient("http://127.0.0.1:15672", "guest", "guest") }) + Context("GET /health/checks/alarms", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + res, err := rmqc.HealthCheckAlarms() + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + }) + }) + + Context("GET /health/checks/local-alarms", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + res, err := rmqc.HealthCheckLocalAlarms() + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + }) + }) + + Context("GET /health/checks/certificate-expiration/1/days", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + res, err := rmqc.HealthCheckCertificateExpiration(1, DAYS) + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + }) + }) + + Context("GET /health/checks/port-listener/5672", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + res, err := rmqc.HealthCheckPortListenerListener(5672) + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + }) + }) + + Context("GET /health/checks/protocol-listener/amqp091", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + res, err := rmqc.HealthCheckProtocolListener(AMQP091) + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + }) + }) + + Context("GET /health/checks/virtual-hosts", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + res, err := rmqc.HealthCheckVirtualHosts() + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + }) + }) + + Context("GET /health/checks/node-is-mirror-sync-critical", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + res, err := rmqc.HealthCheckNodeIsMirrorSyncCritical() + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + }) + }) + + Context("GET /health/checks/node-is-quorum-critical", func() { + It("returns decoded response", func() { + conn := openConnection("/") + defer conn.Close() + + res, err := rmqc.HealthCheckNodeIsMirrorSyncCritical() + Ω(err).Should(BeNil()) + + Ω(res.Status).Should(Equal("ok")) + }) + }) + Context("GET /aliveness-test/%2F", func() { It("returns decoded response", func() { conn := openConnection("/") From 4b93c76aaaef00afc1b5d98e64d2b63baa2bf921 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Mon, 18 Jan 2021 15:33:24 +0100 Subject: [PATCH 16/22] get channel from connection --- rabbithole_test.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/rabbithole_test.go b/rabbithole_test.go index 59a3dd7..6c17c24 100644 --- a/rabbithole_test.go +++ b/rabbithole_test.go @@ -96,6 +96,10 @@ var _ = Describe("Rabbithole", func() { conn := openConnection("/") defer conn.Close() + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + defer ch.Close() + res, err := rmqc.HealthCheckAlarms() Ω(err).Should(BeNil()) @@ -108,6 +112,10 @@ var _ = Describe("Rabbithole", func() { conn := openConnection("/") defer conn.Close() + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + defer ch.Close() + res, err := rmqc.HealthCheckLocalAlarms() Ω(err).Should(BeNil()) @@ -120,6 +128,10 @@ var _ = Describe("Rabbithole", func() { conn := openConnection("/") defer conn.Close() + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + defer ch.Close() + res, err := rmqc.HealthCheckCertificateExpiration(1, DAYS) Ω(err).Should(BeNil()) @@ -132,6 +144,10 @@ var _ = Describe("Rabbithole", func() { conn := openConnection("/") defer conn.Close() + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + defer ch.Close() + res, err := rmqc.HealthCheckPortListenerListener(5672) Ω(err).Should(BeNil()) @@ -144,6 +160,10 @@ var _ = Describe("Rabbithole", func() { conn := openConnection("/") defer conn.Close() + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + defer ch.Close() + res, err := rmqc.HealthCheckProtocolListener(AMQP091) Ω(err).Should(BeNil()) @@ -156,6 +176,10 @@ var _ = Describe("Rabbithole", func() { conn := openConnection("/") defer conn.Close() + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + defer ch.Close() + res, err := rmqc.HealthCheckVirtualHosts() Ω(err).Should(BeNil()) @@ -168,6 +192,10 @@ var _ = Describe("Rabbithole", func() { conn := openConnection("/") defer conn.Close() + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + defer ch.Close() + res, err := rmqc.HealthCheckNodeIsMirrorSyncCritical() Ω(err).Should(BeNil()) @@ -180,6 +208,10 @@ var _ = Describe("Rabbithole", func() { conn := openConnection("/") defer conn.Close() + ch, err := conn.Channel() + Ω(err).Should(BeNil()) + defer ch.Close() + res, err := rmqc.HealthCheckNodeIsMirrorSyncCritical() Ω(err).Should(BeNil()) From 14b755d24ab580c5a4f32a7828a82f88049261a3 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Tue, 26 Jan 2021 15:52:19 +0100 Subject: [PATCH 17/22] add dedicated types for checks --- health_checks.go | 55 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/health_checks.go b/health_checks.go index 58b37f3..2790fa3 100644 --- a/health_checks.go +++ b/health_checks.go @@ -1,6 +1,9 @@ package rabbithole -import "strconv" +import ( + "strconv" + "strings" +) type TimeUnit string @@ -22,13 +25,28 @@ const ( WEB_STOMP Protocol = "web-stomp" ) +type Check interface { + // Returns true if the check is ok, otherwise false + Ok() bool + + // Return true if the check failed, otherwise false + Failed() bool +} + // Health represents response from healthchecks endpoint type Health struct { - Status string `json:"status"` - Reason string `json:"reason"` - Missing string `json:"missing"` - Ports []string `json:"ports"` - Protocols []string `json:"protocols"` + Check + Status string `json:"status"` + Error string `json:"error"` + Reason string `json:"reason"` +} + +func (h *Health) Ok() bool { + return h.Status == "ok" +} + +func (h *Health) Failed() bool { + return !h.Ok() } // Responds a 200 OK if there are no alarms in effect in the cluster, otherwise responds with a 503 Service Unavailable. @@ -76,23 +94,42 @@ func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (r return rec, nil } +type PortListenerHealth struct { + Status string `json:"status"` + Error string `json:"error"'` + Reason string `json:"reason"` + Port string + Ports []string `json:"ports"` +} + // Responds a 200 OK if there is an active listener on the give port, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckPortListenerListener(port uint) (rec *Health, err error) { +func (c *Client) HealthCheckPortListenerListener(port uint) (rec *PortListenerHealth, err error) { req, err := newGETRequest(c, "health/checks/port-listener/"+strconv.Itoa(int(port))) if err != nil { return nil, err } if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err + + if !strings.Contains(err.Error(), "503") { + return nil, err + } + } return rec, nil } +type ProtocolListenerHealth struct { + Status string `json:"status"` + Reason string `json:"reason"` + Missing string `json:"missing"` + Protocols []string `json:"protocols"` +} + // Responds a 200 OK if there is an active listener for the given protocol, otherwise responds with a 503 Service Unavailable. // Valid protocol names are: amqp091, amqp10, mqtt, stomp, web-mqtt, web-stomp. -func (c *Client) HealthCheckProtocolListener(protocol Protocol) (rec *Health, err error) { +func (c *Client) HealthCheckProtocolListener(protocol Protocol) (rec *ProtocolListenerHealth, err error) { req, err := newGETRequest(c, "health/checks/protocol-listener/"+string(protocol)) if err != nil { return nil, err From ecc9f96c5a87018f3a5ebbf5eb0bed59daf8a1e4 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Wed, 27 Jan 2021 13:58:00 +0100 Subject: [PATCH 18/22] use dedicated types for protocol and port check, decode response for 503 --- health_checks.go | 185 ++++++++++++----------------------------------- 1 file changed, 48 insertions(+), 137 deletions(-) diff --git a/health_checks.go b/health_checks.go index 2790fa3..fda19f2 100644 --- a/health_checks.go +++ b/health_checks.go @@ -1,8 +1,9 @@ package rabbithole import ( + "encoding/json" + "net/http" "strconv" - "strings" ) type TimeUnit string @@ -37,7 +38,6 @@ type Check interface { type Health struct { Check Status string `json:"status"` - Error string `json:"error"` Reason string `json:"reason"` } @@ -50,74 +50,38 @@ func (h *Health) Failed() bool { } // Responds a 200 OK if there are no alarms in effect in the cluster, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckAlarms() (rec *Health, err error) { - req, err := newGETRequest(c, "health/checks/alarms") - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil +func (c *Client) HealthCheckAlarms() (rec Health, err error) { + err = executeCheck(c, "health/checks/alarms", &rec) + return rec, err } // Responds a 200 OK if there are no local alarms in effect on the target node, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckLocalAlarms() (rec *Health, err error) { - req, err := newGETRequest(c, "health/checks/local-alarms") - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil +func (c *Client) HealthCheckLocalAlarms() (rec Health, err error) { + err = executeCheck(c, "health/checks/local-alarms", &rec) + return rec, err } // Checks the expiration date on the certificates for every listener configured to use TLS. // Responds a 200 OK if all certificates are valid (have not expired), otherwise responds with a 503 Service Unavailable. // Valid units: days, weeks, months, years. The value of the within argument is the number of units. // So, when within is 2 and unit is "months", the expiration period used by the check will be the next two months. -func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (rec *Health, err error) { - req, err := newGETRequest(c, "health/checks/certificate-expiration/"+strconv.Itoa(int(within))+"/"+string(unit)) - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil +func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (rec Health, err error) { + err = executeCheck(c, "health/checks/certificate-expiration/"+strconv.Itoa(int(within))+"/"+string(unit), &rec) + return rec, err } type PortListenerHealth struct { - Status string `json:"status"` - Error string `json:"error"'` - Reason string `json:"reason"` - Port string - Ports []string `json:"ports"` + Status string `json:"status"` + Reason string `json:"reason"` + Missing string `json:"missing"'` + Port uint `json:"port"` + Ports []uint `json:"ports"` } // Responds a 200 OK if there is an active listener on the give port, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckPortListenerListener(port uint) (rec *PortListenerHealth, err error) { - req, err := newGETRequest(c, "health/checks/port-listener/"+strconv.Itoa(int(port))) - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - - if !strings.Contains(err.Error(), "503") { - return nil, err - } - - } - - return rec, nil +func (c *Client) HealthCheckPortListener(port uint) (rec PortListenerHealth, err error) { + err = executeCheck(c, "health/checks/port-listener/"+strconv.Itoa(int(port)), &rec) + return rec, err } type ProtocolListenerHealth struct { @@ -129,110 +93,57 @@ type ProtocolListenerHealth struct { // Responds a 200 OK if there is an active listener for the given protocol, otherwise responds with a 503 Service Unavailable. // Valid protocol names are: amqp091, amqp10, mqtt, stomp, web-mqtt, web-stomp. -func (c *Client) HealthCheckProtocolListener(protocol Protocol) (rec *ProtocolListenerHealth, err error) { - req, err := newGETRequest(c, "health/checks/protocol-listener/"+string(protocol)) - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil +func (c *Client) HealthCheckProtocolListener(protocol Protocol) (rec ProtocolListenerHealth, err error) { + err = executeCheck(c, "health/checks/protocol-listener/"+string(protocol), &rec) + return rec, err } // Responds a 200 OK if all virtual hosts and running on the target node, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckVirtualHosts() (rec *Health, err error) { - req, err := newGETRequest(c, "health/checks/virtual-hosts") - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil +func (c *Client) HealthCheckVirtualHosts() (rec Health, err error) { + err = executeCheck(c, "health/checks/virtual-hosts", &rec) + return rec, err } // Checks if there are classic mirrored queues without synchronised mirrors online (queues that would potentially lose data if the target node is shut down). // Responds a 200 OK if there are no such classic mirrored queues, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckNodeIsMirrorSyncCritical() (rec *Health, err error) { - req, err := newGETRequest(c, "health/checks/node-is-mirror-sync-critical") - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil +func (c *Client) HealthCheckNodeIsMirrorSyncCritical() (rec Health, err error) { + err = executeCheck(c, "health/checks/node-is-mirror-sync-critical", &rec) + return rec, err } // Checks if there are quorum queues with minimum online quorum (queues that would lose their quorum and availability if the target node is shut down). // Responds a 200 OK if there are no such quorum queues, otherwise responds with a 503 Service Unavailable. -func (c *Client) HealthCheckNodeIsQuorumCritical() (rec *Health, err error) { - req, err := newGETRequest(c, "health/checks/node-is-quorum-critical") - if err != nil { - return nil, err - } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil +func (c *Client) HealthCheckNodeIsQuorumCritical() (rec Health, err error) { + err = executeCheck(c, "health/checks/node-is-quorum-critical", &rec) + return rec, err } -// Deprecated health check api - -// HealthChecks endpoint checks if the application is running, -// channels and queues can be listed, and that no alarms are raised -func (c *Client) HealthCheck() (rec *Health, err error) { - req, err := newGETRequest(c, "healthchecks/node") - if err != nil { - return nil, err +func executeCheck(client *Client, path string, rec interface{}) error { + req, err := newGETRequest(client, path) + httpc := &http.Client{ + Timeout: client.timeout, } - - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err + if client.transport != nil { + httpc.Transport = client.transport } - - return rec, nil -} - -// HealthChecks endpoint checks for a given node if the application is running, -// channels and queues can be listed, and that no alarms are raised -func (c *Client) HealthCheckFor(node string) (rec *Health, err error) { - req, err := newGETRequest(c, "healthchecks/node/"+node) + resp, err := httpc.Do(req) if err != nil { - return nil, err + return err } - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err - } - - return rec, nil -} + defer resp.Body.Close() -// Aliveness represents response from aliveness-test endpoint -type Aliveness struct { - Status string `json:"status"` -} + if resp.StatusCode < http.StatusBadRequest || resp.StatusCode == http.StatusServiceUnavailable { + if err = json.NewDecoder(resp.Body).Decode(&rec); err != nil { + return err + } -// Aliveness endpoint declares a test queue, then publishes a message and consumes a message -func (c *Client) Aliveness(vhost string) (rec *Aliveness, err error) { - req, err := newGETRequest(c, "aliveness-test/"+vhost) - if err != nil { - return nil, err + return nil } - if err = executeAndParseRequest(c, req, &rec); err != nil { - return nil, err + if err = parseResponseErrors(resp); err != nil { + return err } - return rec, nil + return nil } From 9ff340f289165c56841f4c695de16a8a49106b1a Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Wed, 27 Jan 2021 13:58:38 +0100 Subject: [PATCH 19/22] fixed typo --- health_checks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health_checks.go b/health_checks.go index fda19f2..078238e 100644 --- a/health_checks.go +++ b/health_checks.go @@ -30,7 +30,7 @@ type Check interface { // Returns true if the check is ok, otherwise false Ok() bool - // Return true if the check failed, otherwise false + // Returns true if the check failed, otherwise false Failed() bool } From 365a8713dc6c15ebb9a3e056d00951d66a117280 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Wed, 27 Jan 2021 14:01:38 +0100 Subject: [PATCH 20/22] dedicated types use Check interface --- health_checks.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/health_checks.go b/health_checks.go index 078238e..d8bbbfe 100644 --- a/health_checks.go +++ b/health_checks.go @@ -71,6 +71,7 @@ func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (r } type PortListenerHealth struct { + Check Status string `json:"status"` Reason string `json:"reason"` Missing string `json:"missing"'` @@ -85,6 +86,7 @@ func (c *Client) HealthCheckPortListener(port uint) (rec PortListenerHealth, err } type ProtocolListenerHealth struct { + Check Status string `json:"status"` Reason string `json:"reason"` Missing string `json:"missing"` From a20ad1eeb90b5015a79391638551cd9700c0b06f Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Wed, 27 Jan 2021 14:07:49 +0100 Subject: [PATCH 21/22] update comments --- health_checks.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/health_checks.go b/health_checks.go index d8bbbfe..03499d6 100644 --- a/health_checks.go +++ b/health_checks.go @@ -34,7 +34,7 @@ type Check interface { Failed() bool } -// Health represents response from healthchecks endpoint +// Represents general response from health check endpoints if no dedicated representation is defined type Health struct { Check Status string `json:"status"` @@ -49,20 +49,19 @@ func (h *Health) Failed() bool { return !h.Ok() } -// Responds a 200 OK if there are no alarms in effect in the cluster, otherwise responds with a 503 Service Unavailable. +// Checks if there are alarms in effect in the cluster func (c *Client) HealthCheckAlarms() (rec Health, err error) { err = executeCheck(c, "health/checks/alarms", &rec) return rec, err } -// Responds a 200 OK if there are no local alarms in effect on the target node, otherwise responds with a 503 Service Unavailable. +// Checks if there are local alarms in effect on the target node func (c *Client) HealthCheckLocalAlarms() (rec Health, err error) { err = executeCheck(c, "health/checks/local-alarms", &rec) return rec, err } // Checks the expiration date on the certificates for every listener configured to use TLS. -// Responds a 200 OK if all certificates are valid (have not expired), otherwise responds with a 503 Service Unavailable. // Valid units: days, weeks, months, years. The value of the within argument is the number of units. // So, when within is 2 and unit is "months", the expiration period used by the check will be the next two months. func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (rec Health, err error) { @@ -70,21 +69,23 @@ func (c *Client) HealthCheckCertificateExpiration(within uint, unit TimeUnit) (r return rec, err } +// Represents the response from HealthCheckPortListener type PortListenerHealth struct { Check Status string `json:"status"` Reason string `json:"reason"` - Missing string `json:"missing"'` + Missing string `json:"missing"` Port uint `json:"port"` Ports []uint `json:"ports"` } -// Responds a 200 OK if there is an active listener on the give port, otherwise responds with a 503 Service Unavailable. +// Checks if there is an active listener on the give port func (c *Client) HealthCheckPortListener(port uint) (rec PortListenerHealth, err error) { err = executeCheck(c, "health/checks/port-listener/"+strconv.Itoa(int(port)), &rec) return rec, err } +// Represents the response from HealthCheckProtocolListener type ProtocolListenerHealth struct { Check Status string `json:"status"` @@ -93,28 +94,26 @@ type ProtocolListenerHealth struct { Protocols []string `json:"protocols"` } -// Responds a 200 OK if there is an active listener for the given protocol, otherwise responds with a 503 Service Unavailable. +// Checks if there is an active listener for the given protocol // Valid protocol names are: amqp091, amqp10, mqtt, stomp, web-mqtt, web-stomp. func (c *Client) HealthCheckProtocolListener(protocol Protocol) (rec ProtocolListenerHealth, err error) { err = executeCheck(c, "health/checks/protocol-listener/"+string(protocol), &rec) return rec, err } -// Responds a 200 OK if all virtual hosts and running on the target node, otherwise responds with a 503 Service Unavailable. +// Checks if all virtual hosts and running on the target node func (c *Client) HealthCheckVirtualHosts() (rec Health, err error) { err = executeCheck(c, "health/checks/virtual-hosts", &rec) return rec, err } // Checks if there are classic mirrored queues without synchronised mirrors online (queues that would potentially lose data if the target node is shut down). -// Responds a 200 OK if there are no such classic mirrored queues, otherwise responds with a 503 Service Unavailable. func (c *Client) HealthCheckNodeIsMirrorSyncCritical() (rec Health, err error) { err = executeCheck(c, "health/checks/node-is-mirror-sync-critical", &rec) return rec, err } // Checks if there are quorum queues with minimum online quorum (queues that would lose their quorum and availability if the target node is shut down). -// Responds a 200 OK if there are no such quorum queues, otherwise responds with a 503 Service Unavailable. func (c *Client) HealthCheckNodeIsQuorumCritical() (rec Health, err error) { err = executeCheck(c, "health/checks/node-is-quorum-critical", &rec) return rec, err From 17799f05c1b420b623768141e25c6091f1d1e128 Mon Sep 17 00:00:00 2001 From: Martin Krueger Date: Wed, 27 Jan 2021 18:36:18 +0100 Subject: [PATCH 22/22] removed deprecated checks --- rabbithole_test.go | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/rabbithole_test.go b/rabbithole_test.go index 6c17c24..2aa6264 100644 --- a/rabbithole_test.go +++ b/rabbithole_test.go @@ -148,7 +148,7 @@ var _ = Describe("Rabbithole", func() { Ω(err).Should(BeNil()) defer ch.Close() - res, err := rmqc.HealthCheckPortListenerListener(5672) + res, err := rmqc.HealthCheckPortListener(5672) Ω(err).Should(BeNil()) Ω(res.Status).Should(Equal("ok")) @@ -219,44 +219,6 @@ var _ = Describe("Rabbithole", func() { }) }) - Context("GET /aliveness-test/%2F", func() { - It("returns decoded response", func() { - conn := openConnection("/") - defer conn.Close() - - ch, err := conn.Channel() - Ω(err).Should(BeNil()) - - ensureNonZeroMessageRate(ch) - - res, err := rmqc.Aliveness("%2F") - Ω(err).Should(BeNil()) - - Ω(res.Status).Should(Equal("ok")) - - ch.Close() - }) - }) - - Context("GET /healthchecks/nodes", func() { - It("returns decoded response", func() { - conn := openConnection("/") - defer conn.Close() - - ch, err := conn.Channel() - Ω(err).Should(BeNil()) - - ensureNonZeroMessageRate(ch) - - res, err := rmqc.HealthCheck() - Ω(err).Should(BeNil()) - - Ω(res.Status).Should(Equal("ok")) - - ch.Close() - }) - }) - Context("GET /overview", func() { It("returns decoded response", func() { conn := openConnection("/")