code.gitea.io/gitea@v1.21.7/tests/integration/api_comment_test.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package integration
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"net/url"
    10  	"testing"
    11  
    12  	auth_model "code.gitea.io/gitea/models/auth"
    13  	"code.gitea.io/gitea/models/db"
    14  	issues_model "code.gitea.io/gitea/models/issues"
    15  	repo_model "code.gitea.io/gitea/models/repo"
    16  	"code.gitea.io/gitea/models/unittest"
    17  	user_model "code.gitea.io/gitea/models/user"
    18  	api "code.gitea.io/gitea/modules/structs"
    19  	"code.gitea.io/gitea/services/convert"
    20  	"code.gitea.io/gitea/tests"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  func TestAPIListRepoComments(t *testing.T) {
    26  	defer tests.PrepareTestEnv(t)()
    27  
    28  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
    29  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
    30  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
    31  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
    32  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
    33  
    34  	link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments", repoOwner.Name, repo.Name))
    35  	req := NewRequest(t, "GET", link.String())
    36  	resp := MakeRequest(t, req, http.StatusOK)
    37  
    38  	var apiComments []*api.Comment
    39  	DecodeJSON(t, resp, &apiComments)
    40  	assert.Len(t, apiComments, 2)
    41  	for _, apiComment := range apiComments {
    42  		c := &issues_model.Comment{ID: apiComment.ID}
    43  		unittest.AssertExistsAndLoadBean(t, c,
    44  			unittest.Cond("type = ?", issues_model.CommentTypeComment))
    45  		unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: c.IssueID, RepoID: repo.ID})
    46  	}
    47  
    48  	// test before and since filters
    49  	query := url.Values{}
    50  	before := "2000-01-01T00:00:11+00:00" // unix: 946684811
    51  	since := "2000-01-01T00:00:12+00:00"  // unix: 946684812
    52  	query.Add("before", before)
    53  	link.RawQuery = query.Encode()
    54  	req = NewRequest(t, "GET", link.String())
    55  	resp = MakeRequest(t, req, http.StatusOK)
    56  	DecodeJSON(t, resp, &apiComments)
    57  	assert.Len(t, apiComments, 1)
    58  	assert.EqualValues(t, 2, apiComments[0].ID)
    59  
    60  	query.Del("before")
    61  	query.Add("since", since)
    62  	link.RawQuery = query.Encode()
    63  	req = NewRequest(t, "GET", link.String())
    64  	resp = MakeRequest(t, req, http.StatusOK)
    65  	DecodeJSON(t, resp, &apiComments)
    66  	assert.Len(t, apiComments, 1)
    67  	assert.EqualValues(t, 3, apiComments[0].ID)
    68  }
    69  
    70  func TestAPIListIssueComments(t *testing.T) {
    71  	defer tests.PrepareTestEnv(t)()
    72  
    73  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{},
    74  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
    75  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
    76  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
    77  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
    78  
    79  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeReadIssue)
    80  	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
    81  		repoOwner.Name, repo.Name, issue.Index, token)
    82  	resp := MakeRequest(t, req, http.StatusOK)
    83  
    84  	var comments []*api.Comment
    85  	DecodeJSON(t, resp, &comments)
    86  	expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID},
    87  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
    88  	assert.Len(t, comments, expectedCount)
    89  }
    90  
    91  func TestAPICreateComment(t *testing.T) {
    92  	defer tests.PrepareTestEnv(t)()
    93  	const commentBody = "Comment body"
    94  
    95  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
    96  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
    97  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
    98  
    99  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   100  	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
   101  		repoOwner.Name, repo.Name, issue.Index, token)
   102  	req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
   103  		"body": commentBody,
   104  	})
   105  	resp := MakeRequest(t, req, http.StatusCreated)
   106  
   107  	var updatedComment api.Comment
   108  	DecodeJSON(t, resp, &updatedComment)
   109  	assert.EqualValues(t, commentBody, updatedComment.Body)
   110  	unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: updatedComment.ID, IssueID: issue.ID, Content: commentBody})
   111  }
   112  
   113  func TestAPIGetComment(t *testing.T) {
   114  	defer tests.PrepareTestEnv(t)()
   115  
   116  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2})
   117  	assert.NoError(t, comment.LoadIssue(db.DefaultContext))
   118  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID})
   119  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   120  
   121  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeReadIssue)
   122  	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID)
   123  	MakeRequest(t, req, http.StatusOK)
   124  	req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s", repoOwner.Name, repo.Name, comment.ID, token)
   125  	resp := MakeRequest(t, req, http.StatusOK)
   126  
   127  	var apiComment api.Comment
   128  	DecodeJSON(t, resp, &apiComment)
   129  
   130  	assert.NoError(t, comment.LoadPoster(db.DefaultContext))
   131  	expect := convert.ToAPIComment(db.DefaultContext, repo, comment)
   132  
   133  	assert.Equal(t, expect.ID, apiComment.ID)
   134  	assert.Equal(t, expect.Poster.FullName, apiComment.Poster.FullName)
   135  	assert.Equal(t, expect.Body, apiComment.Body)
   136  	assert.Equal(t, expect.Created.Unix(), apiComment.Created.Unix())
   137  }
   138  
   139  func TestAPIGetSystemUserComment(t *testing.T) {
   140  	defer tests.PrepareTestEnv(t)()
   141  
   142  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{})
   143  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   144  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   145  
   146  	for _, systemUser := range []*user_model.User{
   147  		user_model.NewGhostUser(),
   148  		user_model.NewActionsUser(),
   149  	} {
   150  		body := fmt.Sprintf("Hello %s", systemUser.Name)
   151  		comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{
   152  			Type:    issues_model.CommentTypeComment,
   153  			Doer:    systemUser,
   154  			Repo:    repo,
   155  			Issue:   issue,
   156  			Content: body,
   157  		})
   158  		assert.NoError(t, err)
   159  
   160  		req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/comments/%d", repoOwner.Name, repo.Name, comment.ID)
   161  		resp := MakeRequest(t, req, http.StatusOK)
   162  
   163  		var apiComment api.Comment
   164  		DecodeJSON(t, resp, &apiComment)
   165  
   166  		if assert.NotNil(t, apiComment.Poster) {
   167  			if assert.Equal(t, systemUser.ID, apiComment.Poster.ID) {
   168  				assert.NoError(t, comment.LoadPoster(db.DefaultContext))
   169  				assert.Equal(t, systemUser.Name, apiComment.Poster.UserName)
   170  			}
   171  		}
   172  		assert.Equal(t, body, apiComment.Body)
   173  	}
   174  }
   175  
   176  func TestAPIEditComment(t *testing.T) {
   177  	defer tests.PrepareTestEnv(t)()
   178  	const newCommentBody = "This is the new comment body"
   179  
   180  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 8},
   181  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
   182  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
   183  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   184  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   185  
   186  	t.Run("UnrelatedCommentID", func(t *testing.T) {
   187  		// Using the ID of a comment that does not belong to the repository must fail
   188  		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
   189  		repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   190  		token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   191  		urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
   192  			repoOwner.Name, repo.Name, comment.ID, token)
   193  		req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
   194  			"body": newCommentBody,
   195  		})
   196  		MakeRequest(t, req, http.StatusNotFound)
   197  	})
   198  
   199  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   200  	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
   201  		repoOwner.Name, repo.Name, comment.ID, token)
   202  	req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
   203  		"body": newCommentBody,
   204  	})
   205  	resp := MakeRequest(t, req, http.StatusOK)
   206  
   207  	var updatedComment api.Comment
   208  	DecodeJSON(t, resp, &updatedComment)
   209  	assert.EqualValues(t, comment.ID, updatedComment.ID)
   210  	assert.EqualValues(t, newCommentBody, updatedComment.Body)
   211  	unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID, IssueID: issue.ID, Content: newCommentBody})
   212  }
   213  
   214  func TestAPIDeleteComment(t *testing.T) {
   215  	defer tests.PrepareTestEnv(t)()
   216  
   217  	comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 8},
   218  		unittest.Cond("type = ?", issues_model.CommentTypeComment))
   219  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID})
   220  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   221  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   222  
   223  	t.Run("UnrelatedCommentID", func(t *testing.T) {
   224  		// Using the ID of a comment that does not belong to the repository must fail
   225  		repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
   226  		repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   227  		token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   228  		req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
   229  			repoOwner.Name, repo.Name, comment.ID, token)
   230  		MakeRequest(t, req, http.StatusNotFound)
   231  	})
   232  
   233  	token := getUserToken(t, repoOwner.Name, auth_model.AccessTokenScopeWriteIssue)
   234  	req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
   235  		repoOwner.Name, repo.Name, comment.ID, token)
   236  	MakeRequest(t, req, http.StatusNoContent)
   237  
   238  	unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: comment.ID})
   239  }
   240  
   241  func TestAPIListIssueTimeline(t *testing.T) {
   242  	defer tests.PrepareTestEnv(t)()
   243  
   244  	// load comment
   245  	issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1})
   246  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID})
   247  	repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
   248  
   249  	// make request
   250  	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/timeline",
   251  		repoOwner.Name, repo.Name, issue.Index)
   252  	resp := MakeRequest(t, req, http.StatusOK)
   253  
   254  	// check if lens of list returned by API and
   255  	// lists extracted directly from DB are the same
   256  	var comments []*api.TimelineComment
   257  	DecodeJSON(t, resp, &comments)
   258  	expectedCount := unittest.GetCount(t, &issues_model.Comment{IssueID: issue.ID})
   259  	assert.Len(t, comments, expectedCount)
   260  }