- Implement tests for the Entity gRPC service, covering GetState and ListStates methods. - Create tests for the Light gRPC service, including TurnOn, TurnOff, Toggle, and ListLights methods. - Introduce mock service implementations to simulate behavior and validate interactions. - Add logging interceptor tests to ensure proper logging levels based on handler errors. - Develop application layer tests for entity and light functionalities, ensuring correct state management and error propagation.
79 lines
1.9 KiB
Go
79 lines
1.9 KiB
Go
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"sync"
|
|
"testing"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
type recordingHandler struct {
|
|
mu sync.Mutex
|
|
levels []slog.Level
|
|
}
|
|
|
|
func (h *recordingHandler) Enabled(context.Context, slog.Level) bool {
|
|
return true
|
|
}
|
|
|
|
func (h *recordingHandler) Handle(ctx context.Context, record slog.Record) error {
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
h.levels = append(h.levels, record.Level)
|
|
return nil
|
|
}
|
|
|
|
func (h *recordingHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
return h
|
|
}
|
|
|
|
func (h *recordingHandler) WithGroup(name string) slog.Handler {
|
|
return h
|
|
}
|
|
|
|
func TestLoggingUnaryInterceptor(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
handlerErr error
|
|
wantLevel slog.Level
|
|
}{
|
|
{name: "nil error logs info", wantLevel: slog.LevelInfo},
|
|
{name: "not found logs warn", handlerErr: status.Error(codes.NotFound, "missing"), wantLevel: slog.LevelWarn},
|
|
{name: "internal logs error", handlerErr: status.Error(codes.Internal, "boom"), wantLevel: slog.LevelError},
|
|
{name: "unimplemented logs warn", handlerErr: status.Error(codes.Unimplemented, "stub"), wantLevel: slog.LevelWarn},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
h := &recordingHandler{}
|
|
interceptor := LoggingUnaryInterceptor(slog.New(h))
|
|
|
|
_, err := interceptor(
|
|
context.Background(),
|
|
"struct{}{}",
|
|
&grpc.UnaryServerInfo{FullMethod: "/ha.v1.LightService/TurnOn"},
|
|
func(ctx context.Context, req any) (any, error) {
|
|
return "ok", tt.handlerErr
|
|
},
|
|
)
|
|
if status.Code(err) != status.Code(tt.handlerErr) {
|
|
t.Fatalf("handler error = %v, want %v", err, tt.handlerErr)
|
|
}
|
|
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
if len(h.levels) == 0 {
|
|
t.Fatal("no log records captured")
|
|
}
|
|
got := h.levels[len(h.levels)-1]
|
|
if got != tt.wantLevel {
|
|
t.Fatalf("log level = %v, want %v", got, tt.wantLevel)
|
|
}
|
|
})
|
|
}
|
|
}
|