github.com/google/go-github/v57@v57.0.0/github/git_commits_test.go (about) 1 // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "encoding/json" 11 "fmt" 12 "io" 13 "net/http" 14 "testing" 15 "time" 16 17 "github.com/google/go-cmp/cmp" 18 ) 19 20 func mockSigner(t *testing.T, signature string, emitErr error, wantMessage string) MessageSignerFunc { 21 return func(w io.Writer, r io.Reader) error { 22 t.Helper() 23 message, err := io.ReadAll(r) 24 assertNilError(t, err) 25 if wantMessage != "" && string(message) != wantMessage { 26 t.Errorf("MessageSignerFunc got %q, want %q", string(message), wantMessage) 27 } 28 assertWrite(t, w, []byte(signature)) 29 return emitErr 30 } 31 } 32 33 func uncalledSigner(t *testing.T) MessageSignerFunc { 34 return func(w io.Writer, r io.Reader) error { 35 t.Error("MessageSignerFunc should not be called") 36 return nil 37 } 38 } 39 40 func TestCommit_Marshal(t *testing.T) { 41 testJSONMarshal(t, &Commit{}, "{}") 42 43 u := &Commit{ 44 SHA: String("s"), 45 Author: &CommitAuthor{ 46 Date: &Timestamp{referenceTime}, 47 Name: String("n"), 48 Email: String("e"), 49 Login: String("u"), 50 }, 51 Committer: &CommitAuthor{ 52 Date: &Timestamp{referenceTime}, 53 Name: String("n"), 54 Email: String("e"), 55 Login: String("u"), 56 }, 57 Message: String("m"), 58 Tree: &Tree{ 59 SHA: String("s"), 60 Entries: []*TreeEntry{{ 61 SHA: String("s"), 62 Path: String("p"), 63 Mode: String("m"), 64 Type: String("t"), 65 Size: Int(1), 66 Content: String("c"), 67 URL: String("u"), 68 }}, 69 Truncated: Bool(false), 70 }, 71 Parents: nil, 72 Stats: &CommitStats{ 73 Additions: Int(1), 74 Deletions: Int(1), 75 Total: Int(1), 76 }, 77 HTMLURL: String("h"), 78 URL: String("u"), 79 Verification: &SignatureVerification{ 80 Verified: Bool(false), 81 Reason: String("r"), 82 Signature: String("s"), 83 Payload: String("p"), 84 }, 85 NodeID: String("n"), 86 CommentCount: Int(1), 87 } 88 89 want := `{ 90 "sha": "s", 91 "author": { 92 "date": ` + referenceTimeStr + `, 93 "name": "n", 94 "email": "e", 95 "username": "u" 96 }, 97 "committer": { 98 "date": ` + referenceTimeStr + `, 99 "name": "n", 100 "email": "e", 101 "username": "u" 102 }, 103 "message": "m", 104 "tree": { 105 "sha": "s", 106 "tree": [ 107 { 108 "sha": "s", 109 "path": "p", 110 "mode": "m", 111 "type": "t", 112 "size": 1, 113 "content": "c", 114 "url": "u" 115 } 116 ], 117 "truncated": false 118 }, 119 "stats": { 120 "additions": 1, 121 "deletions": 1, 122 "total": 1 123 }, 124 "html_url": "h", 125 "url": "u", 126 "verification": { 127 "verified": false, 128 "reason": "r", 129 "signature": "s", 130 "payload": "p" 131 }, 132 "node_id": "n", 133 "comment_count": 1 134 }` 135 136 testJSONMarshal(t, u, want) 137 } 138 139 func TestGitService_GetCommit(t *testing.T) { 140 client, mux, _, teardown := setup() 141 defer teardown() 142 143 mux.HandleFunc("/repos/o/r/git/commits/s", func(w http.ResponseWriter, r *http.Request) { 144 testMethod(t, r, "GET") 145 fmt.Fprint(w, `{"sha":"s","message":"Commit Message.","author":{"name":"n"}}`) 146 }) 147 148 ctx := context.Background() 149 commit, _, err := client.Git.GetCommit(ctx, "o", "r", "s") 150 if err != nil { 151 t.Errorf("Git.GetCommit returned error: %v", err) 152 } 153 154 want := &Commit{SHA: String("s"), Message: String("Commit Message."), Author: &CommitAuthor{Name: String("n")}} 155 if !cmp.Equal(commit, want) { 156 t.Errorf("Git.GetCommit returned %+v, want %+v", commit, want) 157 } 158 159 const methodName = "GetCommit" 160 testBadOptions(t, methodName, func() (err error) { 161 _, _, err = client.Git.GetCommit(ctx, "\n", "\n", "\n") 162 return err 163 }) 164 165 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 166 got, resp, err := client.Git.GetCommit(ctx, "o", "r", "s") 167 if got != nil { 168 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 169 } 170 return resp, err 171 }) 172 } 173 174 func TestGitService_GetCommit_invalidOwner(t *testing.T) { 175 client, _, _, teardown := setup() 176 defer teardown() 177 178 ctx := context.Background() 179 _, _, err := client.Git.GetCommit(ctx, "%", "%", "%") 180 testURLParseError(t, err) 181 } 182 183 func TestGitService_CreateCommit(t *testing.T) { 184 client, mux, _, teardown := setup() 185 defer teardown() 186 187 input := &Commit{ 188 Message: String("Commit Message."), 189 Tree: &Tree{SHA: String("t")}, 190 Parents: []*Commit{{SHA: String("p")}}, 191 } 192 193 mux.HandleFunc("/repos/o/r/git/commits", func(w http.ResponseWriter, r *http.Request) { 194 v := new(createCommit) 195 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 196 197 testMethod(t, r, "POST") 198 199 want := &createCommit{ 200 Message: input.Message, 201 Tree: String("t"), 202 Parents: []string{"p"}, 203 } 204 if !cmp.Equal(v, want) { 205 t.Errorf("Request body = %+v, want %+v", v, want) 206 } 207 fmt.Fprint(w, `{"sha":"s"}`) 208 }) 209 210 ctx := context.Background() 211 commit, _, err := client.Git.CreateCommit(ctx, "o", "r", input, nil) 212 if err != nil { 213 t.Errorf("Git.CreateCommit returned error: %v", err) 214 } 215 216 want := &Commit{SHA: String("s")} 217 if !cmp.Equal(commit, want) { 218 t.Errorf("Git.CreateCommit returned %+v, want %+v", commit, want) 219 } 220 221 const methodName = "CreateCommit" 222 testBadOptions(t, methodName, func() (err error) { 223 _, _, err = client.Git.CreateCommit(ctx, "\n", "\n", input, nil) 224 return err 225 }) 226 227 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 228 got, resp, err := client.Git.CreateCommit(ctx, "o", "r", input, nil) 229 if got != nil { 230 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 231 } 232 return resp, err 233 }) 234 } 235 236 func TestGitService_CreateSignedCommit(t *testing.T) { 237 client, mux, _, teardown := setup() 238 defer teardown() 239 240 signature := "----- BEGIN PGP SIGNATURE -----\n\naaaa\naaaa\n----- END PGP SIGNATURE -----" 241 242 input := &Commit{ 243 Message: String("Commit Message."), 244 Tree: &Tree{SHA: String("t")}, 245 Parents: []*Commit{{SHA: String("p")}}, 246 Verification: &SignatureVerification{ 247 Signature: String(signature), 248 }, 249 } 250 251 mux.HandleFunc("/repos/o/r/git/commits", func(w http.ResponseWriter, r *http.Request) { 252 v := new(createCommit) 253 assertNilError(t, json.NewDecoder(r.Body).Decode(v)) 254 255 testMethod(t, r, "POST") 256 257 want := &createCommit{ 258 Message: input.Message, 259 Tree: String("t"), 260 Parents: []string{"p"}, 261 Signature: String(signature), 262 } 263 if !cmp.Equal(v, want) { 264 t.Errorf("Request body = %+v, want %+v", v, want) 265 } 266 fmt.Fprint(w, `{"sha":"commitSha"}`) 267 }) 268 269 ctx := context.Background() 270 commit, _, err := client.Git.CreateCommit(ctx, "o", "r", input, nil) 271 if err != nil { 272 t.Errorf("Git.CreateCommit returned error: %v", err) 273 } 274 275 want := &Commit{SHA: String("commitSha")} 276 if !cmp.Equal(commit, want) { 277 t.Errorf("Git.CreateCommit returned %+v, want %+v", commit, want) 278 } 279 280 const methodName = "CreateCommit" 281 testBadOptions(t, methodName, func() (err error) { 282 _, _, err = client.Git.CreateCommit(ctx, "\n", "\n", input, nil) 283 return err 284 }) 285 286 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 287 got, resp, err := client.Git.CreateCommit(ctx, "o", "r", input, nil) 288 if got != nil { 289 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 290 } 291 return resp, err 292 }) 293 } 294 295 func TestGitService_CreateSignedCommitWithInvalidParams(t *testing.T) { 296 client, _, _, teardown := setup() 297 defer teardown() 298 299 input := &Commit{} 300 301 ctx := context.Background() 302 opts := CreateCommitOptions{Signer: uncalledSigner(t)} 303 _, _, err := client.Git.CreateCommit(ctx, "o", "r", input, &opts) 304 if err == nil { 305 t.Errorf("Expected error to be returned because invalid params were passed") 306 } 307 } 308 309 func TestGitService_CreateCommitWithNilCommit(t *testing.T) { 310 client, _, _, teardown := setup() 311 defer teardown() 312 313 ctx := context.Background() 314 _, _, err := client.Git.CreateCommit(ctx, "o", "r", nil, nil) 315 if err == nil { 316 t.Errorf("Expected error to be returned because commit=nil") 317 } 318 } 319 320 func TestGitService_CreateCommit_WithSigner(t *testing.T) { 321 client, mux, _, teardown := setup() 322 defer teardown() 323 signature := "my voice is my password" 324 date := time.Date(2017, time.May, 4, 0, 3, 43, 0, time.FixedZone("CEST", 2*3600)) 325 author := CommitAuthor{ 326 Name: String("go-github"), 327 Email: String("go-github@github.com"), 328 Date: &Timestamp{date}, 329 } 330 wantMessage := `tree t 331 parent p 332 author go-github <go-github@github.com> 1493849023 +0200 333 committer go-github <go-github@github.com> 1493849023 +0200 334 335 Commit Message.` 336 sha := "commitSha" 337 input := &Commit{ 338 SHA: &sha, 339 Message: String("Commit Message."), 340 Tree: &Tree{SHA: String("t")}, 341 Parents: []*Commit{{SHA: String("p")}}, 342 Author: &author, 343 } 344 wantBody := createCommit{ 345 Message: input.Message, 346 Tree: String("t"), 347 Parents: []string{"p"}, 348 Author: &author, 349 Signature: &signature, 350 } 351 var gotBody createCommit 352 mux.HandleFunc("/repos/o/r/git/commits", func(w http.ResponseWriter, r *http.Request) { 353 assertNilError(t, json.NewDecoder(r.Body).Decode(&gotBody)) 354 testMethod(t, r, "POST") 355 fmt.Fprintf(w, `{"sha":"%s"}`, sha) 356 }) 357 ctx := context.Background() 358 wantCommit := &Commit{SHA: String(sha)} 359 opts := CreateCommitOptions{Signer: mockSigner(t, signature, nil, wantMessage)} 360 commit, _, err := client.Git.CreateCommit(ctx, "o", "r", input, &opts) 361 assertNilError(t, err) 362 if cmp.Diff(gotBody, wantBody) != "" { 363 t.Errorf("Request body = %+v, want %+v\n%s", gotBody, wantBody, cmp.Diff(gotBody, wantBody)) 364 } 365 if cmp.Diff(commit, wantCommit) != "" { 366 t.Errorf("Git.CreateCommit returned %+v, want %+v\n%s", commit, wantCommit, cmp.Diff(commit, wantCommit)) 367 } 368 } 369 370 func TestGitService_createSignature_nilSigner(t *testing.T) { 371 a := &createCommit{ 372 Message: String("Commit Message."), 373 Tree: String("t"), 374 Parents: []string{"p"}, 375 } 376 377 _, err := createSignature(nil, a) 378 379 if err == nil { 380 t.Errorf("Expected error to be returned because no author was passed") 381 } 382 } 383 384 func TestGitService_createSignature_nilCommit(t *testing.T) { 385 _, err := createSignature(uncalledSigner(t), nil) 386 387 if err == nil { 388 t.Errorf("Expected error to be returned because no author was passed") 389 } 390 } 391 392 func TestGitService_createSignature_signerError(t *testing.T) { 393 a := &createCommit{ 394 Message: String("Commit Message."), 395 Tree: String("t"), 396 Parents: []string{"p"}, 397 Author: &CommitAuthor{Name: String("go-github")}, 398 } 399 400 signer := mockSigner(t, "", fmt.Errorf("signer error"), "") 401 _, err := createSignature(signer, a) 402 403 if err == nil { 404 t.Errorf("Expected error to be returned because signer returned an error") 405 } 406 } 407 408 func TestGitService_createSignatureMessage_nilCommit(t *testing.T) { 409 _, err := createSignatureMessage(nil) 410 if err == nil { 411 t.Errorf("Expected error to be returned due to nil key") 412 } 413 } 414 415 func TestGitService_createSignatureMessage_nilMessage(t *testing.T) { 416 date, _ := time.Parse("Mon Jan 02 15:04:05 2006 -0700", "Thu May 04 00:03:43 2017 +0200") 417 418 _, err := createSignatureMessage(&createCommit{ 419 Message: nil, 420 Parents: []string{"p"}, 421 Author: &CommitAuthor{ 422 Name: String("go-github"), 423 Email: String("go-github@github.com"), 424 Date: &Timestamp{date}, 425 }, 426 }) 427 if err == nil { 428 t.Errorf("Expected error to be returned due to nil key") 429 } 430 } 431 432 func TestGitService_createSignatureMessage_emptyMessage(t *testing.T) { 433 date, _ := time.Parse("Mon Jan 02 15:04:05 2006 -0700", "Thu May 04 00:03:43 2017 +0200") 434 emptyString := "" 435 _, err := createSignatureMessage(&createCommit{ 436 Message: &emptyString, 437 Parents: []string{"p"}, 438 Author: &CommitAuthor{ 439 Name: String("go-github"), 440 Email: String("go-github@github.com"), 441 Date: &Timestamp{date}, 442 }, 443 }) 444 if err == nil { 445 t.Errorf("Expected error to be returned due to nil key") 446 } 447 } 448 449 func TestGitService_createSignatureMessage_nilAuthor(t *testing.T) { 450 _, err := createSignatureMessage(&createCommit{ 451 Message: String("Commit Message."), 452 Parents: []string{"p"}, 453 Author: nil, 454 }) 455 if err == nil { 456 t.Errorf("Expected error to be returned due to nil key") 457 } 458 } 459 460 func TestGitService_createSignatureMessage_withoutTree(t *testing.T) { 461 date, _ := time.Parse("Mon Jan 02 15:04:05 2006 -0700", "Thu May 04 00:03:43 2017 +0200") 462 463 msg, _ := createSignatureMessage(&createCommit{ 464 Message: String("Commit Message."), 465 Parents: []string{"p"}, 466 Author: &CommitAuthor{ 467 Name: String("go-github"), 468 Email: String("go-github@github.com"), 469 Date: &Timestamp{date}, 470 }, 471 }) 472 expected := `parent p 473 author go-github <go-github@github.com> 1493849023 +0200 474 committer go-github <go-github@github.com> 1493849023 +0200 475 476 Commit Message.` 477 if msg != expected { 478 t.Errorf("Returned message incorrect. returned %s, want %s", msg, expected) 479 } 480 } 481 482 func TestGitService_createSignatureMessage_withoutCommitter(t *testing.T) { 483 date, _ := time.Parse("Mon Jan 02 15:04:05 2006 -0700", "Thu May 04 00:03:43 2017 +0200") 484 485 msg, _ := createSignatureMessage(&createCommit{ 486 Message: String("Commit Message."), 487 Parents: []string{"p"}, 488 Author: &CommitAuthor{ 489 Name: String("go-github"), 490 Email: String("go-github@github.com"), 491 Date: &Timestamp{date}, 492 }, 493 Committer: &CommitAuthor{ 494 Name: String("foo"), 495 Email: String("foo@bar.com"), 496 Date: &Timestamp{date}, 497 }, 498 }) 499 expected := `parent p 500 author go-github <go-github@github.com> 1493849023 +0200 501 committer foo <foo@bar.com> 1493849023 +0200 502 503 Commit Message.` 504 if msg != expected { 505 t.Errorf("Returned message incorrect. returned %s, want %s", msg, expected) 506 } 507 } 508 509 func TestGitService_CreateCommit_invalidOwner(t *testing.T) { 510 client, _, _, teardown := setup() 511 defer teardown() 512 513 ctx := context.Background() 514 _, _, err := client.Git.CreateCommit(ctx, "%", "%", &Commit{}, nil) 515 testURLParseError(t, err) 516 } 517 518 func TestSignatureVerification_Marshal(t *testing.T) { 519 testJSONMarshal(t, &SignatureVerification{}, "{}") 520 521 u := &SignatureVerification{ 522 Verified: Bool(true), 523 Reason: String("reason"), 524 Signature: String("sign"), 525 Payload: String("payload"), 526 } 527 528 want := `{ 529 "verified": true, 530 "reason": "reason", 531 "signature": "sign", 532 "payload": "payload" 533 }` 534 535 testJSONMarshal(t, u, want) 536 } 537 538 func TestCommitAuthor_Marshal(t *testing.T) { 539 testJSONMarshal(t, &CommitAuthor{}, "{}") 540 541 u := &CommitAuthor{ 542 Date: &Timestamp{referenceTime}, 543 Name: String("name"), 544 Email: String("email"), 545 Login: String("login"), 546 } 547 548 want := `{ 549 "date": ` + referenceTimeStr + `, 550 "name": "name", 551 "email": "email", 552 "username": "login" 553 }` 554 555 testJSONMarshal(t, u, want) 556 } 557 558 func TestCreateCommit_Marshal(t *testing.T) { 559 testJSONMarshal(t, &createCommit{}, "{}") 560 561 u := &createCommit{ 562 Author: &CommitAuthor{ 563 Date: &Timestamp{referenceTime}, 564 Name: String("name"), 565 Email: String("email"), 566 Login: String("login"), 567 }, 568 Committer: &CommitAuthor{ 569 Date: &Timestamp{referenceTime}, 570 Name: String("name"), 571 Email: String("email"), 572 Login: String("login"), 573 }, 574 Message: String("message"), 575 Tree: String("tree"), 576 Parents: []string{"p"}, 577 Signature: String("sign"), 578 } 579 580 want := `{ 581 "author": { 582 "date": ` + referenceTimeStr + `, 583 "name": "name", 584 "email": "email", 585 "username": "login" 586 }, 587 "committer": { 588 "date": ` + referenceTimeStr + `, 589 "name": "name", 590 "email": "email", 591 "username": "login" 592 }, 593 "message": "message", 594 "tree": "tree", 595 "parents": [ 596 "p" 597 ], 598 "signature": "sign" 599 }` 600 601 testJSONMarshal(t, u, want) 602 }