package main import ( "context" "strings" "testing" ) // 1426/AC3: the bundle's Tools() lists the six mail-reading verbs and mail_reader_health, each with its own // argument schema. func TestToolsListsTheSixVerbsAndHealth(t *testing.T) { b := &Bundle{} var names []string for _, tool := range b.Tools() { names = append(names, tool.Name) if tool.Input == nil { t.Errorf("%s has no argument schema", tool.Name) } if tool.Description == "" { t.Errorf("%s has no description", tool.Name) } } want := []string{ "mail-reading.entries", "mail-reading.groups", "mail-reading.correct", "mail-reading.lessons", "mail-reading.undo", "mail-reading.status", "mail_reader_health", } if len(names) != len(want) { t.Fatalf("Tools() = %v, want %v", names, want) } for i, n := range want { if names[i] != n { t.Fatalf("Tools()[%d] = %q, want %q", i, names[i], n) } } } // 1426/AC4, 1428/AC5: a mail-reading verb answers a caller the setting callers names, and refuses any other, // naming why — before anything else about the verb (business errors such as an unknown id are not caller // refusals, and are exercised by correct_test.go and 1521's own tests, not here). func TestAMailReadingVerbChecksItsCaller(t *testing.T) { granted := func(map[string]any) string { return "mesh-mail-web" } refused := func(map[string]any) string { return "person.someoneelse" } unproven := func(map[string]any) string { return Unproven } storeOf := func(context.Context) (Store, error) { return newMemStore(), nil } for _, tool := range []struct { name string run func(*Bundle) (any, error) }{ {EntriesTool, func(b *Bundle) (any, error) { return b.entriesTool(map[string]any{}) }}, {GroupsTool, func(b *Bundle) (any, error) { return b.groupsTool(map[string]any{}) }}, {CorrectTool, func(b *Bundle) (any, error) { return b.correctTool(map[string]any{"id": float64(1), "mark": "matters"}) }}, {LessonsTool, func(b *Bundle) (any, error) { return b.lessonsTool(map[string]any{}) }}, {UndoTool, func(b *Bundle) (any, error) { return b.undoTool(map[string]any{"id": float64(1)}) }}, {StatusTool, func(b *Bundle) (any, error) { return b.statusTool(map[string]any{}) }}, } { callers := func() (Callers, error) { return Callers{"mesh-mail-web"}, nil } b := &Bundle{Caller: granted, callersOverride: callers, Store: storeOf} _, err := tool.run(b) if err != nil && strings.Contains(err.Error(), "is not named in the setting callers") { t.Errorf("%s granted: %v, want it to pass the caller check (any other error is its own business, not a caller refusal)", tool.name, err) } b = &Bundle{Caller: refused, callersOverride: callers, Store: storeOf} _, err = tool.run(b) if err == nil || !strings.Contains(err.Error(), "refused") || !strings.Contains(err.Error(), "person.someoneelse") { t.Errorf("%s refused caller: %v, want a refusal naming person.someoneelse", tool.name, err) } b = &Bundle{Caller: unproven, callersOverride: callers, Store: storeOf} _, err = tool.run(b) if err == nil || !strings.Contains(err.Error(), "refused") { t.Errorf("%s unproven caller: %v, want a refusal", tool.name, err) } } } // 1426/AC4: a setting that cannot be read allows nobody, and says why — before the store is ever reached. func TestAMailReadingVerbRefusesWhenCallersCannotBeRead(t *testing.T) { b := &Bundle{ Caller: func(map[string]any) string { return "mesh-mail-web" }, callersOverride: func() (Callers, error) { return nil, errFake }, } _, err := b.entriesTool(map[string]any{}) if err == nil || !strings.Contains(err.Error(), "cannot be read") { t.Fatalf("entriesTool with an unreadable setting: %v", err) } } // mail_reader_health carries no caller check (1426: "mail_reader_health is asked by the node-engine itself"). func TestHealthToolHasNoCallerCheck(t *testing.T) { b := &Bundle{ callersOverride: func() (Callers, error) { return nil, errFake }, Store: func(context.Context) (Store, error) { return newMemStore(), nil }, } _, err := b.healthTool(map[string]any{}) if err != nil { t.Fatalf("mail_reader_health: %v, want it to skip the caller check entirely and answer", err) } } type fakeErr struct{} func (fakeErr) Error() string { return "the setting cannot be read (fake)" } var errFake = fakeErr{}