github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/cloudcontroller/ccv3/deployment_test.go (about)

     1  package ccv3_test
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  
     7  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
     8  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
     9  	"code.cloudfoundry.org/cli/resources"
    10  
    11  	. "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/ghttp"
    15  )
    16  
    17  var _ = Describe("Deployment", func() {
    18  	var client *Client
    19  
    20  	BeforeEach(func() {
    21  		client, _ = NewTestClient()
    22  	})
    23  
    24  	Describe("GetDeployments", func() {
    25  		var (
    26  			deployments []resources.Deployment
    27  			warnings    Warnings
    28  			executeErr  error
    29  		)
    30  
    31  		JustBeforeEach(func() {
    32  			deployments, warnings, executeErr = client.GetDeployments(Query{Key: AppGUIDFilter, Values: []string{"some-app-guid"}}, Query{Key: OrderBy, Values: []string{"-created_at"}}, Query{Key: PerPage, Values: []string{"1"}})
    33  		})
    34  
    35  		var response string
    36  		var response2 string
    37  		BeforeEach(func() {
    38  			response = fmt.Sprintf(`{
    39  	"pagination": {
    40  		"next": {
    41  			"href": "%s/v3/deployments?app_guids=some-app-guid&order_by=-created_at&page=2&per_page=1"
    42  		}
    43  	},
    44  	"resources": [
    45  		{
    46        		"guid": "newest-deployment-guid",
    47        		"created_at": "2018-05-25T22:42:10Z"
    48     	}
    49  	]
    50  }`, server.URL())
    51  			response2 = `{
    52    	"pagination": {
    53  		"next": null
    54  	},
    55  	"resources": [
    56  		{
    57        		"guid": "oldest-deployment-guid",
    58        		"created_at": "2018-04-25T22:42:10Z"
    59     	}
    60  	]
    61  }`
    62  		})
    63  
    64  		Context("when the deployment exists", func() {
    65  			BeforeEach(func() {
    66  				server.AppendHandlers(
    67  					CombineHandlers(
    68  						VerifyRequest(http.MethodGet, "/v3/deployments", "app_guids=some-app-guid&order_by=-created_at&per_page=1"),
    69  						RespondWith(http.StatusAccepted, response),
    70  					),
    71  				)
    72  
    73  				server.AppendHandlers(
    74  					CombineHandlers(
    75  						VerifyRequest(http.MethodGet, "/v3/deployments", "app_guids=some-app-guid&order_by=-created_at&page=2&per_page=1"),
    76  						RespondWith(http.StatusAccepted, response2, http.Header{"X-Cf-Warnings": {"warning"}}),
    77  					),
    78  				)
    79  
    80  			})
    81  
    82  			It("returns the deployment guid of the most recent deployment", func() {
    83  				Expect(executeErr).ToNot(HaveOccurred())
    84  				Expect(warnings).To(ConsistOf("warning"))
    85  				Expect(deployments).To(ConsistOf(
    86  					resources.Deployment{GUID: "newest-deployment-guid", CreatedAt: "2018-05-25T22:42:10Z"},
    87  					resources.Deployment{GUID: "oldest-deployment-guid", CreatedAt: "2018-04-25T22:42:10Z"},
    88  				))
    89  			})
    90  
    91  		})
    92  
    93  		Context("when the request fails", func() {
    94  			BeforeEach(func() {
    95  				response := `{
    96    "errors": [
    97      {
    98        "code": 10008,
    99        "detail": "The request is semantically invalid: command presence",
   100        "title": "CF-UnprocessableEntity"
   101      },
   102      {
   103        "code": 10010,
   104        "detail": "App not found",
   105        "title": "CF-ResourceNotFound"
   106      }
   107    ]
   108  }`
   109  
   110  				server.AppendHandlers(
   111  					CombineHandlers(
   112  						VerifyRequest(http.MethodGet, "/v3/deployments", "app_guids=some-app-guid&order_by=-created_at&per_page=1"),
   113  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"warning"}}),
   114  					),
   115  				)
   116  			})
   117  
   118  			It("returns CC warnings and error", func() {
   119  				Expect(executeErr).To(MatchError(ccerror.MultiError{
   120  					ResponseCode: http.StatusTeapot,
   121  					Errors: []ccerror.V3Error{
   122  						{
   123  							Code:   10008,
   124  							Detail: "The request is semantically invalid: command presence",
   125  							Title:  "CF-UnprocessableEntity",
   126  						},
   127  						{
   128  							Code:   10010,
   129  							Detail: "App not found",
   130  							Title:  "CF-ResourceNotFound",
   131  						},
   132  					},
   133  				}))
   134  				Expect(warnings).To(ConsistOf("warning"))
   135  			})
   136  		})
   137  	})
   138  
   139  	Describe("CancelDeployment", func() {
   140  		var (
   141  			warnings   Warnings
   142  			executeErr error
   143  		)
   144  
   145  		JustBeforeEach(func() {
   146  			warnings, executeErr = client.CancelDeployment("some-deployment-guid")
   147  		})
   148  
   149  		Context("when the deployment exists", func() {
   150  			Context("when cancelling the deployment succeeds", func() {
   151  				BeforeEach(func() {
   152  					server.AppendHandlers(
   153  						CombineHandlers(
   154  							VerifyRequest(http.MethodPost, "/v3/deployments/some-deployment-guid/actions/cancel"),
   155  							RespondWith(http.StatusAccepted, "", http.Header{"X-Cf-Warnings": {"warning"}}),
   156  						),
   157  					)
   158  				})
   159  
   160  				It("cancels the deployment with no errors and returns all warnings", func() {
   161  					Expect(executeErr).ToNot(HaveOccurred())
   162  					Expect(warnings).To(ConsistOf("warning"))
   163  				})
   164  			})
   165  		})
   166  	})
   167  
   168  	Describe("CreateApplicationDeployment", func() {
   169  		var (
   170  			deploymentGUID string
   171  			warnings       Warnings
   172  			executeErr     error
   173  			dropletGUID    string
   174  		)
   175  
   176  		JustBeforeEach(func() {
   177  			deploymentGUID, warnings, executeErr = client.CreateApplicationDeployment("some-app-guid", dropletGUID)
   178  		})
   179  
   180  		Context("when the application exists", func() {
   181  			var response string
   182  			BeforeEach(func() {
   183  				dropletGUID = "some-droplet-guid"
   184  				response = `{
   185    "guid": "some-deployment-guid",
   186    "created_at": "2018-04-25T22:42:10Z",
   187    "relationships": {
   188      "app": {
   189        "data": {
   190          "guid": "some-app-guid"
   191        }
   192      }
   193    }
   194  }`
   195  			})
   196  
   197  			Context("when creating the deployment succeeds", func() {
   198  				BeforeEach(func() {
   199  					server.AppendHandlers(
   200  						CombineHandlers(
   201  							VerifyRequest(http.MethodPost, "/v3/deployments"),
   202  							VerifyJSON(`{"droplet":{ "guid":"some-droplet-guid" }, "relationships":{"app":{"data":{"guid":"some-app-guid"}}}}`),
   203  							RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}),
   204  						),
   205  					)
   206  				})
   207  
   208  				It("creates the deployment with no errors and returns all warnings", func() {
   209  					Expect(deploymentGUID).To(Equal("some-deployment-guid"))
   210  					Expect(executeErr).ToNot(HaveOccurred())
   211  					Expect(warnings).To(ConsistOf("warning"))
   212  				})
   213  
   214  			})
   215  
   216  			Context("when no droplet guid is provided", func() {
   217  				BeforeEach(func() {
   218  					dropletGUID = ""
   219  					server.AppendHandlers(
   220  						CombineHandlers(
   221  							VerifyRequest(http.MethodPost, "/v3/deployments"),
   222  							VerifyJSON(`{"relationships":{"app":{"data":{"guid":"some-app-guid"}}}}`),
   223  							RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}),
   224  						),
   225  					)
   226  				})
   227  
   228  				It("omits the droplet object in the JSON", func() {
   229  					Expect(executeErr).ToNot(HaveOccurred())
   230  					Expect(warnings).To(ConsistOf("warning"))
   231  				})
   232  			})
   233  		})
   234  	})
   235  
   236  	Describe("CreateApplicationDeploymentByRevision", func() {
   237  		var (
   238  			deploymentGUID string
   239  			warnings       Warnings
   240  			executeErr     error
   241  			revisionGUID   string
   242  		)
   243  
   244  		JustBeforeEach(func() {
   245  			deploymentGUID, warnings, executeErr = client.CreateApplicationDeploymentByRevision("some-app-guid", revisionGUID)
   246  		})
   247  
   248  		Context("when the application exists", func() {
   249  			var response string
   250  			BeforeEach(func() {
   251  				revisionGUID = "some-revision-guid"
   252  				response = `{
   253    "guid": "some-deployment-guid",
   254    "created_at": "2018-04-25T22:42:10Z",
   255    "relationships": {
   256      "app": {
   257        "data": {
   258          "guid": "some-app-guid"
   259        }
   260      }
   261    }
   262  }`
   263  			})
   264  
   265  			Context("when creating the deployment succeeds", func() {
   266  				BeforeEach(func() {
   267  					server.AppendHandlers(
   268  						CombineHandlers(
   269  							VerifyRequest(http.MethodPost, "/v3/deployments"),
   270  							VerifyJSON(`{"revision":{ "guid":"some-revision-guid" }, "relationships":{"app":{"data":{"guid":"some-app-guid"}}}}`),
   271  							RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}),
   272  						),
   273  					)
   274  				})
   275  
   276  				It("creates the deployment with no errors and returns all warnings", func() {
   277  					Expect(deploymentGUID).To(Equal("some-deployment-guid"))
   278  					Expect(executeErr).ToNot(HaveOccurred())
   279  					Expect(warnings).To(ConsistOf("warning"))
   280  				})
   281  			})
   282  		})
   283  	})
   284  
   285  	Describe("GetDeployment", func() {
   286  		var response string
   287  		Context("When the deployments exists", func() {
   288  			BeforeEach(func() {
   289  				response = `{
   290  				    "guid": "some-deployment-guid",
   291  					"state": "DEPLOYED",
   292  					"status": {
   293  						"value": "FINALIZED",
   294  						"reason": "SUPERSEDED"
   295  					},
   296  					"droplet": {
   297   					  "guid": "some-droplet-guid"
   298  					},
   299   					"previous_droplet": {
   300   					  "guid": "some-other-droplet-guid"
   301   					},
   302   					"created_at": "some-time",
   303   					"updated_at": "some-later-time",
   304   					"relationships": {
   305   					  "app": {
   306   					    "data": {
   307   					      "guid": "some-app-guid"
   308   					    }
   309   					  }
   310   					}
   311  				}`
   312  				server.AppendHandlers(
   313  					CombineHandlers(
   314  						VerifyRequest(http.MethodGet, "/v3/deployments/some-deployment-guid"),
   315  						RespondWith(http.StatusAccepted, response, http.Header{"X-Cf-Warnings": {"warning"}}),
   316  					),
   317  				)
   318  			})
   319  			It("Successfully returns a deployment object", func() {
   320  				deployment, warnings, err := client.GetDeployment("some-deployment-guid")
   321  				Expect(err).ToNot(HaveOccurred())
   322  				Expect(warnings).To(ConsistOf("warning"))
   323  				Expect(deployment).To(Not(BeNil()))
   324  				Expect(deployment.GUID).To(Equal("some-deployment-guid"))
   325  				Expect(deployment.State).To(Equal(constant.DeploymentDeployed))
   326  				Expect(deployment.StatusValue).To(Equal(constant.DeploymentStatusValueFinalized))
   327  				Expect(deployment.StatusReason).To(Equal(constant.DeploymentStatusReasonSuperseded))
   328  			})
   329  		})
   330  
   331  		Context("when the deployment doesn't exist", func() {
   332  			BeforeEach(func() {
   333  				response := `{
   334  					"errors": [
   335  						{
   336  							"code": 10010,
   337  							"detail": "Deployment not found",
   338  							"title": "CF-ResourceNotFound"
   339  						}
   340  					]
   341  				}`
   342  				server.AppendHandlers(
   343  					CombineHandlers(
   344  						VerifyRequest(http.MethodGet, "/v3/deployments/not-a-deployment"),
   345  						RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"warning-deployment"}}),
   346  					),
   347  				)
   348  			})
   349  
   350  			It("returns the error", func() {
   351  				_, warnings, err := client.GetDeployment("not-a-deployment")
   352  				Expect(err).To(MatchError(ccerror.DeploymentNotFoundError{}))
   353  				Expect(warnings).To(ConsistOf("warning-deployment"))
   354  			})
   355  		})
   356  	})
   357  })