github.com/google/go-github/v65@v65.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  }