mesh/merge-gate pass: builds mesh-cli → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
So a secret reaches the controller's terminal without standing on a command line: mesh-cli secret accept <node> <module> <name> --from - < file. A terminal is never read, more than the bound is refused before anything is asked, and nothing carried is printed. mesh-sdk moves to f047d0a.
156 lines
5.7 KiB
Go
156 lines
5.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"net"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/cli"
|
|
)
|
|
|
|
// The tests' own standard input is the runner's, which may be a pipe nobody closes: read as a terminal unless a test
|
|
// says otherwise.
|
|
func init() { standardInput = func() (io.Reader, bool) { return nil, true } }
|
|
|
|
// lastStdin is the standard input the engine was last given.
|
|
var lastStdin []byte
|
|
|
|
// engine answers one connection on a socket of the test's own as the node-engine would, and says what it was asked.
|
|
func engine(t *testing.T, answer cli.Answer) <-chan []string {
|
|
t.Helper()
|
|
path := filepath.Join(t.TempDir(), "cli.sock")
|
|
l, err := net.Listen("unix", path)
|
|
if err != nil {
|
|
t.Skipf("no unix socket here: %v", err)
|
|
}
|
|
t.Cleanup(func() { l.Close() })
|
|
before := socket
|
|
socket = path
|
|
t.Cleanup(func() { socket = before })
|
|
asked := make(chan []string, 1)
|
|
lastStdin = nil
|
|
go func() {
|
|
conn, err := l.Accept()
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
req, err := cli.ReadRequest(conn)
|
|
if err != nil {
|
|
return
|
|
}
|
|
lastStdin = req.Stdin
|
|
asked <- req.Line
|
|
_ = cli.WriteAnswer(conn, answer)
|
|
}()
|
|
return asked
|
|
}
|
|
|
|
// The line is asked as given, what the controller printed is printed, and its exit is mesh-cli's.
|
|
func TestTheLineIsAskedAndTheAnswerIsPrinted(t *testing.T) {
|
|
t.Setenv("MESH_VERB", "")
|
|
asked := engine(t, cli.Answer{Stdout: []byte("out\n"), Stderr: []byte("err\n"), Exit: 3, Terminal: true, Why: "the terminal"})
|
|
var out, errOut bytes.Buffer
|
|
code := run(context.Background(), []string{"settings", "set", "zsh", `{"execute":"withhold"}`}, &out, &errOut)
|
|
if line := <-asked; strings.Join(line, "|") != `settings|set|zsh|{"execute":"withhold"}` {
|
|
t.Fatalf("asked %q", line)
|
|
}
|
|
if code != 3 || out.String() != "out\n" || errOut.String() != "err\n" {
|
|
t.Fatalf("exit %d, stdout %q, stderr %q", code, out.String(), errOut.String())
|
|
}
|
|
}
|
|
|
|
// Not the terminal, refused, or cut: each is said, and a refusal never exits 0.
|
|
func TestWhyARefusalAndACutAreSaid(t *testing.T) {
|
|
t.Setenv("MESH_VERB", "")
|
|
engine(t, cli.Answer{Why: "not the controller's terminal: agents on laptop may run as operator",
|
|
Refused: "set at the controller's terminal only", Cut: true})
|
|
var out, errOut bytes.Buffer
|
|
code := run(context.Background(), []string{"settings", "set", "x", "{}"}, &out, &errOut)
|
|
said := errOut.String()
|
|
if code == 0 || !strings.Contains(said, "not the controller's terminal") || !strings.Contains(said, "terminal only") ||
|
|
!strings.Contains(said, "cut") {
|
|
t.Fatalf("exit %d, said %q", code, said)
|
|
}
|
|
}
|
|
|
|
// A verb's own process is never the operator: refused before anything is asked.
|
|
func TestAVerbsProcessIsRefusedBeforeAsking(t *testing.T) {
|
|
t.Setenv("MESH_VERB", "command")
|
|
before := socket
|
|
socket = filepath.Join(t.TempDir(), "nothing-listens.sock")
|
|
t.Cleanup(func() { socket = before })
|
|
var out, errOut bytes.Buffer
|
|
if code := run(context.Background(), []string{"status"}, &out, &errOut); code != 1 ||
|
|
!strings.Contains(errOut.String(), "never the operator") {
|
|
t.Fatalf("exit %d, said %q", code, errOut.String())
|
|
}
|
|
}
|
|
|
|
// An engine that does not answer is said, with where it was asked.
|
|
func TestAnEngineThatDoesNotAnswerIsSaid(t *testing.T) {
|
|
t.Setenv("MESH_VERB", "")
|
|
before := socket
|
|
socket = filepath.Join(t.TempDir(), "nothing-listens.sock")
|
|
t.Cleanup(func() { socket = before })
|
|
var out, errOut bytes.Buffer
|
|
if code := run(context.Background(), []string{"status"}, &out, &errOut); code != 1 ||
|
|
!strings.Contains(errOut.String(), "does not answer") {
|
|
t.Fatalf("exit %d, said %q", code, errOut.String())
|
|
}
|
|
}
|
|
|
|
// An outcome not known is said as such — the line may have run — and never as nothing having run.
|
|
func TestAnOutcomeNotKnownIsSaid(t *testing.T) {
|
|
t.Setenv("MESH_VERB", "")
|
|
engine(t, cli.NotKnown("call-4", "no answer within 6m0s"))
|
|
var out, errOut bytes.Buffer
|
|
code := run(context.Background(), []string{"push", "laptop"}, &out, &errOut)
|
|
if code == 0 || !strings.Contains(errOut.String(), "may have run") || !strings.Contains(errOut.String(), "call-4") {
|
|
t.Fatalf("exit %d, said %q", code, errOut.String())
|
|
}
|
|
}
|
|
|
|
// A pipe's or a file's standard input goes with the line, whole; a terminal's is never read; more than the bound is
|
|
// refused and nothing is asked (novox/hq ADR 0259 §10).
|
|
func TestStandardInputGoesWithTheLineAndATerminalIsNeverRead(t *testing.T) {
|
|
t.Setenv("MESH_VERB", "")
|
|
was := standardInput
|
|
t.Cleanup(func() { standardInput = was })
|
|
secret := "123456789:the-bot-token\n"
|
|
|
|
standardInput = func() (io.Reader, bool) { return strings.NewReader(secret), false }
|
|
asked := engine(t, cli.Answer{Terminal: true})
|
|
var out, errOut bytes.Buffer
|
|
if code := run(context.Background(), []string{"secret", "accept", "anchor", "telegram", "telegram-token", "--from", "-"},
|
|
&out, &errOut); code != 0 {
|
|
t.Fatalf("exit %d: %s", code, errOut.String())
|
|
}
|
|
<-asked
|
|
if string(lastStdin) != secret {
|
|
t.Fatalf("the engine was given %q", lastStdin)
|
|
}
|
|
if strings.Contains(out.String()+errOut.String(), "bot-token") {
|
|
t.Fatal("mesh-cli printed what it carried")
|
|
}
|
|
|
|
standardInput = func() (io.Reader, bool) { return strings.NewReader("typed"), true }
|
|
asked = engine(t, cli.Answer{})
|
|
_ = run(context.Background(), []string{"status"}, &out, &errOut)
|
|
<-asked
|
|
if len(lastStdin) != 0 {
|
|
t.Fatalf("a terminal's input was read: %q", lastStdin)
|
|
}
|
|
|
|
standardInput = func() (io.Reader, bool) { return bytes.NewReader(make([]byte, cli.MaxStdin+1)), false }
|
|
errOut.Reset()
|
|
if code := run(context.Background(), []string{"secret", "accept", "a", "b", "c", "--from", "-"}, &out, &errOut); code == 0 ||
|
|
!strings.Contains(errOut.String(), "nothing was asked") {
|
|
t.Fatalf("more than the bound was asked: %d %s", code, errOut.String())
|
|
}
|
|
}
|