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  }