Skip to content

Commit

Permalink
feat: introduce gittest and httptest
Browse files Browse the repository at this point in the history
  • Loading branch information
atzoum committed Sep 5, 2024
1 parent 7b26236 commit 14b676d
Show file tree
Hide file tree
Showing 4 changed files with 620 additions and 0 deletions.
124 changes: 124 additions & 0 deletions gittest/gittest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Package gittest provides a test helper for creating a git server that serves a git repository.
package gittest

import (
"encoding/pem"
"fmt"
"net"
"net/http/cgi"
"net/url"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/require"

"github.com/rudderlabs/rudder-go-kit/httptest"
)

type Server struct {
*httptest.Server
URL string
}

// NewHttpServer creates a new httptest.Server that serves a git repository from the given sourcePath.
func NewHttpServer(t testing.TB, sourcePath string) *Server {
return newServer(t, sourcePath, false)
}

// NewHttpsServer creates a new httptest.Server that serves a git repository from the given sourcePath.
func NewHttpsServer(t testing.TB, sourcePath string) *Server {
return newServer(t, sourcePath, true)
}

// newServer creates a new httptest.Server that serves a git repository from the given sourcePath.
func newServer(t testing.TB, sourcePath string, secure bool) *Server {
t.Helper()
tempDir := t.TempDir()
org := "org"
repo := filepath.Base(sourcePath)
if !strings.HasSuffix(repo, ".git") {
repo = repo + ".git"
}
source := sourcePath
if !strings.HasSuffix(sourcePath, "/") {
source = source + "/"
}
gitRoot := filepath.Join(tempDir, org, repo)
require.NoErrorf(t, os.MkdirAll(gitRoot, os.ModePerm), "should be able to create %s", gitRoot)
require.NoErrorf(t, exec.Command("rsync", "--recursive", source, gitRoot).Run(), "should be able to copy %s to %s", source, gitRoot)
gitPath, err := exec.LookPath("git")
require.NoError(t, err, "should be able to find git in PATH")
require.NoError(t, exec.Command("git", "init", gitRoot).Run(), "should be able to initialize git repository")
require.NoError(t, exec.Command("git", "-C", gitRoot, "add", ".").Run(), "should be able to add files to git repository")
commitCmd := exec.Command("git", "-C", gitRoot, "commit", "-m", "initial commit")
commitCmd.Env = append(commitCmd.Env, "GIT_AUTHOR_NAME=git test", "GIT_COMMITTER_NAME=git test", "[email protected]", "[email protected]")
require.NoError(t, commitCmd.Run(), "should be able to commit files to git repository")

handler := &cgi.Handler{
Path: gitPath,
Args: []string{"http-backend"},
Env: []string{
fmt.Sprintf("GIT_PROJECT_ROOT=%s", tempDir),
"GIT_HTTP_EXPORT_ALL=true",
},
}

localIP := getLocalIP(t)
var s *httptest.Server
if !secure {
s = httptest.NewServer(handler)
} else {
s = httptest.NewTLSServer(localIP, handler)
certPath := filepath.Join(tempDir, "server.crt")
require.NoError(t, writeServerCA(s, certPath))
t.Setenv("SSL_CERT_FILE", certPath)

}
serverURL, err := url.Parse(s.URL)
require.NoError(t, err)
_, port, err := net.SplitHostPort(serverURL.Host)
require.NoError(t, err)
serverURL.Host = net.JoinHostPort(getLocalIP(t), port)
url := serverURL.String() + "/" + org + "/" + repo
return &Server{
Server: s,
URL: url,
}
}

// getServerCA returns a byte slice containing the PEM encoding of the server's CA certificate
func (s *Server) GetServerCA() []byte {
return getServerCA(s.Server)
}

func getServerCA(server *httptest.Server) []byte {
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: server.TLS.Certificates[0].Certificate[0]})
}

// writeServerCA writes the PEM-encoded server certificate to a given path
func writeServerCA(server *httptest.Server, path string) error {
certOut, err := os.Create(path)
if err != nil {
return err
}
defer certOut.Close()

if _, err := certOut.Write(getServerCA(server)); err != nil {
return err
}

return nil
}

func getLocalIP(t testing.TB) string {
conn, err := net.Dial("udp", "8.8.8.8:80")
require.NoError(t, err)
defer func() {
require.NoError(t, conn.Close())
}()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP.String()
}
30 changes: 30 additions & 0 deletions gittest/gittest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package gittest_test

import (
"os/exec"
"testing"

"github.com/stretchr/testify/require"

"github.com/rudderlabs/rudder-go-kit/gittest"
)

func TestGitServer(t *testing.T) {
t.Run("http", func(t *testing.T) {
s := gittest.NewHttpServer(t, "testdata/gitrepo")
defer s.Close()
tempDir := t.TempDir()
url := s.URL
require.NoError(t, exec.Command("git", "-c", "http.sslVerify=false", "clone", url, tempDir).Run(), "should be able to clone the repository")
require.FileExists(t, tempDir+"/README.md", "README.md should exist in the cloned repository")
})

t.Run("https", func(t *testing.T) {
s := gittest.NewHttpsServer(t, "testdata/gitrepo")
defer s.Close()
tempDir := t.TempDir()
url := s.URL
require.NoError(t, exec.Command("git", "-c", "http.sslVerify=false", "clone", url, tempDir).Run(), "should be able to clone the repository")
require.FileExists(t, tempDir+"/README.md", "README.md should exist in the cloned repository")
})
}
1 change: 1 addition & 0 deletions gittest/testdata/gitrepo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World
Loading

0 comments on commit 14b676d

Please sign in to comment.