github.com/tahsinrahman/goreleaser@v0.79.1/internal/http/http_test.go (about) 1 package http 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "io/ioutil" 8 h "net/http" 9 "net/http/httptest" 10 "sync" 11 "testing" 12 13 "github.com/pkg/errors" 14 15 "github.com/goreleaser/goreleaser/config" 16 "github.com/goreleaser/goreleaser/context" 17 "github.com/goreleaser/goreleaser/internal/artifact" 18 ) 19 20 var ( 21 mux *h.ServeMux 22 srv *httptest.Server 23 ) 24 25 func setup() { 26 mux = h.NewServeMux() 27 srv = httptest.NewServer(mux) 28 } 29 30 func teardown() { 31 srv.Close() 32 } 33 34 func TestDefaults(t *testing.T) { 35 type args struct { 36 puts []config.Put 37 } 38 tests := []struct { 39 name string 40 args args 41 wantErr bool 42 wantMode string 43 }{ 44 {"set default", args{[]config.Put{{Name: "a", Target: "http://"}}}, false, ModeArchive}, 45 {"keep value", args{[]config.Put{{Name: "a", Target: "http://...", Mode: ModeBinary}}}, false, ModeBinary}, 46 } 47 for _, tt := range tests { 48 t.Run(tt.name, func(t *testing.T) { 49 if err := Defaults(tt.args.puts); (err != nil) != tt.wantErr { 50 t.Errorf("Defaults() error = %v, wantErr %v", err, tt.wantErr) 51 } 52 if tt.wantMode != tt.args.puts[0].Mode { 53 t.Errorf("Incorrect Defaults() mode %q , wanted %q", tt.args.puts[0].Mode, tt.wantMode) 54 } 55 }) 56 } 57 } 58 59 func TestCheckConfig(t *testing.T) { 60 ctx := context.New(config.Project{ProjectName: "blah"}) 61 ctx.Env["TEST_A_SECRET"] = "x" 62 type args struct { 63 ctx *context.Context 64 upload *config.Put 65 kind string 66 } 67 tests := []struct { 68 name string 69 args args 70 wantErr bool 71 }{ 72 {"ok", args{ctx, &config.Put{Name: "a", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, false}, 73 {"secret missing", args{ctx, &config.Put{Name: "b", Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true}, 74 {"target missing", args{ctx, &config.Put{Name: "a", Username: "pepe", Mode: ModeArchive}, "test"}, true}, 75 {"username missing", args{ctx, &config.Put{Name: "a", Target: "http://blabla", Mode: ModeArchive}, "test"}, true}, 76 {"name missing", args{ctx, &config.Put{Target: "http://blabla", Username: "pepe", Mode: ModeArchive}, "test"}, true}, 77 {"mode missing", args{ctx, &config.Put{Name: "a", Target: "http://blabla", Username: "pepe"}, "test"}, true}, 78 {"mode invalid", args{ctx, &config.Put{Name: "a", Target: "http://blabla", Username: "pepe", Mode: "blabla"}, "test"}, true}, 79 } 80 for _, tt := range tests { 81 t.Run(tt.name, func(t *testing.T) { 82 if err := CheckConfig(tt.args.ctx, tt.args.upload, tt.args.kind); (err != nil) != tt.wantErr { 83 t.Errorf("CheckConfig() error = %v, wantErr %v", err, tt.wantErr) 84 } 85 }) 86 } 87 } 88 89 func count(r io.Reader) (int64, error) { 90 var ( 91 c int64 92 b int64 93 err error 94 buf = make([]byte, 16) 95 ) 96 for b >= 0 && err == nil { 97 b, err := r.Read(buf) 98 if err != nil { 99 return c, err 100 } 101 c = c + int64(b) 102 } 103 return c, nil 104 } 105 106 type check struct { 107 path string 108 user string 109 pass string 110 content []byte 111 } 112 113 func checks(checks ...check) func(rs []*h.Request) error { 114 return func(rs []*h.Request) error { 115 if len(rs) != len(checks) { 116 return errors.New("expectations mismatch requests") 117 } 118 for _, r := range rs { 119 found := false 120 for _, c := range checks { 121 if c.path == r.RequestURI { 122 found = true 123 err := doCheck(c, r) 124 if err != nil { 125 return err 126 } 127 break 128 } 129 } 130 if !found { 131 return errors.Errorf("check not found for request %+v", r) 132 } 133 } 134 return nil 135 } 136 } 137 138 func doCheck(c check, r *h.Request) error { 139 contentLength := int64(len(c.content)) 140 if r.ContentLength != contentLength { 141 return errors.Errorf("request content-length header value %v unexpected, wanted %v", r.ContentLength, contentLength) 142 } 143 bs, err := ioutil.ReadAll(r.Body) 144 if err != nil { 145 return errors.Errorf("reading request body: %v", err) 146 } 147 if !bytes.Equal(bs, c.content) { 148 return errors.New("content does not match") 149 } 150 if int64(len(bs)) != contentLength { 151 return errors.Errorf("request content length %v unexpected, wanted %v", int64(len(bs)), contentLength) 152 } 153 if r.RequestURI != c.path { 154 return errors.Errorf("bad request uri %q, expecting %q", r.RequestURI, c.path) 155 } 156 if u, p, ok := r.BasicAuth(); !ok || u != c.user || p != c.pass { 157 return errors.Errorf("bad basic auth credentials: %s/%s", u, p) 158 } 159 return nil 160 } 161 162 func TestUpload(t *testing.T) { 163 setup() 164 defer teardown() 165 content := []byte("blah!") 166 requests := []*h.Request{} 167 var m sync.Mutex 168 mux.Handle("/", h.HandlerFunc(func(w h.ResponseWriter, r *h.Request) { 169 bs, err := ioutil.ReadAll(r.Body) 170 if err != nil { 171 w.WriteHeader(h.StatusInternalServerError) 172 fmt.Fprintf(w, "reading request body: %v", err) 173 return 174 } 175 r.Body = ioutil.NopCloser(bytes.NewReader(bs)) 176 m.Lock() 177 requests = append(requests, r) 178 m.Unlock() 179 w.WriteHeader(h.StatusCreated) 180 w.Header().Set("Location", r.URL.RequestURI()) 181 })) 182 assetOpen = func(k string, a *artifact.Artifact) (*asset, error) { 183 return &asset{ 184 ReadCloser: ioutil.NopCloser(bytes.NewReader(content)), 185 Size: int64(len(content)), 186 }, nil 187 } 188 defer assetOpenReset() 189 var is2xx ResponseChecker = func(r *h.Response) (string, error) { 190 if r.StatusCode/100 == 2 { 191 return r.Header.Get("Location"), nil 192 } 193 return "", errors.Errorf("unexpected http status code: %v", r.StatusCode) 194 } 195 ctx := context.New(config.Project{ProjectName: "blah"}) 196 ctx.Env["TEST_A_SECRET"] = "x" 197 ctx.Version = "2.1.0" 198 ctx.Artifacts = artifact.New() 199 for _, a := range []struct { 200 ext string 201 typ artifact.Type 202 }{ 203 {"---", artifact.DockerImage}, 204 {"deb", artifact.LinuxPackage}, 205 {"bin", artifact.Binary}, 206 {"tar", artifact.UploadableArchive}, 207 {"ubi", artifact.UploadableBinary}, 208 {"sum", artifact.Checksum}, 209 {"sig", artifact.Signature}, 210 } { 211 ctx.Artifacts.Add(artifact.Artifact{Name: "a." + a.ext, Path: "/a/a." + a.ext, Type: a.typ}) 212 } 213 tests := []struct { 214 name string 215 ctx *context.Context 216 wantErr bool 217 put config.Put 218 check func(r []*h.Request) error 219 }{ 220 {"archive", ctx, false, 221 config.Put{Mode: ModeArchive, Name: "a", Target: srv.URL + "/{{.ProjectName}}/{{.Version}}/", Username: "u1"}, 222 checks( 223 check{"/blah/2.1.0/a.deb", "u1", "x", content}, 224 check{"/blah/2.1.0/a.tar", "u1", "x", content}, 225 ), 226 }, 227 {"binary", ctx, false, 228 config.Put{Mode: ModeBinary, Name: "a", Target: srv.URL + "/{{.ProjectName}}/{{.Version}}/", Username: "u2"}, 229 checks(check{"/blah/2.1.0/a.ubi", "u2", "x", content}), 230 }, 231 {"archive-with-checksum-and-signature", ctx, false, 232 config.Put{Mode: ModeArchive, Name: "a", Target: srv.URL + "/{{.ProjectName}}/{{.Version}}/", Username: "u3", Checksum: true, Signature: true}, 233 checks( 234 check{"/blah/2.1.0/a.deb", "u3", "x", content}, 235 check{"/blah/2.1.0/a.tar", "u3", "x", content}, 236 check{"/blah/2.1.0/a.sum", "u3", "x", content}, 237 check{"/blah/2.1.0/a.sig", "u3", "x", content}, 238 ), 239 }, 240 } 241 for _, tt := range tests { 242 t.Run(tt.name, func(t *testing.T) { 243 requests = nil 244 if err := Upload(tt.ctx, []config.Put{tt.put}, "test", is2xx); (err != nil) != tt.wantErr { 245 t.Errorf("Upload() error = %v, wantErr %v", err, tt.wantErr) 246 } 247 if err := tt.check(requests); err != nil { 248 t.Errorf("Upload() request invalid. Error: %v", err) 249 } 250 }) 251 } 252 }