...

Source file src/oras.land/oras-go/pkg/auth/docker/client_test.go

Documentation: oras.land/oras-go/pkg/auth/docker

     1  /*
     2  Copyright The ORAS Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package docker
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"io/ioutil"
    22  	"net/http"
    23  	"os"
    24  	"path/filepath"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/distribution/distribution/v3/configuration"
    29  	"github.com/distribution/distribution/v3/registry"
    30  	_ "github.com/distribution/distribution/v3/registry/auth/htpasswd"
    31  	_ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory"
    32  	"github.com/phayes/freeport"
    33  	"github.com/stretchr/testify/suite"
    34  	"golang.org/x/crypto/bcrypt"
    35  	iface "oras.land/oras-go/pkg/auth"
    36  )
    37  
    38  var (
    39  	testConfig   = "test.config"
    40  	testHtpasswd = "test.htpasswd"
    41  	testUsername = "alice"
    42  	testPassword = "wonderland"
    43  )
    44  
    45  type DockerClientTestSuite struct {
    46  	suite.Suite
    47  	DockerRegistryHost string
    48  	Client             *Client
    49  	TempTestDir        string
    50  }
    51  
    52  func newContext() context.Context {
    53  	return context.Background()
    54  }
    55  
    56  func (suite *DockerClientTestSuite) SetupSuite() {
    57  	tempDir, err := ioutil.TempDir("", "oras_auth_docker_test")
    58  	suite.Nil(err, "no error creating temp directory for test")
    59  	suite.TempTestDir = tempDir
    60  
    61  	// Create client
    62  	client, err := NewClient(filepath.Join(suite.TempTestDir, testConfig))
    63  	suite.Nil(err, "no error creating client")
    64  	var ok bool
    65  	suite.Client, ok = client.(*Client)
    66  	suite.True(ok, "NewClient returns a *docker.Client inside")
    67  
    68  	// Create htpasswd file with bcrypt
    69  	secret, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost)
    70  	suite.Nil(err, "no error generating bcrypt password for test htpasswd file")
    71  	authRecord := fmt.Sprintf("%s:%s\n", testUsername, string(secret))
    72  	htpasswdPath := filepath.Join(suite.TempTestDir, testHtpasswd)
    73  	err = ioutil.WriteFile(htpasswdPath, []byte(authRecord), 0644)
    74  	suite.Nil(err, "no error creating test htpasswd file")
    75  
    76  	// Registry config
    77  	config := &configuration.Configuration{}
    78  	port, err := freeport.GetFreePort()
    79  	suite.Nil(err, "no error finding free port for test registry")
    80  	suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port)
    81  	config.HTTP.Addr = fmt.Sprintf(":%d", port)
    82  	config.HTTP.DrainTimeout = time.Duration(10) * time.Second
    83  	config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
    84  	config.Auth = configuration.Auth{
    85  		"htpasswd": configuration.Parameters{
    86  			"realm": "localhost",
    87  			"path":  htpasswdPath,
    88  		},
    89  	}
    90  	dockerRegistry, err := registry.NewRegistry(context.Background(), config)
    91  	suite.Nil(err, "no error finding free port for test registry")
    92  
    93  	// Start Docker registry
    94  	go dockerRegistry.ListenAndServe()
    95  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    96  	defer cancel()
    97  	for {
    98  		select {
    99  		case <-ctx.Done():
   100  			suite.FailNow("docker registry timed out")
   101  		default:
   102  		}
   103  		req, err := http.NewRequestWithContext(
   104  			ctx,
   105  			http.MethodGet,
   106  			fmt.Sprintf("http://%s/v2/", suite.DockerRegistryHost),
   107  			nil,
   108  		)
   109  		suite.Nil(err, "no error in generate a /v2/ request")
   110  		resp, err := http.DefaultClient.Do(req)
   111  		if err == nil {
   112  			resp.Body.Close()
   113  			break
   114  		}
   115  		time.Sleep(time.Second)
   116  	}
   117  }
   118  
   119  func (suite *DockerClientTestSuite) TearDownSuite() {
   120  	os.RemoveAll(suite.TempTestDir)
   121  }
   122  
   123  func (suite *DockerClientTestSuite) Test_0_Login() {
   124  	var err error
   125  
   126  	err = suite.Client.Login(newContext(), suite.DockerRegistryHost, "oscar", "opponent", false)
   127  	suite.NotNil(err, "error logging into registry with invalid credentials")
   128  
   129  	err = suite.Client.Login(newContext(), suite.DockerRegistryHost, testUsername, testPassword, false)
   130  	suite.Nil(err, "no error logging into registry with valid credentials")
   131  }
   132  
   133  func (suite *DockerClientTestSuite) Test_1_LoginWithOpts() {
   134  	var err error
   135  
   136  	opts := []iface.LoginOption{
   137  		iface.WithLoginContext(newContext()),
   138  		iface.WithLoginHostname(suite.DockerRegistryHost),
   139  		iface.WithLoginUsername("oscar"),
   140  		iface.WithLoginSecret("opponent"),
   141  	}
   142  	err = suite.Client.LoginWithOpts(opts...)
   143  	suite.NotNil(err, "error logging into registry with invalid credentials (LoginWithOpts)")
   144  
   145  	opts = []iface.LoginOption{
   146  		iface.WithLoginContext(newContext()),
   147  		iface.WithLoginHostname(suite.DockerRegistryHost),
   148  		iface.WithLoginUsername(testUsername),
   149  		iface.WithLoginSecret(testPassword),
   150  	}
   151  	err = suite.Client.LoginWithOpts(opts...)
   152  	suite.Nil(err, "no error logging into registry with valid credentials (LoginWithOpts)")
   153  }
   154  
   155  func (suite *DockerClientTestSuite) Test_2_Logout() {
   156  	var err error
   157  
   158  	err = suite.Client.Logout(newContext(), "non-existing-host:42")
   159  	suite.NotNil(err, "error logging out of registry that has no entry")
   160  
   161  	err = suite.Client.Logout(newContext(), suite.DockerRegistryHost)
   162  	suite.Nil(err, "no error logging out of registry")
   163  }
   164  
   165  func TestDockerClientTestSuite(t *testing.T) {
   166  	suite.Run(t, new(DockerClientTestSuite))
   167  }
   168  

View as plain text