go_study/fabric-main/integration/e2e/health_test.go

152 lines
4.3 KiB
Go

/*
Copyright IBM Corp All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package e2e
import (
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"syscall"
docker "github.com/fsouza/go-dockerclient"
"github.com/hyperledger/fabric-lib-go/healthz"
"github.com/hyperledger/fabric/integration/nwo"
"github.com/hyperledger/fabric/integration/nwo/runner"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/tedsuo/ifrit"
ginkgomon "github.com/tedsuo/ifrit/ginkgomon_v2"
)
var _ = Describe("Health", func() {
var (
testDir string
client *docker.Client
network *nwo.Network
process ifrit.Process
)
BeforeEach(func() {
var err error
testDir, err = ioutil.TempDir("", "e2e")
Expect(err).NotTo(HaveOccurred())
client, err = docker.NewClientFromEnv()
Expect(err).NotTo(HaveOccurred())
config := nwo.BasicEtcdRaft()
network = nwo.New(config, testDir, client, StartPort(), components)
network.GenerateConfigTree()
network.Bootstrap()
})
AfterEach(func() {
if process != nil {
process.Signal(syscall.SIGTERM)
Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
}
if network != nil {
network.Cleanup()
}
os.RemoveAll(testDir)
})
Describe("CouchDB health checks", func() {
var (
couchAddr string
authClient *http.Client
healthURL string
peer *nwo.Peer
couchDB *runner.CouchDB
couchProcess ifrit.Process
)
BeforeEach(func() {
couchDB = &runner.CouchDB{}
couchProcess = ifrit.Invoke(couchDB)
Eventually(couchProcess.Ready(), runner.DefaultStartTimeout).Should(BeClosed())
Consistently(couchProcess.Wait()).ShouldNot(Receive())
couchAddr = couchDB.Address()
peer = network.Peer("Org1", "peer0")
core := network.ReadPeerConfig(peer)
core.Ledger.State.StateDatabase = "CouchDB"
core.Ledger.State.CouchDBConfig.CouchDBAddress = couchAddr
network.WritePeerConfig(peer, core)
peerRunner := network.PeerRunner(peer)
process = ginkgomon.Invoke(peerRunner)
Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
authClient, _ = nwo.PeerOperationalClients(network, peer)
healthURL = fmt.Sprintf("https://127.0.0.1:%d/healthz", network.PeerPort(peer, nwo.OperationsPort))
})
AfterEach(func() {
couchProcess.Signal(syscall.SIGTERM)
Eventually(couchProcess.Wait(), network.EventuallyTimeout).Should(Receive())
})
When("running health checks on Couch DB", func() {
It("returns appropriate response codes", func() {
By("returning 200 when able to reach Couch DB")
statusCode, status := doHealthCheck(authClient, healthURL)
Expect(statusCode).To(Equal(http.StatusOK))
Expect(status.Status).To(Equal("OK"))
By("terminating CouchDB")
couchProcess.Signal(syscall.SIGTERM)
Eventually(couchProcess.Wait(), network.EventuallyTimeout).Should(Receive())
By("waiting for termination to complete")
Eventually(func() bool {
if c, err := net.Dial("tcp", couchDB.Address()); err == nil {
c.Close()
return false
}
return true
}, network.EventuallyTimeout).Should(BeTrue())
By("returning 503 when unable to reach Couch DB")
Eventually(func() int {
statusCode, _ := doHealthCheck(authClient, healthURL)
return statusCode
}, network.EventuallyTimeout).Should(Equal(http.StatusServiceUnavailable))
statusCode, status = doHealthCheck(authClient, healthURL)
Expect(statusCode).To(Equal(http.StatusServiceUnavailable))
Expect(status.Status).To(Equal("Service Unavailable"))
Expect(status.FailedChecks[0].Component).To(Equal("couchdb"))
Expect(status.FailedChecks[0].Reason).To(MatchRegexp(fmt.Sprintf(`failed to connect to couch db \[http error calling couchdb: Head "?http://%s"?: dial tcp %s: .*\]`, couchAddr, couchAddr)))
})
})
})
})
func doHealthCheck(client *http.Client, url string) (int, *healthz.HealthStatus) {
resp, err := client.Get(url)
Expect(err).NotTo(HaveOccurred())
bodyBytes, err := ioutil.ReadAll(resp.Body)
Expect(err).NotTo(HaveOccurred())
resp.Body.Close()
// This occurs when a request to the health check server times out, no body is
// returned when a timeout occurs
if len(bodyBytes) == 0 {
return resp.StatusCode, nil
}
healthStatus := &healthz.HealthStatus{}
err = json.Unmarshal(bodyBytes, &healthStatus)
Expect(err).NotTo(HaveOccurred())
return resp.StatusCode, healthStatus
}