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  }