github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/api/cloudcontroller/ccv3/feature_flag_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"
     9  	"code.cloudfoundry.org/cli/resources"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/ghttp"
    13  )
    14  
    15  var _ = Describe("Feature Flags", func() {
    16  	var client *Client
    17  	var executeErr error
    18  	var warnings Warnings
    19  	var featureFlags []resources.FeatureFlag
    20  
    21  	BeforeEach(func() {
    22  		client, _ = NewTestClient()
    23  	})
    24  	Describe("GetFeatureFlags", func() {
    25  
    26  		JustBeforeEach(func() {
    27  			featureFlags, warnings, executeErr = client.GetFeatureFlags()
    28  		})
    29  
    30  		When("the cloud controller returns without errors", func() {
    31  			BeforeEach(func() {
    32  				response1 := fmt.Sprintf(`{
    33  					"pagination": {
    34  						"next": {
    35  							"href": "%s/v3/feature_flags?page=2&per_page=2"
    36  						}
    37  					},
    38  					"resources": [
    39  						{
    40  						  "name": "flag1",
    41  							"enabled": true,
    42  							"updated_at": "2016-10-17T20:00:42Z",
    43  							"custom_error_message": null,
    44  							"links": {
    45  								"self": {
    46  									"href": "https://api.example.org/v3/feature_flags/flag1"
    47  								}
    48  							}
    49  						},
    50  						{
    51  						  "name": "flag2",
    52  							"enabled": false,
    53  							"updated_at": "2016-10-17T20:00:42Z",
    54  							"custom_error_message": null,
    55  							"links": {
    56  								"self": {
    57  									"href": "https://api.example.org/v3/feature_flags/flag2"
    58  								}
    59  							}
    60  						}
    61  					]
    62  				}`, server.URL())
    63  				response2 := `{
    64  					"pagination": {
    65  						"next": null
    66  					},
    67  					"resources": [
    68  						{
    69  						  "name": "flag3",
    70  							"enabled": true,
    71  							"updated_at": "2016-10-17T20:00:42Z",
    72  							"custom_error_message": "error message the user sees",
    73  							"links": {
    74  								"self": {
    75  									"href": "https://api.example.org/v3/feature_flags/flag3"
    76  								}
    77  							}
    78  						}
    79  					]
    80  				}`
    81  				server.AppendHandlers(
    82  					CombineHandlers(
    83  						VerifyRequest(http.MethodGet, "/v3/feature_flags"),
    84  						RespondWith(http.StatusOK, response1, http.Header{"X-Cf-Warnings": {"page1 warning"}}),
    85  					),
    86  				)
    87  				server.AppendHandlers(
    88  					CombineHandlers(
    89  						VerifyRequest(http.MethodGet, "/v3/feature_flags", "page=2&per_page=2"),
    90  						RespondWith(http.StatusOK, response2, http.Header{"X-Cf-Warnings": {"page2 warning"}}),
    91  					),
    92  				)
    93  			})
    94  
    95  			It("returns feature flags and warnings", func() {
    96  				Expect(executeErr).NotTo(HaveOccurred())
    97  				Expect(warnings).To(ConsistOf("page1 warning", "page2 warning"))
    98  				Expect(featureFlags).To(ConsistOf(
    99  					resources.FeatureFlag{
   100  						Name:    "flag1",
   101  						Enabled: true,
   102  					},
   103  					resources.FeatureFlag{
   104  						Name:    "flag2",
   105  						Enabled: false,
   106  					},
   107  					resources.FeatureFlag{
   108  						Name:    "flag3",
   109  						Enabled: true,
   110  					},
   111  				))
   112  			})
   113  		})
   114  
   115  		When("the cloud controller returns errors and warnings", func() {
   116  			BeforeEach(func() {
   117  				errResponse := `{
   118  		   "errors": [
   119  		      {
   120  		         "detail": "Feature flag not found",
   121  		         "title": "CF-ResourceNotFound",
   122  		         "code": 10010
   123  		      }
   124  		   ]
   125  		}`
   126  				server.AppendHandlers(
   127  					CombineHandlers(
   128  						VerifyRequest(http.MethodGet, "/v3/feature_flags"),
   129  						RespondWith(http.StatusNotFound, errResponse, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   130  					),
   131  				)
   132  			})
   133  
   134  			It("returns a flag not found error", func() {
   135  				Expect(executeErr).To(MatchError(ccerror.FeatureFlagNotFoundError{}))
   136  				Expect(warnings).To(Equal(Warnings{"this is a warning"}))
   137  			})
   138  
   139  		})
   140  
   141  	})
   142  
   143  	Describe("GetFeatureFlag", func() {
   144  		var (
   145  			flagName     string
   146  			flag         resources.FeatureFlag
   147  			warnings     Warnings
   148  			executeError error
   149  		)
   150  
   151  		JustBeforeEach(func() {
   152  			flag, warnings, executeError = client.GetFeatureFlag(flagName)
   153  		})
   154  
   155  		When("The flag exists", func() {
   156  			BeforeEach(func() {
   157  				flagName = "flag1"
   158  				response := `{
   159    "updated_at": "2016-06-08T16:41:39Z",
   160    "name": "flag1",
   161    "enabled": true,
   162    "custom_error_message": "This is wonky",
   163    "links": {
   164      "self": { "href": "https://example.com/v3/config/feature_flags/flag1" }
   165    }
   166  }`
   167  				server.AppendHandlers(
   168  					CombineHandlers(
   169  						VerifyRequest(http.MethodGet, fmt.Sprintf("/v3/feature_flags/%s", flagName)),
   170  						RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   171  					),
   172  				)
   173  			})
   174  
   175  			It("returns the requested flag", func() {
   176  				Expect(executeError).ToNot(HaveOccurred())
   177  				Expect(warnings).To(Equal(Warnings{"this is a warning"}))
   178  				Expect(flag.Name).To(Equal(flagName))
   179  				Expect(flag.Enabled).To(Equal(true))
   180  			})
   181  		})
   182  		When("The flag does not exist", func() {
   183  			BeforeEach(func() {
   184  				flagName = "flag1"
   185  				response := `{
   186  		   "errors": [
   187  		      {
   188  		         "detail": "Feature flag not found",
   189  		         "title": "CF-ResourceNotFound",
   190  		         "code": 10010
   191  		      }
   192  		   ]
   193  		}`
   194  
   195  				server.AppendHandlers(
   196  					CombineHandlers(
   197  						VerifyRequest(http.MethodGet, fmt.Sprintf("/v3/feature_flags/%s", flagName)),
   198  						RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   199  					),
   200  				)
   201  			})
   202  
   203  			It("returns a flag not found error", func() {
   204  				Expect(executeError).To(MatchError(ccerror.FeatureFlagNotFoundError{}))
   205  				Expect(warnings).To(Equal(Warnings{"this is a warning"}))
   206  			})
   207  		})
   208  		When("some other error occurs", func() {
   209  			BeforeEach(func() {
   210  				flagName = "flag1"
   211  				response := `{
   212  		   "errors": [
   213  		     {
   214  		        "code": 10008,
   215  		        "detail": "The request is semantically invalid: command presence",
   216  		        "title": "CF-UnprocessableEntity"
   217  		      }
   218  		   ]
   219  		}`
   220  
   221  				server.AppendHandlers(
   222  					CombineHandlers(
   223  						VerifyRequest(http.MethodGet, fmt.Sprintf("/v3/feature_flags/%s", flagName)),
   224  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   225  					),
   226  				)
   227  			})
   228  
   229  			It("returns the error", func() {
   230  				Expect(executeError).To(MatchError(ccerror.V3UnexpectedResponseError{
   231  					V3ErrorResponse: ccerror.V3ErrorResponse{
   232  						Errors: []ccerror.V3Error{
   233  							{
   234  								Code:   10008,
   235  								Detail: "The request is semantically invalid: command presence",
   236  								Title:  "CF-UnprocessableEntity",
   237  							},
   238  						},
   239  					},
   240  					ResponseCode: http.StatusTeapot,
   241  				},
   242  				))
   243  				Expect(warnings).To(Equal(Warnings{"this is a warning"}))
   244  			})
   245  		})
   246  	})
   247  
   248  	Describe("UpdateFeatureFlag", func() {
   249  		var (
   250  			argFlag      resources.FeatureFlag
   251  			expectedBody string
   252  			ccFlag       resources.FeatureFlag
   253  			warnings     Warnings
   254  			executeError error
   255  		)
   256  
   257  		BeforeEach(func() {
   258  			expectedBody = `{"enabled":false}`
   259  			argFlag = resources.FeatureFlag{
   260  				Name:    "flag1",
   261  				Enabled: false,
   262  			}
   263  		})
   264  
   265  		JustBeforeEach(func() {
   266  			ccFlag, warnings, executeError = client.UpdateFeatureFlag(argFlag)
   267  		})
   268  
   269  		When("The flag exists", func() {
   270  			BeforeEach(func() {
   271  				response := `{
   272    "updated_at": "2016-06-08T16:41:39Z",
   273    "name": "flag1",
   274    "enabled": false,
   275    "custom_error_message": "This is wonky",
   276    "links": {
   277      "self": { "href": "https://example.com/v3/config/feature_flags/flag1" }
   278    }
   279  }`
   280  				server.AppendHandlers(
   281  					CombineHandlers(
   282  						VerifyRequest(http.MethodPatch, fmt.Sprintf("/v3/feature_flags/%s", argFlag.Name)),
   283  						VerifyJSON(expectedBody),
   284  						RespondWith(http.StatusOK, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   285  					),
   286  				)
   287  			})
   288  
   289  			It("Successfully updates the flag", func() {
   290  				Expect(executeError).ToNot(HaveOccurred())
   291  				Expect(warnings).To(Equal(Warnings{"this is a warning"}))
   292  				Expect(ccFlag).To(Equal(argFlag))
   293  			})
   294  		})
   295  
   296  		When("The flag does not exist", func() {
   297  			BeforeEach(func() {
   298  				response := `{
   299  		   "errors": [
   300  		      {
   301  		         "detail": "Feature flag not found",
   302  		         "title": "CF-ResourceNotFound",
   303  		         "code": 10010
   304  		      }
   305  		   ]
   306  		}`
   307  				server.AppendHandlers(
   308  					CombineHandlers(
   309  						VerifyRequest(http.MethodPatch, fmt.Sprintf("/v3/feature_flags/%s", argFlag.Name)),
   310  						VerifyJSON(expectedBody),
   311  						RespondWith(http.StatusNotFound, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   312  					),
   313  				)
   314  			})
   315  
   316  			It("returns a flag not found error", func() {
   317  				Expect(executeError).To(MatchError(ccerror.FeatureFlagNotFoundError{}))
   318  				Expect(warnings).To(Equal(Warnings{"this is a warning"}))
   319  			})
   320  		})
   321  		When("some other error occurs", func() {
   322  			BeforeEach(func() {
   323  				response := `{
   324  		   "errors": [
   325  		     {
   326  		        "code": 10008,
   327  		        "detail": "The request is semantically invalid: command presence",
   328  		        "title": "CF-UnprocessableEntity"
   329  		      }
   330  		   ]
   331  		}`
   332  
   333  				server.AppendHandlers(
   334  					CombineHandlers(
   335  						VerifyRequest(http.MethodPatch, fmt.Sprintf("/v3/feature_flags/%s", argFlag.Name)),
   336  						VerifyJSON(expectedBody),
   337  						RespondWith(http.StatusTeapot, response, http.Header{"X-Cf-Warnings": {"this is a warning"}}),
   338  					),
   339  				)
   340  			})
   341  
   342  			It("returns the error", func() {
   343  				Expect(executeError).To(MatchError(ccerror.V3UnexpectedResponseError{
   344  					V3ErrorResponse: ccerror.V3ErrorResponse{
   345  						Errors: []ccerror.V3Error{
   346  							{
   347  								Code:   10008,
   348  								Detail: "The request is semantically invalid: command presence",
   349  								Title:  "CF-UnprocessableEntity",
   350  							},
   351  						},
   352  					},
   353  					ResponseCode: http.StatusTeapot,
   354  				},
   355  				))
   356  				Expect(warnings).To(Equal(Warnings{"this is a warning"}))
   357  			})
   358  		})
   359  	})
   360  })