github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+incompatible/api/cloudcontroller/ccv3/package_test.go (about)

     1  package ccv3_test
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"strings"
     9  
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    11  	. "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/gbytes"
    15  	. "github.com/onsi/gomega/ghttp"
    16  )
    17  
    18  var _ = Describe("Package", func() {
    19  	var client *Client
    20  
    21  	BeforeEach(func() {
    22  		client = NewTestClient()
    23  	})
    24  
    25  	Describe("GetPackage", func() {
    26  		Context("when the package exist", func() {
    27  			BeforeEach(func() {
    28  				response := `{
    29    "guid": "some-pkg-guid",
    30    "state": "PROCESSING_UPLOAD",
    31  	"links": {
    32      "upload": {
    33        "href": "some-package-upload-url",
    34        "method": "POST"
    35      }
    36  	}
    37  }`
    38  				server.AppendHandlers(
    39  					CombineHandlers(
    40  						VerifyRequest(http.MethodGet, "/v3/packages/some-pkg-guid"),
    41  						RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
    42  					),
    43  				)
    44  			})
    45  
    46  			It("returns the queried packages and all warnings", func() {
    47  				pkg, warnings, err := client.GetPackage("some-pkg-guid")
    48  				Expect(err).NotTo(HaveOccurred())
    49  
    50  				expectedPackage := Package{
    51  					GUID:  "some-pkg-guid",
    52  					State: PackageStateProcessingUpload,
    53  					Links: map[string]APILink{
    54  						"upload": APILink{HREF: "some-package-upload-url", Method: http.MethodPost},
    55  					},
    56  				}
    57  				Expect(pkg).To(Equal(expectedPackage))
    58  				Expect(warnings).To(ConsistOf("this is a warning"))
    59  			})
    60  		})
    61  
    62  		Context("when the cloud controller returns errors and warnings", func() {
    63  			BeforeEach(func() {
    64  				response := `{
    65    "errors": [
    66      {
    67        "code": 10008,
    68        "detail": "The request is semantically invalid: command presence",
    69        "title": "CF-UnprocessableEntity"
    70      },
    71      {
    72        "code": 10010,
    73        "detail": "Package not found",
    74        "title": "CF-ResourceNotFound"
    75      }
    76    ]
    77  }`
    78  				server.AppendHandlers(
    79  					CombineHandlers(
    80  						VerifyRequest(http.MethodGet, "/v3/packages/some-pkg-guid"),
    81  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
    82  					),
    83  				)
    84  			})
    85  
    86  			It("returns the error and all warnings", func() {
    87  				_, warnings, err := client.GetPackage("some-pkg-guid")
    88  				Expect(err).To(MatchError(ccerror.V3UnexpectedResponseError{
    89  					ResponseCode: http.StatusTeapot,
    90  					V3ErrorResponse: ccerror.V3ErrorResponse{
    91  						[]ccerror.V3Error{
    92  							{
    93  								Code:   10008,
    94  								Detail: "The request is semantically invalid: command presence",
    95  								Title:  "CF-UnprocessableEntity",
    96  							},
    97  							{
    98  								Code:   10010,
    99  								Detail: "Package not found",
   100  								Title:  "CF-ResourceNotFound",
   101  							},
   102  						},
   103  					},
   104  				}))
   105  				Expect(warnings).To(ConsistOf("this is a warning"))
   106  			})
   107  		})
   108  	})
   109  
   110  	Describe("CreatePackage", func() {
   111  		Context("when the package successfully is created", func() {
   112  			BeforeEach(func() {
   113  				response := `{
   114  					"guid": "some-pkg-guid",
   115  					"type": "bits",
   116  					"state": "PROCESSING_UPLOAD",
   117  					"links": {
   118  						"upload": {
   119  							"href": "some-package-upload-url",
   120  							"method": "POST"
   121  						}
   122  					}
   123  				}`
   124  
   125  				expectedBody := map[string]interface{}{
   126  					"type": "bits",
   127  					"relationships": map[string]interface{}{
   128  						"app": map[string]interface{}{
   129  							"data": map[string]string{
   130  								"guid": "some-app-guid",
   131  							},
   132  						},
   133  					},
   134  				}
   135  				server.AppendHandlers(
   136  					CombineHandlers(
   137  						VerifyRequest(http.MethodPost, "/v3/packages"),
   138  						VerifyJSONRepresenting(expectedBody),
   139  						RespondWith(http.StatusCreated, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   140  					),
   141  				)
   142  			})
   143  
   144  			It("returns the created package and warnings", func() {
   145  				pkg, warnings, err := client.CreatePackage(Package{
   146  					Type: PackageTypeBits,
   147  					Relationships: Relationships{
   148  						ApplicationRelationship: Relationship{GUID: "some-app-guid"},
   149  					},
   150  				})
   151  
   152  				Expect(err).NotTo(HaveOccurred())
   153  				Expect(warnings).To(ConsistOf("this is a warning"))
   154  
   155  				expectedPackage := Package{
   156  					GUID:  "some-pkg-guid",
   157  					Type:  PackageTypeBits,
   158  					State: PackageStateProcessingUpload,
   159  					Links: map[string]APILink{
   160  						"upload": APILink{HREF: "some-package-upload-url", Method: http.MethodPost},
   161  					},
   162  				}
   163  				Expect(pkg).To(Equal(expectedPackage))
   164  			})
   165  		})
   166  
   167  		Context("when cc returns back an error or warnings", func() {
   168  			BeforeEach(func() {
   169  				response := ` {
   170    "errors": [
   171      {
   172        "code": 10008,
   173        "detail": "The request is semantically invalid: command presence",
   174        "title": "CF-UnprocessableEntity"
   175      },
   176      {
   177        "code": 10010,
   178        "detail": "Package not found",
   179        "title": "CF-ResourceNotFound"
   180      }
   181    ]
   182  }`
   183  				server.AppendHandlers(
   184  					CombineHandlers(
   185  						VerifyRequest(http.MethodPost, "/v3/packages"),
   186  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   187  					),
   188  				)
   189  			})
   190  
   191  			It("returns the error and all warnings", func() {
   192  				_, warnings, err := client.CreatePackage(Package{})
   193  				Expect(err).To(MatchError(ccerror.V3UnexpectedResponseError{
   194  					ResponseCode: http.StatusTeapot,
   195  					V3ErrorResponse: ccerror.V3ErrorResponse{
   196  						[]ccerror.V3Error{
   197  							{
   198  								Code:   10008,
   199  								Detail: "The request is semantically invalid: command presence",
   200  								Title:  "CF-UnprocessableEntity",
   201  							},
   202  							{
   203  								Code:   10010,
   204  								Detail: "Package not found",
   205  								Title:  "CF-ResourceNotFound",
   206  							},
   207  						},
   208  					},
   209  				}))
   210  				Expect(warnings).To(ConsistOf("this is a warning"))
   211  			})
   212  		})
   213  	})
   214  
   215  	Describe("UploadPackage", func() {
   216  		Context("when the package successfully is created", func() {
   217  			var tempFile *os.File
   218  
   219  			BeforeEach(func() {
   220  				var err error
   221  				tempFile, err = ioutil.TempFile("", "package-upload")
   222  				Expect(err).ToNot(HaveOccurred())
   223  				defer tempFile.Close()
   224  
   225  				fileSize := 1024
   226  				contents := strings.Repeat("A", fileSize)
   227  				err = ioutil.WriteFile(tempFile.Name(), []byte(contents), 0666)
   228  				Expect(err).NotTo(HaveOccurred())
   229  
   230  				verifyHeaderAndBody := func(_ http.ResponseWriter, req *http.Request) {
   231  					contentType := req.Header.Get("Content-Type")
   232  					Expect(contentType).To(MatchRegexp("multipart/form-data; boundary=[\\w\\d]+"))
   233  
   234  					boundary := contentType[30:]
   235  
   236  					defer req.Body.Close()
   237  					rawBody, err := ioutil.ReadAll(req.Body)
   238  					Expect(err).NotTo(HaveOccurred())
   239  					body := BufferWithBytes(rawBody)
   240  					Expect(body).To(Say("--%s", boundary))
   241  					Expect(body).To(Say(`name="bits"`))
   242  					Expect(body).To(Say(contents))
   243  					Expect(body).To(Say("--%s--", boundary))
   244  				}
   245  
   246  				response := `{
   247  					"guid": "some-pkg-guid",
   248  					"state": "PROCESSING_UPLOAD",
   249  					"links": {
   250  						"upload": {
   251  							"href": "some-package-upload-url",
   252  							"method": "POST"
   253  						}
   254  					}
   255  				}`
   256  
   257  				server.AppendHandlers(
   258  					CombineHandlers(
   259  						VerifyRequest(http.MethodPost, "/v3/my-special-endpoint/some-pkg-guid/upload"),
   260  						verifyHeaderAndBody,
   261  						RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   262  					),
   263  				)
   264  			})
   265  
   266  			AfterEach(func() {
   267  				if tempFile != nil {
   268  					Expect(os.Remove(tempFile.Name())).ToNot(HaveOccurred())
   269  				}
   270  			})
   271  
   272  			It("returns the created package and warnings", func() {
   273  				pkg, warnings, err := client.UploadPackage(Package{
   274  					State: PackageStateAwaitingUpload,
   275  					Links: map[string]APILink{
   276  						"upload": APILink{
   277  							HREF:   fmt.Sprintf("%s/v3/my-special-endpoint/some-pkg-guid/upload", server.URL()),
   278  							Method: http.MethodPost,
   279  						},
   280  					},
   281  				}, tempFile.Name())
   282  
   283  				Expect(err).NotTo(HaveOccurred())
   284  
   285  				expectedPackage := Package{
   286  					GUID:  "some-pkg-guid",
   287  					State: PackageStateProcessingUpload,
   288  					Links: map[string]APILink{
   289  						"upload": APILink{HREF: "some-package-upload-url", Method: http.MethodPost},
   290  					},
   291  				}
   292  				Expect(pkg).To(Equal(expectedPackage))
   293  				Expect(warnings).To(ConsistOf("this is a warning"))
   294  			})
   295  		})
   296  
   297  		Context("when the package does not have an upload link", func() {
   298  			It("returns an UploadLinkNotFoundError", func() {
   299  				_, _, err := client.UploadPackage(Package{GUID: "some-pkg-guid", State: PackageStateAwaitingUpload}, "/path/to/foo")
   300  				Expect(err).To(MatchError(ccerror.UploadLinkNotFoundError{PackageGUID: "some-pkg-guid"}))
   301  			})
   302  		})
   303  	})
   304  })