github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/runtime/handler_test.go (about)

     1  package runtime_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"net/http/httptest"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/gorilla/mux"
    12  	"github.com/kyma-project/control-plane/components/provisioner/pkg/gqlschema"
    13  	pkg "github.com/kyma-project/kyma-environment-broker/common/runtime"
    14  	"github.com/kyma-project/kyma-environment-broker/internal"
    15  	"github.com/kyma-project/kyma-environment-broker/internal/fixture"
    16  	"github.com/kyma-project/kyma-environment-broker/internal/ptr"
    17  	"github.com/kyma-project/kyma-environment-broker/internal/runtime"
    18  	"github.com/kyma-project/kyma-environment-broker/internal/storage/driver/memory"
    19  	"github.com/pivotal-cf/brokerapi/v8/domain"
    20  	"github.com/sirupsen/logrus"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/require"
    23  	"k8s.io/apimachinery/pkg/util/rand"
    24  )
    25  
    26  func TestRuntimeHandler(t *testing.T) {
    27  	t.Run("test pagination should work", func(t *testing.T) {
    28  		// given
    29  		operations := memory.NewOperation()
    30  		instances := memory.NewInstance(operations)
    31  		states := memory.NewRuntimeStates()
    32  		testID1 := "Test1"
    33  		testID2 := "Test2"
    34  		testTime1 := time.Now()
    35  		testTime2 := time.Now().Add(time.Minute)
    36  		testInstance1 := internal.Instance{
    37  			InstanceID: testID1,
    38  			CreatedAt:  testTime1,
    39  			Parameters: internal.ProvisioningParameters{},
    40  		}
    41  		testInstance2 := internal.Instance{
    42  			InstanceID: testID2,
    43  			CreatedAt:  testTime2,
    44  			Parameters: internal.ProvisioningParameters{},
    45  		}
    46  
    47  		err := instances.Insert(testInstance1)
    48  		require.NoError(t, err)
    49  		err = instances.Insert(testInstance2)
    50  		require.NoError(t, err)
    51  
    52  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "")
    53  
    54  		req, err := http.NewRequest("GET", "/runtimes?page_size=1", nil)
    55  		require.NoError(t, err)
    56  
    57  		rr := httptest.NewRecorder()
    58  		router := mux.NewRouter()
    59  		runtimeHandler.AttachRoutes(router)
    60  
    61  		// when
    62  		router.ServeHTTP(rr, req)
    63  
    64  		// then
    65  		require.Equal(t, http.StatusOK, rr.Code)
    66  
    67  		var out pkg.RuntimesPage
    68  
    69  		err = json.Unmarshal(rr.Body.Bytes(), &out)
    70  		require.NoError(t, err)
    71  
    72  		assert.Equal(t, 2, out.TotalCount)
    73  		assert.Equal(t, 1, out.Count)
    74  		assert.Equal(t, testID1, out.Data[0].InstanceID)
    75  
    76  		// given
    77  		urlPath := fmt.Sprintf("/runtimes?page=2&page_size=1")
    78  		req, err = http.NewRequest(http.MethodGet, urlPath, nil)
    79  		require.NoError(t, err)
    80  		rr = httptest.NewRecorder()
    81  
    82  		// when
    83  		router.ServeHTTP(rr, req)
    84  
    85  		// then
    86  		require.Equal(t, http.StatusOK, rr.Code)
    87  
    88  		err = json.Unmarshal(rr.Body.Bytes(), &out)
    89  		require.NoError(t, err)
    90  		logrus.Print(out.Data)
    91  		assert.Equal(t, 2, out.TotalCount)
    92  		assert.Equal(t, 1, out.Count)
    93  		assert.Equal(t, testID2, out.Data[0].InstanceID)
    94  
    95  	})
    96  
    97  	t.Run("test validation should work", func(t *testing.T) {
    98  		// given
    99  		operations := memory.NewOperation()
   100  		instances := memory.NewInstance(operations)
   101  		states := memory.NewRuntimeStates()
   102  
   103  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "region")
   104  
   105  		req, err := http.NewRequest("GET", "/runtimes?page_size=a", nil)
   106  		require.NoError(t, err)
   107  
   108  		rr := httptest.NewRecorder()
   109  		router := mux.NewRouter()
   110  		runtimeHandler.AttachRoutes(router)
   111  
   112  		router.ServeHTTP(rr, req)
   113  
   114  		require.Equal(t, http.StatusBadRequest, rr.Code)
   115  
   116  		req, err = http.NewRequest("GET", "/runtimes?page_size=1,2,3", nil)
   117  		require.NoError(t, err)
   118  
   119  		rr = httptest.NewRecorder()
   120  		router.ServeHTTP(rr, req)
   121  
   122  		require.Equal(t, http.StatusBadRequest, rr.Code)
   123  
   124  		req, err = http.NewRequest("GET", "/runtimes?page_size=abc", nil)
   125  		require.NoError(t, err)
   126  
   127  		rr = httptest.NewRecorder()
   128  		router.ServeHTTP(rr, req)
   129  
   130  		require.Equal(t, http.StatusBadRequest, rr.Code)
   131  	})
   132  
   133  	t.Run("test filtering should work", func(t *testing.T) {
   134  		// given
   135  		operations := memory.NewOperation()
   136  		instances := memory.NewInstance(operations)
   137  		states := memory.NewRuntimeStates()
   138  		testID1 := "Test1"
   139  		testID2 := "Test2"
   140  		testTime1 := time.Now()
   141  		testTime2 := time.Now().Add(time.Minute)
   142  		testInstance1 := fixInstance(testID1, testTime1)
   143  		testInstance2 := fixInstance(testID2, testTime2)
   144  		testInstance1.InstanceDetails = fixture.FixInstanceDetails(testID1)
   145  		testInstance2.InstanceDetails = fixture.FixInstanceDetails(testID2)
   146  		testOp1 := fixture.FixProvisioningOperation("op1", testID1)
   147  		testOp2 := fixture.FixProvisioningOperation("op2", testID2)
   148  
   149  		err := instances.Insert(testInstance1)
   150  		require.NoError(t, err)
   151  		err = instances.Insert(testInstance2)
   152  		require.NoError(t, err)
   153  		err = operations.InsertOperation(testOp1)
   154  		require.NoError(t, err)
   155  		err = operations.InsertOperation(testOp2)
   156  		require.NoError(t, err)
   157  
   158  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "")
   159  
   160  		req, err := http.NewRequest("GET", fmt.Sprintf("/runtimes?account=%s&subaccount=%s&instance_id=%s&runtime_id=%s&region=%s&shoot=%s", testID1, testID1, testID1, testID1, testID1, fmt.Sprintf("Shoot-%s", testID1)), nil)
   161  		require.NoError(t, err)
   162  
   163  		rr := httptest.NewRecorder()
   164  		router := mux.NewRouter()
   165  		runtimeHandler.AttachRoutes(router)
   166  
   167  		// when
   168  		router.ServeHTTP(rr, req)
   169  
   170  		// then
   171  		require.Equal(t, http.StatusOK, rr.Code)
   172  
   173  		var out pkg.RuntimesPage
   174  
   175  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   176  		require.NoError(t, err)
   177  
   178  		assert.Equal(t, 1, out.TotalCount)
   179  		assert.Equal(t, 1, out.Count)
   180  		assert.Equal(t, testID1, out.Data[0].InstanceID)
   181  	})
   182  
   183  	t.Run("test state filtering should work", func(t *testing.T) {
   184  		// given
   185  		operations := memory.NewOperation()
   186  		instances := memory.NewInstance(operations)
   187  		states := memory.NewRuntimeStates()
   188  		testID1 := "Test1"
   189  		testID2 := "Test2"
   190  		testID3 := "Test3"
   191  		testTime1 := time.Now()
   192  		testTime2 := time.Now().Add(time.Minute)
   193  		testInstance1 := fixInstance(testID1, testTime1)
   194  		testInstance2 := fixInstance(testID2, testTime2)
   195  		testInstance3 := fixInstance(testID3, time.Now().Add(2*time.Minute))
   196  
   197  		err := instances.Insert(testInstance1)
   198  		require.NoError(t, err)
   199  		err = instances.Insert(testInstance2)
   200  		require.NoError(t, err)
   201  		err = instances.Insert(testInstance3)
   202  		require.NoError(t, err)
   203  
   204  		provOp1 := fixture.FixProvisioningOperation(fixRandomID(), testID1)
   205  		err = operations.InsertOperation(provOp1)
   206  		require.NoError(t, err)
   207  
   208  		provOp2 := fixture.FixProvisioningOperation(fixRandomID(), testID2)
   209  		err = operations.InsertOperation(provOp2)
   210  		require.NoError(t, err)
   211  		upgOp2 := fixture.FixUpgradeKymaOperation(fixRandomID(), testID2)
   212  		upgOp2.State = domain.Failed
   213  		upgOp2.CreatedAt = upgOp2.CreatedAt.Add(time.Minute)
   214  		err = operations.InsertUpgradeKymaOperation(upgOp2)
   215  		require.NoError(t, err)
   216  
   217  		provOp3 := fixture.FixProvisioningOperation(fixRandomID(), testID3)
   218  		err = operations.InsertOperation(provOp3)
   219  		require.NoError(t, err)
   220  		upgOp3 := fixture.FixUpgradeKymaOperation(fixRandomID(), testID3)
   221  		upgOp3.State = domain.Failed
   222  		upgOp3.CreatedAt = upgOp3.CreatedAt.Add(time.Minute)
   223  		err = operations.InsertUpgradeKymaOperation(upgOp3)
   224  		require.NoError(t, err)
   225  		deprovOp3 := fixture.FixDeprovisioningOperation(fixRandomID(), testID3)
   226  		deprovOp3.State = domain.Succeeded
   227  		deprovOp3.CreatedAt = deprovOp3.CreatedAt.Add(2 * time.Minute)
   228  		err = operations.InsertDeprovisioningOperation(deprovOp3)
   229  		require.NoError(t, err)
   230  
   231  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "")
   232  
   233  		rr := httptest.NewRecorder()
   234  		router := mux.NewRouter()
   235  		runtimeHandler.AttachRoutes(router)
   236  
   237  		// when
   238  		req, err := http.NewRequest("GET", fmt.Sprintf("/runtimes?state=%s", pkg.StateSucceeded), nil)
   239  		require.NoError(t, err)
   240  		router.ServeHTTP(rr, req)
   241  
   242  		// then
   243  		require.Equal(t, http.StatusOK, rr.Code)
   244  
   245  		var out pkg.RuntimesPage
   246  
   247  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   248  		require.NoError(t, err)
   249  
   250  		assert.Equal(t, 1, out.TotalCount)
   251  		assert.Equal(t, 1, out.Count)
   252  		assert.Equal(t, testID1, out.Data[0].InstanceID)
   253  
   254  		// when
   255  		rr = httptest.NewRecorder()
   256  		req, err = http.NewRequest("GET", fmt.Sprintf("/runtimes?state=%s", pkg.StateError), nil)
   257  		require.NoError(t, err)
   258  		router.ServeHTTP(rr, req)
   259  
   260  		// then
   261  		require.Equal(t, http.StatusOK, rr.Code)
   262  
   263  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   264  		require.NoError(t, err)
   265  
   266  		assert.Equal(t, 1, out.TotalCount)
   267  		assert.Equal(t, 1, out.Count)
   268  		assert.Equal(t, testID2, out.Data[0].InstanceID)
   269  
   270  		rr = httptest.NewRecorder()
   271  		req, err = http.NewRequest("GET", fmt.Sprintf("/runtimes?state=%s", pkg.StateFailed), nil)
   272  		require.NoError(t, err)
   273  		router.ServeHTTP(rr, req)
   274  
   275  		// then
   276  		require.Equal(t, http.StatusOK, rr.Code)
   277  
   278  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   279  		require.NoError(t, err)
   280  
   281  		assert.Equal(t, 0, out.TotalCount)
   282  		assert.Equal(t, 0, out.Count)
   283  		assert.Len(t, out.Data, 0)
   284  	})
   285  
   286  	t.Run("should show suspension and unsuspension operations", func(t *testing.T) {
   287  		// given
   288  		operations := memory.NewOperation()
   289  		instances := memory.NewInstance(operations)
   290  		states := memory.NewRuntimeStates()
   291  		testID1 := "Test1"
   292  		testTime1 := time.Now()
   293  		testInstance1 := fixInstance(testID1, testTime1)
   294  
   295  		unsuspensionOpId := "unsuspension-op-id"
   296  		suspensionOpId := "suspension-op-id"
   297  
   298  		err := instances.Insert(testInstance1)
   299  		require.NoError(t, err)
   300  
   301  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   302  			Operation: internal.Operation{
   303  				ID:         "first-provisioning-id",
   304  				Version:    0,
   305  				CreatedAt:  time.Now(),
   306  				UpdatedAt:  time.Now(),
   307  				InstanceID: testID1,
   308  				Type:       internal.OperationTypeProvision,
   309  			},
   310  		})
   311  		require.NoError(t, err)
   312  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   313  			Operation: internal.Operation{
   314  				ID:         unsuspensionOpId,
   315  				Version:    0,
   316  				CreatedAt:  time.Now().Add(1 * time.Hour),
   317  				UpdatedAt:  time.Now().Add(1 * time.Hour),
   318  				InstanceID: testID1,
   319  				Type:       internal.OperationTypeProvision,
   320  			},
   321  		})
   322  
   323  		require.NoError(t, err)
   324  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   325  			Operation: internal.Operation{
   326  				ID:         suspensionOpId,
   327  				Version:    0,
   328  				CreatedAt:  time.Now(),
   329  				UpdatedAt:  time.Now(),
   330  				InstanceID: testID1,
   331  				Temporary:  true,
   332  				Type:       internal.OperationTypeDeprovision,
   333  			},
   334  		})
   335  		require.NoError(t, err)
   336  
   337  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "")
   338  
   339  		req, err := http.NewRequest("GET", "/runtimes", nil)
   340  		require.NoError(t, err)
   341  
   342  		rr := httptest.NewRecorder()
   343  		router := mux.NewRouter()
   344  		runtimeHandler.AttachRoutes(router)
   345  
   346  		// when
   347  		router.ServeHTTP(rr, req)
   348  
   349  		// then
   350  		require.Equal(t, http.StatusOK, rr.Code)
   351  
   352  		var out pkg.RuntimesPage
   353  
   354  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   355  		require.NoError(t, err)
   356  
   357  		assert.Equal(t, 1, out.TotalCount)
   358  		assert.Equal(t, 1, out.Count)
   359  		assert.Equal(t, testID1, out.Data[0].InstanceID)
   360  
   361  		unsuspensionOps := out.Data[0].Status.Unsuspension.Data
   362  		assert.Equal(t, 1, len(unsuspensionOps))
   363  		assert.Equal(t, unsuspensionOpId, unsuspensionOps[0].OperationID)
   364  
   365  		suspensionOps := out.Data[0].Status.Suspension.Data
   366  		assert.Equal(t, 1, len(suspensionOps))
   367  		assert.Equal(t, suspensionOpId, suspensionOps[0].OperationID)
   368  	})
   369  
   370  	t.Run("should distinguish between provisioning & unsuspension operations", func(t *testing.T) {
   371  		// given
   372  		operations := memory.NewOperation()
   373  		instances := memory.NewInstance(operations)
   374  		states := memory.NewRuntimeStates()
   375  		testInstance1 := fixture.FixInstance("instance-1")
   376  
   377  		provisioningOpId := "provisioning-op-id"
   378  		unsuspensionOpId := "unsuspension-op-id"
   379  
   380  		err := instances.Insert(testInstance1)
   381  		require.NoError(t, err)
   382  
   383  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   384  			Operation: internal.Operation{
   385  				ID:         provisioningOpId,
   386  				Version:    0,
   387  				CreatedAt:  time.Now(),
   388  				UpdatedAt:  time.Now(),
   389  				InstanceID: testInstance1.InstanceID,
   390  				Type:       internal.OperationTypeProvision,
   391  			},
   392  		})
   393  		require.NoError(t, err)
   394  
   395  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   396  			Operation: internal.Operation{
   397  				ID:         unsuspensionOpId,
   398  				Version:    0,
   399  				CreatedAt:  time.Now().Add(1 * time.Hour),
   400  				UpdatedAt:  time.Now().Add(1 * time.Hour),
   401  				InstanceID: testInstance1.InstanceID,
   402  				Type:       internal.OperationTypeProvision,
   403  			},
   404  		})
   405  		require.NoError(t, err)
   406  
   407  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "")
   408  
   409  		req, err := http.NewRequest("GET", "/runtimes", nil)
   410  		require.NoError(t, err)
   411  
   412  		rr := httptest.NewRecorder()
   413  		router := mux.NewRouter()
   414  		runtimeHandler.AttachRoutes(router)
   415  
   416  		// when
   417  		router.ServeHTTP(rr, req)
   418  
   419  		// then
   420  		require.Equal(t, http.StatusOK, rr.Code)
   421  
   422  		var out pkg.RuntimesPage
   423  
   424  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   425  		require.NoError(t, err)
   426  
   427  		assert.Equal(t, 1, out.TotalCount)
   428  		assert.Equal(t, 1, out.Count)
   429  		assert.Equal(t, testInstance1.InstanceID, out.Data[0].InstanceID)
   430  		assert.Equal(t, provisioningOpId, out.Data[0].Status.Provisioning.OperationID)
   431  
   432  		unsuspensionOps := out.Data[0].Status.Unsuspension.Data
   433  		assert.Equal(t, 1, len(unsuspensionOps))
   434  		assert.Equal(t, unsuspensionOpId, unsuspensionOps[0].OperationID)
   435  	})
   436  
   437  	t.Run("should distinguish between deprovisioning & suspension operations", func(t *testing.T) {
   438  		// given
   439  		operations := memory.NewOperation()
   440  		instances := memory.NewInstance(operations)
   441  		states := memory.NewRuntimeStates()
   442  		testInstance1 := fixture.FixInstance("instance-1")
   443  
   444  		suspensionOpId := "suspension-op-id"
   445  		deprovisioningOpId := "deprovisioning-op-id"
   446  
   447  		err := instances.Insert(testInstance1)
   448  		require.NoError(t, err)
   449  
   450  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   451  			Operation: internal.Operation{
   452  				ID:         suspensionOpId,
   453  				Version:    0,
   454  				CreatedAt:  time.Now(),
   455  				UpdatedAt:  time.Now(),
   456  				InstanceID: testInstance1.InstanceID,
   457  				Temporary:  true,
   458  				Type:       internal.OperationTypeDeprovision,
   459  			},
   460  		})
   461  		require.NoError(t, err)
   462  
   463  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   464  			Operation: internal.Operation{
   465  				ID:         deprovisioningOpId,
   466  				Version:    0,
   467  				CreatedAt:  time.Now().Add(1 * time.Hour),
   468  				UpdatedAt:  time.Now().Add(1 * time.Hour),
   469  				InstanceID: testInstance1.InstanceID,
   470  				Temporary:  false,
   471  				Type:       internal.OperationTypeDeprovision,
   472  			},
   473  		})
   474  		require.NoError(t, err)
   475  
   476  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "")
   477  
   478  		req, err := http.NewRequest("GET", "/runtimes", nil)
   479  		require.NoError(t, err)
   480  
   481  		rr := httptest.NewRecorder()
   482  		router := mux.NewRouter()
   483  		runtimeHandler.AttachRoutes(router)
   484  
   485  		// when
   486  		router.ServeHTTP(rr, req)
   487  
   488  		// then
   489  		require.Equal(t, http.StatusOK, rr.Code)
   490  
   491  		var out pkg.RuntimesPage
   492  
   493  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   494  		require.NoError(t, err)
   495  
   496  		assert.Equal(t, 1, out.TotalCount)
   497  		assert.Equal(t, 1, out.Count)
   498  		assert.Equal(t, testInstance1.InstanceID, out.Data[0].InstanceID)
   499  
   500  		suspensionOps := out.Data[0].Status.Suspension.Data
   501  		assert.Equal(t, 1, len(suspensionOps))
   502  		assert.Equal(t, suspensionOpId, suspensionOps[0].OperationID)
   503  
   504  		assert.Equal(t, deprovisioningOpId, out.Data[0].Status.Deprovisioning.OperationID)
   505  	})
   506  
   507  	t.Run("test operation detail parameter and runtime state", func(t *testing.T) {
   508  		// given
   509  		operations := memory.NewOperation()
   510  		instances := memory.NewInstance(operations)
   511  		states := memory.NewRuntimeStates()
   512  		testID := "Test1"
   513  		testTime := time.Now()
   514  		testInstance := fixInstance(testID, testTime)
   515  
   516  		err := instances.Insert(testInstance)
   517  		require.NoError(t, err)
   518  
   519  		provOp := fixture.FixProvisioningOperation(fixRandomID(), testID)
   520  		err = operations.InsertOperation(provOp)
   521  		require.NoError(t, err)
   522  		upgOp := fixture.FixUpgradeKymaOperation(fixRandomID(), testID)
   523  		upgOp.State = domain.Failed
   524  		upgOp.CreatedAt = upgOp.CreatedAt.Add(time.Minute)
   525  		err = operations.InsertUpgradeKymaOperation(upgOp)
   526  		require.NoError(t, err)
   527  
   528  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "")
   529  
   530  		rr := httptest.NewRecorder()
   531  		router := mux.NewRouter()
   532  		runtimeHandler.AttachRoutes(router)
   533  
   534  		// when
   535  		req, err := http.NewRequest("GET", fmt.Sprintf("/runtimes?op_detail=%s", pkg.AllOperation), nil)
   536  		require.NoError(t, err)
   537  		router.ServeHTTP(rr, req)
   538  
   539  		// then
   540  		require.Equal(t, http.StatusOK, rr.Code)
   541  
   542  		var out pkg.RuntimesPage
   543  
   544  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   545  		require.NoError(t, err)
   546  
   547  		require.Equal(t, 1, out.TotalCount)
   548  		require.Equal(t, 1, out.Count)
   549  		assert.Equal(t, testID, out.Data[0].InstanceID)
   550  		assert.NotNil(t, out.Data[0].Status.Provisioning)
   551  		assert.NotNil(t, out.Data[0].Status.UpgradingKyma)
   552  		assert.Equal(t, 1, out.Data[0].Status.UpgradingKyma.Count)
   553  		assert.Nil(t, out.Data[0].Status.Deprovisioning)
   554  		assert.Equal(t, pkg.StateError, out.Data[0].Status.State)
   555  
   556  		// when
   557  		rr = httptest.NewRecorder()
   558  		req, err = http.NewRequest("GET", fmt.Sprintf("/runtimes?op_detail=%s", pkg.LastOperation), nil)
   559  		require.NoError(t, err)
   560  		router.ServeHTTP(rr, req)
   561  
   562  		// then
   563  		require.Equal(t, http.StatusOK, rr.Code)
   564  
   565  		out = pkg.RuntimesPage{}
   566  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   567  		require.NoError(t, err)
   568  
   569  		require.Equal(t, 1, out.TotalCount)
   570  		require.Equal(t, 1, out.Count)
   571  		assert.Equal(t, testID, out.Data[0].InstanceID)
   572  		assert.Nil(t, out.Data[0].Status.Provisioning)
   573  		assert.NotNil(t, out.Data[0].Status.UpgradingKyma)
   574  		assert.Nil(t, out.Data[0].Status.Deprovisioning)
   575  		assert.Equal(t, pkg.StateError, out.Data[0].Status.State)
   576  	})
   577  
   578  	t.Run("test kyma_config and cluster_config optional attributes", func(t *testing.T) {
   579  		// given
   580  		operations := memory.NewOperation()
   581  		instances := memory.NewInstance(operations)
   582  		states := memory.NewRuntimeStates()
   583  		testID := "Test1"
   584  		testTime := time.Now()
   585  		testInstance := fixInstance(testID, testTime)
   586  
   587  		err := instances.Insert(testInstance)
   588  		require.NoError(t, err)
   589  
   590  		provOp := fixture.FixProvisioningOperation(fixRandomID(), testID)
   591  		err = operations.InsertOperation(provOp)
   592  		require.NoError(t, err)
   593  		upgOp := fixture.FixUpgradeKymaOperation(fixRandomID(), testID)
   594  		upgOp.State = domain.Failed
   595  		upgOp.CreatedAt = upgOp.CreatedAt.Add(time.Minute)
   596  		err = operations.InsertUpgradeKymaOperation(upgOp)
   597  		require.NoError(t, err)
   598  		upgClOp := fixture.FixUpgradeClusterOperation(fixRandomID(), testID)
   599  		upgClOp.CreatedAt = upgOp.CreatedAt.Add(2 * time.Minute)
   600  		err = operations.InsertUpgradeClusterOperation(upgClOp)
   601  		require.NoError(t, err)
   602  
   603  		fixProvState := internal.RuntimeState{
   604  			ID:          fixRandomID(),
   605  			CreatedAt:   provOp.CreatedAt,
   606  			RuntimeID:   testInstance.RuntimeID,
   607  			OperationID: provOp.ID,
   608  			KymaConfig: gqlschema.KymaConfigInput{
   609  				Version: "1.22.0",
   610  			},
   611  			ClusterConfig: gqlschema.GardenerConfigInput{
   612  				Name:              testID,
   613  				KubernetesVersion: "1.18.18",
   614  				Provider:          string(internal.AWS),
   615  			},
   616  		}
   617  		err = states.Insert(fixProvState)
   618  		require.NoError(t, err)
   619  		fixUpgKymaState := internal.RuntimeState{
   620  			ID:          fixRandomID(),
   621  			CreatedAt:   upgOp.CreatedAt,
   622  			RuntimeID:   testInstance.RuntimeID,
   623  			OperationID: upgOp.Operation.ID,
   624  			KymaConfig: gqlschema.KymaConfigInput{
   625  				Version: "1.23.0",
   626  				Profile: (*gqlschema.KymaProfile)(ptr.String("production")),
   627  				Components: []*gqlschema.ComponentConfigurationInput{
   628  					{
   629  						Component: "istio",
   630  						Namespace: "istio-system",
   631  						Configuration: []*gqlschema.ConfigEntryInput{
   632  							{
   633  								Key:   "test_key",
   634  								Value: "test_value",
   635  							},
   636  						},
   637  					},
   638  				},
   639  			},
   640  		}
   641  		err = states.Insert(fixUpgKymaState)
   642  		require.NoError(t, err)
   643  		fixOpgClusterState := internal.RuntimeState{
   644  			ID:          fixRandomID(),
   645  			CreatedAt:   upgClOp.CreatedAt,
   646  			RuntimeID:   testInstance.RuntimeID,
   647  			OperationID: upgClOp.Operation.ID,
   648  			ClusterConfig: gqlschema.GardenerConfigInput{
   649  				Name:                testID,
   650  				KubernetesVersion:   "1.19.19",
   651  				Provider:            string(internal.AWS),
   652  				MachineImage:        ptr.String("gardenlinux"),
   653  				MachineImageVersion: ptr.String("1.0.0"),
   654  			},
   655  		}
   656  		err = states.Insert(fixOpgClusterState)
   657  		require.NoError(t, err)
   658  
   659  		runtimeHandler := runtime.NewHandler(instances, operations, states, 2, "")
   660  
   661  		rr := httptest.NewRecorder()
   662  		router := mux.NewRouter()
   663  		runtimeHandler.AttachRoutes(router)
   664  
   665  		// when
   666  		req, err := http.NewRequest("GET", "/runtimes?kyma_config=true&cluster_config=true", nil)
   667  		require.NoError(t, err)
   668  		router.ServeHTTP(rr, req)
   669  
   670  		// then
   671  		require.Equal(t, http.StatusOK, rr.Code)
   672  
   673  		var out pkg.RuntimesPage
   674  
   675  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   676  		require.NoError(t, err)
   677  
   678  		require.Equal(t, 1, out.TotalCount)
   679  		require.Equal(t, 1, out.Count)
   680  		assert.Equal(t, testID, out.Data[0].InstanceID)
   681  		require.NotNil(t, out.Data[0].KymaConfig)
   682  		assert.Equal(t, "1.23.0", out.Data[0].KymaConfig.Version)
   683  		require.NotNil(t, out.Data[0].ClusterConfig)
   684  		assert.Equal(t, "1.19.19", out.Data[0].ClusterConfig.KubernetesVersion)
   685  	})
   686  }
   687  
   688  func fixInstance(id string, t time.Time) internal.Instance {
   689  	return internal.Instance{
   690  		InstanceID:      id,
   691  		CreatedAt:       t,
   692  		GlobalAccountID: id,
   693  		SubAccountID:    id,
   694  		RuntimeID:       id,
   695  		ServiceID:       id,
   696  		ServiceName:     id,
   697  		ServicePlanID:   id,
   698  		ServicePlanName: id,
   699  		DashboardURL:    fmt.Sprintf("https://console.%s.kyma.local", id),
   700  		ProviderRegion:  id,
   701  		Parameters:      internal.ProvisioningParameters{},
   702  	}
   703  }
   704  
   705  func fixRandomID() string {
   706  	return rand.String(16)
   707  }