github.com/m-lab/locate@v0.17.6/connection/connection_test.go (about)

     1  package connection
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/gorilla/websocket"
    11  	"github.com/m-lab/locate/connection/testdata"
    12  )
    13  
    14  func Test_Dial(t *testing.T) {
    15  	c := NewConn()
    16  	fh := testdata.FakeHandler{}
    17  	s := testdata.FakeServer(fh.Upgrade)
    18  	defer close(c, s)
    19  
    20  	err := c.Dial(s.URL, http.Header{}, testdata.FakeRegistration)
    21  
    22  	if err != nil {
    23  		t.Errorf("Dial() should have returned nil error, err: %v", err)
    24  	}
    25  
    26  	if !c.IsConnected() {
    27  		t.Error("Dial() error, not connected")
    28  	}
    29  }
    30  
    31  func Test_Dial_ThenClose(t *testing.T) {
    32  	c := NewConn()
    33  	fh := testdata.FakeHandler{}
    34  	s := testdata.FakeServer(fh.Upgrade)
    35  	defer s.Close()
    36  
    37  	if err := c.Dial(s.URL, http.Header{}, testdata.FakeRegistration); err != nil {
    38  		t.Errorf("Dial() should have returned nil error, err: %v", err)
    39  	}
    40  
    41  	if !c.IsConnected() {
    42  		t.Error("Dial() error, not connected")
    43  	}
    44  
    45  	if err := c.Close(); err != nil {
    46  		t.Errorf("Close() should have returned nil error, err: %v", err)
    47  	}
    48  
    49  	if c.IsConnected() {
    50  		t.Error("Close() error, still connected")
    51  	}
    52  
    53  	if err := c.Dial(s.URL, http.Header{}, testdata.FakeRegistration); err != nil {
    54  		t.Errorf("Dial() should have returned nil error, err: %v", err)
    55  	}
    56  
    57  	if !c.IsConnected() {
    58  		t.Error("Dial() error, not connected")
    59  	}
    60  
    61  	if err := c.Close(); err != nil {
    62  		t.Errorf("Close() should have returned nil error, err: %v", err)
    63  	}
    64  
    65  	if c.IsConnected() {
    66  		t.Error("Close() error, still connected")
    67  	}
    68  }
    69  
    70  func Test_Dial_InvalidUrl(t *testing.T) {
    71  	tests := []struct {
    72  		name string
    73  		url  string
    74  	}{
    75  		{
    76  			name: "malformed",
    77  			url:  "foo",
    78  		},
    79  		{
    80  			name: "https-invalid-scheme",
    81  			url:  "https://127.0.0.2:1234/v2/heartbeat",
    82  		},
    83  	}
    84  
    85  	for _, tt := range tests {
    86  		t.Run(tt.name, func(t *testing.T) {
    87  			c := NewConn()
    88  			err := c.Dial(tt.url, http.Header{}, testdata.FakeRegistration)
    89  
    90  			if err == nil {
    91  				t.Error("Dial() should return an error when given an invalid URL")
    92  			}
    93  		})
    94  	}
    95  }
    96  
    97  func Test_Dial_ServerDown(t *testing.T) {
    98  	c := NewConn()
    99  	defer c.Close()
   100  	fh := testdata.FakeHandler{}
   101  	s := testdata.FakeServer(fh.Upgrade)
   102  	// Shut down server for testing.
   103  	s.Close()
   104  
   105  	c.InitialInterval = 500 * time.Millisecond
   106  	c.MaxElapsedTime = time.Second
   107  
   108  	err := c.Dial(s.URL, http.Header{}, testdata.FakeRegistration)
   109  	if err == nil {
   110  		t.Error("Dial() should return an error once backoff ticker stops")
   111  	}
   112  }
   113  
   114  func Test_Dial_BadRequest(t *testing.T) {
   115  	c := NewConn()
   116  	fh := testdata.FakeHandler{}
   117  	// This handler returns a 400 status code.
   118  	s := testdata.FakeServer(fh.BadUpgrade)
   119  	err := c.Dial(s.URL, http.Header{}, testdata.FakeRegistration)
   120  
   121  	if err == nil {
   122  		t.Error("Dial() should fail when a 400 response status code is received")
   123  	}
   124  }
   125  
   126  func Test_WriteMessage(t *testing.T) {
   127  	tests := []struct {
   128  		name       string
   129  		disconnect bool
   130  	}{
   131  		{
   132  			name:       "success",
   133  			disconnect: false,
   134  		},
   135  		{
   136  			name:       "disconnect-reconnect",
   137  			disconnect: true,
   138  		},
   139  	}
   140  
   141  	for _, tt := range tests {
   142  		t.Run(tt.name, func(t *testing.T) {
   143  			c := NewConn()
   144  			fh := testdata.FakeHandler{}
   145  			s := testdata.FakeServer(fh.Upgrade)
   146  
   147  			c.Dial(s.URL, http.Header{}, testdata.FakeRegistration)
   148  
   149  			if tt.disconnect {
   150  				fh.Close()
   151  			}
   152  
   153  			// Write new message. If connection was closed, it should reconnect
   154  			// and retry to send the message.
   155  			err := c.WriteMessage(websocket.TextMessage, []byte("Health message!"))
   156  
   157  			if err != nil {
   158  				t.Errorf("WriteMessage() should have succeeded; err: %v", err)
   159  			}
   160  
   161  			close(c, s)
   162  		})
   163  	}
   164  }
   165  
   166  func Test_WriteMessage_ErrNotDailed(t *testing.T) {
   167  	c := NewConn()
   168  	err := c.WriteMessage(websocket.TextMessage, []byte("Health message!"))
   169  	if !errors.Is(err, ErrNotDailed) {
   170  		t.Errorf("WriteMessage() incorrect error; got: %v, want: ErrNotDailed", err)
   171  	}
   172  }
   173  
   174  func TestWriteMessage_ClosedServer(t *testing.T) {
   175  	c := NewConn()
   176  	defer c.Close()
   177  	fh := testdata.FakeHandler{}
   178  	s := testdata.FakeServer(fh.Upgrade)
   179  	c.InitialInterval = 500 * time.Millisecond
   180  	c.MaxElapsedTime = time.Second
   181  	c.Dial(s.URL, http.Header{}, testdata.FakeRegistration)
   182  
   183  	// Shut down server for testing.
   184  	fh.Close()
   185  	s.Close()
   186  
   187  	// Write should fail and connection should become disconnected.
   188  	err := c.WriteMessage(websocket.TextMessage, []byte("Health message!"))
   189  	if err == nil {
   190  		t.Error("WriteMessage() should fail after server is disconnected")
   191  	}
   192  	if c.IsConnected() {
   193  		t.Errorf("IsConnected() should be false after writing to closed server.")
   194  	}
   195  
   196  	// Subsequent writes should fail.
   197  	err = c.WriteMessage(websocket.TextMessage, []byte("Health message!"))
   198  	if err == nil {
   199  		t.Error("WriteMessage() should fail after client detects disconnection")
   200  	}
   201  }
   202  
   203  func close(c *Conn, s *httptest.Server) {
   204  	c.Close()
   205  	s.Close()
   206  }