1package testscript
2
3import (
4 "context"
5 "flag"
6 "fmt"
7 "os"
8 "path/filepath"
9 "sync"
10 "testing"
11 "time"
12
13 "github.com/charmbracelet/soft-serve/server"
14 "github.com/charmbracelet/soft-serve/server/config"
15 "github.com/charmbracelet/soft-serve/server/test"
16 "github.com/rogpeppe/go-internal/testscript"
17)
18
19var update = flag.Bool("update", false, "update script files")
20
21func TestScript(t *testing.T) {
22 flag.Parse()
23 var lock sync.Mutex
24
25 // we'll use this key to talk with soft serve, and since testscript changes
26 // the cwd, we need to get its full path here
27 key, err := filepath.Abs("./testdata/admin1")
28 if err != nil {
29 t.Fatal(err)
30 }
31
32 // git does not handle 0600, and on clone, will save the files with its
33 // default perm, 0644, which is too open for ssh.
34 for _, f := range []string{
35 "admin1",
36 "admin2",
37 "user1",
38 "user2",
39 } {
40 if err := os.Chmod(filepath.Join("./testdata/", f), 0o600); err != nil {
41 t.Fatal(err)
42 }
43 }
44
45 testscript.Run(t, testscript.Params{
46 Dir: "testdata/script",
47 UpdateScripts: *update,
48 Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
49 "soft": func(ts *testscript.TestScript, _ bool, args []string) {
50 // TODO: maybe use plain ssh client here?
51 args = append([]string{
52 "-F", "/dev/null",
53 "-o", "StrictHostKeyChecking=no",
54 "-o", "UserKnownHostsFile=/dev/null",
55 "-o", "IdentityAgent=none",
56 "-o", "IdentitiesOnly=yes",
57 "-i", key,
58 "-p", ts.Getenv("SSH_PORT"),
59 "localhost",
60 "--",
61 }, args...)
62 ts.Check(ts.Exec("ssh", args...))
63 },
64 },
65 Setup: func(e *testscript.Env) error {
66 sshPort := test.RandomPort()
67 e.Setenv("SSH_PORT", fmt.Sprintf("%d", sshPort))
68 data := t.TempDir()
69 cfg := config.Config{
70 Name: "Test Soft Serve",
71 DataPath: data,
72 InitialAdminKeys: []string{
73 "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJI/1tawpdPmzuJcTGTJ+QReqB6cRUdKj4iQIdJUFdrl",
74 },
75 SSH: config.SSHConfig{
76 ListenAddr: fmt.Sprintf("localhost:%d", sshPort),
77 PublicURL: fmt.Sprintf("ssh://localhost:%d", sshPort),
78 KeyPath: filepath.Join(data, "ssh", "soft_serve_host_ed25519"),
79 ClientKeyPath: filepath.Join(data, "ssh", "soft_serve_client_ed25519"),
80 },
81 Git: config.GitConfig{
82 ListenAddr: fmt.Sprintf("localhost:%d", test.RandomPort()),
83 IdleTimeout: 3,
84 MaxConnections: 32,
85 },
86 HTTP: config.HTTPConfig{
87 ListenAddr: fmt.Sprintf("localhost:%d", test.RandomPort()),
88 PublicURL: fmt.Sprintf("http://localhost:%d", test.RandomPort()),
89 },
90 Stats: config.StatsConfig{
91 ListenAddr: fmt.Sprintf("localhost:%d", test.RandomPort()),
92 },
93 Log: config.LogConfig{
94 Format: "text",
95 TimeFormat: time.DateTime,
96 },
97 }
98 ctx := config.WithContext(context.Background(), &cfg)
99
100 // prevent race condition in lipgloss...
101 // this will probably be autofixed when we start using the colors
102 // from the ssh session instead of the server.
103 // XXX: take another look at this soon
104 lock.Lock()
105 srv, err := server.NewServer(ctx)
106 if err != nil {
107 return err
108 }
109 lock.Unlock()
110 go func() {
111 if err := srv.Start(); err != nil {
112 e.T().Fatal(err)
113 }
114 }()
115 e.Defer(func() {
116 ctx, cancel := context.WithTimeout(context.Background(), time.Second)
117 defer cancel()
118 if err := srv.Shutdown(ctx); err != nil {
119 e.T().Fatal(err)
120 }
121 })
122 return nil
123 },
124 })
125}