c752dcdf51
In a future commit, we're going to be accessing credential handling from multiple packages. To avoid an import loop, move credential handling into its own package. Update all the callers of the credential handling code to use a qualified name. Where there is a local variable called "creds", which would conflict with our package name, rename it "cred" instead.
267 lines
7.6 KiB
Go
267 lines
7.6 KiB
Go
package creds
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type testCredHelper struct {
|
|
fillErr error
|
|
approveErr error
|
|
rejectErr error
|
|
fill []Creds
|
|
approve []Creds
|
|
reject []Creds
|
|
}
|
|
|
|
func newTestCredHelper() *testCredHelper {
|
|
return &testCredHelper{
|
|
fill: make([]Creds, 0),
|
|
approve: make([]Creds, 0),
|
|
reject: make([]Creds, 0),
|
|
}
|
|
}
|
|
|
|
func (h *testCredHelper) Fill(input Creds) (Creds, error) {
|
|
h.fill = append(h.fill, input)
|
|
return input, h.fillErr
|
|
}
|
|
|
|
func (h *testCredHelper) Approve(creds Creds) error {
|
|
h.approve = append(h.approve, creds)
|
|
return h.approveErr
|
|
}
|
|
|
|
func (h *testCredHelper) Reject(creds Creds) error {
|
|
h.reject = append(h.reject, creds)
|
|
return h.rejectErr
|
|
}
|
|
|
|
func TestCredHelperSetNoErrors(t *testing.T) {
|
|
cache := NewCredentialCacher()
|
|
helper1 := newTestCredHelper()
|
|
helper2 := newTestCredHelper()
|
|
helpers := NewCredentialHelpers([]CredentialHelper{cache, helper1, helper2})
|
|
creds := Creds{"protocol": "https", "host": "example.com"}
|
|
|
|
out, err := helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
|
|
// calling Fill() with empty cache
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 2, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
|
|
credsWithPass := Creds{"protocol": "https", "host": "example.com", "username": "foo", "password": "bar"}
|
|
assert.Nil(t, helpers.Approve(credsWithPass))
|
|
assert.Equal(t, 1, len(helper1.approve))
|
|
assert.Equal(t, 0, len(helper2.approve))
|
|
|
|
// calling Approve() again is cached
|
|
assert.Nil(t, helpers.Approve(credsWithPass))
|
|
assert.Equal(t, 1, len(helper1.approve))
|
|
assert.Equal(t, 0, len(helper2.approve))
|
|
|
|
// access cache
|
|
for i := 0; i < 3; i++ {
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, credsWithPass, out)
|
|
assert.Equal(t, 2, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
}
|
|
|
|
assert.Nil(t, helpers.Reject(creds))
|
|
assert.Equal(t, 1, len(helper1.reject))
|
|
assert.Equal(t, 0, len(helper2.reject))
|
|
|
|
// Reject() is never cached
|
|
assert.Nil(t, helpers.Reject(creds))
|
|
assert.Equal(t, 2, len(helper1.reject))
|
|
assert.Equal(t, 0, len(helper2.reject))
|
|
|
|
// calling Fill() with empty cache
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 3, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
}
|
|
|
|
func TestCredHelperSetFillError(t *testing.T) {
|
|
cache := NewCredentialCacher()
|
|
helper1 := newTestCredHelper()
|
|
helper2 := newTestCredHelper()
|
|
helpers := NewCredentialHelpers([]CredentialHelper{cache, helper1, helper2})
|
|
creds := Creds{"protocol": "https", "host": "example.com"}
|
|
|
|
helper1.fillErr = errors.New("boom")
|
|
out, err := helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill))
|
|
assert.Equal(t, 1, len(helper2.fill))
|
|
|
|
assert.Nil(t, helpers.Approve(creds))
|
|
assert.Equal(t, 0, len(helper1.approve))
|
|
assert.Equal(t, 1, len(helper2.approve))
|
|
|
|
// Fill() with cache
|
|
for i := 0; i < 3; i++ {
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill))
|
|
assert.Equal(t, 1, len(helper2.fill))
|
|
}
|
|
|
|
assert.Nil(t, helpers.Reject(creds))
|
|
assert.Equal(t, 0, len(helper1.reject))
|
|
assert.Equal(t, 1, len(helper2.reject))
|
|
|
|
// Fill() with empty cache
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill)) // still skipped
|
|
assert.Equal(t, 2, len(helper2.fill))
|
|
}
|
|
|
|
func TestCredHelperSetApproveError(t *testing.T) {
|
|
cache := NewCredentialCacher()
|
|
helper1 := newTestCredHelper()
|
|
helper2 := newTestCredHelper()
|
|
helpers := NewCredentialHelpers([]CredentialHelper{cache, helper1, helper2})
|
|
creds := Creds{"protocol": "https", "host": "example.com"}
|
|
|
|
approveErr := errors.New("boom")
|
|
helper1.approveErr = approveErr
|
|
out, err := helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
|
|
assert.Equal(t, approveErr, helpers.Approve(creds))
|
|
assert.Equal(t, 1, len(helper1.approve))
|
|
assert.Equal(t, 0, len(helper2.approve))
|
|
|
|
// cache is never set
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 2, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
|
|
assert.Nil(t, helpers.Reject(creds))
|
|
assert.Equal(t, 1, len(helper1.reject))
|
|
assert.Equal(t, 0, len(helper2.reject))
|
|
}
|
|
|
|
func TestCredHelperSetFillAndApproveError(t *testing.T) {
|
|
cache := NewCredentialCacher()
|
|
helper1 := newTestCredHelper()
|
|
helper2 := newTestCredHelper()
|
|
helpers := NewCredentialHelpers([]CredentialHelper{cache, helper1, helper2})
|
|
creds := Creds{"protocol": "https", "host": "example.com"}
|
|
|
|
credErr := errors.New("boom")
|
|
helper1.fillErr = credErr
|
|
helper2.approveErr = credErr
|
|
|
|
out, err := helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill))
|
|
assert.Equal(t, 1, len(helper2.fill))
|
|
|
|
assert.Equal(t, credErr, helpers.Approve(creds))
|
|
assert.Equal(t, 0, len(helper1.approve)) // skipped
|
|
assert.Equal(t, 0, len(helper1.reject)) // skipped
|
|
assert.Equal(t, 1, len(helper2.approve))
|
|
|
|
// never approved, so cache is empty
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill)) // still skipped
|
|
assert.Equal(t, 2, len(helper2.fill))
|
|
}
|
|
|
|
func TestCredHelperSetRejectError(t *testing.T) {
|
|
cache := NewCredentialCacher()
|
|
helper1 := newTestCredHelper()
|
|
helper2 := newTestCredHelper()
|
|
helpers := NewCredentialHelpers([]CredentialHelper{cache, helper1, helper2})
|
|
creds := Creds{"protocol": "https", "host": "example.com"}
|
|
|
|
rejectErr := errors.New("boom")
|
|
helper1.rejectErr = rejectErr
|
|
out, err := helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
|
|
assert.Nil(t, helpers.Approve(creds))
|
|
assert.Equal(t, 1, len(helper1.approve))
|
|
assert.Equal(t, 0, len(helper2.approve))
|
|
|
|
// Fill() with cache
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 1, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
|
|
assert.Equal(t, rejectErr, helpers.Reject(creds))
|
|
assert.Equal(t, 1, len(helper1.reject))
|
|
assert.Equal(t, 0, len(helper2.reject))
|
|
|
|
// failed Reject() still clears cache
|
|
out, err = helpers.Fill(creds)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, creds, out)
|
|
assert.Equal(t, 2, len(helper1.fill))
|
|
assert.Equal(t, 0, len(helper2.fill))
|
|
}
|
|
|
|
func TestCredHelperSetAllFillErrors(t *testing.T) {
|
|
cache := NewCredentialCacher()
|
|
helper1 := newTestCredHelper()
|
|
helper2 := newTestCredHelper()
|
|
helpers := NewCredentialHelpers([]CredentialHelper{cache, helper1, helper2})
|
|
creds := Creds{"protocol": "https", "host": "example.com"}
|
|
|
|
helper1.fillErr = errors.New("boom 1")
|
|
helper2.fillErr = errors.New("boom 2")
|
|
out, err := helpers.Fill(creds)
|
|
if assert.NotNil(t, err) {
|
|
assert.Equal(t, "credential fill errors:\nboom 1\nboom 2", err.Error())
|
|
}
|
|
assert.Nil(t, out)
|
|
assert.Equal(t, 1, len(helper1.fill))
|
|
assert.Equal(t, 1, len(helper2.fill))
|
|
|
|
err = helpers.Approve(creds)
|
|
if assert.NotNil(t, err) {
|
|
assert.Equal(t, "no valid credential helpers to approve", err.Error())
|
|
}
|
|
assert.Equal(t, 0, len(helper1.approve))
|
|
assert.Equal(t, 0, len(helper2.approve))
|
|
|
|
err = helpers.Reject(creds)
|
|
if assert.NotNil(t, err) {
|
|
assert.Equal(t, "no valid credential helpers to reject", err.Error())
|
|
}
|
|
assert.Equal(t, 0, len(helper1.reject))
|
|
assert.Equal(t, 0, len(helper2.reject))
|
|
}
|