Files
member-console/internal/server/external_claim_gate_test.go
T
cgalo5758 88db730fcc Add dual licensing and SPDX headers
Introduce a commercial license option alongside AGPL-3.0-only, require a
CLA for contributors, and document the terms in COMMERCIAL.md and
NOTICE. Add a script to stamp SPDX headers on Go files and apply it
across the tree.
2026-09-06 02:29:42 -05:00

64 lines
2.5 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Commercial
// SPDX-FileCopyrightText: 2025-2026 Christian Galo
package server
import (
"context"
"errors"
"io"
"log/slog"
"testing"
"git.coopcloud.tech/wiki-cafe/member-console/internal/domains"
)
// TestNewExternalClaimGateRefusals pins the gate's two refusal conditions in
// the order they short-circuit: no connect target refuses regardless of
// entitlement state (no serving path exists), and an absent entitlement
// source reads as not granted, never as an error.
func TestNewExternalClaimGateRefusals(t *testing.T) {
noTarget := NewExternalClaimGate(nil, " ")
if err := noTarget(context.Background(), "ws-1"); !errors.Is(err, domains.ErrNoConnectTarget) {
t.Errorf("empty connect target: got %v, want ErrNoConnectTarget", err)
}
noEntQ := NewExternalClaimGate(nil, "connect.example.test")
if err := noEntQ(context.Background(), "ws-1"); !errors.Is(err, domains.ErrExternalClaimsNotEntitled) {
t.Errorf("nil entitlements querier: got %v, want ErrExternalClaimsNotEntitled", err)
}
}
// TestExternalClaimGateRefusedClassification keeps the refusal/infrastructure
// distinction honest — surfaces close the affordance on refusals but must
// surface real failures.
func TestExternalClaimGateRefusedClassification(t *testing.T) {
if !externalClaimGateRefused(domains.ErrExternalClaimsNotEntitled) ||
!externalClaimGateRefused(domains.ErrNoConnectTarget) {
t.Error("typed refusals must classify as refused")
}
if externalClaimGateRefused(errors.New("connection reset")) {
t.Error("an infrastructure error must not classify as a refusal")
}
if externalClaimGateRefused(nil) {
t.Error("nil is admission, not refusal")
}
}
// TestMemberDomainsHandlerCarriesGate pins the constructor wiring: a member
// domains handler always holds a gate (built from its own config), so the
// affordance read can never dereference nil. The registry-side injections in
// server.go and fedwiki.go are exercised end-to-end by the walkthroughs.
func TestMemberDomainsHandlerCarriesGate(t *testing.T) {
h, err := NewMemberDomainsHandler(MemberDomainsConfig{Logger: slog.New(slog.NewTextHandler(io.Discard, nil))})
if err != nil {
t.Fatalf("construct handler: %v", err)
}
if h.gate == nil {
t.Fatal("member domains handler constructed without a gate")
}
if err := h.gate(context.Background(), "ws-1"); !errors.Is(err, domains.ErrNoConnectTarget) {
t.Errorf("gate with empty config: got %v, want ErrNoConnectTarget", err)
}
}