github.com/GregorioDiStefano/go-file-storage@v0.0.0-20161001105139-5707ab351525/controllers/routes_test.go (about) 1 package controller 2 3 import ( 4 "bytes" 5 "crypto/rand" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "net/http/httptest" 11 "os" 12 "strconv" 13 "strings" 14 "testing" 15 "time" 16 17 "github.com/GregorioDiStefano/go-file-storage/models" 18 "github.com/GregorioDiStefano/go-file-storage/utils" 19 "github.com/gin-gonic/gin" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 var r *gin.Engine 24 25 type uploadedFileInfo struct { 26 payload []byte 27 downloadURL string 28 deleteURL string 29 } 30 31 func HTTPResponseToBytes(resp http.Response) []byte { 32 b, _ := ioutil.ReadAll(resp.Body) 33 return b 34 } 35 36 func performRequest(r http.Handler, method, path string, data []byte) ([]byte, http.Header, int) { 37 req, _ := http.NewRequest(method, path, bytes.NewReader(data)) 38 req.Header.Add("Content-Length", strconv.Itoa(len(data))) 39 w := httptest.NewRecorder() 40 41 r.ServeHTTP(w, req) 42 43 if w.Code == http.StatusMovedPermanently { 44 finalURL := w.Header().Get("Location") 45 resp, err := http.Get(finalURL) 46 if err != nil { 47 panic(err) 48 } 49 respBytes, _ := ioutil.ReadAll(resp.Body) 50 return respBytes, resp.Header, resp.StatusCode 51 } 52 53 return w.Body.Bytes(), w.Header(), w.Code 54 } 55 56 func downloadPathToMap(path string) map[string]string { 57 splitStr := strings.Split(path, "/") 58 59 key := splitStr[1] 60 filename := splitStr[2] 61 62 return map[string]string{ 63 "key": key, 64 "filename": filename, 65 } 66 } 67 68 func deletePathToMap(path string) map[string]string { 69 splitStr := strings.Split(path, "/") 70 71 key := splitStr[1] 72 deleteKey := splitStr[2] 73 filename := splitStr[3] 74 75 return map[string]string{ 76 "key": key, 77 "deleteKey": deleteKey, 78 "filename": filename, 79 } 80 } 81 82 func TestMain(m *testing.M) { 83 84 if err := os.Chdir("../"); err != nil { 85 panic(err) 86 } 87 88 utils.LoadConfig("config/config.testing.yaml") 89 models.DB.Setup(utils.Config.GetInt("key_size")) 90 models.DB.OpenDatabaseFile() 91 92 r = gin.Default() 93 94 r.LoadHTMLGlob("templates/*") 95 96 downloader := NewDownloader(utils.Config.GetString("CAPTCHA_SECRET"), utils.Config.GetInt("max_downloads")) 97 uploader := NewUploader(utils.Config.GetString("domain"), utils.Config.GetInt64("max_file_size"), utils.Config.GetInt("delete_key_size"), utils.Config.GetString("aws.bucket"), utils.Config.GetString("aws.region")) 98 deleter := NewDeleter(*uploader) 99 100 r.PUT("/:filename", func(c *gin.Context) { 101 uploader.UploadFile(c) 102 }) 103 104 r.DELETE("/:key/:delete_key/:filename", func(c *gin.Context) { 105 deleter.DeleteFile(c) 106 }) 107 108 r.GET("/:key/:filename", func(c *gin.Context) { 109 downloader.DownloadFile(c) 110 }) 111 112 os.Exit(m.Run()) 113 } 114 115 func uploadFile(data []byte, filename string) uploadedFileInfo { 116 var dl map[string]string 117 118 respBytes, _, _ := performRequest(r, "PUT", "/"+filename, data) 119 120 if err := json.Unmarshal(respBytes, &dl); err != nil { 121 panic(err) 122 } 123 124 return uploadedFileInfo{data, dl["downloadURL"], dl["deleteURL"]} 125 } 126 127 func TestUpload_1byte(t *testing.T) { 128 data := []byte{0x01} 129 uf := uploadFile(data, "test123") 130 131 respBytes, _, statusCode := performRequest(r, "GET", uf.downloadURL, nil) 132 133 assert.Equal(t, uf.payload, respBytes) 134 assert.Equal(t, http.StatusOK, statusCode) 135 } 136 137 func TestUpload_10MB(t *testing.T) { 138 data := []byte{0x01} 139 uf := uploadFile(bytes.Repeat(data, 10000000), "test1234") 140 141 respBytes, _, _ := performRequest(r, "GET", uf.downloadURL, nil) 142 assert.Equal(t, uf.payload, respBytes) 143 } 144 145 func TestUploadEqualMaxSize(t *testing.T) { 146 maxUploadSize := utils.Config.GetInt("max_file_size") 147 148 if maxUploadSize >= (1 * 1024 * 1024 * 1024) { 149 t.Skip("maxUploadSize is huge, skipping") 150 } 151 152 randomData := make([]byte, maxUploadSize) 153 _, err := rand.Read(randomData) 154 155 if err != nil { 156 panic(err) 157 } 158 159 _, _, statusCode := performRequest(r, "PUT", "/hugepass", randomData) 160 assert.Equal(t, http.StatusCreated, statusCode) 161 } 162 163 func TestUploadExceedingMaxSize(t *testing.T) { 164 maxUploadSize := utils.Config.GetInt("max_file_size") 165 166 if maxUploadSize >= (1 * 1024 * 1024 * 1024) { 167 t.Skip("maxUploadSize is huge, skipping") 168 } 169 randomData := make([]byte, maxUploadSize+1) 170 _, err := rand.Read(randomData) 171 172 if err != nil { 173 panic(err) 174 } 175 176 _, _, statusCode := performRequest(r, "PUT", "/hugefail", randomData) 177 assert.Equal(t, http.StatusForbidden, statusCode) 178 } 179 180 func TestInvalidDownload_1(t *testing.T) { 181 ufl := uploadFile(bytes.Repeat([]byte{0xff}, 1024*1024), "test") 182 downloadURL := downloadPathToMap(strings.Replace(ufl.downloadURL, utils.Config.GetString("domain"), "", 1)) 183 184 key := downloadURL["key"] 185 invalidFilename := downloadURL["filename"] + ".x" 186 187 invalidDownloadURL := fmt.Sprintf("%s/%s/%s", utils.Config.GetString("domain"), key, invalidFilename) 188 189 _, _, statusCode := performRequest(r, "GET", invalidDownloadURL, nil) 190 assert.Equal(t, http.StatusForbidden, statusCode) 191 } 192 193 func TestInvalidDownload_2(t *testing.T) { 194 ufl := uploadFile(bytes.Repeat([]byte{0x00, 0x11}, 1024*1024), "test") 195 downloadURL := downloadPathToMap(strings.Replace(ufl.downloadURL, utils.Config.GetString("domain"), "", 1)) 196 197 key := downloadURL["key"] + "foo" 198 invalidFilename := downloadURL["filename"] 199 200 invalidDownloadURL := fmt.Sprintf("%s/%s/%s", utils.Config.GetString("domain"), key, invalidFilename) 201 _, _, statusCode := performRequest(r, "GET", invalidDownloadURL, nil) 202 assert.Equal(t, http.StatusForbidden, statusCode) 203 } 204 205 func TestMaxDownloads(t *testing.T) { 206 db := models.Database{Filename: models.DbFilename, Bucket: models.Bucket} 207 ufl := uploadFile(bytes.Repeat([]byte{0x11, 0x22, 0x33, 0xff}, 1024), "test") 208 209 for i := int64(1); i <= int64(utils.Config.GetInt("max_downloads")); i++ { 210 respBytes, _, statusCode := performRequest(r, "GET", ufl.downloadURL, nil) 211 assert.Equal(t, ufl.payload, respBytes) 212 assert.Equal(t, http.StatusOK, statusCode) 213 } 214 215 downloadURLPath := downloadPathToMap(strings.Replace(ufl.downloadURL, utils.Config.GetString("domain"), "", 1)) 216 downloadsStoredInDB := db.ReadStoredFile(downloadURLPath["key"]).Downloads 217 assert.Equal(t, utils.Config.GetInt("max_downloads"), int(downloadsStoredInDB)) 218 219 _, _, statusCode := performRequest(r, "GET", ufl.downloadURL, nil) 220 downloadPathToMap(strings.Replace(ufl.downloadURL, utils.Config.GetString("domain"), "", 1)) 221 assert.Equal(t, http.StatusForbidden, statusCode) 222 } 223 224 func TestDeleteFile(t *testing.T) { 225 ufl := uploadFile(bytes.Repeat([]byte{0x11, 0x22, 0x33, 0xff}, 1024), "test") 226 227 _, _, statusCode := performRequest(r, "GET", ufl.downloadURL, nil) 228 assert.Equal(t, http.StatusOK, statusCode) 229 230 _, _, statusCode = performRequest(r, "DELETE", ufl.deleteURL, nil) 231 assert.Equal(t, http.StatusOK, statusCode) 232 233 _, _, statusCode = performRequest(r, "DELETE", ufl.deleteURL, nil) 234 assert.Equal(t, http.StatusForbidden, statusCode) 235 } 236 237 func TestDownloadLastAccess(t *testing.T) { 238 ufl := uploadFile(bytes.Repeat([]byte{0xff}, 10), "test") 239 downloadURLPath := downloadPathToMap(strings.Replace(ufl.downloadURL, utils.Config.GetString("domain"), "", 1)) 240 performRequest(r, "GET", ufl.downloadURL, nil) 241 expectedTime := models.DB.ReadStoredFile(downloadURLPath["key"]).LastAccess.Unix() 242 assert.True(t, expectedTime == time.Now().Unix() || expectedTime+1 == time.Now().Unix()) 243 } 244 245 func TestDownloadDeletedFile(t *testing.T) { 246 ufl := uploadFile(bytes.Repeat([]byte{0xff}, 1024), "random.ext") 247 downloadURLPath := downloadPathToMap(strings.Replace(ufl.downloadURL, utils.Config.GetString("domain"), "", 1)) 248 249 storedFile := models.DB.ReadStoredFile(downloadURLPath["key"]) 250 storedFile.Deleted = true 251 models.DB.WriteStoredFile(*storedFile) 252 253 _, _, statusCode := performRequest(r, "GET", ufl.downloadURL, nil) 254 assert.Equal(t, http.StatusForbidden, statusCode) 255 } 256 257 func TestUploadDownloadUnicode(t *testing.T) { 258 ufl := uploadFile(bytes.Repeat([]byte{0xff}, 1024), "test̉–.ext") 259 assert.True(t, strings.Contains(ufl.downloadURL, "test̉–.ext")) 260 261 respBytes, _, _ := performRequest(r, "GET", ufl.downloadURL, nil) 262 assert.Equal(t, ufl.payload, respBytes) 263 } 264 265 func TestDeleteInvalid_1(t *testing.T) { 266 ufl := uploadFile(bytes.Repeat([]byte{0x11, 0x22, 0x33}, 1024), "test") 267 deleteURL := deletePathToMap(strings.Replace(ufl.deleteURL, utils.Config.GetString("domain"), "", 1)) 268 269 key := deleteURL["key"] 270 deleteKey := deleteURL["deleteKey"] 271 invalidFilename := deleteURL["filename"] + ".x" 272 273 invalidDeleteURL := fmt.Sprintf("%s/%s/%s/%s", utils.Config.GetString("domain"), key, deleteKey, invalidFilename) 274 _, _, statusCode := performRequest(r, "DELETE", invalidDeleteURL, nil) 275 assert.Equal(t, http.StatusForbidden, statusCode) 276 } 277 278 func TestDeleteInvalid_2(t *testing.T) { 279 ufl := uploadFile(bytes.Repeat([]byte{0x11, 0x22, 0x33}, 1024), "test") 280 deleteURL := deletePathToMap(strings.Replace(ufl.deleteURL, utils.Config.GetString("domain"), "", 1)) 281 282 key := deleteURL["key"] 283 invalidDeleteKey := deleteURL["deleteKey"] + ".x" 284 filename := deleteURL["filename"] 285 286 invalidDeleteURL := fmt.Sprintf("%s/%s/%s/%s", utils.Config.GetString("domain"), key, invalidDeleteKey, filename) 287 288 _, _, statusCode := performRequest(r, "DELETE", invalidDeleteURL, nil) 289 assert.Equal(t, http.StatusForbidden, statusCode) 290 } 291 292 func TestDeleteInvalid_3(t *testing.T) { 293 ufl := uploadFile(bytes.Repeat([]byte{0x11, 0x22, 0x33}, 1024), "test") 294 deleteURL := deletePathToMap(strings.Replace(ufl.deleteURL, utils.Config.GetString("domain"), "", 1)) 295 296 invalidKey := deleteURL["key"] + ".x" 297 deleteKey := deleteURL["deleteKey"] 298 filename := deleteURL["filename"] 299 300 invalidDeleteURL := fmt.Sprintf("%s/%s/%s/%s", utils.Config.GetString("domain"), invalidKey, deleteKey, filename) 301 _, _, statusCode := performRequest(r, "DELETE", invalidDeleteURL, nil) 302 assert.Equal(t, http.StatusForbidden, statusCode) 303 }