blob: 53cdef8723877022d26ff815479ea1a9c81ed2a7 [file] [log] [blame]
/*
Test utilities for mocking the V2 frontend.
*/
package frontend
import (
"encoding/json"
"net/http"
"net/http/httptest"
"sync"
"go.skia.org/infra/ct/go/ctfe/pending_tasks"
"go.skia.org/infra/ct/go/ctfe/task_common"
ctfeutil "go.skia.org/infra/ct/go/ctfe/util"
"go.skia.org/infra/go/httputils"
skutil "go.skia.org/infra/go/util"
"go.skia.org/infra/go/webhook"
)
// UpdateTaskReq includes the URL of an update request, the unmarshaled body, and any error
// encountered.
type UpdateTaskReq struct {
Url string
Vars task_common.UpdateTaskCommonVars
Error error
}
// MockServer implements http.Handler and can be given a task with which to respond to
// ctfeutil.GET_OLDEST_PENDING_TASK_URI. It also collects any other requests and attempts to parse
// the body as task_common.UpdateTaskCommonVars JSON. Safe for use in multiple goroutines.
// Example usage:
// mockServer := MockServer{}
// mockServer.SetCurrentTask(&admin_tasks.RecreateWebpageArchivesDBTask{...})
// defer CloseTestServer(InitTestServer(&mockServer))
// ...
// expect.Equal(t, 1, mockServer.OldestPendingTaskReqCount())
// assert.Len(t, mockServer.UpdateTaskReqs(), 1)
// updateReq := mockServer.UpdateTaskReqs()[0]
// expect.Equal(t, "/"+ctfeutil.UPDATE_RECREATE_WEBPAGE_ARCHIVES_TASK_POST_URI, updateReq.Url)
// expect.NoError(t, updateReq.Error)
// expect.Equal(t, int64(42), updateReq.Vars.Id)
// ...
type MockServer struct {
mutex sync.RWMutex
currentTask task_common.Task
oldestPendingTaskReqCount int
updateTaskReqs []UpdateTaskReq
}
// SetCurrentTask provides the Task to be returned for a ctfeutil.GET_OLDEST_PENDING_TASK_URI
// request.
func (ms *MockServer) SetCurrentTask(currentTask task_common.Task) {
ms.mutex.Lock()
defer ms.mutex.Unlock()
ms.currentTask = currentTask
}
func (ms *MockServer) OldestPendingTaskReqCount() int {
ms.mutex.RLock()
defer ms.mutex.RUnlock()
return ms.oldestPendingTaskReqCount
}
// Returns all update requests seen thus far.
func (ms *MockServer) UpdateTaskReqs() []UpdateTaskReq {
ms.mutex.RLock()
defer ms.mutex.RUnlock()
// TODO(benjaminwagner): Can I just return ms.updateTaskReqs?
result := make([]UpdateTaskReq, len(ms.updateTaskReqs))
copy(result, ms.updateTaskReqs)
return result
}
func (ms *MockServer) HandleGetOldestPendingTask(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
ms.mutex.Lock()
defer ms.mutex.Unlock()
ms.oldestPendingTaskReqCount++
if err := pending_tasks.EncodeTask(w, ms.currentTask); err != nil {
httputils.ReportError(w, r, err, "Failed to encode JSON")
return
}
}
func (ms *MockServer) HandleUpdateTask(w http.ResponseWriter, r *http.Request) {
updateTaskReq := UpdateTaskReq{Url: r.URL.Path}
data, err := webhook.AuthenticateRequest(r)
defer skutil.Close(r.Body)
if err != nil {
updateTaskReq.Error = err
httputils.ReportError(w, r, err, "")
return
}
err = json.Unmarshal(data, &updateTaskReq.Vars)
if err != nil {
updateTaskReq.Error = err
httputils.ReportError(w, r, err, "")
return
}
w.Header().Set("Content-Type", "application/json")
ms.mutex.Lock()
defer ms.mutex.Unlock()
ms.updateTaskReqs = append(ms.updateTaskReqs, updateTaskReq)
}
func (ms *MockServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/"+ctfeutil.GET_OLDEST_PENDING_TASK_URI {
ms.HandleGetOldestPendingTask(w, r)
} else {
ms.HandleUpdateTask(w, r)
}
}
// Creates an httptest.Server using h as its handler and calls Init to ensure
// GetOldestPendingTaskV2 and UpdateWebappTaskV2 use the test server. Also calls
// InitForTesting. Can be used as "defer CloseTestServer(InitTestServer(h))".
func InitTestServer(h http.Handler) *httptest.Server {
ts := httptest.NewServer(h)
InitForTesting(ts.URL + "/")
return ts
}
// Closes ts, resets CtfeV2, and resets the webapp Url for GetOldestPendingTaskV2 and
// UpdateWebappTaskV2. Can be used as "defer CloseTestServer(InitTestServer(h))".
func CloseTestServer(ts *httptest.Server) {
ts.Close()
InitForTesting(WEBAPP_ROOT_V2)
}