github.com/MetalBlockchain/metalgo@v1.11.9/api/health/service_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package health 5 6 import ( 7 "context" 8 "net/http" 9 "testing" 10 11 "github.com/prometheus/client_golang/prometheus" 12 "github.com/stretchr/testify/require" 13 14 "github.com/MetalBlockchain/metalgo/ids" 15 "github.com/MetalBlockchain/metalgo/utils/logging" 16 ) 17 18 func TestServiceResponses(t *testing.T) { 19 require := require.New(t) 20 21 check := CheckerFunc(func(context.Context) (interface{}, error) { 22 return "", nil 23 }) 24 25 h, err := New(logging.NoLog{}, prometheus.NewRegistry()) 26 require.NoError(err) 27 28 s := &Service{ 29 log: logging.NoLog{}, 30 health: h, 31 } 32 33 require.NoError(h.RegisterReadinessCheck("check", check)) 34 require.NoError(h.RegisterHealthCheck("check", check)) 35 require.NoError(h.RegisterLivenessCheck("check", check)) 36 37 { 38 reply := APIReply{} 39 require.NoError(s.Readiness(nil, &APIArgs{}, &reply)) 40 41 require.Len(reply.Checks, 1) 42 require.Contains(reply.Checks, "check") 43 require.Equal(notYetRunResult, reply.Checks["check"]) 44 require.False(reply.Healthy) 45 } 46 47 { 48 reply := APIReply{} 49 require.NoError(s.Health(nil, &APIArgs{}, &reply)) 50 51 require.Len(reply.Checks, 1) 52 require.Contains(reply.Checks, "check") 53 require.Equal(notYetRunResult, reply.Checks["check"]) 54 require.False(reply.Healthy) 55 } 56 57 { 58 reply := APIReply{} 59 require.NoError(s.Liveness(nil, &APIArgs{}, &reply)) 60 61 require.Len(reply.Checks, 1) 62 require.Contains(reply.Checks, "check") 63 require.Equal(notYetRunResult, reply.Checks["check"]) 64 require.False(reply.Healthy) 65 } 66 67 h.Start(context.Background(), checkFreq) 68 defer h.Stop() 69 70 awaitReadiness(t, h, true) 71 awaitHealthy(t, h, true) 72 awaitLiveness(t, h, true) 73 74 { 75 reply := APIReply{} 76 require.NoError(s.Readiness(nil, &APIArgs{}, &reply)) 77 78 result := reply.Checks["check"] 79 require.Equal("", result.Details) 80 require.Nil(result.Error) 81 require.Zero(result.ContiguousFailures) 82 require.True(reply.Healthy) 83 } 84 85 { 86 reply := APIReply{} 87 require.NoError(s.Health(nil, &APIArgs{}, &reply)) 88 89 result := reply.Checks["check"] 90 require.Equal("", result.Details) 91 require.Nil(result.Error) 92 require.Zero(result.ContiguousFailures) 93 require.True(reply.Healthy) 94 } 95 96 { 97 reply := APIReply{} 98 require.NoError(s.Liveness(nil, &APIArgs{}, &reply)) 99 100 result := reply.Checks["check"] 101 require.Equal("", result.Details) 102 require.Nil(result.Error) 103 require.Zero(result.ContiguousFailures) 104 require.True(reply.Healthy) 105 } 106 } 107 108 func TestServiceTagResponse(t *testing.T) { 109 check := CheckerFunc(func(context.Context) (interface{}, error) { 110 return "", nil 111 }) 112 113 subnetID1 := ids.GenerateTestID() 114 subnetID2 := ids.GenerateTestID() 115 116 // test cases 117 type testMethods struct { 118 name string 119 register func(Health, string, Checker, ...string) error 120 check func(*Service, *http.Request, *APIArgs, *APIReply) error 121 await func(*testing.T, Reporter, bool) 122 } 123 124 tests := []testMethods{ 125 { 126 name: "Readiness", 127 register: func(h Health, s1 string, c Checker, s2 ...string) error { 128 return h.RegisterReadinessCheck(s1, c, s2...) 129 }, 130 check: func(s *Service, req *http.Request, a1 *APIArgs, a2 *APIReply) error { 131 return s.Readiness(req, a1, a2) 132 }, 133 await: awaitReadiness, 134 }, 135 { 136 name: "Health", 137 register: func(h Health, s1 string, c Checker, s2 ...string) error { 138 return h.RegisterHealthCheck(s1, c, s2...) 139 }, 140 check: func(s *Service, r *http.Request, a1 *APIArgs, a2 *APIReply) error { 141 return s.Health(r, a1, a2) 142 }, 143 await: awaitHealthy, 144 }, 145 { 146 name: "Liveness", 147 register: func(h Health, s1 string, c Checker, s2 ...string) error { 148 return h.RegisterLivenessCheck(s1, c, s2...) 149 }, 150 check: func(s *Service, r *http.Request, a1 *APIArgs, a2 *APIReply) error { 151 return s.Liveness(r, a1, a2) 152 }, 153 await: awaitLiveness, 154 }, 155 } 156 157 for _, test := range tests { 158 t.Run(test.name, func(t *testing.T) { 159 require := require.New(t) 160 161 h, err := New(logging.NoLog{}, prometheus.NewRegistry()) 162 require.NoError(err) 163 require.NoError(test.register(h, "check1", check)) 164 require.NoError(test.register(h, "check2", check, subnetID1.String())) 165 require.NoError(test.register(h, "check3", check, subnetID2.String())) 166 require.NoError(test.register(h, "check4", check, subnetID1.String(), subnetID2.String())) 167 168 s := &Service{ 169 log: logging.NoLog{}, 170 health: h, 171 } 172 173 // default checks 174 { 175 reply := APIReply{} 176 require.NoError(test.check(s, nil, &APIArgs{}, &reply)) 177 require.Len(reply.Checks, 4) 178 require.Contains(reply.Checks, "check1") 179 require.Contains(reply.Checks, "check2") 180 require.Contains(reply.Checks, "check3") 181 require.Contains(reply.Checks, "check4") 182 require.Equal(notYetRunResult, reply.Checks["check1"]) 183 require.False(reply.Healthy) 184 185 require.NoError(test.check(s, nil, &APIArgs{Tags: []string{subnetID1.String()}}, &reply)) 186 require.Len(reply.Checks, 2) 187 require.Contains(reply.Checks, "check2") 188 require.Contains(reply.Checks, "check4") 189 require.Equal(notYetRunResult, reply.Checks["check2"]) 190 require.False(reply.Healthy) 191 } 192 193 h.Start(context.Background(), checkFreq) 194 195 test.await(t, h, true) 196 197 { 198 reply := APIReply{} 199 require.NoError(test.check(s, nil, &APIArgs{Tags: []string{subnetID1.String()}}, &reply)) 200 require.Len(reply.Checks, 2) 201 require.Contains(reply.Checks, "check2") 202 require.Contains(reply.Checks, "check4") 203 require.True(reply.Healthy) 204 } 205 206 // stop the health check 207 h.Stop() 208 209 { 210 // now we'll add a new check which is unhealthy by default (notYetRunResult) 211 require.NoError(test.register(h, "check5", check, subnetID1.String())) 212 213 reply := APIReply{} 214 require.NoError(test.check(s, nil, &APIArgs{Tags: []string{subnetID1.String()}}, &reply)) 215 require.Len(reply.Checks, 3) 216 require.Contains(reply.Checks, "check2") 217 require.Contains(reply.Checks, "check4") 218 require.Contains(reply.Checks, "check5") 219 require.Equal(notYetRunResult, reply.Checks["check5"]) 220 require.False(reply.Healthy) 221 } 222 }) 223 } 224 }