e071084ebe
govulncheck / govulncheck (push) Has been cancelled
Lint / golangci-lint (push) Has been cancelled
Run Tests / Unit Tests (push) Has been cancelled
Run Tests / Etcd Integration Tests (push) Has been cancelled
Harness (E2E) / Harnesses (mock LLM) (push) Has been cancelled
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Has been cancelled
149 lines
4.4 KiB
Go
149 lines
4.4 KiB
Go
package health
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"go-micro.dev/v6/registry"
|
|
)
|
|
|
|
// fakeRegistry implements registry.Registry with a configurable
|
|
// ListServices result, for exercising RegistryCheck.
|
|
type fakeRegistry struct {
|
|
listErr error
|
|
block chan struct{} // if non-nil, ListServices blocks until it is closed
|
|
}
|
|
|
|
func (f *fakeRegistry) Init(...registry.Option) error { return nil }
|
|
func (f *fakeRegistry) Options() registry.Options { return registry.Options{} }
|
|
func (f *fakeRegistry) Register(*registry.Service, ...registry.RegisterOption) error {
|
|
return nil
|
|
}
|
|
func (f *fakeRegistry) Deregister(*registry.Service, ...registry.DeregisterOption) error {
|
|
return nil
|
|
}
|
|
func (f *fakeRegistry) GetService(string, ...registry.GetOption) ([]*registry.Service, error) {
|
|
return nil, nil
|
|
}
|
|
func (f *fakeRegistry) ListServices(...registry.ListOption) ([]*registry.Service, error) {
|
|
if f.block != nil {
|
|
<-f.block
|
|
}
|
|
return nil, f.listErr
|
|
}
|
|
func (f *fakeRegistry) Watch(...registry.WatchOption) (registry.Watcher, error) { return nil, nil }
|
|
func (f *fakeRegistry) String() string { return "fake" }
|
|
|
|
func TestRegistryCheckNil(t *testing.T) {
|
|
if err := RegistryCheck(nil)(context.Background()); err == nil {
|
|
t.Fatal("a nil registry should fail the check")
|
|
}
|
|
}
|
|
|
|
func TestRegistryCheckHealthy(t *testing.T) {
|
|
check := RegistryCheck(registry.NewMemoryRegistry())
|
|
if err := check(context.Background()); err != nil {
|
|
t.Fatalf("a reachable registry should pass: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRegistryCheckDown(t *testing.T) {
|
|
check := RegistryCheck(&fakeRegistry{listErr: errors.New("connection refused")})
|
|
err := check(context.Background())
|
|
if err == nil {
|
|
t.Fatal("the check should fail when the registry is unreachable")
|
|
}
|
|
if !strings.Contains(err.Error(), "unreachable") {
|
|
t.Errorf("error should describe the registry as unreachable: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRegistryCheckTimeout(t *testing.T) {
|
|
block := make(chan struct{})
|
|
defer close(block)
|
|
|
|
check := RegistryCheck(&fakeRegistry{block: block})
|
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond)
|
|
defer cancel()
|
|
|
|
err := check(ctx)
|
|
if err == nil {
|
|
t.Fatal("the check should time out when the registry call hangs")
|
|
}
|
|
if !strings.Contains(err.Error(), "timed out") {
|
|
t.Errorf("error should describe a timeout: %v", err)
|
|
}
|
|
}
|
|
|
|
// RegistryCheck should integrate with the readiness machinery: a down
|
|
// registry registered as a (critical) check makes the service not ready.
|
|
func TestRegistryCheckMarksNotReady(t *testing.T) {
|
|
Reset()
|
|
defer Reset()
|
|
|
|
Register("registry", RegistryCheck(&fakeRegistry{listErr: errors.New("etcd gone")}))
|
|
if IsReady(context.Background()) {
|
|
t.Error("service should be not-ready when the registry check is down")
|
|
}
|
|
}
|
|
|
|
func TestRegistryServiceCheckHealthy(t *testing.T) {
|
|
reg := registry.NewMemoryRegistry()
|
|
service := ®istry.Service{
|
|
Name: "orders",
|
|
Nodes: []*registry.Node{{Id: "orders-1"}},
|
|
}
|
|
if err := reg.Register(service); err != nil {
|
|
t.Fatalf("register service: %v", err)
|
|
}
|
|
|
|
check := RegistryServiceCheck(reg, "orders", "orders-1")
|
|
if err := check(context.Background()); err != nil {
|
|
t.Fatalf("registered service node should pass: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRegistryServiceCheckMissingNode(t *testing.T) {
|
|
reg := registry.NewMemoryRegistry()
|
|
service := ®istry.Service{
|
|
Name: "orders",
|
|
Nodes: []*registry.Node{{Id: "orders-1"}},
|
|
}
|
|
if err := reg.Register(service); err != nil {
|
|
t.Fatalf("register service: %v", err)
|
|
}
|
|
|
|
check := RegistryServiceCheck(reg, "orders", "orders-2")
|
|
err := check(context.Background())
|
|
if err == nil {
|
|
t.Fatal("missing service node should fail")
|
|
}
|
|
if !strings.Contains(err.Error(), "missing node orders-2") {
|
|
t.Errorf("error should describe the missing node: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRegistryServiceCheckMissingService(t *testing.T) {
|
|
check := RegistryServiceCheck(registry.NewMemoryRegistry(), "orders", "orders-1")
|
|
err := check(context.Background())
|
|
if err == nil {
|
|
t.Fatal("missing service should fail")
|
|
}
|
|
if !strings.Contains(err.Error(), registry.ErrNotFound.Error()) {
|
|
t.Errorf("error should include registry lookup failure: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRegistryServiceCheckMarksNotReady(t *testing.T) {
|
|
Reset()
|
|
defer Reset()
|
|
|
|
Register("registry-service", RegistryServiceCheck(registry.NewMemoryRegistry(), "orders", "orders-1"))
|
|
if IsReady(context.Background()) {
|
|
t.Error("service should be not-ready when its registry node is missing")
|
|
}
|
|
}
|