go.fuchsia.dev/jiri@v0.0.0-20240502161911-b66513b29486/gerrit/gerrit_test.go (about)

     1  // Copyright 2015 The Vanadium 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  	"fmt"
     9  	"reflect"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  func TestParseQueryResults(t *testing.T) {
    15  	t.Parallel()
    16  	input := `)]}'
    17  	[
    18  		{
    19  			"change_id": "I26f771cebd6e512b89e98bec1fadfa1cb2aad6e8",
    20  			"current_revision": "3654e38b2f80a5410ea94f1d7321477d89cac391",
    21  			"project": "vanadium",
    22  			"owner": {
    23  				"_account_id": 1234,
    24  				"name": "John Doe",
    25  				"email": "john.doe@example.com"
    26  			},
    27  			"revisions": {
    28  				"3654e38b2f80a5410ea94f1d7321477d89cac391": {
    29  					"fetch": {
    30  						"http": {
    31  							"ref": "refs/changes/40/4440/1"
    32  						}
    33  					}
    34  				}
    35  			}
    36  		},
    37  		{
    38  			"change_id": "I26f771cebd6e512b89e98bec1fadfa1cb2aad6e8",
    39  			"current_revision": "3654e38b2f80a5410ea94f1d7321477d89cac391",
    40  			"labels": {
    41  				"Code-Review": {},
    42  				"Verified": {}
    43  			},
    44  			"project": "vanadium",
    45  			"owner": {
    46  				"_account_id": 1234,
    47  				"name": "John Doe",
    48  				"email": "john.doe@example.com"
    49  			},
    50  			"topic": "test",
    51  			"revisions": {
    52  				"3654e38b2f80a5410ea94f1d7321477d89cac391": {
    53  					"fetch": {
    54  						"http": {
    55  							"ref": "refs/changes/40/4440/1"
    56  						}
    57  					},
    58  					"commit": {
    59  						"message": "MultiPart: 1/3\nPresubmitTest: none"
    60  					}
    61  				}
    62  			}
    63  		},
    64  		{
    65  			"change_id": "I35d83f8adae5b7db1974062fdc744f700e456677",
    66  			"current_revision": "b60413712472f1b576c7be951c4de309c6edaa53",
    67  			"project": "tools",
    68  			"owner": {
    69  				"_account_id": 1234,
    70  				"name": "John Doe",
    71  				"email": "john.doe@example.com"
    72  			},
    73  			"revisions": {
    74  				"b60413712472f1b576c7be951c4de309c6edaa53": {
    75  					"fetch": {
    76  						"http": {
    77  							"ref": "refs/changes/43/4443/1"
    78  						}
    79  					},
    80  					"commit": {
    81  						"message": "this change is great.\nPresubmitTest: none"
    82  					}
    83  				}
    84  			}
    85  		}
    86  	]
    87  	`
    88  	expectedFields := []struct {
    89  		ref           string
    90  		project       string
    91  		ownerEmail    string
    92  		multiPart     *MultiPartCLInfo
    93  		presubmitType PresubmitTestType
    94  	}{
    95  		{
    96  			ref:           "refs/changes/40/4440/1",
    97  			project:       "vanadium",
    98  			ownerEmail:    "john.doe@example.com",
    99  			multiPart:     nil,
   100  			presubmitType: PresubmitTestTypeAll,
   101  		},
   102  		{
   103  			ref:        "refs/changes/40/4440/1",
   104  			project:    "vanadium",
   105  			ownerEmail: "john.doe@example.com",
   106  			multiPart: &MultiPartCLInfo{
   107  				Topic: "test",
   108  				Index: 1,
   109  				Total: 3,
   110  			},
   111  			presubmitType: PresubmitTestTypeNone,
   112  		},
   113  		{
   114  			ref:           "refs/changes/43/4443/1",
   115  			project:       "tools",
   116  			ownerEmail:    "john.doe@example.com",
   117  			multiPart:     nil,
   118  			presubmitType: PresubmitTestTypeNone,
   119  		},
   120  	}
   121  
   122  	got, err := parseQueryResults(strings.NewReader(input))
   123  	if err != nil {
   124  		t.Fatalf("%v", err)
   125  	}
   126  	for i, curChange := range got {
   127  		f := expectedFields[i]
   128  		if want, got := f.ref, curChange.Reference(); want != got {
   129  			t.Fatalf("%d: want: %q, got: %q", i, want, got)
   130  		}
   131  		if want, got := f.project, curChange.Project; want != got {
   132  			t.Fatalf("%d: want: %q, got: %q", i, want, got)
   133  		}
   134  		if want, got := f.ownerEmail, curChange.OwnerEmail(); want != got {
   135  			t.Fatalf("%d: want: %q, got: %q", i, want, got)
   136  		}
   137  		if want, got := f.multiPart, curChange.MultiPart; !reflect.DeepEqual(want, got) {
   138  			t.Fatalf("%d: want:\n%#v\ngot:\n%#v\n", i, want, got)
   139  		}
   140  		if want, got := f.presubmitType, curChange.PresubmitTest; want != got {
   141  			t.Fatalf("%d: want: %q, got: %q", i, want, got)
   142  		}
   143  	}
   144  }
   145  
   146  func TestParseMultiPartMatch(t *testing.T) {
   147  	t.Parallel()
   148  	type testCase struct {
   149  		str             string
   150  		expectNoMatches bool
   151  		expectedIndex   string
   152  		expectedTotal   string
   153  	}
   154  	testCases := []testCase{
   155  		{
   156  			str:             "message...\nMultiPart: a/3",
   157  			expectNoMatches: true,
   158  		},
   159  		{
   160  			str:             "message...\n1/3",
   161  			expectNoMatches: true,
   162  		},
   163  		{
   164  			str:           "message...\nMultiPart:1/2",
   165  			expectedIndex: "1",
   166  			expectedTotal: "2",
   167  		},
   168  		{
   169  			str:           "message...\nMultiPart: 1/2",
   170  			expectedIndex: "1",
   171  			expectedTotal: "2",
   172  		},
   173  		{
   174  			str:           "message...\nMultiPart: 1 /2",
   175  			expectedIndex: "1",
   176  			expectedTotal: "2",
   177  		},
   178  		{
   179  			str:           "message...\nMultiPart: 1/ 2",
   180  			expectedIndex: "1",
   181  			expectedTotal: "2",
   182  		},
   183  		{
   184  			str:           "message...\nMultiPart: 1 / 2",
   185  			expectedIndex: "1",
   186  			expectedTotal: "2",
   187  		},
   188  		{
   189  			str:           "message...\nMultiPart: 123/234",
   190  			expectedIndex: "123",
   191  			expectedTotal: "234",
   192  		},
   193  	}
   194  	for _, test := range testCases {
   195  		multiPartCLInfo, _ := parseMultiPartMatch(test.str)
   196  		if test.expectNoMatches && multiPartCLInfo != nil {
   197  			t.Fatalf("want no matches, got %v", multiPartCLInfo)
   198  		}
   199  		if !test.expectNoMatches && multiPartCLInfo == nil {
   200  			t.Fatalf("want matches, got no matches")
   201  		}
   202  		if !test.expectNoMatches {
   203  			if want, got := test.expectedIndex, fmt.Sprintf("%d", multiPartCLInfo.Index); want != got {
   204  				t.Fatalf("want 'index' %q, got %q", want, got)
   205  			}
   206  			if want, got := test.expectedTotal, fmt.Sprintf("%d", multiPartCLInfo.Total); want != got {
   207  				t.Fatalf("want 'total' %q, got %q", want, got)
   208  			}
   209  		}
   210  	}
   211  }
   212  
   213  func TestParseValidGitCookieFile(t *testing.T) {
   214  	t.Parallel()
   215  	// Valid content.
   216  	gitCookieFileContent := `
   217  vanadium.googlesource.com	FALSE	/	TRUE	2147483647	o	git-johndoe.example.com=12345
   218  vanadium-review.googlesource.com	FALSE	/	TRUE	2147483647	o	git-johndoe.example.com=54321
   219  .googlesource.com	FALSE	/	TRUE	2147483647	o	git-johndoe.example.com=12321
   220  	`
   221  	got, err := parseGitCookieFile(strings.NewReader(gitCookieFileContent))
   222  	expected := map[string]*credentials{
   223  		"vanadium.googlesource.com": {
   224  			username: "git-johndoe.example.com",
   225  			password: "12345",
   226  		},
   227  		"vanadium-review.googlesource.com": {
   228  			username: "git-johndoe.example.com",
   229  			password: "54321",
   230  		},
   231  		".googlesource.com": {
   232  			username: "git-johndoe.example.com",
   233  			password: "12321",
   234  		},
   235  	}
   236  	if err != nil {
   237  		t.Fatalf("want no errors, got: %v", err)
   238  	}
   239  	if !reflect.DeepEqual(expected, got) {
   240  		t.Fatalf("want: %#v, got: %#v", expected, got)
   241  	}
   242  }
   243  
   244  func TestParseInvalidGitCookieFile(t *testing.T) {
   245  	t.Parallel()
   246  	// Content with invalid entries which should be skipped.
   247  	gitCookieFileContentWithInvalidEntries := `
   248  vanadium.googlesource.com	FALSE	/	TRUE	2147483647	o	git-johndoe.example.com
   249  vanadium-review.googlesource.com FALSE / TRUE 2147483647 o git-johndoe.example.com=54321
   250  vanadium.googlesource.com	FALSE	/	TRUE	2147483647	o	git-johndoe.example.com=12345
   251  vanadium-review.googlesource.com	FALSE	/	TRUE	2147483647	o
   252  	`
   253  	got, err := parseGitCookieFile(strings.NewReader(gitCookieFileContentWithInvalidEntries))
   254  	expected := map[string]*credentials{
   255  		"vanadium.googlesource.com": {
   256  			username: "git-johndoe.example.com",
   257  			password: "12345",
   258  		},
   259  	}
   260  	if err != nil {
   261  		t.Fatalf("want no errors, got: %v", err)
   262  	}
   263  	if !reflect.DeepEqual(expected, got) {
   264  		t.Fatalf("want: %#v, got: %#v", expected, got)
   265  	}
   266  }
   267  
   268  func TestParseValidNetRcFile(t *testing.T) {
   269  	t.Parallel()
   270  	// Valid content.
   271  	netrcFileContent := `
   272  machine vanadium.googlesource.com login git-johndoe.example.com password 12345
   273  machine vanadium-review.googlesource.com login git-johndoe.example.com password 54321
   274  	`
   275  	got, err := parseNetrcFile(strings.NewReader(netrcFileContent))
   276  	expected := map[string]*credentials{
   277  		"vanadium.googlesource.com": {
   278  			username: "git-johndoe.example.com",
   279  			password: "12345",
   280  		},
   281  		"vanadium-review.googlesource.com": {
   282  			username: "git-johndoe.example.com",
   283  			password: "54321",
   284  		},
   285  	}
   286  	if err != nil {
   287  		t.Fatalf("want no errors, got: %v", err)
   288  	}
   289  	if !reflect.DeepEqual(expected, got) {
   290  		t.Fatalf("want: %#v, got: %#v", expected, got)
   291  	}
   292  }
   293  
   294  func TestParseInvalidNetRcFile(t *testing.T) {
   295  	t.Parallel()
   296  	// Content with invalid entries which should be skipped.
   297  	netRcFileContentWithInvalidEntries := `
   298  machine vanadium.googlesource.com login git-johndoe.example.com password
   299  machine_blah vanadium3.googlesource.com login git-johndoe.example.com password 12345
   300  machine vanadium2.googlesource.com login_blah git-johndoe.example.com password 12345
   301  machine vanadium4.googlesource.com login git-johndoe.example.com password_blah 12345
   302  machine vanadium-review.googlesource.com login git-johndoe.example.com password 54321
   303  	`
   304  	got, err := parseNetrcFile(strings.NewReader(netRcFileContentWithInvalidEntries))
   305  	expected := map[string]*credentials{
   306  		"vanadium-review.googlesource.com": {
   307  			username: "git-johndoe.example.com",
   308  			password: "54321",
   309  		},
   310  	}
   311  	if err != nil {
   312  		t.Fatalf("want no errors, got: %v", err)
   313  	}
   314  	if !reflect.DeepEqual(expected, got) {
   315  		t.Fatalf("want: %#v, got: %#v", expected, got)
   316  	}
   317  }
   318  
   319  func TestParseRefString(t *testing.T) {
   320  	t.Parallel()
   321  	type testCase struct {
   322  		ref              string
   323  		expectErr        bool
   324  		expectedCL       int
   325  		expectedPatchSet int
   326  	}
   327  	testCases := []testCase{
   328  		// Normal case
   329  		{
   330  			ref:              "ref/changes/12/3412/2",
   331  			expectedCL:       3412,
   332  			expectedPatchSet: 2,
   333  		},
   334  		// Error cases
   335  		{
   336  			ref:       "ref/123",
   337  			expectErr: true,
   338  		},
   339  		{
   340  			ref:       "ref/changes/12/a/2",
   341  			expectErr: true,
   342  		},
   343  		{
   344  			ref:       "ref/changes/12/3412/a",
   345  			expectErr: true,
   346  		},
   347  	}
   348  	for _, test := range testCases {
   349  		cl, patchset, err := ParseRefString(test.ref)
   350  		if test.expectErr {
   351  			if err == nil {
   352  				t.Fatalf("want errors, got: %v", err)
   353  			}
   354  		} else {
   355  			if err != nil {
   356  				t.Fatalf("want no errors, got: %v", err)
   357  			}
   358  			if cl != test.expectedCL {
   359  				t.Fatalf("want %v, got %v", test.expectedCL, cl)
   360  			}
   361  			if patchset != test.expectedPatchSet {
   362  				t.Fatalf("want %v, got %v", test.expectedPatchSet, patchset)
   363  			}
   364  		}
   365  	}
   366  }
   367  
   368  func TestReference(t *testing.T) {
   369  	t.Parallel()
   370  	testOpts := CLOpts{
   371  		RemoteBranch: "main",
   372  		Labels:       []string{"Commit-Queue+1"},
   373  		Reviewers:    []string{"a@example.com", "b@example.com"},
   374  	}
   375  	gold := "refs/for/main%l=Commit-Queue+1,r=a@example.com,r=b@example.com"
   376  	ref := Reference(testOpts)
   377  	if gold != ref {
   378  		t.Errorf("expecting %q, got %q", gold, ref)
   379  	}
   380  }
   381  
   382  // TODO(jsimsa): Add a test for the hostCredentials function that
   383  // exercises the logic that reads the .netrc and git cookie files.