| // Copyright 2016 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | //go:build cgo | 
 |  | 
 | package app | 
 |  | 
 | import ( | 
 | 	"encoding/json" | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"mime/multipart" | 
 | 	"net/http" | 
 | 	"net/http/httptest" | 
 | 	"reflect" | 
 | 	"testing" | 
 | 	"time" | 
 |  | 
 | 	"golang.org/x/build/perfdata/db" | 
 | 	"golang.org/x/build/perfdata/db/dbtest" | 
 | 	_ "golang.org/x/build/perfdata/db/sqlite3" | 
 | 	"golang.org/x/build/perfdata/fs" | 
 | ) | 
 |  | 
 | type testApp struct { | 
 | 	db        *db.DB | 
 | 	dbCleanup func() | 
 | 	fs        *fs.MemFS | 
 | 	app       *App | 
 | 	srv       *httptest.Server | 
 | } | 
 |  | 
 | func (app *testApp) Close() { | 
 | 	app.dbCleanup() | 
 | 	app.srv.Close() | 
 | } | 
 |  | 
 | // createTestApp returns a testApp corresponding to a new app | 
 | // serving from an in-memory database and file system on an | 
 | // isolated test HTTP server. | 
 | // | 
 | // When finished with app, the caller must call app.Close(). | 
 | func createTestApp(t *testing.T) *testApp { | 
 | 	db, cleanup := dbtest.NewDB(t) | 
 |  | 
 | 	fs := fs.NewMemFS() | 
 |  | 
 | 	app := &App{ | 
 | 		DB:          db, | 
 | 		FS:          fs, | 
 | 		Auth:        func(http.ResponseWriter, *http.Request) (string, error) { return "user", nil }, | 
 | 		ViewURLBase: "view:", | 
 | 	} | 
 |  | 
 | 	mux := http.NewServeMux() | 
 | 	app.RegisterOnMux(mux) | 
 |  | 
 | 	srv := httptest.NewServer(mux) | 
 |  | 
 | 	return &testApp{db, cleanup, fs, app, srv} | 
 | } | 
 |  | 
 | // uploadFiles calls the /upload endpoint and executes f in a new | 
 | // goroutine to write files to the POST request. | 
 | func (app *testApp) uploadFiles(t *testing.T, f func(*multipart.Writer)) *uploadStatus { | 
 | 	pr, pw := io.Pipe() | 
 | 	mpw := multipart.NewWriter(pw) | 
 |  | 
 | 	go func() { | 
 | 		defer pw.Close() | 
 | 		defer mpw.Close() | 
 | 		f(mpw) | 
 | 	}() | 
 |  | 
 | 	resp, err := http.Post(app.srv.URL+"/upload", mpw.FormDataContentType(), pr) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	defer resp.Body.Close() | 
 | 	if resp.StatusCode != 200 { | 
 | 		t.Fatalf("post /upload: %v", resp.Status) | 
 | 	} | 
 | 	body, err := io.ReadAll(resp.Body) | 
 | 	if err != nil { | 
 | 		t.Fatalf("reading /upload response: %v", err) | 
 | 	} | 
 | 	t.Logf("/upload response:\n%s", body) | 
 |  | 
 | 	status := &uploadStatus{} | 
 | 	if err := json.Unmarshal(body, status); err != nil { | 
 | 		t.Fatalf("unmarshaling /upload response: %v", err) | 
 | 	} | 
 | 	return status | 
 | } | 
 |  | 
 | func TestUpload(t *testing.T) { | 
 | 	app := createTestApp(t) | 
 | 	defer app.Close() | 
 |  | 
 | 	wantID := time.Now().UTC().Format("20060102.") + "1" | 
 |  | 
 | 	status := app.uploadFiles(t, func(mpw *multipart.Writer) { | 
 | 		w, err := mpw.CreateFormFile("file", "1.txt") | 
 | 		if err != nil { | 
 | 			t.Errorf("CreateFormFile: %v", err) | 
 | 		} | 
 | 		fmt.Fprintf(w, "key: value\nBenchmarkOne 5 ns/op\nkey:value2\nBenchmarkTwo 10 ns/op\n") | 
 | 	}) | 
 |  | 
 | 	if status.UploadID != wantID { | 
 | 		t.Errorf("uploadid = %q, want %q", status.UploadID, wantID) | 
 | 	} | 
 | 	if have, want := status.FileIDs, []string{wantID + "/0"}; !reflect.DeepEqual(have, want) { | 
 | 		t.Errorf("fileids = %v, want %v", have, want) | 
 | 	} | 
 | 	if want := "view:" + wantID; status.ViewURL != want { | 
 | 		t.Errorf("viewurl = %q, want %q", status.ViewURL, want) | 
 | 	} | 
 |  | 
 | 	if len(app.fs.Files()) != 1 { | 
 | 		t.Errorf("/upload wrote %d files, want 1", len(app.fs.Files())) | 
 | 	} | 
 | } |