github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/domain/label/repository_test.go (about)

     1  package label_test
     2  
     3  import (
     4  	"context"
     5  	"database/sql"
     6  	"database/sql/driver"
     7  	"regexp"
     8  	"testing"
     9  
    10  	"github.com/pkg/errors"
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/mock"
    13  
    14  	"github.com/DATA-DOG/go-sqlmock"
    15  	"github.com/kyma-incubator/compass/components/director/internal/domain/label"
    16  	"github.com/kyma-incubator/compass/components/director/internal/domain/label/automock"
    17  	"github.com/kyma-incubator/compass/components/director/internal/model"
    18  	"github.com/kyma-incubator/compass/components/director/internal/repo/testdb"
    19  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    20  	"github.com/stretchr/testify/require"
    21  )
    22  
    23  func TestRepository_Create(t *testing.T) {
    24  	var nilLabelModel *model.Label
    25  	applabelModel := fixModelLabel(model.ApplicationLabelableObject)
    26  	appLabelEntity := fixEntityLabel(model.ApplicationLabelableObject)
    27  	runtimelabelModel := fixModelLabel(model.RuntimeLabelableObject)
    28  	runtimeLabelEntity := fixEntityLabel(model.RuntimeLabelableObject)
    29  	runtimeCtxlabelModel := fixModelLabel(model.RuntimeContextLabelableObject)
    30  	runtimeCtxLabelEntity := fixEntityLabel(model.RuntimeContextLabelableObject)
    31  
    32  	appLabelSuite := testdb.RepoCreateTestSuite{
    33  		Name: "Create Application Label",
    34  		SQLQueryDetails: []testdb.SQLQueryDetails{
    35  			{
    36  				Query:    regexp.QuoteMeta("SELECT 1 FROM tenant_applications WHERE tenant_id = $1 AND id = $2 AND owner = $3"),
    37  				Args:     []driver.Value{tenantID, refID, true},
    38  				IsSelect: true,
    39  				ValidRowsProvider: func() []*sqlmock.Rows {
    40  					return []*sqlmock.Rows{testdb.RowWhenObjectExist()}
    41  				},
    42  				InvalidRowsProvider: func() []*sqlmock.Rows {
    43  					return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()}
    44  				},
    45  			},
    46  			{
    47  				Query:       regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )"),
    48  				Args:        []driver.Value{appLabelEntity.ID, appLabelEntity.TenantID, appLabelEntity.AppID, appLabelEntity.RuntimeID, appLabelEntity.RuntimeContextID, appLabelEntity.AppTemplateID, appLabelEntity.Key, appLabelEntity.Value, appLabelEntity.Version},
    49  				ValidResult: sqlmock.NewResult(-1, 1),
    50  			},
    51  		},
    52  		ConverterMockProvider: func() testdb.Mock {
    53  			return &automock.Converter{}
    54  		},
    55  		RepoConstructorFunc: label.NewRepository,
    56  		ModelEntity:         applabelModel,
    57  		DBEntity:            appLabelEntity,
    58  		NilModelEntity:      nilLabelModel,
    59  		TenantID:            tenantID,
    60  	}
    61  
    62  	runtimeLabelSuite := testdb.RepoCreateTestSuite{
    63  		Name: "Create Runtime Label",
    64  		SQLQueryDetails: []testdb.SQLQueryDetails{
    65  			{
    66  				Query:    regexp.QuoteMeta("SELECT 1 FROM tenant_runtimes WHERE tenant_id = $1 AND id = $2 AND owner = $3"),
    67  				Args:     []driver.Value{tenantID, refID, true},
    68  				IsSelect: true,
    69  				ValidRowsProvider: func() []*sqlmock.Rows {
    70  					return []*sqlmock.Rows{testdb.RowWhenObjectExist()}
    71  				},
    72  				InvalidRowsProvider: func() []*sqlmock.Rows {
    73  					return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()}
    74  				},
    75  			},
    76  			{
    77  				Query:       regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )"),
    78  				Args:        []driver.Value{runtimeLabelEntity.ID, runtimeLabelEntity.TenantID, runtimeLabelEntity.AppID, runtimeLabelEntity.RuntimeID, runtimeLabelEntity.RuntimeContextID, runtimeLabelEntity.AppTemplateID, runtimeLabelEntity.Key, runtimeLabelEntity.Value, runtimeLabelEntity.Version},
    79  				ValidResult: sqlmock.NewResult(-1, 1),
    80  			},
    81  		},
    82  		ConverterMockProvider: func() testdb.Mock {
    83  			return &automock.Converter{}
    84  		},
    85  		RepoConstructorFunc: label.NewRepository,
    86  		ModelEntity:         runtimelabelModel,
    87  		DBEntity:            runtimeLabelEntity,
    88  		NilModelEntity:      nilLabelModel,
    89  		TenantID:            tenantID,
    90  	}
    91  
    92  	runtimeCtxLabelSuite := testdb.RepoCreateTestSuite{
    93  		Name: "Create RuntimeCtx Label",
    94  		SQLQueryDetails: []testdb.SQLQueryDetails{
    95  			{
    96  				Query:    regexp.QuoteMeta("SELECT 1 FROM tenant_runtime_contexts WHERE tenant_id = $1 AND id = $2 AND owner = $3"),
    97  				Args:     []driver.Value{tenantID, refID, true},
    98  				IsSelect: true,
    99  				ValidRowsProvider: func() []*sqlmock.Rows {
   100  					return []*sqlmock.Rows{testdb.RowWhenObjectExist()}
   101  				},
   102  				InvalidRowsProvider: func() []*sqlmock.Rows {
   103  					return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()}
   104  				},
   105  			},
   106  			{
   107  				Query:       regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )"),
   108  				Args:        []driver.Value{runtimeCtxLabelEntity.ID, runtimeCtxLabelEntity.TenantID, runtimeCtxLabelEntity.AppID, runtimeCtxLabelEntity.RuntimeID, runtimeCtxLabelEntity.RuntimeContextID, runtimeCtxLabelEntity.AppTemplateID, runtimeCtxLabelEntity.Key, runtimeCtxLabelEntity.Value, runtimeCtxLabelEntity.Version},
   109  				ValidResult: sqlmock.NewResult(-1, 1),
   110  			},
   111  		},
   112  		ConverterMockProvider: func() testdb.Mock {
   113  			return &automock.Converter{}
   114  		},
   115  		RepoConstructorFunc: label.NewRepository,
   116  		ModelEntity:         runtimeCtxlabelModel,
   117  		DBEntity:            runtimeCtxLabelEntity,
   118  		NilModelEntity:      nilLabelModel,
   119  		TenantID:            tenantID,
   120  		IsTopLevelEntity:    true,
   121  	}
   122  
   123  	appLabelSuite.Run(t)
   124  	runtimeLabelSuite.Run(t)
   125  	runtimeCtxLabelSuite.Run(t)
   126  
   127  	// Additional tests - tenant labels are created globally as the tenant is embedded in the entity.
   128  	t.Run("Success create - Label for Tenant", func(t *testing.T) {
   129  		// GIVEN
   130  		labelModel := fixModelLabel(model.TenantLabelableObject)
   131  		labelEntity := fixEntityLabel(model.TenantLabelableObject)
   132  
   133  		mockConverter := &automock.Converter{}
   134  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   135  		defer mockConverter.AssertExpectations(t)
   136  
   137  		labelRepo := label.NewRepository(mockConverter)
   138  
   139  		db, dbMock := testdb.MockDatabase(t)
   140  		defer dbMock.AssertExpectations(t)
   141  
   142  		escapedInsertQuery := regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )")
   143  		dbMock.ExpectExec(escapedInsertQuery).WithArgs(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version).WillReturnResult(sqlmock.NewResult(1, 1))
   144  
   145  		ctx := context.TODO()
   146  		ctx = persistence.SaveToContext(ctx, db)
   147  		// WHEN
   148  		err := labelRepo.Create(ctx, tenantID, labelModel)
   149  		// THEN
   150  		require.NoError(t, err)
   151  	})
   152  
   153  	t.Run("Success create - Label for Application Template", func(t *testing.T) {
   154  		// GIVEN
   155  		appTemplateLabelModel := fixModelLabel(model.AppTemplateLabelableObject)
   156  		appTemplateLabelEntity := fixEntityLabel(model.AppTemplateLabelableObject)
   157  
   158  		mockConverter := &automock.Converter{}
   159  		mockConverter.On("ToEntity", appTemplateLabelModel).Return(appTemplateLabelEntity, nil).Once()
   160  		defer mockConverter.AssertExpectations(t)
   161  
   162  		labelRepo := label.NewRepository(mockConverter)
   163  
   164  		db, dbMock := testdb.MockDatabase(t)
   165  		defer dbMock.AssertExpectations(t)
   166  
   167  		escapedInsertQuery := regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )")
   168  		dbMock.ExpectExec(escapedInsertQuery).WithArgs(appTemplateLabelEntity.ID, appTemplateLabelEntity.TenantID, appTemplateLabelEntity.AppID, appTemplateLabelEntity.RuntimeID, appTemplateLabelEntity.RuntimeContextID, appTemplateLabelEntity.AppTemplateID, appTemplateLabelEntity.Key, appTemplateLabelEntity.Value, appTemplateLabelEntity.Version).WillReturnResult(sqlmock.NewResult(1, 1))
   169  
   170  		ctx := context.TODO()
   171  		ctx = persistence.SaveToContext(ctx, db)
   172  		// WHEN
   173  		err := labelRepo.Create(ctx, tenantID, appTemplateLabelModel)
   174  		// THEN
   175  		require.NoError(t, err)
   176  	})
   177  }
   178  
   179  func TestRepository_CreateGlobal(t *testing.T) {
   180  	var nilLabelModel *model.Label
   181  	appLabelModel := fixModelLabel(model.ApplicationLabelableObject)
   182  	appLabelEntity := fixEntityLabel(model.ApplicationLabelableObject)
   183  
   184  	appLabelSuite := testdb.RepoCreateTestSuite{
   185  		Name: "Create Application Label with global creator",
   186  		SQLQueryDetails: []testdb.SQLQueryDetails{
   187  			{
   188  				Query:       regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )"),
   189  				Args:        []driver.Value{appLabelEntity.ID, appLabelEntity.TenantID, appLabelEntity.AppID, appLabelEntity.RuntimeID, appLabelEntity.RuntimeContextID, appLabelEntity.AppTemplateID, appLabelEntity.Key, appLabelEntity.Value, appLabelEntity.Version},
   190  				ValidResult: sqlmock.NewResult(-1, 1),
   191  			},
   192  		},
   193  		ConverterMockProvider: func() testdb.Mock {
   194  			return &automock.Converter{}
   195  		},
   196  		RepoConstructorFunc: label.NewRepository,
   197  		ModelEntity:         appLabelModel,
   198  		DBEntity:            appLabelEntity,
   199  		NilModelEntity:      nilLabelModel,
   200  		MethodName:          "CreateGlobal",
   201  		IsGlobal:            true,
   202  	}
   203  
   204  	appLabelSuite.Run(t)
   205  }
   206  
   207  func TestRepository_Upsert(t *testing.T) {
   208  	testErr := errors.New("Test error")
   209  
   210  	t.Run("Success update - Label for Runtime", func(t *testing.T) {
   211  		labelModel := fixModelLabel(model.RuntimeLabelableObject)
   212  		labelEntity := fixEntityLabel(model.TenantLabelableObject)
   213  
   214  		mockConverter := &automock.Converter{}
   215  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   216  		mockConverter.On("FromEntity", labelEntity).Return(labelModel, nil).Once()
   217  		defer mockConverter.AssertExpectations(t)
   218  
   219  		labelRepo := label.NewRepository(mockConverter)
   220  
   221  		db, dbMock := testdb.MockDatabase(t)
   222  		defer dbMock.AssertExpectations(t)
   223  
   224  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_id = $2 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $3))`)
   225  		escapedUpdateQuery := regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ? AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = ? AND owner = true))`)
   226  		escapedExsistsQuery := regexp.QuoteMeta("SELECT 1 FROM public.labels WHERE id = $1 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $2 AND owner = true))")
   227  
   228  		mockedRows := sqlmock.NewRows(fixColumns).AddRow(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version)
   229  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID, tenantID).WillReturnRows(mockedRows)
   230  		dbMock.ExpectQuery(escapedExsistsQuery).WithArgs(labelID, tenantID).WillReturnRows(testdb.RowWhenObjectExist())
   231  		dbMock.ExpectExec(escapedUpdateQuery).WithArgs(labelEntity.Value, labelEntity.ID, tenantID).WillReturnResult(sqlmock.NewResult(-1, 1))
   232  
   233  		ctx := context.TODO()
   234  		ctx = persistence.SaveToContext(ctx, db)
   235  		// WHEN
   236  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   237  		// THEN
   238  		require.NoError(t, err)
   239  	})
   240  
   241  	t.Run("Success update - Label for Runtime Context", func(t *testing.T) {
   242  		// GIVEN
   243  		labelModel := fixModelLabel(model.RuntimeContextLabelableObject)
   244  		labelEntity := fixEntityLabel(model.RuntimeContextLabelableObject)
   245  
   246  		mockConverter := &automock.Converter{}
   247  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   248  		mockConverter.On("FromEntity", labelEntity).Return(labelModel, nil).Once()
   249  		defer mockConverter.AssertExpectations(t)
   250  
   251  		labelRepo := label.NewRepository(mockConverter)
   252  
   253  		db, dbMock := testdb.MockDatabase(t)
   254  		defer dbMock.AssertExpectations(t)
   255  
   256  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_context_id = $2 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $3))`)
   257  		escapedUpdateQuery := regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ? AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = ? AND owner = true))`)
   258  		escapedExsistsQuery := regexp.QuoteMeta("SELECT 1 FROM public.labels WHERE id = $1 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $2 AND owner = true))")
   259  
   260  		mockedRows := sqlmock.NewRows(fixColumns).AddRow(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version)
   261  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID, tenantID).WillReturnRows(mockedRows)
   262  		dbMock.ExpectQuery(escapedExsistsQuery).WithArgs(labelID, tenantID).WillReturnRows(testdb.RowWhenObjectExist())
   263  		dbMock.ExpectExec(escapedUpdateQuery).WithArgs(labelEntity.Value, labelEntity.ID, tenantID).WillReturnResult(sqlmock.NewResult(-1, 1))
   264  
   265  		ctx := context.TODO()
   266  		ctx = persistence.SaveToContext(ctx, db)
   267  		// WHEN
   268  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   269  		// THEN
   270  		require.NoError(t, err)
   271  	})
   272  
   273  	t.Run("Success update - Label for Application", func(t *testing.T) {
   274  		labelModel := fixModelLabel(model.ApplicationLabelableObject)
   275  		labelEntity := fixEntityLabel(model.ApplicationLabelableObject)
   276  
   277  		mockConverter := &automock.Converter{}
   278  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   279  		mockConverter.On("FromEntity", labelEntity).Return(labelModel, nil).Once()
   280  		defer mockConverter.AssertExpectations(t)
   281  
   282  		labelRepo := label.NewRepository(mockConverter)
   283  
   284  		db, dbMock := testdb.MockDatabase(t)
   285  		defer dbMock.AssertExpectations(t)
   286  
   287  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id = $2 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3))`)
   288  		escapedUpdateQuery := regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ? AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = ? AND owner = true))`)
   289  		escapedExsistsQuery := regexp.QuoteMeta("SELECT 1 FROM public.labels WHERE id = $1 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $2 AND owner = true))")
   290  
   291  		mockedRows := sqlmock.NewRows(fixColumns).AddRow(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version)
   292  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID, tenantID).WillReturnRows(mockedRows)
   293  		dbMock.ExpectQuery(escapedExsistsQuery).WithArgs(labelID, tenantID).WillReturnRows(testdb.RowWhenObjectExist())
   294  		dbMock.ExpectExec(escapedUpdateQuery).WithArgs(labelEntity.Value, labelEntity.ID, tenantID).WillReturnResult(sqlmock.NewResult(-1, 1))
   295  
   296  		ctx := context.TODO()
   297  		ctx = persistence.SaveToContext(ctx, db)
   298  		// WHEN
   299  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   300  		// THEN
   301  		require.NoError(t, err)
   302  	})
   303  
   304  	t.Run("Success update - Label for Tenant", func(t *testing.T) {
   305  		labelModel := fixModelLabel(model.TenantLabelableObject)
   306  		labelEntity := fixEntityLabel(model.TenantLabelableObject)
   307  
   308  		mockConverter := &automock.Converter{}
   309  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   310  		mockConverter.On("FromEntity", labelEntity).Return(labelModel, nil).Once()
   311  		defer mockConverter.AssertExpectations(t)
   312  
   313  		labelRepo := label.NewRepository(mockConverter)
   314  
   315  		db, dbMock := testdb.MockDatabase(t)
   316  		defer dbMock.AssertExpectations(t)
   317  
   318  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE tenant_id = $1 AND key = $2`)
   319  		escapedUpdateQuery := regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ? AND tenant_id = ?`)
   320  
   321  		mockedRows := sqlmock.NewRows(fixColumns).AddRow(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version)
   322  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(tenantID, key).WillReturnRows(mockedRows)
   323  		dbMock.ExpectExec(escapedUpdateQuery).WithArgs(labelEntity.Value, labelEntity.ID, labelEntity.TenantID).WillReturnResult(sqlmock.NewResult(-1, 1))
   324  
   325  		ctx := context.TODO()
   326  		ctx = persistence.SaveToContext(ctx, db)
   327  		// WHEN
   328  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   329  		// THEN
   330  		require.NoError(t, err)
   331  	})
   332  
   333  	t.Run("Success update - Label for Application Template", func(t *testing.T) {
   334  		appTemplateLabelModel := fixModelLabel(model.AppTemplateLabelableObject)
   335  		appTemplateLabelEntity := fixEntityLabel(model.AppTemplateLabelableObject)
   336  
   337  		mockConverter := &automock.Converter{}
   338  		mockConverter.On("ToEntity", appTemplateLabelModel).Return(appTemplateLabelEntity, nil).Once()
   339  		mockConverter.On("FromEntity", appTemplateLabelEntity).Return(appTemplateLabelModel, nil).Once()
   340  		defer mockConverter.AssertExpectations(t)
   341  
   342  		labelRepo := label.NewRepository(mockConverter)
   343  
   344  		db, dbMock := testdb.MockDatabase(t)
   345  		defer dbMock.AssertExpectations(t)
   346  
   347  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_template_id = $2`)
   348  		escapedUpdateQuery := regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ?`)
   349  
   350  		mockedRows := sqlmock.NewRows(fixColumns).AddRow(appTemplateLabelEntity.ID, appTemplateLabelEntity.TenantID, appTemplateLabelEntity.AppID, appTemplateLabelEntity.RuntimeID, appTemplateLabelEntity.RuntimeContextID, appTemplateLabelEntity.AppTemplateID, appTemplateLabelEntity.Key, appTemplateLabelEntity.Value, appTemplateLabelEntity.Version)
   351  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID).WillReturnRows(mockedRows)
   352  		dbMock.ExpectExec(escapedUpdateQuery).WithArgs(appTemplateLabelEntity.Value, appTemplateLabelEntity.ID).WillReturnResult(sqlmock.NewResult(-1, 1))
   353  
   354  		ctx := context.TODO()
   355  		ctx = persistence.SaveToContext(ctx, db)
   356  		// WHEN
   357  		err := labelRepo.Upsert(ctx, tenantID, appTemplateLabelModel)
   358  		// THEN
   359  		require.NoError(t, err)
   360  	})
   361  
   362  	t.Run("Success create - Label for Runtime", func(t *testing.T) {
   363  		labelModel := fixModelLabel(model.RuntimeLabelableObject)
   364  		labelEntity := fixEntityLabel(model.RuntimeLabelableObject)
   365  
   366  		mockConverter := &automock.Converter{}
   367  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   368  		defer mockConverter.AssertExpectations(t)
   369  
   370  		labelRepo := label.NewRepository(mockConverter)
   371  
   372  		db, dbMock := testdb.MockDatabase(t)
   373  		defer dbMock.AssertExpectations(t)
   374  
   375  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_id = $2 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $3))`)
   376  		escapedCheckParentAccessQuery := regexp.QuoteMeta("SELECT 1 FROM tenant_runtimes WHERE tenant_id = $1 AND id = $2 AND owner = $3")
   377  		escapedInsertQuery := regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )")
   378  
   379  		mockedRows := sqlmock.NewRows(fixColumns)
   380  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID, tenantID).WillReturnRows(mockedRows)
   381  		dbMock.ExpectQuery(escapedCheckParentAccessQuery).WithArgs(tenantID, refID, true).WillReturnRows(testdb.RowWhenObjectExist())
   382  		dbMock.ExpectExec(escapedInsertQuery).WithArgs(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version).WillReturnResult(sqlmock.NewResult(1, 1))
   383  
   384  		ctx := context.TODO()
   385  		ctx = persistence.SaveToContext(ctx, db)
   386  		// WHEN
   387  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   388  		// THEN
   389  		require.NoError(t, err)
   390  	})
   391  
   392  	t.Run("Success create - Label for Runtime Context", func(t *testing.T) {
   393  		labelModel := fixModelLabel(model.RuntimeContextLabelableObject)
   394  		labelEntity := fixEntityLabel(model.RuntimeContextLabelableObject)
   395  
   396  		mockConverter := &automock.Converter{}
   397  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   398  		defer mockConverter.AssertExpectations(t)
   399  
   400  		labelRepo := label.NewRepository(mockConverter)
   401  
   402  		db, dbMock := testdb.MockDatabase(t)
   403  		defer dbMock.AssertExpectations(t)
   404  
   405  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_context_id = $2 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $3))`)
   406  		escapedCheckParentAccessQuery := regexp.QuoteMeta("SELECT 1 FROM tenant_runtime_contexts WHERE tenant_id = $1 AND id = $2 AND owner = $3")
   407  		escapedInsertQuery := regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )")
   408  
   409  		mockedRows := sqlmock.NewRows(fixColumns)
   410  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID, tenantID).WillReturnRows(mockedRows)
   411  		dbMock.ExpectQuery(escapedCheckParentAccessQuery).WithArgs(tenantID, refID, true).WillReturnRows(testdb.RowWhenObjectExist())
   412  		dbMock.ExpectExec(escapedInsertQuery).WithArgs(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version).WillReturnResult(sqlmock.NewResult(1, 1))
   413  
   414  		ctx := context.TODO()
   415  		ctx = persistence.SaveToContext(ctx, db)
   416  		// WHEN
   417  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   418  		// THEN
   419  		require.NoError(t, err)
   420  	})
   421  
   422  	t.Run("Success create - Label for Application", func(t *testing.T) {
   423  		labelModel := fixModelLabel(model.ApplicationLabelableObject)
   424  		labelEntity := fixEntityLabel(model.ApplicationLabelableObject)
   425  
   426  		mockConverter := &automock.Converter{}
   427  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   428  		defer mockConverter.AssertExpectations(t)
   429  
   430  		labelRepo := label.NewRepository(mockConverter)
   431  
   432  		db, dbMock := testdb.MockDatabase(t)
   433  		defer dbMock.AssertExpectations(t)
   434  
   435  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id = $2 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3))`)
   436  		escapedCheckParentAccessQuery := regexp.QuoteMeta("SELECT 1 FROM tenant_applications WHERE tenant_id = $1 AND id = $2 AND owner = $3")
   437  		escapedInsertQuery := regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )")
   438  
   439  		mockedRows := sqlmock.NewRows(fixColumns)
   440  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID, tenantID).WillReturnRows(mockedRows)
   441  		dbMock.ExpectQuery(escapedCheckParentAccessQuery).WithArgs(tenantID, refID, true).WillReturnRows(testdb.RowWhenObjectExist())
   442  		dbMock.ExpectExec(escapedInsertQuery).WithArgs(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version).WillReturnResult(sqlmock.NewResult(1, 1))
   443  
   444  		ctx := context.TODO()
   445  		ctx = persistence.SaveToContext(ctx, db)
   446  		// WHEN
   447  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   448  		// THEN
   449  		require.NoError(t, err)
   450  	})
   451  
   452  	t.Run("Success create - Label for Tenant", func(t *testing.T) {
   453  		labelModel := fixModelLabel(model.TenantLabelableObject)
   454  		labelEntity := fixEntityLabel(model.TenantLabelableObject)
   455  
   456  		mockConverter := &automock.Converter{}
   457  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   458  		defer mockConverter.AssertExpectations(t)
   459  
   460  		labelRepo := label.NewRepository(mockConverter)
   461  
   462  		db, dbMock := testdb.MockDatabase(t)
   463  		defer dbMock.AssertExpectations(t)
   464  
   465  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE tenant_id = $1 AND key = $2`)
   466  		escapedInsertQuery := regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )")
   467  
   468  		mockedRows := sqlmock.NewRows(fixColumns)
   469  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(tenantID, key).WillReturnRows(mockedRows)
   470  		dbMock.ExpectExec(escapedInsertQuery).WithArgs(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version).WillReturnResult(sqlmock.NewResult(1, 1))
   471  
   472  		ctx := context.TODO()
   473  		ctx = persistence.SaveToContext(ctx, db)
   474  		// WHEN
   475  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   476  		// THEN
   477  		require.NoError(t, err)
   478  	})
   479  
   480  	t.Run("Success create - Label for Tenant", func(t *testing.T) {
   481  		labelModel := fixModelLabel(model.AppTemplateLabelableObject)
   482  		labelEntity := fixEntityLabel(model.AppTemplateLabelableObject)
   483  
   484  		mockConverter := &automock.Converter{}
   485  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   486  		defer mockConverter.AssertExpectations(t)
   487  
   488  		labelRepo := label.NewRepository(mockConverter)
   489  
   490  		db, dbMock := testdb.MockDatabase(t)
   491  		defer dbMock.AssertExpectations(t)
   492  
   493  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_template_id = $2`)
   494  		escapedInsertQuery := regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )")
   495  
   496  		mockedRows := sqlmock.NewRows(fixColumns)
   497  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID).WillReturnRows(mockedRows)
   498  		dbMock.ExpectExec(escapedInsertQuery).WithArgs(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version).WillReturnResult(sqlmock.NewResult(1, 1))
   499  
   500  		ctx := context.TODO()
   501  		ctx = persistence.SaveToContext(ctx, db)
   502  		// WHEN
   503  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   504  		// THEN
   505  		require.NoError(t, err)
   506  	})
   507  
   508  	t.Run("Error - GetByKey", func(t *testing.T) {
   509  		labelModel := fixModelLabel(model.RuntimeLabelableObject)
   510  
   511  		labelRepo := label.NewRepository(&automock.Converter{})
   512  
   513  		db, dbMock := testdb.MockDatabase(t)
   514  		defer dbMock.AssertExpectations(t)
   515  
   516  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_id = $2 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $3))`)
   517  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID, tenantID).WillReturnError(testErr)
   518  
   519  		ctx := context.TODO()
   520  		ctx = persistence.SaveToContext(ctx, db)
   521  		// WHEN
   522  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   523  		// THEN
   524  		require.Error(t, err)
   525  		assert.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   526  	})
   527  
   528  	t.Run("Error - Create", func(t *testing.T) {
   529  		labelModel := fixModelLabel(model.RuntimeLabelableObject)
   530  		labelEntity := fixEntityLabel(model.RuntimeLabelableObject)
   531  
   532  		mockConverter := &automock.Converter{}
   533  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   534  		defer mockConverter.AssertExpectations(t)
   535  
   536  		labelRepo := label.NewRepository(mockConverter)
   537  
   538  		db, dbMock := testdb.MockDatabase(t)
   539  		defer dbMock.AssertExpectations(t)
   540  
   541  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_id = $2 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $3))`)
   542  		escapedCheckParentAccessQuery := regexp.QuoteMeta("SELECT 1 FROM tenant_runtimes WHERE tenant_id = $1 AND id = $2 AND owner = $3")
   543  		escapedInsertQuery := regexp.QuoteMeta("INSERT INTO public.labels ( id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )")
   544  
   545  		mockedRows := sqlmock.NewRows(fixColumns)
   546  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID, tenantID).WillReturnRows(mockedRows)
   547  		dbMock.ExpectQuery(escapedCheckParentAccessQuery).WithArgs(tenantID, refID, true).WillReturnRows(testdb.RowWhenObjectExist())
   548  		dbMock.ExpectExec(escapedInsertQuery).WithArgs(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version).WillReturnError(testErr)
   549  
   550  		ctx := context.TODO()
   551  		ctx = persistence.SaveToContext(ctx, db)
   552  		// WHEN
   553  		err := labelRepo.Upsert(ctx, tenantID, labelModel)
   554  		// THEN
   555  		require.Error(t, err)
   556  		assert.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   557  	})
   558  }
   559  
   560  func TestRepository_UpsertGlobal(t *testing.T) {
   561  	testErr := errors.New("Test error")
   562  
   563  	t.Run("Success update of label for Application", func(t *testing.T) {
   564  		labelModel := fixModelLabel(model.ApplicationLabelableObject)
   565  		labelEntity := fixEntityLabel(model.ApplicationLabelableObject)
   566  
   567  		mockConverter := &automock.Converter{}
   568  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   569  		mockConverter.On("FromEntity", labelEntity).Return(labelModel, nil).Once()
   570  		defer mockConverter.AssertExpectations(t)
   571  
   572  		labelRepo := label.NewRepository(mockConverter)
   573  
   574  		db, dbMock := testdb.MockDatabase(t)
   575  		defer dbMock.AssertExpectations(t)
   576  
   577  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id = $2`)
   578  		escapedUpdateQuery := regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ?`)
   579  
   580  		mockedRows := sqlmock.NewRows(fixColumns).AddRow(labelEntity.ID, labelEntity.TenantID, labelEntity.AppID, labelEntity.RuntimeID, labelEntity.RuntimeContextID, labelEntity.AppTemplateID, labelEntity.Key, labelEntity.Value, labelEntity.Version)
   581  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID).WillReturnRows(mockedRows)
   582  		dbMock.ExpectExec(escapedUpdateQuery).WithArgs(labelEntity.Value, labelEntity.ID).WillReturnResult(sqlmock.NewResult(-1, 1))
   583  
   584  		ctx := context.TODO()
   585  		ctx = persistence.SaveToContext(ctx, db)
   586  		// WHEN
   587  		err := labelRepo.UpsertGlobal(ctx, labelModel)
   588  		// THEN
   589  		require.NoError(t, err)
   590  	})
   591  
   592  	t.Run("Error in GetByKeyGlobal", func(t *testing.T) {
   593  		labelModel := fixModelLabel(model.ApplicationLabelableObject)
   594  
   595  		labelRepo := label.NewRepository(&automock.Converter{})
   596  
   597  		db, dbMock := testdb.MockDatabase(t)
   598  		defer dbMock.AssertExpectations(t)
   599  
   600  		escapedGetQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id = $2`)
   601  		dbMock.ExpectQuery(escapedGetQuery).WithArgs(key, refID).WillReturnError(testErr)
   602  
   603  		ctx := context.TODO()
   604  		ctx = persistence.SaveToContext(ctx, db)
   605  		// WHEN
   606  		err := labelRepo.UpsertGlobal(ctx, labelModel)
   607  		// THEN
   608  		require.Error(t, err)
   609  		assert.EqualError(t, err, "Internal Server Error: Unexpected error while executing SQL query")
   610  	})
   611  
   612  	t.Run("Error when empty label is passed", func(t *testing.T) {
   613  		var labelModel *model.Label
   614  		labelRepo := label.NewRepository(&automock.Converter{})
   615  
   616  		db, dbMock := testdb.MockDatabase(t)
   617  		defer dbMock.AssertExpectations(t)
   618  
   619  		ctx := context.TODO()
   620  		ctx = persistence.SaveToContext(ctx, db)
   621  		// WHEN
   622  		err := labelRepo.UpsertGlobal(ctx, labelModel)
   623  		// THEN
   624  		require.Error(t, err)
   625  		assert.EqualError(t, err, "Internal Server Error: item can not be empty")
   626  	})
   627  }
   628  
   629  func TestRepository_UpdateWithVersion(t *testing.T) {
   630  	version := 42
   631  
   632  	var nilLabelModel *model.Label
   633  	applabelModel := fixModelLabel(model.ApplicationLabelableObject)
   634  	appLabelEntity := fixEntityLabel(model.ApplicationLabelableObject)
   635  	runtimelabelModel := fixModelLabel(model.RuntimeLabelableObject)
   636  	runtimeLabelEntity := fixEntityLabel(model.RuntimeLabelableObject)
   637  	runtimeCtxlabelModel := fixModelLabel(model.RuntimeContextLabelableObject)
   638  	runtimeCtxLabelEntity := fixEntityLabel(model.RuntimeContextLabelableObject)
   639  
   640  	appLabelSuite := testdb.RepoUpdateTestSuite{
   641  		Name: "Update Application Label",
   642  		SQLQueryDetails: []testdb.SQLQueryDetails{
   643  			{
   644  				Query:    regexp.QuoteMeta("SELECT 1 FROM public.labels WHERE id = $1 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $2 AND owner = true))"),
   645  				Args:     []driver.Value{labelID, tenantID},
   646  				IsSelect: true,
   647  				ValidRowsProvider: func() []*sqlmock.Rows {
   648  					return []*sqlmock.Rows{testdb.RowWhenObjectExist()}
   649  				},
   650  				InvalidRowsProvider: func() []*sqlmock.Rows {
   651  					return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()}
   652  				},
   653  			},
   654  			{
   655  				Query:         regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ? AND version = ? AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = ? AND owner = true))`),
   656  				Args:          []driver.Value{appLabelEntity.Value, appLabelEntity.ID, version, tenantID},
   657  				ValidResult:   sqlmock.NewResult(-1, 1),
   658  				InvalidResult: sqlmock.NewResult(-1, 0),
   659  			},
   660  		},
   661  		ConverterMockProvider: func() testdb.Mock {
   662  			return &automock.Converter{}
   663  		},
   664  		RepoConstructorFunc: label.NewRepository,
   665  		ModelEntity:         applabelModel,
   666  		DBEntity:            appLabelEntity,
   667  		NilModelEntity:      nilLabelModel,
   668  		TenantID:            tenantID,
   669  		UpdateMethodName:    "UpdateWithVersion",
   670  	}
   671  
   672  	runtimeLabelSuite := testdb.RepoUpdateTestSuite{
   673  		Name: "Update Runtime Label",
   674  		SQLQueryDetails: []testdb.SQLQueryDetails{
   675  			{
   676  				Query:    regexp.QuoteMeta("SELECT 1 FROM public.labels WHERE id = $1 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $2 AND owner = true))"),
   677  				Args:     []driver.Value{labelID, tenantID},
   678  				IsSelect: true,
   679  				ValidRowsProvider: func() []*sqlmock.Rows {
   680  					return []*sqlmock.Rows{testdb.RowWhenObjectExist()}
   681  				},
   682  				InvalidRowsProvider: func() []*sqlmock.Rows {
   683  					return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()}
   684  				},
   685  			},
   686  			{
   687  				Query:         regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ? AND version = ? AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = ? AND owner = true))`),
   688  				Args:          []driver.Value{runtimeLabelEntity.Value, runtimeLabelEntity.ID, version, tenantID},
   689  				ValidResult:   sqlmock.NewResult(-1, 1),
   690  				InvalidResult: sqlmock.NewResult(-1, 0),
   691  			},
   692  		},
   693  		ConverterMockProvider: func() testdb.Mock {
   694  			return &automock.Converter{}
   695  		},
   696  		RepoConstructorFunc: label.NewRepository,
   697  		ModelEntity:         runtimelabelModel,
   698  		DBEntity:            runtimeLabelEntity,
   699  		NilModelEntity:      nilLabelModel,
   700  		TenantID:            tenantID,
   701  		UpdateMethodName:    "UpdateWithVersion",
   702  	}
   703  
   704  	runtimeCtxLabelSuite := testdb.RepoUpdateTestSuite{
   705  		Name: "Update RuntimeCtx Label",
   706  		SQLQueryDetails: []testdb.SQLQueryDetails{
   707  			{
   708  				Query:    regexp.QuoteMeta("SELECT 1 FROM public.labels WHERE id = $1 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $2 AND owner = true))"),
   709  				Args:     []driver.Value{labelID, tenantID},
   710  				IsSelect: true,
   711  				ValidRowsProvider: func() []*sqlmock.Rows {
   712  					return []*sqlmock.Rows{testdb.RowWhenObjectExist()}
   713  				},
   714  				InvalidRowsProvider: func() []*sqlmock.Rows {
   715  					return []*sqlmock.Rows{testdb.RowWhenObjectDoesNotExist()}
   716  				},
   717  			},
   718  			{
   719  				Query:         regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ? AND version = ? AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = ? AND owner = true))`),
   720  				Args:          []driver.Value{runtimeCtxLabelEntity.Value, runtimeCtxLabelEntity.ID, version, tenantID},
   721  				ValidResult:   sqlmock.NewResult(-1, 1),
   722  				InvalidResult: sqlmock.NewResult(-1, 0),
   723  			},
   724  		},
   725  		ConverterMockProvider: func() testdb.Mock {
   726  			return &automock.Converter{}
   727  		},
   728  		RepoConstructorFunc: label.NewRepository,
   729  		ModelEntity:         runtimeCtxlabelModel,
   730  		DBEntity:            runtimeCtxLabelEntity,
   731  		NilModelEntity:      nilLabelModel,
   732  		TenantID:            tenantID,
   733  		UpdateMethodName:    "UpdateWithVersion",
   734  	}
   735  
   736  	appLabelSuite.Run(t)
   737  	runtimeLabelSuite.Run(t)
   738  	runtimeCtxLabelSuite.Run(t)
   739  
   740  	// Additional tests - tenant labels are updated globally as the tenant is embedded in the entity.
   741  	t.Run("Success update - Label for Tenant", func(t *testing.T) {
   742  		// GIVEN
   743  		labelModel := fixModelLabel(model.TenantLabelableObject)
   744  		labelEntity := fixEntityLabel(model.TenantLabelableObject)
   745  
   746  		mockConverter := &automock.Converter{}
   747  		mockConverter.On("ToEntity", labelModel).Return(labelEntity, nil).Once()
   748  		defer mockConverter.AssertExpectations(t)
   749  
   750  		labelRepo := label.NewRepository(mockConverter)
   751  
   752  		db, dbMock := testdb.MockDatabase(t)
   753  		defer dbMock.AssertExpectations(t)
   754  
   755  		escapedUpdateQuery := regexp.QuoteMeta(`UPDATE public.labels SET value = ?, version = version+1 WHERE id = ? AND version = ? AND tenant_id = ?`)
   756  		dbMock.ExpectExec(escapedUpdateQuery).WithArgs(labelEntity.Value, labelEntity.ID, version, labelEntity.TenantID).WillReturnResult(sqlmock.NewResult(1, 1))
   757  
   758  		ctx := context.TODO()
   759  		ctx = persistence.SaveToContext(ctx, db)
   760  		// WHEN
   761  		err := labelRepo.UpdateWithVersion(ctx, tenantID, labelModel)
   762  		// THEN
   763  		require.NoError(t, err)
   764  	})
   765  }
   766  
   767  func TestRepository_GetByKey(t *testing.T) {
   768  	applabelModel := fixModelLabel(model.ApplicationLabelableObject)
   769  	appLabelEntity := fixEntityLabel(model.ApplicationLabelableObject)
   770  	runtimelabelModel := fixModelLabel(model.RuntimeLabelableObject)
   771  	runtimeLabelEntity := fixEntityLabel(model.RuntimeLabelableObject)
   772  	runtimeCtxlabelModel := fixModelLabel(model.RuntimeContextLabelableObject)
   773  	runtimeCtxLabelEntity := fixEntityLabel(model.RuntimeContextLabelableObject)
   774  
   775  	appLabelSuite := testdb.RepoGetTestSuite{
   776  		Name: "Get Application Label",
   777  		SQLQueryDetails: []testdb.SQLQueryDetails{
   778  			{
   779  				Query:    regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id = $2 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3))`),
   780  				Args:     []driver.Value{key, refID, tenantID},
   781  				IsSelect: true,
   782  				ValidRowsProvider: func() []*sqlmock.Rows {
   783  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).
   784  						AddRow(appLabelEntity.ID, appLabelEntity.TenantID, appLabelEntity.AppID, appLabelEntity.RuntimeID, appLabelEntity.RuntimeContextID, appLabelEntity.AppTemplateID, appLabelEntity.Key, appLabelEntity.Value, appLabelEntity.Version)}
   785  				},
   786  				InvalidRowsProvider: func() []*sqlmock.Rows {
   787  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)}
   788  				},
   789  			},
   790  		},
   791  		ConverterMockProvider: func() testdb.Mock {
   792  			return &automock.Converter{}
   793  		},
   794  		RepoConstructorFunc: label.NewRepository,
   795  		ExpectedModelEntity: applabelModel,
   796  		ExpectedDBEntity:    appLabelEntity,
   797  		MethodArgs:          []interface{}{tenantID, model.ApplicationLabelableObject, refID, key},
   798  		MethodName:          "GetByKey",
   799  	}
   800  
   801  	rtLabelSuite := testdb.RepoGetTestSuite{
   802  		Name: "Get Runtime Label",
   803  		SQLQueryDetails: []testdb.SQLQueryDetails{
   804  			{
   805  				Query:    regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_id = $2 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $3))`),
   806  				Args:     []driver.Value{key, refID, tenantID},
   807  				IsSelect: true,
   808  				ValidRowsProvider: func() []*sqlmock.Rows {
   809  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).
   810  						AddRow(runtimeLabelEntity.ID, runtimeLabelEntity.TenantID, runtimeLabelEntity.AppID, runtimeLabelEntity.RuntimeID, runtimeLabelEntity.RuntimeContextID, runtimeCtxLabelEntity.AppTemplateID, runtimeLabelEntity.Key, runtimeLabelEntity.Value, runtimeLabelEntity.Version)}
   811  				},
   812  				InvalidRowsProvider: func() []*sqlmock.Rows {
   813  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)}
   814  				},
   815  			},
   816  		},
   817  		ConverterMockProvider: func() testdb.Mock {
   818  			return &automock.Converter{}
   819  		},
   820  		RepoConstructorFunc: label.NewRepository,
   821  		ExpectedModelEntity: runtimelabelModel,
   822  		ExpectedDBEntity:    runtimeLabelEntity,
   823  		MethodArgs:          []interface{}{tenantID, model.RuntimeLabelableObject, refID, key},
   824  		MethodName:          "GetByKey",
   825  	}
   826  
   827  	rtCtxLabelSuite := testdb.RepoGetTestSuite{
   828  		Name: "Get Runtime Context Label",
   829  		SQLQueryDetails: []testdb.SQLQueryDetails{
   830  			{
   831  				Query:    regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_context_id = $2 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $3))`),
   832  				Args:     []driver.Value{key, refID, tenantID},
   833  				IsSelect: true,
   834  				ValidRowsProvider: func() []*sqlmock.Rows {
   835  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).
   836  						AddRow(runtimeCtxLabelEntity.ID, runtimeCtxLabelEntity.TenantID, runtimeCtxLabelEntity.AppID, runtimeCtxLabelEntity.RuntimeID, runtimeCtxLabelEntity.RuntimeContextID, runtimeCtxLabelEntity.AppTemplateID, runtimeCtxLabelEntity.Key, runtimeCtxLabelEntity.Value, runtimeCtxLabelEntity.Version)}
   837  				},
   838  				InvalidRowsProvider: func() []*sqlmock.Rows {
   839  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)}
   840  				},
   841  			},
   842  		},
   843  		ConverterMockProvider: func() testdb.Mock {
   844  			return &automock.Converter{}
   845  		},
   846  		RepoConstructorFunc: label.NewRepository,
   847  		ExpectedModelEntity: runtimeCtxlabelModel,
   848  		ExpectedDBEntity:    runtimeCtxLabelEntity,
   849  		MethodArgs:          []interface{}{tenantID, model.RuntimeContextLabelableObject, refID, key},
   850  		MethodName:          "GetByKey",
   851  	}
   852  
   853  	appLabelSuite.Run(t)
   854  	rtLabelSuite.Run(t)
   855  	rtCtxLabelSuite.Run(t)
   856  
   857  	t.Run("Success - Label for Tenant", func(t *testing.T) {
   858  		tenantLabelModel := fixModelLabel(model.TenantLabelableObject)
   859  		tenantLabelEntity := fixEntityLabel(model.TenantLabelableObject)
   860  
   861  		mockConverter := &automock.Converter{}
   862  		defer mockConverter.AssertExpectations(t)
   863  		mockConverter.On("FromEntity", tenantLabelEntity).Return(tenantLabelModel, nil).Once()
   864  
   865  		labelRepo := label.NewRepository(mockConverter)
   866  
   867  		db, dbMock := testdb.MockDatabase(t)
   868  		defer dbMock.AssertExpectations(t)
   869  
   870  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE tenant_id = $1 AND key = $2`)
   871  		mockedRows := sqlmock.NewRows(fixColumns).AddRow(tenantLabelEntity.ID, tenantLabelEntity.TenantID, tenantLabelEntity.AppID, tenantLabelEntity.RuntimeID, tenantLabelEntity.RuntimeContextID, tenantLabelEntity.AppTemplateID, tenantLabelEntity.Key, tenantLabelEntity.Value, tenantLabelEntity.Version)
   872  		dbMock.ExpectQuery(escapedQuery).WithArgs(tenantID, key).WillReturnRows(mockedRows)
   873  
   874  		ctx := context.TODO()
   875  		ctx = persistence.SaveToContext(ctx, db)
   876  		// WHEN
   877  		actual, err := labelRepo.GetByKey(ctx, tenantID, model.TenantLabelableObject, tenantID, key)
   878  		// THEN
   879  		require.NoError(t, err)
   880  		require.Equal(t, tenantLabelModel, actual)
   881  		require.Equal(t, value, actual.Value)
   882  	})
   883  
   884  	t.Run("Success - Label for Application Template", func(t *testing.T) {
   885  		appTemplatelabelModel := fixModelLabel(model.AppTemplateLabelableObject)
   886  		appTemplateLabelEntity := fixEntityLabel(model.AppTemplateLabelableObject)
   887  
   888  		mockConverter := &automock.Converter{}
   889  		defer mockConverter.AssertExpectations(t)
   890  		mockConverter.On("FromEntity", appTemplateLabelEntity).Return(appTemplatelabelModel, nil).Once()
   891  
   892  		labelRepo := label.NewRepository(mockConverter)
   893  
   894  		db, dbMock := testdb.MockDatabase(t)
   895  		defer dbMock.AssertExpectations(t)
   896  
   897  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE tenant_id = $1 AND key = $2`)
   898  		mockedRows := sqlmock.NewRows(fixColumns).AddRow(appTemplateLabelEntity.ID, appTemplateLabelEntity.TenantID, appTemplateLabelEntity.AppID, appTemplateLabelEntity.RuntimeID, appTemplateLabelEntity.RuntimeContextID, appTemplateLabelEntity.AppTemplateID, appTemplateLabelEntity.Key, appTemplateLabelEntity.Value, appTemplateLabelEntity.Version)
   899  		dbMock.ExpectQuery(escapedQuery).WithArgs(tenantID, key).WillReturnRows(mockedRows)
   900  
   901  		ctx := context.TODO()
   902  		ctx = persistence.SaveToContext(ctx, db)
   903  		// WHEN
   904  		actual, err := labelRepo.GetByKey(ctx, tenantID, model.TenantLabelableObject, tenantID, key)
   905  		// THEN
   906  		require.NoError(t, err)
   907  		require.Equal(t, appTemplatelabelModel, actual)
   908  		require.Equal(t, value, actual.Value)
   909  	})
   910  }
   911  
   912  func TestRepository_GetByKeyGlobal(t *testing.T) {
   913  	appLabelModel := fixModelLabel(model.ApplicationLabelableObject)
   914  	appLabelEntity := fixEntityLabel(model.ApplicationLabelableObject)
   915  
   916  	appLabelSuite := testdb.RepoGetTestSuite{
   917  		Name: "Get Application Label with global getter",
   918  		SQLQueryDetails: []testdb.SQLQueryDetails{
   919  			{
   920  				Query:    regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id = $2`),
   921  				Args:     []driver.Value{key, refID},
   922  				IsSelect: true,
   923  				ValidRowsProvider: func() []*sqlmock.Rows {
   924  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).
   925  						AddRow(appLabelEntity.ID, appLabelEntity.TenantID, appLabelEntity.AppID, appLabelEntity.RuntimeID, appLabelEntity.RuntimeContextID, appLabelEntity.AppTemplateID, appLabelEntity.Key, appLabelEntity.Value, appLabelEntity.Version)}
   926  				},
   927  				InvalidRowsProvider: func() []*sqlmock.Rows {
   928  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)}
   929  				},
   930  			},
   931  		},
   932  		ConverterMockProvider: func() testdb.Mock {
   933  			return &automock.Converter{}
   934  		},
   935  		RepoConstructorFunc: label.NewRepository,
   936  		ExpectedModelEntity: appLabelModel,
   937  		ExpectedDBEntity:    appLabelEntity,
   938  		MethodArgs:          []interface{}{model.ApplicationLabelableObject, refID, key},
   939  		MethodName:          "GetByKeyGlobal",
   940  	}
   941  
   942  	appLabelSuite.Run(t)
   943  }
   944  
   945  func TestRepository_ListForObject(t *testing.T) {
   946  	t.Run("Success - Label for Runtime", func(t *testing.T) {
   947  		// GIVEN
   948  		label1Model := fixModelLabelWithID("1", "foo", model.RuntimeLabelableObject)
   949  		label2Model := fixModelLabelWithID("2", "bar", model.RuntimeLabelableObject)
   950  
   951  		label1Entity := fixEntityLabelWithID("1", "foo", model.RuntimeLabelableObject)
   952  		label2Entity := fixEntityLabelWithID("2", "bar", model.RuntimeLabelableObject)
   953  
   954  		inputItems := []*label.Entity{label1Entity, label2Entity}
   955  		expected := map[string]*model.Label{
   956  			"foo": label1Model,
   957  			"bar": label2Model,
   958  		}
   959  
   960  		mockConverter := &automock.Converter{}
   961  		defer mockConverter.AssertExpectations(t)
   962  		for _, entity := range inputItems {
   963  			mockConverter.On("FromEntity", entity).Return(expected[entity.Key], nil).Once()
   964  		}
   965  
   966  		labelRepo := label.NewRepository(mockConverter)
   967  
   968  		db, dbMock := testdb.MockDatabase(t)
   969  		defer dbMock.AssertExpectations(t)
   970  
   971  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE runtime_id = $1 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $2))`)
   972  		mockedRows := sqlmock.NewRows(fixColumns).
   973  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
   974  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
   975  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: refID}, tenantID).WillReturnRows(mockedRows)
   976  
   977  		ctx := context.TODO()
   978  		ctx = persistence.SaveToContext(ctx, db)
   979  		// WHEN
   980  		actual, err := labelRepo.ListForObject(ctx, tenantID, model.RuntimeLabelableObject, refID)
   981  		// THEN
   982  		require.NoError(t, err)
   983  		assert.Equal(t, expected, actual)
   984  	})
   985  
   986  	t.Run("Success - Label for Runtime Context", func(t *testing.T) {
   987  		// GIVEN
   988  		label1Model := fixModelLabelWithID("1", "foo", model.RuntimeContextLabelableObject)
   989  		label2Model := fixModelLabelWithID("2", "bar", model.RuntimeContextLabelableObject)
   990  
   991  		label1Entity := fixEntityLabelWithID("1", "foo", model.RuntimeContextLabelableObject)
   992  		label2Entity := fixEntityLabelWithID("2", "bar", model.RuntimeContextLabelableObject)
   993  
   994  		inputItems := []*label.Entity{label1Entity, label2Entity}
   995  		expected := map[string]*model.Label{
   996  			"foo": label1Model,
   997  			"bar": label2Model,
   998  		}
   999  
  1000  		mockConverter := &automock.Converter{}
  1001  		defer mockConverter.AssertExpectations(t)
  1002  		for _, entity := range inputItems {
  1003  			mockConverter.On("FromEntity", entity).Return(expected[entity.Key], nil).Once()
  1004  		}
  1005  
  1006  		labelRepo := label.NewRepository(mockConverter)
  1007  
  1008  		db, dbMock := testdb.MockDatabase(t)
  1009  		defer dbMock.AssertExpectations(t)
  1010  
  1011  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE runtime_context_id = $1 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $2))`)
  1012  		mockedRows := sqlmock.NewRows(fixColumns).
  1013  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1014  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  1015  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: refID}, tenantID).WillReturnRows(mockedRows)
  1016  
  1017  		ctx := context.TODO()
  1018  		ctx = persistence.SaveToContext(ctx, db)
  1019  		// WHEN
  1020  		actual, err := labelRepo.ListForObject(ctx, tenantID, model.RuntimeContextLabelableObject, refID)
  1021  		// THEN
  1022  		require.NoError(t, err)
  1023  		assert.Equal(t, expected, actual)
  1024  	})
  1025  
  1026  	t.Run("Success - Label for Application", func(t *testing.T) {
  1027  		// GIVEN
  1028  		label1Model := fixModelLabelWithID("1", "foo", model.ApplicationLabelableObject)
  1029  		label2Model := fixModelLabelWithID("2", "bar", model.ApplicationLabelableObject)
  1030  
  1031  		label1Entity := fixEntityLabelWithID("1", "foo", model.ApplicationLabelableObject)
  1032  		label2Entity := fixEntityLabelWithID("2", "bar", model.ApplicationLabelableObject)
  1033  
  1034  		inputItems := []*label.Entity{label1Entity, label2Entity}
  1035  		expected := map[string]*model.Label{
  1036  			"foo": label1Model,
  1037  			"bar": label2Model,
  1038  		}
  1039  
  1040  		mockConverter := &automock.Converter{}
  1041  		defer mockConverter.AssertExpectations(t)
  1042  		for _, entity := range inputItems {
  1043  			mockConverter.On("FromEntity", entity).Return(expected[entity.Key], nil).Once()
  1044  		}
  1045  
  1046  		labelRepo := label.NewRepository(mockConverter)
  1047  
  1048  		db, dbMock := testdb.MockDatabase(t)
  1049  		defer dbMock.AssertExpectations(t)
  1050  
  1051  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_id = $1 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $2))`)
  1052  		mockedRows := sqlmock.NewRows(fixColumns).
  1053  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1054  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label1Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  1055  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: refID}, tenantID).WillReturnRows(mockedRows)
  1056  
  1057  		ctx := context.TODO()
  1058  		ctx = persistence.SaveToContext(ctx, db)
  1059  
  1060  		// WHEN
  1061  		actual, err := labelRepo.ListForObject(ctx, tenantID, model.ApplicationLabelableObject, refID)
  1062  		// THEN
  1063  		require.NoError(t, err)
  1064  		assert.Equal(t, expected, actual)
  1065  	})
  1066  
  1067  	t.Run("Success - Label for Tenant", func(t *testing.T) {
  1068  		// GIVEN
  1069  		label1Model := fixModelLabelWithID("1", "foo", model.TenantLabelableObject)
  1070  		label2Model := fixModelLabelWithID("2", "bar", model.TenantLabelableObject)
  1071  
  1072  		label1Entity := fixEntityLabelWithID("1", "foo", model.TenantLabelableObject)
  1073  		label2Entity := fixEntityLabelWithID("2", "bar", model.TenantLabelableObject)
  1074  
  1075  		inputItems := []*label.Entity{label1Entity, label2Entity}
  1076  		expected := map[string]*model.Label{
  1077  			"foo": label1Model,
  1078  			"bar": label2Model,
  1079  		}
  1080  
  1081  		mockConverter := &automock.Converter{}
  1082  		defer mockConverter.AssertExpectations(t)
  1083  		for _, entity := range inputItems {
  1084  			mockConverter.On("FromEntity", entity).Return(expected[entity.Key], nil).Once()
  1085  		}
  1086  
  1087  		labelRepo := label.NewRepository(mockConverter)
  1088  
  1089  		db, dbMock := testdb.MockDatabase(t)
  1090  		defer dbMock.AssertExpectations(t)
  1091  
  1092  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE tenant_id = $1 AND app_id IS NULL AND runtime_context_id IS NULL AND runtime_id IS NULL`)
  1093  		mockedRows := sqlmock.NewRows(fixColumns).
  1094  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1095  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  1096  		dbMock.ExpectQuery(escapedQuery).WithArgs(tenantID).WillReturnRows(mockedRows)
  1097  
  1098  		ctx := context.TODO()
  1099  		ctx = persistence.SaveToContext(ctx, db)
  1100  
  1101  		// WHEN
  1102  		actual, err := labelRepo.ListForObject(ctx, tenantID, model.TenantLabelableObject, tenantID)
  1103  		// THEN
  1104  		require.NoError(t, err)
  1105  		assert.Equal(t, expected, actual)
  1106  	})
  1107  
  1108  	t.Run("Success - Label for Application Template", func(t *testing.T) {
  1109  		// GIVEN
  1110  		label1Model := fixModelLabelWithID("1", "foo", model.AppTemplateLabelableObject)
  1111  		label2Model := fixModelLabelWithID("2", "bar", model.AppTemplateLabelableObject)
  1112  
  1113  		label1Entity := fixEntityLabelWithID("1", "foo", model.AppTemplateLabelableObject)
  1114  		label2Entity := fixEntityLabelWithID("2", "bar", model.AppTemplateLabelableObject)
  1115  
  1116  		inputItems := []*label.Entity{label1Entity, label2Entity}
  1117  		expected := map[string]*model.Label{
  1118  			"foo": label1Model,
  1119  			"bar": label2Model,
  1120  		}
  1121  
  1122  		mockConverter := &automock.Converter{}
  1123  		defer mockConverter.AssertExpectations(t)
  1124  		for _, entity := range inputItems {
  1125  			mockConverter.On("FromEntity", entity).Return(expected[entity.Key], nil).Once()
  1126  		}
  1127  
  1128  		labelRepo := label.NewRepository(mockConverter)
  1129  
  1130  		db, dbMock := testdb.MockDatabase(t)
  1131  		defer dbMock.AssertExpectations(t)
  1132  
  1133  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE `)
  1134  		mockedRows := sqlmock.NewRows(fixColumns).
  1135  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1136  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  1137  		dbMock.ExpectQuery(escapedQuery).WithArgs(tenantID).WillReturnRows(mockedRows)
  1138  
  1139  		ctx := context.TODO()
  1140  		ctx = persistence.SaveToContext(ctx, db)
  1141  
  1142  		// WHEN
  1143  		actual, err := labelRepo.ListForObject(ctx, tenantID, model.AppTemplateLabelableObject, tenantID)
  1144  		// THEN
  1145  		require.NoError(t, err)
  1146  		assert.Equal(t, expected, actual)
  1147  	})
  1148  
  1149  	t.Run("Error - Doesn't exist", func(t *testing.T) {
  1150  		mockConverter := &automock.Converter{}
  1151  		defer mockConverter.AssertExpectations(t)
  1152  
  1153  		labelRepo := label.NewRepository(mockConverter)
  1154  
  1155  		db, dbMock := testdb.MockDatabase(t)
  1156  		defer dbMock.AssertExpectations(t)
  1157  
  1158  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_id = $1 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $2))`)
  1159  		mockedRows := sqlmock.NewRows(fixColumns)
  1160  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: refID}, tenantID).WillReturnRows(mockedRows)
  1161  
  1162  		ctx := context.TODO()
  1163  		ctx = persistence.SaveToContext(ctx, db)
  1164  		// WHEN
  1165  		actual, err := labelRepo.ListForObject(ctx, tenantID, model.ApplicationLabelableObject, refID)
  1166  		// THEN
  1167  		require.NoError(t, err)
  1168  		assert.Empty(t, actual)
  1169  	})
  1170  
  1171  	t.Run("Error - Select error", func(t *testing.T) {
  1172  		labelRepo := label.NewRepository(nil)
  1173  		db, dbMock := testdb.MockDatabase(t)
  1174  		defer dbMock.AssertExpectations(t)
  1175  
  1176  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_id = $1 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $2))`)
  1177  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: refID}, tenantID).WillReturnError(errors.New("persistence error"))
  1178  
  1179  		ctx := context.TODO()
  1180  		ctx = persistence.SaveToContext(ctx, db)
  1181  		// WHEN
  1182  		_, err := labelRepo.ListForObject(ctx, tenantID, model.ApplicationLabelableObject, refID)
  1183  		// THEN
  1184  		require.Error(t, err)
  1185  		require.Contains(t, err.Error(), "Unexpected error while executing SQL query")
  1186  	})
  1187  
  1188  	t.Run("Error - Missing persistence", func(t *testing.T) {
  1189  		// GIVEN
  1190  		labelRepo := label.NewRepository(nil)
  1191  
  1192  		// WHEN
  1193  		_, err := labelRepo.ListForObject(context.TODO(), tenantID, model.ApplicationLabelableObject, refID)
  1194  		// THEN
  1195  		require.Error(t, err)
  1196  		require.Contains(t, err.Error(), "unable to fetch database from context")
  1197  	})
  1198  }
  1199  
  1200  func TestRepository_ListByKey(t *testing.T) {
  1201  	label1Model := fixModelLabelWithID("1", "foo", model.RuntimeLabelableObject)
  1202  	label2Model := fixModelLabelWithID("2", "bar", model.ApplicationLabelableObject)
  1203  	label3Model := fixModelLabelWithID("3", "bar", model.RuntimeContextLabelableObject)
  1204  
  1205  	label1Entity := fixEntityLabelWithID("1", "foo", model.RuntimeLabelableObject)
  1206  	label2Entity := fixEntityLabelWithID("2", "bar", model.ApplicationLabelableObject)
  1207  	label3Entity := fixEntityLabelWithID("3", "bar", model.RuntimeContextLabelableObject)
  1208  
  1209  	suite := testdb.RepoListTestSuite{
  1210  		Name: "List Labels by key",
  1211  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1212  			{
  1213  				Query:    regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND (id IN (SELECT id FROM labels_tenants WHERE tenant_id = $2))`),
  1214  				Args:     []driver.Value{key, tenantID},
  1215  				IsSelect: true,
  1216  				ValidRowsProvider: func() []*sqlmock.Rows {
  1217  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).
  1218  						AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1219  						AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version).
  1220  						AddRow(label3Entity.ID, label3Entity.TenantID, label3Entity.AppID, label3Entity.RuntimeID, label3Entity.RuntimeContextID, label3Entity.AppTemplateID, label3Entity.Key, label3Entity.Value, label3Entity.Version),
  1221  					}
  1222  				},
  1223  				InvalidRowsProvider: func() []*sqlmock.Rows {
  1224  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)}
  1225  				},
  1226  			},
  1227  		},
  1228  		ConverterMockProvider: func() testdb.Mock {
  1229  			return &automock.Converter{}
  1230  		},
  1231  		RepoConstructorFunc:   label.NewRepository,
  1232  		ExpectedModelEntities: []interface{}{label1Model, label2Model, label3Model},
  1233  		ExpectedDBEntities:    []interface{}{label1Entity, label2Entity, label3Entity},
  1234  		MethodArgs:            []interface{}{tenantID, key},
  1235  		MethodName:            "ListByKey",
  1236  	}
  1237  
  1238  	suite.Run(t)
  1239  }
  1240  
  1241  func TestRepository_ListGlobalByKey(t *testing.T) {
  1242  	t.Run("Success", func(t *testing.T) {
  1243  		// GIVEN
  1244  		objType := model.ApplicationLabelableObject
  1245  		objIDs := []string{"foo", "bar", "baz"}
  1246  		labelKey := "key"
  1247  		version := 42
  1248  
  1249  		inputItems := []*label.Entity{
  1250  			{ID: "1", Key: labelKey, Value: "test1", AppID: sql.NullString{Valid: true, String: objIDs[0]}, Version: version},
  1251  			{ID: "2", Key: labelKey, Value: "test2", AppID: sql.NullString{Valid: true, String: objIDs[1]}, Version: version},
  1252  			{ID: "3", Key: labelKey, Value: "test3", AppID: sql.NullString{Valid: true, String: objIDs[2]}, Version: version},
  1253  		}
  1254  		expected := []*model.Label{
  1255  			{ID: "1", Key: labelKey, Value: "test1", ObjectType: objType, ObjectID: objIDs[0], Version: version},
  1256  			{ID: "2", Key: labelKey, Value: "test2", ObjectType: objType, ObjectID: objIDs[1], Version: version},
  1257  			{ID: "3", Key: labelKey, Value: "test3", ObjectType: objType, ObjectID: objIDs[2], Version: version},
  1258  		}
  1259  
  1260  		mockConverter := &automock.Converter{}
  1261  		defer mockConverter.AssertExpectations(t)
  1262  		for _, entity := range inputItems {
  1263  			for i := range expected {
  1264  				if expected[i].ObjectID == entity.AppID.String {
  1265  					mockConverter.On("FromEntity", entity).Return(expected[i], nil).Once()
  1266  				}
  1267  			}
  1268  		}
  1269  
  1270  		labelRepo := label.NewRepository(mockConverter)
  1271  
  1272  		db, dbMock := testdb.MockDatabase(t)
  1273  		defer dbMock.AssertExpectations(t)
  1274  
  1275  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1`)
  1276  		mockedRows := sqlmock.NewRows([]string{"id", "tenant_id", "app_template_id", "key", "value", "app_id", "runtime_id", "runtime_context_id", "version"}).
  1277  			AddRow("1", nil, nil, labelKey, "test1", objIDs[0], nil, nil, version).
  1278  			AddRow("2", nil, nil, labelKey, "test2", objIDs[1], nil, nil, version).
  1279  			AddRow("3", nil, nil, labelKey, "test3", objIDs[2], nil, nil, version)
  1280  		dbMock.ExpectQuery(escapedQuery).WithArgs(labelKey).WillReturnRows(mockedRows)
  1281  
  1282  		ctx := context.TODO()
  1283  		ctx = persistence.SaveToContext(ctx, db)
  1284  
  1285  		// WHEN
  1286  		actual, err := labelRepo.ListGlobalByKey(ctx, labelKey)
  1287  		// THEN
  1288  		require.NoError(t, err)
  1289  		assert.Equal(t, expected, actual)
  1290  	})
  1291  
  1292  	t.Run("Error - Select error", func(t *testing.T) {
  1293  		// GIVEN
  1294  		labelKey := "key"
  1295  
  1296  		labelRepo := label.NewRepository(nil)
  1297  
  1298  		db, dbMock := testdb.MockDatabase(t)
  1299  		defer dbMock.AssertExpectations(t)
  1300  
  1301  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1`)
  1302  		dbMock.ExpectQuery(escapedQuery).WithArgs(labelKey).WillReturnError(errors.New("persistence error"))
  1303  
  1304  		ctx := context.TODO()
  1305  		ctx = persistence.SaveToContext(ctx, db)
  1306  
  1307  		// WHEN
  1308  		_, err := labelRepo.ListGlobalByKey(ctx, labelKey)
  1309  		// THEN
  1310  		require.Error(t, err)
  1311  		require.Contains(t, err.Error(), "Unexpected error while executing SQL query")
  1312  	})
  1313  
  1314  	t.Run("Error - Converting entity", func(t *testing.T) {
  1315  		// GIVEN
  1316  		objIDs := []string{"foo", "bar", "baz"}
  1317  		labelKey := "key"
  1318  		testErr := errors.New("test error")
  1319  		version := 42
  1320  
  1321  		mockConverter := &automock.Converter{}
  1322  		mockConverter.On("FromEntity", mock.Anything).Return(&model.Label{}, testErr).Once()
  1323  
  1324  		labelRepo := label.NewRepository(mockConverter)
  1325  
  1326  		db, dbMock := testdb.MockDatabase(t)
  1327  		defer dbMock.AssertExpectations(t)
  1328  
  1329  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1`)
  1330  		mockedRows := sqlmock.NewRows([]string{"id", "tenant_id", "app_template_id", "key", "value", "app_id", "runtime_id", "runtime_context_id", "version"}).
  1331  			AddRow("1", nil, nil, labelKey, "test1", objIDs[0], nil, nil, version)
  1332  		dbMock.ExpectQuery(escapedQuery).WithArgs(labelKey).WillReturnRows(mockedRows)
  1333  
  1334  		ctx := context.TODO()
  1335  		ctx = persistence.SaveToContext(ctx, db)
  1336  
  1337  		// WHEN
  1338  		_, err := labelRepo.ListGlobalByKey(ctx, labelKey)
  1339  		// THEN
  1340  		require.Error(t, err)
  1341  	})
  1342  }
  1343  
  1344  func TestRepository_ListGlobalByKeyAndObjects(t *testing.T) {
  1345  	t.Run("Success", func(t *testing.T) {
  1346  		// GIVEN
  1347  		objType := model.ApplicationLabelableObject
  1348  		objIDs := []string{"foo", "bar", "baz"}
  1349  		labelKey := "key"
  1350  		version := 42
  1351  
  1352  		inputItems := []*label.Entity{
  1353  			{ID: "1", Key: labelKey, Value: "test1", AppID: sql.NullString{Valid: true, String: objIDs[0]}, Version: version},
  1354  			{ID: "2", Key: labelKey, Value: "test2", AppID: sql.NullString{Valid: true, String: objIDs[1]}, Version: version},
  1355  			{ID: "3", Key: labelKey, Value: "test3", AppID: sql.NullString{Valid: true, String: objIDs[2]}, Version: version},
  1356  		}
  1357  		expected := []*model.Label{
  1358  			{ID: "1", Key: labelKey, Value: "test1", ObjectType: objType, ObjectID: objIDs[0], Version: version},
  1359  			{ID: "2", Key: labelKey, Value: "test2", ObjectType: objType, ObjectID: objIDs[1], Version: version},
  1360  			{ID: "3", Key: labelKey, Value: "test3", ObjectType: objType, ObjectID: objIDs[2], Version: version},
  1361  		}
  1362  
  1363  		mockConverter := &automock.Converter{}
  1364  		defer mockConverter.AssertExpectations(t)
  1365  		for _, entity := range inputItems {
  1366  			for i := range expected {
  1367  				if expected[i].ObjectID == entity.AppID.String {
  1368  					mockConverter.On("FromEntity", entity).Return(expected[i], nil).Once()
  1369  				}
  1370  			}
  1371  		}
  1372  
  1373  		labelRepo := label.NewRepository(mockConverter)
  1374  
  1375  		db, dbMock := testdb.MockDatabase(t)
  1376  		defer dbMock.AssertExpectations(t)
  1377  
  1378  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id IN ($2, $3, $4) FOR UPDATE`)
  1379  		mockedRows := sqlmock.NewRows([]string{"id", "tenant_id", "app_template_id", "key", "value", "app_id", "runtime_id", "runtime_context_id", "version"}).
  1380  			AddRow("1", nil, nil, labelKey, "test1", objIDs[0], nil, nil, version).
  1381  			AddRow("2", nil, nil, labelKey, "test2", objIDs[1], nil, nil, version).
  1382  			AddRow("3", nil, nil, labelKey, "test3", objIDs[2], nil, nil, version)
  1383  		dbMock.ExpectQuery(escapedQuery).WithArgs(labelKey, sql.NullString{Valid: true, String: objIDs[0]}, sql.NullString{Valid: true, String: objIDs[1]}, sql.NullString{Valid: true, String: objIDs[2]}).WillReturnRows(mockedRows)
  1384  
  1385  		ctx := context.TODO()
  1386  		ctx = persistence.SaveToContext(ctx, db)
  1387  
  1388  		// WHEN
  1389  		actual, err := labelRepo.ListGlobalByKeyAndObjects(ctx, objType, objIDs, labelKey)
  1390  		// THEN
  1391  		require.NoError(t, err)
  1392  		assert.Equal(t, expected, actual)
  1393  	})
  1394  
  1395  	t.Run("Error - Select error", func(t *testing.T) {
  1396  		// GIVEN
  1397  		objType := model.ApplicationLabelableObject
  1398  		objIDs := []string{"foo", "bar", "baz"}
  1399  		labelKey := "key"
  1400  
  1401  		labelRepo := label.NewRepository(nil)
  1402  
  1403  		db, dbMock := testdb.MockDatabase(t)
  1404  		defer dbMock.AssertExpectations(t)
  1405  
  1406  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id IN ($2, $3, $4) FOR UPDATE`)
  1407  		dbMock.ExpectQuery(escapedQuery).WithArgs(labelKey, sql.NullString{Valid: true, String: objIDs[0]}, sql.NullString{Valid: true, String: objIDs[1]}, sql.NullString{Valid: true, String: objIDs[2]}).
  1408  			WillReturnError(errors.New("persistence error"))
  1409  
  1410  		ctx := context.TODO()
  1411  		ctx = persistence.SaveToContext(ctx, db)
  1412  
  1413  		// WHEN
  1414  		_, err := labelRepo.ListGlobalByKeyAndObjects(ctx, objType, objIDs, labelKey)
  1415  		// THEN
  1416  		require.Error(t, err)
  1417  		require.Contains(t, err.Error(), "Unexpected error while executing SQL query")
  1418  	})
  1419  
  1420  	t.Run("Error - Converting entity", func(t *testing.T) {
  1421  		// GIVEN
  1422  		objType := model.ApplicationLabelableObject
  1423  		objIDs := []string{"foo", "bar", "baz"}
  1424  		labelKey := "key"
  1425  		testErr := errors.New("test error")
  1426  		version := 42
  1427  
  1428  		mockConverter := &automock.Converter{}
  1429  		mockConverter.On("FromEntity", mock.Anything).Return(&model.Label{}, testErr).Once()
  1430  
  1431  		labelRepo := label.NewRepository(mockConverter)
  1432  
  1433  		db, dbMock := testdb.MockDatabase(t)
  1434  		defer dbMock.AssertExpectations(t)
  1435  
  1436  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND app_id IN ($2, $3, $4) FOR UPDATE`)
  1437  		mockedRows := sqlmock.NewRows([]string{"id", "tenant_id", "app_template_id", "key", "value", "app_id", "runtime_id", "runtime_context_id", "version"}).
  1438  			AddRow("1", nil, nil, labelKey, "test1", objIDs[0], nil, nil, version)
  1439  		dbMock.ExpectQuery(escapedQuery).WithArgs(labelKey, sql.NullString{Valid: true, String: objIDs[0]}, sql.NullString{Valid: true, String: objIDs[1]}, sql.NullString{Valid: true, String: objIDs[2]}).WillReturnRows(mockedRows)
  1440  
  1441  		ctx := context.TODO()
  1442  		ctx = persistence.SaveToContext(ctx, db)
  1443  
  1444  		// WHEN
  1445  		_, err := labelRepo.ListGlobalByKeyAndObjects(ctx, objType, objIDs, labelKey)
  1446  		// THEN
  1447  		require.Error(t, err)
  1448  	})
  1449  }
  1450  
  1451  func TestRepository_Delete(t *testing.T) {
  1452  	appLabelSuite := testdb.RepoDeleteTestSuite{
  1453  		Name: "App Label Delete",
  1454  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1455  			{
  1456  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE key = $1 AND app_id = $2 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3 AND owner = true))`),
  1457  				Args:          []driver.Value{key, refID, tenantID},
  1458  				ValidResult:   sqlmock.NewResult(-1, 1),
  1459  				InvalidResult: sqlmock.NewResult(-1, 2),
  1460  			},
  1461  		},
  1462  		ConverterMockProvider: func() testdb.Mock {
  1463  			return &automock.Converter{}
  1464  		},
  1465  		RepoConstructorFunc: label.NewRepository,
  1466  		MethodArgs:          []interface{}{tenantID, model.ApplicationLabelableObject, refID, key},
  1467  		IsDeleteMany:        true,
  1468  	}
  1469  
  1470  	rtLabelSuite := testdb.RepoDeleteTestSuite{
  1471  		Name: "Runtime Label Delete",
  1472  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1473  			{
  1474  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE key = $1 AND runtime_id = $2 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $3 AND owner = true))`),
  1475  				Args:          []driver.Value{key, refID, tenantID},
  1476  				ValidResult:   sqlmock.NewResult(-1, 1),
  1477  				InvalidResult: sqlmock.NewResult(-1, 2),
  1478  			},
  1479  		},
  1480  		ConverterMockProvider: func() testdb.Mock {
  1481  			return &automock.Converter{}
  1482  		},
  1483  		RepoConstructorFunc: label.NewRepository,
  1484  		MethodArgs:          []interface{}{tenantID, model.RuntimeLabelableObject, refID, key},
  1485  		IsDeleteMany:        true,
  1486  	}
  1487  
  1488  	rtCtxLabelSuite := testdb.RepoDeleteTestSuite{
  1489  		Name: "Runtime Context Label Delete",
  1490  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1491  			{
  1492  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE key = $1 AND runtime_context_id = $2 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $3 AND owner = true))`),
  1493  				Args:          []driver.Value{key, refID, tenantID},
  1494  				ValidResult:   sqlmock.NewResult(-1, 1),
  1495  				InvalidResult: sqlmock.NewResult(-1, 2),
  1496  			},
  1497  		},
  1498  		ConverterMockProvider: func() testdb.Mock {
  1499  			return &automock.Converter{}
  1500  		},
  1501  		RepoConstructorFunc: label.NewRepository,
  1502  		MethodArgs:          []interface{}{tenantID, model.RuntimeContextLabelableObject, refID, key},
  1503  		IsDeleteMany:        true,
  1504  	}
  1505  
  1506  	appLabelSuite.Run(t)
  1507  	rtLabelSuite.Run(t)
  1508  	rtCtxLabelSuite.Run(t)
  1509  
  1510  	t.Run("Success - Label for Tenant", func(t *testing.T) {
  1511  		mockConverter := &automock.Converter{}
  1512  		defer mockConverter.AssertExpectations(t)
  1513  
  1514  		labelRepo := label.NewRepository(mockConverter)
  1515  
  1516  		db, dbMock := testdb.MockDatabase(t)
  1517  		defer dbMock.AssertExpectations(t)
  1518  
  1519  		escapedQuery := regexp.QuoteMeta(`DELETE FROM public.labels WHERE tenant_id = $1 AND key = $2`)
  1520  		dbMock.ExpectExec(escapedQuery).WithArgs(tenantID, key).WillReturnResult(sqlmock.NewResult(-1, 1))
  1521  
  1522  		ctx := context.TODO()
  1523  		ctx = persistence.SaveToContext(ctx, db)
  1524  		// WHEN
  1525  		err := labelRepo.Delete(ctx, tenantID, model.TenantLabelableObject, tenantID, key)
  1526  		// THEN
  1527  		require.NoError(t, err)
  1528  	})
  1529  
  1530  	t.Run("Success - Label for Tenant", func(t *testing.T) {
  1531  		mockConverter := &automock.Converter{}
  1532  		defer mockConverter.AssertExpectations(t)
  1533  
  1534  		labelRepo := label.NewRepository(mockConverter)
  1535  
  1536  		db, dbMock := testdb.MockDatabase(t)
  1537  		defer dbMock.AssertExpectations(t)
  1538  
  1539  		escapedQuery := regexp.QuoteMeta(`DELETE FROM public.labels WHERE key = $1 AND app_template_id = $2`)
  1540  		dbMock.ExpectExec(escapedQuery).WithArgs(key, refID).WillReturnResult(sqlmock.NewResult(-1, 1))
  1541  
  1542  		ctx := context.TODO()
  1543  		ctx = persistence.SaveToContext(ctx, db)
  1544  		// WHEN
  1545  		err := labelRepo.Delete(ctx, tenantID, model.AppTemplateLabelableObject, refID, key)
  1546  		// THEN
  1547  		require.NoError(t, err)
  1548  	})
  1549  }
  1550  
  1551  func TestRepository_DeleteAll(t *testing.T) {
  1552  	appLabelSuite := testdb.RepoDeleteTestSuite{
  1553  		Name: "App Label Delete All",
  1554  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1555  			{
  1556  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE app_id = $1 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $2 AND owner = true))`),
  1557  				Args:          []driver.Value{refID, tenantID},
  1558  				ValidResult:   sqlmock.NewResult(-1, 1),
  1559  				InvalidResult: sqlmock.NewResult(-1, 2),
  1560  			},
  1561  		},
  1562  		ConverterMockProvider: func() testdb.Mock {
  1563  			return &automock.Converter{}
  1564  		},
  1565  		RepoConstructorFunc: label.NewRepository,
  1566  		MethodArgs:          []interface{}{tenantID, model.ApplicationLabelableObject, refID},
  1567  		MethodName:          "DeleteAll",
  1568  		IsDeleteMany:        true,
  1569  	}
  1570  
  1571  	rtLabelSuite := testdb.RepoDeleteTestSuite{
  1572  		Name: "Runtime Label Delete All",
  1573  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1574  			{
  1575  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE runtime_id = $1 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $2 AND owner = true))`),
  1576  				Args:          []driver.Value{refID, tenantID},
  1577  				ValidResult:   sqlmock.NewResult(-1, 1),
  1578  				InvalidResult: sqlmock.NewResult(-1, 2),
  1579  			},
  1580  		},
  1581  		ConverterMockProvider: func() testdb.Mock {
  1582  			return &automock.Converter{}
  1583  		},
  1584  		RepoConstructorFunc: label.NewRepository,
  1585  		MethodArgs:          []interface{}{tenantID, model.RuntimeLabelableObject, refID},
  1586  		MethodName:          "DeleteAll",
  1587  		IsDeleteMany:        true,
  1588  	}
  1589  
  1590  	rtCtxLabelSuite := testdb.RepoDeleteTestSuite{
  1591  		Name: "Runtime Context Label Delete All",
  1592  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1593  			{
  1594  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE runtime_context_id = $1 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $2 AND owner = true))`),
  1595  				Args:          []driver.Value{refID, tenantID},
  1596  				ValidResult:   sqlmock.NewResult(-1, 1),
  1597  				InvalidResult: sqlmock.NewResult(-1, 2),
  1598  			},
  1599  		},
  1600  		ConverterMockProvider: func() testdb.Mock {
  1601  			return &automock.Converter{}
  1602  		},
  1603  		RepoConstructorFunc: label.NewRepository,
  1604  		MethodArgs:          []interface{}{tenantID, model.RuntimeContextLabelableObject, refID},
  1605  		MethodName:          "DeleteAll",
  1606  		IsDeleteMany:        true,
  1607  	}
  1608  
  1609  	appLabelSuite.Run(t)
  1610  	rtLabelSuite.Run(t)
  1611  	rtCtxLabelSuite.Run(t)
  1612  
  1613  	t.Run("Success - Label for Tenant", func(t *testing.T) {
  1614  		mockConverter := &automock.Converter{}
  1615  		defer mockConverter.AssertExpectations(t)
  1616  
  1617  		labelRepo := label.NewRepository(mockConverter)
  1618  
  1619  		db, dbMock := testdb.MockDatabase(t)
  1620  		defer dbMock.AssertExpectations(t)
  1621  
  1622  		escapedQuery := regexp.QuoteMeta(`DELETE FROM public.labels WHERE tenant_id = $1`)
  1623  		dbMock.ExpectExec(escapedQuery).WithArgs(tenantID).WillReturnResult(sqlmock.NewResult(-1, 1))
  1624  
  1625  		ctx := context.TODO()
  1626  		ctx = persistence.SaveToContext(ctx, db)
  1627  		// WHEN
  1628  		err := labelRepo.DeleteAll(ctx, tenantID, model.TenantLabelableObject, tenantID)
  1629  		// THEN
  1630  		require.NoError(t, err)
  1631  	})
  1632  
  1633  	t.Run("Success - Label for Application Template", func(t *testing.T) {
  1634  		mockConverter := &automock.Converter{}
  1635  		defer mockConverter.AssertExpectations(t)
  1636  
  1637  		labelRepo := label.NewRepository(mockConverter)
  1638  
  1639  		db, dbMock := testdb.MockDatabase(t)
  1640  		defer dbMock.AssertExpectations(t)
  1641  
  1642  		escapedQuery := regexp.QuoteMeta(`DELETE FROM public.labels WHERE app_template_id = $1`)
  1643  		dbMock.ExpectExec(escapedQuery).WithArgs(refID).WillReturnResult(sqlmock.NewResult(-1, 1))
  1644  
  1645  		ctx := context.TODO()
  1646  		ctx = persistence.SaveToContext(ctx, db)
  1647  		// WHEN
  1648  		err := labelRepo.DeleteAll(ctx, tenantID, model.AppTemplateLabelableObject, refID)
  1649  		// THEN
  1650  		require.NoError(t, err)
  1651  	})
  1652  }
  1653  
  1654  func TestRepository_DeleteByKey(t *testing.T) {
  1655  	suite := testdb.RepoDeleteTestSuite{
  1656  		Name: "Label Delete By Key",
  1657  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1658  			{
  1659  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE key = $1 AND (id IN (SELECT id FROM labels_tenants WHERE tenant_id = $2 AND owner = true))`),
  1660  				Args:          []driver.Value{key, tenantID},
  1661  				ValidResult:   sqlmock.NewResult(-1, 1),
  1662  				InvalidResult: sqlmock.NewResult(-1, 2),
  1663  			},
  1664  		},
  1665  		ConverterMockProvider: func() testdb.Mock {
  1666  			return &automock.Converter{}
  1667  		},
  1668  		RepoConstructorFunc: label.NewRepository,
  1669  		MethodArgs:          []interface{}{tenantID, key},
  1670  		MethodName:          "DeleteByKey",
  1671  		IsDeleteMany:        true,
  1672  	}
  1673  
  1674  	suite.Run(t)
  1675  }
  1676  
  1677  func TestRepository_DeleteByKeyNegationPattern(t *testing.T) {
  1678  	pattern := "pattern"
  1679  
  1680  	appLabelSuite := testdb.RepoDeleteTestSuite{
  1681  		Name: "App Label DeleteByKeyNegationPattern",
  1682  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1683  			{
  1684  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE NOT key ~ $1 AND app_id = $2 AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3 AND owner = true))`),
  1685  				Args:          []driver.Value{pattern, refID, tenantID},
  1686  				ValidResult:   sqlmock.NewResult(-1, 1),
  1687  				InvalidResult: sqlmock.NewResult(-1, 2),
  1688  			},
  1689  		},
  1690  		ConverterMockProvider: func() testdb.Mock {
  1691  			return &automock.Converter{}
  1692  		},
  1693  		RepoConstructorFunc: label.NewRepository,
  1694  		MethodArgs:          []interface{}{tenantID, model.ApplicationLabelableObject, refID, pattern},
  1695  		MethodName:          "DeleteByKeyNegationPattern",
  1696  		IsDeleteMany:        true,
  1697  	}
  1698  
  1699  	rtLabelSuite := testdb.RepoDeleteTestSuite{
  1700  		Name: "Runtime Label DeleteByKeyNegationPattern",
  1701  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1702  			{
  1703  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE NOT key ~ $1 AND runtime_id = $2 AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $3 AND owner = true))`),
  1704  				Args:          []driver.Value{pattern, refID, tenantID},
  1705  				ValidResult:   sqlmock.NewResult(-1, 1),
  1706  				InvalidResult: sqlmock.NewResult(-1, 2),
  1707  			},
  1708  		},
  1709  		ConverterMockProvider: func() testdb.Mock {
  1710  			return &automock.Converter{}
  1711  		},
  1712  		RepoConstructorFunc: label.NewRepository,
  1713  		MethodArgs:          []interface{}{tenantID, model.RuntimeLabelableObject, refID, pattern},
  1714  		MethodName:          "DeleteByKeyNegationPattern",
  1715  		IsDeleteMany:        true,
  1716  	}
  1717  
  1718  	rtCtxLabelSuite := testdb.RepoDeleteTestSuite{
  1719  		Name: "Runtime Context Label DeleteByKeyNegationPattern",
  1720  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1721  			{
  1722  				Query:         regexp.QuoteMeta(`DELETE FROM public.labels WHERE NOT key ~ $1 AND runtime_context_id = $2 AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $3 AND owner = true))`),
  1723  				Args:          []driver.Value{pattern, refID, tenantID},
  1724  				ValidResult:   sqlmock.NewResult(-1, 1),
  1725  				InvalidResult: sqlmock.NewResult(-1, 2),
  1726  			},
  1727  		},
  1728  		ConverterMockProvider: func() testdb.Mock {
  1729  			return &automock.Converter{}
  1730  		},
  1731  		RepoConstructorFunc: label.NewRepository,
  1732  		MethodArgs:          []interface{}{tenantID, model.RuntimeContextLabelableObject, refID, pattern},
  1733  		MethodName:          "DeleteByKeyNegationPattern",
  1734  		IsDeleteMany:        true,
  1735  	}
  1736  
  1737  	appLabelSuite.Run(t)
  1738  	rtLabelSuite.Run(t)
  1739  	rtCtxLabelSuite.Run(t)
  1740  
  1741  	t.Run("Success - Label for Tenant", func(t *testing.T) {
  1742  		mockConverter := &automock.Converter{}
  1743  		defer mockConverter.AssertExpectations(t)
  1744  
  1745  		labelRepo := label.NewRepository(mockConverter)
  1746  
  1747  		db, dbMock := testdb.MockDatabase(t)
  1748  		defer dbMock.AssertExpectations(t)
  1749  
  1750  		escapedQuery := regexp.QuoteMeta(`DELETE FROM public.labels WHERE tenant_id = $1 AND NOT key ~ $2 `)
  1751  		dbMock.ExpectExec(escapedQuery).WithArgs(tenantID, pattern).WillReturnResult(sqlmock.NewResult(-1, 1))
  1752  
  1753  		ctx := context.TODO()
  1754  		ctx = persistence.SaveToContext(ctx, db)
  1755  		// WHEN
  1756  		err := labelRepo.DeleteByKeyNegationPattern(ctx, tenantID, model.TenantLabelableObject, tenantID, pattern)
  1757  		// THEN
  1758  		require.NoError(t, err)
  1759  	})
  1760  
  1761  	t.Run("Success - Label for Application Template", func(t *testing.T) {
  1762  		mockConverter := &automock.Converter{}
  1763  		defer mockConverter.AssertExpectations(t)
  1764  
  1765  		labelRepo := label.NewRepository(mockConverter)
  1766  
  1767  		db, dbMock := testdb.MockDatabase(t)
  1768  		defer dbMock.AssertExpectations(t)
  1769  
  1770  		escapedQuery := regexp.QuoteMeta(`DELETE FROM public.labels WHERE NOT key ~ $1 AND app_template_id = $2`)
  1771  		dbMock.ExpectExec(escapedQuery).WithArgs(pattern, refID).WillReturnResult(sqlmock.NewResult(-1, 1))
  1772  
  1773  		ctx := context.TODO()
  1774  		ctx = persistence.SaveToContext(ctx, db)
  1775  		// WHEN
  1776  		err := labelRepo.DeleteByKeyNegationPattern(ctx, tenantID, model.AppTemplateLabelableObject, refID, pattern)
  1777  		// THEN
  1778  		require.NoError(t, err)
  1779  	})
  1780  }
  1781  
  1782  func TestRepository_GetScenarioLabelsForRuntimes(t *testing.T) {
  1783  	rt1ID := "rt1"
  1784  	rt2ID := "rt2"
  1785  
  1786  	label1Model := fixModelLabelWithRefID("1", model.ScenariosKey, model.RuntimeLabelableObject, rt1ID)
  1787  	label2Model := fixModelLabelWithRefID("2", model.ScenariosKey, model.RuntimeLabelableObject, rt2ID)
  1788  
  1789  	label1Entity := fixEntityLabelWithRefID("1", model.ScenariosKey, model.RuntimeLabelableObject, rt1ID)
  1790  	label2Entity := fixEntityLabelWithRefID("2", model.ScenariosKey, model.RuntimeLabelableObject, rt2ID)
  1791  
  1792  	suite := testdb.RepoListTestSuite{
  1793  		Name: "List Runtime Scenarios Matching Selector",
  1794  		SQLQueryDetails: []testdb.SQLQueryDetails{
  1795  			{
  1796  				Query:    regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE key = $1 AND runtime_id IN ($2, $3) AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $4))`),
  1797  				Args:     []driver.Value{model.ScenariosKey, rt1ID, rt2ID, tenantID},
  1798  				IsSelect: true,
  1799  				ValidRowsProvider: func() []*sqlmock.Rows {
  1800  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns).
  1801  						AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1802  						AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version),
  1803  					}
  1804  				},
  1805  				InvalidRowsProvider: func() []*sqlmock.Rows {
  1806  					return []*sqlmock.Rows{sqlmock.NewRows(fixColumns)}
  1807  				},
  1808  			},
  1809  		},
  1810  		ConverterMockProvider: func() testdb.Mock {
  1811  			return &automock.Converter{}
  1812  		},
  1813  		RepoConstructorFunc:   label.NewRepository,
  1814  		ExpectedModelEntities: []interface{}{label1Model, label2Model},
  1815  		ExpectedDBEntities:    []interface{}{label1Entity, label2Entity},
  1816  		MethodArgs:            []interface{}{tenantID, []string{rt1ID, rt2ID}},
  1817  		MethodName:            "GetScenarioLabelsForRuntimes",
  1818  	}
  1819  
  1820  	suite.Run(t)
  1821  }
  1822  
  1823  func TestRepository_ListForObjectIDs(t *testing.T) {
  1824  	labelIDs := []string{"1", "2"}
  1825  	t.Run("Success - Label for Runtime", func(t *testing.T) {
  1826  		// GIVEN
  1827  		rt1ID := "rt1"
  1828  		rt2ID := "rt2"
  1829  
  1830  		label1Model := fixModelLabelWithRefID("1", "foo", model.RuntimeLabelableObject, rt1ID)
  1831  		label2Model := fixModelLabelWithRefID("2", "bar", model.RuntimeLabelableObject, rt2ID)
  1832  
  1833  		label1Entity := fixEntityLabelWithRefID("1", "foo", model.RuntimeLabelableObject, rt1ID)
  1834  		label2Entity := fixEntityLabelWithRefID("2", "bar", model.RuntimeLabelableObject, rt2ID)
  1835  
  1836  		inputItems := []*label.Entity{label1Entity, label2Entity}
  1837  		outputItems := []*model.Label{label1Model, label2Model}
  1838  		expected := map[string]map[string]interface{}{
  1839  			rt1ID: {
  1840  				label1Model.Key: label1Model.Value,
  1841  			},
  1842  			rt2ID: {
  1843  				label2Model.Key: label2Model.Value,
  1844  			},
  1845  		}
  1846  
  1847  		mockConverter := &automock.Converter{}
  1848  		defer mockConverter.AssertExpectations(t)
  1849  		for i, entity := range inputItems {
  1850  			mockConverter.On("FromEntity", entity).Return(outputItems[i], nil).Once()
  1851  		}
  1852  
  1853  		labelRepo := label.NewRepository(mockConverter)
  1854  
  1855  		db, dbMock := testdb.MockDatabase(t)
  1856  		defer dbMock.AssertExpectations(t)
  1857  
  1858  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE runtime_id IN ($1, $2) AND (id IN (SELECT id FROM runtime_labels_tenants WHERE tenant_id = $3))`)
  1859  		mockedRows := sqlmock.NewRows(fixColumns).
  1860  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1861  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  1862  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}, tenantID).WillReturnRows(mockedRows)
  1863  
  1864  		ctx := context.TODO()
  1865  		ctx = persistence.SaveToContext(ctx, db)
  1866  		// WHEN
  1867  		actual, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.RuntimeLabelableObject, labelIDs)
  1868  		// THEN
  1869  		require.NoError(t, err)
  1870  		assert.Equal(t, expected, actual)
  1871  	})
  1872  
  1873  	t.Run("Success - Label for Runtime Context", func(t *testing.T) {
  1874  		// GIVEN
  1875  		rtCtx1Id := "rtm-ctx-1"
  1876  		rtCtx2Id := "rtm-ctx-2"
  1877  
  1878  		label1Model := fixModelLabelWithRefID("1", "foo", model.RuntimeContextLabelableObject, rtCtx1Id)
  1879  		label2Model := fixModelLabelWithRefID("2", "bar", model.RuntimeContextLabelableObject, rtCtx2Id)
  1880  
  1881  		label1Entity := fixEntityLabelWithRefID("1", "foo", model.RuntimeContextLabelableObject, rtCtx1Id)
  1882  		label2Entity := fixEntityLabelWithRefID("2", "bar", model.RuntimeContextLabelableObject, rtCtx2Id)
  1883  
  1884  		inputItems := []*label.Entity{label1Entity, label2Entity}
  1885  		outputItems := []*model.Label{label1Model, label2Model}
  1886  		expected := map[string]map[string]interface{}{
  1887  			rtCtx1Id: {
  1888  				label1Model.Key: label1Model.Value,
  1889  			},
  1890  			rtCtx2Id: {
  1891  				label2Model.Key: label2Model.Value,
  1892  			},
  1893  		}
  1894  
  1895  		mockConverter := &automock.Converter{}
  1896  		defer mockConverter.AssertExpectations(t)
  1897  		for i, entity := range inputItems {
  1898  			mockConverter.On("FromEntity", entity).Return(outputItems[i], nil).Once()
  1899  		}
  1900  
  1901  		labelRepo := label.NewRepository(mockConverter)
  1902  
  1903  		db, dbMock := testdb.MockDatabase(t)
  1904  		defer dbMock.AssertExpectations(t)
  1905  
  1906  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE runtime_context_id IN ($1, $2) AND (id IN (SELECT id FROM runtime_contexts_labels_tenants WHERE tenant_id = $3))`)
  1907  		mockedRows := sqlmock.NewRows(fixColumns).
  1908  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1909  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  1910  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}, tenantID).WillReturnRows(mockedRows)
  1911  
  1912  		ctx := context.TODO()
  1913  		ctx = persistence.SaveToContext(ctx, db)
  1914  		// WHEN
  1915  		actual, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.RuntimeContextLabelableObject, labelIDs)
  1916  		// THEN
  1917  		require.NoError(t, err)
  1918  		assert.Equal(t, expected, actual)
  1919  	})
  1920  
  1921  	t.Run("Success - Label for Application", func(t *testing.T) {
  1922  		// GIVEN
  1923  		app1Id := "app-1"
  1924  		app2Id := "app-2"
  1925  
  1926  		label1Model := fixModelLabelWithRefID("1", "foo", model.ApplicationLabelableObject, app1Id)
  1927  		label2Model := fixModelLabelWithRefID("2", "bar", model.ApplicationLabelableObject, app2Id)
  1928  
  1929  		label1Entity := fixEntityLabelWithRefID("1", "foo", model.ApplicationLabelableObject, app1Id)
  1930  		label2Entity := fixEntityLabelWithRefID("2", "bar", model.ApplicationLabelableObject, app2Id)
  1931  
  1932  		inputItems := []*label.Entity{label1Entity, label2Entity}
  1933  		outputItems := []*model.Label{label1Model, label2Model}
  1934  		expected := map[string]map[string]interface{}{
  1935  			app1Id: {
  1936  				label1Model.Key: label1Model.Value,
  1937  			},
  1938  			app2Id: {
  1939  				label2Model.Key: label2Model.Value,
  1940  			},
  1941  		}
  1942  
  1943  		mockConverter := &automock.Converter{}
  1944  		defer mockConverter.AssertExpectations(t)
  1945  		for i, entity := range inputItems {
  1946  			mockConverter.On("FromEntity", entity).Return(outputItems[i], nil).Once()
  1947  		}
  1948  
  1949  		labelRepo := label.NewRepository(mockConverter)
  1950  
  1951  		db, dbMock := testdb.MockDatabase(t)
  1952  		defer dbMock.AssertExpectations(t)
  1953  
  1954  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_id IN ($1, $2) AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3))`)
  1955  		mockedRows := sqlmock.NewRows(fixColumns).
  1956  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  1957  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label1Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  1958  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}, tenantID).WillReturnRows(mockedRows)
  1959  
  1960  		ctx := context.TODO()
  1961  		ctx = persistence.SaveToContext(ctx, db)
  1962  
  1963  		// WHEN
  1964  		actual, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.ApplicationLabelableObject, labelIDs)
  1965  		// THEN
  1966  		require.NoError(t, err)
  1967  		assert.Equal(t, expected, actual)
  1968  	})
  1969  
  1970  	t.Run("Success - Label for Tenant", func(t *testing.T) {
  1971  		// GIVEN
  1972  		tenant1Id := "tenant-1"
  1973  		tenant2Id := "tenant-2"
  1974  
  1975  		label1Model := fixModelLabelWithRefID("1", "foo", model.TenantLabelableObject, tenant1Id)
  1976  		label2Model := fixModelLabelWithRefID("2", "bar", model.TenantLabelableObject, tenant2Id)
  1977  
  1978  		label1Entity := fixEntityLabelWithRefID("1", "foo", model.TenantLabelableObject, tenant1Id)
  1979  		label2Entity := fixEntityLabelWithRefID("2", "bar", model.TenantLabelableObject, tenant2Id)
  1980  
  1981  		inputItems := []*label.Entity{label1Entity, label2Entity}
  1982  		outputItems := []*model.Label{label1Model, label2Model}
  1983  		expected := map[string]map[string]interface{}{
  1984  			tenant1Id: {
  1985  				label1Model.Key: label1Model.Value,
  1986  			},
  1987  			tenant2Id: {
  1988  				label2Model.Key: label2Model.Value,
  1989  			},
  1990  		}
  1991  
  1992  		mockConverter := &automock.Converter{}
  1993  		defer mockConverter.AssertExpectations(t)
  1994  		for i, entity := range inputItems {
  1995  			mockConverter.On("FromEntity", entity).Return(outputItems[i], nil).Once()
  1996  		}
  1997  
  1998  		labelRepo := label.NewRepository(mockConverter)
  1999  
  2000  		db, dbMock := testdb.MockDatabase(t)
  2001  		defer dbMock.AssertExpectations(t)
  2002  
  2003  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE tenant_id = $1 AND tenant_id IN ($2, $3) AND app_id IS NULL AND runtime_context_id IS NULL AND runtime_id IS NULL`)
  2004  		mockedRows := sqlmock.NewRows(fixColumns).
  2005  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  2006  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  2007  		dbMock.ExpectQuery(escapedQuery).WithArgs(tenantID, sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}).WillReturnRows(mockedRows)
  2008  
  2009  		ctx := context.TODO()
  2010  		ctx = persistence.SaveToContext(ctx, db)
  2011  
  2012  		// WHEN
  2013  		actual, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.TenantLabelableObject, labelIDs)
  2014  		// THEN
  2015  		require.NoError(t, err)
  2016  		assert.Equal(t, expected, actual)
  2017  	})
  2018  
  2019  	t.Run("Success - Label for Application Template", func(t *testing.T) {
  2020  		// GIVEN
  2021  		tenant1Id := "tenant-1"
  2022  		tenant2Id := "tenant-2"
  2023  
  2024  		label1Model := fixModelLabelWithRefID("1", "foo", model.AppTemplateLabelableObject, tenant1Id)
  2025  		label2Model := fixModelLabelWithRefID("2", "bar", model.AppTemplateLabelableObject, tenant2Id)
  2026  
  2027  		label1Entity := fixEntityLabelWithRefID("1", "foo", model.AppTemplateLabelableObject, tenant1Id)
  2028  		label2Entity := fixEntityLabelWithRefID("2", "bar", model.AppTemplateLabelableObject, tenant2Id)
  2029  
  2030  		inputItems := []*label.Entity{label1Entity, label2Entity}
  2031  		outputItems := []*model.Label{label1Model, label2Model}
  2032  		expected := map[string]map[string]interface{}{
  2033  			tenant1Id: {
  2034  				label1Model.Key: label1Model.Value,
  2035  			},
  2036  			tenant2Id: {
  2037  				label2Model.Key: label2Model.Value,
  2038  			},
  2039  		}
  2040  
  2041  		mockConverter := &automock.Converter{}
  2042  		defer mockConverter.AssertExpectations(t)
  2043  		for i, entity := range inputItems {
  2044  			mockConverter.On("FromEntity", entity).Return(outputItems[i], nil).Once()
  2045  		}
  2046  
  2047  		labelRepo := label.NewRepository(mockConverter)
  2048  
  2049  		db, dbMock := testdb.MockDatabase(t)
  2050  		defer dbMock.AssertExpectations(t)
  2051  
  2052  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_template_id IN ($1, $2)`)
  2053  		mockedRows := sqlmock.NewRows(fixColumns).
  2054  			AddRow(label1Entity.ID, label1Entity.TenantID, label1Entity.AppID, label1Entity.RuntimeID, label1Entity.RuntimeContextID, label1Entity.AppTemplateID, label1Entity.Key, label1Entity.Value, label1Entity.Version).
  2055  			AddRow(label2Entity.ID, label2Entity.TenantID, label2Entity.AppID, label2Entity.RuntimeID, label2Entity.RuntimeContextID, label2Entity.AppTemplateID, label2Entity.Key, label2Entity.Value, label2Entity.Version)
  2056  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}).WillReturnRows(mockedRows)
  2057  
  2058  		ctx := context.TODO()
  2059  		ctx = persistence.SaveToContext(ctx, db)
  2060  
  2061  		// WHEN
  2062  		actual, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.AppTemplateLabelableObject, labelIDs)
  2063  		// THEN
  2064  		require.NoError(t, err)
  2065  		assert.Equal(t, expected, actual)
  2066  	})
  2067  
  2068  	t.Run("Error - Doesn't exist", func(t *testing.T) {
  2069  		mockConverter := &automock.Converter{}
  2070  		defer mockConverter.AssertExpectations(t)
  2071  
  2072  		labelRepo := label.NewRepository(mockConverter)
  2073  
  2074  		db, dbMock := testdb.MockDatabase(t)
  2075  		defer dbMock.AssertExpectations(t)
  2076  
  2077  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_id IN ($1, $2) AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3))`)
  2078  		mockedRows := sqlmock.NewRows(fixColumns)
  2079  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}, tenantID).WillReturnRows(mockedRows)
  2080  
  2081  		ctx := context.TODO()
  2082  		ctx = persistence.SaveToContext(ctx, db)
  2083  		// WHEN
  2084  		actual, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.ApplicationLabelableObject, labelIDs)
  2085  		// THEN
  2086  		require.NoError(t, err)
  2087  		assert.Empty(t, actual)
  2088  	})
  2089  
  2090  	t.Run("Error - Select error", func(t *testing.T) {
  2091  		labelRepo := label.NewRepository(nil)
  2092  		db, dbMock := testdb.MockDatabase(t)
  2093  		defer dbMock.AssertExpectations(t)
  2094  
  2095  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_id IN ($1, $2) AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3))`)
  2096  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}, tenantID).WillReturnError(errors.New("persistence error"))
  2097  
  2098  		ctx := context.TODO()
  2099  		ctx = persistence.SaveToContext(ctx, db)
  2100  		// WHEN
  2101  		_, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.ApplicationLabelableObject, labelIDs)
  2102  		// THEN
  2103  		require.Error(t, err)
  2104  		require.Contains(t, err.Error(), "Unexpected error while executing SQL query")
  2105  	})
  2106  
  2107  	t.Run("Error - Select error on global lister", func(t *testing.T) {
  2108  		labelRepo := label.NewRepository(nil)
  2109  		db, dbMock := testdb.MockDatabase(t)
  2110  		defer dbMock.AssertExpectations(t)
  2111  
  2112  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_template_id IN ($1, $2)`)
  2113  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}).WillReturnError(errors.New("persistence error"))
  2114  
  2115  		ctx := context.TODO()
  2116  		ctx = persistence.SaveToContext(ctx, db)
  2117  		// WHEN
  2118  		_, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.AppTemplateLabelableObject, labelIDs)
  2119  		// THEN
  2120  		require.Error(t, err)
  2121  		require.Contains(t, err.Error(), "Unexpected error while executing SQL query")
  2122  	})
  2123  
  2124  	t.Run("Error - While converting to model", func(t *testing.T) {
  2125  		// GIVEN
  2126  		app1Id := "app-1"
  2127  
  2128  		inputItem := fixEntityLabelWithRefID("1", "foo", model.ApplicationLabelableObject, app1Id)
  2129  		expectedErr := errors.New("converting error")
  2130  
  2131  		mockConverter := &automock.Converter{}
  2132  		defer mockConverter.AssertExpectations(t)
  2133  		mockConverter.On("FromEntity", inputItem).Return(nil, expectedErr).Once()
  2134  
  2135  		labelRepo := label.NewRepository(mockConverter)
  2136  
  2137  		db, dbMock := testdb.MockDatabase(t)
  2138  		defer dbMock.AssertExpectations(t)
  2139  
  2140  		escapedQuery := regexp.QuoteMeta(`SELECT id, tenant_id, app_id, runtime_id, runtime_context_id, app_template_id, key, value, version FROM public.labels WHERE app_id IN ($1, $2) AND (id IN (SELECT id FROM application_labels_tenants WHERE tenant_id = $3))`)
  2141  		mockedRows := sqlmock.NewRows(fixColumns).
  2142  			AddRow(inputItem.ID, inputItem.TenantID, inputItem.AppID, inputItem.RuntimeID, inputItem.RuntimeContextID, inputItem.AppTemplateID, inputItem.Key, inputItem.Value, inputItem.Version)
  2143  		dbMock.ExpectQuery(escapedQuery).WithArgs(sql.NullString{Valid: true, String: labelIDs[0]}, sql.NullString{Valid: true, String: labelIDs[1]}, tenantID).WillReturnRows(mockedRows)
  2144  
  2145  		ctx := context.TODO()
  2146  		ctx = persistence.SaveToContext(ctx, db)
  2147  
  2148  		// WHEN
  2149  		_, err := labelRepo.ListForObjectIDs(ctx, tenantID, model.ApplicationLabelableObject, labelIDs)
  2150  		// THEN
  2151  		require.Error(t, err)
  2152  		require.Contains(t, err.Error(), expectedErr.Error())
  2153  	})
  2154  
  2155  	t.Run("Error - Missing persistence", func(t *testing.T) {
  2156  		// GIVEN
  2157  		labelRepo := label.NewRepository(nil)
  2158  
  2159  		// WHEN
  2160  		_, err := labelRepo.ListForObjectIDs(context.TODO(), tenantID, model.ApplicationLabelableObject, labelIDs)
  2161  		// THEN
  2162  		require.Error(t, err)
  2163  		require.Contains(t, err.Error(), "unable to fetch database from context")
  2164  	})
  2165  
  2166  	t.Run("Returns nil when given no object IDs", func(t *testing.T) {
  2167  		// GIVEN
  2168  		labelRepo := label.NewRepository(nil)
  2169  
  2170  		// WHEN
  2171  		actual, err := labelRepo.ListForObjectIDs(context.TODO(), tenantID, model.ApplicationLabelableObject, []string{})
  2172  		// THEN
  2173  		require.NoError(t, err)
  2174  		require.Nil(t, actual)
  2175  	})
  2176  }