github.com/azure-devops-engineer/helm@v3.0.0-alpha.2+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 Out: suite.Out, 75 Authorizer: Authorizer{ 76 Client: client, 77 }, 78 Resolver: Resolver{ 79 Resolver: resolver, 80 }, 81 CacheRootDir: suite.CacheRootDir, 82 }) 83 84 // create htpasswd file (w BCrypt, which is required) 85 pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost) 86 suite.Nil(err, "no error generating bcrypt password for test htpasswd file") 87 htpasswdPath := filepath.Join(suite.CacheRootDir, testHtpasswdFileBasename) 88 err = ioutil.WriteFile(htpasswdPath, []byte(fmt.Sprintf("%s:%s\n", testUsername, string(pwBytes))), 0644) 89 suite.Nil(err, "no error creating test htpasswd file") 90 91 // Registry config 92 config := &configuration.Configuration{} 93 port, err := getFreePort() 94 suite.Nil(err, "no error finding free port for test registry") 95 suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port) 96 config.HTTP.Addr = fmt.Sprintf(":%d", port) 97 config.HTTP.DrainTimeout = time.Duration(10) * time.Second 98 config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}} 99 config.Auth = configuration.Auth{ 100 "htpasswd": configuration.Parameters{ 101 "realm": "localhost", 102 "path": htpasswdPath, 103 }, 104 } 105 dockerRegistry, err := registry.NewRegistry(context.Background(), config) 106 suite.Nil(err, "no error creating test registry") 107 108 // Start Docker registry 109 go dockerRegistry.ListenAndServe() 110 } 111 112 func (suite *RegistryClientTestSuite) TearDownSuite() { 113 os.RemoveAll(suite.CacheRootDir) 114 } 115 116 func (suite *RegistryClientTestSuite) Test_0_Login() { 117 err := suite.RegistryClient.Login(suite.DockerRegistryHost, "badverybad", "ohsobad") 118 suite.NotNil(err, "error logging into registry with bad credentials") 119 120 err = suite.RegistryClient.Login(suite.DockerRegistryHost, testUsername, testPassword) 121 suite.Nil(err, "no error logging into registry with good credentials") 122 } 123 124 func (suite *RegistryClientTestSuite) Test_1_SaveChart() { 125 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 126 suite.Nil(err) 127 128 // empty chart 129 err = suite.RegistryClient.SaveChart(&chart.Chart{}, ref) 130 suite.NotNil(err) 131 132 // valid chart 133 ch := &chart.Chart{} 134 ch.Metadata = &chart.Metadata{ 135 APIVersion: "v1", 136 Name: "testchart", 137 Version: "1.2.3", 138 } 139 err = suite.RegistryClient.SaveChart(ch, ref) 140 suite.Nil(err) 141 } 142 143 func (suite *RegistryClientTestSuite) Test_2_LoadChart() { 144 145 // non-existent ref 146 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) 147 suite.Nil(err) 148 ch, err := suite.RegistryClient.LoadChart(ref) 149 suite.NotNil(err) 150 151 // existing ref 152 ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 153 suite.Nil(err) 154 ch, err = suite.RegistryClient.LoadChart(ref) 155 suite.Nil(err) 156 suite.Equal("testchart", ch.Metadata.Name) 157 suite.Equal("1.2.3", ch.Metadata.Version) 158 } 159 160 func (suite *RegistryClientTestSuite) Test_3_PushChart() { 161 162 // non-existent ref 163 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) 164 suite.Nil(err) 165 err = suite.RegistryClient.PushChart(ref) 166 suite.NotNil(err) 167 168 // existing ref 169 ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 170 suite.Nil(err) 171 err = suite.RegistryClient.PushChart(ref) 172 suite.Nil(err) 173 } 174 175 func (suite *RegistryClientTestSuite) Test_4_PullChart() { 176 177 // non-existent ref 178 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) 179 suite.Nil(err) 180 err = suite.RegistryClient.PullChart(ref) 181 suite.NotNil(err) 182 183 // existing ref 184 ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 185 suite.Nil(err) 186 err = suite.RegistryClient.PullChart(ref) 187 suite.Nil(err) 188 } 189 190 func (suite *RegistryClientTestSuite) Test_5_PrintChartTable() { 191 err := suite.RegistryClient.PrintChartTable() 192 suite.Nil(err) 193 } 194 195 func (suite *RegistryClientTestSuite) Test_6_RemoveChart() { 196 197 // non-existent ref 198 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) 199 suite.Nil(err) 200 err = suite.RegistryClient.RemoveChart(ref) 201 suite.NotNil(err) 202 203 // existing ref 204 ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 205 suite.Nil(err) 206 err = suite.RegistryClient.RemoveChart(ref) 207 suite.Nil(err) 208 } 209 210 func (suite *RegistryClientTestSuite) Test_7_Logout() { 211 err := suite.RegistryClient.Logout("this-host-aint-real:5000") 212 suite.NotNil(err, "error logging out of registry that has no entry") 213 214 err = suite.RegistryClient.Logout(suite.DockerRegistryHost) 215 suite.Nil(err, "no error logging out of registry") 216 } 217 218 func TestRegistryClientTestSuite(t *testing.T) { 219 suite.Run(t, new(RegistryClientTestSuite)) 220 } 221 222 // borrowed from https://github.com/phayes/freeport 223 func getFreePort() (int, error) { 224 addr, err := net.ResolveTCPAddr("tcp", "localhost:0") 225 if err != nil { 226 return 0, err 227 } 228 229 l, err := net.ListenTCP("tcp", addr) 230 if err != nil { 231 return 0, err 232 } 233 defer l.Close() 234 return l.Addr().(*net.TCPAddr).Port, nil 235 }