code.gitea.io/gitea@v1.22.3/tests/integration/api_repo_topic_test.go (about)

     1  // Copyright 2019 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  	repo_model "code.gitea.io/gitea/models/repo"
    14  	"code.gitea.io/gitea/models/unittest"
    15  	user_model "code.gitea.io/gitea/models/user"
    16  	api "code.gitea.io/gitea/modules/structs"
    17  	"code.gitea.io/gitea/tests"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func TestAPITopicSearch(t *testing.T) {
    23  	defer tests.PrepareTestEnv(t)()
    24  	searchURL, _ := url.Parse("/api/v1/topics/search")
    25  	var topics struct {
    26  		TopicNames []*api.TopicResponse `json:"topics"`
    27  	}
    28  
    29  	// search all topics
    30  	res := MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
    31  	DecodeJSON(t, res, &topics)
    32  	assert.Len(t, topics.TopicNames, 6)
    33  	assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
    34  
    35  	// pagination search topics first page
    36  	topics.TopicNames = nil
    37  	query := url.Values{"page": []string{"1"}, "limit": []string{"4"}}
    38  
    39  	searchURL.RawQuery = query.Encode()
    40  	res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
    41  	DecodeJSON(t, res, &topics)
    42  	assert.Len(t, topics.TopicNames, 4)
    43  	assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
    44  
    45  	// pagination search topics second page
    46  	topics.TopicNames = nil
    47  	query = url.Values{"page": []string{"2"}, "limit": []string{"4"}}
    48  
    49  	searchURL.RawQuery = query.Encode()
    50  	res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
    51  	DecodeJSON(t, res, &topics)
    52  	assert.Len(t, topics.TopicNames, 2)
    53  	assert.EqualValues(t, "6", res.Header().Get("x-total-count"))
    54  
    55  	// add keyword search
    56  	query = url.Values{"page": []string{"1"}, "limit": []string{"4"}}
    57  	query.Add("q", "topic")
    58  	searchURL.RawQuery = query.Encode()
    59  	res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
    60  	DecodeJSON(t, res, &topics)
    61  	assert.Len(t, topics.TopicNames, 2)
    62  
    63  	query.Set("q", "database")
    64  	searchURL.RawQuery = query.Encode()
    65  	res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK)
    66  	DecodeJSON(t, res, &topics)
    67  	if assert.Len(t, topics.TopicNames, 1) {
    68  		assert.EqualValues(t, 2, topics.TopicNames[0].ID)
    69  		assert.EqualValues(t, "database", topics.TopicNames[0].Name)
    70  		assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount)
    71  	}
    72  }
    73  
    74  func TestAPIRepoTopic(t *testing.T) {
    75  	defer tests.PrepareTestEnv(t)()
    76  	user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of repo2
    77  	org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})  // owner of repo3
    78  	user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // write access to repo 3
    79  	repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
    80  	repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
    81  
    82  	// Get user2's token
    83  	token2 := getUserToken(t, user2.Name, auth_model.AccessTokenScopeWriteRepository)
    84  
    85  	// Test read topics using login
    86  	req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/topics", user2.Name, repo2.Name)).
    87  		AddTokenAuth(token2)
    88  	res := MakeRequest(t, req, http.StatusOK)
    89  	var topics *api.TopicName
    90  	DecodeJSON(t, res, &topics)
    91  	assert.ElementsMatch(t, []string{"topicname1", "topicname2"}, topics.TopicNames)
    92  
    93  	// Test delete a topic
    94  	req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/topics/%s", user2.Name, repo2.Name, "Topicname1").
    95  		AddTokenAuth(token2)
    96  	MakeRequest(t, req, http.StatusNoContent)
    97  
    98  	// Test add an existing topic
    99  	req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s", user2.Name, repo2.Name, "Golang").
   100  		AddTokenAuth(token2)
   101  	MakeRequest(t, req, http.StatusNoContent)
   102  
   103  	// Test add a topic
   104  	req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s", user2.Name, repo2.Name, "topicName3").
   105  		AddTokenAuth(token2)
   106  	MakeRequest(t, req, http.StatusNoContent)
   107  
   108  	url := fmt.Sprintf("/api/v1/repos/%s/%s/topics", user2.Name, repo2.Name)
   109  
   110  	// Test read topics using token
   111  	req = NewRequest(t, "GET", url).
   112  		AddTokenAuth(token2)
   113  	res = MakeRequest(t, req, http.StatusOK)
   114  	DecodeJSON(t, res, &topics)
   115  	assert.ElementsMatch(t, []string{"topicname2", "golang", "topicname3"}, topics.TopicNames)
   116  
   117  	// Test replace topics
   118  	newTopics := []string{"   windows ", "   ", "MAC  "}
   119  	req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
   120  		Topics: newTopics,
   121  	}).AddTokenAuth(token2)
   122  	MakeRequest(t, req, http.StatusNoContent)
   123  	req = NewRequest(t, "GET", url).
   124  		AddTokenAuth(token2)
   125  	res = MakeRequest(t, req, http.StatusOK)
   126  	DecodeJSON(t, res, &topics)
   127  	assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
   128  
   129  	// Test replace topics with something invalid
   130  	newTopics = []string{"topicname1", "topicname2", "topicname!"}
   131  	req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
   132  		Topics: newTopics,
   133  	}).AddTokenAuth(token2)
   134  	MakeRequest(t, req, http.StatusUnprocessableEntity)
   135  	req = NewRequest(t, "GET", url).
   136  		AddTokenAuth(token2)
   137  	res = MakeRequest(t, req, http.StatusOK)
   138  	DecodeJSON(t, res, &topics)
   139  	assert.ElementsMatch(t, []string{"windows", "mac"}, topics.TopicNames)
   140  
   141  	// Test with some topics multiple times, less than 25 unique
   142  	newTopics = []string{"t1", "t2", "t1", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "17", "t18", "t19", "t20", "t21", "t22", "t23", "t24", "t25"}
   143  	req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
   144  		Topics: newTopics,
   145  	}).AddTokenAuth(token2)
   146  	MakeRequest(t, req, http.StatusNoContent)
   147  	req = NewRequest(t, "GET", url).
   148  		AddTokenAuth(token2)
   149  	res = MakeRequest(t, req, http.StatusOK)
   150  	DecodeJSON(t, res, &topics)
   151  	assert.Len(t, topics.TopicNames, 25)
   152  
   153  	// Test writing more topics than allowed
   154  	newTopics = append(newTopics, "t26")
   155  	req = NewRequestWithJSON(t, "PUT", url, &api.RepoTopicOptions{
   156  		Topics: newTopics,
   157  	}).AddTokenAuth(token2)
   158  	MakeRequest(t, req, http.StatusUnprocessableEntity)
   159  
   160  	// Test add a topic when there is already maximum
   161  	req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s", user2.Name, repo2.Name, "t26").
   162  		AddTokenAuth(token2)
   163  	MakeRequest(t, req, http.StatusUnprocessableEntity)
   164  
   165  	// Test delete a topic that repo doesn't have
   166  	req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/topics/%s", user2.Name, repo2.Name, "Topicname1").
   167  		AddTokenAuth(token2)
   168  	MakeRequest(t, req, http.StatusNotFound)
   169  
   170  	// Get user4's token
   171  	token4 := getUserToken(t, user4.Name, auth_model.AccessTokenScopeWriteRepository)
   172  
   173  	// Test read topics with write access
   174  	req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/topics", org3.Name, repo3.Name)).
   175  		AddTokenAuth(token4)
   176  	res = MakeRequest(t, req, http.StatusOK)
   177  	DecodeJSON(t, res, &topics)
   178  	assert.Empty(t, topics.TopicNames)
   179  
   180  	// Test add a topic to repo with write access (requires repo admin access)
   181  	req = NewRequestf(t, "PUT", "/api/v1/repos/%s/%s/topics/%s", org3.Name, repo3.Name, "topicName").
   182  		AddTokenAuth(token4)
   183  	MakeRequest(t, req, http.StatusForbidden)
   184  }