github.com/martinohmann/rfoutlet@v1.2.1-0.20220707195255-8a66aa411105/internal/websocket/client_test.go (about)

     1  package websocket
     2  
     3  import (
     4  	"context"
     5  	"net/http"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/gin-gonic/gin"
    10  	"github.com/martinohmann/rfoutlet/internal/command"
    11  	"github.com/posener/wstest"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestClient_listenRead(t *testing.T) {
    17  	tests := []struct {
    18  		name            string
    19  		data            interface{}
    20  		expectedCmdType command.Command
    21  	}{
    22  		{
    23  			name: "outlet action",
    24  			data: map[string]interface{}{
    25  				"type": "outlet",
    26  				"data": map[string]string{
    27  					"action": "on",
    28  					"id":     "foo",
    29  				},
    30  			},
    31  			expectedCmdType: &command.OutletCommand{},
    32  		},
    33  		{
    34  			name: "status action",
    35  			data: map[string]interface{}{
    36  				"type": "status",
    37  			},
    38  			expectedCmdType: &command.StatusCommand{},
    39  		},
    40  		{
    41  			name: "unknown command",
    42  			data: map[string]interface{}{
    43  				"type": "foo",
    44  			},
    45  		},
    46  	}
    47  
    48  	for _, test := range tests {
    49  		t.Run(test.name, func(t *testing.T) {
    50  			hub := NewHub()
    51  
    52  			queue := make(chan command.Command)
    53  
    54  			r := gin.New()
    55  			r.GET("/ws", Handler(hub, queue))
    56  
    57  			c, _, err := wstest.NewDialer(r).Dial("ws://localhost/ws", nil)
    58  			require.NoError(t, err)
    59  			defer c.Close()
    60  
    61  			go func(data interface{}) {
    62  				require.NoError(t, c.WriteJSON(data))
    63  			}(test.data)
    64  
    65  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
    66  			defer cancel()
    67  
    68  			go hub.Run(ctx.Done())
    69  
    70  			select {
    71  			case <-ctx.Done():
    72  				if test.expectedCmdType != nil {
    73  					t.Fatal(ctx.Err())
    74  				}
    75  			case cmd := <-queue:
    76  				if test.expectedCmdType == nil {
    77  					t.Fatalf("did not expect command, but got %T", cmd)
    78  				}
    79  
    80  				assert.IsType(t, test.expectedCmdType, cmd)
    81  			}
    82  		})
    83  	}
    84  }
    85  
    86  func TestClient_listenWrite(t *testing.T) {
    87  	stopCh := make(chan struct{})
    88  	defer close(stopCh)
    89  
    90  	hub := NewHub()
    91  	go hub.Run(stopCh)
    92  
    93  	queue := make(chan command.Command)
    94  
    95  	r := gin.New()
    96  	r.GET("/ws", Handler(hub, queue))
    97  
    98  	c, rr, err := wstest.NewDialer(r).Dial("ws://localhost/ws", nil)
    99  	require.NoError(t, err)
   100  	defer c.Close()
   101  
   102  	assert.Equal(t, http.StatusSwitchingProtocols, rr.StatusCode)
   103  
   104  	ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
   105  	defer cancel()
   106  
   107  	go func() {
   108  		// give the client some time to register to hub before broadcasting
   109  		<-time.After(20 * time.Millisecond)
   110  		hub.Broadcast([]byte(`{"name":"bar"}`))
   111  
   112  		<-ctx.Done()
   113  		c.Close()
   114  	}()
   115  
   116  	type foo struct {
   117  		Name string
   118  	}
   119  
   120  	val := foo{}
   121  
   122  	require.NoError(t, c.ReadJSON(&val))
   123  	assert.Equal(t, foo{Name: "bar"}, val)
   124  }