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 6package github 7 8import ( 9 "bytes" 10 "context" 11 "encoding/json" 12 "fmt" 13 "io/ioutil" 14 "net/http" 15 "os" 16 "reflect" 17 "strings" 18 "testing" 19) 20 21func TestRepositoriesService_ListReleases(t *testing.T) { 22 client, mux, _, teardown := setup() 23 defer teardown() 24 25 mux.HandleFunc("/repos/o/r/releases", func(w http.ResponseWriter, r *http.Request) { 26 testMethod(t, r, "GET") 27 testFormValues(t, r, values{"page": "2"}) 28 fmt.Fprint(w, `[{"id":1}]`) 29 }) 30 31 opt := &ListOptions{Page: 2} 32 releases, _, err := client.Repositories.ListReleases(context.Background(), "o", "r", opt) 33 if err != nil { 34 t.Errorf("Repositories.ListReleases returned error: %v", err) 35 } 36 want := []*RepositoryRelease{{ID: Int64(1)}} 37 if !reflect.DeepEqual(releases, want) { 38 t.Errorf("Repositories.ListReleases returned %+v, want %+v", releases, want) 39 } 40} 41 42func TestRepositoriesService_GetRelease(t *testing.T) { 43 client, mux, _, teardown := setup() 44 defer teardown() 45 46 mux.HandleFunc("/repos/o/r/releases/1", func(w http.ResponseWriter, r *http.Request) { 47 testMethod(t, r, "GET") 48 fmt.Fprint(w, `{"id":1,"author":{"login":"l"}}`) 49 }) 50 51 release, resp, err := client.Repositories.GetRelease(context.Background(), "o", "r", 1) 52 if err != nil { 53 t.Errorf("Repositories.GetRelease returned error: %v\n%v", err, resp.Body) 54 } 55 56 want := &RepositoryRelease{ID: Int64(1), Author: &User{Login: String("l")}} 57 if !reflect.DeepEqual(release, want) { 58 t.Errorf("Repositories.GetRelease returned %+v, want %+v", release, want) 59 } 60} 61 62func TestRepositoriesService_GetLatestRelease(t *testing.T) { 63 client, mux, _, teardown := setup() 64 defer teardown() 65 66 mux.HandleFunc("/repos/o/r/releases/latest", func(w http.ResponseWriter, r *http.Request) { 67 testMethod(t, r, "GET") 68 fmt.Fprint(w, `{"id":3}`) 69 }) 70 71 release, resp, err := client.Repositories.GetLatestRelease(context.Background(), "o", "r") 72 if err != nil { 73 t.Errorf("Repositories.GetLatestRelease returned error: %v\n%v", err, resp.Body) 74 } 75 76 want := &RepositoryRelease{ID: Int64(3)} 77 if !reflect.DeepEqual(release, want) { 78 t.Errorf("Repositories.GetLatestRelease returned %+v, want %+v", release, want) 79 } 80} 81 82func TestRepositoriesService_GetReleaseByTag(t *testing.T) { 83 client, mux, _, teardown := setup() 84 defer teardown() 85 86 mux.HandleFunc("/repos/o/r/releases/tags/foo", func(w http.ResponseWriter, r *http.Request) { 87 testMethod(t, r, "GET") 88 fmt.Fprint(w, `{"id":13}`) 89 }) 90 91 release, resp, err := client.Repositories.GetReleaseByTag(context.Background(), "o", "r", "foo") 92 if err != nil { 93 t.Errorf("Repositories.GetReleaseByTag returned error: %v\n%v", err, resp.Body) 94 } 95 96 want := &RepositoryRelease{ID: Int64(13)} 97 if !reflect.DeepEqual(release, want) { 98 t.Errorf("Repositories.GetReleaseByTag returned %+v, want %+v", release, want) 99 } 100} 101 102func TestRepositoriesService_CreateRelease(t *testing.T) { 103 client, mux, _, teardown := setup() 104 defer teardown() 105 106 input := &RepositoryRelease{ 107 Name: String("v1.0"), 108 // Fields to be removed: 109 ID: Int64(2), 110 CreatedAt: &Timestamp{referenceTime}, 111 PublishedAt: &Timestamp{referenceTime}, 112 URL: String("http://url/"), 113 HTMLURL: String("http://htmlurl/"), 114 AssetsURL: String("http://assetsurl/"), 115 Assets: []ReleaseAsset{{ID: Int64(5)}}, 116 UploadURL: String("http://uploadurl/"), 117 ZipballURL: String("http://zipballurl/"), 118 TarballURL: String("http://tarballurl/"), 119 Author: &User{Name: String("octocat")}, 120 NodeID: String("nodeid"), 121 } 122 123 mux.HandleFunc("/repos/o/r/releases", func(w http.ResponseWriter, r *http.Request) { 124 v := new(repositoryReleaseRequest) 125 json.NewDecoder(r.Body).Decode(v) 126 127 testMethod(t, r, "POST") 128 want := &repositoryReleaseRequest{Name: String("v1.0")} 129 if !reflect.DeepEqual(v, want) { 130 t.Errorf("Request body = %+v, want %+v", v, want) 131 } 132 fmt.Fprint(w, `{"id":1}`) 133 }) 134 135 release, _, err := client.Repositories.CreateRelease(context.Background(), "o", "r", input) 136 if err != nil { 137 t.Errorf("Repositories.CreateRelease returned error: %v", err) 138 } 139 140 want := &RepositoryRelease{ID: Int64(1)} 141 if !reflect.DeepEqual(release, want) { 142 t.Errorf("Repositories.CreateRelease returned %+v, want %+v", release, want) 143 } 144} 145 146func TestRepositoriesService_EditRelease(t *testing.T) { 147 client, mux, _, teardown := setup() 148 defer teardown() 149 150 input := &RepositoryRelease{ 151 Name: String("n"), 152 // Fields to be removed: 153 ID: Int64(2), 154 CreatedAt: &Timestamp{referenceTime}, 155 PublishedAt: &Timestamp{referenceTime}, 156 URL: String("http://url/"), 157 HTMLURL: String("http://htmlurl/"), 158 AssetsURL: String("http://assetsurl/"), 159 Assets: []ReleaseAsset{{ID: Int64(5)}}, 160 UploadURL: String("http://uploadurl/"), 161 ZipballURL: String("http://zipballurl/"), 162 TarballURL: String("http://tarballurl/"), 163 Author: &User{Name: String("octocat")}, 164 NodeID: String("nodeid"), 165 } 166 167 mux.HandleFunc("/repos/o/r/releases/1", func(w http.ResponseWriter, r *http.Request) { 168 v := new(repositoryReleaseRequest) 169 json.NewDecoder(r.Body).Decode(v) 170 171 testMethod(t, r, "PATCH") 172 want := &repositoryReleaseRequest{Name: String("n")} 173 if !reflect.DeepEqual(v, want) { 174 t.Errorf("Request body = %+v, want %+v", v, want) 175 } 176 fmt.Fprint(w, `{"id":1}`) 177 }) 178 179 release, _, err := client.Repositories.EditRelease(context.Background(), "o", "r", 1, input) 180 if err != nil { 181 t.Errorf("Repositories.EditRelease returned error: %v", err) 182 } 183 want := &RepositoryRelease{ID: Int64(1)} 184 if !reflect.DeepEqual(release, want) { 185 t.Errorf("Repositories.EditRelease returned = %+v, want %+v", release, want) 186 } 187} 188 189func TestRepositoriesService_DeleteRelease(t *testing.T) { 190 client, mux, _, teardown := setup() 191 defer teardown() 192 193 mux.HandleFunc("/repos/o/r/releases/1", func(w http.ResponseWriter, r *http.Request) { 194 testMethod(t, r, "DELETE") 195 }) 196 197 _, err := client.Repositories.DeleteRelease(context.Background(), "o", "r", 1) 198 if err != nil { 199 t.Errorf("Repositories.DeleteRelease returned error: %v", err) 200 } 201} 202 203func TestRepositoriesService_ListReleaseAssets(t *testing.T) { 204 client, mux, _, teardown := setup() 205 defer teardown() 206 207 mux.HandleFunc("/repos/o/r/releases/1/assets", func(w http.ResponseWriter, r *http.Request) { 208 testMethod(t, r, "GET") 209 testFormValues(t, r, values{"page": "2"}) 210 fmt.Fprint(w, `[{"id":1}]`) 211 }) 212 213 opt := &ListOptions{Page: 2} 214 assets, _, err := client.Repositories.ListReleaseAssets(context.Background(), "o", "r", 1, opt) 215 if err != nil { 216 t.Errorf("Repositories.ListReleaseAssets returned error: %v", err) 217 } 218 want := []*ReleaseAsset{{ID: Int64(1)}} 219 if !reflect.DeepEqual(assets, want) { 220 t.Errorf("Repositories.ListReleaseAssets returned %+v, want %+v", assets, want) 221 } 222} 223 224func TestRepositoriesService_GetReleaseAsset(t *testing.T) { 225 client, mux, _, teardown := setup() 226 defer teardown() 227 228 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 229 testMethod(t, r, "GET") 230 fmt.Fprint(w, `{"id":1}`) 231 }) 232 233 asset, _, err := client.Repositories.GetReleaseAsset(context.Background(), "o", "r", 1) 234 if err != nil { 235 t.Errorf("Repositories.GetReleaseAsset returned error: %v", err) 236 } 237 want := &ReleaseAsset{ID: Int64(1)} 238 if !reflect.DeepEqual(asset, want) { 239 t.Errorf("Repositories.GetReleaseAsset returned %+v, want %+v", asset, want) 240 } 241} 242 243func TestRepositoriesService_DownloadReleaseAsset_Stream(t *testing.T) { 244 client, mux, _, teardown := setup() 245 defer teardown() 246 247 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 248 testMethod(t, r, "GET") 249 testHeader(t, r, "Accept", defaultMediaType) 250 w.Header().Set("Content-Type", "application/octet-stream") 251 w.Header().Set("Content-Disposition", "attachment; filename=hello-world.txt") 252 fmt.Fprint(w, "Hello World") 253 }) 254 255 reader, _, err := client.Repositories.DownloadReleaseAsset(context.Background(), "o", "r", 1) 256 if err != nil { 257 t.Errorf("Repositories.DownloadReleaseAsset returned error: %v", err) 258 } 259 want := []byte("Hello World") 260 content, err := ioutil.ReadAll(reader) 261 if err != nil { 262 t.Errorf("Repositories.DownloadReleaseAsset returned bad reader: %v", err) 263 } 264 if !bytes.Equal(want, content) { 265 t.Errorf("Repositories.DownloadReleaseAsset returned %+v, want %+v", content, want) 266 } 267} 268 269func TestRepositoriesService_DownloadReleaseAsset_Redirect(t *testing.T) { 270 client, mux, _, teardown := setup() 271 defer teardown() 272 273 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 274 testMethod(t, r, "GET") 275 testHeader(t, r, "Accept", defaultMediaType) 276 http.Redirect(w, r, "/yo", http.StatusFound) 277 }) 278 279 _, got, err := client.Repositories.DownloadReleaseAsset(context.Background(), "o", "r", 1) 280 if err != nil { 281 t.Errorf("Repositories.DownloadReleaseAsset returned error: %v", err) 282 } 283 want := "/yo" 284 if !strings.HasSuffix(got, want) { 285 t.Errorf("Repositories.DownloadReleaseAsset returned %+v, want %+v", got, want) 286 } 287} 288 289func TestRepositoriesService_DownloadReleaseAsset_APIError(t *testing.T) { 290 client, mux, _, teardown := setup() 291 defer teardown() 292 293 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 294 testMethod(t, r, "GET") 295 testHeader(t, r, "Accept", defaultMediaType) 296 w.WriteHeader(http.StatusNotFound) 297 fmt.Fprint(w, `{"message":"Not Found","documentation_url":"https://developer.github.com/v3"}`) 298 }) 299 300 resp, loc, err := client.Repositories.DownloadReleaseAsset(context.Background(), "o", "r", 1) 301 if err == nil { 302 t.Error("Repositories.DownloadReleaseAsset did not return an error") 303 } 304 305 if resp != nil { 306 resp.Close() 307 t.Error("Repositories.DownloadReleaseAsset returned stream, want nil") 308 } 309 310 if loc != "" { 311 t.Errorf(`Repositories.DownloadReleaseAsset returned "%s", want empty ""`, loc) 312 } 313} 314 315func TestRepositoriesService_EditReleaseAsset(t *testing.T) { 316 client, mux, _, teardown := setup() 317 defer teardown() 318 319 input := &ReleaseAsset{Name: String("n")} 320 321 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 322 v := new(ReleaseAsset) 323 json.NewDecoder(r.Body).Decode(v) 324 325 testMethod(t, r, "PATCH") 326 if !reflect.DeepEqual(v, input) { 327 t.Errorf("Request body = %+v, want %+v", v, input) 328 } 329 fmt.Fprint(w, `{"id":1}`) 330 }) 331 332 asset, _, err := client.Repositories.EditReleaseAsset(context.Background(), "o", "r", 1, input) 333 if err != nil { 334 t.Errorf("Repositories.EditReleaseAsset returned error: %v", err) 335 } 336 want := &ReleaseAsset{ID: Int64(1)} 337 if !reflect.DeepEqual(asset, want) { 338 t.Errorf("Repositories.EditReleaseAsset returned = %+v, want %+v", asset, want) 339 } 340} 341 342func TestRepositoriesService_DeleteReleaseAsset(t *testing.T) { 343 client, mux, _, teardown := setup() 344 defer teardown() 345 346 mux.HandleFunc("/repos/o/r/releases/assets/1", func(w http.ResponseWriter, r *http.Request) { 347 testMethod(t, r, "DELETE") 348 }) 349 350 _, err := client.Repositories.DeleteReleaseAsset(context.Background(), "o", "r", 1) 351 if err != nil { 352 t.Errorf("Repositories.DeleteReleaseAsset returned error: %v", err) 353 } 354} 355 356func TestRepositoriesService_UploadReleaseAsset(t *testing.T) { 357 var ( 358 defaultUploadOptions = &UploadOptions{Name: "n"} 359 defaultExpectedFormValue = values{"name": "n"} 360 mediaTypeTextPlain = "text/plain; charset=utf-8" 361 ) 362 uploadTests := []struct { 363 uploadOpts *UploadOptions 364 fileName string 365 expectedFormValues values 366 expectedMediaType string 367 }{ 368 // No file extension and no explicit media type. 369 { 370 defaultUploadOptions, 371 "upload", 372 defaultExpectedFormValue, 373 defaultMediaType, 374 }, 375 // File extension and no explicit media type. 376 { 377 defaultUploadOptions, 378 "upload.txt", 379 defaultExpectedFormValue, 380 mediaTypeTextPlain, 381 }, 382 // No file extension and explicit media type. 383 { 384 &UploadOptions{Name: "n", MediaType: "image/png"}, 385 "upload", 386 defaultExpectedFormValue, 387 "image/png", 388 }, 389 // File extension and explicit media type. 390 { 391 &UploadOptions{Name: "n", MediaType: "image/png"}, 392 "upload.png", 393 defaultExpectedFormValue, 394 "image/png", 395 }, 396 // Label provided. 397 { 398 &UploadOptions{Name: "n", Label: "l"}, 399 "upload.txt", 400 values{"name": "n", "label": "l"}, 401 mediaTypeTextPlain, 402 }, 403 // No label provided. 404 { 405 defaultUploadOptions, 406 "upload.txt", 407 defaultExpectedFormValue, 408 mediaTypeTextPlain, 409 }, 410 } 411 412 client, mux, _, teardown := setup() 413 defer teardown() 414 415 for key, test := range uploadTests { 416 releaseEndpoint := fmt.Sprintf("/repos/o/r/releases/%d/assets", key) 417 mux.HandleFunc(releaseEndpoint, func(w http.ResponseWriter, r *http.Request) { 418 testMethod(t, r, "POST") 419 testHeader(t, r, "Content-Type", test.expectedMediaType) 420 testHeader(t, r, "Content-Length", "12") 421 testFormValues(t, r, test.expectedFormValues) 422 testBody(t, r, "Upload me !\n") 423 424 fmt.Fprintf(w, `{"id":1}`) 425 }) 426 427 file, dir, err := openTestFile(test.fileName, "Upload me !\n") 428 if err != nil { 429 t.Fatalf("Unable to create temp file: %v", err) 430 } 431 defer os.RemoveAll(dir) 432 433 asset, _, err := client.Repositories.UploadReleaseAsset(context.Background(), "o", "r", int64(key), test.uploadOpts, file) 434 if err != nil { 435 t.Errorf("Repositories.UploadReleaseAssert returned error: %v", err) 436 } 437 want := &ReleaseAsset{ID: Int64(1)} 438 if !reflect.DeepEqual(asset, want) { 439 t.Errorf("Repositories.UploadReleaseAssert returned %+v, want %+v", asset, want) 440 } 441 } 442} 443