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