github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/messaging/service/http/httpmsgsvc_test.go (about)

     1  /*
     2   *
     3   * Copyright SecureKey Technologies Inc. All Rights Reserved.
     4   *
     5   * SPDX-License-Identifier: Apache-2.0
     6   * /
     7   *
     8   */
     9  
    10  package http
    11  
    12  import (
    13  	"encoding/json"
    14  	"fmt"
    15  	"net/http"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/stretchr/testify/require"
    20  
    21  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
    22  )
    23  
    24  func TestNewOverDIDComm(t *testing.T) {
    25  	tests := []struct {
    26  		name    string
    27  		svcName string
    28  		purpose []string
    29  		handle  RequestHandle
    30  		failure string
    31  	}{
    32  		{
    33  			"Successfully create new HTTP Over DIDComm service with all args",
    34  			"sample-name-01",
    35  			[]string{"prp-01", "prp-02"},
    36  			newMockHandle(), "",
    37  		},
    38  		{
    39  			"Successfully create new HTTP Over DIDComm service without purpose",
    40  			"sample-name-01", nil, newMockHandle(), "",
    41  		},
    42  		{
    43  			"Failed to create new HTTP Over DIDComm service without name",
    44  			"",
    45  			[]string{"prp-01", "prp-02"},
    46  			newMockHandle(), errNameAndHandleMandatory,
    47  		},
    48  		{
    49  			"Failed to create new HTTP Over DIDComm service without handle",
    50  			"sample-name-01",
    51  			[]string{"prp-01", "prp-02"},
    52  			nil, errNameAndHandleMandatory,
    53  		},
    54  	}
    55  
    56  	t.Parallel()
    57  
    58  	for _, test := range tests {
    59  		tc := test
    60  		t.Run(tc.name, func(t *testing.T) {
    61  			svc, err := NewOverDIDComm(tc.svcName, tc.handle, tc.purpose...)
    62  			if tc.failure != "" {
    63  				require.Error(t, err)
    64  				require.Nil(t, svc)
    65  				require.Contains(t, err.Error(), tc.failure)
    66  				return
    67  			}
    68  			require.NoError(t, err)
    69  			require.NotNil(t, svc)
    70  		})
    71  	}
    72  }
    73  
    74  func TestOverDIDComm_Name(t *testing.T) {
    75  	const sampleName = "sample-name-01"
    76  
    77  	svc, err := NewOverDIDComm("sample-name-01", newMockHandle(), "prp-01", "prp-02")
    78  	require.NoError(t, err)
    79  	require.NotNil(t, svc)
    80  	require.Equal(t, sampleName, svc.Name())
    81  }
    82  
    83  func TestOverDIDComm_Accept(t *testing.T) {
    84  	tests := []struct {
    85  		name      string
    86  		svcName   string
    87  		purpose   []string
    88  		testdatas []struct {
    89  			msgType string
    90  			purpose []string
    91  			result  bool
    92  		}
    93  	}{
    94  		{
    95  			"Test acceptance criteria with purpose",
    96  			"sample-name-01",
    97  			[]string{"foo", "bar"},
    98  			[]struct {
    99  				msgType string
   100  				purpose []string
   101  				result  bool
   102  			}{
   103  				{
   104  					"sample-msgtype-01", []string{"baz"}, false,
   105  				},
   106  				{
   107  					"sample-msgtype-01", []string{""}, false,
   108  				},
   109  				{
   110  					"sample-msgtype-01", nil, false,
   111  				},
   112  				{
   113  					"sample-msgtype-01", []string{"foo"}, false,
   114  				},
   115  				{
   116  					"sample-msgtype-01", []string{"bar"}, false,
   117  				},
   118  				{
   119  					"sample-msgtype-01", []string{"foo", "bar"}, false,
   120  				},
   121  				{
   122  					OverDIDCommMsgRequestType, []string{"bla"}, false,
   123  				},
   124  				{
   125  					OverDIDCommMsgRequestType, []string{}, false,
   126  				},
   127  				{
   128  					OverDIDCommMsgRequestType, nil, false,
   129  				},
   130  				{
   131  					OverDIDCommMsgRequestType, []string{"foo"}, true,
   132  				},
   133  				{
   134  					OverDIDCommMsgRequestType, []string{"bar"}, true,
   135  				},
   136  				{
   137  					OverDIDCommMsgRequestType, []string{"foo", "bar"}, true,
   138  				},
   139  			},
   140  		},
   141  		{
   142  			"Test acceptance criteria without purpose",
   143  			"sample-name-01", nil,
   144  			[]struct {
   145  				msgType string
   146  				purpose []string
   147  				result  bool
   148  			}{
   149  				{
   150  					"sample-msgtype-01", []string{"baz"}, false,
   151  				},
   152  				{
   153  					"sample-msgtype-01", []string{""}, false,
   154  				},
   155  				{
   156  					"sample-msgtype-01", nil, false,
   157  				},
   158  				{
   159  					"sample-msgtype-01", []string{"foo"}, false,
   160  				},
   161  				{
   162  					"sample-msgtype-01", []string{"bar"}, false,
   163  				},
   164  				{
   165  					"sample-msgtype-01", []string{"foo", "bar"}, false,
   166  				},
   167  				{
   168  					OverDIDCommMsgRequestType, []string{"bla"}, true,
   169  				},
   170  				{
   171  					OverDIDCommMsgRequestType, []string{}, true,
   172  				},
   173  				{
   174  					OverDIDCommMsgRequestType, nil, true,
   175  				},
   176  				{
   177  					OverDIDCommMsgRequestType, []string{"foo"}, true,
   178  				},
   179  				{
   180  					OverDIDCommMsgRequestType, []string{"bar"}, true,
   181  				},
   182  				{
   183  					OverDIDCommMsgRequestType, []string{"foo", "bar"}, true,
   184  				},
   185  			},
   186  		},
   187  	}
   188  
   189  	t.Parallel()
   190  
   191  	for _, test := range tests {
   192  		tc := test
   193  		t.Run(tc.name, func(t *testing.T) {
   194  			svc, err := NewOverDIDComm(tc.svcName, newMockHandle(), tc.purpose...)
   195  			require.NoError(t, err)
   196  			require.NotNil(t, svc)
   197  			for _, testdata := range tc.testdatas {
   198  				require.Equal(t, testdata.result, svc.Accept(testdata.msgType, testdata.purpose),
   199  					"testdata: %v", testdata)
   200  			}
   201  		})
   202  	}
   203  }
   204  
   205  func TestOverDIDComm_HandleInbound(t *testing.T) {
   206  	tests := []struct {
   207  		name     string
   208  		jsonStr  string
   209  		expected struct {
   210  			method      string
   211  			resourceURI string
   212  			body        string
   213  			version     string
   214  			header      []struct {
   215  				key   string
   216  				value string
   217  			}
   218  			failure string
   219  		}
   220  	}{
   221  		{
   222  			name:    "Testing request handle with empty didcomm msg",
   223  			jsonStr: `{"@id":"sample-id", "@type":"https://didcomm.org/http-over-didcomm/1.0/request"}`,
   224  			expected: struct {
   225  				method      string
   226  				resourceURI string
   227  				body        string
   228  				version     string
   229  				header      []struct {
   230  					key   string
   231  					value string
   232  				}
   233  				failure string
   234  			}{
   235  				http.MethodGet, "", "", "HTTP/1.1", nil, "",
   236  			},
   237  		},
   238  		{
   239  			name: "Testing request handle with valid didcomm msg",
   240  			jsonStr: `{"@id":"sample-id", "@type":"https://didcomm.org/http-over-didcomm/1.0/request",
   241  "method":"POST", "resource-uri":"/sample-resource-uri", "headers":[{"name":"header1","value":"value1"}, 
   242  {"name":"header2","value":"value2"}],"body":"eyJjb2RlIjoiMDExMjM0In0="}`,
   243  			expected: struct {
   244  				method      string
   245  				resourceURI string
   246  				body        string
   247  				version     string
   248  				header      []struct {
   249  					key   string
   250  					value string
   251  				}
   252  				failure string
   253  			}{
   254  				http.MethodPost, "/sample-resource-uri", "011234", "HTTP/1.1", []struct {
   255  					key   string
   256  					value string
   257  				}{{"header1", "value1"}, {"header2", "value2"}}, "",
   258  			},
   259  		},
   260  		{
   261  			name:    "Testing failure in handleInBound due to invalid message body",
   262  			jsonStr: `{"@id":"sample-id", "@type":"https://didcomm.org/http-over-didcomm/1.0/request", "body":"--$#@!"}`,
   263  			expected: struct {
   264  				method      string
   265  				resourceURI string
   266  				body        string
   267  				version     string
   268  				header      []struct {
   269  					key   string
   270  					value string
   271  				}
   272  				failure string
   273  			}{
   274  				"", "", "", "", nil, "unable to decode message body",
   275  			},
   276  		},
   277  		{
   278  			name:    "Testing failure in handleInBound due to invalid request fields",
   279  			jsonStr: `{"@id":"sample-id", "@type":"https://didcomm.org/http-over-didcomm/1.0/request", "method":"--$#@!"}`,
   280  			expected: struct {
   281  				method      string
   282  				resourceURI string
   283  				body        string
   284  				version     string
   285  				header      []struct {
   286  					key   string
   287  					value string
   288  				}
   289  				failure string
   290  			}{
   291  				"", "", "", "", nil, "failed to create http request from incoming message",
   292  			},
   293  		},
   294  	}
   295  
   296  	rqCh := make(chan *http.Request)
   297  
   298  	handle := func(id string, rq *http.Request) error {
   299  		require.Equal(t, "sample-id", id)
   300  		rqCh <- rq
   301  
   302  		return nil
   303  	}
   304  
   305  	svc, err := NewOverDIDComm("sample-service", handle)
   306  	require.NoError(t, err)
   307  	require.NotNil(t, svc)
   308  
   309  	t.Parallel()
   310  
   311  	for _, test := range tests {
   312  		tc := test
   313  		t.Run(tc.name, func(t *testing.T) {
   314  			didCommMsg, err := service.ParseDIDCommMsgMap([]byte(tc.jsonStr))
   315  			require.NoError(t, err)
   316  
   317  			if tc.expected.failure != "" {
   318  				_, err = svc.HandleInbound(didCommMsg, service.EmptyDIDCommContext())
   319  				require.Error(t, err)
   320  				require.Contains(t, err.Error(), tc.expected.failure)
   321  				return
   322  			}
   323  
   324  			go func() {
   325  				_, err = svc.HandleInbound(didCommMsg, service.EmptyDIDCommContext())
   326  				require.NoError(t, err)
   327  			}()
   328  
   329  			select {
   330  			case rqst := <-rqCh:
   331  				// test request properties
   332  				require.Equal(t, tc.expected.method, rqst.Method)
   333  				require.Equal(t, tc.expected.version, rqst.Proto)
   334  				require.Equal(t, tc.expected.resourceURI, rqst.URL.String())
   335  
   336  				// test body
   337  				if tc.expected.body != "" {
   338  					v := struct {
   339  						Code string `json:"code"`
   340  					}{}
   341  
   342  					require.NoError(t, json.NewDecoder(rqst.Body).Decode(&v))
   343  					require.Equal(t, tc.expected.body, v.Code)
   344  				}
   345  
   346  				// test headers
   347  				for _, h := range tc.expected.header {
   348  					require.Equal(t, h.value, rqst.Header.Get(h.key))
   349  				}
   350  
   351  			case <-time.After(2 * time.Second):
   352  				require.Fail(t, "didn't receive post event responded")
   353  			}
   354  		})
   355  	}
   356  }
   357  
   358  func TestOverDIDComm_HandleInbound_InvalidMsg(t *testing.T) {
   359  	svc, err := NewOverDIDComm("sample-service", newMockHandle())
   360  	require.NoError(t, err)
   361  	require.NotNil(t, svc)
   362  
   363  	_, err = svc.HandleInbound(&mockMsg{err: fmt.Errorf("sample-error")}, service.EmptyDIDCommContext())
   364  	require.Error(t, err)
   365  	require.Contains(t, err.Error(), "unable to decode DID comm message")
   366  }
   367  
   368  func newMockHandle() RequestHandle {
   369  	return func(string, *http.Request) error { return nil }
   370  }
   371  
   372  type mockMsg struct {
   373  	*service.DIDCommMsgMap
   374  	err error
   375  }
   376  
   377  func (m *mockMsg) Decode(v interface{}) error {
   378  	return m.err
   379  }