github.com/replicatedcom/ship@v0.50.0/pkg/specs/githubclient/client_test.go (about)

     1  package githubclient
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"io"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"net/url"
    10  	"path"
    11  	"path/filepath"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/go-kit/kit/log"
    16  	"github.com/google/go-github/github"
    17  	. "github.com/onsi/ginkgo"
    18  	. "github.com/onsi/gomega"
    19  	"github.com/replicatedhq/ship/pkg/constants"
    20  	"github.com/spf13/afero"
    21  )
    22  
    23  var client *github.Client
    24  var mux *http.ServeMux
    25  var serverURL string
    26  var teardown func()
    27  
    28  func setupGitClient() (client *github.Client, mux *http.ServeMux, serveURL string, teardown func()) {
    29  	mux = http.NewServeMux()
    30  	server := httptest.NewServer(mux)
    31  	client = github.NewClient(nil)
    32  	url, _ := url.Parse(server.URL + "/")
    33  	client.BaseURL = url
    34  	client.UploadURL = url
    35  
    36  	return client, mux, server.URL, server.Close
    37  }
    38  
    39  func TestGithubClient(t *testing.T) {
    40  	RegisterFailHandler(Fail)
    41  	RunSpecs(t, "GithubClient")
    42  }
    43  
    44  var _ = Describe("GithubClient", func() {
    45  	client, mux, serverURL, teardown = setupGitClient()
    46  	redirectArchive := func(w http.ResponseWriter, r *http.Request) {
    47  		http.Redirect(w, r, serverURL+"/archive.tar.gz", http.StatusFound)
    48  		return
    49  	}
    50  	mux.HandleFunc("/repos/o/r/tarball/", redirectArchive)
    51  	mux.HandleFunc("/repos/o/r/tarball", redirectArchive)
    52  
    53  	mux.HandleFunc("/archive.tar.gz", func(w http.ResponseWriter, r *http.Request) {
    54  		archiveData := `H4sIAJKjXFsAA+3WXW6CQBQFYJbCBmrv/D831ce+uIOpDtGEKQaoibt3qERbEmiNI6TxfC8TIwkXTg65lfW73D3ZcrXZ7t1zcg9EZJRKv059OonL09lKmRDcMM6k0SkxSYolqbrLNB2fVW3LMIoPr2DounBZlg383z7H+fwnqp/5v25sWc8O1ucR7xHeh5ZyKH9xzl+TDPkroylJKeIMvR48//fw8PC4Ov1fLl7mb4uZX8e8xzX9V4Y1/RdMof9jyIpi6hFgQp3+1y78tLWrYm6CV+1/oum/JqGx/42hN/+12+XFwbuPsA7euA3++v1n/LL/sZA/JyM4vv9juMQ89SQwhd7+V67cb1fu5vInf9n/zLf+y6b/nDP0fwxtzFOPAQAAAAAAAAAAAACRHQEZehxJACgAAA==`
    55  		dec := base64.NewDecoder(base64.StdEncoding, strings.NewReader(archiveData))
    56  		w.Header().Set("Content-Type", "application/gzip")
    57  		io.Copy(w, dec)
    58  	})
    59  
    60  	Describe("GetFiles", func() {
    61  		Context("With a url prefixed with http(s)", func() {
    62  			It("should fetch and persist README.md and Chart.yaml", func() {
    63  				validGitURLWithPrefix := "http://www.github.com/o/r/"
    64  				mockFs := afero.Afero{Fs: afero.NewMemMapFs()}
    65  				gitClient := &GithubClient{
    66  					Client: client,
    67  					Fs:     mockFs,
    68  					Logger: log.NewNopLogger(),
    69  				}
    70  
    71  				dest, err := gitClient.GetFiles(context.Background(), validGitURLWithPrefix, constants.HelmChartPath)
    72  				Expect(err).NotTo(HaveOccurred())
    73  
    74  				readme, err := gitClient.Fs.ReadFile(path.Join(dest, "README.md"))
    75  				Expect(err).NotTo(HaveOccurred())
    76  				chart, err := gitClient.Fs.ReadFile(path.Join(dest, "Chart.yaml"))
    77  				Expect(err).NotTo(HaveOccurred())
    78  				deployment, err := gitClient.Fs.ReadFile(path.Join(dest, "templates", "deployment.yml"))
    79  				Expect(err).NotTo(HaveOccurred())
    80  				service, err := gitClient.Fs.ReadFile(path.Join(dest, "templates", "service.yml"))
    81  				Expect(err).NotTo(HaveOccurred())
    82  
    83  				Expect(string(readme)).To(Equal("foo"))
    84  				Expect(string(chart)).To(Equal("bar"))
    85  				Expect(string(deployment)).To(Equal("deployment"))
    86  				Expect(string(service)).To(Equal("service"))
    87  			})
    88  		})
    89  
    90  		Context("With a url not prefixed with http", func() {
    91  			It("should fetch and persist README.md and Chart.yaml", func() {
    92  				validGitURLWithoutPrefix := "github.com/o/r"
    93  				mockFs := afero.Afero{Fs: afero.NewMemMapFs()}
    94  				gitClient := &GithubClient{
    95  					Client: client,
    96  					Fs:     mockFs,
    97  					Logger: log.NewNopLogger(),
    98  				}
    99  
   100  				dest, err := gitClient.GetFiles(context.Background(), validGitURLWithoutPrefix, constants.HelmChartPath)
   101  				Expect(err).NotTo(HaveOccurred())
   102  
   103  				readme, err := gitClient.Fs.ReadFile(path.Join(dest, "README.md"))
   104  				Expect(err).NotTo(HaveOccurred())
   105  				chart, err := gitClient.Fs.ReadFile(path.Join(dest, "Chart.yaml"))
   106  				Expect(err).NotTo(HaveOccurred())
   107  				deployment, err := gitClient.Fs.ReadFile(path.Join(dest, "templates", "deployment.yml"))
   108  				Expect(err).NotTo(HaveOccurred())
   109  				service, err := gitClient.Fs.ReadFile(path.Join(dest, "templates", "service.yml"))
   110  				Expect(err).NotTo(HaveOccurred())
   111  
   112  				Expect(string(readme)).To(Equal("foo"))
   113  				Expect(string(chart)).To(Equal("bar"))
   114  				Expect(string(deployment)).To(Equal("deployment"))
   115  				Expect(string(service)).To(Equal("service"))
   116  			})
   117  		})
   118  
   119  		Context("With a non-github url", func() {
   120  			It("should return an error", func() {
   121  				nonGithubURL := "gitlab.com/o/r"
   122  				mockFs := afero.Afero{Fs: afero.NewMemMapFs()}
   123  				gitClient := &GithubClient{
   124  					Client: client,
   125  					Fs:     mockFs,
   126  					Logger: log.NewNopLogger(),
   127  				}
   128  
   129  				_, err := gitClient.GetFiles(context.Background(), nonGithubURL, constants.HelmChartPath)
   130  				Expect(err).NotTo(BeNil())
   131  				Expect(err.Error()).To(Equal("http://gitlab.com/o/r is not a Github URL"))
   132  			})
   133  		})
   134  
   135  		Context("With a url path to a single file at the base of the repo", func() {
   136  			It("should fetch and persist the file", func() {
   137  				validGithubURLSingle := "github.com/o/r/blob/master/Chart.yaml"
   138  				mockFs := afero.Afero{Fs: afero.NewMemMapFs()}
   139  				gitClient := &GithubClient{
   140  					Client: client,
   141  					Fs:     mockFs,
   142  					Logger: log.NewNopLogger(),
   143  				}
   144  
   145  				dest, err := gitClient.GetFiles(context.Background(), validGithubURLSingle, constants.HelmChartPath)
   146  				Expect(err).NotTo(HaveOccurred())
   147  
   148  				chart, err := gitClient.Fs.ReadFile(filepath.Join(dest, "Chart.yaml"))
   149  				Expect(err).NotTo(HaveOccurred())
   150  
   151  				Expect(string(chart)).To(Equal("bar"))
   152  			})
   153  		})
   154  
   155  		Context("With a url path to a single nested file", func() {
   156  			It("should fetch and persist the file", func() {
   157  				validGithubURLSingle := "github.com/o/r/blob/master/templates/service.yml"
   158  				mockFs := afero.Afero{Fs: afero.NewMemMapFs()}
   159  				gitClient := &GithubClient{
   160  					Client: client,
   161  					Fs:     mockFs,
   162  					Logger: log.NewNopLogger(),
   163  				}
   164  
   165  				dest, err := gitClient.GetFiles(context.Background(), validGithubURLSingle, constants.HelmChartPath)
   166  				Expect(err).NotTo(HaveOccurred())
   167  				chart, err := gitClient.Fs.ReadFile(filepath.Join(dest, "templates", "service.yml"))
   168  				Expect(err).NotTo(HaveOccurred())
   169  
   170  				Expect(string(chart)).To(Equal("service"))
   171  			})
   172  		})
   173  	})
   174  
   175  	Describe("decodeGitHubURL", func() {
   176  		Context("With a valid github url", func() {
   177  			It("should decode a valid url without a path", func() {
   178  				chartPath := "github.com/o/r"
   179  				o, r, b, p, err := decodeGitHubURL(chartPath)
   180  				Expect(err).NotTo(HaveOccurred())
   181  
   182  				Expect(o).To(Equal("o"))
   183  				Expect(r).To(Equal("r"))
   184  				Expect(p).To(Equal(""))
   185  				Expect(b).To(Equal(""))
   186  			})
   187  
   188  			It("should decode a valid url with a path", func() {
   189  				chartPath := "github.com/o/r/stable/chart"
   190  				o, r, b, p, err := decodeGitHubURL(chartPath)
   191  				Expect(err).NotTo(HaveOccurred())
   192  
   193  				Expect(o).To(Equal("o"))
   194  				Expect(r).To(Equal("r"))
   195  				Expect(p).To(Equal("stable/chart"))
   196  				Expect(b).To(Equal(""))
   197  			})
   198  
   199  			It("should decode a valid url with a /tree/<branch>/ path", func() {
   200  				chartPath := "github.com/o/r/tree/master/stable/chart"
   201  				o, r, b, p, err := decodeGitHubURL(chartPath)
   202  				Expect(err).NotTo(HaveOccurred())
   203  
   204  				Expect(o).To(Equal("o"))
   205  				Expect(r).To(Equal("r"))
   206  				Expect(p).To(Equal("stable/chart"))
   207  				Expect(b).To(Equal("master"))
   208  			})
   209  		})
   210  
   211  		Context("With an invalid github url", func() {
   212  			It("should failed to decode a url without a path", func() {
   213  				chartPath := "github.com"
   214  				_, _, _, _, err := decodeGitHubURL(chartPath)
   215  				Expect(err).NotTo(BeNil())
   216  				Expect(err.Error()).To(Equal("github.com: unable to decode github url"))
   217  			})
   218  
   219  			It("should fail to decode a url with a path", func() {
   220  				chartPath := "github.com/o"
   221  				_, _, _, _, err := decodeGitHubURL(chartPath)
   222  				Expect(err).NotTo(BeNil())
   223  				Expect(err.Error()).To(Equal("github.com/o: unable to decode github url"))
   224  			})
   225  		})
   226  	})
   227  
   228  })
   229  
   230  var _ = AfterSuite(func() {
   231  	teardown()
   232  })