...

Source file src/github.com/docker/docker-credential-helpers/client/client_test.go

Documentation: github.com/docker/docker-credential-helpers/client

     1  package client
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/docker/docker-credential-helpers/credentials"
    11  )
    12  
    13  const (
    14  	validServerAddress   = "https://registry.example.com/v1"
    15  	validUsername        = "linus"
    16  	validServerAddress2  = "https://example.com:5002"
    17  	invalidServerAddress = "https://foobar.example.com"
    18  	missingCredsAddress  = "https://missing.example.com/v1"
    19  )
    20  
    21  var errProgramExited = fmt.Errorf("exited 1")
    22  
    23  // mockProgram simulates interactions between the docker client and a remote
    24  // credentials-helper.
    25  // Unit tests inject this mocked command into the remote to control execution.
    26  type mockProgram struct {
    27  	arg   string
    28  	input io.Reader
    29  }
    30  
    31  // Output returns responses from the remote credentials-helper.
    32  // It mocks those responses based in the input in the mock.
    33  func (m *mockProgram) Output() ([]byte, error) {
    34  	in, err := io.ReadAll(m.input)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	inS := string(in)
    39  
    40  	switch m.arg {
    41  	case "erase":
    42  		switch inS {
    43  		case validServerAddress:
    44  			return nil, nil
    45  		default:
    46  			return []byte("program failed"), errProgramExited
    47  		}
    48  	case "get":
    49  		switch inS {
    50  		case validServerAddress:
    51  			return []byte(`{"Username": "foo", "Secret": "bar"}`), nil
    52  		case validServerAddress2:
    53  			return []byte(`{"Username": "<token>", "Secret": "abcd1234"}`), nil
    54  		case missingCredsAddress:
    55  			return []byte(credentials.NewErrCredentialsNotFound().Error()), errProgramExited
    56  		case invalidServerAddress:
    57  			return []byte("program failed"), errProgramExited
    58  		case "":
    59  			return []byte(credentials.NewErrCredentialsMissingServerURL().Error()), errProgramExited
    60  		}
    61  	case "store":
    62  		var c credentials.Credentials
    63  		err := json.NewDecoder(strings.NewReader(inS)).Decode(&c)
    64  		if err != nil {
    65  			return []byte("error storing credentials"), errProgramExited
    66  		}
    67  		switch c.ServerURL {
    68  		case validServerAddress:
    69  			return nil, nil
    70  		case validServerAddress2:
    71  			return nil, nil
    72  		default:
    73  			return []byte("error storing credentials"), errProgramExited
    74  		}
    75  	case "list":
    76  		return []byte(fmt.Sprintf(`{"%s": "%s"}`, validServerAddress, validUsername)), nil
    77  
    78  	}
    79  
    80  	return []byte(fmt.Sprintf("unknown argument %q with %q", m.arg, inS)), errProgramExited
    81  }
    82  
    83  // Input sets the input to send to a remote credentials-helper.
    84  func (m *mockProgram) Input(in io.Reader) {
    85  	m.input = in
    86  }
    87  
    88  func mockProgramFn(args ...string) Program {
    89  	return &mockProgram{
    90  		arg: args[0],
    91  	}
    92  }
    93  
    94  func ExampleStore() {
    95  	p := NewShellProgramFunc("docker-credential-pass")
    96  
    97  	c := &credentials.Credentials{
    98  		ServerURL: "https://registry.example.com",
    99  		Username:  "exampleuser",
   100  		Secret:    "my super secret token",
   101  	}
   102  
   103  	if err := Store(p, c); err != nil {
   104  		_, _ = fmt.Println(err)
   105  	}
   106  }
   107  
   108  func TestStore(t *testing.T) {
   109  	valid := []credentials.Credentials{
   110  		{ServerURL: validServerAddress, Username: "foo", Secret: "bar"},
   111  		{ServerURL: validServerAddress2, Username: "<token>", Secret: "abcd1234"},
   112  	}
   113  
   114  	for _, v := range valid {
   115  		if err := Store(mockProgramFn, &v); err != nil {
   116  			t.Error(err)
   117  		}
   118  	}
   119  
   120  	invalid := []credentials.Credentials{
   121  		{ServerURL: invalidServerAddress, Username: "foo", Secret: "bar"},
   122  	}
   123  
   124  	for _, v := range invalid {
   125  		if err := Store(mockProgramFn, &v); err == nil {
   126  			t.Errorf("Expected error for server %s, got nil", v.ServerURL)
   127  		}
   128  	}
   129  }
   130  
   131  func ExampleGet() {
   132  	p := NewShellProgramFunc("docker-credential-pass")
   133  
   134  	creds, err := Get(p, "https://registry.example.com")
   135  	if err != nil {
   136  		_, _ = fmt.Println(err)
   137  	}
   138  
   139  	_, _ = fmt.Printf("Got credentials for user `%s` in `%s`\n", creds.Username, creds.ServerURL)
   140  }
   141  
   142  func TestGet(t *testing.T) {
   143  	valid := []credentials.Credentials{
   144  		{ServerURL: validServerAddress, Username: "foo", Secret: "bar"},
   145  		{ServerURL: validServerAddress2, Username: "<token>", Secret: "abcd1234"},
   146  	}
   147  
   148  	for _, v := range valid {
   149  		c, err := Get(mockProgramFn, v.ServerURL)
   150  		if err != nil {
   151  			t.Fatal(err)
   152  		}
   153  
   154  		if c.Username != v.Username {
   155  			t.Errorf("expected username `%s`, got %s", v.Username, c.Username)
   156  		}
   157  		if c.Secret != v.Secret {
   158  			t.Errorf("expected secret `%s`, got %s", v.Secret, c.Secret)
   159  		}
   160  	}
   161  
   162  	missingServerURLErr := credentials.NewErrCredentialsMissingServerURL()
   163  
   164  	invalid := []struct {
   165  		serverURL string
   166  		err       string
   167  	}{
   168  		{
   169  			serverURL: missingCredsAddress,
   170  			err:       credentials.NewErrCredentialsNotFound().Error(),
   171  		},
   172  		{
   173  			serverURL: invalidServerAddress,
   174  			err:       "error getting credentials - err: exited 1, out: `program failed`",
   175  		},
   176  		{
   177  			err: fmt.Sprintf("error getting credentials - err: %s, out: `%s`", missingServerURLErr.Error(), missingServerURLErr.Error()),
   178  		},
   179  	}
   180  
   181  	for _, v := range invalid {
   182  		_, err := Get(mockProgramFn, v.serverURL)
   183  		if err == nil {
   184  			t.Fatalf("Expected error for server %s, got nil", v.serverURL)
   185  		}
   186  		if err.Error() != v.err {
   187  			t.Errorf("Expected error `%s`, got `%v`", v.err, err)
   188  		}
   189  	}
   190  }
   191  
   192  func ExampleErase() {
   193  	p := NewShellProgramFunc("docker-credential-pass")
   194  
   195  	if err := Erase(p, "https://registry.example.com"); err != nil {
   196  		_, _ = fmt.Println(err)
   197  	}
   198  }
   199  
   200  func TestErase(t *testing.T) {
   201  	if err := Erase(mockProgramFn, validServerAddress); err != nil {
   202  		t.Error(err)
   203  	}
   204  
   205  	if err := Erase(mockProgramFn, invalidServerAddress); err == nil {
   206  		t.Errorf("Expected error for server %s, got nil", invalidServerAddress)
   207  	}
   208  }
   209  
   210  func TestList(t *testing.T) {
   211  	auths, err := List(mockProgramFn)
   212  	if err != nil {
   213  		t.Fatal(err)
   214  	}
   215  
   216  	if username, exists := auths[validServerAddress]; !exists || username != validUsername {
   217  		t.Errorf("auths[%s] returned %s, %t; expected %s, %t", validServerAddress, username, exists, validUsername, true)
   218  	}
   219  }
   220  

View as plain text