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

     1  package appinfo_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/kyma-environment-broker/internal"
    13  	"github.com/kyma-project/kyma-environment-broker/internal/appinfo"
    14  	"github.com/kyma-project/kyma-environment-broker/internal/appinfo/automock"
    15  	"github.com/kyma-project/kyma-environment-broker/internal/broker"
    16  	"github.com/kyma-project/kyma-environment-broker/internal/fixture"
    17  	"github.com/kyma-project/kyma-environment-broker/internal/httputil"
    18  	"github.com/kyma-project/kyma-environment-broker/internal/logger"
    19  	"github.com/kyma-project/kyma-environment-broker/internal/storage"
    20  	"github.com/kyma-project/kyma-environment-broker/internal/storage/driver/memory"
    21  	"github.com/pivotal-cf/brokerapi/v8/domain"
    22  	"github.com/sebdah/goldie/v2"
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/stretchr/testify/mock"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  // go test ./internal/appinfo -update -run=TestRuntimeInfoHandlerSuccess
    29  func TestRuntimeInfoHandlerSuccess(t *testing.T) {
    30  	tests := map[string]struct {
    31  		instances     []internal.Instance
    32  		provisionOp   []internal.ProvisioningOperation
    33  		deprovisionOp []internal.DeprovisioningOperation
    34  	}{
    35  		"no instances": {
    36  			instances: []internal.Instance{},
    37  		},
    38  		"instances without operations": {
    39  			instances: []internal.Instance{
    40  				fixInstance(1), fixInstance(2), fixInstance(2),
    41  			},
    42  		},
    43  		"instances without service and plan name should have defaults": {
    44  			instances: func() []internal.Instance {
    45  				i := fixInstance(1)
    46  				i.ServicePlanName = ""
    47  				i.ServiceName = ""
    48  				// selecting servicePlanName based on existing real planID
    49  				i.ServicePlanID = broker.GCPPlanID
    50  				return []internal.Instance{i}
    51  			}(),
    52  		},
    53  		"instances without platform region name should have default": {
    54  			instances: func() []internal.Instance {
    55  				i := fixInstance(1)
    56  				// the platform_region is not specified
    57  				i.Parameters = internal.ProvisioningParameters{}
    58  				return []internal.Instance{i}
    59  			}(),
    60  		},
    61  		"instances with provision operation": {
    62  			instances: []internal.Instance{
    63  				fixInstance(1), fixInstance(2), fixInstance(3),
    64  			},
    65  			provisionOp: []internal.ProvisioningOperation{
    66  				fixProvisionOperation(1), fixProvisionOperation(2),
    67  			},
    68  		},
    69  		"instances with deprovision operation": {
    70  			instances: []internal.Instance{
    71  				fixInstance(1), fixInstance(2), fixInstance(3),
    72  			},
    73  			deprovisionOp: []internal.DeprovisioningOperation{
    74  				fixDeprovisionOperation(1), fixDeprovisionOperation(2),
    75  			},
    76  		},
    77  		"instances with provision and deprovision operations": {
    78  			instances: []internal.Instance{
    79  				fixInstance(1), fixInstance(2), fixInstance(3),
    80  			},
    81  			provisionOp: []internal.ProvisioningOperation{
    82  				fixProvisionOperation(1), fixProvisionOperation(2),
    83  			},
    84  			deprovisionOp: []internal.DeprovisioningOperation{
    85  				fixDeprovisionOperation(1), fixDeprovisionOperation(2),
    86  			},
    87  		},
    88  	}
    89  	for tn, tc := range tests {
    90  		t.Run(tn, func(t *testing.T) {
    91  			// given
    92  			var (
    93  				fixReq     = httptest.NewRequest("GET", "http://example.com/foo", nil)
    94  				respSpy    = httptest.NewRecorder()
    95  				writer     = httputil.NewResponseWriter(logger.NewLogDummy(), true)
    96  				memStorage = newInMemoryStorage(t, tc.instances, tc.provisionOp, tc.deprovisionOp)
    97  			)
    98  
    99  			handler := appinfo.NewRuntimeInfoHandler(memStorage.Instances(), memStorage.Operations(), broker.PlansConfig{}, "default-region", writer)
   100  
   101  			// when
   102  			handler.ServeHTTP(respSpy, fixReq)
   103  
   104  			// then
   105  			assert.Equal(t, http.StatusOK, respSpy.Result().StatusCode)
   106  			assert.Equal(t, "application/json", respSpy.Result().Header.Get("Content-Type"))
   107  
   108  			assertJSONWithGoldenFile(t, respSpy.Body.Bytes())
   109  		})
   110  	}
   111  }
   112  
   113  func TestRuntimeInfoHandlerFailures(t *testing.T) {
   114  	// given
   115  	var (
   116  		fixReq  = httptest.NewRequest("GET", "http://example.com/foo", nil)
   117  		respSpy = httptest.NewRecorder()
   118  		writer  = httputil.NewResponseWriter(logger.NewLogDummy(), true)
   119  		expBody = `{
   120  				  "status": 500,
   121  				  "requestId": "",
   122  				  "message": "Something went very wrong. Please try again.",
   123  				  "details": "while fetching all instances: ups.. internal info"
   124  				}`
   125  	)
   126  
   127  	storageMock := &automock.InstanceFinder{}
   128  	defer storageMock.AssertExpectations(t)
   129  	storageMock.On("FindAllJoinedWithOperations", mock.Anything).Return(nil, fmt.Errorf("ups.. internal info"))
   130  	handler := appinfo.NewRuntimeInfoHandler(storageMock, nil, broker.PlansConfig{}, "", writer)
   131  
   132  	// when
   133  	handler.ServeHTTP(respSpy, fixReq)
   134  
   135  	// then
   136  	assert.Equal(t, http.StatusInternalServerError, respSpy.Result().StatusCode)
   137  	assert.Equal(t, "application/json", respSpy.Result().Header.Get("Content-Type"))
   138  
   139  	assert.JSONEq(t, expBody, respSpy.Body.String())
   140  }
   141  
   142  func TestRuntimeInfoHandlerOperationRecognition(t *testing.T) {
   143  	t.Run("should distinguish between provisioning & unsuspension operations", func(t *testing.T) {
   144  		// given
   145  		operations := memory.NewOperation()
   146  		instances := memory.NewInstance(operations)
   147  
   148  		testInstance1 := fixture.FixInstance("instance-1")
   149  		testInstance2 := fixture.FixInstance("instance-2")
   150  
   151  		err := instances.Insert(testInstance1)
   152  		require.NoError(t, err)
   153  		err = instances.Insert(testInstance2)
   154  		require.NoError(t, err)
   155  
   156  		provisioningOpId1 := "provisioning-op-1"
   157  		provisioningOpId2 := "provisioning-op-2"
   158  		unsuspensionOpId1 := "unsuspension-op-1"
   159  		unsuspensionOpId2 := "unsuspension-op-2"
   160  		provisioningOpDesc1 := "succeeded provisioning operation 1"
   161  		provisioningOpDesc2 := "succeeded provisioning operation 2"
   162  		unsuspensionOpDesc1 := "succeeded unsuspension operation 1"
   163  		unsuspensionOpDesc2 := "succeeded unsuspension operation 2"
   164  
   165  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   166  			Operation: internal.Operation{
   167  				ID:          provisioningOpId1,
   168  				Version:     0,
   169  				CreatedAt:   time.Now(),
   170  				UpdatedAt:   time.Now().Add(5 * time.Minute),
   171  				Type:        internal.OperationTypeProvision,
   172  				InstanceID:  testInstance1.InstanceID,
   173  				State:       domain.Succeeded,
   174  				Description: provisioningOpDesc1,
   175  			},
   176  		})
   177  		require.NoError(t, err)
   178  
   179  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   180  			Operation: internal.Operation{
   181  				ID:          unsuspensionOpId1,
   182  				Version:     0,
   183  				CreatedAt:   time.Now().Add(1 * time.Hour),
   184  				UpdatedAt:   time.Now().Add(1 * time.Hour).Add(5 * time.Minute),
   185  				Type:        internal.OperationTypeProvision,
   186  				InstanceID:  testInstance1.InstanceID,
   187  				State:       domain.Succeeded,
   188  				Description: unsuspensionOpDesc1,
   189  			},
   190  		})
   191  		require.NoError(t, err)
   192  
   193  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   194  			Operation: internal.Operation{
   195  				ID:          unsuspensionOpId2,
   196  				Version:     0,
   197  				CreatedAt:   time.Now().Add(1 * time.Hour),
   198  				UpdatedAt:   time.Now().Add(1 * time.Hour).Add(5 * time.Minute),
   199  				Type:        internal.OperationTypeProvision,
   200  				InstanceID:  testInstance2.InstanceID,
   201  				State:       domain.Succeeded,
   202  				Description: unsuspensionOpDesc2,
   203  			},
   204  		})
   205  		require.NoError(t, err)
   206  
   207  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   208  			Operation: internal.Operation{
   209  				ID:          provisioningOpId2,
   210  				Version:     0,
   211  				CreatedAt:   time.Now(),
   212  				UpdatedAt:   time.Now().Add(5 * time.Minute),
   213  				Type:        internal.OperationTypeProvision,
   214  				InstanceID:  testInstance2.InstanceID,
   215  				State:       domain.Succeeded,
   216  				Description: provisioningOpDesc2,
   217  			},
   218  		})
   219  		require.NoError(t, err)
   220  
   221  		req, err := http.NewRequest("GET", "/info/runtimes", nil)
   222  		require.NoError(t, err)
   223  
   224  		responseWriter := httputil.NewResponseWriter(logger.NewLogDummy(), true)
   225  		runtimesInfoHandler := appinfo.NewRuntimeInfoHandler(instances, operations, broker.PlansConfig{}, "", responseWriter)
   226  
   227  		rr := httptest.NewRecorder()
   228  		router := mux.NewRouter()
   229  		router.Handle("/info/runtimes", runtimesInfoHandler)
   230  
   231  		// when
   232  		runtimesInfoHandler.ServeHTTP(rr, req)
   233  
   234  		// then
   235  		require.Equal(t, http.StatusOK, rr.Code)
   236  
   237  		var out []*appinfo.RuntimeDTO
   238  
   239  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   240  		require.NoError(t, err)
   241  
   242  		assert.Equal(t, 2, len(out))
   243  		assert.Equal(t, testInstance1.InstanceID, out[0].ServiceInstanceID)
   244  		assert.Equal(t, testInstance2.InstanceID, out[1].ServiceInstanceID)
   245  		assert.Equal(t, provisioningOpDesc1, out[0].Status.Provisioning.Description)
   246  		assert.Equal(t, provisioningOpDesc2, out[1].Status.Provisioning.Description)
   247  
   248  	})
   249  
   250  	t.Run("should distinguish between deprovisioning & suspension operations", func(t *testing.T) {
   251  		// given
   252  		operations := memory.NewOperation()
   253  		instances := memory.NewInstance(operations)
   254  
   255  		testInstance1 := fixture.FixInstance("instance-1")
   256  		testInstance2 := fixture.FixInstance("instance-2")
   257  
   258  		err := instances.Insert(testInstance1)
   259  		require.NoError(t, err)
   260  		err = instances.Insert(testInstance2)
   261  		require.NoError(t, err)
   262  
   263  		deprovisioningOpId1 := "deprovisioning-op-1"
   264  		deprovisioningOpId2 := "deprovisioning-op-2"
   265  		suspensionOpId1 := "suspension-op-1"
   266  		suspensionOpId2 := "suspension-op-2"
   267  		deprovisioningOpDesc1 := "succeeded deprovisioning operation 1"
   268  		deprovisioningOpDesc2 := "succeeded deprovisioning operation 2"
   269  		suspensionOpDesc1 := "succeeded suspension operation 1"
   270  		suspensionOpDesc2 := "succeeded suspension operation 2"
   271  
   272  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   273  			Operation: internal.Operation{
   274  				ID:          suspensionOpId1,
   275  				Version:     0,
   276  				CreatedAt:   time.Now(),
   277  				UpdatedAt:   time.Now().Add(5 * time.Minute),
   278  				Type:        internal.OperationTypeDeprovision,
   279  				InstanceID:  testInstance1.InstanceID,
   280  				State:       domain.Succeeded,
   281  				Description: suspensionOpDesc1,
   282  				Temporary:   true,
   283  			},
   284  		})
   285  		require.NoError(t, err)
   286  
   287  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   288  			Operation: internal.Operation{
   289  				ID:          deprovisioningOpId1,
   290  				Version:     0,
   291  				CreatedAt:   time.Now().Add(1 * time.Hour),
   292  				UpdatedAt:   time.Now().Add(1 * time.Hour).Add(5 * time.Minute),
   293  				Type:        internal.OperationTypeDeprovision,
   294  				InstanceID:  testInstance1.InstanceID,
   295  				State:       domain.Succeeded,
   296  				Description: deprovisioningOpDesc1,
   297  			},
   298  		})
   299  		require.NoError(t, err)
   300  
   301  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   302  			Operation: internal.Operation{
   303  				ID:          deprovisioningOpId2,
   304  				Version:     0,
   305  				CreatedAt:   time.Now().Add(1 * time.Hour),
   306  				UpdatedAt:   time.Now().Add(1 * time.Hour).Add(5 * time.Minute),
   307  				Type:        internal.OperationTypeDeprovision,
   308  				InstanceID:  testInstance2.InstanceID,
   309  				State:       domain.Succeeded,
   310  				Description: deprovisioningOpDesc2,
   311  			},
   312  		})
   313  		require.NoError(t, err)
   314  
   315  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   316  			Operation: internal.Operation{
   317  				ID:          suspensionOpId2,
   318  				Version:     0,
   319  				CreatedAt:   time.Now(),
   320  				UpdatedAt:   time.Now().Add(5 * time.Minute),
   321  				Type:        internal.OperationTypeProvision,
   322  				InstanceID:  testInstance2.InstanceID,
   323  				State:       domain.Succeeded,
   324  				Description: suspensionOpDesc2,
   325  				Temporary:   true,
   326  			},
   327  		})
   328  		require.NoError(t, err)
   329  
   330  		req, err := http.NewRequest("GET", "/info/runtimes", nil)
   331  		require.NoError(t, err)
   332  
   333  		responseWriter := httputil.NewResponseWriter(logger.NewLogDummy(), true)
   334  		runtimesInfoHandler := appinfo.NewRuntimeInfoHandler(instances, operations, broker.PlansConfig{}, "", responseWriter)
   335  
   336  		rr := httptest.NewRecorder()
   337  		router := mux.NewRouter()
   338  		router.Handle("/info/runtimes", runtimesInfoHandler)
   339  
   340  		// when
   341  		runtimesInfoHandler.ServeHTTP(rr, req)
   342  
   343  		// then
   344  		require.Equal(t, http.StatusOK, rr.Code)
   345  
   346  		var out []*appinfo.RuntimeDTO
   347  
   348  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   349  		require.NoError(t, err)
   350  
   351  		assert.Equal(t, 2, len(out))
   352  		assert.Equal(t, testInstance1.InstanceID, out[0].ServiceInstanceID)
   353  		assert.Equal(t, testInstance2.InstanceID, out[1].ServiceInstanceID)
   354  		assert.Equal(t, deprovisioningOpDesc1, out[0].Status.Deprovisioning.Description)
   355  		assert.Equal(t, deprovisioningOpDesc2, out[1].Status.Deprovisioning.Description)
   356  
   357  	})
   358  
   359  	t.Run("should recognize prov & deprov ops among suspend/unsuspend operations", func(t *testing.T) {
   360  		// given
   361  		operations := memory.NewOperation()
   362  		instances := memory.NewInstance(operations)
   363  
   364  		testInstance1 := fixture.FixInstance("instance-1")
   365  
   366  		err := instances.Insert(testInstance1)
   367  		require.NoError(t, err)
   368  
   369  		provisioningOpId := "provisioning-op"
   370  		deprovisioningOpId := "deprovisioning-op"
   371  		suspensionOpId1 := "suspension-op-1"
   372  		suspensionOpId2 := "suspension-op-2"
   373  		unsuspensionOpId1 := "unsuspension-op-1"
   374  		unsuspensionOpId2 := "unsuspension-op-2"
   375  		provisioningOpDesc := "succeeded provisioning operation"
   376  		deprovisioningOpDesc := "succeeded deprovisioning operation"
   377  		suspensionOpDesc1 := "failed suspension operation 1"
   378  		suspensionOpDesc2 := "succeeded suspension operation 2"
   379  		unsuspensionOpDesc1 := "failed unsuspension operation 1"
   380  		unsuspensionOpDesc2 := "succeeded unsuspension operation 2"
   381  
   382  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   383  			Operation: internal.Operation{
   384  				ID:          provisioningOpId,
   385  				Version:     0,
   386  				CreatedAt:   time.Now(),
   387  				UpdatedAt:   time.Now().Add(5 * time.Minute),
   388  				Type:        internal.OperationTypeProvision,
   389  				InstanceID:  testInstance1.InstanceID,
   390  				State:       domain.Succeeded,
   391  				Description: provisioningOpDesc,
   392  			},
   393  		})
   394  		require.NoError(t, err)
   395  
   396  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   397  			Operation: internal.Operation{
   398  				ID:          suspensionOpId1,
   399  				Version:     0,
   400  				CreatedAt:   time.Now().Add(1 * time.Hour),
   401  				UpdatedAt:   time.Now().Add(1 * time.Hour).Add(5 * time.Minute),
   402  				Type:        internal.OperationTypeDeprovision,
   403  				InstanceID:  testInstance1.InstanceID,
   404  				State:       domain.Failed,
   405  				Description: suspensionOpDesc1,
   406  				Temporary:   true,
   407  			},
   408  		})
   409  		require.NoError(t, err)
   410  
   411  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   412  			Operation: internal.Operation{
   413  				ID:          suspensionOpId2,
   414  				Version:     0,
   415  				CreatedAt:   time.Now().Add(2 * time.Hour),
   416  				UpdatedAt:   time.Now().Add(2 * time.Hour).Add(5 * time.Minute),
   417  				Type:        internal.OperationTypeDeprovision,
   418  				InstanceID:  testInstance1.InstanceID,
   419  				State:       domain.Succeeded,
   420  				Description: suspensionOpDesc2,
   421  				Temporary:   true,
   422  			},
   423  		})
   424  		require.NoError(t, err)
   425  
   426  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   427  			Operation: internal.Operation{
   428  				ID:          unsuspensionOpId1,
   429  				Version:     0,
   430  				CreatedAt:   time.Now().Add(3 * time.Hour),
   431  				UpdatedAt:   time.Now().Add(3 * time.Hour).Add(5 * time.Minute),
   432  				Type:        internal.OperationTypeProvision,
   433  				InstanceID:  testInstance1.InstanceID,
   434  				State:       domain.Failed,
   435  				Description: unsuspensionOpDesc1,
   436  			},
   437  		})
   438  		require.NoError(t, err)
   439  
   440  		err = operations.InsertProvisioningOperation(internal.ProvisioningOperation{
   441  			Operation: internal.Operation{
   442  				ID:          unsuspensionOpId2,
   443  				Version:     0,
   444  				CreatedAt:   time.Now().Add(4 * time.Hour),
   445  				UpdatedAt:   time.Now().Add(4 * time.Hour).Add(5 * time.Minute),
   446  				Type:        internal.OperationTypeProvision,
   447  				InstanceID:  testInstance1.InstanceID,
   448  				State:       domain.Succeeded,
   449  				Description: unsuspensionOpDesc2,
   450  			},
   451  		})
   452  		require.NoError(t, err)
   453  
   454  		err = operations.InsertDeprovisioningOperation(internal.DeprovisioningOperation{
   455  			Operation: internal.Operation{
   456  				ID:          deprovisioningOpId,
   457  				Version:     0,
   458  				CreatedAt:   time.Now().Add(5 * time.Hour),
   459  				UpdatedAt:   time.Now().Add(5 * time.Hour).Add(5 * time.Minute),
   460  				Type:        internal.OperationTypeDeprovision,
   461  				InstanceID:  testInstance1.InstanceID,
   462  				State:       domain.Succeeded,
   463  				Description: deprovisioningOpDesc,
   464  			},
   465  		})
   466  		require.NoError(t, err)
   467  
   468  		req, err := http.NewRequest("GET", "/info/runtimes", nil)
   469  		require.NoError(t, err)
   470  
   471  		responseWriter := httputil.NewResponseWriter(logger.NewLogDummy(), true)
   472  		runtimesInfoHandler := appinfo.NewRuntimeInfoHandler(instances, operations, broker.PlansConfig{}, "", responseWriter)
   473  
   474  		rr := httptest.NewRecorder()
   475  		router := mux.NewRouter()
   476  		router.Handle("/info/runtimes", runtimesInfoHandler)
   477  
   478  		// when
   479  		runtimesInfoHandler.ServeHTTP(rr, req)
   480  
   481  		// then
   482  		require.Equal(t, http.StatusOK, rr.Code)
   483  
   484  		var out []*appinfo.RuntimeDTO
   485  
   486  		err = json.Unmarshal(rr.Body.Bytes(), &out)
   487  		require.NoError(t, err)
   488  
   489  		assert.Equal(t, 1, len(out))
   490  		assert.Equal(t, testInstance1.InstanceID, out[0].ServiceInstanceID)
   491  		assert.Equal(t, provisioningOpDesc, out[0].Status.Provisioning.Description)
   492  		assert.Equal(t, deprovisioningOpDesc, out[0].Status.Deprovisioning.Description)
   493  
   494  	})
   495  }
   496  
   497  func assertJSONWithGoldenFile(t *testing.T, gotRawJSON []byte) {
   498  	t.Helper()
   499  	g := goldie.New(t, goldie.WithNameSuffix(".golden.json"))
   500  
   501  	var jsonGoType interface{}
   502  	require.NoError(t, json.Unmarshal(gotRawJSON, &jsonGoType))
   503  	g.AssertJson(t, t.Name(), jsonGoType)
   504  }
   505  
   506  func fixTime() time.Time {
   507  	return time.Date(2020, 04, 21, 0, 0, 23, 42, time.UTC)
   508  }
   509  
   510  func fixInstance(idx int) internal.Instance {
   511  	return internal.Instance{
   512  		InstanceID:      fmt.Sprintf("InstanceID field. IDX: %d", idx),
   513  		RuntimeID:       fmt.Sprintf("RuntimeID field. IDX: %d", idx),
   514  		GlobalAccountID: fmt.Sprintf("GlobalAccountID field. IDX: %d", idx),
   515  		SubAccountID:    fmt.Sprintf("SubAccountID field. IDX: %d", idx),
   516  		ServiceID:       fmt.Sprintf("ServiceID field. IDX: %d", idx),
   517  		ServiceName:     fmt.Sprintf("ServiceName field. IDX: %d", idx),
   518  		ServicePlanID:   fmt.Sprintf("ServicePlanID field. IDX: %d", idx),
   519  		ServicePlanName: fmt.Sprintf("ServicePlanName field. IDX: %d", idx),
   520  		DashboardURL:    fmt.Sprintf("DashboardURL field. IDX: %d", idx),
   521  		Parameters: internal.ProvisioningParameters{
   522  			PlatformRegion: fmt.Sprintf("region-value-idx-%d", idx),
   523  		},
   524  		CreatedAt: fixTime().Add(time.Duration(idx) * time.Second),
   525  		UpdatedAt: fixTime().Add(time.Duration(idx) * time.Minute),
   526  		DeletedAt: fixTime().Add(time.Duration(idx) * time.Hour),
   527  	}
   528  }
   529  
   530  func newInMemoryStorage(t *testing.T,
   531  	instances []internal.Instance,
   532  	provisionOp []internal.ProvisioningOperation,
   533  	deprovisionOp []internal.DeprovisioningOperation) storage.BrokerStorage {
   534  
   535  	t.Helper()
   536  	memStorage := storage.NewMemoryStorage()
   537  	for _, i := range instances {
   538  		require.NoError(t, memStorage.Instances().Insert(i))
   539  	}
   540  	for _, op := range provisionOp {
   541  		require.NoError(t, memStorage.Operations().InsertProvisioningOperation(op))
   542  	}
   543  	for _, op := range deprovisionOp {
   544  		require.NoError(t, memStorage.Operations().InsertDeprovisioningOperation(op))
   545  	}
   546  
   547  	return memStorage
   548  }
   549  
   550  func fixProvisionOperation(idx int) internal.ProvisioningOperation {
   551  	o := internal.ProvisioningOperation{
   552  		Operation: fixSucceededOperation(internal.OperationTypeProvision, idx),
   553  	}
   554  	o.Type = internal.OperationTypeProvision
   555  	return o
   556  }
   557  func fixDeprovisionOperation(idx int) internal.DeprovisioningOperation {
   558  	return internal.DeprovisioningOperation{
   559  		Operation: fixSucceededOperation(internal.OperationTypeDeprovision, idx),
   560  	}
   561  }
   562  
   563  func fixSucceededOperation(operationType internal.OperationType, idx int) internal.Operation {
   564  	return internal.Operation{
   565  		ID:                     fmt.Sprintf("Operation %v ID field. IDX: %d", operationType, idx),
   566  		Version:                0,
   567  		CreatedAt:              fixTime().Add(time.Duration(idx) * 24 * time.Hour),
   568  		UpdatedAt:              fixTime().Add(time.Duration(idx) * 48 * time.Hour),
   569  		InstanceID:             fmt.Sprintf("InstanceID field. IDX: %d", idx),
   570  		ProvisionerOperationID: fmt.Sprintf("ProvisionerOperationID field. IDX: %d", idx),
   571  		State:                  domain.Succeeded,
   572  		Description:            fmt.Sprintf("esc for succeeded op.. IDX: %d", idx),
   573  		Type:                   operationType,
   574  	}
   575  }