github.com/cli/cli@v1.14.1-0.20210902173923-1af6a669e342/api/queries_repo_test.go (about) 1 package api 2 3 import ( 4 "io" 5 "net/http" 6 "strings" 7 "testing" 8 9 "github.com/cli/cli/internal/ghrepo" 10 "github.com/cli/cli/pkg/httpmock" 11 ) 12 13 func Test_RepoMetadata(t *testing.T) { 14 http := &httpmock.Registry{} 15 client := NewClient(ReplaceTripper(http)) 16 17 repo, _ := ghrepo.FromFullName("OWNER/REPO") 18 input := RepoMetadataInput{ 19 Assignees: true, 20 Reviewers: true, 21 Labels: true, 22 Projects: true, 23 Milestones: true, 24 } 25 26 http.Register( 27 httpmock.GraphQL(`query RepositoryAssignableUsers\b`), 28 httpmock.StringResponse(` 29 { "data": { "repository": { "assignableUsers": { 30 "nodes": [ 31 { "login": "hubot", "id": "HUBOTID" }, 32 { "login": "MonaLisa", "id": "MONAID" } 33 ], 34 "pageInfo": { "hasNextPage": false } 35 } } } } 36 `)) 37 http.Register( 38 httpmock.GraphQL(`query RepositoryLabelList\b`), 39 httpmock.StringResponse(` 40 { "data": { "repository": { "labels": { 41 "nodes": [ 42 { "name": "feature", "id": "FEATUREID" }, 43 { "name": "TODO", "id": "TODOID" }, 44 { "name": "bug", "id": "BUGID" } 45 ], 46 "pageInfo": { "hasNextPage": false } 47 } } } } 48 `)) 49 http.Register( 50 httpmock.GraphQL(`query RepositoryMilestoneList\b`), 51 httpmock.StringResponse(` 52 { "data": { "repository": { "milestones": { 53 "nodes": [ 54 { "title": "GA", "id": "GAID" }, 55 { "title": "Big One.oh", "id": "BIGONEID" } 56 ], 57 "pageInfo": { "hasNextPage": false } 58 } } } } 59 `)) 60 http.Register( 61 httpmock.GraphQL(`query RepositoryProjectList\b`), 62 httpmock.StringResponse(` 63 { "data": { "repository": { "projects": { 64 "nodes": [ 65 { "name": "Cleanup", "id": "CLEANUPID" }, 66 { "name": "Roadmap", "id": "ROADMAPID" } 67 ], 68 "pageInfo": { "hasNextPage": false } 69 } } } } 70 `)) 71 http.Register( 72 httpmock.GraphQL(`query OrganizationProjectList\b`), 73 httpmock.StringResponse(` 74 { "data": { "organization": { "projects": { 75 "nodes": [ 76 { "name": "Triage", "id": "TRIAGEID" } 77 ], 78 "pageInfo": { "hasNextPage": false } 79 } } } } 80 `)) 81 http.Register( 82 httpmock.GraphQL(`query OrganizationTeamList\b`), 83 httpmock.StringResponse(` 84 { "data": { "organization": { "teams": { 85 "nodes": [ 86 { "slug": "owners", "id": "OWNERSID" }, 87 { "slug": "Core", "id": "COREID" } 88 ], 89 "pageInfo": { "hasNextPage": false } 90 } } } } 91 `)) 92 93 result, err := RepoMetadata(client, repo, input) 94 if err != nil { 95 t.Fatalf("unexpected error: %v", err) 96 } 97 98 expectedMemberIDs := []string{"MONAID", "HUBOTID"} 99 memberIDs, err := result.MembersToIDs([]string{"monalisa", "hubot"}) 100 if err != nil { 101 t.Errorf("error resolving members: %v", err) 102 } 103 if !sliceEqual(memberIDs, expectedMemberIDs) { 104 t.Errorf("expected members %v, got %v", expectedMemberIDs, memberIDs) 105 } 106 107 expectedTeamIDs := []string{"COREID", "OWNERSID"} 108 teamIDs, err := result.TeamsToIDs([]string{"OWNER/core", "/owners"}) 109 if err != nil { 110 t.Errorf("error resolving teams: %v", err) 111 } 112 if !sliceEqual(teamIDs, expectedTeamIDs) { 113 t.Errorf("expected teams %v, got %v", expectedTeamIDs, teamIDs) 114 } 115 116 expectedLabelIDs := []string{"BUGID", "TODOID"} 117 labelIDs, err := result.LabelsToIDs([]string{"bug", "todo"}) 118 if err != nil { 119 t.Errorf("error resolving labels: %v", err) 120 } 121 if !sliceEqual(labelIDs, expectedLabelIDs) { 122 t.Errorf("expected labels %v, got %v", expectedLabelIDs, labelIDs) 123 } 124 125 expectedProjectIDs := []string{"TRIAGEID", "ROADMAPID"} 126 projectIDs, err := result.ProjectsToIDs([]string{"triage", "roadmap"}) 127 if err != nil { 128 t.Errorf("error resolving projects: %v", err) 129 } 130 if !sliceEqual(projectIDs, expectedProjectIDs) { 131 t.Errorf("expected projects %v, got %v", expectedProjectIDs, projectIDs) 132 } 133 134 expectedMilestoneID := "BIGONEID" 135 milestoneID, err := result.MilestoneToID("big one.oh") 136 if err != nil { 137 t.Errorf("error resolving milestone: %v", err) 138 } 139 if milestoneID != expectedMilestoneID { 140 t.Errorf("expected milestone %v, got %v", expectedMilestoneID, milestoneID) 141 } 142 } 143 144 func Test_ProjectsToPaths(t *testing.T) { 145 expectedProjectPaths := []string{"OWNER/REPO/PROJECT_NUMBER", "ORG/PROJECT_NUMBER"} 146 projects := []RepoProject{ 147 {ID: "id1", Name: "My Project", ResourcePath: "/OWNER/REPO/projects/PROJECT_NUMBER"}, 148 {ID: "id2", Name: "Org Project", ResourcePath: "/orgs/ORG/projects/PROJECT_NUMBER"}, 149 {ID: "id3", Name: "Project", ResourcePath: "/orgs/ORG/projects/PROJECT_NUMBER_2"}, 150 } 151 projectNames := []string{"My Project", "Org Project"} 152 153 projectPaths, err := ProjectsToPaths(projects, projectNames) 154 if err != nil { 155 t.Errorf("error resolving projects: %v", err) 156 } 157 if !sliceEqual(projectPaths, expectedProjectPaths) { 158 t.Errorf("expected projects %v, got %v", expectedProjectPaths, projectPaths) 159 } 160 } 161 162 func Test_ProjectNamesToPaths(t *testing.T) { 163 http := &httpmock.Registry{} 164 client := NewClient(ReplaceTripper(http)) 165 166 repo, _ := ghrepo.FromFullName("OWNER/REPO") 167 168 http.Register( 169 httpmock.GraphQL(`query RepositoryProjectList\b`), 170 httpmock.StringResponse(` 171 { "data": { "repository": { "projects": { 172 "nodes": [ 173 { "name": "Cleanup", "id": "CLEANUPID", "resourcePath": "/OWNER/REPO/projects/1" }, 174 { "name": "Roadmap", "id": "ROADMAPID", "resourcePath": "/OWNER/REPO/projects/2" } 175 ], 176 "pageInfo": { "hasNextPage": false } 177 } } } } 178 `)) 179 http.Register( 180 httpmock.GraphQL(`query OrganizationProjectList\b`), 181 httpmock.StringResponse(` 182 { "data": { "organization": { "projects": { 183 "nodes": [ 184 { "name": "Triage", "id": "TRIAGEID", "resourcePath": "/orgs/ORG/projects/1" } 185 ], 186 "pageInfo": { "hasNextPage": false } 187 } } } } 188 `)) 189 190 projectPaths, err := ProjectNamesToPaths(client, repo, []string{"Triage", "Roadmap"}) 191 if err != nil { 192 t.Fatalf("unexpected error: %v", err) 193 } 194 195 expectedProjectPaths := []string{"ORG/1", "OWNER/REPO/2"} 196 if !sliceEqual(projectPaths, expectedProjectPaths) { 197 t.Errorf("expected projects paths %v, got %v", expectedProjectPaths, projectPaths) 198 } 199 } 200 201 func Test_RepoResolveMetadataIDs(t *testing.T) { 202 http := &httpmock.Registry{} 203 client := NewClient(ReplaceTripper(http)) 204 205 repo, _ := ghrepo.FromFullName("OWNER/REPO") 206 input := RepoResolveInput{ 207 Assignees: []string{"monalisa", "hubot"}, 208 Reviewers: []string{"monalisa", "octocat", "OWNER/core", "/robots"}, 209 Labels: []string{"bug", "help wanted"}, 210 } 211 212 expectedQuery := `query RepositoryResolveMetadataIDs { 213 u000: user(login:"monalisa"){id,login} 214 u001: user(login:"hubot"){id,login} 215 u002: user(login:"octocat"){id,login} 216 repository(owner:"OWNER",name:"REPO"){ 217 l000: label(name:"bug"){id,name} 218 l001: label(name:"help wanted"){id,name} 219 } 220 organization(login:"OWNER"){ 221 t000: team(slug:"core"){id,slug} 222 t001: team(slug:"robots"){id,slug} 223 } 224 } 225 ` 226 responseJSON := ` 227 { "data": { 228 "u000": { "login": "MonaLisa", "id": "MONAID" }, 229 "u001": { "login": "hubot", "id": "HUBOTID" }, 230 "u002": { "login": "octocat", "id": "OCTOID" }, 231 "repository": { 232 "l000": { "name": "bug", "id": "BUGID" }, 233 "l001": { "name": "Help Wanted", "id": "HELPID" } 234 }, 235 "organization": { 236 "t000": { "slug": "core", "id": "COREID" }, 237 "t001": { "slug": "Robots", "id": "ROBOTID" } 238 } 239 } } 240 ` 241 242 http.Register( 243 httpmock.GraphQL(`query RepositoryResolveMetadataIDs\b`), 244 httpmock.GraphQLQuery(responseJSON, func(q string, _ map[string]interface{}) { 245 if q != expectedQuery { 246 t.Errorf("expected query %q, got %q", expectedQuery, q) 247 } 248 })) 249 250 result, err := RepoResolveMetadataIDs(client, repo, input) 251 if err != nil { 252 t.Fatalf("unexpected error: %v", err) 253 } 254 255 expectedMemberIDs := []string{"MONAID", "HUBOTID", "OCTOID"} 256 memberIDs, err := result.MembersToIDs([]string{"monalisa", "hubot", "octocat"}) 257 if err != nil { 258 t.Errorf("error resolving members: %v", err) 259 } 260 if !sliceEqual(memberIDs, expectedMemberIDs) { 261 t.Errorf("expected members %v, got %v", expectedMemberIDs, memberIDs) 262 } 263 264 expectedTeamIDs := []string{"COREID", "ROBOTID"} 265 teamIDs, err := result.TeamsToIDs([]string{"/core", "/robots"}) 266 if err != nil { 267 t.Errorf("error resolving teams: %v", err) 268 } 269 if !sliceEqual(teamIDs, expectedTeamIDs) { 270 t.Errorf("expected members %v, got %v", expectedTeamIDs, teamIDs) 271 } 272 273 expectedLabelIDs := []string{"BUGID", "HELPID"} 274 labelIDs, err := result.LabelsToIDs([]string{"bug", "help wanted"}) 275 if err != nil { 276 t.Errorf("error resolving labels: %v", err) 277 } 278 if !sliceEqual(labelIDs, expectedLabelIDs) { 279 t.Errorf("expected members %v, got %v", expectedLabelIDs, labelIDs) 280 } 281 } 282 283 func sliceEqual(a, b []string) bool { 284 if len(a) != len(b) { 285 return false 286 } 287 288 for i := range a { 289 if a[i] != b[i] { 290 return false 291 } 292 } 293 294 return true 295 } 296 297 func Test_RepoMilestones(t *testing.T) { 298 tests := []struct { 299 state string 300 want string 301 wantErr bool 302 }{ 303 { 304 state: "open", 305 want: `"states":["OPEN"]`, 306 }, 307 { 308 state: "closed", 309 want: `"states":["CLOSED"]`, 310 }, 311 { 312 state: "all", 313 want: `"states":["OPEN","CLOSED"]`, 314 }, 315 { 316 state: "invalid state", 317 wantErr: true, 318 }, 319 } 320 for _, tt := range tests { 321 var query string 322 reg := &httpmock.Registry{} 323 reg.Register(httpmock.MatchAny, func(req *http.Request) (*http.Response, error) { 324 buf := new(strings.Builder) 325 _, err := io.Copy(buf, req.Body) 326 if err != nil { 327 return nil, err 328 } 329 query = buf.String() 330 return httpmock.StringResponse("{}")(req) 331 }) 332 client := NewClient(ReplaceTripper(reg)) 333 334 _, err := RepoMilestones(client, ghrepo.New("OWNER", "REPO"), tt.state) 335 if (err != nil) != tt.wantErr { 336 t.Errorf("RepoMilestones() error = %v, wantErr %v", err, tt.wantErr) 337 return 338 } 339 if !strings.Contains(query, tt.want) { 340 t.Errorf("query does not contain %v", tt.want) 341 } 342 } 343 }