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 }