okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

Aly Raffauffeat(api)!: migrate daemon and clients to protocol 361c43ca

main
2.1 KiB51 linesraw
1// Error decoding must preserve status and structured causes even for malformed
2// responses, which the real daemon E2E suite does not produce.
3package daemon
4
5import (
6	"context"
7	"errors"
8	"fmt"
9	"io"
10	"net"
11	"net/http"
12	"net/http/httptest"
13	"strings"
14	"testing"
15)
16
17func TestHTTPFailuresRetainIdentity(t *testing.T) {
18	for _, tc := range []struct {
19		name, body, code string
20		status           int
21	}{
22		{"workspace", `{"type":"about:blank","title":"Workspace unavailable","status":503,"code":"workspace_unavailable","detail":"wording can change"}`, "workspace_unavailable", 503},
23		{"forbidden", `{"type":"about:blank","title":"Forbidden","status":403,"code":"forbidden","detail":"access denied"}`, "forbidden", 403},
24		{"unauthorized", `{"type":"about:blank","title":"Unauthorized","status":401,"code":"unauthorized","detail":"sign in again"}`, "unauthorized", 401},
25		{"code only", `{"code":"busy"}`, "busy", 503},
26		{"malformed", `<html>bad gateway</html>`, "", 502},
27	} {
28		t.Run(tc.name, func(t *testing.T) {
29			server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
30				w.WriteHeader(tc.status)
31				_, _ = io.WriteString(w, tc.body)
32			}))
33			defer server.Close()
34			// This fixed peer has no discovery directory; authentication errors stay local.
35			conn := NewConnection(ConnectionSnapshot{Port: server.Listener.Addr().(*net.TCPAddr).Port}, nil)
36			_, requestErr := requestBytes(context.Background(), conn, operation{Name: "read failure", Method: http.MethodGet, Path: "/failure", Policy: readRecovery}, responseLimits{bodyBytes: 50 * 1024 * 1024, errorBytes: 64 * 1024})
37			client := NewChatClient(conn, "session")
38			_, chatErr := client.GetStatus(context.Background())
39			for _, err := range []error{requestErr, chatErr} {
40				err = fmt.Errorf("request context: %w", err)
41				var apiErr *APIError
42				if !errors.As(err, &apiErr) || apiErr.StatusCode != tc.status || apiErr.Code != tc.code {
43					t.Fatalf("lost HTTP failure identity: %v", err)
44				}
45				if strings.Contains(err.Error(), "<html>") {
46					t.Fatalf("exposed unstructured response body: %v", err)
47				}
48			}
49		})
50	}
51}