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  }