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