code.gitea.io/gitea@v1.22.3/services/contexttest/context_tests.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  // Package contexttest provides utilities for testing Web/API contexts with models.
     5  package contexttest
     6  
     7  import (
     8  	gocontext "context"
     9  	"io"
    10  	"maps"
    11  	"net/http"
    12  	"net/http/httptest"
    13  	"net/url"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  
    18  	access_model "code.gitea.io/gitea/models/perm/access"
    19  	repo_model "code.gitea.io/gitea/models/repo"
    20  	"code.gitea.io/gitea/models/unittest"
    21  	user_model "code.gitea.io/gitea/models/user"
    22  	"code.gitea.io/gitea/modules/cache"
    23  	"code.gitea.io/gitea/modules/gitrepo"
    24  	"code.gitea.io/gitea/modules/session"
    25  	"code.gitea.io/gitea/modules/templates"
    26  	"code.gitea.io/gitea/modules/translation"
    27  	"code.gitea.io/gitea/modules/web/middleware"
    28  	"code.gitea.io/gitea/services/context"
    29  
    30  	"github.com/go-chi/chi/v5"
    31  	"github.com/stretchr/testify/assert"
    32  )
    33  
    34  func mockRequest(t *testing.T, reqPath string) *http.Request {
    35  	method, path, found := strings.Cut(reqPath, " ")
    36  	if !found {
    37  		method = "GET"
    38  		path = reqPath
    39  	}
    40  	requestURL, err := url.Parse(path)
    41  	assert.NoError(t, err)
    42  	req := &http.Request{Method: method, Host: requestURL.Host, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}}
    43  	req = req.WithContext(middleware.WithContextData(req.Context()))
    44  	return req
    45  }
    46  
    47  type MockContextOption struct {
    48  	Render       context.Render
    49  	SessionStore *session.MockStore
    50  }
    51  
    52  // MockContext mock context for unit tests
    53  func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*context.Context, *httptest.ResponseRecorder) {
    54  	var opt MockContextOption
    55  	if len(opts) > 0 {
    56  		opt = opts[0]
    57  	}
    58  	if opt.Render == nil {
    59  		opt.Render = &MockRender{}
    60  	}
    61  	resp := httptest.NewRecorder()
    62  	req := mockRequest(t, reqPath)
    63  	base, baseCleanUp := context.NewBaseContext(resp, req)
    64  	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later
    65  	base.Data = middleware.GetContextData(req.Context())
    66  	base.Locale = &translation.MockLocale{}
    67  
    68  	chiCtx := chi.NewRouteContext()
    69  	ctx := context.NewWebContext(base, opt.Render, nil)
    70  	ctx.AppendContextValue(context.WebContextKey, ctx)
    71  	ctx.AppendContextValue(chi.RouteCtxKey, chiCtx)
    72  	if opt.SessionStore != nil {
    73  		ctx.AppendContextValue(session.MockStoreContextKey, opt.SessionStore)
    74  		ctx.Session = opt.SessionStore
    75  	}
    76  	ctx.Cache = cache.GetCache()
    77  	ctx.PageData = map[string]any{}
    78  	ctx.Data["PageStartTime"] = time.Now()
    79  	return ctx, resp
    80  }
    81  
    82  // MockAPIContext mock context for unit tests
    83  func MockAPIContext(t *testing.T, reqPath string) (*context.APIContext, *httptest.ResponseRecorder) {
    84  	resp := httptest.NewRecorder()
    85  	req := mockRequest(t, reqPath)
    86  	base, baseCleanUp := context.NewBaseContext(resp, req)
    87  	base.Data = middleware.GetContextData(req.Context())
    88  	base.Locale = &translation.MockLocale{}
    89  	ctx := &context.APIContext{Base: base}
    90  	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later
    91  
    92  	chiCtx := chi.NewRouteContext()
    93  	ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx)
    94  	return ctx, resp
    95  }
    96  
    97  func MockPrivateContext(t *testing.T, reqPath string) (*context.PrivateContext, *httptest.ResponseRecorder) {
    98  	resp := httptest.NewRecorder()
    99  	req := mockRequest(t, reqPath)
   100  	base, baseCleanUp := context.NewBaseContext(resp, req)
   101  	base.Data = middleware.GetContextData(req.Context())
   102  	base.Locale = &translation.MockLocale{}
   103  	ctx := &context.PrivateContext{Base: base}
   104  	_ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later
   105  	chiCtx := chi.NewRouteContext()
   106  	ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx)
   107  	return ctx, resp
   108  }
   109  
   110  // LoadRepo load a repo into a test context.
   111  func LoadRepo(t *testing.T, ctx gocontext.Context, repoID int64) {
   112  	var doer *user_model.User
   113  	repo := &context.Repository{}
   114  	switch ctx := ctx.(type) {
   115  	case *context.Context:
   116  		ctx.Repo = repo
   117  		doer = ctx.Doer
   118  	case *context.APIContext:
   119  		ctx.Repo = repo
   120  		doer = ctx.Doer
   121  	default:
   122  		assert.FailNow(t, "context is not *context.Context or *context.APIContext")
   123  	}
   124  
   125  	repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
   126  	var err error
   127  	repo.Owner, err = user_model.GetUserByID(ctx, repo.Repository.OwnerID)
   128  	assert.NoError(t, err)
   129  	repo.RepoLink = repo.Repository.Link()
   130  	repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo.Repository, doer)
   131  	assert.NoError(t, err)
   132  }
   133  
   134  // LoadRepoCommit loads a repo's commit into a test context.
   135  func LoadRepoCommit(t *testing.T, ctx gocontext.Context) {
   136  	var repo *context.Repository
   137  	switch ctx := ctx.(type) {
   138  	case *context.Context:
   139  		repo = ctx.Repo
   140  	case *context.APIContext:
   141  		repo = ctx.Repo
   142  	default:
   143  		assert.FailNow(t, "context is not *context.Context or *context.APIContext")
   144  	}
   145  
   146  	gitRepo, err := gitrepo.OpenRepository(ctx, repo.Repository)
   147  	assert.NoError(t, err)
   148  	defer gitRepo.Close()
   149  	branch, err := gitRepo.GetHEADBranch()
   150  	assert.NoError(t, err)
   151  	assert.NotNil(t, branch)
   152  	if branch != nil {
   153  		repo.Commit, err = gitRepo.GetBranchCommit(branch.Name)
   154  		assert.NoError(t, err)
   155  	}
   156  }
   157  
   158  // LoadUser load a user into a test context
   159  func LoadUser(t *testing.T, ctx gocontext.Context, userID int64) {
   160  	doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
   161  	switch ctx := ctx.(type) {
   162  	case *context.Context:
   163  		ctx.Doer = doer
   164  	case *context.APIContext:
   165  		ctx.Doer = doer
   166  	default:
   167  		assert.FailNow(t, "context is not *context.Context or *context.APIContext")
   168  	}
   169  }
   170  
   171  // LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has
   172  // already been populated.
   173  func LoadGitRepo(t *testing.T, ctx *context.Context) {
   174  	assert.NoError(t, ctx.Repo.Repository.LoadOwner(ctx))
   175  	var err error
   176  	ctx.Repo.GitRepo, err = gitrepo.OpenRepository(ctx, ctx.Repo.Repository)
   177  	assert.NoError(t, err)
   178  }
   179  
   180  type MockRender struct{}
   181  
   182  func (tr *MockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) {
   183  	return nil, nil
   184  }
   185  
   186  func (tr *MockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error {
   187  	if resp, ok := w.(http.ResponseWriter); ok {
   188  		resp.WriteHeader(status)
   189  	}
   190  	return nil
   191  }