1112 lines
36 KiB
Go
1112 lines
36 KiB
Go
// Package pam provides a wrapper for the PAM application API.
|
|
package pam
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type customConvRequest int
|
|
|
|
func (r customConvRequest) Style() Style {
|
|
return Style(r)
|
|
}
|
|
|
|
func ensureNoError(t *testing.T, err error) {
|
|
t.Helper()
|
|
if err != nil {
|
|
t.Fatalf("unexpected error %v", err)
|
|
}
|
|
}
|
|
|
|
func Test_NewNullModuleTransaction(t *testing.T) {
|
|
t.Parallel()
|
|
t.Cleanup(maybeDoLeakCheck)
|
|
mt := moduleTransaction{}
|
|
|
|
if mt.handle != nil {
|
|
t.Fatalf("unexpected handle value: %v", mt.handle)
|
|
}
|
|
|
|
if s := Error(mt.lastStatus.Load()); s != success {
|
|
t.Fatalf("unexpected status: %v", s)
|
|
}
|
|
|
|
tests := map[string]struct {
|
|
testFunc func(t *testing.T) (any, error)
|
|
expectedError error
|
|
ignoreError bool
|
|
}{
|
|
"GetItem": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return mt.GetItem(Service)
|
|
},
|
|
},
|
|
"SetItem": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return nil, mt.SetItem(Service, "foo")
|
|
},
|
|
},
|
|
"GetEnv": {
|
|
ignoreError: true,
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return mt.GetEnv("foo"), nil
|
|
},
|
|
},
|
|
"PutEnv": {
|
|
expectedError: ErrAbort,
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return nil, mt.PutEnv("foo=bar")
|
|
},
|
|
},
|
|
"GetEnvList": {
|
|
expectedError: ErrBuf,
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
list, err := mt.GetEnvList()
|
|
if len(list) > 0 {
|
|
t.Fatalf("unexpected list: %v", list)
|
|
}
|
|
return nil, err
|
|
},
|
|
},
|
|
"GetUser": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return mt.GetUser("prompt")
|
|
},
|
|
},
|
|
"GetData": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return mt.GetData("some-data")
|
|
},
|
|
},
|
|
"SetData": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return nil, mt.SetData("foo", []interface{}{})
|
|
},
|
|
},
|
|
"SetData-nil": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return nil, mt.SetData("foo", nil)
|
|
},
|
|
},
|
|
"StartConv-StringConv": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return mt.StartConv(NewStringConvRequest(TextInfo, "a prompt"))
|
|
},
|
|
},
|
|
"StartStringConv": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return mt.StartStringConv(TextInfo, "a prompt")
|
|
},
|
|
},
|
|
"StartStringConvf": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return mt.StartStringConvf(TextInfo, "a prompt %s", "with info")
|
|
},
|
|
},
|
|
"StartConvMulti": {
|
|
testFunc: func(t *testing.T) (any, error) {
|
|
t.Helper()
|
|
return mt.StartConvMulti([]ConvRequest{
|
|
NewStringConvRequest(TextInfo, "a prompt"),
|
|
NewStringConvRequest(ErrorMsg, "another prompt"),
|
|
NewBinaryConvRequest(BinaryPointer(&mt), nil),
|
|
NewBinaryConvRequestFromBytes([]byte("These are bytes!")),
|
|
NewBinaryConvRequestFromBytes([]byte{}),
|
|
NewBinaryConvRequestFromBytes(nil),
|
|
NewBinaryConvRequest(nil, nil),
|
|
})
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, tc := range tests {
|
|
tc := tc
|
|
t.Run(name+"-error-check", func(t *testing.T) {
|
|
t.Parallel()
|
|
t.Cleanup(maybeDoLeakCheck)
|
|
data, err := tc.testFunc(t)
|
|
|
|
switch d := data.(type) {
|
|
case string:
|
|
if d != "" {
|
|
t.Fatalf("empty value was expected, got %s", d)
|
|
}
|
|
case interface{}:
|
|
if !reflect.ValueOf(d).IsNil() {
|
|
t.Fatalf("nil value was expected, got %v", d)
|
|
}
|
|
default:
|
|
if d != nil {
|
|
t.Fatalf("nil value was expected, got %v", d)
|
|
}
|
|
}
|
|
|
|
if tc.ignoreError {
|
|
return
|
|
}
|
|
if err == nil {
|
|
t.Fatal("error was expected, but got none")
|
|
}
|
|
|
|
var expectedError error = ErrSystem
|
|
if tc.expectedError != nil {
|
|
expectedError = tc.expectedError
|
|
}
|
|
|
|
if !errors.Is(err, expectedError) {
|
|
t.Fatalf("status %v was expected, but got %v",
|
|
expectedError, err)
|
|
}
|
|
})
|
|
}
|
|
|
|
for name, tc := range tests {
|
|
// These can't be parallel - we test a private value that is not thread safe
|
|
t.Run(name+"-lastStatus-check", func(t *testing.T) {
|
|
mt.lastStatus.Store(99999)
|
|
_, err := tc.testFunc(t)
|
|
status := Error(mt.lastStatus.Load())
|
|
|
|
if tc.ignoreError {
|
|
return
|
|
}
|
|
if err == nil {
|
|
t.Fatal("error was expected, but got none")
|
|
}
|
|
|
|
expectedStatus := ErrSystem
|
|
if tc.expectedError != nil {
|
|
errors.As(err, &expectedStatus)
|
|
}
|
|
|
|
if status != expectedStatus {
|
|
t.Fatalf("status %v was expected, but got %d",
|
|
expectedStatus, status)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_ModuleTransaction_InvokeHandler(t *testing.T) {
|
|
t.Parallel()
|
|
t.Cleanup(maybeDoLeakCheck)
|
|
mt := &moduleTransaction{}
|
|
|
|
err := mt.InvokeHandler(nil, 0, nil)
|
|
if !errors.Is(err, ErrIgnore) {
|
|
t.Fatalf("unexpected err: %v", err)
|
|
}
|
|
|
|
tests := map[string]struct {
|
|
flags Flags
|
|
args []string
|
|
returnedError error
|
|
expectedError error
|
|
expectedErrorMsg string
|
|
}{
|
|
"success": {
|
|
expectedError: nil,
|
|
},
|
|
"success-with-flags": {
|
|
expectedError: nil,
|
|
flags: Silent | RefreshCred,
|
|
},
|
|
"success-with-args": {
|
|
expectedError: nil,
|
|
args: []string{"foo", "bar"},
|
|
},
|
|
"success-with-args-and-flags": {
|
|
expectedError: nil,
|
|
flags: Silent | RefreshCred,
|
|
args: []string{"foo", "bar"},
|
|
},
|
|
"ignore": {
|
|
expectedError: ErrIgnore,
|
|
returnedError: ErrIgnore,
|
|
},
|
|
"ignore-with-args-and-flags": {
|
|
expectedError: ErrIgnore,
|
|
returnedError: ErrIgnore,
|
|
args: []string{"foo", "bar"},
|
|
},
|
|
"generic-error": {
|
|
expectedError: ErrSystem,
|
|
returnedError: errors.New("this is a generic go error"),
|
|
expectedErrorMsg: "this is a generic go error",
|
|
},
|
|
"transaction-error-service-error": {
|
|
expectedError: ErrService,
|
|
returnedError: errors.Join(ErrService, errors.New("ErrService")),
|
|
expectedErrorMsg: ErrService.Error(),
|
|
},
|
|
"return-type-as-error-success": {
|
|
expectedError: nil,
|
|
returnedError: Error(0),
|
|
},
|
|
"return-type-as-error": {
|
|
expectedError: ErrNoModuleData,
|
|
returnedError: ErrNoModuleData,
|
|
expectedErrorMsg: ErrNoModuleData.Error(),
|
|
},
|
|
}
|
|
|
|
for name, tc := range tests {
|
|
tc := tc
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
err := mt.InvokeHandler(func(handlerMt ModuleTransaction,
|
|
handlerFlags Flags, handlerArgs []string) error {
|
|
if handlerMt != mt {
|
|
t.Fatalf("unexpected mt: %#v vs %#v", mt, handlerMt)
|
|
}
|
|
if handlerFlags != tc.flags {
|
|
t.Fatalf("unexpected mt: %#v vs %#v", tc.flags, handlerFlags)
|
|
}
|
|
if strings.Join(handlerArgs, "") != strings.Join(tc.args, "") {
|
|
t.Fatalf("unexpected mt: %#v vs %#v", tc.args, handlerArgs)
|
|
}
|
|
|
|
return tc.returnedError
|
|
}, tc.flags, tc.args)
|
|
|
|
status := Error(mt.lastStatus.Load())
|
|
|
|
if !errors.Is(err, tc.expectedError) {
|
|
t.Fatalf("unexpected err: %#v vs %#v", err, tc.expectedError)
|
|
}
|
|
|
|
var expectedStatus Error
|
|
if err != nil {
|
|
var pamErr Error
|
|
if errors.As(err, &pamErr) {
|
|
expectedStatus = pamErr
|
|
} else {
|
|
expectedStatus = ErrSystem
|
|
}
|
|
}
|
|
|
|
if status != expectedStatus {
|
|
t.Fatalf("unexpected status: %#v vs %#v", status, expectedStatus)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func testMockModuleTransaction(t *testing.T, mt *moduleTransaction) {
|
|
t.Helper()
|
|
t.Parallel()
|
|
t.Cleanup(maybeDoLeakCheck)
|
|
|
|
tests := map[string]struct {
|
|
testFunc func(mock *mockModuleTransaction) (any, error)
|
|
mockExpectations mockModuleTransactionExpectations
|
|
mockRetData mockModuleTransactionReturnedData
|
|
conversationHandler ConversationHandler
|
|
|
|
expectedError error
|
|
expectedValue any
|
|
ignoreError bool
|
|
}{
|
|
"GetUser-empty": {
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
UserPrompt: "who are you?"},
|
|
expectedValue: "",
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.getUserImpl(mock, "who are you?")
|
|
},
|
|
},
|
|
"GetUser-preset-value": {
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
UserPrompt: "who are you?"},
|
|
mockRetData: mockModuleTransactionReturnedData{User: "dummy-user"},
|
|
expectedValue: "dummy-user",
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.getUserImpl(mock, "who are you?")
|
|
},
|
|
},
|
|
"GetUser-conversation-value": {
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
UserPrompt: "who are you?"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: PromptEchoOn,
|
|
ExpectedMessage: "who are you?",
|
|
User: "returned-dummy-user",
|
|
},
|
|
expectedValue: "returned-dummy-user",
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.getUserImpl(mock, "who are you?")
|
|
},
|
|
},
|
|
"GetUser-conversation-error-prompt": {
|
|
expectedError: ErrConv,
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
UserPrompt: "who are you?"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: PromptEchoOn,
|
|
ExpectedMessage: "who are you???",
|
|
},
|
|
expectedValue: "",
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.getUserImpl(mock, "who are you?")
|
|
},
|
|
},
|
|
"GetUser-conversation-error-style": {
|
|
expectedError: ErrConv,
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
UserPrompt: "who are you?"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: PromptEchoOff,
|
|
ExpectedMessage: "who are you?",
|
|
},
|
|
expectedValue: "",
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.getUserImpl(mock, "who are you?")
|
|
},
|
|
},
|
|
"GetData-not-available": {
|
|
expectedError: ErrNoModuleData,
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
DataKey: "not-available-data"},
|
|
expectedValue: nil,
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.getDataImpl(mock, "not-available-data")
|
|
},
|
|
},
|
|
"GetData-not-available-other-failure": {
|
|
expectedError: ErrBuf,
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
DataKey: "not-available-data"},
|
|
mockRetData: mockModuleTransactionReturnedData{Status: ErrBuf},
|
|
expectedValue: nil,
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.getDataImpl(mock, "not-available-data")
|
|
},
|
|
},
|
|
"SetData-empty-nil": {
|
|
expectedError: ErrNoModuleData,
|
|
expectedValue: nil,
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
ensureNoError(mock.T, mt.setDataImpl(mock, "", nil))
|
|
return mt.getDataImpl(mock, "")
|
|
},
|
|
},
|
|
"SetData-empty-to-value": {
|
|
expectedValue: []string{"hello", "world"},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
ensureNoError(mock.T, mt.setDataImpl(mock, "",
|
|
[]string{"hello", "world"}))
|
|
return mt.getDataImpl(mock, "")
|
|
},
|
|
},
|
|
"SetData-to-value": {
|
|
expectedValue: []interface{}{"a string", true, 0.55, errors.New("oh no")},
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
DataKey: "some-data"},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
ensureNoError(mock.T, mt.setDataImpl(mock, "some-data",
|
|
[]interface{}{"a string", true, 0.55, errors.New("oh no")}))
|
|
return mt.getDataImpl(mock, "some-data")
|
|
},
|
|
},
|
|
"SetData-to-value-replacing": {
|
|
expectedValue: "just a value",
|
|
mockExpectations: mockModuleTransactionExpectations{
|
|
DataKey: "replaced-data"},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
ensureNoError(mock.T, mt.setDataImpl(mock, "replaced-data",
|
|
[]interface{}{"a string", true, 0.55, errors.New("oh no")}))
|
|
ensureNoError(mock.T, mt.setDataImpl(mock, "replaced-data",
|
|
"just a value"))
|
|
return mt.getDataImpl(mock, "replaced-data")
|
|
},
|
|
},
|
|
"StartConv-no-conv-set": {
|
|
expectedError: ErrConv,
|
|
expectedValue: nil,
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, StringConvRequest{
|
|
TextInfo,
|
|
"hello PAM!",
|
|
})
|
|
},
|
|
},
|
|
"StartConv-text-info": {
|
|
expectedValue: stringConvResponse{TextInfo, "nice to see you, Go!"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: TextInfo,
|
|
ExpectedMessage: "hello PAM!",
|
|
TextInfo: "nice to see you, Go!",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, StringConvRequest{
|
|
TextInfo,
|
|
"hello PAM!",
|
|
})
|
|
},
|
|
},
|
|
"StartConv-error-msg": {
|
|
expectedValue: stringConvResponse{ErrorMsg, "ops, sorry..."},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: ErrorMsg,
|
|
ExpectedMessage: "This is wrong, PAM!",
|
|
ErrorMsg: "ops, sorry...",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, StringConvRequest{
|
|
ErrorMsg,
|
|
"This is wrong, PAM!",
|
|
})
|
|
},
|
|
},
|
|
"StartConv-prompt-echo-on": {
|
|
expectedValue: stringConvResponse{PromptEchoOn, "here's my public data"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: PromptEchoOn,
|
|
ExpectedMessage: "Give me your non-private infos",
|
|
PromptEchoOn: "here's my public data",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, StringConvRequest{
|
|
PromptEchoOn,
|
|
"Give me your non-private infos",
|
|
})
|
|
},
|
|
},
|
|
"StartConv-prompt-echo-off": {
|
|
expectedValue: stringConvResponse{PromptEchoOff, "here's my private data"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: PromptEchoOff,
|
|
ExpectedMessage: "Give me your private secrets",
|
|
PromptEchoOff: "here's my private data",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, StringConvRequest{
|
|
PromptEchoOff,
|
|
"Give me your private secrets",
|
|
})
|
|
},
|
|
},
|
|
"StartConv-unknown-style": {
|
|
expectedError: ErrConv,
|
|
expectedValue: nil,
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: Style(9999),
|
|
ExpectedMessage: "hello PAM!",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, StringConvRequest{
|
|
Style(9999),
|
|
"hello PAM!",
|
|
})
|
|
},
|
|
},
|
|
"StartConv-unknown-style-response": {
|
|
expectedError: ErrConv,
|
|
expectedValue: nil,
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: Style(9999),
|
|
ExpectedMessage: "hello PAM!",
|
|
IgnoreUnknownStyle: true,
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, StringConvRequest{
|
|
Style(9999),
|
|
"hello PAM!",
|
|
})
|
|
},
|
|
},
|
|
"StartStringConv-text-info": {
|
|
expectedValue: stringConvResponse{TextInfo, "nice to see you, Go!"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: TextInfo,
|
|
ExpectedMessage: "hello PAM!",
|
|
TextInfo: "nice to see you, Go!",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startStringConvImpl(mock, TextInfo,
|
|
"hello PAM!")
|
|
},
|
|
},
|
|
"StartStringConv-error-msg": {
|
|
expectedValue: stringConvResponse{ErrorMsg, "ops, sorry..."},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: ErrorMsg,
|
|
ExpectedMessage: "This is wrong, PAM!",
|
|
ErrorMsg: "ops, sorry...",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startStringConvImpl(mock, ErrorMsg,
|
|
"This is wrong, PAM!")
|
|
},
|
|
},
|
|
"StartStringConv-prompt-echo-on": {
|
|
expectedValue: stringConvResponse{PromptEchoOn, "here's my public data"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: PromptEchoOn,
|
|
ExpectedMessage: "Give me your non-private infos",
|
|
PromptEchoOn: "here's my public data",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startStringConvImpl(mock, PromptEchoOn,
|
|
"Give me your non-private infos")
|
|
},
|
|
},
|
|
"StartStringConv-prompt-echo-off": {
|
|
expectedValue: stringConvResponse{PromptEchoOff, "here's my private data"},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: PromptEchoOff,
|
|
ExpectedMessage: "Give me your private secrets",
|
|
PromptEchoOff: "here's my private data",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startStringConvImpl(mock, PromptEchoOff,
|
|
"Give me your private secrets")
|
|
},
|
|
},
|
|
"StartStringConv-binary": {
|
|
expectedError: ErrConv,
|
|
expectedValue: nil,
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedMessage: "require binary data",
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startStringConvImpl(mock, PromptEchoOff,
|
|
"require binary data")
|
|
},
|
|
},
|
|
"StartConvMulti-missing": {
|
|
expectedError: ErrConv,
|
|
expectedValue: ([]ConvResponse)(nil),
|
|
conversationHandler: mockConversationHandler{},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvMultiImpl(mock, nil)
|
|
},
|
|
},
|
|
"StartConvMulti-too-many": {
|
|
expectedError: ErrConv,
|
|
expectedValue: ([]ConvResponse)(nil),
|
|
conversationHandler: mockConversationHandler{},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
reqs := [maxNumMsg + 1]ConvRequest{}
|
|
return mt.startConvMultiImpl(mock, reqs[:])
|
|
},
|
|
},
|
|
"StartConvMulti-unexpected-style": {
|
|
expectedError: ErrConv,
|
|
expectedValue: ([]ConvResponse)(nil),
|
|
conversationHandler: mockConversationHandler{},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
var req ConvRequest = customConvRequest(0xdeadbeef)
|
|
return mt.startConvMultiImpl(mock, []ConvRequest{req})
|
|
},
|
|
},
|
|
"StartConvMulti-string-as-binary": {
|
|
expectedError: ErrConv,
|
|
expectedValue: ([]ConvResponse)(nil),
|
|
conversationHandler: mockConversationHandler{},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvMultiImpl(mock, []ConvRequest{
|
|
NewStringConvRequest(BinaryPrompt, "no binary!"),
|
|
})
|
|
},
|
|
},
|
|
"StartConvMulti-all-types": {
|
|
expectedValue: []any{
|
|
[]ConvResponse{
|
|
stringConvResponse{TextInfo, "nice to see you, Go!"},
|
|
stringConvResponse{ErrorMsg, "ops, sorry..."},
|
|
stringConvResponse{PromptEchoOn, "here's my public data"},
|
|
stringConvResponse{PromptEchoOff, "here's my private data"},
|
|
},
|
|
[][]byte{
|
|
{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
},
|
|
},
|
|
conversationHandler: mockConversationHandler{
|
|
TextInfo: "nice to see you, Go!",
|
|
ErrorMsg: "ops, sorry...",
|
|
PromptEchoOn: "here's my public data",
|
|
PromptEchoOff: "here's my private data",
|
|
Binary: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
ExpectedMessagesByStyle: map[Style]string{
|
|
TextInfo: "hello PAM!",
|
|
ErrorMsg: "This is wrong, PAM!",
|
|
PromptEchoOn: "Give me your non-private infos",
|
|
PromptEchoOff: "Give me your private secrets",
|
|
},
|
|
ExpectedBinary: []byte("\x00This is a binary data request\xC5\x00\xffYes it is!"),
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
requests := []ConvRequest{
|
|
NewStringConvRequest(TextInfo, "hello PAM!"),
|
|
NewStringConvRequest(ErrorMsg, "This is wrong, PAM!"),
|
|
NewStringConvRequest(PromptEchoOn, "Give me your non-private infos"),
|
|
NewStringConvRequest(PromptEchoOff, "Give me your private secrets"),
|
|
NewBinaryConvRequestFromBytes(
|
|
testBinaryDataEncoder([]byte("\x00This is a binary data request\xC5\x00\xffYes it is!"))),
|
|
}
|
|
|
|
data, err := mt.startConvMultiImpl(mock, requests)
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
|
|
stringResponses := []ConvResponse{}
|
|
binaryResponses := [][]byte{}
|
|
for i, r := range data {
|
|
if r.Style() != requests[i].Style() {
|
|
mock.T.Fatalf("unexpected style %#v vs %#v",
|
|
r.Style(), requests[i].Style())
|
|
}
|
|
|
|
switch rt := r.(type) {
|
|
case BinaryConvResponse:
|
|
decoded, err := rt.Decode(testBinaryDataDecoder)
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
binaryResponses = append(binaryResponses, decoded)
|
|
case StringConvResponse:
|
|
stringResponses = append(stringResponses, r)
|
|
default:
|
|
mock.T.Fatalf("unexpected value %v", rt)
|
|
}
|
|
}
|
|
return []any{
|
|
stringResponses,
|
|
binaryResponses,
|
|
}, err
|
|
},
|
|
},
|
|
"StartConvMulti-all-types-some-failing": {
|
|
expectedError: ErrConv,
|
|
expectedValue: []ConvResponse(nil),
|
|
conversationHandler: mockConversationHandler{
|
|
TextInfo: "nice to see you, Go!",
|
|
ErrorMsg: "ops, sorry...",
|
|
PromptEchoOn: "here's my public data",
|
|
PromptEchoOff: "here's my private data",
|
|
Binary: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
ExpectedMessagesByStyle: map[Style]string{
|
|
TextInfo: "hello PAM!",
|
|
ErrorMsg: "This is wrong, PAM!",
|
|
PromptEchoOn: "Give me your non-private infos",
|
|
PromptEchoOff: "Give me your private secrets",
|
|
Style(0xfaaf): "This will fail",
|
|
},
|
|
ExpectedBinary: []byte("\x00This is a binary data request\xC5\x00\xffYes it is!"),
|
|
IgnoreUnknownStyle: true,
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
requests := []ConvRequest{
|
|
NewStringConvRequest(TextInfo, "hello PAM!"),
|
|
NewStringConvRequest(ErrorMsg, "This is wrong, PAM!"),
|
|
NewStringConvRequest(PromptEchoOn, "Give me your non-private infos"),
|
|
NewStringConvRequest(PromptEchoOff, "Give me your private secrets"),
|
|
NewStringConvRequest(Style(0xfaaf), "This will fail"),
|
|
NewBinaryConvRequestFromBytes(
|
|
testBinaryDataEncoder([]byte("\x00This is a binary data request\xC5\x00\xffYes it is!"))),
|
|
}
|
|
|
|
return mt.startConvMultiImpl(mock, requests)
|
|
},
|
|
},
|
|
"StartConv-Binary-unsupported": {
|
|
expectedValue: nil,
|
|
expectedError: ErrConv,
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x00This is a binary data request\xC5\x00\xffYes it is!"),
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
mock.binaryProtocol = false
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is!"))
|
|
return mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
},
|
|
},
|
|
"StartConv-Binary": {
|
|
expectedValue: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x00This is a binary data request\xC5\x00\xffYes it is!"),
|
|
Binary: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is!"))
|
|
data, err := mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
bcr, _ := data.(BinaryConvResponse)
|
|
return bcr.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartConv-Binary-expected-data-mismatch": {
|
|
expectedError: ErrConv,
|
|
expectedValue: nil,
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x00This is not the expected data!"),
|
|
Binary: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is!"))
|
|
return mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
},
|
|
},
|
|
"StartConv-Binary-unexpected-nil": {
|
|
expectedError: ErrConv,
|
|
expectedValue: nil,
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x00This should not be nil"),
|
|
Binary: []byte("\x1ASome binary Dat\xaa"),
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(nil))
|
|
},
|
|
},
|
|
"StartConv-Binary-expected-nil": {
|
|
expectedValue: []byte("\x1ASome binary Dat\xaa"),
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedNil: true,
|
|
ExpectedBinary: []byte("\x00This should not be nil"),
|
|
Binary: []byte("\x1ASome binary Dat\xaa"),
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
data, err := mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(nil))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
bcr, _ := data.(BinaryConvResponse)
|
|
return bcr.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartConv-Binary-returns-nil": {
|
|
expectedValue: BinaryPointer(nil),
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x1ASome binary Dat\xaa"),
|
|
Binary: nil,
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte("\x1ASome binary Dat\xaa"))
|
|
data, err := mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
bcr, _ := data.(BinaryConvResponse)
|
|
return bcr.Data(), err
|
|
},
|
|
},
|
|
"StartBinaryConv": {
|
|
expectedValue: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x00This is a binary data request\xC5\x00\xffYes it is!"),
|
|
Binary: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is!"))
|
|
data, err := mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
bcr, _ := data.(BinaryConvResponse)
|
|
return bcr.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartBinaryConv-expected-data-mismatch": {
|
|
expectedError: ErrConv,
|
|
expectedValue: nil,
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x00This is not the expected data!"),
|
|
Binary: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is!"))
|
|
return mt.startBinaryConvImpl(mock, bytes)
|
|
},
|
|
},
|
|
"StartBinaryConv-unexpected-nil": {
|
|
expectedError: ErrConv,
|
|
expectedValue: nil,
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x00This should not be nil"),
|
|
Binary: []byte("\x1ASome binary Dat\xaa"),
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startBinaryConvImpl(mock, nil)
|
|
},
|
|
},
|
|
"StartBinaryConv-expected-nil": {
|
|
expectedValue: []byte("\x1ASome binary Dat\xaa"),
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedNil: true,
|
|
ExpectedBinary: []byte("\x00This should not be nil"),
|
|
Binary: []byte("\x1ASome binary Dat\xaa"),
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
data, err := mt.startBinaryConvImpl(mock, nil)
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
return data.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartBinaryConv-returns-nil": {
|
|
expectedValue: BinaryPointer(nil),
|
|
conversationHandler: mockConversationHandler{
|
|
ExpectedStyle: BinaryPrompt,
|
|
ExpectedBinary: []byte("\x1ASome binary Dat\xaa"),
|
|
Binary: nil,
|
|
},
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte("\x1ASome binary Dat\xaa"))
|
|
data, err := mt.startBinaryConvImpl(mock, bytes)
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
return data.Data(), err
|
|
},
|
|
},
|
|
"StartConv-Binary-with-ConvFunc": {
|
|
expectedValue: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99},
|
|
conversationHandler: BinaryConversationFunc(func(ptr BinaryPointer) ([]byte, error) {
|
|
bytes, _ := testBinaryDataDecoder(ptr)
|
|
expectedBinary := []byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is!")
|
|
if !reflect.DeepEqual(bytes, expectedBinary) {
|
|
return nil, fmt.Errorf("%w, data mismatch %#v vs %#v",
|
|
ErrConv, bytes, expectedBinary)
|
|
}
|
|
return testBinaryDataEncoder([]byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x99}), nil
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is!"))
|
|
data, err := mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
resp, _ := data.(BinaryConvResponse)
|
|
return resp.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartConv-Binary-with-ConvFunc-error": {
|
|
expectedError: ErrConv,
|
|
conversationHandler: BinaryConversationFunc(func(ptr BinaryPointer) ([]byte, error) {
|
|
return nil, errors.New("got an error")
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, NewBinaryConvRequestFromBytes([]byte{}))
|
|
},
|
|
},
|
|
"StartConv-String-with-ConvBinaryFunc": {
|
|
expectedError: ErrConv,
|
|
conversationHandler: BinaryConversationFunc(func(ptr BinaryPointer) ([]byte, error) {
|
|
return nil, nil
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, NewStringConvRequest(TextInfo, "prompt"))
|
|
},
|
|
},
|
|
"StartConv-Binary-with-PointerConvFunc": {
|
|
expectedValue: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x95},
|
|
conversationHandler: BinaryPointerConversationFunc(func(ptr BinaryPointer) (BinaryPointer, error) {
|
|
bytes, _ := testBinaryDataDecoder(ptr)
|
|
expectedBinary := []byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is! From bytes pointer.")
|
|
if !reflect.DeepEqual(bytes, expectedBinary) {
|
|
return nil,
|
|
fmt.Errorf("%w: data mismatch %#v vs %#v", ErrConv, bytes, expectedBinary)
|
|
}
|
|
return allocateCBytes(testBinaryDataEncoder([]byte{
|
|
0x01, 0x02, 0x03, 0x05, 0x00, 0x95})), nil
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is! From bytes pointer."))
|
|
data, err := mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
resp, _ := data.(BinaryConvResponse)
|
|
return resp.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartConv-Binary-with-PointerConvFunc-and-allocated-data": {
|
|
expectedValue: []byte{0x01, 0x02, 0x03, 0x05, 0x00, 0x95},
|
|
conversationHandler: BinaryPointerConversationFunc(func(ptr BinaryPointer) (BinaryPointer, error) {
|
|
bytes, _ := testBinaryDataDecoder(ptr)
|
|
expectedBinary := []byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is! From pointer...")
|
|
if !reflect.DeepEqual(bytes, expectedBinary) {
|
|
return nil,
|
|
fmt.Errorf("%w: data mismatch %#v vs %#v", ErrConv, bytes, expectedBinary)
|
|
}
|
|
return allocateCBytes(testBinaryDataEncoder([]byte{
|
|
0x01, 0x02, 0x03, 0x05, 0x00, 0x95})), nil
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is! From pointer..."))
|
|
data, err := mt.startConvImpl(mock,
|
|
NewBinaryConvRequest(allocateCBytes(bytes), binaryPointerCBytesFinalizer))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
resp, _ := data.(BinaryConvResponse)
|
|
return resp.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartConv-Binary-with-PointerConvFunc-and-allocated-data-erroring": {
|
|
expectedValue: nil,
|
|
expectedError: ErrConv,
|
|
conversationHandler: BinaryPointerConversationFunc(func(ptr BinaryPointer) (BinaryPointer, error) {
|
|
bytes, _ := testBinaryDataDecoder(ptr)
|
|
expectedBinary := []byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is! From pointer...")
|
|
if !reflect.DeepEqual(bytes, expectedBinary) {
|
|
return nil,
|
|
fmt.Errorf("%w: data mismatch %#v vs %#v", ErrConv, bytes, expectedBinary)
|
|
}
|
|
return allocateCBytes(testBinaryDataEncoder([]byte{
|
|
0x01, 0x02, 0x03, 0x05, 0x00, 0x95})), ErrConv
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a binary data request\xC5\x00\xffYes it is! From pointer..."))
|
|
data, err := mt.startConvImpl(mock,
|
|
NewBinaryConvRequest(allocateCBytes(bytes), binaryPointerCBytesFinalizer))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
resp, _ := data.(BinaryConvResponse)
|
|
return resp.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartConv-Binary-with-PointerConvFunc-empty": {
|
|
expectedValue: []byte{},
|
|
conversationHandler: BinaryPointerConversationFunc(func(ptr BinaryPointer) (BinaryPointer, error) {
|
|
bytes, _ := testBinaryDataDecoder(ptr)
|
|
expectedBinary := []byte(
|
|
"\x00This is an empty binary data request\xC5\x00\xffYes it is!")
|
|
if !reflect.DeepEqual(bytes, expectedBinary) {
|
|
return nil,
|
|
fmt.Errorf("%w: data mismatch %#v vs %#v", ErrConv, bytes, expectedBinary)
|
|
}
|
|
return allocateCBytes(testBinaryDataEncoder([]byte{})), nil
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is an empty binary data request\xC5\x00\xffYes it is!"))
|
|
data, err := mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
resp, _ := data.(BinaryConvResponse)
|
|
return resp.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartConv-Binary-with-PointerConvFunc-nil": {
|
|
expectedValue: []byte(nil),
|
|
conversationHandler: BinaryPointerConversationFunc(func(ptr BinaryPointer) (BinaryPointer, error) {
|
|
bytes, _ := testBinaryDataDecoder(ptr)
|
|
expectedBinary := []byte(
|
|
"\x00This is a nil binary data request\xC5\x00\xffYes it is!")
|
|
if !reflect.DeepEqual(bytes, expectedBinary) {
|
|
return nil,
|
|
fmt.Errorf("%w: data mismatch %#v vs %#v", ErrConv, bytes, expectedBinary)
|
|
}
|
|
return nil, nil
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
bytes := testBinaryDataEncoder([]byte(
|
|
"\x00This is a nil binary data request\xC5\x00\xffYes it is!"))
|
|
data, err := mt.startConvImpl(mock, NewBinaryConvRequestFromBytes(bytes))
|
|
if err != nil {
|
|
return data, err
|
|
}
|
|
resp, _ := data.(BinaryConvResponse)
|
|
return resp.Decode(testBinaryDataDecoder)
|
|
},
|
|
},
|
|
"StartConv-Binary-with-PointerConvFunc-error": {
|
|
expectedError: ErrConv,
|
|
conversationHandler: BinaryPointerConversationFunc(func(ptr BinaryPointer) (BinaryPointer, error) {
|
|
return nil, errors.New("got an error")
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, NewBinaryConvRequestFromBytes([]byte{}))
|
|
},
|
|
},
|
|
"StartConv-String-with-ConvPointerBinaryFunc": {
|
|
expectedError: ErrConv,
|
|
conversationHandler: BinaryPointerConversationFunc(func(ptr BinaryPointer) (BinaryPointer, error) {
|
|
return nil, nil
|
|
}),
|
|
testFunc: func(mock *mockModuleTransaction) (any, error) {
|
|
return mt.startConvImpl(mock, NewStringConvRequest(TextInfo, "prompt"))
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, tc := range tests {
|
|
tc := tc
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
t.Cleanup(maybeDoLeakCheck)
|
|
mock := newMockModuleTransaction(&mockModuleTransaction{T: t,
|
|
Expectations: tc.mockExpectations, RetData: tc.mockRetData,
|
|
ConversationHandler: tc.conversationHandler})
|
|
data, err := tc.testFunc(mock)
|
|
|
|
if !tc.ignoreError && !errors.Is(err, tc.expectedError) {
|
|
t.Fatalf("unexpected err: %#v vs %#v", err, tc.expectedError)
|
|
}
|
|
|
|
if !reflect.DeepEqual(data, tc.expectedValue) {
|
|
t.Fatalf("data mismatch, %#v vs %#v", data, tc.expectedValue)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_MockModuleTransaction(t *testing.T) {
|
|
mt, _ := NewModuleTransactionInvoker(nil).(*moduleTransaction)
|
|
testMockModuleTransaction(t, mt)
|
|
}
|
|
|
|
func Test_MockModuleTransactionParallelConv(t *testing.T) {
|
|
mt, _ := NewModuleTransactionInvokerParallelConv(nil).(*moduleTransaction)
|
|
testMockModuleTransaction(t, mt)
|
|
}
|