github.com/wtsi-hgi/go-softpack-builder@v1.8.1/internal/gitmock/mock.go (about)

     1  package gitmock
     2  
     3  import (
     4  	crypto "crypto/rand"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"io"
     8  	"math/rand"
     9  	"net/http"
    10  
    11  	"github.com/wtsi-hgi/go-softpack-builder/internal"
    12  )
    13  
    14  const (
    15  	refsPath         = "/info/refs"
    16  	refsQuery        = "?service=git-upload-pack"
    17  	headPath         = "/HEAD"
    18  	smartContentType = "application/x-git-upload-pack-advertisement"
    19  	expectedHeader   = "001e# service=git-upload-pack\n0000"
    20  	headRef          = "HEAD"
    21  
    22  	numRefGen = 5
    23  	hashLen   = 40
    24  )
    25  
    26  const (
    27  	ErrNotFound = internal.Error("not found")
    28  )
    29  
    30  // MockGit can be used to start a pretend git server for testing custom spack
    31  // repos.
    32  type MockGit struct {
    33  	refs       map[string]string
    34  	masterName string
    35  	Smart      bool
    36  }
    37  
    38  // New returns a new MockGit that provides a git repo with a random number of
    39  // random refs.
    40  func New() (*MockGit, string) {
    41  	numRefs := rand.Intn(numRefGen) + numRefGen //nolint:gosec
    42  
    43  	refs := make(map[string]string, numRefs)
    44  
    45  	var (
    46  		masterName, masterCommit string
    47  		hash                     [20]byte
    48  	)
    49  
    50  	for i := 0; i < numRefs; i++ {
    51  		randChars := make([]byte, rand.Intn(numRefGen)+numRefGen) //nolint:gosec
    52  		crypto.Read(randChars)                                    //nolint:errcheck
    53  		crypto.Read(hash[:])                                      //nolint:errcheck
    54  
    55  		masterName = base64.RawStdEncoding.EncodeToString(randChars)
    56  		masterCommit = fmt.Sprintf("%020X", hash)
    57  
    58  		refs[masterName] = masterCommit
    59  	}
    60  
    61  	return &MockGit{
    62  		refs:       refs,
    63  		masterName: masterName,
    64  	}, masterCommit
    65  }
    66  
    67  // ServeHTTP is to implement http.Handler so you can httptest.NewServer(m).
    68  func (m *MockGit) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    69  	if err := m.handle(w, r.URL.Path); err != nil {
    70  		http.Error(w, err.Error(), http.StatusInternalServerError)
    71  	}
    72  }
    73  
    74  func (m *MockGit) handle(w http.ResponseWriter, path string) error {
    75  	switch path {
    76  	case refsPath:
    77  		if m.Smart {
    78  			w.Header().Set("Content-Type", smartContentType)
    79  
    80  			return m.handleSmartRefs(w)
    81  		}
    82  
    83  		return m.handleRefs(w)
    84  	case headPath:
    85  		return m.handleHead(w)
    86  	}
    87  
    88  	return ErrNotFound
    89  }
    90  
    91  func (m *MockGit) handleSmartRefs(w io.Writer) error {
    92  	if _, err := fmt.Fprintf(w, "%s002D%s %s\n", expectedHeader, m.refs[m.masterName], headRef); err != nil {
    93  		return err
    94  	}
    95  
    96  	for ref, commit := range m.refs {
    97  		if _, err := fmt.Fprintf(w, "%04X%s %s\n", hashLen+1+len(ref), commit, ref); err != nil {
    98  			return err
    99  		}
   100  	}
   101  
   102  	_, err := io.WriteString(w, "0000")
   103  
   104  	return err
   105  }
   106  
   107  func (m *MockGit) handleRefs(w io.Writer) error {
   108  	for ref, commit := range m.refs {
   109  		if _, err := fmt.Fprintf(w, "%s\t%s\n", commit, ref); err != nil {
   110  			return err
   111  		}
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  func (m *MockGit) handleHead(w io.Writer) error {
   118  	_, err := io.WriteString(w, "ref: "+m.masterName)
   119  
   120  	return err
   121  }