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