github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/pkg/cmd/auth/shared/login_flow_test.go (about) 1 package shared 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "net/http" 7 "path/filepath" 8 "testing" 9 10 "github.com/MakeNowJust/heredoc" 11 "github.com/andrewhsu/cli/v2/internal/run" 12 "github.com/andrewhsu/cli/v2/pkg/httpmock" 13 "github.com/andrewhsu/cli/v2/pkg/iostreams" 14 "github.com/andrewhsu/cli/v2/pkg/prompt" 15 "github.com/stretchr/testify/assert" 16 ) 17 18 type tinyConfig map[string]string 19 20 func (c tinyConfig) Get(host, key string) (string, error) { 21 return c[fmt.Sprintf("%s:%s", host, key)], nil 22 } 23 24 func (c tinyConfig) Set(host string, key string, value string) error { 25 c[fmt.Sprintf("%s:%s", host, key)] = value 26 return nil 27 } 28 29 func (c tinyConfig) Write() error { 30 return nil 31 } 32 33 func TestLogin_ssh(t *testing.T) { 34 dir := t.TempDir() 35 io, _, stdout, stderr := iostreams.Test() 36 37 tr := httpmock.Registry{} 38 defer tr.Verify(t) 39 40 tr.Register( 41 httpmock.REST("GET", "api/v3/"), 42 httpmock.ScopesResponder("repo,read:org")) 43 tr.Register( 44 httpmock.GraphQL(`query UserCurrent\b`), 45 httpmock.StringResponse(`{"data":{"viewer":{ "login": "monalisa" }}}`)) 46 tr.Register( 47 httpmock.REST("POST", "api/v3/user/keys"), 48 httpmock.StringResponse(`{}`)) 49 50 ask, askRestore := prompt.InitAskStubber() 51 defer askRestore() 52 53 ask.StubOne("SSH") // preferred protocol 54 ask.StubOne(true) // generate a new key 55 ask.StubOne("monkey") // enter a passphrase 56 ask.StubOne(1) // paste a token 57 ask.StubOne("ATOKEN") // token 58 59 rs, runRestore := run.Stub() 60 defer runRestore(t) 61 62 keyFile := filepath.Join(dir, "id_ed25519") 63 rs.Register(`ssh-keygen`, 0, "", func(args []string) { 64 expected := []string{ 65 "ssh-keygen", "-t", "ed25519", 66 "-C", "", 67 "-N", "monkey", 68 "-f", keyFile, 69 } 70 assert.Equal(t, expected, args) 71 // simulate that the public key file has been generated 72 _ = ioutil.WriteFile(keyFile+".pub", []byte("PUBKEY"), 0600) 73 }) 74 75 cfg := tinyConfig{} 76 77 err := Login(&LoginOptions{ 78 IO: io, 79 Config: &cfg, 80 HTTPClient: &http.Client{Transport: &tr}, 81 Hostname: "example.com", 82 Interactive: true, 83 sshContext: sshContext{ 84 configDir: dir, 85 keygenExe: "ssh-keygen", 86 }, 87 }) 88 assert.NoError(t, err) 89 90 assert.Equal(t, "", stdout.String()) 91 assert.Equal(t, heredoc.Docf(` 92 Tip: you can generate a Personal Access Token here https://example.com/settings/tokens 93 The minimum required scopes are 'repo', 'read:org', 'admin:public_key'. 94 - gh config set -h example.com git_protocol ssh 95 ✓ Configured git protocol 96 ✓ Uploaded the SSH key to your GitHub account: %s.pub 97 ✓ Logged in as monalisa 98 `, keyFile), stderr.String()) 99 100 assert.Equal(t, "monalisa", cfg["example.com:user"]) 101 assert.Equal(t, "ATOKEN", cfg["example.com:oauth_token"]) 102 assert.Equal(t, "ssh", cfg["example.com:git_protocol"]) 103 } 104 105 func Test_scopesSentence(t *testing.T) { 106 type args struct { 107 scopes []string 108 isEnterprise bool 109 } 110 tests := []struct { 111 name string 112 args args 113 want string 114 }{ 115 { 116 name: "basic scopes", 117 args: args{ 118 scopes: []string{"repo", "read:org"}, 119 isEnterprise: false, 120 }, 121 want: "'repo', 'read:org'", 122 }, 123 { 124 name: "empty", 125 args: args{ 126 scopes: []string(nil), 127 isEnterprise: false, 128 }, 129 want: "", 130 }, 131 { 132 name: "workflow scope for dotcom", 133 args: args{ 134 scopes: []string{"repo", "workflow"}, 135 isEnterprise: false, 136 }, 137 want: "'repo', 'workflow'", 138 }, 139 { 140 name: "workflow scope for GHE", 141 args: args{ 142 scopes: []string{"repo", "workflow"}, 143 isEnterprise: true, 144 }, 145 want: "'repo', 'workflow' (GHE 3.0+)", 146 }, 147 } 148 for _, tt := range tests { 149 t.Run(tt.name, func(t *testing.T) { 150 if got := scopesSentence(tt.args.scopes, tt.args.isEnterprise); got != tt.want { 151 t.Errorf("scopesSentence() = %q, want %q", got, tt.want) 152 } 153 }) 154 } 155 }