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 }