github.com/umeshredd/helm@v3.0.0-alpha.1+incompatible/pkg/registry/client_test.go (about)

     1  /*
     2  Copyright The Helm Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package registry
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"io"
    24  	"io/ioutil"
    25  	"net"
    26  	"os"
    27  	"path/filepath"
    28  	"testing"
    29  	"time"
    30  
    31  	auth "github.com/deislabs/oras/pkg/auth/docker"
    32  	"github.com/docker/distribution/configuration"
    33  	"github.com/docker/distribution/registry"
    34  	_ "github.com/docker/distribution/registry/auth/htpasswd"
    35  	_ "github.com/docker/distribution/registry/storage/driver/inmemory"
    36  	"github.com/stretchr/testify/suite"
    37  	"golang.org/x/crypto/bcrypt"
    38  
    39  	"helm.sh/helm/pkg/chart"
    40  )
    41  
    42  var (
    43  	testCacheRootDir         = "helm-registry-test"
    44  	testHtpasswdFileBasename = "authtest.htpasswd"
    45  	testUsername             = "myuser"
    46  	testPassword             = "mypass"
    47  )
    48  
    49  type RegistryClientTestSuite struct {
    50  	suite.Suite
    51  	Out                io.Writer
    52  	DockerRegistryHost string
    53  	CacheRootDir       string
    54  	RegistryClient     *Client
    55  }
    56  
    57  func (suite *RegistryClientTestSuite) SetupSuite() {
    58  	suite.CacheRootDir = testCacheRootDir
    59  	os.RemoveAll(suite.CacheRootDir)
    60  	os.Mkdir(suite.CacheRootDir, 0700)
    61  
    62  	var out bytes.Buffer
    63  	suite.Out = &out
    64  	credentialsFile := filepath.Join(suite.CacheRootDir, CredentialsFileBasename)
    65  
    66  	client, err := auth.NewClient(credentialsFile)
    67  	suite.Nil(err, "no error creating auth client")
    68  
    69  	resolver, err := client.Resolver(context.Background())
    70  	suite.Nil(err, "no error creating resolver")
    71  
    72  	// Init test client
    73  	suite.RegistryClient = NewClient(&ClientOptions{
    74  		Debug: false,
    75  		Out:   suite.Out,
    76  		Authorizer: Authorizer{
    77  			Client: client,
    78  		},
    79  		Resolver: Resolver{
    80  			Resolver: resolver,
    81  		},
    82  		CacheRootDir: suite.CacheRootDir,
    83  	})
    84  
    85  	// create htpasswd file (w BCrypt, which is required)
    86  	pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost)
    87  	suite.Nil(err, "no error generating bcrypt password for test htpasswd file")
    88  	htpasswdPath := filepath.Join(suite.CacheRootDir, testHtpasswdFileBasename)
    89  	err = ioutil.WriteFile(htpasswdPath, []byte(fmt.Sprintf("%s:%s\n", testUsername, string(pwBytes))), 0644)
    90  	suite.Nil(err, "no error creating test htpasswd file")
    91  
    92  	// Registry config
    93  	config := &configuration.Configuration{}
    94  	port, err := getFreePort()
    95  	suite.Nil(err, "no error finding free port for test registry")
    96  	suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port)
    97  	config.HTTP.Addr = fmt.Sprintf(":%d", port)
    98  	config.HTTP.DrainTimeout = time.Duration(10) * time.Second
    99  	config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
   100  	config.Auth = configuration.Auth{
   101  		"htpasswd": configuration.Parameters{
   102  			"realm": "localhost",
   103  			"path":  htpasswdPath,
   104  		},
   105  	}
   106  	dockerRegistry, err := registry.NewRegistry(context.Background(), config)
   107  	suite.Nil(err, "no error creating test registry")
   108  
   109  	// Start Docker registry
   110  	go dockerRegistry.ListenAndServe()
   111  }
   112  
   113  func (suite *RegistryClientTestSuite) TearDownSuite() {
   114  	os.RemoveAll(suite.CacheRootDir)
   115  }
   116  
   117  func (suite *RegistryClientTestSuite) Test_0_Login() {
   118  	err := suite.RegistryClient.Login(suite.DockerRegistryHost, "badverybad", "ohsobad")
   119  	suite.NotNil(err, "error logging into registry with bad credentials")
   120  
   121  	err = suite.RegistryClient.Login(suite.DockerRegistryHost, testUsername, testPassword)
   122  	suite.Nil(err, "no error logging into registry with good credentials")
   123  }
   124  
   125  func (suite *RegistryClientTestSuite) Test_1_SaveChart() {
   126  	ref, err := ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
   127  	suite.Nil(err)
   128  
   129  	// empty chart
   130  	err = suite.RegistryClient.SaveChart(&chart.Chart{}, ref)
   131  	suite.NotNil(err)
   132  
   133  	// valid chart
   134  	ch := &chart.Chart{}
   135  	ch.Metadata = &chart.Metadata{
   136  		APIVersion: "v1",
   137  		Name:       "testchart",
   138  		Version:    "1.2.3",
   139  	}
   140  	err = suite.RegistryClient.SaveChart(ch, ref)
   141  	suite.Nil(err)
   142  }
   143  
   144  func (suite *RegistryClientTestSuite) Test_2_LoadChart() {
   145  
   146  	// non-existent ref
   147  	ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
   148  	suite.Nil(err)
   149  	ch, err := suite.RegistryClient.LoadChart(ref)
   150  	suite.NotNil(err)
   151  
   152  	// existing ref
   153  	ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
   154  	suite.Nil(err)
   155  	ch, err = suite.RegistryClient.LoadChart(ref)
   156  	suite.Nil(err)
   157  	suite.Equal("testchart", ch.Metadata.Name)
   158  	suite.Equal("1.2.3", ch.Metadata.Version)
   159  }
   160  
   161  func (suite *RegistryClientTestSuite) Test_3_PushChart() {
   162  
   163  	// non-existent ref
   164  	ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
   165  	suite.Nil(err)
   166  	err = suite.RegistryClient.PushChart(ref)
   167  	suite.NotNil(err)
   168  
   169  	// existing ref
   170  	ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
   171  	suite.Nil(err)
   172  	err = suite.RegistryClient.PushChart(ref)
   173  	suite.Nil(err)
   174  }
   175  
   176  func (suite *RegistryClientTestSuite) Test_4_PullChart() {
   177  
   178  	// non-existent ref
   179  	ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
   180  	suite.Nil(err)
   181  	err = suite.RegistryClient.PullChart(ref)
   182  	suite.NotNil(err)
   183  
   184  	// existing ref
   185  	ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
   186  	suite.Nil(err)
   187  	err = suite.RegistryClient.PullChart(ref)
   188  	suite.Nil(err)
   189  }
   190  
   191  func (suite *RegistryClientTestSuite) Test_5_PrintChartTable() {
   192  	err := suite.RegistryClient.PrintChartTable()
   193  	suite.Nil(err)
   194  }
   195  
   196  func (suite *RegistryClientTestSuite) Test_6_RemoveChart() {
   197  
   198  	// non-existent ref
   199  	ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost))
   200  	suite.Nil(err)
   201  	err = suite.RegistryClient.RemoveChart(ref)
   202  	suite.NotNil(err)
   203  
   204  	// existing ref
   205  	ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost))
   206  	suite.Nil(err)
   207  	err = suite.RegistryClient.RemoveChart(ref)
   208  	suite.Nil(err)
   209  }
   210  
   211  func (suite *RegistryClientTestSuite) Test_7_Logout() {
   212  	err := suite.RegistryClient.Logout("this-host-aint-real:5000")
   213  	suite.NotNil(err, "error logging out of registry that has no entry")
   214  
   215  	err = suite.RegistryClient.Logout(suite.DockerRegistryHost)
   216  	suite.Nil(err, "no error logging out of registry")
   217  }
   218  
   219  func TestRegistryClientTestSuite(t *testing.T) {
   220  	suite.Run(t, new(RegistryClientTestSuite))
   221  }
   222  
   223  // borrowed from https://github.com/phayes/freeport
   224  func getFreePort() (int, error) {
   225  	addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
   226  	if err != nil {
   227  		return 0, err
   228  	}
   229  
   230  	l, err := net.ListenTCP("tcp", addr)
   231  	if err != nil {
   232  		return 0, err
   233  	}
   234  	defer l.Close()
   235  	return l.Addr().(*net.TCPAddr).Port, nil
   236  }