all repos

mugit @ dbbfe17

🐮 git server that your cow will love

mugit/testscript_test.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
git: set default branch; dont replay on list of default branches (#7)..., 2 months ago
1
package main_test
2
3
import (
4
	"context"
5
	"fmt"
6
	"net"
7
	"net/http"
8
	"os"
9
	"os/exec"
10
	"path/filepath"
11
	"strconv"
12
	"testing"
13
	"time"
14
15
	"github.com/rogpeppe/go-internal/testscript"
16
	"gopkg.in/yaml.v2"
17
18
	"olexsmir.xyz/mugit/internal/config"
19
	"olexsmir.xyz/mugit/internal/handlers"
20
)
21
22
var (
23
	mugitBin   string
24
	httpPort   int
25
	reposDir   string
26
	configPath string
27
)
28
29
func TestMain(m *testing.M) { os.Exit(testMain(m)) }
30
func testMain(m *testing.M) int {
31
	ctx, cancel := context.WithCancel(context.Background())
32
	defer cancel()
33
34
	tmpDir, err := os.MkdirTemp("", "mugit-test-*")
35
	if err != nil {
36
		fmt.Fprintf(os.Stderr, "failed to create temp dir: %v\n", err)
37
		return 1
38
	}
39
	defer os.RemoveAll(tmpDir)
40
41
	reposDir = filepath.Join(tmpDir, "repos")
42
	if jerr := os.MkdirAll(reposDir, 0o755); jerr != nil {
43
		fmt.Fprintf(os.Stderr, "failed to create repo dir: %v\n", jerr)
44
		return 1
45
	}
46
47
	if berr := buildMugitBinary(tmpDir); berr != nil {
48
		fmt.Fprintf(os.Stderr, "failed to build binary: %v\n", berr)
49
		return 1
50
	}
51
52
	port, err := findFreePort()
53
	if err != nil {
54
		fmt.Fprintf(os.Stderr, "failed to find free port: %v\n", err)
55
		return 1
56
	}
57
	httpPort = port
58
59
	cfg := &config.Config{
60
		Server: config.ServerConfig{
61
			Host: "127.0.0.1",
62
			Port: httpPort,
63
		},
64
		Meta: config.MetaConfig{
65
			Title: "test mugit",
66
			Host:  "localhost",
67
		},
68
		Repo: config.RepoConfig{
69
			Dir:     reposDir,
70
			Readmes: []string{"README.md"},
71
		},
72
		SSH:    config.SSHConfig{Enable: true, User: "git"},
73
		Mirror: config.MirrorConfig{Enable: false},
74
		Cache: config.CacheConfig{
75
			HomePage: 0,
76
			Readme:   0,
77
			Diff:     0,
78
		},
79
	}
80
81
	configPath = filepath.Join(tmpDir, "config.yaml")
82
	configBytes, err := yaml.Marshal(cfg)
83
	if err != nil {
84
		fmt.Fprintf(os.Stderr, "failed to marshal config: %v\n", err)
85
		return 1
86
	}
87
	if err := os.WriteFile(configPath, configBytes, 0o600); err != nil {
88
		fmt.Fprintf(os.Stderr, "failed to write config: %v\n", err)
89
		return 1
90
	}
91
92
	httpServer := &http.Server{
93
		Addr:    net.JoinHostPort(cfg.Server.Host, strconv.Itoa(cfg.Server.Port)),
94
		Handler: handlers.InitRoutes(cfg),
95
	}
96
	go func() {
97
		if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
98
			fmt.Fprintf(os.Stderr, "HTTP server error: %v\n", err)
99
		}
100
	}()
101
102
	if err := waitForPort(httpPort, 5*time.Second); err != nil {
103
		fmt.Fprintf(os.Stderr, "server did not become ready: %v\n", err)
104
		return 1
105
	}
106
107
	code := m.Run()
108
	httpServer.Shutdown(ctx)
109
	return code
110
}
111
112
func TestScript(t *testing.T) {
113
	if testing.Short() {
114
		t.Skip("skipping integration tests")
115
	}
116
117
	sshWrapperContent := fmt.Sprintf(`#!/bin/sh
118
export SSH_ORIGINAL_COMMAND="$2"
119
exec %s shell -c %s`, mugitBin, configPath)
120
121
	testscript.Run(t, testscript.Params{
122
		Dir: "testscript",
123
		Cmds: map[string]func(ts *testscript.TestScript, neg bool, args []string){
124
			"mugit": cmdMugit,
125
			"git":   cmdGit,
126
		},
127
		Setup: func(env *testscript.Env) error {
128
			work := env.Getenv("WORK")
129
			sshWrapperPath := filepath.Join(work, "ssh-wrapper.sh")
130
			if err := os.WriteFile(sshWrapperPath, []byte(sshWrapperContent), 0o700); err != nil {
131
				return fmt.Errorf("failed to create ssh wrapper: %w", err)
132
			}
133
134
			env.Setenv("SSH_WRAPPER", sshWrapperPath)
135
			env.Setenv("REPOS", reposDir)
136
			env.Setenv("MPORT", strconv.Itoa(httpPort))
137
			env.Setenv("MURL", fmt.Sprintf("http://127.0.0.1:%d", httpPort))
138
			return nil
139
		},
140
	})
141
}
142
143
func buildMugitBinary(tmpDir string) error {
144
	mugitBin = filepath.Join(tmpDir, "mugit")
145
	cmd := exec.Command("go", "build", "-o", mugitBin, ".")
146
	cmd.Dir = "."
147
	if out, err := cmd.CombinedOutput(); err != nil {
148
		os.RemoveAll(tmpDir)
149
		return fmt.Errorf("go build: %v\n%s", err, out)
150
	}
151
	return nil
152
}
153
154
func findFreePort() (int, error) {
155
	l, err := net.Listen("tcp", "127.0.0.1:0")
156
	if err != nil {
157
		return 0, err
158
	}
159
	port := l.Addr().(*net.TCPAddr).Port
160
	l.Close()
161
	return port, nil
162
}
163
164
func waitForPort(port int, timeout time.Duration) error {
165
	deadline := time.Now().Add(timeout)
166
	for time.Now().Before(deadline) {
167
		if conn, err := net.DialTimeout(
168
			"tcp",
169
			net.JoinHostPort("127.0.0.1", strconv.Itoa(port)),
170
			200*time.Millisecond,
171
		); err == nil {
172
			conn.Close()
173
			return nil
174
		}
175
		time.Sleep(50 * time.Millisecond)
176
	}
177
	return fmt.Errorf("port %d not ready after %s", port, timeout)
178
}
179
180
func cmdMugit(ts *testscript.TestScript, neg bool, args []string) {
181
	if len(args) < 1 {
182
		ts.Fatalf("usage: mugit <subcommand> ...")
183
	}
184
	cmd := exec.Command(mugitBin, append([]string{"-c", configPath}, args...)...)
185
	cmd.Env = os.Environ()
186
	cmd.Stdout = ts.Stdout()
187
	cmd.Stderr = ts.Stderr()
188
	err := cmd.Run()
189
	if neg {
190
		if err == nil {
191
			ts.Fatalf("expected mugit to fail, it succeeded")
192
		}
193
	} else {
194
		if err != nil {
195
			ts.Fatalf("mugit: %v", err)
196
		}
197
	}
198
}
199
200
func cmdGit(ts *testscript.TestScript, neg bool, args []string) {
201
	if len(args) > 0 && args[0] == "init" {
202
		hasBranch := false
203
		for _, arg := range args {
204
			if arg == "-b" || arg == "--initial-branch" {
205
				hasBranch = true
206
				break
207
			}
208
		}
209
		if !hasBranch {
210
			args = append([]string{"init", "-b", "master"}, args[1:]...)
211
		}
212
	}
213
	args = append([]string{
214
		"-c", "user.email=test@test.local",
215
		"-c", "user.name=Test User",
216
	}, args...)
217
	cmd := exec.Command("git", args...)
218
	cmd.Dir = ts.Getenv("WORK")
219
	cmd.Stdout = ts.Stdout()
220
	cmd.Stderr = ts.Stderr()
221
222
	err := cmd.Run()
223
	if err == nil && neg {
224
		ts.Fatalf("expected git to fail, but it succeeded")
225
	}
226
	if err != nil && !neg {
227
		ts.Fatalf("git: %v", err)
228
	}
229
}