package grpcclient import ( "context" "strings" "testing" "time" "google.golang.org/grpc" ) func TestNormalizeRestoresTransportDefaults(t *testing.T) { cfg := Normalize(Config{}) if cfg.DefaultTimeout != 5*time.Second || cfg.ConnectTimeout != 2*time.Second { t.Fatalf("deadline defaults mismatch: %+v", cfg) } if cfg.KeepaliveTime != 30*time.Second || cfg.KeepaliveTimeout != 10*time.Second { t.Fatalf("keepalive defaults mismatch: %+v", cfg) } if cfg.RetryMaxAttempts != 2 || cfg.RetryInitialBackoff != 100*time.Millisecond || cfg.RetryMaxBackoff != 500*time.Millisecond { t.Fatalf("retry defaults mismatch: %+v", cfg) } } func TestTimeoutInterceptorPreservesExistingDeadline(t *testing.T) { parent, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() before, _ := parent.Deadline() interceptor := timeoutUnaryInterceptor(time.Millisecond) err := interceptor(parent, "/svc/Method", nil, nil, nil, func(ctx context.Context, method string, req any, reply any, conn *grpc.ClientConn, opts ...grpc.CallOption) error { after, ok := ctx.Deadline() if !ok || !after.Equal(before) { t.Fatalf("deadline should be preserved: ok=%t before=%s after=%s", ok, before, after) } return nil }) if err != nil { t.Fatalf("interceptor returned error: %v", err) } } func TestDefaultServiceConfigIncludesUnavailableRetry(t *testing.T) { serviceConfig := defaultServiceConfig(DefaultConfig()) if !strings.Contains(serviceConfig, `"retryableStatusCodes":["UNAVAILABLE"]`) { t.Fatalf("retry policy missing UNAVAILABLE: %s", serviceConfig) } if !strings.Contains(serviceConfig, `"waitForReady":true`) { t.Fatalf("service config should enable waitForReady: %s", serviceConfig) } }