github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/updater/util/http_test.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package util 5 6 import ( 7 "bytes" 8 "fmt" 9 "net/http" 10 "net/http/httptest" 11 "os" 12 "path/filepath" 13 "runtime" 14 "testing" 15 "time" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestDiscardAndCloseBodyNil(t *testing.T) { 22 err := DiscardAndCloseBody(nil) 23 if err == nil { 24 t.Fatal("Should have errored") 25 } 26 } 27 28 func testServer(t *testing.T, data string, delay time.Duration) *httptest.Server { 29 return testServerWithETag(t, data, delay, "") 30 } 31 32 func testServerWithETag(t *testing.T, data string, delay time.Duration, etag string) *httptest.Server { 33 return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 34 if delay > 0 { 35 time.Sleep(delay) 36 } 37 38 etagMatch := r.Header.Get("If-None-Match") 39 if etagMatch != "" { 40 t.Logf("Checking etag match: %s == %s", etag, etagMatch) 41 if etag == etagMatch { 42 w.WriteHeader(http.StatusNotModified) 43 return 44 } 45 } 46 47 w.Header().Set("Content-Type", "application/json") 48 fmt.Fprintln(w, data) 49 })) 50 } 51 52 func testServerForError(err error) *httptest.Server { 53 return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 54 http.Error(w, err.Error(), 500) 55 })) 56 } 57 58 func TestSaveHTTPResponse(t *testing.T) { 59 data := `{"test": true}` 60 server := testServer(t, data, 0) 61 defer server.Close() 62 resp, err := http.Get(server.URL) 63 assert.NoError(t, err) 64 65 savePath := TempPath("", "TestSaveHTTPResponse.") 66 defer RemoveFileAtPath(savePath) 67 68 err = SaveHTTPResponse(resp, savePath, 0600, testLog) 69 assert.NoError(t, err) 70 71 saved, err := os.ReadFile(savePath) 72 assert.NoError(t, err) 73 74 assert.Equal(t, string(saved), data+"\n") 75 } 76 77 func TestSaveHTTPResponseInvalidPath(t *testing.T) { 78 data := `{"test": true}` 79 server := testServer(t, data, 0) 80 defer server.Close() 81 resp, err := http.Get(server.URL) 82 assert.NoError(t, err) 83 84 savePath := TempPath("", "TestSaveHTTPResponse.") 85 defer RemoveFileAtPath(savePath) 86 87 badPath := "/badpath" 88 if runtime.GOOS == "windows" { 89 badPath = `x:\` // Shouldn't be writable 90 } 91 92 err = SaveHTTPResponse(resp, badPath, 0600, testLog) 93 assert.Error(t, err) 94 err = SaveHTTPResponse(nil, savePath, 0600, testLog) 95 assert.Error(t, err) 96 } 97 98 func TestURLExistsValid(t *testing.T) { 99 server := testServer(t, "ok", 0) 100 defer server.Close() 101 exists, err := URLExists(server.URL, time.Second, testLog) 102 assert.True(t, exists) 103 assert.NoError(t, err) 104 } 105 106 func TestURLExistsInvalid(t *testing.T) { 107 exists, err := URLExists("", time.Second, testLog) 108 assert.Error(t, err) 109 assert.False(t, exists) 110 111 exists, err = URLExists("badurl", time.Second, testLog) 112 assert.Error(t, err) 113 assert.False(t, exists) 114 115 exists, err = URLExists("http://n", time.Second, testLog) 116 assert.Error(t, err) 117 assert.False(t, exists) 118 } 119 120 func TestURLExistsTimeout(t *testing.T) { 121 server := testServer(t, "timeout", time.Second) 122 defer server.Close() 123 exists, err := URLExists(server.URL, time.Millisecond, testLog) 124 t.Logf("Timeout error: %s", err) 125 assert.Error(t, err) 126 assert.False(t, exists) 127 } 128 129 func TestURLExistsFile(t *testing.T) { 130 path, err := WriteTempFile("TestURLExistsFile", []byte(""), 0600) 131 assert.NoError(t, err) 132 exists, err := URLExists(URLStringForPath(path), 0, testLog) 133 assert.NoError(t, err) 134 assert.True(t, exists) 135 136 exists, err = URLExists(URLStringForPath("/invalid"), 0, testLog) 137 assert.NoError(t, err) 138 assert.False(t, exists) 139 } 140 141 func TestDownloadURLValid(t *testing.T) { 142 server := testServer(t, "ok", 0) 143 defer server.Close() 144 destinationPath := TempPath("", "TestDownloadURLValid.") 145 digest, err := Digest(bytes.NewReader([]byte("ok\n"))) 146 assert.NoError(t, err) 147 err = DownloadURL(server.URL, destinationPath, DownloadURLOptions{Digest: digest, RequireDigest: true, Log: testLog}) 148 if assert.NoError(t, err) { 149 // Check file saved and correct data 150 fileExists, fileErr := FileExists(destinationPath) 151 assert.NoError(t, fileErr) 152 assert.True(t, fileExists) 153 data, readErr := os.ReadFile(destinationPath) 154 assert.NoError(t, readErr) 155 assert.Equal(t, []byte("ok\n"), data) 156 } 157 158 // Repeat test, download again, overwriting destination 159 server2 := testServer(t, "ok2", 0) 160 defer server2.Close() 161 digest2, err := Digest(bytes.NewReader([]byte("ok2\n"))) 162 assert.NoError(t, err) 163 err = DownloadURL(server2.URL, destinationPath, DownloadURLOptions{Digest: digest2, RequireDigest: true, Log: testLog}) 164 if assert.NoError(t, err) { 165 fileExists2, err := FileExists(destinationPath) 166 assert.NoError(t, err) 167 assert.True(t, fileExists2) 168 data2, err := os.ReadFile(destinationPath) 169 assert.NoError(t, err) 170 assert.Equal(t, []byte("ok2\n"), data2) 171 } 172 } 173 174 func TestDownloadURLInvalid(t *testing.T) { 175 destinationPath := TempPath("", "TestDownloadURLInvalid.") 176 177 err := DownloadURL("", destinationPath, DownloadURLOptions{Log: testLog}) 178 assert.Error(t, err) 179 180 err = DownloadURL("badurl", destinationPath, DownloadURLOptions{Log: testLog}) 181 assert.Error(t, err) 182 183 err = DownloadURL("http://", destinationPath, DownloadURLOptions{Log: testLog}) 184 assert.Error(t, err) 185 } 186 187 func TestDownloadURLTimeout(t *testing.T) { 188 server := testServer(t, "timeout", time.Second) 189 defer server.Close() 190 destinationPath := TempPath("", "TestDownloadURLInvalid.") 191 err := DownloadURL(server.URL, destinationPath, DownloadURLOptions{Timeout: time.Millisecond, Log: testLog}) 192 t.Logf("Timeout error: %s", err) 193 assert.Error(t, err) 194 } 195 196 func TestDownloadURLParseError(t *testing.T) { 197 err := DownloadURL("invalid", "", DownloadURLOptions{Log: testLog}) 198 assert.Error(t, err) 199 } 200 201 func TestDownloadURLError(t *testing.T) { 202 server := testServerForError(fmt.Errorf("Test error")) 203 defer server.Close() 204 205 err := DownloadURL(server.URL, "", DownloadURLOptions{Log: testLog}) 206 assert.EqualError(t, err, "Responded with 500 Internal Server Error") 207 } 208 209 func TestDownloadURLLocal(t *testing.T) { 210 _, filename, _, _ := runtime.Caller(0) 211 testZipPath := filepath.Join(filepath.Dir(filename), "../test/test.zip") 212 destinationPath := TempPath("", "TestDownloadURLLocal.") 213 defer RemoveFileAtPath(destinationPath) 214 err := DownloadURL(URLStringForPath(testZipPath), destinationPath, DownloadURLOptions{Log: testLog}) 215 assert.NoError(t, err) 216 217 exists, err := FileExists(destinationPath) 218 assert.NoError(t, err) 219 assert.True(t, exists) 220 } 221 222 func TestDownloadURLETag(t *testing.T) { 223 data := []byte("ok\n") 224 etag := "eff5bc1ef8ec9d03e640fc4370f5eacd" 225 server := testServerWithETag(t, "ok", 0, etag) 226 defer server.Close() 227 destinationPath := TempPath("", "TestDownloadURLETag.") 228 err := os.WriteFile(destinationPath, data, 0600) 229 require.NoError(t, err) 230 digest, err := Digest(bytes.NewReader(data)) 231 assert.NoError(t, err) 232 cached, err := downloadURL(server.URL, destinationPath, DownloadURLOptions{Digest: digest, RequireDigest: true, UseETag: true, Log: testLog}) 233 require.NoError(t, err) 234 assert.True(t, cached) 235 } 236 237 func TestURLExistsParseError(t *testing.T) { 238 exists, err := URLExists("invalid", time.Millisecond, testLog) 239 assert.False(t, exists) 240 assert.Error(t, err) 241 } 242 243 func TestURLExistsError(t *testing.T) { 244 server := testServerForError(fmt.Errorf("Test error")) 245 defer server.Close() 246 247 exists, err := URLExists(server.URL, time.Second, testLog) 248 assert.False(t, exists) 249 assert.EqualError(t, err, "Invalid status code (500)") 250 } 251 252 func TestURLValueForBool(t *testing.T) { 253 assert.Equal(t, "0", URLValueForBool(false)) 254 assert.Equal(t, "1", URLValueForBool(true)) 255 }