module-transaction: Add GetUser() method that prompts an user if non-set
We can now finally test this properly both using a mock and through the interactive module that will do the request for us in various conditions.
This commit is contained in:
@@ -29,7 +29,7 @@ func ensureError(t *testing.T, err error, expected error) {
|
||||
func ensureEqual(t *testing.T, a any, b any) {
|
||||
t.Helper()
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.Fatalf("values mismatch %v vs %v", a, b)
|
||||
t.Fatalf("values mismatch %#v vs %#v", a, b)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,8 @@ func (cr *checkedRequest) check(res *Result) error {
|
||||
return cr.r.check(res, cr.exp)
|
||||
}
|
||||
|
||||
func ensureItem(tx *pam.Transaction, item pam.Item, expected string) error {
|
||||
func ensureUser(tx *pam.Transaction, expected string) error {
|
||||
item := pam.User
|
||||
if value, err := tx.GetItem(item); err != nil {
|
||||
return err
|
||||
} else if value != expected {
|
||||
@@ -152,7 +153,7 @@ func Test_Moduler_IntegrationTesterModule(t *testing.T) {
|
||||
exp: []interface{}{"an-user", nil},
|
||||
}},
|
||||
finish: func(tx *pam.Transaction, l *Listener, ts testState) error {
|
||||
return ensureItem(tx, pam.User, "an-user")
|
||||
return ensureUser(tx, "an-user")
|
||||
},
|
||||
},
|
||||
"set-item-User-preset": {
|
||||
@@ -167,7 +168,7 @@ func Test_Moduler_IntegrationTesterModule(t *testing.T) {
|
||||
exp: []interface{}{"an-user", nil},
|
||||
}},
|
||||
finish: func(tx *pam.Transaction, l *Listener, ts testState) error {
|
||||
return ensureItem(tx, pam.User, "an-user")
|
||||
return ensureUser(tx, "an-user")
|
||||
},
|
||||
},
|
||||
"set-get-item-User-empty": {
|
||||
@@ -488,6 +489,59 @@ func Test_Moduler_IntegrationTesterModule(t *testing.T) {
|
||||
return nil
|
||||
},
|
||||
},
|
||||
"get-user-empty-no-conv-set": {
|
||||
expectedError: pam.ErrConv,
|
||||
checkedRequests: []checkedRequest{{
|
||||
r: NewRequest("GetUser", "who are you? "),
|
||||
exp: []interface{}{"", pam.ErrConv},
|
||||
}},
|
||||
finish: func(tx *pam.Transaction, l *Listener, ts testState) error {
|
||||
return ensureUser(tx, "")
|
||||
},
|
||||
},
|
||||
"get-user-empty-with-conv": {
|
||||
credentials: utils.Credentials{
|
||||
User: "replying-user",
|
||||
ExpectedMessage: "who are you? ",
|
||||
ExpectedStyle: pam.PromptEchoOn,
|
||||
},
|
||||
checkedRequests: []checkedRequest{{
|
||||
r: NewRequest("GetUser", "who are you? "),
|
||||
exp: []interface{}{"replying-user", nil},
|
||||
}},
|
||||
finish: func(tx *pam.Transaction, l *Listener, ts testState) error {
|
||||
return ensureUser(tx, "replying-user")
|
||||
},
|
||||
},
|
||||
"get-user-preset-without-conv": {
|
||||
setup: func(tx *pam.Transaction, l *Listener, ts testState) error {
|
||||
return tx.SetItem(pam.User, "setup-user")
|
||||
},
|
||||
checkedRequests: []checkedRequest{{
|
||||
r: NewRequest("GetUser", "who are you? "),
|
||||
exp: []interface{}{"setup-user", nil},
|
||||
}},
|
||||
finish: func(tx *pam.Transaction, l *Listener, ts testState) error {
|
||||
return ensureUser(tx, "setup-user")
|
||||
},
|
||||
},
|
||||
"get-user-preset-with-conv": {
|
||||
credentials: utils.Credentials{
|
||||
User: "replying-user",
|
||||
ExpectedMessage: "No message should have been shown!",
|
||||
ExpectedStyle: pam.PromptEchoOn,
|
||||
},
|
||||
setup: func(tx *pam.Transaction, l *Listener, ts testState) error {
|
||||
return tx.SetItem(pam.User, "setup-user")
|
||||
},
|
||||
checkedRequests: []checkedRequest{{
|
||||
r: NewRequest("GetUser", "who are you? "),
|
||||
exp: []interface{}{"setup-user", nil},
|
||||
}},
|
||||
finish: func(tx *pam.Transaction, l *Listener, ts testState) error {
|
||||
return ensureUser(tx, "setup-user")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range tests {
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
// Package utils contains the internal test utils
|
||||
package utils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/msteinert/pam/v2"
|
||||
)
|
||||
|
||||
// Action represents a PAM action to perform.
|
||||
type Action int
|
||||
|
||||
@@ -106,3 +113,43 @@ type SerializableError struct {
|
||||
func (e *SerializableError) Error() string {
|
||||
return e.Msg
|
||||
}
|
||||
|
||||
// Credentials is a test [pam.ConversationHandler] implementation.
|
||||
type Credentials struct {
|
||||
User string
|
||||
Password string
|
||||
ExpectedMessage string
|
||||
CheckEmptyMessage bool
|
||||
ExpectedStyle pam.Style
|
||||
CheckZeroStyle bool
|
||||
Context interface{}
|
||||
}
|
||||
|
||||
// RespondPAM handles PAM string conversations.
|
||||
func (c Credentials) RespondPAM(s pam.Style, msg string) (string, error) {
|
||||
if (c.ExpectedMessage != "" || c.CheckEmptyMessage) &&
|
||||
msg != c.ExpectedMessage {
|
||||
return "", errors.Join(pam.ErrConv,
|
||||
&SerializableError{
|
||||
fmt.Sprintf("unexpected prompt: %s vs %s", msg, c.ExpectedMessage),
|
||||
})
|
||||
}
|
||||
|
||||
if (c.ExpectedStyle != 0 || c.CheckZeroStyle) &&
|
||||
s != c.ExpectedStyle {
|
||||
return "", errors.Join(pam.ErrConv,
|
||||
&SerializableError{
|
||||
fmt.Sprintf("unexpected style: %#v vs %#v", s, c.ExpectedStyle),
|
||||
})
|
||||
}
|
||||
|
||||
switch s {
|
||||
case pam.PromptEchoOn:
|
||||
return c.User, nil
|
||||
case pam.PromptEchoOff:
|
||||
return c.Password, nil
|
||||
}
|
||||
|
||||
return "", errors.Join(pam.ErrConv,
|
||||
&SerializableError{fmt.Sprintf("unhandled style: %v", s)})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user