Commit 72f847b9 authored by Quentin Smith's avatar Quentin Smith

storage: report a view URL in /upload responses if configured

Change-Id: I5e10082adc66e51898a71e1a67da7833f287af9d
Reviewed-on: https://go-review.googlesource.com/35067Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 3c74c699
...@@ -25,6 +25,11 @@ type App struct { ...@@ -25,6 +25,11 @@ type App struct {
// If necessary, it can write its own response (e.g. a // If necessary, it can write its own response (e.g. a
// redirect) and return ErrResponseWritten. // redirect) and return ErrResponseWritten.
Auth func(http.ResponseWriter, *http.Request) (string, error) Auth func(http.ResponseWriter, *http.Request) (string, error)
// ViewURLBase will be used to construct a URL to return as
// "viewurl" in the response from /upload. If it is non-empty,
// the upload ID will be appended to ViewURLBase.
ViewURLBase string
} }
// ErrResponseWritten can be returned by App.Auth to abort the normal /upload handling. // ErrResponseWritten can be returned by App.Auth to abort the normal /upload handling.
......
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"io" "io"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"net/url"
"sort" "sort"
"golang.org/x/net/context" "golang.org/x/net/context"
...@@ -71,6 +72,8 @@ type uploadStatus struct { ...@@ -71,6 +72,8 @@ type uploadStatus struct {
UploadID string `json:"uploadid"` UploadID string `json:"uploadid"`
// FileIDs is the list of file IDs assigned to the files in the upload. // FileIDs is the list of file IDs assigned to the files in the upload.
FileIDs []string `json:"fileids"` FileIDs []string `json:"fileids"`
// ViewURL is a URL that can be used to interactively view the upload.
ViewURL string `json:"viewurl,omitempty"`
} }
// processUpload takes one or more files from a multipart.Reader, // processUpload takes one or more files from a multipart.Reader,
...@@ -118,7 +121,12 @@ func (a *App) processUpload(ctx context.Context, user string, mr *multipart.Read ...@@ -118,7 +121,12 @@ func (a *App) processUpload(ctx context.Context, user string, mr *multipart.Read
fileids = append(fileids, meta["fileid"]) fileids = append(fileids, meta["fileid"])
} }
return &uploadStatus{upload.ID, fileids}, nil status := &uploadStatus{UploadID: upload.ID, FileIDs: fileids}
if a.ViewURLBase != "" {
status.ViewURL = a.ViewURLBase + url.QueryEscape(upload.ID)
}
return status, nil
} }
func (a *App) indexFile(ctx context.Context, upload *db.Upload, p io.Reader, meta map[string]string) (err error) { func (a *App) indexFile(ctx context.Context, upload *db.Upload, p io.Reader, meta map[string]string) (err error) {
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"reflect"
"testing" "testing"
"golang.org/x/perf/storage/db" "golang.org/x/perf/storage/db"
...@@ -47,6 +48,7 @@ func createTestApp(t *testing.T) *testApp { ...@@ -47,6 +48,7 @@ func createTestApp(t *testing.T) *testApp {
DB: db, DB: db,
FS: fs, FS: fs,
Auth: func(http.ResponseWriter, *http.Request) (string, error) { return "user", nil }, Auth: func(http.ResponseWriter, *http.Request) (string, error) { return "user", nil },
ViewURLBase: "view:",
} }
mux := http.NewServeMux() mux := http.NewServeMux()
...@@ -94,7 +96,7 @@ func TestUpload(t *testing.T) { ...@@ -94,7 +96,7 @@ func TestUpload(t *testing.T) {
app := createTestApp(t) app := createTestApp(t)
defer app.Close() defer app.Close()
app.uploadFiles(t, func(mpw *multipart.Writer) { status := app.uploadFiles(t, func(mpw *multipart.Writer) {
w, err := mpw.CreateFormFile("file", "1.txt") w, err := mpw.CreateFormFile("file", "1.txt")
if err != nil { if err != nil {
t.Errorf("CreateFormFile: %v", err) t.Errorf("CreateFormFile: %v", err)
...@@ -102,6 +104,16 @@ func TestUpload(t *testing.T) { ...@@ -102,6 +104,16 @@ func TestUpload(t *testing.T) {
fmt.Fprintf(w, "key: value\nBenchmarkOne 5 ns/op\nkey:value2\nBenchmarkTwo 10 ns/op\n") fmt.Fprintf(w, "key: value\nBenchmarkOne 5 ns/op\nkey:value2\nBenchmarkTwo 10 ns/op\n")
}) })
if status.UploadID != "1" {
t.Errorf("uploadid = %q, want %q", status.UploadID, "1")
}
if have, want := status.FileIDs, []string{"1/0"}; !reflect.DeepEqual(have, want) {
t.Errorf("fileids = %v, want %v", have, want)
}
if status.ViewURL != "view:1" {
t.Errorf("viewurl = %q, want %q", status.ViewURL, "view:1")
}
if len(app.fs.Files()) != 1 { if len(app.fs.Files()) != 1 {
t.Errorf("/upload wrote %d files, want 1", len(app.fs.Files())) t.Errorf("/upload wrote %d files, want 1", len(app.fs.Files()))
} }
......
...@@ -65,7 +65,8 @@ func auth(w http.ResponseWriter, r *http.Request) (string, error) { ...@@ -65,7 +65,8 @@ func auth(w http.ResponseWriter, r *http.Request) (string, error) {
// It creates a new App instance using the appengine Context and then // It creates a new App instance using the appengine Context and then
// dispatches the request to the App. The environment variable // dispatches the request to the App. The environment variable
// GCS_BUCKET must be set in app.yaml with the name of the bucket to // GCS_BUCKET must be set in app.yaml with the name of the bucket to
// write to. // write to. PERFDATA_VIEW_URL_BASE may be set to the URL that should
// be supplied in /upload responses.
func appHandler(w http.ResponseWriter, r *http.Request) { func appHandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r) ctx := appengine.NewContext(r)
// GCS clients need to be constructed with an AppEngine // GCS clients need to be constructed with an AppEngine
...@@ -88,7 +89,7 @@ func appHandler(w http.ResponseWriter, r *http.Request) { ...@@ -88,7 +89,7 @@ func appHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
mux := http.NewServeMux() mux := http.NewServeMux()
app := &app.App{DB: db, FS: fs, Auth: auth} app := &app.App{DB: db, FS: fs, Auth: auth, ViewURLBase: os.Getenv("PERFDATA_VIEW_URL_BASE")}
app.RegisterOnMux(mux) app.RegisterOnMux(mux)
mux.ServeHTTP(w, r) mux.ServeHTTP(w, r)
} }
......
...@@ -21,3 +21,4 @@ env_variables: ...@@ -21,3 +21,4 @@ env_variables:
CLOUDSQL_PASSWORD: '' CLOUDSQL_PASSWORD: ''
CLOUDSQL_DATABASE: perfdata CLOUDSQL_DATABASE: perfdata
GCS_BUCKET: golang-perfdata GCS_BUCKET: golang-perfdata
PERFDATA_VIEW_URL_BASE: https://perf.golang.org/search?q=uploadid:
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment