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