package commonclient import ( "context" "fmt" "testing" "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/vmstate" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) type mockWaiter struct { mock.Mock } func (w *mockWaiter) successfulResult(txHash util.Uint256) *state.AppExecResult { return &state.AppExecResult{ Container: txHash, Execution: state.Execution{ Trigger: trigger.Application, VMState: vmstate.Halt, GasConsumed: 100500, Stack: nil, Events: nil, FaultException: "", }, } } func (w *mockWaiter) failedResult(txHash util.Uint256, exception string) *state.AppExecResult { return &state.AppExecResult{ Container: txHash, Execution: state.Execution{ Trigger: trigger.Application, VMState: vmstate.Fault, GasConsumed: 100500, Stack: nil, Events: nil, FaultException: exception, }, } } func (m *mockWaiter) Wait(h util.Uint256, vub uint32, err error) (*state.AppExecResult, error) { args := m.Called(h, vub, err) result := args.Get(0) if result == nil { return nil, args.Error(1) } return result.(*state.AppExecResult), args.Error(1) } func (m *mockWaiter) WaitAny(ctx context.Context, vub uint32, hashes ...util.Uint256) (*state.AppExecResult, error) { args := m.Called(ctx, vub, hashes) result := args.Get(0) if result == nil { return nil, args.Error(1) } return result.(*state.AppExecResult), args.Error(1) } func TestWaiter(t *testing.T) { txHash := util.Uint256{} vub := uint32(100) t.Run("ignore already exists error", func(t *testing.T) { sendErr := fmt.Errorf("transaction already exists") mw := &mockWaiter{} mw.On("Wait", txHash, vub, mock.Anything).Return(mw.successfulResult(txHash), nil) waiter := NewWaiter(mw, WaiterOptions{IgnoreAlreadyExistsError: true}) _, err := waiter.Wait(txHash, vub, sendErr) require.NoError(t, err) }) t.Run("report already exists error", func(t *testing.T) { sendErr := fmt.Errorf("transaction already exists") mw := &mockWaiter{} mw.On("Wait", txHash, vub, mock.Anything).Return(mw.successfulResult(txHash), nil) waiter := NewWaiter(mw, WaiterOptions{IgnoreAlreadyExistsError: false}) _, err := waiter.Wait(txHash, vub, sendErr) require.Error(t, err) }) t.Run("report wait error when transaction error is ignored", func(t *testing.T) { waitErr := fmt.Errorf("mock error") mw := &mockWaiter{} mw.On("Wait", txHash, vub, nil).Return(nil, waitErr) waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: false}) _, err := waiter.Wait(txHash, vub, nil) require.ErrorIs(t, err, waitErr) }) t.Run("report wait error when transaction error is verified", func(t *testing.T) { waitErr := fmt.Errorf("mock error") mw := &mockWaiter{} mw.On("Wait", txHash, vub, nil).Return(nil, waitErr) waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: true}) _, err := waiter.Wait(txHash, vub, nil) require.ErrorIs(t, err, waitErr) }) t.Run("ignore error from transaction", func(t *testing.T) { txError := "mock error" mw := &mockWaiter{} mw.On("Wait", txHash, vub, nil).Return(mw.failedResult(txHash, txError), nil) waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: false}) _, err := waiter.Wait(txHash, vub, nil) require.NoError(t, err) }) t.Run("examine error from transaction", func(t *testing.T) { txError := "mock error" mw := &mockWaiter{} mw.On("Wait", txHash, vub, nil).Return(mw.failedResult(txHash, txError), nil) waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: true}) _, err := waiter.Wait(txHash, vub, nil) require.ErrorContains(t, err, txError) }) }