package agent import ( "io" "os" "path/filepath" "strings" "testing" "time" "github.com/x-grk/longpolling-remote-access/internal/proto" ) // A terminal opened with a folder starts its shell there; a folder that is // not there leaves it at home. func TestStartPTYDir(t *testing.T) { dir, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } sub := filepath.Join(dir, "sub dir") if err := os.Mkdir(sub, 0o755); err != nil { t.Fatal(err) } if got := ptyPwd(t, sub); got != sub { t.Fatalf("pwd = %q, want %q", got, sub) } home, _ := filepath.EvalSymlinks(homeDir("")) if got := ptyPwd(t, filepath.Join(dir, "missing")); got != home { t.Fatalf("pwd for a missing folder = %q, want home %q", got, home) } } // ptyPwd opens a terminal at dir and returns where its shell is. func ptyPwd(t *testing.T, dir string) string { t.Helper() t.Setenv("SHELL", "/bin/sh") p, err := StartPTY("", dir) if err != nil { t.Fatal(err) } defer p.Close() if _, err := p.Write([]byte("echo \"@@$(pwd -P)@@\"\n")); err != nil { t.Fatal(err) } var out strings.Builder buf := make([]byte, 4096) deadline := time.Now().Add(5 * time.Second) for time.Now().Before(deadline) { n, err := p.Read(buf) out.Write(buf[:n]) s := out.String() // The echoed command line has "@@$(pwd" in it; the answer does not. for _, part := range strings.Split(s, "@@") { if strings.HasPrefix(part, "/") && strings.Contains(s, part+"@@") { return part } } if err != nil { break } } t.Fatalf("no pwd in %q", out.String()) return "" } // A terminal tells the folder its shell is in now, after a cd. func TestPTYCwd(t *testing.T) { dir, err := filepath.EvalSymlinks(t.TempDir()) if err != nil { t.Fatal(err) } sub := filepath.Join(dir, "next one") if err := os.Mkdir(sub, 0o755); err != nil { t.Fatal(err) } t.Setenv("SHELL", "/bin/sh") p, err := StartPTY("", dir) if err != nil { t.Fatal(err) } defer p.Close() go func() { _, _ = io.Copy(io.Discard, p) }() if _, err := p.Write([]byte("cd 'next one'\n")); err != nil { t.Fatal(err) } var got string for i := 0; i < 50; i++ { if got, err = p.Cwd(); err == nil && got == sub { return } time.Sleep(100 * time.Millisecond) } t.Fatalf("Cwd = %q, %v; want %q", got, err, sub) } // The panel asks for a terminal's folder by its session. func TestTermCwdTask(t *testing.T) { dir, _ := filepath.EvalSymlinks(t.TempDir()) t.Setenv("SHELL", "/bin/sh") p, err := StartPTY("", dir) if err != nil { t.Fatal(err) } defer p.Close() termsBySID.Store("s1", p) defer termsBySID.Delete("s1") res, err := dispatchTask(proto.TaskEnvelope{Type: proto.TaskTermCwd, Args: []byte(`{"session":"s1"}`)}) if err != nil || res.(map[string]string)["path"] != dir { t.Fatalf("term.cwd = %v, %v; want %q", res, err, dir) } if _, err := dispatchTask(proto.TaskEnvelope{Type: proto.TaskTermCwd, Args: []byte(`{"session":"nope"}`)}); err == nil { t.Fatal("an unknown session has a folder") } }