github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/broker/client_test.go (about) 1 package broker 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "net/http/httptest" 9 "path" 10 "testing" 11 12 "github.com/gorilla/mux" 13 "github.com/kyma-project/kyma-environment-broker/internal" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 const ( 18 fixInstanceID = "72b83910-ac12-4dcb-b91d-960cca2b36abx" 19 fixRuntimeID = "24da44ea-0295-4b1c-b5c1-6fd26efa4f24" 20 fixOpID = "04f91bff-9e17-45cb-a246-84d511274ef1" 21 22 gcpPlanID = "ca6e5357-707f-4565-bbbd-b3ab732597c6" 23 azurePlanID = "4deee563-e5ec-4731-b9b1-53b42d855f0c" 24 ) 25 26 func TestClient_Deprovision(t *testing.T) { 27 t.Run("should return deprovisioning operation ID on success", func(t *testing.T) { 28 // given 29 testServer := fixHTTPServer(nil) 30 defer testServer.Close() 31 32 config := NewClientConfig(testServer.URL) 33 client := NewClientWithPoller(context.Background(), *config, NewPassthroughPoller()) 34 client.setHttpClient(testServer.Client()) 35 36 instance := internal.Instance{ 37 InstanceID: fixInstanceID, 38 RuntimeID: fixRuntimeID, 39 ServicePlanID: azurePlanID, 40 } 41 42 // when 43 opID, err := client.Deprovision(instance) 44 45 // then 46 assert.NoError(t, err) 47 assert.Equal(t, fixOpID, opID) 48 }) 49 50 t.Run("should return error on failed request execution", func(t *testing.T) { 51 // given 52 testServer := fixHTTPServer(requestFailureServerError) 53 defer testServer.Close() 54 55 config := NewClientConfig(testServer.URL) 56 57 client := NewClientWithPoller(context.Background(), *config, NewPassthroughPoller()) 58 59 client.setHttpClient(testServer.Client()) 60 61 instance := internal.Instance{ 62 InstanceID: fixInstanceID, 63 RuntimeID: fixRuntimeID, 64 ServicePlanID: gcpPlanID, 65 } 66 67 // when 68 opID, err := client.Deprovision(instance) 69 70 // then 71 assert.Error(t, err) 72 assert.Len(t, opID, 0) 73 }) 74 } 75 76 func TestClient_ExpirationRequest(t *testing.T) { 77 78 t.Run("should return true on successfully commenced suspension", func(t *testing.T) { 79 // given 80 testServer := fixHTTPServer(nil) 81 defer testServer.Close() 82 83 config := ClientConfig{ 84 URL: testServer.URL, 85 } 86 client := NewClientWithPoller(context.Background(), config, NewPassthroughPoller()) 87 client.setHttpClient(testServer.Client()) 88 89 instance := internal.Instance{ 90 InstanceID: fixInstanceID, 91 RuntimeID: fixRuntimeID, 92 ServicePlanID: TrialPlanID, 93 } 94 95 // when 96 suspensionUnderWay, err := client.SendExpirationRequest(instance) 97 98 // then 99 assert.NoError(t, err) 100 assert.True(t, suspensionUnderWay) 101 }) 102 103 t.Run("should return error when trying to make other plan than trial expired", func(t *testing.T) { 104 // given 105 testServer := fixHTTPServer(nil) 106 defer testServer.Close() 107 108 config := ClientConfig{ 109 URL: testServer.URL, 110 } 111 client := NewClientWithPoller(context.Background(), config, NewPassthroughPoller()) 112 client.setHttpClient(testServer.Client()) 113 114 instance := internal.Instance{ 115 InstanceID: fixInstanceID, 116 RuntimeID: fixRuntimeID, 117 ServicePlanID: azurePlanID, 118 } 119 120 // when 121 suspensionUnderWay, err := client.SendExpirationRequest(instance) 122 123 // then 124 assert.Error(t, err) 125 assert.False(t, suspensionUnderWay) 126 }) 127 128 t.Run("should return error when update fails", func(t *testing.T) { 129 // given 130 testServer := fixHTTPServer(requestFailureServerError) 131 defer testServer.Close() 132 133 config := ClientConfig{ 134 URL: testServer.URL, 135 } 136 client := NewClientWithPoller(context.Background(), config, NewPassthroughPoller()) 137 138 client.setHttpClient(testServer.Client()) 139 140 instance := internal.Instance{ 141 InstanceID: fixInstanceID, 142 RuntimeID: fixRuntimeID, 143 ServicePlanID: TrialPlanID, 144 } 145 146 // when 147 suspensionUnderWay, err := client.SendExpirationRequest(instance) 148 149 // then 150 assert.Error(t, err) 151 assert.False(t, suspensionUnderWay) 152 }) 153 154 t.Run("should return false on unprocessable entity", func(t *testing.T) { 155 // given 156 testServer := fixHTTPServer(requestFailureUnprocessableEntity) 157 defer testServer.Close() 158 159 config := ClientConfig{ 160 URL: testServer.URL, 161 } 162 client := NewClientWithPoller(context.Background(), config, NewPassthroughPoller()) 163 client.setHttpClient(testServer.Client()) 164 165 instance := internal.Instance{ 166 InstanceID: fixInstanceID, 167 RuntimeID: fixRuntimeID, 168 ServicePlanID: TrialPlanID, 169 } 170 171 // when 172 suspensionUnderWay, err := client.SendExpirationRequest(instance) 173 174 // then 175 assert.Error(t, err) 176 assert.False(t, suspensionUnderWay) 177 }) 178 179 t.Run("should return true for non-existent instanceId and false for existing", func(t *testing.T) { 180 // given 181 testServer := fixHTTPServer(nil) 182 defer testServer.Close() 183 184 config := ClientConfig{ 185 URL: testServer.URL, 186 } 187 client := NewClientWithPoller(context.Background(), config, NewPassthroughPoller()) 188 client.setHttpClient(testServer.Client()) 189 190 // when 191 response, err := client.GetInstanceRequest("non-existent") 192 193 // then 194 assert.NoError(t, err) 195 assert.Equal(t, response.StatusCode, http.StatusNotFound) 196 197 // when 198 responseOtherThanNotFound, err := client.GetInstanceRequest("real") 199 200 // then 201 assert.NoError(t, err) 202 assert.NotEqual(t, responseOtherThanNotFound.StatusCode, http.StatusNotFound) 203 }) 204 } 205 206 func fixHTTPServer(requestFailureFunc func(http.ResponseWriter, *http.Request)) *httptest.Server { 207 if requestFailureFunc != nil { 208 r := mux.NewRouter() 209 r.HandleFunc("/oauth/v2/service_instances/{instance_id}", requestFailureFunc).Methods(http.MethodDelete) 210 r.HandleFunc("/oauth/v2/service_instances/{instance_id}", requestFailureFunc).Methods(http.MethodPatch) 211 return httptest.NewServer(r) 212 } 213 214 r := mux.NewRouter() 215 r.HandleFunc("/oauth/v2/service_instances/{instance_id}", deprovision).Methods(http.MethodDelete) 216 r.HandleFunc("/oauth/v2/service_instances/{instance_id}", serviceUpdateWithExpiration).Methods(http.MethodPatch) 217 r.HandleFunc("/oauth/v2/service_instances/{instance_id}", getInstance).Methods(http.MethodGet) 218 return httptest.NewServer(r) 219 } 220 221 func serviceUpdateWithExpiration(w http.ResponseWriter, r *http.Request) { 222 responseDTO := serviceUpdatePatchDTO{} 223 err := json.NewDecoder(r.Body).Decode(&responseDTO) 224 225 validRequest := err == nil && responseDTO.PlanID == TrialPlanID && 226 *responseDTO.Parameters.Expired && !*responseDTO.Context.Active 227 228 if !validRequest { 229 w.WriteHeader(http.StatusBadRequest) 230 return 231 } 232 233 w.WriteHeader(http.StatusAccepted) 234 w.Write([]byte(fmt.Sprintf(`{"operation": "%s"}`, fixOpID))) 235 } 236 237 func deprovision(w http.ResponseWriter, r *http.Request) { 238 params := r.URL.Query() 239 _, okServiceID := params["service_id"] 240 if !okServiceID { 241 w.WriteHeader(http.StatusBadRequest) 242 return 243 } 244 _, okPlanID := params["plan_id"] 245 if !okPlanID { 246 w.WriteHeader(http.StatusBadRequest) 247 return 248 } 249 250 w.WriteHeader(http.StatusAccepted) 251 w.Write([]byte(fmt.Sprintf(`{"operation": "%s"}`, fixOpID))) 252 } 253 254 func requestFailureServerError(w http.ResponseWriter, _ *http.Request) { 255 w.WriteHeader(http.StatusInternalServerError) 256 } 257 258 func requestFailureUnprocessableEntity(w http.ResponseWriter, _ *http.Request) { 259 w.WriteHeader(http.StatusUnprocessableEntity) 260 } 261 262 func getInstance(w http.ResponseWriter, r *http.Request) { 263 instance := path.Base(r.URL.Path) 264 if instance == "non-existent" { 265 w.WriteHeader(http.StatusNotFound) 266 } else { 267 w.Write([]byte(fmt.Sprintf(`{"instanceID": "%s"}`, instance))) 268 w.WriteHeader(http.StatusOK) 269 } 270 }