github.com/jgbaldwinbrown/perf@v0.1.1/storage/app/upload_test.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build cgo 6 // +build cgo 7 8 package app 9 10 import ( 11 "encoding/json" 12 "fmt" 13 "io" 14 "mime/multipart" 15 "net/http" 16 "net/http/httptest" 17 "reflect" 18 "testing" 19 "time" 20 21 "golang.org/x/perf/storage/db" 22 "golang.org/x/perf/storage/db/dbtest" 23 _ "golang.org/x/perf/storage/db/sqlite3" 24 "golang.org/x/perf/storage/fs" 25 ) 26 27 type testApp struct { 28 db *db.DB 29 dbCleanup func() 30 fs *fs.MemFS 31 app *App 32 srv *httptest.Server 33 } 34 35 func (app *testApp) Close() { 36 app.dbCleanup() 37 app.srv.Close() 38 } 39 40 // createTestApp returns a testApp corresponding to a new app 41 // serving from an in-memory database and file system on an 42 // isolated test HTTP server. 43 // 44 // When finished with app, the caller must call app.Close(). 45 func createTestApp(t *testing.T) *testApp { 46 db, cleanup := dbtest.NewDB(t) 47 48 fs := fs.NewMemFS() 49 50 app := &App{ 51 DB: db, 52 FS: fs, 53 Auth: func(http.ResponseWriter, *http.Request) (string, error) { return "user", nil }, 54 ViewURLBase: "view:", 55 } 56 57 mux := http.NewServeMux() 58 app.RegisterOnMux(mux) 59 60 srv := httptest.NewServer(mux) 61 62 return &testApp{db, cleanup, fs, app, srv} 63 } 64 65 // uploadFiles calls the /upload endpoint and executes f in a new 66 // goroutine to write files to the POST request. 67 func (app *testApp) uploadFiles(t *testing.T, f func(*multipart.Writer)) *uploadStatus { 68 pr, pw := io.Pipe() 69 mpw := multipart.NewWriter(pw) 70 71 go func() { 72 defer pw.Close() 73 defer mpw.Close() 74 f(mpw) 75 }() 76 77 resp, err := http.Post(app.srv.URL+"/upload", mpw.FormDataContentType(), pr) 78 if err != nil { 79 t.Fatal(err) 80 } 81 defer resp.Body.Close() 82 if resp.StatusCode != 200 { 83 t.Fatalf("post /upload: %v", resp.Status) 84 } 85 body, err := io.ReadAll(resp.Body) 86 if err != nil { 87 t.Fatalf("reading /upload response: %v", err) 88 } 89 t.Logf("/upload response:\n%s", body) 90 91 status := &uploadStatus{} 92 if err := json.Unmarshal(body, status); err != nil { 93 t.Fatalf("unmarshaling /upload response: %v", err) 94 } 95 return status 96 } 97 98 func TestUpload(t *testing.T) { 99 app := createTestApp(t) 100 defer app.Close() 101 102 wantID := time.Now().UTC().Format("20060102.") + "1" 103 104 status := app.uploadFiles(t, func(mpw *multipart.Writer) { 105 w, err := mpw.CreateFormFile("file", "1.txt") 106 if err != nil { 107 t.Errorf("CreateFormFile: %v", err) 108 } 109 fmt.Fprintf(w, "key: value\nBenchmarkOne 5 ns/op\nkey:value2\nBenchmarkTwo 10 ns/op\n") 110 }) 111 112 if status.UploadID != wantID { 113 t.Errorf("uploadid = %q, want %q", status.UploadID, wantID) 114 } 115 if have, want := status.FileIDs, []string{wantID + "/0"}; !reflect.DeepEqual(have, want) { 116 t.Errorf("fileids = %v, want %v", have, want) 117 } 118 if want := "view:" + wantID; status.ViewURL != want { 119 t.Errorf("viewurl = %q, want %q", status.ViewURL, want) 120 } 121 122 if len(app.fs.Files()) != 1 { 123 t.Errorf("/upload wrote %d files, want 1", len(app.fs.Files())) 124 } 125 }