golang.org/x/build@v0.0.0-20240506185731-218518f32b70/gerrit/gerrit_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gerrit 6 7 import ( 8 "context" 9 "errors" 10 "io" 11 "net/http" 12 "net/http/httptest" 13 "net/url" 14 "strings" 15 "testing" 16 "time" 17 ) 18 19 // taken from https://go-review.googlesource.com/projects/go 20 var exampleProjectResponse = []byte(`)]}' 21 { 22 "id": "go", 23 "name": "go", 24 "parent": "All-Projects", 25 "description": "The Go Programming Language", 26 "state": "ACTIVE", 27 "web_links": [ 28 { 29 "name": "gitiles", 30 "url": "https://go.googlesource.com/go/", 31 "target": "_blank" 32 } 33 ] 34 } 35 `) 36 37 func TestGetProjectInfo(t *testing.T) { 38 hitServer := false 39 path := "" 40 s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 41 hitServer = true 42 path = r.URL.Path 43 w.Header().Set("Content-Type", "application/json; charset=UTF-8") 44 w.WriteHeader(200) 45 w.Write(exampleProjectResponse) 46 })) 47 defer s.Close() 48 c := NewClient(s.URL, NoAuth) 49 info, err := c.GetProjectInfo(context.Background(), "go") 50 if err != nil { 51 t.Fatal(err) 52 } 53 if !hitServer { 54 t.Errorf("expected to hit test server, didn't") 55 } 56 if path != "/projects/go" { 57 t.Errorf("expected Path to be '/projects/go', got %s", path) 58 } 59 if info.Name != "go" { 60 t.Errorf("expected Name to be 'go', got %s", info.Name) 61 } 62 } 63 64 func TestProjectNotFound(t *testing.T) { 65 s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 66 w.Header().Set("Content-Type", "text/plain; charset=UTF-8") 67 w.WriteHeader(404) 68 w.Write([]byte("Not found: unknown")) 69 })) 70 defer s.Close() 71 c := NewClient(s.URL, NoAuth) 72 _, err := c.GetProjectInfo(context.Background(), "unknown") 73 if !errors.Is(err, ErrResourceNotExist) { 74 t.Errorf("expected to get ErrResourceNotExist, got %v", err) 75 } 76 } 77 78 func TestContextError(t *testing.T) { 79 c := NewClient("http://localhost", NoAuth) 80 yearsAgo, _ := time.Parse("2006", "2006") 81 ctx, cancel := context.WithDeadline(context.Background(), yearsAgo) 82 defer cancel() 83 _, err := c.GetProjectInfo(ctx, "unknown") 84 if err == nil { 85 t.Errorf("expected non-nil error, got nil") 86 } 87 uerr, ok := err.(*url.Error) 88 if !ok { 89 t.Errorf("expected url.Error, got %#v", err) 90 } 91 if uerr.Err != context.DeadlineExceeded { 92 t.Errorf("expected DeadlineExceeded error, got %v", uerr.Err) 93 } 94 } 95 96 var getChangeResponse = []byte(`)]}' 97 { 98 "id": "build~master~I92989e0231299ed305ddfbbe6034d293f1c87470", 99 "project": "build", 100 "branch": "master", 101 "hashtags": [], 102 "change_id": "I92989e0231299ed305ddfbbe6034d293f1c87470", 103 "subject": "devapp: fix tests", 104 "status": "ABANDONED", 105 "created": "2017-07-13 06:09:10.000000000", 106 "updated": "2017-07-14 16:31:32.000000000", 107 "insertions": 1, 108 "deletions": 1, 109 "unresolved_comment_count": 0, 110 "has_review_started": true, 111 "_number": 48330, 112 "owner": { 113 "_account_id": 13437 114 }, 115 "messages": [ 116 { 117 "id": "f9fcf0ff9eb58fc8edd989f8bbb3500ff73f9b11", 118 "author": { 119 "_account_id": 22285 120 }, 121 "real_author": { 122 "_account_id": 22285 123 }, 124 "date": "2017-07-13 06:14:48.000000000", 125 "message": "Patch Set 1:\n\nCheck out https://go-review.googlesource.com/c/48350/ :)", 126 "_revision_number": 1 127 } 128 ] 129 }`) 130 131 func TestGetChange(t *testing.T) { 132 hitServer := false 133 uri := "" 134 s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 135 hitServer = true 136 uri = r.URL.RequestURI() 137 w.Header().Set("Content-Type", "application/json; charset=UTF-8") 138 w.WriteHeader(200) 139 w.Write(getChangeResponse) 140 })) 141 defer s.Close() 142 c := NewClient(s.URL, NoAuth) 143 info, err := c.GetChange(context.Background(), "48330", QueryChangesOpt{ 144 Fields: []string{"MESSAGES"}, 145 }) 146 if err != nil { 147 t.Fatal(err) 148 } 149 if !hitServer { 150 t.Errorf("expected to hit test server, didn't") 151 } 152 if want := "/changes/48330?o=MESSAGES"; uri != want { 153 t.Errorf("expected RequestURI to be %q, got %q", want, uri) 154 } 155 if len(info.Messages) != 1 { 156 t.Errorf("expected message length to be 1, got %d", len(info.Messages)) 157 } 158 msg := info.Messages[0].Message 159 if !strings.Contains(msg, "Check out") { 160 t.Errorf("expected to find string in Message, got %s", msg) 161 } 162 } 163 164 func TestGetChangeError(t *testing.T) { 165 hitServer := false 166 s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 167 hitServer = true 168 w.Header().Set("Content-Type", "text/plain; charset=UTF-8") 169 w.WriteHeader(404) 170 io.WriteString(w, "Not found: 99999") 171 })) 172 defer s.Close() 173 c := NewClient(s.URL, NoAuth) 174 _, err := c.GetChange(context.Background(), "99999", QueryChangesOpt{ 175 Fields: []string{"MESSAGES"}, 176 }) 177 if !hitServer { 178 t.Errorf("expected to hit test server, didn't") 179 } 180 if !errors.Is(err, ErrResourceNotExist) { 181 t.Errorf("expected ErrResourceNotExist, got %v", err) 182 } 183 } 184 185 var queryAccountsResponse = []byte(`)]}' 186 [ 187 { 188 "_account_id": 1, 189 "name": "John Doe", 190 "email": "john@doe.com" 191 }, 192 { 193 "_account_id": 2, 194 "name": "Jane Doe", 195 "email": "jane@doe.com", 196 "_more_accounts": true 197 } 198 ]`) 199 200 func TestQueryAccounts(t *testing.T) { 201 hitServer := false 202 uri := "" 203 204 s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 205 hitServer = true 206 uri = r.URL.RequestURI() 207 w.Header().Set("Content-Type", "application/json; charset=UTF-8") 208 w.WriteHeader(200) 209 w.Write(queryAccountsResponse) 210 })) 211 defer s.Close() 212 c := NewClient(s.URL, NoAuth) 213 info, err := c.QueryAccounts(context.Background(), "is:active", QueryAccountsOpt{ 214 Fields: []string{"DETAILS"}, 215 N: 2, 216 }) 217 if err != nil { 218 t.Fatal(err.Error()) 219 } 220 if !hitServer { 221 t.Errorf("expected to hit test server, didn't") 222 } 223 if want := "/accounts/?n=2&o=DETAILS&q=is%3Aactive"; uri != want { 224 t.Errorf("expected RequestURI to be %q, got %q", want, uri) 225 } 226 if len(info) != 2 { 227 t.Errorf("expected accounts length to be 2, got %d", len(info)) 228 } 229 if info[0].NumericID != 1 || info[0].Name != "John Doe" || info[0].Email != "john@doe.com" { 230 t.Errorf("expected to match John Doe in account, got %v", info[0]) 231 } 232 if info[1].NumericID != 2 || info[1].Name != "Jane Doe" || info[1].Email != "jane@doe.com" { 233 t.Errorf("expected to match Jane Doe in account, got %v", info[1]) 234 } 235 if info[0].MoreAccounts { 236 t.Errorf("expected to MoreAccounts to be false for John Doe") 237 } 238 if !info[1].MoreAccounts { 239 t.Errorf("expected to MoreAccounts to be true for Jane Doe") 240 } 241 } 242 243 func TestTimeStampMarshalJson(t *testing.T) { 244 ts := TimeStamp(time.Date(1888, 6, 24, 6, 8, 30, 123456789, time.FixedZone("+1", 3600))) 245 b, err := ts.MarshalJSON() 246 if err != nil { 247 t.Errorf("unexpected err %v", err) 248 } 249 expected := `"1888-06-24 05:08:30.123456789"` 250 if string(b) != expected { 251 t.Errorf("expected %q, got %q", expected, b) 252 } 253 } 254 255 func TestTimeStampUnmarshalJson(t *testing.T) { 256 var ts TimeStamp 257 err := ts.UnmarshalJSON([]byte(`"1888-06-24 05:08:30.123456789"`)) 258 if err != nil { 259 t.Errorf("unexpected err %v", err) 260 } 261 expected := time.Date(1888, 6, 24, 5, 8, 30, 123456789, time.UTC) 262 if !ts.Time().Equal(expected) { 263 t.Errorf("expected %v, got %v", expected, ts.Time()) 264 } 265 } 266 267 // taken from https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#list-tags 268 var exampleProjectTagsResponse = []byte(` )]}' 269 [ 270 { 271 "ref": "refs/tags/v1.0", 272 "revision": "49ce77fdcfd3398dc0dedbe016d1a425fd52d666", 273 "object": "1624f5af8ae89148d1a3730df8c290413e3dcf30", 274 "message": "Annotated tag", 275 "tagger": { 276 "name": "David Pursehouse", 277 "email": "david.pursehouse@sonymobile.com", 278 "date": "2014-10-06 07:35:03.000000000", 279 "tz": 540 280 } 281 }, 282 { 283 "ref": "refs/tags/v2.0", 284 "revision": "1624f5af8ae89148d1a3730df8c290413e3dcf30" 285 } 286 ] 287 `) 288 289 func TestGetProjectTags(t *testing.T) { 290 hitServer := false 291 path := "" 292 s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 293 hitServer = true 294 path = r.URL.Path 295 w.Header().Set("Content-Type", "application/json; charset=UTF-8") 296 w.WriteHeader(200) 297 w.Write(exampleProjectTagsResponse) 298 })) 299 defer s.Close() 300 c := NewClient(s.URL, NoAuth) 301 tags, err := c.GetProjectTags(context.Background(), "go") 302 if err != nil { 303 t.Fatal(err) 304 } 305 if !hitServer { 306 t.Errorf("expected to hit test server, didn't") 307 } 308 if path != "/projects/go/tags/" { 309 t.Errorf("expected Path to be '/projects/go/tags/', got %s", path) 310 } 311 expectedTags := map[string]TagInfo{ 312 "refs/tags/v1.0": TagInfo{ 313 Ref: "refs/tags/v1.0", 314 Revision: "49ce77fdcfd3398dc0dedbe016d1a425fd52d666", 315 Object: "1624f5af8ae89148d1a3730df8c290413e3dcf30", 316 Message: "Annotated tag", 317 Tagger: &GitPersonInfo{ 318 Name: "David Pursehouse", 319 Email: "david.pursehouse@sonymobile.com", 320 Date: TimeStamp(time.Date(2014, 10, 6, 7, 35, 3, 0, time.UTC)), 321 TZOffset: 540, 322 }, 323 }, 324 "refs/tags/v2.0": TagInfo{ 325 Ref: "refs/tags/v2.0", 326 Revision: "1624f5af8ae89148d1a3730df8c290413e3dcf30", 327 }, 328 } 329 if len(tags) != len(expectedTags) { 330 t.Errorf("expected %d tags, got %d", len(expectedTags), len(tags)) 331 } 332 for ref, tag := range tags { 333 expectedTag, found := expectedTags[ref] 334 if !found { 335 t.Errorf("unexpected tag %q", ref) 336 } 337 if !tag.Equal(&expectedTag) { 338 t.Errorf("tags don't match (expected %#v and got %#v)", expectedTag, tag) 339 } 340 } 341 }