github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/transport/ws/outbound_test.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package ws
     8  
     9  import (
    10  	"context"
    11  	"encoding/json"
    12  	"net/http"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/google/uuid"
    17  	"github.com/stretchr/testify/require"
    18  	"nhooyr.io/websocket"
    19  
    20  	cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto"
    21  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
    22  	"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
    23  	mockpackager "github.com/hyperledger/aries-framework-go/pkg/mock/didcomm/packager"
    24  )
    25  
    26  func TestClient(t *testing.T) {
    27  	t.Run("test outbound transport - accept", func(t *testing.T) {
    28  		outbound := NewOutbound()
    29  		require.NotNil(t, outbound)
    30  
    31  		require.True(t, outbound.Accept(webSocketScheme))
    32  		require.False(t, outbound.Accept("http"))
    33  	})
    34  
    35  	t.Run("test outbound transport - invalid url", func(t *testing.T) {
    36  		outbound := NewOutbound()
    37  		require.NotNil(t, outbound)
    38  
    39  		_, err := outbound.Send([]byte(""), prepareDestination("ws://invalid"))
    40  		require.Error(t, err)
    41  		require.Contains(t, err.Error(), "websocket client")
    42  	})
    43  
    44  	t.Run("test outbound transport - success", func(t *testing.T) {
    45  		outbound := NewOutbound()
    46  		require.NotNil(t, outbound)
    47  		addr := startWebSocketServer(t, echo)
    48  
    49  		data := "hello"
    50  		resp, err := outbound.Send([]byte(data), prepareDestination("ws://"+addr))
    51  		require.NoError(t, err)
    52  		require.Equal(t, "", resp)
    53  	})
    54  
    55  	t.Run("test outbound transport - not a websocket server", func(t *testing.T) {
    56  		outbound := NewOutbound()
    57  		require.NotNil(t, outbound)
    58  		addr := startWebSocketServer(t, func(_ *testing.T, w http.ResponseWriter, r *http.Request) {
    59  			logger.Infof("inside http path")
    60  		})
    61  
    62  		_, err := outbound.Send([]byte("ws-request"), prepareDestination("ws://"+addr))
    63  		require.Error(t, err)
    64  		require.Contains(t, err.Error(), "websocket client")
    65  	})
    66  
    67  	t.Run("test outbound transport pool success - no existing connections", func(t *testing.T) {
    68  		outbound := NewOutbound()
    69  		require.NotNil(t, outbound)
    70  
    71  		require.NoError(t, outbound.Start(&mockProvider{}))
    72  
    73  		addr := startWebSocketServer(t, echo)
    74  
    75  		data := "hello"
    76  		resp, err := outbound.Send([]byte(data), prepareDestination("ws://"+addr))
    77  		require.NoError(t, err)
    78  		require.Equal(t, "", resp)
    79  	})
    80  
    81  	t.Run("test outbound transport pool - accept recipients", func(t *testing.T) {
    82  		verKey := "XYZ"
    83  		recKey := []string{verKey}
    84  
    85  		outbound := NewOutbound()
    86  		require.NotNil(t, outbound)
    87  
    88  		require.NoError(t, outbound.Start(&mockProvider{
    89  			&mockpackager.Packager{UnpackValue: &transport.Envelope{Message: []byte("data")}},
    90  		},
    91  		))
    92  
    93  		addr := startWebSocketServer(t, echo)
    94  
    95  		resp, err := outbound.Send(createTransportDecRequest(t, decorator.TransportReturnRouteAll),
    96  			prepareDestinationWithTransport("ws://"+addr, decorator.TransportReturnRouteAll, recKey, nil))
    97  		require.NoError(t, err)
    98  		require.Equal(t, "", resp)
    99  
   100  		// verify connection exists for the verKey
   101  		require.True(t, outbound.AcceptRecipient(recKey))
   102  
   103  		// close the connection and verify
   104  		conn := outbound.pool.fetch(verKey)
   105  		require.NoError(t, conn.Close(websocket.StatusNormalClosure, "close conn"))
   106  		require.False(t, outbound.AcceptRecipient(recKey))
   107  
   108  		// connection was remove in prev step
   109  		require.False(t, outbound.AcceptRecipient(recKey))
   110  	})
   111  
   112  	t.Run("test outbound transport pool - accept routing keys", func(t *testing.T) {
   113  		verKey := "XYZ"
   114  		routeKey := "ABC"
   115  		recKey := []string{verKey}
   116  		routingKeys := []string{routeKey}
   117  
   118  		outbound := NewOutbound()
   119  		require.NotNil(t, outbound)
   120  
   121  		require.NoError(t, outbound.Start(&mockProvider{
   122  			&mockpackager.Packager{UnpackValue: &transport.Envelope{Message: []byte("data")}},
   123  		},
   124  		))
   125  
   126  		addr := startWebSocketServer(t, echo)
   127  
   128  		des := prepareDestinationWithTransport("ws://"+addr, decorator.TransportReturnRouteAll, recKey, routingKeys)
   129  
   130  		data := "didcomm-message"
   131  		resp, err := outbound.Send([]byte(data), des)
   132  		require.NoError(t, err)
   133  		require.Equal(t, "", resp)
   134  	})
   135  
   136  	t.Run("test outbound transport pool success - transport decorator", func(t *testing.T) {
   137  		outbound := NewOutbound()
   138  		require.NotNil(t, outbound)
   139  
   140  		require.NoError(t, outbound.Start(&mockProvider{
   141  			&mockpackager.Packager{UnpackValue: &transport.Envelope{Message: []byte("data")}},
   142  		},
   143  		))
   144  
   145  		addr := startWebSocketServer(t, echo)
   146  
   147  		resp, err := outbound.Send(createTransportDecRequest(t, decorator.TransportReturnRouteAll),
   148  			prepareDestinationWithTransport("ws://"+addr, decorator.TransportReturnRouteAll, nil, nil))
   149  		require.NoError(t, err)
   150  		require.Equal(t, "", resp)
   151  	})
   152  
   153  	t.Run("test outbound transport pool - transport decorator value none", func(t *testing.T) {
   154  		outbound := NewOutbound()
   155  		require.NotNil(t, outbound)
   156  
   157  		require.NoError(t, outbound.Start(&mockProvider{
   158  			&mockpackager.Packager{UnpackValue: &transport.Envelope{Message: []byte("data")}},
   159  		},
   160  		))
   161  
   162  		addr := startWebSocketServer(t, echo)
   163  
   164  		resp, err := outbound.Send(createTransportDecRequest(t, decorator.TransportReturnRouteNone),
   165  			prepareDestinationWithTransport("ws://"+addr, decorator.TransportReturnRouteNone, nil, nil))
   166  		require.NoError(t, err)
   167  		require.Equal(t, "", resp)
   168  	})
   169  
   170  	t.Run("test outbound transport - custom read limit for a single message", func(t *testing.T) {
   171  		outboundClient := NewOutbound(WithOutboundReadLimit(defaultReadLimit + 1))
   172  		require.NotNil(t, outboundClient)
   173  
   174  		done := make(chan struct{})
   175  
   176  		unpackMsg, err := json.Marshal(&decorator.Transport{
   177  			ReturnRoute: &decorator.ReturnRoute{
   178  				Value: decorator.TransportReturnRouteAll,
   179  			},
   180  		})
   181  		require.NoError(t, err)
   182  
   183  		fromKey, err := json.Marshal(&cryptoapi.PublicKey{KID: "keyID"})
   184  		require.NoError(t, err)
   185  
   186  		transportProvider := &mockTransportProvider{
   187  			frameworkID: uuid.New().String(),
   188  			packagerValue: &mockpackager.Packager{
   189  				UnpackValue: &transport.Envelope{Message: unpackMsg, FromKey: fromKey},
   190  			},
   191  			executeInbound: func(envelope *transport.Envelope) error {
   192  				done <- struct{}{}
   193  				return nil
   194  			},
   195  		}
   196  
   197  		addr := startWebSocketServer(t, func(t *testing.T, w http.ResponseWriter, r *http.Request) {
   198  			c, errAcc := Accept(w, r)
   199  			require.NoError(t, errAcc)
   200  
   201  			defer func() {
   202  				require.NoError(t, c.Close(websocket.StatusNormalClosure, "closing the connection"))
   203  			}()
   204  
   205  			bigMsg := make([]byte, defaultReadLimit+1)
   206  
   207  			errWrite := c.Write(context.Background(), websocket.MessageText, bigMsg)
   208  			require.NoError(t, errWrite)
   209  		})
   210  
   211  		err = outboundClient.Start(transportProvider)
   212  		require.NoError(t, err)
   213  
   214  		resp, err := outboundClient.Send([]byte("data"),
   215  			prepareDestinationWithTransport("ws://"+addr, decorator.TransportReturnRouteAll, nil, nil))
   216  		require.NoError(t, err)
   217  		require.Equal(t, "", resp)
   218  
   219  		select {
   220  		case <-done:
   221  		case <-time.After(3 * time.Second):
   222  			require.Fail(t, "inbound message handler was not called within given timeout")
   223  		}
   224  	})
   225  }