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  }