session_test.go

 1package ssh
 2
 3import (
 4	"context"
 5	"errors"
 6	"fmt"
 7	"log"
 8	"os"
 9	"testing"
10	"time"
11
12	"github.com/charmbracelet/soft-serve/server/backend/sqlite"
13	"github.com/charmbracelet/soft-serve/server/cache"
14	"github.com/charmbracelet/soft-serve/server/cache/noop"
15	"github.com/charmbracelet/soft-serve/server/config"
16	"github.com/charmbracelet/soft-serve/server/test"
17	"github.com/charmbracelet/ssh"
18	bm "github.com/charmbracelet/wish/bubbletea"
19	"github.com/charmbracelet/wish/testsession"
20	"github.com/matryer/is"
21	"github.com/muesli/termenv"
22	gossh "golang.org/x/crypto/ssh"
23)
24
25func TestSession(t *testing.T) {
26	is := is.New(t)
27	t.Run("authorized repo access", func(t *testing.T) {
28		t.Log("setting up")
29		s, close := setup(t)
30		s.Stderr = os.Stderr
31		t.Log("requesting pty")
32		err := s.RequestPty("xterm", 80, 40, nil)
33		is.NoErr(err)
34		go func() {
35			time.Sleep(1 * time.Second)
36			s.Signal(gossh.SIGTERM)
37			// FIXME: exit with code 0 instead of forcibly closing the session
38			s.Close()
39		}()
40		t.Log("waiting for session to exit")
41		_, err = s.Output("test")
42		var ee *gossh.ExitMissingError
43		is.True(errors.As(err, &ee))
44		t.Log("session exited")
45		_ = close()
46	})
47}
48
49func setup(tb testing.TB) (*gossh.Session, func() error) {
50	tb.Helper()
51	is := is.New(tb)
52	dp := tb.TempDir()
53	is.NoErr(os.Setenv("SOFT_SERVE_DATA_PATH", dp))
54	is.NoErr(os.Setenv("SOFT_SERVE_GIT_LISTEN_ADDR", ":9418"))
55	is.NoErr(os.Setenv("SOFT_SERVE_SSH_LISTEN_ADDR", fmt.Sprintf(":%d", test.RandomPort())))
56	tb.Cleanup(func() {
57		is.NoErr(os.Unsetenv("SOFT_SERVE_DATA_PATH"))
58		is.NoErr(os.Unsetenv("SOFT_SERVE_GIT_LISTEN_ADDR"))
59		is.NoErr(os.Unsetenv("SOFT_SERVE_SSH_LISTEN_ADDR"))
60		is.NoErr(os.RemoveAll(dp))
61	})
62	ctx := context.TODO()
63	ca, _ := noop.NewCache(ctx)
64	ctx = cache.WithContext(ctx, ca)
65	cfg := config.DefaultConfig()
66	ctx = config.WithContext(ctx, cfg)
67	fb, err := sqlite.NewSqliteBackend(ctx)
68	if err != nil {
69		log.Fatal(err)
70	}
71	cfg = cfg.WithBackend(fb)
72	return testsession.New(tb, &ssh.Server{
73		Handler: bm.MiddlewareWithProgramHandler(SessionHandler(cfg), termenv.ANSI256)(func(s ssh.Session) {
74			_, _, active := s.Pty()
75			if !active {
76				os.Exit(1)
77			}
78			s.Exit(0)
79		}),
80	}, nil), fb.Close
81}