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