208 lines · 6.3 KB · Go
RawDownload
// Copyright 2017 The Gitea Authors. All rights reserved.// SPDX-License-Identifier: MIT // Package contexttest provides utilities for testing Web/API contexts with models.package contexttest import (	gocontext "context"	"io"	"maps"	"net/http"	"net/http/httptest"	"net/url"	"strings"	"testing"	"time" 	org_model "forgejo.org/models/organization"	access_model "forgejo.org/models/perm/access"	repo_model "forgejo.org/models/repo"	"forgejo.org/models/unittest"	user_model "forgejo.org/models/user"	"forgejo.org/modules/gitrepo"	"forgejo.org/modules/templates"	"forgejo.org/modules/translation"	"forgejo.org/modules/web/middleware"	"forgejo.org/services/context" 	"github.com/go-chi/chi/v5"	"github.com/stretchr/testify/assert"	"github.com/stretchr/testify/require") func mockRequest(t *testing.T, reqPath string) *http.Request {	method, path, found := strings.Cut(reqPath, " ")	if !found {		method = "GET"		path = reqPath	}	requestURL, err := url.Parse(path)	require.NoError(t, err)	req := &http.Request{Method: method, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}}	req = req.WithContext(middleware.WithContextData(req.Context()))	return req} type MockContextOption struct {	Render context.Render} // MockContext mock context for unit testsfunc MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*context.Context, *httptest.ResponseRecorder) {	var opt MockContextOption	if len(opts) > 0 {		opt = opts[0]	}	if opt.Render == nil {		opt.Render = &MockRender{}	}	resp := httptest.NewRecorder()	req := mockRequest(t, reqPath)	base, baseCleanUp := context.NewBaseContext(resp, req)	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later	base.Data = middleware.GetContextData(req.Context())	base.Locale = &translation.MockLocale{} 	ctx := context.NewWebContext(base, opt.Render, nil)	ctx.PageData = map[string]any{}	ctx.Data["PageStartTime"] = time.Now()	chiCtx := chi.NewRouteContext()	ctx.AppendContextValue(chi.RouteCtxKey, chiCtx)	return ctx, resp} // MockAPIContext mock context for unit testsfunc MockAPIContext(t *testing.T, reqPath string) (*context.APIContext, *httptest.ResponseRecorder) {	resp := httptest.NewRecorder()	req := mockRequest(t, reqPath)	base, baseCleanUp := context.NewBaseContext(resp, req)	base.Data = middleware.GetContextData(req.Context())	base.Locale = &translation.MockLocale{}	ctx := &context.APIContext{Base: base}	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later 	chiCtx := chi.NewRouteContext()	ctx.AppendContextValue(chi.RouteCtxKey, chiCtx)	return ctx, resp} func MockPrivateContext(t *testing.T, reqPath string) (*context.PrivateContext, *httptest.ResponseRecorder) {	resp := httptest.NewRecorder()	req := mockRequest(t, reqPath)	base, baseCleanUp := context.NewBaseContext(resp, req)	base.Data = middleware.GetContextData(req.Context())	base.Locale = &translation.MockLocale{}	ctx := &context.PrivateContext{Base: base}	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later	chiCtx := chi.NewRouteContext()	ctx.AppendContextValue(chi.RouteCtxKey, chiCtx)	return ctx, resp} // LoadRepo load a repo into a test context.func LoadRepo(t *testing.T, ctx gocontext.Context, repoID int64) {	var doer *user_model.User	repo := &context.Repository{}	switch ctx := ctx.(type) {	case *context.Context:		ctx.Repo = repo		doer = ctx.Doer	case *context.APIContext:		ctx.Repo = repo		doer = ctx.Doer	default:		assert.FailNow(t, "context is not *context.Context or *context.APIContext")	} 	repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})	var err error	repo.Owner, err = user_model.GetUserByID(ctx, repo.Repository.OwnerID)	require.NoError(t, err)	repo.RepoLink = repo.Repository.Link()	repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo.Repository, doer)	require.NoError(t, err)} // LoadRepoCommit loads a repo's commit into a test context.func LoadRepoCommit(t *testing.T, ctx gocontext.Context) {	var repo *context.Repository	switch ctx := ctx.(type) {	case *context.Context:		repo = ctx.Repo	case *context.APIContext:		repo = ctx.Repo	default:		assert.FailNow(t, "context is not *context.Context or *context.APIContext")	} 	if repo.GitRepo == nil {		assert.FailNow(t, "must call LoadGitRepo")	} 	branch, err := repo.GitRepo.GetHEADBranch()	require.NoError(t, err)	assert.NotNil(t, branch)	if branch != nil {		repo.Commit, err = repo.GitRepo.GetBranchCommit(branch.Name)		require.NoError(t, err)	}} // LoadUser load a user into a test contextfunc LoadUser(t *testing.T, ctx gocontext.Context, userID int64) {	doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})	switch ctx := ctx.(type) {	case *context.Context:		ctx.Doer = doer	case *context.APIContext:		ctx.Doer = doer	default:		assert.FailNow(t, "context is not *context.Context or *context.APIContext")	}} // LoadOrganization load an org into a test contextfunc LoadOrganization(t *testing.T, ctx gocontext.Context, orgID int64) {	org := unittest.AssertExistsAndLoadBean(t, &org_model.Organization{ID: orgID})	switch ctx := ctx.(type) {	case *context.Context:		ctx.Org.Organization = org	case *context.APIContext:		ctx.Org.Organization = org	default:		assert.FailNow(t, "context is not *context.Context or *context.APIContext")	}} // LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has// already been populated.func LoadGitRepo(t *testing.T, ctx gocontext.Context) {	var repo *context.Repository	switch ctx := ctx.(type) {	case *context.Context:		repo = ctx.Repo	case *context.APIContext:		repo = ctx.Repo	default:		assert.FailNow(t, "context is not *context.Context or *context.APIContext")	} 	require.NoError(t, repo.Repository.LoadOwner(ctx))	var err error	repo.GitRepo, err = gitrepo.OpenRepository(ctx, repo.Repository)	require.NoError(t, err)} type MockRender struct{} func (tr *MockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) {	return nil, nil} func (tr *MockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error {	if resp, ok := w.(http.ResponseWriter); ok {		resp.WriteHeader(status)	}	return nil}