189 lines
4.6 KiB
Go
189 lines
4.6 KiB
Go
package grpcapi
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
|
|
"git.ipng.ch/ipng/vpp-maglev/internal/checker"
|
|
"git.ipng.ch/ipng/vpp-maglev/internal/config"
|
|
"git.ipng.ch/ipng/vpp-maglev/internal/health"
|
|
)
|
|
|
|
func makeTestChecker(ctx context.Context) *checker.Checker {
|
|
cfg := &config.Frontend{
|
|
HealthCheckNetns: "test",
|
|
HealthChecker: config.HealthCheckerConfig{TransitionHistory: 5},
|
|
VIPs: map[string]config.VIP{
|
|
"web": {
|
|
Address: net.ParseIP("192.0.2.1"),
|
|
Protocol: "tcp",
|
|
Port: 80,
|
|
Backends: []net.IP{net.ParseIP("10.0.0.2")},
|
|
HealthCheck: config.HealthCheck{
|
|
Type: "icmp",
|
|
Interval: time.Hour, // long interval: probes won't fire during tests
|
|
Timeout: time.Second,
|
|
Fall: 3,
|
|
Rise: 2,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
c := checker.New(cfg)
|
|
go c.Run(ctx) //nolint:errcheck
|
|
// Allow the Run goroutine to initialize workers.
|
|
time.Sleep(10 * time.Millisecond)
|
|
return c
|
|
}
|
|
|
|
func startTestServer(t *testing.T, c *checker.Checker) (HealthCheckerClient, func()) {
|
|
t.Helper()
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
t.Fatalf("listen: %v", err)
|
|
}
|
|
srv := grpc.NewServer()
|
|
RegisterHealthCheckerServer(srv, NewServer(c))
|
|
go srv.Serve(lis) //nolint:errcheck
|
|
|
|
conn, err := grpc.NewClient(lis.Addr().String(),
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()))
|
|
if err != nil {
|
|
t.Fatalf("dial: %v", err)
|
|
}
|
|
return NewHealthCheckerClient(conn), func() {
|
|
conn.Close()
|
|
srv.Stop()
|
|
}
|
|
}
|
|
|
|
func TestListVIPs(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
c := makeTestChecker(ctx)
|
|
client, cleanup := startTestServer(t, c)
|
|
defer cleanup()
|
|
|
|
resp, err := client.ListVIPs(ctx, &ListVIPsRequest{})
|
|
if err != nil {
|
|
t.Fatalf("ListVIPs: %v", err)
|
|
}
|
|
if len(resp.VipNames) != 1 || resp.VipNames[0] != "web" {
|
|
t.Errorf("ListVIPs: got %v, want [web]", resp.VipNames)
|
|
}
|
|
}
|
|
|
|
func TestGetVIP(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
c := makeTestChecker(ctx)
|
|
client, cleanup := startTestServer(t, c)
|
|
defer cleanup()
|
|
|
|
info, err := client.GetVIP(ctx, &GetVIPRequest{VipName: "web"})
|
|
if err != nil {
|
|
t.Fatalf("GetVIP: %v", err)
|
|
}
|
|
if info.Address != "192.0.2.1" {
|
|
t.Errorf("GetVIP address: got %q, want 192.0.2.1", info.Address)
|
|
}
|
|
if info.Port != 80 {
|
|
t.Errorf("GetVIP port: got %d, want 80", info.Port)
|
|
}
|
|
}
|
|
|
|
func TestGetVIPNotFound(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
c := makeTestChecker(ctx)
|
|
client, cleanup := startTestServer(t, c)
|
|
defer cleanup()
|
|
|
|
_, err := client.GetVIP(ctx, &GetVIPRequest{VipName: "nope"})
|
|
if err == nil {
|
|
t.Error("expected error for unknown VIP")
|
|
}
|
|
}
|
|
|
|
func TestGetBackend(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
c := makeTestChecker(ctx)
|
|
client, cleanup := startTestServer(t, c)
|
|
defer cleanup()
|
|
|
|
info, err := client.GetBackend(ctx, &GetBackendRequest{
|
|
VipName: "web",
|
|
BackendAddress: "10.0.0.2",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("GetBackend: %v", err)
|
|
}
|
|
if info.State != health.StateUnknown.String() {
|
|
t.Errorf("initial state: got %q, want unknown", info.State)
|
|
}
|
|
}
|
|
|
|
func TestPauseResumeBackend(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
c := makeTestChecker(ctx)
|
|
client, cleanup := startTestServer(t, c)
|
|
defer cleanup()
|
|
|
|
info, err := client.PauseBackend(ctx, &PauseResumeRequest{
|
|
VipName: "web",
|
|
BackendAddress: "10.0.0.2",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("PauseBackend: %v", err)
|
|
}
|
|
if info.State != health.StatePaused.String() {
|
|
t.Errorf("after pause: got %q, want paused", info.State)
|
|
}
|
|
|
|
info, err = client.ResumeBackend(ctx, &PauseResumeRequest{
|
|
VipName: "web",
|
|
BackendAddress: "10.0.0.2",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("ResumeBackend: %v", err)
|
|
}
|
|
if info.State != health.StateUnknown.String() {
|
|
t.Errorf("after resume: got %q, want unknown", info.State)
|
|
}
|
|
}
|
|
|
|
func TestWatchTransitions(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
c := makeTestChecker(ctx)
|
|
client, cleanup := startTestServer(t, c)
|
|
defer cleanup()
|
|
|
|
stream, err := client.WatchTransitions(ctx, &WatchRequest{})
|
|
if err != nil {
|
|
t.Fatalf("WatchTransitions: %v", err)
|
|
}
|
|
|
|
// Should receive the current state for web:10.0.0.2 immediately.
|
|
ev, err := stream.Recv()
|
|
if err != nil {
|
|
t.Fatalf("Recv: %v", err)
|
|
}
|
|
if ev.VipName != "web" || ev.BackendAddress != "10.0.0.2" {
|
|
t.Errorf("initial event: vip=%q backend=%q", ev.VipName, ev.BackendAddress)
|
|
}
|
|
}
|