github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/protocol/introduce/states_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package introduce
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"testing"
    13  
    14  	"github.com/golang/mock/gomock"
    15  	"github.com/google/uuid"
    16  	"github.com/stretchr/testify/require"
    17  
    18  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
    19  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
    20  	serviceMocks "github.com/hyperledger/aries-framework-go/pkg/internal/gomocks/didcomm/common/service"
    21  )
    22  
    23  func notTransition(t *testing.T, st state) {
    24  	t.Helper()
    25  
    26  	allState := [...]state{
    27  		&noOp{}, &start{}, &done{},
    28  		&arranging{}, &delivering{},
    29  		&confirming{}, &abandoning{},
    30  		&deciding{}, &waiting{}, &requesting{},
    31  	}
    32  
    33  	for _, s := range allState {
    34  		require.False(t, st.CanTransitionTo(s))
    35  	}
    36  }
    37  
    38  func TestNoOp_CanTransitionTo(t *testing.T) {
    39  	noop := &noOp{}
    40  	require.Equal(t, stateNameNoop, noop.Name())
    41  	notTransition(t, noop)
    42  }
    43  
    44  func TestNoOp_ExecuteInbound(t *testing.T) {
    45  	followup, _, err := (&noOp{}).ExecuteInbound(nil, &metaData{})
    46  	require.Error(t, err)
    47  	require.Nil(t, followup)
    48  }
    49  
    50  func TestNoOp_saveMetadata(t *testing.T) {
    51  	require.NoError(t, (&Service{}).saveMetadata(nil, ""))
    52  }
    53  
    54  func TestNoOp_ExecuteOutbound(t *testing.T) {
    55  	followup, _, err := (&noOp{}).ExecuteOutbound(nil, &metaData{})
    56  	require.Error(t, err)
    57  	require.Nil(t, followup)
    58  }
    59  
    60  func TestStart_CanTransitionTo(t *testing.T) {
    61  	st := &start{}
    62  	require.Equal(t, stateNameStart, st.Name())
    63  
    64  	require.True(t, st.CanTransitionTo(&arranging{}))
    65  	require.True(t, st.CanTransitionTo(&deciding{}))
    66  	require.True(t, st.CanTransitionTo(&requesting{}))
    67  	require.True(t, st.CanTransitionTo(&abandoning{}))
    68  
    69  	require.False(t, st.CanTransitionTo(&delivering{}))
    70  	require.False(t, st.CanTransitionTo(&noOp{}))
    71  	require.False(t, st.CanTransitionTo(&start{}))
    72  	require.False(t, st.CanTransitionTo(&done{}))
    73  	require.False(t, st.CanTransitionTo(&confirming{}))
    74  	require.False(t, st.CanTransitionTo(&waiting{}))
    75  }
    76  
    77  func TestStart_ExecuteInbound(t *testing.T) {
    78  	followup, _, err := (&start{}).ExecuteInbound(nil, &metaData{})
    79  	require.EqualError(t, err, "start: ExecuteInbound function is not supposed to be used")
    80  	require.Nil(t, followup)
    81  }
    82  
    83  func TestStart_ExecuteOutbound(t *testing.T) {
    84  	followup, _, err := (&start{}).ExecuteOutbound(nil, &metaData{})
    85  	require.EqualError(t, err, "start: ExecuteOutbound function is not supposed to be used")
    86  	require.Nil(t, followup)
    87  }
    88  
    89  func TestDone_CanTransitionTo(t *testing.T) {
    90  	st := &done{}
    91  	require.Equal(t, stateNameDone, st.Name())
    92  	notTransition(t, st)
    93  }
    94  
    95  func TestDone_ExecuteInbound(t *testing.T) {
    96  	followup, _, err := (&done{}).ExecuteInbound(nil, &metaData{})
    97  	require.NoError(t, err)
    98  	require.Equal(t, &noOp{}, followup)
    99  }
   100  
   101  func TestDone_ExecuteOutbound(t *testing.T) {
   102  	followup, _, err := (&done{}).ExecuteOutbound(nil, &metaData{})
   103  	require.Error(t, err)
   104  	require.Nil(t, followup)
   105  }
   106  
   107  func TestArranging_CanTransitionTo(t *testing.T) {
   108  	st := &arranging{}
   109  	require.Equal(t, stateNameArranging, st.Name())
   110  
   111  	require.True(t, st.CanTransitionTo(&arranging{}))
   112  	require.True(t, st.CanTransitionTo(&abandoning{}))
   113  	require.True(t, st.CanTransitionTo(&done{}))
   114  	require.True(t, st.CanTransitionTo(&delivering{}))
   115  
   116  	require.False(t, st.CanTransitionTo(&noOp{}))
   117  	require.False(t, st.CanTransitionTo(&start{}))
   118  	require.False(t, st.CanTransitionTo(&confirming{}))
   119  	require.False(t, st.CanTransitionTo(&deciding{}))
   120  	require.False(t, st.CanTransitionTo(&waiting{}))
   121  	require.False(t, st.CanTransitionTo(&requesting{}))
   122  }
   123  
   124  func TestArranging_ExecuteOutbound(t *testing.T) {
   125  	const errMsg = "test error"
   126  
   127  	ctrl := gomock.NewController(t)
   128  	defer ctrl.Finish()
   129  
   130  	messenger := serviceMocks.NewMockMessenger(ctrl)
   131  	messenger.EXPECT().Send(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
   132  	messenger.EXPECT().Send(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New(errMsg))
   133  
   134  	followup, action, err := (&arranging{}).ExecuteOutbound(messenger, &metaData{
   135  		transitionalPayload: transitionalPayload{Action: Action{Msg: service.NewDIDCommMsgMap(struct{}{})}},
   136  		saveMetadata:        func(_ service.DIDCommMsgMap, _ string) error { return nil },
   137  	})
   138  	require.NoError(t, err)
   139  	require.NoError(t, action())
   140  	require.Equal(t, &noOp{}, followup)
   141  
   142  	// Send an error
   143  	followup, action, err = (&arranging{}).ExecuteOutbound(messenger, &metaData{
   144  		transitionalPayload: transitionalPayload{Action: Action{Msg: service.NewDIDCommMsgMap(struct{}{})}},
   145  		saveMetadata:        func(_ service.DIDCommMsgMap, _ string) error { return nil },
   146  	})
   147  	require.NoError(t, err)
   148  	require.Contains(t, fmt.Sprintf("%v", action()), errMsg)
   149  	require.Equal(t, &noOp{}, followup)
   150  
   151  	followup, action, err = (&arranging{}).ExecuteOutbound(messenger, &metaData{
   152  		transitionalPayload: transitionalPayload{Action: Action{Msg: service.NewDIDCommMsgMap(struct{}{})}},
   153  		saveMetadata:        func(_ service.DIDCommMsgMap, _ string) error { return errors.New(errMsg) },
   154  	})
   155  	require.NoError(t, err)
   156  	require.Contains(t, fmt.Sprintf("%v", action()), errMsg)
   157  	require.Equal(t, &noOp{}, followup)
   158  
   159  	followup, action, err = (&arranging{}).ExecuteOutbound(messenger, &metaData{
   160  		saveMetadata:        func(msg service.DIDCommMsgMap, thID string) error { return errors.New("test error") },
   161  		transitionalPayload: transitionalPayload{Action: Action{Msg: service.DIDCommMsgMap{}}},
   162  	})
   163  	require.NoError(t, err)
   164  	require.Contains(t, fmt.Sprintf("%v", action()), "test error")
   165  	require.Equal(t, &noOp{}, followup)
   166  }
   167  
   168  func TestDelivering_CanTransitionTo(t *testing.T) {
   169  	st := &delivering{}
   170  	require.Equal(t, stateNameDelivering, st.Name())
   171  
   172  	require.True(t, st.CanTransitionTo(&confirming{}))
   173  	require.True(t, st.CanTransitionTo(&abandoning{}))
   174  	require.True(t, st.CanTransitionTo(&done{}))
   175  
   176  	require.False(t, st.CanTransitionTo(&noOp{}))
   177  	require.False(t, st.CanTransitionTo(&start{}))
   178  	require.False(t, st.CanTransitionTo(&delivering{}))
   179  	require.False(t, st.CanTransitionTo(&arranging{}))
   180  	require.False(t, st.CanTransitionTo(&deciding{}))
   181  	require.False(t, st.CanTransitionTo(&waiting{}))
   182  	require.False(t, st.CanTransitionTo(&requesting{}))
   183  }
   184  
   185  func TestDelivering_ExecuteOutbound(t *testing.T) {
   186  	followup, _, err := (&delivering{}).ExecuteOutbound(nil, &metaData{})
   187  	require.Error(t, err)
   188  	require.Nil(t, followup)
   189  }
   190  
   191  func TestConfirming_CanTransitionTo(t *testing.T) {
   192  	st := &confirming{}
   193  	require.Equal(t, stateNameConfirming, st.Name())
   194  
   195  	require.True(t, st.CanTransitionTo(&abandoning{}))
   196  	require.True(t, st.CanTransitionTo(&done{}))
   197  
   198  	require.False(t, st.CanTransitionTo(&noOp{}))
   199  	require.False(t, st.CanTransitionTo(&start{}))
   200  	require.False(t, st.CanTransitionTo(&delivering{}))
   201  	require.False(t, st.CanTransitionTo(&arranging{}))
   202  	require.False(t, st.CanTransitionTo(&confirming{}))
   203  	require.False(t, st.CanTransitionTo(&deciding{}))
   204  	require.False(t, st.CanTransitionTo(&waiting{}))
   205  	require.False(t, st.CanTransitionTo(&requesting{}))
   206  }
   207  
   208  func TestConfirming_ExecuteOutbound(t *testing.T) {
   209  	followup, _, err := (&confirming{}).ExecuteOutbound(nil, &metaData{})
   210  	require.Error(t, err)
   211  	require.Nil(t, followup)
   212  }
   213  
   214  func TestAbandoning_CanTransitionTo(t *testing.T) {
   215  	st := &abandoning{}
   216  	require.Equal(t, stateNameAbandoning, st.Name())
   217  
   218  	require.True(t, st.CanTransitionTo(&done{}))
   219  
   220  	require.False(t, st.CanTransitionTo(&noOp{}))
   221  	require.False(t, st.CanTransitionTo(&start{}))
   222  	require.False(t, st.CanTransitionTo(&delivering{}))
   223  	require.False(t, st.CanTransitionTo(&arranging{}))
   224  	require.False(t, st.CanTransitionTo(&confirming{}))
   225  	require.False(t, st.CanTransitionTo(&deciding{}))
   226  	require.False(t, st.CanTransitionTo(&abandoning{}))
   227  	require.False(t, st.CanTransitionTo(&waiting{}))
   228  	require.False(t, st.CanTransitionTo(&requesting{}))
   229  }
   230  
   231  func TestAbandoning_ExecuteOutbound(t *testing.T) {
   232  	followup, _, err := (&abandoning{}).ExecuteOutbound(nil, &metaData{})
   233  	require.Error(t, err)
   234  	require.Nil(t, followup)
   235  }
   236  
   237  func TestDeciding_CanTransitionTo(t *testing.T) {
   238  	st := &deciding{}
   239  	require.Equal(t, stateNameDeciding, st.Name())
   240  
   241  	require.True(t, st.CanTransitionTo(&waiting{}))
   242  	require.True(t, st.CanTransitionTo(&done{}))
   243  	require.True(t, st.CanTransitionTo(&abandoning{}))
   244  
   245  	require.False(t, st.CanTransitionTo(&noOp{}))
   246  	require.False(t, st.CanTransitionTo(&start{}))
   247  	require.False(t, st.CanTransitionTo(&delivering{}))
   248  	require.False(t, st.CanTransitionTo(&arranging{}))
   249  	require.False(t, st.CanTransitionTo(&confirming{}))
   250  	require.False(t, st.CanTransitionTo(&deciding{}))
   251  	require.False(t, st.CanTransitionTo(&requesting{}))
   252  }
   253  
   254  func TestDeciding_ExecuteInbound(t *testing.T) {
   255  	ctrl := gomock.NewController(t)
   256  	defer ctrl.Finish()
   257  
   258  	t.Run("handles inbound message", func(t *testing.T) {
   259  		messenger := serviceMocks.NewMockMessenger(ctrl)
   260  		messenger.EXPECT().ReplyToMsg(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
   261  
   262  		followup, action, err := (&deciding{}).ExecuteInbound(messenger, &metaData{
   263  			transitionalPayload: transitionalPayload{Action: Action{Msg: service.NewDIDCommMsgMap(struct{}{})}},
   264  		})
   265  
   266  		require.NoError(t, err)
   267  		require.NoError(t, action())
   268  		require.Equal(t, &waiting{}, followup)
   269  	})
   270  
   271  	t.Run("adds attachment", func(t *testing.T) {
   272  		expected := &decorator.Attachment{
   273  			ID: uuid.New().String(),
   274  		}
   275  		messenger := serviceMocks.NewMockMessenger(ctrl)
   276  		messenger.EXPECT().ReplyToMsg(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
   277  			func(_, msg service.DIDCommMsgMap, _, _ string) error {
   278  				result := &Response{}
   279  				err := msg.Decode(result)
   280  				require.NoError(t, err)
   281  				require.Len(t, result.Attachments, 1)
   282  				require.Equal(t, expected, result.Attachments[0])
   283  				return nil
   284  			},
   285  		).Times(1)
   286  		msg := service.NewDIDCommMsgMap(struct{}{})
   287  		msg.Metadata()[metaAttachment] = []*decorator.Attachment{expected}
   288  		_, action, err := (&deciding{}).ExecuteInbound(messenger, &metaData{
   289  			transitionalPayload: transitionalPayload{Action: Action{Msg: msg}},
   290  		})
   291  		require.NoError(t, err)
   292  		err = action()
   293  		require.NoError(t, err)
   294  	})
   295  
   296  	t.Run("fails if attachments used improperly", func(t *testing.T) {
   297  		messenger := serviceMocks.NewMockMessenger(ctrl)
   298  		messenger.EXPECT().ReplyToMsg(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).MaxTimes(0)
   299  		msg := service.NewDIDCommMsgMap(struct{}{})
   300  		msg.Metadata()[metaAttachment] = []struct{}{}
   301  		_, action, err := (&deciding{}).ExecuteInbound(messenger, &metaData{
   302  			transitionalPayload: transitionalPayload{Action: Action{Msg: msg}},
   303  		})
   304  		require.NoError(t, err)
   305  		err = action()
   306  		require.Error(t, err)
   307  	})
   308  }
   309  
   310  func TestDeciding_ExecuteOutbound(t *testing.T) {
   311  	followup, _, err := (&deciding{}).ExecuteOutbound(nil, &metaData{})
   312  	require.Error(t, err)
   313  	require.Nil(t, followup)
   314  }
   315  
   316  func TestWaiting_CanTransitionTo(t *testing.T) {
   317  	st := &waiting{}
   318  	require.Equal(t, stateNameWaiting, st.Name())
   319  
   320  	require.True(t, st.CanTransitionTo(&done{}))
   321  	require.True(t, st.CanTransitionTo(&abandoning{}))
   322  
   323  	require.False(t, st.CanTransitionTo(&noOp{}))
   324  	require.False(t, st.CanTransitionTo(&start{}))
   325  	require.False(t, st.CanTransitionTo(&delivering{}))
   326  	require.False(t, st.CanTransitionTo(&arranging{}))
   327  	require.False(t, st.CanTransitionTo(&confirming{}))
   328  	require.False(t, st.CanTransitionTo(&deciding{}))
   329  	require.False(t, st.CanTransitionTo(&waiting{}))
   330  	require.False(t, st.CanTransitionTo(&requesting{}))
   331  }
   332  
   333  func TestWaiting_ExecuteInbound(t *testing.T) {
   334  	followup, _, err := (&waiting{}).ExecuteInbound(nil, &metaData{})
   335  	require.NoError(t, err)
   336  	require.Equal(t, &noOp{}, followup)
   337  }
   338  
   339  func TestWaiting_ExecuteOutbound(t *testing.T) {
   340  	followup, _, err := (&waiting{}).ExecuteOutbound(nil, &metaData{})
   341  	require.Error(t, err)
   342  	require.Nil(t, followup)
   343  }
   344  
   345  func TestRequesting_CanTransitionTo(t *testing.T) {
   346  	st := &requesting{}
   347  	require.Equal(t, stateNameRequesting, st.Name())
   348  
   349  	require.True(t, st.CanTransitionTo(&deciding{}))
   350  	require.True(t, st.CanTransitionTo(&done{}))
   351  	require.True(t, st.CanTransitionTo(&abandoning{}))
   352  
   353  	require.False(t, st.CanTransitionTo(&noOp{}))
   354  	require.False(t, st.CanTransitionTo(&start{}))
   355  	require.False(t, st.CanTransitionTo(&delivering{}))
   356  	require.False(t, st.CanTransitionTo(&arranging{}))
   357  	require.False(t, st.CanTransitionTo(&confirming{}))
   358  	require.False(t, st.CanTransitionTo(&waiting{}))
   359  	require.False(t, st.CanTransitionTo(&requesting{}))
   360  }
   361  
   362  func TestRequesting_ExecuteInbound(t *testing.T) {
   363  	followup, _, err := (&requesting{}).ExecuteInbound(nil, &metaData{})
   364  	require.Error(t, err)
   365  	require.Nil(t, followup)
   366  }
   367  
   368  func Test_stateFromName(t *testing.T) {
   369  	st := stateFromName(stateNameNoop)
   370  	require.Equal(t, &noOp{}, st)
   371  
   372  	st = stateFromName(stateNameStart)
   373  	require.Equal(t, &start{}, st)
   374  
   375  	st = stateFromName(stateNameDone)
   376  	require.Equal(t, &done{}, st)
   377  
   378  	st = stateFromName(stateNameArranging)
   379  	require.Equal(t, &arranging{}, st)
   380  
   381  	st = stateFromName(stateNameDelivering)
   382  	require.Equal(t, &delivering{}, st)
   383  
   384  	st = stateFromName(stateNameConfirming)
   385  	require.Equal(t, &confirming{}, st)
   386  
   387  	st = stateFromName(stateNameAbandoning)
   388  	require.Equal(t, &abandoning{}, st)
   389  
   390  	st = stateFromName(stateNameDeciding)
   391  	require.Equal(t, &deciding{}, st)
   392  
   393  	st = stateFromName(stateNameWaiting)
   394  	require.Equal(t, &waiting{}, st)
   395  
   396  	st = stateFromName(stateNameRequesting)
   397  	require.Equal(t, &requesting{}, st)
   398  
   399  	st = stateFromName("unknown")
   400  	require.Equal(t, &noOp{}, st)
   401  }
   402  
   403  func Test_sendProposals(t *testing.T) {
   404  	const errMsg = "test error"
   405  
   406  	ctrl := gomock.NewController(t)
   407  	defer ctrl.Finish()
   408  
   409  	messenger := serviceMocks.NewMockMessenger(ctrl)
   410  	messenger.EXPECT().ReplyToMsg(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New(errMsg))
   411  
   412  	msg := service.NewDIDCommMsgMap(struct{}{})
   413  	msg.SetID(uuid.New().String())
   414  
   415  	msg.Metadata()[metaRecipients] = map[string]int{}
   416  
   417  	require.NoError(t, sendProposals(messenger, &metaData{
   418  		transitionalPayload: transitionalPayload{Action: Action{Msg: msg}},
   419  	}))
   420  
   421  	msg.Metadata()[metaRecipients] = []interface{}{&Recipient{}}
   422  	require.Contains(t, fmt.Sprintf("%v", sendProposals(messenger, &metaData{
   423  		transitionalPayload: transitionalPayload{Action: Action{Msg: msg}},
   424  		saveMetadata:        func(_ service.DIDCommMsgMap, _ string) error { return nil },
   425  	})), errMsg)
   426  
   427  	require.Contains(t, fmt.Sprintf("%v", sendProposals(messenger, &metaData{
   428  		transitionalPayload: transitionalPayload{Action: Action{Msg: msg}},
   429  		saveMetadata:        func(_ service.DIDCommMsgMap, _ string) error { return errors.New(errMsg) },
   430  	})), errMsg)
   431  
   432  	msg = service.NewDIDCommMsgMap(struct{}{})
   433  	msg.Metadata()[metaRecipients] = []interface{}{&Recipient{}}
   434  	require.EqualError(t, sendProposals(messenger, &metaData{
   435  		transitionalPayload: transitionalPayload{Action: Action{Msg: msg}},
   436  	}), "get threadID: threadID not found")
   437  
   438  	msg = service.NewDIDCommMsgMap(struct{}{})
   439  	msg.Metadata()[metaRecipients] = []interface{}{&Recipient{MyDID: "my_did"}}
   440  	require.EqualError(t, sendProposals(messenger, &metaData{
   441  		transitionalPayload: transitionalPayload{Action: Action{Msg: msg}},
   442  		saveMetadata:        func(_ service.DIDCommMsgMap, _ string) error { return errors.New(errMsg) },
   443  	}), "save metadata: test error")
   444  }