okami.mom/albedo

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

Aly Raffaufrefactor(cli): extract local daemon lifecycled9c1a13

main
4.9 KiB122 linesraw
1// Controlled cancellation and malformed wire batches cannot be forced reliably
2// through a scripted provider; these tests exercise the public transport boundaries.
3package daemon
4
5import (
6	"albedo/cli/internal/daemon/protocol"
7	"encoding/json"
8	"errors"
9	"fmt"
10	"net/http"
11	"testing"
12)
13
14func TestAgentEventsValidateNullableSendersAndBooleanFields(t *testing.T) {
15	event, err := decodeAgentEvent(json.RawMessage(`{"type":"mail","data":{"mail_id":"m","sender_session_id":null,"sender_label":null,"receiver_session_id":"s","kind":"message","bytes":2}}`))
16	if err != nil || event == nil || event.To != "s" {
17		t.Fatalf("nullable bus sender rejected: %v", err)
18	}
19	if _, err := decodeAgentEvent(json.RawMessage(`{"type":"invalidate","data":{"urls":[],"session_ids":["s"],"scope_dirty":"false"}}`)); err == nil {
20		t.Fatal("malformed bus boolean accepted")
21	}
22}
23
24// Presence and null differ even when Go would decode both as the same zero.
25// A controlled peer can violate these contracts at every nested boundary.
26func TestSessionReadValidatesRequiredAndNullableMembers(t *testing.T) {
27	for _, scenario := range []struct {
28		name   string
29		change func(map[string]any)
30		valid  bool
31	}{
32		{"required nullable omitted", func(session map[string]any) { delete(session, "effort") }, false},
33		{"nullable retained", func(session map[string]any) { session["effort"] = nil }, true},
34		{"nested required omitted", func(session map[string]any) {
35			delete(session["kernel"].(map[string]any), "live_job_count")
36		}, false},
37		{"nested nullable retained", func(session map[string]any) {
38			session["kernel"].(map[string]any)["live_job_count"] = nil
39		}, true},
40		{"job list omitted", func(session map[string]any) {
41			delete(session["kernel"].(map[string]any), "running_jobs")
42		}, false},
43		{"unknown job list", func(session map[string]any) {
44			session["kernel"].(map[string]any)["running_jobs"] = nil
45		}, true},
46		{"job pid omitted", func(session map[string]any) {
47			session["kernel"].(map[string]any)["running_jobs"] = []any{map[string]any{"id": "j", "command": "sleep 10"}}
48		}, false},
49		{"nullable job pid", func(session map[string]any) {
50			session["kernel"].(map[string]any)["running_jobs"] = []any{map[string]any{"id": "j", "pid": nil, "command": "sleep 10", "started_at": 0}}
51		}, true},
52		{"job started_at omitted", func(session map[string]any) {
53			session["kernel"].(map[string]any)["running_jobs"] = []any{map[string]any{"id": "j", "pid": nil, "command": "sleep 10"}}
54		}, false},
55		{"null scalar", func(session map[string]any) {
56			session["status"].(map[string]any)["interrupt_requested"] = nil
57		}, false},
58		{"null array", func(session map[string]any) { session["glances"] = nil }, false},
59		{"null object", func(session map[string]any) { session["preferences"] = nil }, false},
60		{"optional progress preview omitted", func(session map[string]any) {
61			progress := canonicalProgress("call")
62			delete(progress, "preview")
63			session["current_progress"] = []any{progress}
64		}, true},
65		{"optional progress preview null", func(session map[string]any) {
66			progress := canonicalProgress("call")
67			progress["preview"] = nil
68			session["current_progress"] = []any{progress}
69		}, false},
70	} {
71		t.Run(scenario.name, func(t *testing.T) {
72			session := canonicalSession("s", generationA, 0)
73			scenario.change(session)
74			conn := controlledConnection(t, func(w http.ResponseWriter, request *http.Request) {
75				if request.URL.RequestURI() != "/sessions/s?tail=0" {
76					t.Errorf("unexpected session read %s", request.URL)
77				}
78				_ = json.NewEncoder(w).Encode(session)
79			})
80			captured, err := GetSession(t.Context(), conn, "s")
81			if scenario.valid {
82				if err != nil || captured.ID != "s" {
83					t.Fatalf("nullable native fact rejected: %+v, %v", captured, err)
84				}
85			} else if _, ok := errors.AsType[*ProtocolError](err); !ok {
86				t.Fatalf("malformed required member accepted: %v", err)
87			}
88		})
89	}
90}
91
92func TestSessionChangeRejectsMissingNestedMembers(t *testing.T) {
93	for _, valid := range []bool{true, false} {
94		session := canonicalSession("s", generationA, 0)
95		if !valid {
96			delete(session["kernel"].(map[string]any), "live_job_count")
97		}
98		payload, err := json.Marshal(map[string]any{"session": session, "resource": session["configuration_resource"], "move": nil})
99		if err != nil {
100			t.Fatal(err)
101		}
102		var change protocol.SessionChange
103		err = decodeRequired(payload, &change)
104		if (err == nil) != valid {
105			t.Fatalf("nested session validation valid=%v: %v", valid, err)
106		}
107	}
108}
109
110func TestModelPagingRejectsRepeatedTokens(t *testing.T) {
111	calls := 0
112	conn := controlledConnection(t, func(w http.ResponseWriter, r *http.Request) {
113		calls++
114		if calls == 1 && r.URL.Query().Get("next") != "" || calls == 2 && r.URL.Query().Get("next") != "same" {
115			t.Errorf("wrong cursor at page %d: %s", calls, r.URL)
116		}
117		_, _ = fmt.Fprint(w, `{"items":[],"next":"same"}`)
118	})
119	if _, err := ListModels(t.Context(), conn, "provider", ""); err == nil || calls != 2 {
120		t.Fatalf("repeated cursor accepted: calls=%d, error=%v", calls, err)
121	}
122}