http_test.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. package megauploader
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "flag"
  6. "fmt"
  7. "io/ioutil"
  8. "mime/multipart"
  9. "net/http"
  10. "net/http/httptest"
  11. "os"
  12. "strconv"
  13. "strings"
  14. "testing"
  15. "github.com/Flaque/filet"
  16. "github.com/headzoo/surf"
  17. )
  18. var (
  19. doHTTP = flag.Bool("http-tests", false, "run HTTP integration tests")
  20. )
  21. func TestMain(m *testing.M) {
  22. flag.Parse()
  23. result := m.Run()
  24. os.Exit(result)
  25. }
  26. func getServer(cfg string) *httptest.Server {
  27. conf, err := ParseConf([]byte(cfg))
  28. if err != nil {
  29. panic("Error parsing conf in getServer")
  30. }
  31. mu := NewMegaUploader(conf)
  32. ts := httptest.NewServer(mu.SetupRoutes())
  33. return ts
  34. }
  35. // ask home page without authentication; 401 expected
  36. func TestAuthDeny(t *testing.T) {
  37. if !*doHTTP {
  38. return
  39. }
  40. ts := getServer(``)
  41. defer ts.Close()
  42. resp, err := ts.Client().Get(ts.URL)
  43. if err != nil {
  44. t.Fatalf("Error asking home to test server")
  45. return
  46. }
  47. if resp.StatusCode != 401 {
  48. t.Errorf("Viewing home should require authentication; got `%s` instead",
  49. resp.Status,
  50. )
  51. }
  52. }
  53. // ask for non-existing page without authentication; 404 expected
  54. func TestNotFoundWhenUnauthenticated(t *testing.T) {
  55. if !*doHTTP {
  56. return
  57. }
  58. ts := getServer(``)
  59. defer ts.Close()
  60. resp, err := ts.Client().Get(ts.URL + "/dontexist")
  61. if err != nil {
  62. t.Fatalf("Error asking non-existent URL to test server: \n%s\n", err)
  63. return
  64. }
  65. if resp.StatusCode != 404 {
  66. t.Errorf("Asked not existing endpoint, expected 404; got `%s` instead",
  67. resp.Status,
  68. )
  69. }
  70. }
  71. func userRequest(url, user string, t *testing.T) *http.Request {
  72. req, err := http.NewRequest("GET", url, nil)
  73. if err != nil {
  74. t.Fatalf("error preparing request: \n%s\n", err)
  75. return nil
  76. }
  77. req.Header.Add("X-Forwarded-User", user)
  78. return req
  79. }
  80. // ask for home with valid user
  81. func TestAuthOk(t *testing.T) {
  82. if !*doHTTP {
  83. return
  84. }
  85. ts := getServer(``)
  86. defer ts.Close()
  87. cl := ts.Client()
  88. req := userRequest(ts.URL, "someone", t)
  89. resp, err := cl.Do(req)
  90. if err != nil {
  91. t.Fatalf("Error asking home to test server")
  92. return
  93. }
  94. if resp.StatusCode != 200 {
  95. t.Errorf("Viewing home should require authentication; got `%s` instead",
  96. resp.Status,
  97. )
  98. }
  99. }
  100. func getShareList(ts *httptest.Server, user string, t *testing.T) []Share {
  101. req := userRequest(ts.URL+"/api/share", user, t)
  102. cl := ts.Client()
  103. resp, err := cl.Do(req)
  104. if err != nil {
  105. t.Fatalf("Error asking share list to test server: \n%s\n", err)
  106. return []Share{}
  107. }
  108. body, err := ioutil.ReadAll(resp.Body)
  109. if err != nil {
  110. t.Fatal("Error reading response", err)
  111. return []Share{}
  112. }
  113. var shares []Share
  114. err = json.Unmarshal(body, &shares)
  115. if err != nil {
  116. t.Fatal("Invalid JSON received", err)
  117. return []Share{}
  118. }
  119. return shares
  120. }
  121. // share list with invalid user
  122. func TestShareRejected(t *testing.T) {
  123. if !*doHTTP {
  124. return
  125. }
  126. ts := getServer(`
  127. global:
  128. excluded:
  129. - john@doe.us
  130. - foo bar
  131. shares:
  132. - name: foo
  133. authorized: ["*"]
  134. description: foo
  135. `)
  136. defer ts.Close()
  137. shares := getShareList(ts, "john@doe.us", t)
  138. if len(shares) != 0 {
  139. t.Fatal("Asked share list with banned user, expected empty, got", shares)
  140. return
  141. }
  142. }
  143. // share list with valid user
  144. func TestShareOk(t *testing.T) {
  145. if !*doHTTP {
  146. return
  147. }
  148. ts := getServer(`
  149. global:
  150. excluded:
  151. - john@doe.us
  152. - foo bar
  153. shares:
  154. - name: foo
  155. authorized: ["*"]
  156. description: foo
  157. `)
  158. defer ts.Close()
  159. shares := getShareList(ts, "someone elese", t)
  160. if len(shares) == 0 {
  161. t.Fatal("Asked share list with not banned user, expected [foo], got", shares)
  162. return
  163. }
  164. if shares[0].Name != "foo" {
  165. t.Error("The only share should be `foo`, got", shares[0].Name)
  166. return
  167. }
  168. }
  169. func TestUpload(t *testing.T) {
  170. if !*doHTTP {
  171. return
  172. }
  173. defer filet.CleanUp(t)
  174. d := filet.TmpDir(t, "")
  175. conf := `
  176. shares:
  177. - name: foo
  178. dir: DIR
  179. authorized: ["*"]
  180. description: foo
  181. `
  182. conf = strings.Replace(conf, "DIR", d, 1)
  183. ts := getServer(conf)
  184. cl := ts.Client()
  185. bodyBuf := bytes.Buffer{}
  186. bodyWriter := multipart.NewWriter(&bodyBuf)
  187. fileWriter, err := bodyWriter.CreateFormFile("file", "foo.txt")
  188. if err != nil {
  189. t.Fatal("error creating form file", err)
  190. return
  191. }
  192. _, err = fileWriter.Write([]byte(`example content`))
  193. if err != nil {
  194. t.Fatal("error writing on form file", err)
  195. return
  196. }
  197. contentType := bodyWriter.FormDataContentType()
  198. bodyWriter.Close()
  199. req := userRequest(ts.URL+"/api/upload/foo", "someone", t)
  200. req.Method = "POST"
  201. req.Header.Set("Content-Type", contentType)
  202. req.ContentLength = int64(bodyBuf.Len())
  203. req.Body = ioutil.NopCloser(&bodyBuf)
  204. resp, err := cl.Do(req)
  205. if err != nil {
  206. t.Fatal("Error POSTing file", err)
  207. return
  208. }
  209. defer resp.Body.Close()
  210. respBody, err := ioutil.ReadAll(resp.Body)
  211. if err != nil {
  212. t.Fatal("Error reading server response", err)
  213. return
  214. }
  215. if resp.StatusCode < 200 || resp.StatusCode > 299 {
  216. t.Error("Server status is not success:", resp.Status, respBody)
  217. }
  218. fname := d + "/" + string(respBody)
  219. if !filet.Exists(t, fname) {
  220. t.Error("File does not exist", fname)
  221. } else if !filet.FileSays(t, fname, []byte("example content")) {
  222. t.Error("File exists but has wrong content")
  223. }
  224. }
  225. func TestUploadBig(t *testing.T) {
  226. if !*doHTTP {
  227. return
  228. }
  229. limit := 21
  230. if testing.Short() {
  231. limit = 2
  232. }
  233. // test with 1,5,9,13,17,21MB
  234. for i := 1; i < limit; i += 4 {
  235. t.Run(fmt.Sprintf("S=%d", i), testUploadBig)
  236. }
  237. }
  238. func testUploadBig(t *testing.T) {
  239. size, err := strconv.Atoi(strings.SplitN(t.Name(), "=", 2)[1])
  240. if err != nil {
  241. t.Fatalf("Cannot convert size %s to int: %s", t.Name(), err)
  242. return
  243. }
  244. size *= 1024 * 1024
  245. defer filet.CleanUp(t)
  246. d := filet.TmpDir(t, "")
  247. conf := `
  248. shares:
  249. - name: foo
  250. dir: DIR
  251. authorized: ["*"]
  252. description: foo
  253. `
  254. conf = strings.Replace(conf, "DIR", d, 1)
  255. ts := getServer(conf)
  256. cl := ts.Client()
  257. bodyBuf := bytes.Buffer{}
  258. bodyWriter := multipart.NewWriter(&bodyBuf)
  259. fileWriter, err := bodyWriter.CreateFormFile("file", "foo.txt")
  260. if err != nil {
  261. t.Fatal("error creating form file", err)
  262. return
  263. }
  264. // write 3MB made of 'a'
  265. for i := 0; i < size; i++ {
  266. _, err = fileWriter.Write([]byte(`a`))
  267. if err != nil {
  268. t.Fatal("error writing on form file", err)
  269. return
  270. }
  271. }
  272. contentType := bodyWriter.FormDataContentType()
  273. bodyWriter.Close()
  274. req := userRequest(ts.URL+"/api/upload/foo", "someone", t)
  275. req.Method = "POST"
  276. req.Header.Set("Content-Type", contentType)
  277. req.ContentLength = int64(bodyBuf.Len())
  278. req.Body = ioutil.NopCloser(&bodyBuf)
  279. resp, err := cl.Do(req)
  280. if err != nil {
  281. t.Fatal("Error POSTing file", err)
  282. return
  283. }
  284. defer resp.Body.Close()
  285. respBody, err := ioutil.ReadAll(resp.Body)
  286. if err != nil {
  287. t.Fatal("Error reading server response", err)
  288. return
  289. }
  290. if resp.StatusCode < 200 || resp.StatusCode > 299 {
  291. t.Error("Server status is not success:", resp.Status, respBody)
  292. }
  293. fname := d + "/" + string(respBody)
  294. if !filet.Exists(t, fname) {
  295. t.Error("File does not exist", fname)
  296. } else {
  297. info, err := os.Stat(fname)
  298. if err != nil {
  299. t.Fatal("error reading info on uploaded file", err)
  300. return
  301. }
  302. if info.Size() != int64(size) {
  303. t.Errorf("File exists but has wrong size: expected %d, found %d", size, info.Size())
  304. }
  305. }
  306. }
  307. func TestUploadTooBig(t *testing.T) {
  308. size := 900*1024 + 1
  309. defer filet.CleanUp(t)
  310. d := filet.TmpDir(t, "")
  311. conf := `
  312. shares:
  313. - name: foo
  314. dir: DIR
  315. sizelimit: 900K
  316. authorized: ["*"]
  317. description: foo
  318. `
  319. conf = strings.Replace(conf, "DIR", d, 1)
  320. ts := getServer(conf)
  321. cl := ts.Client()
  322. bodyBuf := bytes.Buffer{}
  323. bodyWriter := multipart.NewWriter(&bodyBuf)
  324. fileWriter, err := bodyWriter.CreateFormFile("file", "foo.txt")
  325. if err != nil {
  326. t.Fatal("error creating form file", err)
  327. return
  328. }
  329. // write 3MB made of 'a'
  330. for i := 0; i < size; i++ {
  331. _, err = fileWriter.Write([]byte(`a`))
  332. if err != nil {
  333. t.Fatal("error writing on form file", err)
  334. return
  335. }
  336. }
  337. contentType := bodyWriter.FormDataContentType()
  338. bodyWriter.Close()
  339. req := userRequest(ts.URL+"/api/upload/foo", "someone", t)
  340. req.Method = "POST"
  341. req.Header.Set("Content-Type", contentType)
  342. req.ContentLength = int64(bodyBuf.Len())
  343. req.Body = ioutil.NopCloser(&bodyBuf)
  344. resp, err := cl.Do(req)
  345. if err != nil {
  346. t.Fatal("Error POSTing file", err)
  347. return
  348. }
  349. defer resp.Body.Close()
  350. _, err = ioutil.ReadAll(resp.Body)
  351. if err != nil {
  352. t.Fatal("Error reading server response", err)
  353. return
  354. }
  355. if resp.StatusCode < 299 {
  356. t.Error("Upload succeeded despite high size", resp.Status)
  357. }
  358. files, err := ioutil.ReadDir(d)
  359. if err != nil {
  360. t.Fatal("Error checking if upload dir is empty", err)
  361. }
  362. if len(files) != 0 {
  363. t.Error("Upload dir not empty; should be refused!", len(files))
  364. t.Log(files[0])
  365. }
  366. }
  367. func TestSurfUpload(t *testing.T) {
  368. if !*doHTTP {
  369. return
  370. }
  371. defer filet.CleanUp(t)
  372. d := filet.TmpDir(t, "")
  373. conf := `
  374. shares:
  375. - name: foo
  376. dir: DIR
  377. authorized: ["*"]
  378. description: example
  379. sizelimit: 1M
  380. `
  381. conf = strings.Replace(conf, "DIR", d, 1)
  382. ts := getServer(conf)
  383. bow := surf.NewBrowser()
  384. bow.AddRequestHeader("X-Forwarded-User", "someone")
  385. var err error
  386. if err = bow.Open(ts.URL); err != nil {
  387. t.Fatal("error opening home", err)
  388. return
  389. }
  390. if err = bow.Click("li a"); err != nil {
  391. t.Fatal("error clicking on share", err)
  392. return
  393. }
  394. form, err := bow.Form("form")
  395. if err != nil {
  396. t.Fatal("can't find form", err)
  397. return
  398. }
  399. form.SetFile("file", "foo.txt", strings.NewReader("example content"))
  400. if err = form.Submit(); err != nil {
  401. t.Error("error submitting form", err)
  402. }
  403. if bow.StatusCode() > 299 {
  404. t.Error("Invalid status code", bow.StatusCode(), bow.Body())
  405. }
  406. fname := d + "/" + bow.Body()
  407. if !filet.Exists(t, fname) {
  408. t.Error("File does not exist", fname)
  409. } else if !filet.FileSays(t, fname, []byte("example content")) {
  410. t.Error("File exists but has wrong content")
  411. }
  412. }