mirror of https://github.com/knative/func.git
				
				
				
			
		
			
				
	
	
		
			218 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
| // package testing includes minor testing helpers.
 | |
| //
 | |
| // These helpers include extensions to the testing nomenclature which exist to
 | |
| // ease the development of tests for functions.  It is mostly just syntactic
 | |
| // sugar and closures for creating an removing test directories etc.
 | |
| // It was originally included in each of the requisite testing packages, but
 | |
| // since we use both private-access enabled tests (in the function package),
 | |
| // as well as closed-box tests (in function_test package), and they are gradually
 | |
| // increasing in size and complexity, the choice was made to choose a small
 | |
| // dependency over a small amount of copying.
 | |
| //
 | |
| // Another reason for including these in a separate locaiton is that they will
 | |
| // have no tags such that no combination of tags can cause them to either be
 | |
| // missing or interfere with eachother (a problem encountered with knative
 | |
| // tooling which by default runs tests with all tags enabled simultaneously)
 | |
| package testing
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"net/http/cgi"
 | |
| 	"os"
 | |
| 	"os/exec"
 | |
| 	"path/filepath"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| )
 | |
| 
 | |
| // Using the given path, create it as a new directory and return a deferrable
 | |
| // which will remove it.
 | |
| // usage:
 | |
| //
 | |
| //	defer using(t, "testdata/example.com/someExampleTest")()
 | |
| func Using(t *testing.T, root string) func() {
 | |
| 	t.Helper()
 | |
| 	mkdir(t, root)
 | |
| 	return func() {
 | |
| 		rm(t, root)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // mkdir creates a directory as a test helper, failing the test on error.
 | |
| func mkdir(t *testing.T, dir string) {
 | |
| 	t.Helper()
 | |
| 	if err := os.MkdirAll(dir, 0700); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // rm a directory as a test helper, failing the test on error.
 | |
| func rm(t *testing.T, dir string) {
 | |
| 	t.Helper()
 | |
| 	if err := os.RemoveAll(dir); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Within the given root creates the directory, CDs to it, and rturns a
 | |
| // closure that when executed (intended in a defer) removes the given dirctory
 | |
| // and returns the caller to the initial working directory.
 | |
| // usage:
 | |
| //   defer within(t, "somedir")()
 | |
| func Within(t *testing.T, root string) func() {
 | |
| 	t.Helper()
 | |
| 	cwd := pwd(t)
 | |
| 	mkdir(t, root)
 | |
| 	cd(t, root)
 | |
| 	return func() {
 | |
| 		cd(t, cwd)
 | |
| 		rm(t, root)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Mktemp creates a temporary directory, CDs the current processes (test) to
 | |
| // said directory, and returns the path to said directory.
 | |
| // Usage:
 | |
| //   path, rm := Mktemp(t)
 | |
| //   defer rm()
 | |
| //   CWD is now 'path'
 | |
| // errors encountererd fail the current test.
 | |
| func Mktemp(t *testing.T) (string, func()) {
 | |
| 	t.Helper()
 | |
| 	tmp := t.TempDir()
 | |
| 	owd := pwd(t)
 | |
| 	cd(t, tmp)
 | |
| 	return tmp, func() {
 | |
| 		cd(t, owd)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Fromtemp is like Mktemp, but does not bother returing the temp path.
 | |
| func Fromtemp(t *testing.T) func() {
 | |
| 	_, done := Mktemp(t)
 | |
| 	return done
 | |
| }
 | |
| 
 | |
| // pwd prints the current working directory.
 | |
| // errors fail the test.
 | |
| func pwd(t *testing.T) string {
 | |
| 	t.Helper()
 | |
| 	d, err := os.Getwd()
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	return d
 | |
| }
 | |
| 
 | |
| // cd changes directory to the given directory.
 | |
| // errors fail the given test.
 | |
| func cd(t *testing.T, dir string) {
 | |
| 	if err := os.Chdir(dir); err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // ServeRepositry [name] from ./testdata/[name] returning URL at which
 | |
| // the named repository is available.
 | |
| // Must be called before any helpers which change test working directory
 | |
| // such as fromTempDirectory(t)
 | |
| func ServeRepo(name string, t *testing.T) string {
 | |
| 	t.Helper()
 | |
| 	var (
 | |
| 		path   = filepath.Join("./testdata", name)
 | |
| 		dir    = filepath.Dir(path)
 | |
| 		abs, _ = filepath.Abs(dir)
 | |
| 		repo   = filepath.Base(path)
 | |
| 		url    = RunGitServer(abs, t)
 | |
| 	)
 | |
| 	return fmt.Sprintf("%v/%v", url, repo)
 | |
| }
 | |
| 
 | |
| // WithExecutable creates an executable of the given name and source in a temp
 | |
| // directory which is then added to PATH.  Returned is a deferrable which will
 | |
| // clean up both the script and PATH.
 | |
| func WithExecutable(t *testing.T, name, goSrc string) {
 | |
| 	var err error
 | |
| 	binDir := t.TempDir()
 | |
| 
 | |
| 	newPath := binDir + string(os.PathListSeparator) + os.Getenv("PATH")
 | |
| 	t.Setenv("PATH", newPath)
 | |
| 
 | |
| 	goSrcPath := filepath.Join(binDir, fmt.Sprintf("%s.go", name))
 | |
| 
 | |
| 	err = os.WriteFile(goSrcPath,
 | |
| 		[]byte(goSrc),
 | |
| 		0400)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	runnerScriptName := name
 | |
| 	if runtime.GOOS == "windows" {
 | |
| 		runnerScriptName = runnerScriptName + ".bat"
 | |
| 	}
 | |
| 
 | |
| 	runnerScriptSrc := `#!/bin/sh
 | |
| exec go run GO_SCRIPT_PATH $@;
 | |
| `
 | |
| 	if runtime.GOOS == "windows" {
 | |
| 		runnerScriptSrc = `@echo off
 | |
| go.exe run GO_SCRIPT_PATH %*
 | |
| `
 | |
| 	}
 | |
| 
 | |
| 	runnerScriptPath := filepath.Join(binDir, runnerScriptName)
 | |
| 	runnerScriptSrc = strings.ReplaceAll(runnerScriptSrc, "GO_SCRIPT_PATH", goSrcPath)
 | |
| 	err = os.WriteFile(runnerScriptPath, []byte(runnerScriptSrc), 0700)
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // RunGitServer starts serving git HTTP server and returns its address
 | |
| func RunGitServer(root string, t *testing.T) (url string) {
 | |
| 	l, err := net.Listen("tcp", "127.0.0.1:0")
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 	url = l.Addr().String()
 | |
| 
 | |
| 	cmd := exec.Command("git", "--exec-path")
 | |
| 	out, err := cmd.CombinedOutput()
 | |
| 	if err != nil {
 | |
| 		t.Fatal(err)
 | |
| 	}
 | |
| 
 | |
| 	server := &http.Server{
 | |
| 		Handler: &cgi.Handler{
 | |
| 			Path: filepath.Join(strings.Trim(string(out), "\n"), "git-http-backend"),
 | |
| 			Env:  []string{"GIT_HTTP_EXPORT_ALL=true", fmt.Sprintf("GIT_PROJECT_ROOT=%s", root)},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	go func() {
 | |
| 		err = server.Serve(l)
 | |
| 		if err != nil && !strings.Contains(err.Error(), "Server closed") {
 | |
| 			fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	t.Cleanup(func() {
 | |
| 		server.Close()
 | |
| 	})
 | |
| 
 | |
| 	return "http://" + url
 | |
| }
 | |
| 
 | |
| // Cwd returns the current working directory or panic if unable to determine.
 | |
| func Cwd() (cwd string) {
 | |
| 	cwd, err := os.Getwd()
 | |
| 	if err != nil {
 | |
| 		panic(fmt.Sprintf("Unable to determine current working directory: %v", err))
 | |
| 	}
 | |
| 	return cwd
 | |
| }
 |