package hub // S3 Group C — RegisterWG client (POST /hosts/{id}/wg, per-host key). Typed-error mapping and // the no-token-in-errors invariant, same scaffolding as the desired-state client tests. import ( "context" "errors" "io" "net/http" "strings" "testing" ) func TestRegisterWG_PathAuthBodyAndDecode(t *testing.T) { var gotPath, gotAuth, gotMethod, gotBody string c := testClient(func(r *http.Request) (*http.Response, error) { gotPath = r.URL.Path gotAuth = r.Header.Get("Authorization") gotMethod = r.Method b, _ := io.ReadAll(r.Body) gotBody = string(b) return httpResp(200, `{"pubkey":"PK","assigned_ip":"10.77.0.2/32","existed":false,"generation":3,"sync":"ok"}`), nil }) resp, err := c.RegisterWG(context.Background(), "PK") if err != nil { t.Fatalf("RegisterWG: %v", err) } if gotMethod != http.MethodPost || gotPath != "/api/v1/hosts/demo-host-01/wg" { t.Errorf("request = %s %s, want POST /api/v1/hosts/demo-host-01/wg", gotMethod, gotPath) } if gotAuth != "Bearer super-secret-bearer-key" { t.Errorf("auth = %q", gotAuth) } if gotBody != `{"pubkey":"PK"}` { t.Errorf("body = %s", gotBody) } if resp.AssignedIP != "10.77.0.2/32" || resp.Existed || resp.Generation != 3 || resp.Sync != "ok" { t.Errorf("resp = %+v", resp) } } func TestRegisterWG_TypedErrors(t *testing.T) { for _, tc := range []struct { status int body string }{ {403, "Forbidden: host_id mismatch"}, {404, "Unknown host_id"}, {409, "wg endpoint not configured"}, {409, "pubkey already registered elsewhere"}, } { c := testClient(func(r *http.Request) (*http.Response, error) { return httpResp(tc.status, tc.body), nil }) _, err := c.RegisterWG(context.Background(), "PK") var he *HTTPError if !errors.As(err, &he) || he.StatusCode != tc.status { t.Errorf("status %d: err = %v, want HTTPError %d", tc.status, err, tc.status) } if strings.Contains(err.Error(), "super-secret-bearer-key") { t.Fatalf("bearer token leaked into error: %v", err) } } // Transport failure → TransportError, token-free. c := testClient(func(r *http.Request) (*http.Response, error) { return nil, errors.New("dial tcp: connection refused") }) _, err := c.RegisterWG(context.Background(), "PK") var te *TransportError if !errors.As(err, &te) { t.Errorf("transport err = %v, want TransportError", err) } }