github.com/andrewhsu/cli/v2@v2.0.1-0.20210910131313-d4b4061f5b89/pkg/cmd/factory/http_test.go (about) 1 package factory 2 3 import ( 4 "fmt" 5 "net/http" 6 "net/http/httptest" 7 "os" 8 "regexp" 9 "testing" 10 11 "github.com/MakeNowJust/heredoc" 12 "github.com/andrewhsu/cli/v2/pkg/iostreams" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func TestNewHTTPClient(t *testing.T) { 18 type args struct { 19 config configGetter 20 appVersion string 21 setAccept bool 22 } 23 tests := []struct { 24 name string 25 args args 26 envDebug string 27 host string 28 wantHeader map[string]string 29 wantStderr string 30 }{ 31 { 32 name: "github.com with Accept header", 33 args: args{ 34 config: tinyConfig{"github.com:oauth_token": "MYTOKEN"}, 35 appVersion: "v1.2.3", 36 setAccept: true, 37 }, 38 host: "github.com", 39 wantHeader: map[string]string{ 40 "authorization": "token MYTOKEN", 41 "user-agent": "GitHub CLI v1.2.3", 42 "accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview", 43 }, 44 wantStderr: "", 45 }, 46 { 47 name: "github.com no Accept header", 48 args: args{ 49 config: tinyConfig{"github.com:oauth_token": "MYTOKEN"}, 50 appVersion: "v1.2.3", 51 setAccept: false, 52 }, 53 host: "github.com", 54 wantHeader: map[string]string{ 55 "authorization": "token MYTOKEN", 56 "user-agent": "GitHub CLI v1.2.3", 57 "accept": "", 58 }, 59 wantStderr: "", 60 }, 61 { 62 name: "github.com no authentication token", 63 args: args{ 64 config: tinyConfig{"example.com:oauth_token": "MYTOKEN"}, 65 appVersion: "v1.2.3", 66 setAccept: true, 67 }, 68 host: "github.com", 69 wantHeader: map[string]string{ 70 "authorization": "", 71 "user-agent": "GitHub CLI v1.2.3", 72 "accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview", 73 }, 74 wantStderr: "", 75 }, 76 { 77 name: "github.com in verbose mode", 78 args: args{ 79 config: tinyConfig{"github.com:oauth_token": "MYTOKEN"}, 80 appVersion: "v1.2.3", 81 setAccept: true, 82 }, 83 host: "github.com", 84 envDebug: "api", 85 wantHeader: map[string]string{ 86 "authorization": "token MYTOKEN", 87 "user-agent": "GitHub CLI v1.2.3", 88 "accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview", 89 }, 90 wantStderr: heredoc.Doc(` 91 * Request at <time> 92 * Request to http://<host>:<port> 93 > GET / HTTP/1.1 94 > Host: github.com 95 > Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview 96 > Authorization: token ████████████████████ 97 > User-Agent: GitHub CLI v1.2.3 98 99 < HTTP/1.1 204 No Content 100 < Date: <time> 101 102 * Request took <duration> 103 `), 104 }, 105 { 106 name: "GHES Accept header", 107 args: args{ 108 config: tinyConfig{"example.com:oauth_token": "GHETOKEN"}, 109 appVersion: "v1.2.3", 110 setAccept: true, 111 }, 112 host: "example.com", 113 wantHeader: map[string]string{ 114 "authorization": "token GHETOKEN", 115 "user-agent": "GitHub CLI v1.2.3", 116 "accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview, application/vnd.github.antiope-preview, application/vnd.github.shadow-cat-preview", 117 }, 118 wantStderr: "", 119 }, 120 } 121 122 var gotReq *http.Request 123 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 124 gotReq = r 125 w.WriteHeader(http.StatusNoContent) 126 })) 127 defer ts.Close() 128 129 for _, tt := range tests { 130 t.Run(tt.name, func(t *testing.T) { 131 oldDebug := os.Getenv("DEBUG") 132 os.Setenv("DEBUG", tt.envDebug) 133 t.Cleanup(func() { 134 os.Setenv("DEBUG", oldDebug) 135 }) 136 137 io, _, _, stderr := iostreams.Test() 138 client, err := NewHTTPClient(io, tt.args.config, tt.args.appVersion, tt.args.setAccept) 139 require.NoError(t, err) 140 141 req, err := http.NewRequest("GET", ts.URL, nil) 142 req.Host = tt.host 143 require.NoError(t, err) 144 145 res, err := client.Do(req) 146 require.NoError(t, err) 147 148 for name, value := range tt.wantHeader { 149 assert.Equal(t, value, gotReq.Header.Get(name), name) 150 } 151 152 assert.Equal(t, 204, res.StatusCode) 153 assert.Equal(t, tt.wantStderr, normalizeVerboseLog(stderr.String())) 154 }) 155 } 156 } 157 158 type tinyConfig map[string]string 159 160 func (c tinyConfig) Get(host, key string) (string, error) { 161 return c[fmt.Sprintf("%s:%s", host, key)], nil 162 } 163 164 var requestAtRE = regexp.MustCompile(`(?m)^\* Request at .+`) 165 var dateRE = regexp.MustCompile(`(?m)^< Date: .+`) 166 var hostWithPortRE = regexp.MustCompile(`127\.0\.0\.1:\d+`) 167 var durationRE = regexp.MustCompile(`(?m)^\* Request took .+`) 168 169 func normalizeVerboseLog(t string) string { 170 t = requestAtRE.ReplaceAllString(t, "* Request at <time>") 171 t = hostWithPortRE.ReplaceAllString(t, "<host>:<port>") 172 t = dateRE.ReplaceAllString(t, "< Date: <time>") 173 t = durationRE.ReplaceAllString(t, "* Request took <duration>") 174 return t 175 }