github.com/sleungcy/cli@v7.1.0+incompatible/integration/helpers/plugin_repo.go (about)

     1  package helpers
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"log"
     9  	"net/http"
    10  	"os"
    11  	"path/filepath"
    12  
    13  	"code.cloudfoundry.org/cli/util"
    14  	"code.cloudfoundry.org/cli/util/generic"
    15  
    16  	. "github.com/onsi/gomega"
    17  	. "github.com/onsi/gomega/ghttp"
    18  )
    19  
    20  // Binary represents the metadata need to retrieve one of the binaries that makes up a plugin.
    21  type Binary struct {
    22  	Checksum string `json:"checksum"`
    23  	Platform string `json:"platform"`
    24  	URL      string `json:"url"`
    25  }
    26  
    27  // Plugin represents a plugin object provided by a plugin repo.
    28  type Plugin struct {
    29  	Name     string   `json:"name"`
    30  	Version  string   `json:"version"`
    31  	Binaries []Binary `json:"binaries"`
    32  }
    33  
    34  // PluginRepository represents a repo response object describing a list of plugins available.
    35  type PluginRepository struct {
    36  	Plugins []Plugin `json:"plugins"`
    37  }
    38  
    39  // PluginRepositoryServerWithPlugin represents a server used to provide downloadable plugins.
    40  type PluginRepositoryServerWithPlugin struct {
    41  	server     *Server
    42  	pluginPath string
    43  }
    44  
    45  // NewPluginRepositoryServer is used to configure and start a new plugin repo server, exposing the plugins contained
    46  // in the pluginRepo.
    47  func NewPluginRepositoryServer(pluginRepo PluginRepository) *Server {
    48  	return configurePluginRepositoryServer(NewTLSServer(), pluginRepo)
    49  }
    50  
    51  // NewPluginRepositoryServerWithPlugin is used to create a server to provide a single configurable_plugin
    52  // with user provided name, version, and platform.
    53  func NewPluginRepositoryServerWithPlugin(pluginType string, pluginName string, version string, platform string, shouldCalculateChecksum bool) *PluginRepositoryServerWithPlugin {
    54  	pluginRepoServer := PluginRepositoryServerWithPlugin{}
    55  
    56  	pluginRepoServer.Init(pluginType, pluginName, version, platform, shouldCalculateChecksum)
    57  
    58  	return &pluginRepoServer
    59  }
    60  
    61  // Init initializes a server to provide a single configurable_plugin with user provided name, version, and platform.
    62  func (pluginRepoServer *PluginRepositoryServerWithPlugin) Init(pluginType string, pluginName string, version string, platform string, shouldCalculateChecksum bool) {
    63  	pluginPath := BuildConfigurablePlugin(pluginType, pluginName, version,
    64  		[]PluginCommand{
    65  			{Name: "some-command", Help: "some-command-help"},
    66  		},
    67  	)
    68  
    69  	repoServer := NewServer()
    70  
    71  	pluginRepoServer.server = repoServer
    72  	pluginRepoServer.pluginPath = pluginPath
    73  
    74  	var (
    75  		checksum []byte
    76  		err      error
    77  	)
    78  
    79  	if shouldCalculateChecksum {
    80  		checksum, err = util.NewSha1Checksum(pluginPath).ComputeFileSha1()
    81  		Expect(err).NotTo(HaveOccurred())
    82  	}
    83  
    84  	baseFile := fmt.Sprintf("/%s", generic.ExecutableFilename(filepath.Base(pluginPath)))
    85  	downloadURL := fmt.Sprintf("%s%s", repoServer.URL(), baseFile)
    86  	pluginRepo := PluginRepository{
    87  		Plugins: []Plugin{
    88  			{
    89  				Name:    pluginName,
    90  				Version: version,
    91  				Binaries: []Binary{
    92  					{
    93  						Checksum: fmt.Sprintf("%x", checksum),
    94  						Platform: platform,
    95  						URL:      downloadURL,
    96  					},
    97  				},
    98  			},
    99  		}}
   100  
   101  	// Suppresses ginkgo server logs
   102  	repoServer.HTTPTestServer.Config.ErrorLog = log.New(&bytes.Buffer{}, "", 0)
   103  
   104  	jsonBytes, err := json.Marshal(pluginRepo)
   105  	Expect(err).ToNot(HaveOccurred())
   106  
   107  	pluginData, err := ioutil.ReadFile(pluginPath)
   108  	Expect(err).ToNot(HaveOccurred())
   109  
   110  	repoServer.AppendHandlers(
   111  		CombineHandlers(
   112  			VerifyRequest(http.MethodGet, "/list"),
   113  			RespondWith(http.StatusOK, jsonBytes),
   114  		),
   115  		CombineHandlers(
   116  			VerifyRequest(http.MethodGet, "/list"),
   117  			RespondWith(http.StatusOK, jsonBytes),
   118  		),
   119  		CombineHandlers(
   120  			VerifyRequest(http.MethodGet, baseFile),
   121  			RespondWith(http.StatusOK, pluginData),
   122  		),
   123  	)
   124  }
   125  
   126  // PluginSize is used to get the size in bytes of the single plugin provided by the pluginRepoServer
   127  func (pluginRepoServer *PluginRepositoryServerWithPlugin) PluginSize() int64 {
   128  	fileinfo, err := os.Stat(pluginRepoServer.pluginPath)
   129  	Expect(err).NotTo(HaveOccurred())
   130  	return fileinfo.Size()
   131  }
   132  
   133  // URL is used to get the pluginRepo's server url
   134  func (pluginRepoServer *PluginRepositoryServerWithPlugin) URL() string {
   135  	return pluginRepoServer.server.URL()
   136  }
   137  
   138  // Close is used to destroy the repo server and cleanup any files
   139  func (pluginRepoServer *PluginRepositoryServerWithPlugin) Cleanup() {
   140  	pluginRepoServer.server.Close()
   141  	Expect(os.RemoveAll(filepath.Dir(pluginRepoServer.pluginPath))).NotTo(HaveOccurred())
   142  }
   143  
   144  // NewPluginRepositoryTLSServer is used to configure and start a new TLS plugin repo server, exposing the plugins contained
   145  // in the pluginRepo.
   146  func NewPluginRepositoryTLSServer(pluginRepo PluginRepository) *Server {
   147  	return configurePluginRepositoryServer(NewTLSServer(), pluginRepo)
   148  }
   149  
   150  func configurePluginRepositoryServer(server *Server, pluginRepo PluginRepository) *Server {
   151  	// Suppresses ginkgo server logs
   152  	server.HTTPTestServer.Config.ErrorLog = log.New(&bytes.Buffer{}, "", 0)
   153  
   154  	jsonBytes, err := json.Marshal(pluginRepo)
   155  	Expect(err).ToNot(HaveOccurred())
   156  
   157  	server.AppendHandlers(
   158  		RespondWith(http.StatusOK, string(jsonBytes)),
   159  		RespondWith(http.StatusOK, string(jsonBytes)),
   160  		RespondWith(http.StatusOK, string(jsonBytes)),
   161  		RespondWith(http.StatusOK, string(jsonBytes)),
   162  	)
   163  
   164  	return server
   165  }