github.com/vugu/vugu@v0.3.6-0.20240430171613-3f6f402e014b/devutil/file-server_test.go (about)

     1  package devutil
     2  
     3  import (
     4  	"bytes"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"net/http/httputil"
     8  	"os"
     9  	"path/filepath"
    10  	"testing"
    11  )
    12  
    13  func TestFileServer(t *testing.T) {
    14  
    15  	tmpDir, err := os.MkdirTemp("", "TestFileServer")
    16  	must(err)
    17  	defer os.RemoveAll(tmpDir)
    18  	t.Logf("Using temporary dir: %s", tmpDir)
    19  
    20  	fs := NewFileServer().SetDir(tmpDir)
    21  
    22  	// redirect /dir to /dir/
    23  	err = os.Mkdir(filepath.Join(tmpDir, "dir"), 0755)
    24  	must(err)
    25  	wr := httptest.NewRecorder()
    26  	r, _ := http.NewRequest("GET", "/dir", nil)
    27  	fs.ServeHTTP(wr, r)
    28  	checkStatus(t, r, wr.Result(), 301)
    29  	checkHeader(t, r, wr.Result(), "Location", "dir/")
    30  
    31  	// should error in a sane way on /dir/ if no listings
    32  	wr = httptest.NewRecorder()
    33  	r, _ = http.NewRequest("GET", "/dir/", nil)
    34  	fs.ServeHTTP(wr, r)
    35  	checkStatus(t, r, wr.Result(), 404)
    36  
    37  	// serve index.html from /dir/
    38  	must(os.WriteFile(filepath.Join(tmpDir, "dir/index.html"), []byte(`<html><body>index page here</body></html>`), 0644))
    39  	wr = httptest.NewRecorder()
    40  	r, _ = http.NewRequest("GET", "/dir/", nil)
    41  	fs.ServeHTTP(wr, r)
    42  	checkStatus(t, r, wr.Result(), 200)
    43  	checkBody(t, r, wr.Result(), "index page here")
    44  
    45  	// listing for /dir/
    46  	os.Remove(filepath.Join(tmpDir, "dir/index.html"))
    47  	must(os.WriteFile(filepath.Join(tmpDir, "dir/blerg.html"), []byte(`<html><body>blerg page here</body></html>`), 0644))
    48  	fs.SetListings(true)
    49  	wr = httptest.NewRecorder()
    50  	r, _ = http.NewRequest("GET", "/dir/", nil)
    51  	fs.ServeHTTP(wr, r)
    52  	checkStatus(t, r, wr.Result(), 200)
    53  	checkBody(t, r, wr.Result(), "blerg.html")
    54  	checkHeader(t, r, wr.Result(), "Content-Type", "text/html; charset=utf-8")
    55  
    56  	fs.SetListings(false)
    57  
    58  	// /a.html should serve a.html
    59  	must(os.WriteFile(filepath.Join(tmpDir, "a.html"), []byte(`<html><body>a page here</body></html>`), 0644))
    60  	wr = httptest.NewRecorder()
    61  	r, _ = http.NewRequest("GET", "/a.html", nil)
    62  	fs.ServeHTTP(wr, r)
    63  	checkStatus(t, r, wr.Result(), 200)
    64  	checkBody(t, r, wr.Result(), "a page here")
    65  	checkHeader(t, r, wr.Result(), "Content-Type", "text/html; charset=utf-8")
    66  
    67  	// /a should also serve a.html
    68  	wr = httptest.NewRecorder()
    69  	r, _ = http.NewRequest("GET", "/a", nil)
    70  	fs.ServeHTTP(wr, r)
    71  	checkStatus(t, r, wr.Result(), 200)
    72  	checkBody(t, r, wr.Result(), "a page here")
    73  	checkHeader(t, r, wr.Result(), "Content-Type", "text/html; charset=utf-8")
    74  
    75  	// not found should serve 404.html if present
    76  	must(os.WriteFile(filepath.Join(tmpDir, "404.html"), []byte(`<html><body>custom not found page here</body></html>`), 0644))
    77  	wr = httptest.NewRecorder()
    78  	r, _ = http.NewRequest("GET", "/ainthere", nil)
    79  	fs.ServeHTTP(wr, r)
    80  	checkStatus(t, r, wr.Result(), 404)
    81  	checkBody(t, r, wr.Result(), "custom not found page here")
    82  	checkHeader(t, r, wr.Result(), "Content-Type", "text/html; charset=utf-8")
    83  
    84  	// default not found
    85  	os.Remove(filepath.Join(tmpDir, "404.html"))
    86  	wr = httptest.NewRecorder()
    87  	r, _ = http.NewRequest("GET", "/ainthere", nil)
    88  	fs.ServeHTTP(wr, r)
    89  	checkStatus(t, r, wr.Result(), 404)
    90  	checkBody(t, r, wr.Result(), "404 page not found")
    91  
    92  	// custom not found
    93  	fs.SetNotFoundHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    94  		w.WriteHeader(403)
    95  		_, _ = w.Write([]byte("some other response here"))
    96  	}))
    97  	wr = httptest.NewRecorder()
    98  	r, _ = http.NewRequest("GET", "/ainthere", nil)
    99  	fs.ServeHTTP(wr, r)
   100  	checkStatus(t, r, wr.Result(), 403)
   101  	checkBody(t, r, wr.Result(), "some other response here")
   102  
   103  }
   104  
   105  func checkBody(t *testing.T, req *http.Request, res *http.Response, text string) {
   106  	b, err := httputil.DumpResponse(res, true)
   107  	if err != nil {
   108  		t.Logf("response dump failed: %v", err)
   109  		return
   110  	}
   111  	if !bytes.Contains(b, []byte(text)) {
   112  		t.Errorf("for %q expected response body to contain %q but it did not, full body: %s", req.URL.Path, text, b)
   113  	}
   114  
   115  }
   116  
   117  func checkStatus(t *testing.T, req *http.Request, res *http.Response, status int) {
   118  	st := res.StatusCode
   119  	if st != status {
   120  		t.Errorf("for %q expected status to be %v but got %v", req.URL.Path, status, st)
   121  	}
   122  }
   123  
   124  func checkHeader(t *testing.T, req *http.Request, res *http.Response, key, val string) {
   125  	hval := res.Header.Get(key)
   126  	if hval != val {
   127  		t.Errorf("for %q expected header %q to be %q but got %q", req.URL.Path, key, val, hval)
   128  	}
   129  }