github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/integration/e2e/health_test.go (about)

     1  /*
     2  Copyright hechain All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package e2e
     8  
     9  import (
    10  	"encoding/json"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"net"
    14  	"net/http"
    15  	"os"
    16  	"syscall"
    17  
    18  	docker "github.com/fsouza/go-dockerclient"
    19  	"github.com/hechain20/hechain/integration/nwo"
    20  	"github.com/hechain20/hechain/integration/nwo/runner"
    21  	"github.com/hyperledger/fabric-lib-go/healthz"
    22  	. "github.com/onsi/ginkgo"
    23  	. "github.com/onsi/gomega"
    24  	"github.com/tedsuo/ifrit"
    25  	"github.com/tedsuo/ifrit/ginkgomon"
    26  )
    27  
    28  var _ = Describe("Health", func() {
    29  	var (
    30  		testDir string
    31  		client  *docker.Client
    32  		network *nwo.Network
    33  		process ifrit.Process
    34  	)
    35  
    36  	BeforeEach(func() {
    37  		var err error
    38  		testDir, err = ioutil.TempDir("", "e2e")
    39  		Expect(err).NotTo(HaveOccurred())
    40  
    41  		client, err = docker.NewClientFromEnv()
    42  		Expect(err).NotTo(HaveOccurred())
    43  
    44  		config := nwo.BasicEtcdRaft()
    45  		network = nwo.New(config, testDir, client, StartPort(), components)
    46  		network.GenerateConfigTree()
    47  		network.Bootstrap()
    48  	})
    49  
    50  	AfterEach(func() {
    51  		if process != nil {
    52  			process.Signal(syscall.SIGTERM)
    53  			Eventually(process.Wait(), network.EventuallyTimeout).Should(Receive())
    54  		}
    55  		if network != nil {
    56  			network.Cleanup()
    57  		}
    58  		os.RemoveAll(testDir)
    59  	})
    60  
    61  	Describe("CouchDB health checks", func() {
    62  		var (
    63  			couchAddr    string
    64  			authClient   *http.Client
    65  			healthURL    string
    66  			peer         *nwo.Peer
    67  			couchDB      *runner.CouchDB
    68  			couchProcess ifrit.Process
    69  		)
    70  
    71  		BeforeEach(func() {
    72  			couchDB = &runner.CouchDB{}
    73  			couchProcess = ifrit.Invoke(couchDB)
    74  			Eventually(couchProcess.Ready(), runner.DefaultStartTimeout).Should(BeClosed())
    75  			Consistently(couchProcess.Wait()).ShouldNot(Receive())
    76  			couchAddr = couchDB.Address()
    77  
    78  			peer = network.Peer("Org1", "peer0")
    79  			core := network.ReadPeerConfig(peer)
    80  			core.Ledger.State.StateDatabase = "CouchDB"
    81  			core.Ledger.State.CouchDBConfig.CouchDBAddress = couchAddr
    82  			network.WritePeerConfig(peer, core)
    83  
    84  			peerRunner := network.PeerRunner(peer)
    85  			process = ginkgomon.Invoke(peerRunner)
    86  			Eventually(process.Ready(), network.EventuallyTimeout).Should(BeClosed())
    87  
    88  			authClient, _ = nwo.PeerOperationalClients(network, peer)
    89  			healthURL = fmt.Sprintf("https://127.0.0.1:%d/healthz", network.PeerPort(peer, nwo.OperationsPort))
    90  		})
    91  
    92  		AfterEach(func() {
    93  			couchProcess.Signal(syscall.SIGTERM)
    94  			Eventually(couchProcess.Wait(), network.EventuallyTimeout).Should(Receive())
    95  		})
    96  
    97  		When("running health checks on Couch DB", func() {
    98  			It("returns appropriate response codes", func() {
    99  				By("returning 200 when able to reach Couch DB")
   100  				statusCode, status := doHealthCheck(authClient, healthURL)
   101  				Expect(statusCode).To(Equal(http.StatusOK))
   102  				Expect(status.Status).To(Equal("OK"))
   103  
   104  				By("terminating CouchDB")
   105  				couchProcess.Signal(syscall.SIGTERM)
   106  				Eventually(couchProcess.Wait(), network.EventuallyTimeout).Should(Receive())
   107  
   108  				By("waiting for termination to complete")
   109  				Eventually(func() bool {
   110  					if c, err := net.Dial("tcp", couchDB.Address()); err == nil {
   111  						c.Close()
   112  						return false
   113  					}
   114  					return true
   115  				}, network.EventuallyTimeout).Should(BeTrue())
   116  
   117  				By("returning 503 when unable to reach Couch DB")
   118  				Eventually(func() int {
   119  					statusCode, _ := doHealthCheck(authClient, healthURL)
   120  					return statusCode
   121  				}, network.EventuallyTimeout).Should(Equal(http.StatusServiceUnavailable))
   122  				statusCode, status = doHealthCheck(authClient, healthURL)
   123  				Expect(statusCode).To(Equal(http.StatusServiceUnavailable))
   124  				Expect(status.Status).To(Equal("Service Unavailable"))
   125  				Expect(status.FailedChecks[0].Component).To(Equal("couchdb"))
   126  				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)))
   127  			})
   128  		})
   129  	})
   130  })
   131  
   132  func doHealthCheck(client *http.Client, url string) (int, *healthz.HealthStatus) {
   133  	resp, err := client.Get(url)
   134  	Expect(err).NotTo(HaveOccurred())
   135  
   136  	bodyBytes, err := ioutil.ReadAll(resp.Body)
   137  	Expect(err).NotTo(HaveOccurred())
   138  	resp.Body.Close()
   139  
   140  	// This occurs when a request to the health check server times out, no body is
   141  	// returned when a timeout occurs
   142  	if len(bodyBytes) == 0 {
   143  		return resp.StatusCode, nil
   144  	}
   145  
   146  	healthStatus := &healthz.HealthStatus{}
   147  	err = json.Unmarshal(bodyBytes, &healthStatus)
   148  	Expect(err).NotTo(HaveOccurred())
   149  
   150  	return resp.StatusCode, healthStatus
   151  }