main_test.go 3.98 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
package main

import (
	"fmt"
	"net"
	"net/http"
	"net/http/httptest"
	"os"
	"os/exec"
	"path"
	"syscall"
	"testing"
	"time"
)

const servAddr = "127.0.0.1:8181"
const servWaitListen = 10000 // milliseconds to wait for server to start listening
const servWaitSleep = 100    // milliseconds sleep interval
const scratchDir = "test/scratch"
const testRepoRoot = "test/data"
21 22 23
const testRepo = "test.git"

var remote = fmt.Sprintf("http://%s/%s", servAddr, testRepo)
Jacob Vosmaer's avatar
Jacob Vosmaer committed
24
var checkoutDir = path.Join(scratchDir, "test")
25 26

func TestAllowedClone(t *testing.T) {
27 28 29 30 31 32
	// Prepare clone directory
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}

	// Prepare test server and backend
33
	ts := testAuthServer(200, `{"GL_ID":"user-123"}`)
34
	defer ts.Close()
35 36 37 38 39
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
40
	if err := waitServer(); err != nil {
41 42
		t.Fatal(err)
	}
43 44

	// Do the git clone
Jacob Vosmaer's avatar
Jacob Vosmaer committed
45
	cloneCmd := exec.Command("git", "clone", remote, checkoutDir)
46
	runOrFail(t, cloneCmd)
47

48 49 50 51
	// We may have cloned an 'empty' repository, 'git log' will fail in it
	logCmd := exec.Command("git", "log", "-1", "--oneline")
	logCmd.Dir = checkoutDir
	runOrFail(t, logCmd)
52 53
}

Jacob Vosmaer's avatar
Jacob Vosmaer committed
54 55 56 57 58 59 60
func TestDeniedClone(t *testing.T) {
	// Prepare clone directory
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}

	// Prepare test server and backend
61
	ts := testAuthServer(403, `{"GL_ID":"user-123"}`)
Jacob Vosmaer's avatar
Jacob Vosmaer committed
62 63 64 65 66 67 68 69 70 71 72
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}

	// Do the git clone
Jacob Vosmaer's avatar
Jacob Vosmaer committed
73
	cloneCmd := exec.Command("git", "clone", remote, checkoutDir)
Jacob Vosmaer's avatar
Jacob Vosmaer committed
74 75 76 77 78
	if err := cloneCmd.Run(); err == nil {
		t.Fatal("git clone should have failed")
	}
}

79
func TestAllowedPush(t *testing.T) {
Jacob Vosmaer's avatar
Jacob Vosmaer committed
80
	branch := preparePushRepo(t)
81 82 83 84 85 86 87 88 89

	// Prepare the test server and backend
	ts := testAuthServer(200, `{"GL_ID":"user-123"}`)
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
90 91 92
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}
93 94 95 96

	// Perform the git push
	pushCmd := exec.Command("git", "push", remote, branch)
	pushCmd.Dir = checkoutDir
97
	runOrFail(t, pushCmd)
98 99
}

Jacob Vosmaer's avatar
Jacob Vosmaer committed
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
func TestDeniedPush(t *testing.T) {
	branch := preparePushRepo(t)

	// Prepare the test server and backend
	ts := testAuthServer(403, "Access denied")
	defer ts.Close()
	cmd, err := startServer(ts)
	if err != nil {
		t.Fatal(err)
	}
	defer cleanUpProcessGroup(cmd)
	if err := waitServer(); err != nil {
		t.Fatal(err)
	}

	// Perform the git push
	pushCmd := exec.Command("git", "push", remote, branch)
	pushCmd.Dir = checkoutDir
	if err := pushCmd.Run(); err == nil {
		t.Fatal("git push should have failed")
	}
}

func preparePushRepo(t *testing.T) string {
	if err := os.RemoveAll(scratchDir); err != nil {
		t.Fatal(err)
	}
	cloneCmd := exec.Command("git", "clone", path.Join(testRepoRoot, testRepo), checkoutDir)
	runOrFail(t, cloneCmd)
	branch := fmt.Sprintf("branch-%d", time.Now().UnixNano())
	branchCmd := exec.Command("git", "branch", branch)
	branchCmd.Dir = checkoutDir
	runOrFail(t, branchCmd)
	return branch
}

136 137 138 139 140
func testAuthServer(code int, body string) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(code)
		fmt.Fprint(w, body)
	}))
141 142
}

143 144
func startServer(ts *httptest.Server) (*exec.Cmd, error) {
	cmd := exec.Command("go", "run", "main.go", fmt.Sprintf("-authBackend=%s", ts.URL), fmt.Sprintf("-listenAddr=%s", servAddr), testRepoRoot)
145
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
146 147
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
148 149 150 151 152
	return cmd, cmd.Start()
}

func waitServer() (err error) {
	var conn net.Conn
Jacob Vosmaer's avatar
Jacob Vosmaer committed
153

154 155 156 157
	for i := 0; i < servWaitListen/servWaitSleep; i++ {
		conn, err = net.Dial("tcp", servAddr)
		if err == nil {
			conn.Close()
158
			return
159 160 161 162 163
		}
		time.Sleep(servWaitSleep * time.Millisecond)
	}
	return
}
164 165 166 167 168 169 170

func runOrFail(t *testing.T, cmd *exec.Cmd) {
	if out, err := cmd.CombinedOutput(); err != nil {
		t.Logf("%s", out)
		t.Fatal(err)
	}
}