github.com/codefresh-io/kcfi@v0.0.0-20230301195427-c1578715cc46/pkg/helm-internal/experimental/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 "net/http" 27 "os" 28 "path/filepath" 29 "testing" 30 "time" 31 32 auth "github.com/deislabs/oras/pkg/auth/docker" 33 "github.com/docker/distribution/configuration" 34 "github.com/docker/distribution/registry" 35 _ "github.com/docker/distribution/registry/auth/htpasswd" 36 _ "github.com/docker/distribution/registry/storage/driver/inmemory" 37 "github.com/stretchr/testify/suite" 38 "golang.org/x/crypto/bcrypt" 39 40 "helm.sh/helm/v3/pkg/chart" 41 ) 42 43 var ( 44 testCacheRootDir = "helm-registry-test" 45 testHtpasswdFileBasename = "authtest.htpasswd" 46 testUsername = "myuser" 47 testPassword = "mypass" 48 ) 49 50 type RegistryClientTestSuite struct { 51 suite.Suite 52 Out io.Writer 53 DockerRegistryHost string 54 CacheRootDir string 55 RegistryClient *Client 56 } 57 58 func (suite *RegistryClientTestSuite) SetupSuite() { 59 suite.CacheRootDir = testCacheRootDir 60 os.RemoveAll(suite.CacheRootDir) 61 os.Mkdir(suite.CacheRootDir, 0700) 62 63 var out bytes.Buffer 64 suite.Out = &out 65 credentialsFile := filepath.Join(suite.CacheRootDir, CredentialsFileBasename) 66 67 client, err := auth.NewClient(credentialsFile) 68 suite.Nil(err, "no error creating auth client") 69 70 resolver, err := client.Resolver(context.Background(), http.DefaultClient, false) 71 suite.Nil(err, "no error creating resolver") 72 73 // create cache 74 cache, err := NewCache( 75 CacheOptDebug(true), 76 CacheOptWriter(suite.Out), 77 CacheOptRoot(filepath.Join(suite.CacheRootDir, CacheRootDir)), 78 ) 79 suite.Nil(err, "no error creating cache") 80 81 // init test client 82 suite.RegistryClient, err = NewClient( 83 ClientOptDebug(true), 84 ClientOptWriter(suite.Out), 85 ClientOptAuthorizer(&Authorizer{ 86 Client: client, 87 }), 88 ClientOptResolver(&Resolver{ 89 Resolver: resolver, 90 }), 91 ClientOptCache(cache), 92 ) 93 suite.Nil(err, "no error creating registry client") 94 95 // create htpasswd file (w BCrypt, which is required) 96 pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost) 97 suite.Nil(err, "no error generating bcrypt password for test htpasswd file") 98 htpasswdPath := filepath.Join(suite.CacheRootDir, testHtpasswdFileBasename) 99 err = ioutil.WriteFile(htpasswdPath, []byte(fmt.Sprintf("%s:%s\n", testUsername, string(pwBytes))), 0644) 100 suite.Nil(err, "no error creating test htpasswd file") 101 102 // Registry config 103 config := &configuration.Configuration{} 104 port, err := getFreePort() 105 suite.Nil(err, "no error finding free port for test registry") 106 suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port) 107 config.HTTP.Addr = fmt.Sprintf(":%d", port) 108 config.HTTP.DrainTimeout = time.Duration(10) * time.Second 109 config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}} 110 config.Auth = configuration.Auth{ 111 "htpasswd": configuration.Parameters{ 112 "realm": "localhost", 113 "path": htpasswdPath, 114 }, 115 } 116 dockerRegistry, err := registry.NewRegistry(context.Background(), config) 117 suite.Nil(err, "no error creating test registry") 118 119 // Start Docker registry 120 go dockerRegistry.ListenAndServe() 121 } 122 123 func (suite *RegistryClientTestSuite) TearDownSuite() { 124 os.RemoveAll(suite.CacheRootDir) 125 } 126 127 func (suite *RegistryClientTestSuite) Test_0_Login() { 128 err := suite.RegistryClient.Login(suite.DockerRegistryHost, "badverybad", "ohsobad", false) 129 suite.NotNil(err, "error logging into registry with bad credentials") 130 131 err = suite.RegistryClient.Login(suite.DockerRegistryHost, "badverybad", "ohsobad", true) 132 suite.NotNil(err, "error logging into registry with bad credentials, insecure mode") 133 134 err = suite.RegistryClient.Login(suite.DockerRegistryHost, testUsername, testPassword, false) 135 suite.Nil(err, "no error logging into registry with good credentials") 136 137 err = suite.RegistryClient.Login(suite.DockerRegistryHost, testUsername, testPassword, true) 138 suite.Nil(err, "no error logging into registry with good credentials, insecure mode") 139 } 140 141 func (suite *RegistryClientTestSuite) Test_1_SaveChart() { 142 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 143 suite.Nil(err) 144 145 // empty chart 146 err = suite.RegistryClient.SaveChart(&chart.Chart{}, ref) 147 suite.NotNil(err) 148 149 // valid chart 150 ch := &chart.Chart{} 151 ch.Metadata = &chart.Metadata{ 152 APIVersion: "v1", 153 Name: "testchart", 154 Version: "1.2.3", 155 } 156 err = suite.RegistryClient.SaveChart(ch, ref) 157 suite.Nil(err) 158 } 159 160 func (suite *RegistryClientTestSuite) Test_2_LoadChart() { 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.LoadChart(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 ch, err := suite.RegistryClient.LoadChart(ref) 172 suite.Nil(err) 173 suite.Equal("testchart", ch.Metadata.Name) 174 suite.Equal("1.2.3", ch.Metadata.Version) 175 } 176 177 func (suite *RegistryClientTestSuite) Test_3_PushChart() { 178 179 // non-existent ref 180 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) 181 suite.Nil(err) 182 err = suite.RegistryClient.PushChart(ref) 183 suite.NotNil(err) 184 185 // existing ref 186 ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 187 suite.Nil(err) 188 err = suite.RegistryClient.PushChart(ref) 189 suite.Nil(err) 190 } 191 192 func (suite *RegistryClientTestSuite) Test_4_PullChart() { 193 194 // non-existent ref 195 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) 196 suite.Nil(err) 197 err = suite.RegistryClient.PullChart(ref) 198 suite.NotNil(err) 199 200 // existing ref 201 ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 202 suite.Nil(err) 203 err = suite.RegistryClient.PullChart(ref) 204 suite.Nil(err) 205 } 206 207 func (suite *RegistryClientTestSuite) Test_5_PrintChartTable() { 208 err := suite.RegistryClient.PrintChartTable() 209 suite.Nil(err) 210 } 211 212 func (suite *RegistryClientTestSuite) Test_6_RemoveChart() { 213 214 // non-existent ref 215 ref, err := ParseReference(fmt.Sprintf("%s/testrepo/whodis:9.9.9", suite.DockerRegistryHost)) 216 suite.Nil(err) 217 err = suite.RegistryClient.RemoveChart(ref) 218 suite.NotNil(err) 219 220 // existing ref 221 ref, err = ParseReference(fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)) 222 suite.Nil(err) 223 err = suite.RegistryClient.RemoveChart(ref) 224 suite.Nil(err) 225 } 226 227 func (suite *RegistryClientTestSuite) Test_7_Logout() { 228 err := suite.RegistryClient.Logout("this-host-aint-real:5000") 229 suite.NotNil(err, "error logging out of registry that has no entry") 230 231 err = suite.RegistryClient.Logout(suite.DockerRegistryHost) 232 suite.Nil(err, "no error logging out of registry") 233 } 234 235 func TestRegistryClientTestSuite(t *testing.T) { 236 suite.Run(t, new(RegistryClientTestSuite)) 237 } 238 239 // borrowed from https://github.com/phayes/freeport 240 func getFreePort() (int, error) { 241 addr, err := net.ResolveTCPAddr("tcp", "localhost:0") 242 if err != nil { 243 return 0, err 244 } 245 246 l, err := net.ListenTCP("tcp", addr) 247 if err != nil { 248 return 0, err 249 } 250 defer l.Close() 251 return l.Addr().(*net.TCPAddr).Port, nil 252 }