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

     1  package systemfetcher_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/tidwall/gjson"
    12  
    13  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    14  
    15  	"github.com/kyma-incubator/compass/components/director/internal/model"
    16  	"github.com/kyma-incubator/compass/components/director/internal/systemfetcher"
    17  	"github.com/kyma-incubator/compass/components/director/internal/systemfetcher/automock"
    18  	pAutomock "github.com/kyma-incubator/compass/components/director/pkg/persistence/automock"
    19  	"github.com/kyma-incubator/compass/components/director/pkg/persistence/txtest"
    20  	tenantEntity "github.com/kyma-incubator/compass/components/director/pkg/tenant"
    21  	"github.com/stretchr/testify/mock"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  const (
    26  	appType    = "type-1"
    27  	mainURLKey = "mainUrl"
    28  	testID     = "testID"
    29  )
    30  
    31  func TestSyncSystems(t *testing.T) {
    32  	const appTemplateID = "appTmp1"
    33  	testErr := errors.New("testErr")
    34  	setupSuccessfulTemplateRenderer := func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer {
    35  		svc := &automock.TemplateRenderer{}
    36  		for i := range appsInputs {
    37  			svc.On("ApplicationRegisterInputFromTemplate", txtest.CtxWithDBMatcher(), systems[i]).Return(&appsInputs[i], nil).Once()
    38  		}
    39  		return svc
    40  	}
    41  
    42  	var mutex sync.Mutex
    43  	type testCase struct {
    44  		name                     string
    45  		mockTransactioner        func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner)
    46  		fixTestSystems           func() []systemfetcher.System
    47  		fixAppInputs             func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate
    48  		setupTenantSvc           func() *automock.TenantService
    49  		setupTbtSvc              func() *automock.TenantBusinessTypeService
    50  		setupTemplateRendererSvc func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer
    51  		setupSystemSvc           func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService
    52  		setupSystemsSyncSvc      func() *automock.SystemsSyncService
    53  		setupSysAPIClient        func(testSystems []systemfetcher.System) *automock.SystemsAPIClient
    54  		setupDirectorClient      func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient
    55  		verificationTenant       string
    56  		expectedErr              error
    57  	}
    58  	tests := []testCase{
    59  		{
    60  			name: "Success with one tenant and one system",
    61  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
    62  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(3)
    63  				return mockedTx, transactioner
    64  			},
    65  			fixTestSystems: func() []systemfetcher.System {
    66  				systems := fixSystems()
    67  				systems[0].TemplateID = appTemplateID
    68  				systems[0].SystemPayload["productId"] = "TEST"
    69  				return systems
    70  			},
    71  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
    72  				return fixAppsInputsWithTemplatesBySystems(t, systems)
    73  			},
    74  			setupTenantSvc: func() *automock.TenantService {
    75  				tenants := []*model.BusinessTenantMapping{
    76  					newModelBusinessTenantMapping("t1", "tenant1"),
    77  				}
    78  				tenantSvc := &automock.TenantService{}
    79  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
    80  				return tenantSvc
    81  			},
    82  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
    83  				tbtSvc := &automock.TenantBusinessTypeService{}
    84  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
    85  				return tbtSvc
    86  			},
    87  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
    88  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
    89  				systemSvc := &automock.SystemsService{}
    90  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[0].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
    91  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
    92  					BaseEntity: &model.BaseEntity{
    93  						ID: "id",
    94  					},
    95  				}, nil)
    96  				return systemSvc
    97  			},
    98  			setupSystemsSyncSvc: emptySystemsSyncSvc,
    99  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   100  				sysAPIClient := &automock.SystemsAPIClient{}
   101  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   102  				return sysAPIClient
   103  			},
   104  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   105  				return &automock.DirectorClient{}
   106  			},
   107  		},
   108  		{
   109  			name: "Success with one tenant and one system which has tbt and tbt does not exist in the db",
   110  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   111  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(3)
   112  				return mockedTx, transactioner
   113  			},
   114  			fixTestSystems: func() []systemfetcher.System {
   115  				systems := fixSystemsWithTbt()
   116  				systems[0].TemplateID = appTemplateID
   117  				systems[0].SystemPayload["productId"] = "TEST"
   118  				return systems
   119  			},
   120  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   121  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   122  			},
   123  			setupTenantSvc: func() *automock.TenantService {
   124  				tenants := []*model.BusinessTenantMapping{
   125  					newModelBusinessTenantMapping("t1", "tenant1"),
   126  				}
   127  				tenantSvc := &automock.TenantService{}
   128  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   129  				return tenantSvc
   130  			},
   131  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   132  				tbtSvc := &automock.TenantBusinessTypeService{}
   133  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil).Once()
   134  				tbtSvc.On("Create", txtest.CtxWithDBMatcher(), &model.TenantBusinessTypeInput{Code: fixSystemsWithTbt()[0].SystemPayload["businessTypeId"].(string), Name: fixSystemsWithTbt()[0].SystemPayload["businessTypeDescription"].(string)}).Return(testID, nil).Once()
   135  				tbtSvc.On("GetByID", txtest.CtxWithDBMatcher(), testID).Return(&model.TenantBusinessType{ID: testID, Code: fixSystemsWithTbt()[0].SystemPayload["businessTypeId"].(string), Name: fixSystemsWithTbt()[0].SystemPayload["businessTypeDescription"].(string)}, nil).Once()
   136  				return tbtSvc
   137  			},
   138  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
   139  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   140  				systemSvc := &automock.SystemsService{}
   141  				appsInputs[0].ApplicationRegisterInput.TenantBusinessTypeID = str.Ptr(testID)
   142  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[0].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
   143  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   144  					BaseEntity: &model.BaseEntity{
   145  						ID: "id",
   146  					},
   147  				}, nil)
   148  				return systemSvc
   149  			},
   150  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   151  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   152  				sysAPIClient := &automock.SystemsAPIClient{}
   153  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   154  				return sysAPIClient
   155  			},
   156  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   157  				return &automock.DirectorClient{}
   158  			},
   159  		},
   160  		{
   161  			name: "Success with one tenant and one system which has tbt and tbt exists in the db",
   162  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   163  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(3)
   164  				return mockedTx, transactioner
   165  			},
   166  			fixTestSystems: func() []systemfetcher.System {
   167  				systems := fixSystemsWithTbt()
   168  				systems[0].TemplateID = appTemplateID
   169  				systems[0].SystemPayload["productId"] = "TEST"
   170  				return systems
   171  			},
   172  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   173  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   174  			},
   175  			setupTenantSvc: func() *automock.TenantService {
   176  				tenants := []*model.BusinessTenantMapping{
   177  					newModelBusinessTenantMapping("t1", "tenant1"),
   178  				}
   179  				tenantSvc := &automock.TenantService{}
   180  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   181  				return tenantSvc
   182  			},
   183  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   184  				tbtSvc := &automock.TenantBusinessTypeService{}
   185  				systemPayload, err := json.Marshal(fixSystemsWithTbt()[0].SystemPayload)
   186  				require.NoError(t, err)
   187  
   188  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{{ID: testID, Code: gjson.GetBytes(systemPayload, "businessTypeId").String(), Name: gjson.GetBytes(systemPayload, "BusinessTypeDescription").String()}}, nil).Once()
   189  				return tbtSvc
   190  			},
   191  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
   192  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   193  				systemSvc := &automock.SystemsService{}
   194  				appsInputs[0].ApplicationRegisterInput.TenantBusinessTypeID = str.Ptr(testID)
   195  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[0].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
   196  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   197  					BaseEntity: &model.BaseEntity{
   198  						ID: "id",
   199  					},
   200  				}, nil)
   201  				return systemSvc
   202  			},
   203  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   204  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   205  				sysAPIClient := &automock.SystemsAPIClient{}
   206  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   207  				return sysAPIClient
   208  			},
   209  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   210  				return &automock.DirectorClient{}
   211  			},
   212  		},
   213  		{
   214  			name: "Success when in verification mode",
   215  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   216  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(3)
   217  				return mockedTx, transactioner
   218  			},
   219  			fixTestSystems: func() []systemfetcher.System {
   220  				systems := fixSystems()
   221  				systems[0].TemplateID = appTemplateID
   222  				systems[0].SystemPayload["productId"] = "TEST"
   223  				return systems
   224  			},
   225  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   226  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   227  			},
   228  			setupTenantSvc: func() *automock.TenantService {
   229  				tenants := []*model.BusinessTenantMapping{
   230  					newModelBusinessTenantMapping("t1", "tenant1"),
   231  				}
   232  				tenantSvc := &automock.TenantService{}
   233  				tenantSvc.On("GetTenantByExternalID", txtest.CtxWithDBMatcher(), "t1").Return(tenants[0], nil).Once()
   234  				return tenantSvc
   235  			},
   236  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   237  				tbtSvc := &automock.TenantBusinessTypeService{}
   238  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
   239  				return tbtSvc
   240  			},
   241  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
   242  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   243  				systemSvc := &automock.SystemsService{}
   244  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[0].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
   245  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   246  					BaseEntity: &model.BaseEntity{
   247  						ID: "id",
   248  					},
   249  				}, nil)
   250  				return systemSvc
   251  			},
   252  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   253  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   254  				sysAPIClient := &automock.SystemsAPIClient{}
   255  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   256  				return sysAPIClient
   257  			},
   258  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   259  				return &automock.DirectorClient{}
   260  			},
   261  			verificationTenant: "t1",
   262  		},
   263  		{
   264  			name: "Success with one tenant and one system that has already been in the database and will not have it's status condition changed",
   265  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   266  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(3)
   267  				return mockedTx, transactioner
   268  			},
   269  			fixTestSystems: func() []systemfetcher.System {
   270  				systems := fixSystems()
   271  				systems[0].TemplateID = appTemplateID
   272  				systems[0].SystemPayload["productId"] = "TEST"
   273  				return systems
   274  			},
   275  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   276  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   277  			},
   278  			setupTenantSvc: func() *automock.TenantService {
   279  				tenants := []*model.BusinessTenantMapping{
   280  					newModelBusinessTenantMapping("t1", "tenant1"),
   281  				}
   282  				tenantSvc := &automock.TenantService{}
   283  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   284  				return tenantSvc
   285  			},
   286  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   287  				tbtSvc := &automock.TenantBusinessTypeService{}
   288  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
   289  				return tbtSvc
   290  			},
   291  			setupTemplateRendererSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   292  				svc := &automock.TemplateRenderer{}
   293  				connectedStatus := model.ApplicationStatusConditionConnected
   294  
   295  				for i := range appsInputs {
   296  					input := systems[i]
   297  					input.StatusCondition = connectedStatus
   298  
   299  					result := appsInputs[i]
   300  					result.StatusCondition = &connectedStatus
   301  
   302  					svc.On("ApplicationRegisterInputFromTemplate", txtest.CtxWithDBMatcher(), input).Return(&result, nil).Once()
   303  				}
   304  				return svc
   305  			},
   306  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   307  				systemSvc := &automock.SystemsService{}
   308  
   309  				connectedStatus := model.ApplicationStatusConditionConnected
   310  				appInput := appsInputs[0].ApplicationRegisterInput
   311  				appInput.StatusCondition = &connectedStatus
   312  
   313  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appInput, mock.Anything).Return(nil).Once()
   314  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   315  					BaseEntity: &model.BaseEntity{
   316  						ID: "id",
   317  					},
   318  					Status: &model.ApplicationStatus{
   319  						Condition: model.ApplicationStatusConditionConnected,
   320  					},
   321  				}, nil)
   322  				return systemSvc
   323  			},
   324  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   325  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   326  				sysAPIClient := &automock.SystemsAPIClient{}
   327  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   328  				return sysAPIClient
   329  			},
   330  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   331  				return &automock.DirectorClient{}
   332  			},
   333  		},
   334  		{
   335  			name: "Success with one tenant and one system with null base url",
   336  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   337  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(3)
   338  				return mockedTx, transactioner
   339  			},
   340  			fixTestSystems: func() []systemfetcher.System {
   341  				systems := []systemfetcher.System{
   342  					{
   343  						SystemPayload: map[string]interface{}{
   344  							"displayName":            "System1",
   345  							"productDescription":     "System1 description",
   346  							"infrastructureProvider": "test",
   347  						},
   348  						StatusCondition: model.ApplicationStatusConditionInitial,
   349  					},
   350  				}
   351  				systems[0].TemplateID = "type1"
   352  				systems[0].SystemPayload["productId"] = "TEST"
   353  				return systems
   354  			},
   355  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   356  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   357  			},
   358  			setupTenantSvc: func() *automock.TenantService {
   359  				tenants := []*model.BusinessTenantMapping{
   360  					newModelBusinessTenantMapping("t1", "tenant1"),
   361  				}
   362  				tenantSvc := &automock.TenantService{}
   363  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   364  				return tenantSvc
   365  			},
   366  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   367  				tbtSvc := &automock.TenantBusinessTypeService{}
   368  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
   369  				return tbtSvc
   370  			},
   371  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
   372  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   373  				systemSvc := &automock.SystemsService{}
   374  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationRegisterInput"), mock.Anything).Return(nil).Once()
   375  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   376  					BaseEntity: &model.BaseEntity{
   377  						ID: "id",
   378  					},
   379  				}, nil)
   380  				return systemSvc
   381  			},
   382  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   383  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   384  				sysAPIClient := &automock.SystemsAPIClient{}
   385  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   386  				return sysAPIClient
   387  			},
   388  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   389  				return &automock.DirectorClient{}
   390  			},
   391  		},
   392  		{
   393  			name: "Success with one tenant and one system without template",
   394  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   395  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(3)
   396  				return mockedTx, transactioner
   397  			},
   398  			fixTestSystems: fixSystems,
   399  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   400  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   401  			},
   402  			setupTenantSvc: func() *automock.TenantService {
   403  				tenants := []*model.BusinessTenantMapping{
   404  					newModelBusinessTenantMapping("t1", "tenant1"),
   405  				}
   406  				tenantSvc := &automock.TenantService{}
   407  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   408  				return tenantSvc
   409  			},
   410  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   411  				tbtSvc := &automock.TenantBusinessTypeService{}
   412  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
   413  				return tbtSvc
   414  			},
   415  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   416  				return &automock.TemplateRenderer{}
   417  			},
   418  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   419  				systemSvc := &automock.SystemsService{}
   420  				systemSvc.On("TrustedUpsert", txtest.CtxWithDBMatcher(), appsInputs[0].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
   421  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   422  					BaseEntity: &model.BaseEntity{
   423  						ID: "id",
   424  					},
   425  				}, nil)
   426  				return systemSvc
   427  			},
   428  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   429  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   430  				sysAPIClient := &automock.SystemsAPIClient{}
   431  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   432  				return sysAPIClient
   433  			},
   434  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   435  				return &automock.DirectorClient{}
   436  			},
   437  		},
   438  		{
   439  			name: "Success with one tenant and multiple systems",
   440  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   441  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(4)
   442  				return mockedTx, transactioner
   443  			},
   444  			fixTestSystems: func() []systemfetcher.System {
   445  				systems := fixSystems()
   446  				systems[0].TemplateID = appTemplateID
   447  				systems = append(systems, systemfetcher.System{
   448  					SystemPayload: map[string]interface{}{
   449  						"displayName":            "System2",
   450  						"productDescription":     "System2 description",
   451  						"baseUrl":                "http://example2.com",
   452  						"infrastructureProvider": "test",
   453  					},
   454  					TemplateID:      "appTmp2",
   455  					StatusCondition: model.ApplicationStatusConditionInitial,
   456  				})
   457  				return systems
   458  			},
   459  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   460  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   461  			},
   462  			setupTenantSvc: func() *automock.TenantService {
   463  				tenants := []*model.BusinessTenantMapping{
   464  					newModelBusinessTenantMapping("t1", "tenant1"),
   465  				}
   466  				tenantSvc := &automock.TenantService{}
   467  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   468  				return tenantSvc
   469  			},
   470  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   471  				tbtSvc := &automock.TenantBusinessTypeService{}
   472  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
   473  				return tbtSvc
   474  			},
   475  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
   476  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   477  				systemSvc := &automock.SystemsService{}
   478  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[0].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
   479  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[1].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
   480  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   481  					BaseEntity: &model.BaseEntity{
   482  						ID: "id",
   483  					},
   484  				}, nil)
   485  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[1].SystemNumber).Return(&model.Application{
   486  					BaseEntity: &model.BaseEntity{
   487  						ID: "id",
   488  					},
   489  				}, nil)
   490  				return systemSvc
   491  			},
   492  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   493  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   494  				sysAPIClient := &automock.SystemsAPIClient{}
   495  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   496  				return sysAPIClient
   497  			},
   498  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   499  				return &automock.DirectorClient{}
   500  			},
   501  		},
   502  		{
   503  			name: "Success with multiple tenants with one system",
   504  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   505  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(4)
   506  				return mockedTx, transactioner
   507  			},
   508  			fixTestSystems: func() []systemfetcher.System {
   509  				systems := fixSystems()
   510  				systems[0].TemplateID = appTemplateID
   511  				systems = append(systems, systemfetcher.System{
   512  					SystemPayload: map[string]interface{}{
   513  						"displayName":            "System2",
   514  						"productDescription":     "System2 description",
   515  						"baseUrl":                "http://example2.com",
   516  						"infrastructureProvider": "test",
   517  					},
   518  					TemplateID:      "appTmp2",
   519  					StatusCondition: model.ApplicationStatusConditionInitial,
   520  				})
   521  				return systems
   522  			},
   523  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   524  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   525  			},
   526  			setupTenantSvc: func() *automock.TenantService {
   527  				firstTenant := newModelBusinessTenantMapping("t1", "tenant1")
   528  				firstTenant.ExternalTenant = "t1"
   529  				secondTenant := newModelBusinessTenantMapping("t2", "tenant2")
   530  				secondTenant.ExternalTenant = "t2"
   531  				tenants := []*model.BusinessTenantMapping{firstTenant, secondTenant}
   532  				tenantSvc := &automock.TenantService{}
   533  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   534  				return tenantSvc
   535  			},
   536  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   537  				tbtSvc := &automock.TenantBusinessTypeService{}
   538  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
   539  				return tbtSvc
   540  			},
   541  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
   542  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   543  				systemSvc := &automock.SystemsService{}
   544  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[0].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
   545  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[1].ApplicationRegisterInput, mock.Anything).Return(nil).Once()
   546  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   547  					BaseEntity: &model.BaseEntity{
   548  						ID: "id",
   549  					},
   550  				}, nil)
   551  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[1].SystemNumber).Return(&model.Application{
   552  					BaseEntity: &model.BaseEntity{
   553  						ID: "id",
   554  					},
   555  				}, nil)
   556  				return systemSvc
   557  			},
   558  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   559  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   560  				sysAPIClient := &automock.SystemsAPIClient{}
   561  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "t1", &mutex).Return([]systemfetcher.System{testSystems[0]}, nil).Once()
   562  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "t2", &mutex).Return([]systemfetcher.System{testSystems[1]}, nil).Once()
   563  				return sysAPIClient
   564  			},
   565  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   566  				return &automock.DirectorClient{}
   567  			},
   568  		},
   569  		{
   570  			name: "Fail when listing all tenant business types",
   571  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   572  				persistTx := &pAutomock.PersistenceTx{}
   573  				persistTx.On("Commit").Return(nil).Once()
   574  
   575  				transact := &pAutomock.Transactioner{}
   576  				transact.On("Begin").Return(persistTx, nil).Twice()
   577  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Once()
   578  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(true).Once()
   579  
   580  				return persistTx, transact
   581  			},
   582  			fixTestSystems: func() []systemfetcher.System {
   583  				return fixSystemsWithTbt()
   584  			},
   585  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   586  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   587  			},
   588  			setupTenantSvc: func() *automock.TenantService {
   589  				tenants := []*model.BusinessTenantMapping{
   590  					newModelBusinessTenantMapping("t1", "tenant1"),
   591  				}
   592  				tenantSvc := &automock.TenantService{}
   593  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   594  				return tenantSvc
   595  			},
   596  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   597  				tbtSvc := &automock.TenantBusinessTypeService{}
   598  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return(nil, testErr).Once()
   599  				return tbtSvc
   600  			},
   601  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   602  				return &automock.TemplateRenderer{}
   603  			},
   604  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   605  				return &automock.SystemsService{}
   606  			},
   607  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   608  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   609  				return &automock.SystemsAPIClient{}
   610  			},
   611  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   612  				return &automock.DirectorClient{}
   613  			},
   614  			expectedErr: testErr,
   615  		},
   616  		{
   617  			name: "Begin transaction fails when listing all tenant business types",
   618  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   619  				persistTx := &pAutomock.PersistenceTx{}
   620  				persistTx.On("Commit").Return(nil).Once()
   621  
   622  				transact := &pAutomock.Transactioner{}
   623  				transact.On("Begin").Return(persistTx, nil).Once()
   624  				transact.On("Begin").Return(persistTx, testErr).Once()
   625  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Once()
   626  
   627  				return persistTx, transact
   628  			},
   629  			fixTestSystems: func() []systemfetcher.System {
   630  				return fixSystemsWithTbt()
   631  			},
   632  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   633  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   634  			},
   635  			setupTenantSvc: func() *automock.TenantService {
   636  				tenants := []*model.BusinessTenantMapping{
   637  					newModelBusinessTenantMapping("t1", "tenant1"),
   638  				}
   639  				tenantSvc := &automock.TenantService{}
   640  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   641  				return tenantSvc
   642  			},
   643  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   644  				return &automock.TenantBusinessTypeService{}
   645  			},
   646  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   647  				return &automock.TemplateRenderer{}
   648  			},
   649  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   650  				return &automock.SystemsService{}
   651  			},
   652  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   653  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   654  				return &automock.SystemsAPIClient{}
   655  			},
   656  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   657  				return &automock.DirectorClient{}
   658  			},
   659  			expectedErr: testErr,
   660  		},
   661  		{
   662  			name: "Commit transaction fails when listing all tenant business types",
   663  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   664  				persistTx := &pAutomock.PersistenceTx{}
   665  				persistTx.On("Commit").Return(nil).Once()
   666  				persistTx.On("Commit").Return(testErr).Once()
   667  
   668  				transact := &pAutomock.Transactioner{}
   669  				transact.On("Begin").Return(persistTx, nil).Twice()
   670  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Once()
   671  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(true).Once()
   672  
   673  				return persistTx, transact
   674  			},
   675  			fixTestSystems: func() []systemfetcher.System {
   676  				return fixSystemsWithTbt()
   677  			},
   678  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   679  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   680  			},
   681  			setupTenantSvc: func() *automock.TenantService {
   682  				tenants := []*model.BusinessTenantMapping{
   683  					newModelBusinessTenantMapping("t1", "tenant1"),
   684  				}
   685  				tenantSvc := &automock.TenantService{}
   686  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   687  				return tenantSvc
   688  			},
   689  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   690  				tbtSvc := &automock.TenantBusinessTypeService{}
   691  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{{ID: testID, Code: fixSystemsWithTbt()[0].SystemPayload["businessTypeId"].(string), Name: fixSystemsWithTbt()[0].SystemPayload["businessTypeDescription"].(string)}}, nil).Once()
   692  				return tbtSvc
   693  			},
   694  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   695  				return &automock.TemplateRenderer{}
   696  			},
   697  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   698  				return &automock.SystemsService{}
   699  			},
   700  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   701  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   702  				return &automock.SystemsAPIClient{}
   703  			},
   704  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   705  				return &automock.DirectorClient{}
   706  			},
   707  			expectedErr: testErr,
   708  		},
   709  		{
   710  			name: "Fails when creating new tenant business type",
   711  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   712  				persistTx := &pAutomock.PersistenceTx{}
   713  				persistTx.On("Commit").Return(nil).Twice()
   714  
   715  				transact := &pAutomock.Transactioner{}
   716  				transact.On("Begin").Return(persistTx, nil).Times(3)
   717  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Twice()
   718  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(true).Once()
   719  
   720  				return persistTx, transact
   721  			},
   722  			fixTestSystems: func() []systemfetcher.System {
   723  				return fixSystemsWithTbt()
   724  			},
   725  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   726  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   727  			},
   728  			setupTenantSvc: func() *automock.TenantService {
   729  				tenants := []*model.BusinessTenantMapping{
   730  					newModelBusinessTenantMapping("t1", "tenant1"),
   731  				}
   732  				tenantSvc := &automock.TenantService{}
   733  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   734  				return tenantSvc
   735  			},
   736  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   737  				tbtSvc := &automock.TenantBusinessTypeService{}
   738  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil).Once()
   739  				tbtSvc.On("Create", txtest.CtxWithDBMatcher(), &model.TenantBusinessTypeInput{Code: fixSystemsWithTbt()[0].SystemPayload["businessTypeId"].(string), Name: fixSystemsWithTbt()[0].SystemPayload["businessTypeDescription"].(string)}).Return("", testErr).Once()
   740  				return tbtSvc
   741  			},
   742  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   743  				return &automock.TemplateRenderer{}
   744  			},
   745  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   746  				systemSvc := &automock.SystemsService{}
   747  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   748  					BaseEntity: &model.BaseEntity{
   749  						ID: "id",
   750  					},
   751  				}, nil)
   752  				return systemSvc
   753  			},
   754  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   755  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   756  				sysAPIClient := &automock.SystemsAPIClient{}
   757  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   758  				return sysAPIClient
   759  			},
   760  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   761  				return &automock.DirectorClient{}
   762  			},
   763  		},
   764  		{
   765  			name: "Fails when getting by id newly created tenant business type",
   766  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   767  				persistTx := &pAutomock.PersistenceTx{}
   768  				persistTx.On("Commit").Return(nil).Twice()
   769  
   770  				transact := &pAutomock.Transactioner{}
   771  				transact.On("Begin").Return(persistTx, nil).Times(3)
   772  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(false).Twice()
   773  				transact.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(true).Once()
   774  
   775  				return persistTx, transact
   776  			},
   777  			fixTestSystems: func() []systemfetcher.System {
   778  				return fixSystemsWithTbt()
   779  			},
   780  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   781  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   782  			},
   783  			setupTenantSvc: func() *automock.TenantService {
   784  				tenants := []*model.BusinessTenantMapping{
   785  					newModelBusinessTenantMapping("t1", "tenant1"),
   786  				}
   787  				tenantSvc := &automock.TenantService{}
   788  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   789  				return tenantSvc
   790  			},
   791  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   792  				tbtSvc := &automock.TenantBusinessTypeService{}
   793  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil).Once()
   794  				tbtSvc.On("Create", txtest.CtxWithDBMatcher(), &model.TenantBusinessTypeInput{Code: fixSystemsWithTbt()[0].SystemPayload["businessTypeId"].(string), Name: fixSystemsWithTbt()[0].SystemPayload["businessTypeDescription"].(string)}).Return(testID, nil).Once()
   795  				tbtSvc.On("GetByID", txtest.CtxWithDBMatcher(), testID).Return(nil, testErr).Once()
   796  				return tbtSvc
   797  			},
   798  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   799  				return &automock.TemplateRenderer{}
   800  			},
   801  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   802  				systemSvc := &automock.SystemsService{}
   803  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
   804  					BaseEntity: &model.BaseEntity{
   805  						ID: "id",
   806  					},
   807  				}, nil)
   808  				return systemSvc
   809  			},
   810  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   811  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   812  				sysAPIClient := &automock.SystemsAPIClient{}
   813  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(testSystems, nil).Once()
   814  				return sysAPIClient
   815  			},
   816  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   817  				return &automock.DirectorClient{}
   818  			},
   819  		},
   820  		{
   821  			name: "Fail when tenant fetching fails",
   822  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   823  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit()
   824  
   825  				return mockedTx, transactioner
   826  			},
   827  			fixTestSystems: fixSystems,
   828  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   829  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   830  			},
   831  			setupTenantSvc: func() *automock.TenantService {
   832  				tenantSvc := &automock.TenantService{}
   833  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(nil, testErr).Once()
   834  				return tenantSvc
   835  			},
   836  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   837  				return &automock.TenantBusinessTypeService{}
   838  			},
   839  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   840  				return &automock.TemplateRenderer{}
   841  			},
   842  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   843  				return &automock.SystemsService{}
   844  			},
   845  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   846  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   847  				return &automock.SystemsAPIClient{}
   848  			},
   849  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   850  				return &automock.DirectorClient{}
   851  			},
   852  			expectedErr: testErr,
   853  		},
   854  		{
   855  			name: "Fail when transaction cannot be started",
   856  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   857  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(testErr).ThatFailsOnBegin()
   858  
   859  				return mockedTx, transactioner
   860  			},
   861  			fixTestSystems: fixSystems,
   862  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   863  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   864  			},
   865  			setupTenantSvc: func() *automock.TenantService {
   866  				return &automock.TenantService{}
   867  			},
   868  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   869  				return &automock.TenantBusinessTypeService{}
   870  			},
   871  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   872  				return &automock.TemplateRenderer{}
   873  			},
   874  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   875  				return &automock.SystemsService{}
   876  			},
   877  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   878  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   879  				return &automock.SystemsAPIClient{}
   880  			},
   881  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   882  				return &automock.DirectorClient{}
   883  			},
   884  			expectedErr: testErr,
   885  		},
   886  		{
   887  			name: "Fail when commit fails",
   888  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   889  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(testErr).ThatFailsOnCommit()
   890  				return mockedTx, transactioner
   891  			},
   892  			fixTestSystems: func() []systemfetcher.System {
   893  				systems := fixSystems()
   894  				systems[0].TemplateID = appTemplateID
   895  				return systems
   896  			},
   897  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   898  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   899  			},
   900  			setupTenantSvc: func() *automock.TenantService {
   901  				tenants := []*model.BusinessTenantMapping{
   902  					newModelBusinessTenantMapping("t1", "tenant1"),
   903  				}
   904  				tenantSvc := &automock.TenantService{}
   905  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   906  				return tenantSvc
   907  			},
   908  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   909  				return &automock.TenantBusinessTypeService{}
   910  			},
   911  			setupTemplateRendererSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   912  				return &automock.TemplateRenderer{}
   913  			},
   914  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   915  				return &automock.SystemsService{}
   916  			},
   917  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   918  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   919  				return &automock.SystemsAPIClient{}
   920  			},
   921  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   922  				return &automock.DirectorClient{}
   923  			},
   924  			expectedErr: testErr,
   925  		},
   926  		{
   927  			name: "Fail when client fails to fetch systems",
   928  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   929  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(2)
   930  
   931  				return mockedTx, transactioner
   932  			},
   933  			fixTestSystems: func() []systemfetcher.System {
   934  				return fixSystems()
   935  			},
   936  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   937  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   938  			},
   939  			setupTenantSvc: func() *automock.TenantService {
   940  				tenants := []*model.BusinessTenantMapping{
   941  					newModelBusinessTenantMapping("t1", "tenant1"),
   942  				}
   943  				tenantSvc := &automock.TenantService{}
   944  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   945  				return tenantSvc
   946  			},
   947  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   948  				tbtSvc := &automock.TenantBusinessTypeService{}
   949  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
   950  				return tbtSvc
   951  			},
   952  			setupTemplateRendererSvc: func(_ []systemfetcher.System, _ []model.ApplicationRegisterInput) *automock.TemplateRenderer {
   953  				return &automock.TemplateRenderer{}
   954  			},
   955  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
   956  				return &automock.SystemsService{}
   957  			},
   958  			setupSystemsSyncSvc: emptySystemsSyncSvc,
   959  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
   960  				sysAPIClient := &automock.SystemsAPIClient{}
   961  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(nil, errors.New("expected")).Once()
   962  				return sysAPIClient
   963  			},
   964  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
   965  				return &automock.DirectorClient{}
   966  			},
   967  		},
   968  		{
   969  			name: "Fail when service fails to save systems",
   970  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
   971  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(2)
   972  				persistTx := &pAutomock.PersistenceTx{}
   973  
   974  				transactioner.On("Begin").Return(persistTx, nil).Once()
   975  				persistTx.On("Commit").Return(nil).Once()
   976  				transactioner.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(true).Once()
   977  
   978  				return mockedTx, transactioner
   979  			},
   980  			fixTestSystems: func() []systemfetcher.System {
   981  				systems := fixSystems()
   982  				systems[0].TemplateID = appTemplateID
   983  				return systems
   984  			},
   985  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
   986  				return fixAppsInputsWithTemplatesBySystems(t, systems)
   987  			},
   988  			setupTenantSvc: func() *automock.TenantService {
   989  				tenants := []*model.BusinessTenantMapping{
   990  					newModelBusinessTenantMapping("t1", "tenant1"),
   991  				}
   992  				tenantSvc := &automock.TenantService{}
   993  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
   994  				return tenantSvc
   995  			},
   996  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
   997  				tbtSvc := &automock.TenantBusinessTypeService{}
   998  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
   999  				return tbtSvc
  1000  			},
  1001  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
  1002  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
  1003  				systemSvc := &automock.SystemsService{}
  1004  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), appsInputs[0].ApplicationRegisterInput, mock.Anything).Return(errors.New("expected")).Once()
  1005  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
  1006  					BaseEntity: &model.BaseEntity{
  1007  						ID: "id",
  1008  					},
  1009  				}, nil)
  1010  				return systemSvc
  1011  			},
  1012  			setupSystemsSyncSvc: emptySystemsSyncSvc,
  1013  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
  1014  				sysAPIClient := &automock.SystemsAPIClient{}
  1015  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return([]systemfetcher.System{testSystems[0]}, nil).Once()
  1016  				return sysAPIClient
  1017  			},
  1018  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
  1019  				return &automock.DirectorClient{}
  1020  			},
  1021  		},
  1022  		{
  1023  			name: "Fail when application from template cannot be rendered",
  1024  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
  1025  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(2)
  1026  				persistTx := &pAutomock.PersistenceTx{}
  1027  
  1028  				transactioner.On("Begin").Return(persistTx, nil).Once()
  1029  				transactioner.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(true).Once()
  1030  
  1031  				return mockedTx, transactioner
  1032  			},
  1033  			fixTestSystems: func() []systemfetcher.System {
  1034  				systems := fixSystems()
  1035  				systems[0].TemplateID = appTemplateID
  1036  				return systems
  1037  			},
  1038  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
  1039  				return fixAppsInputsWithTemplatesBySystems(t, systems)
  1040  			},
  1041  			setupTenantSvc: func() *automock.TenantService {
  1042  				tenants := []*model.BusinessTenantMapping{
  1043  					newModelBusinessTenantMapping("t1", "tenant1"),
  1044  				}
  1045  				tenantSvc := &automock.TenantService{}
  1046  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
  1047  				return tenantSvc
  1048  			},
  1049  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
  1050  				tbtSvc := &automock.TenantBusinessTypeService{}
  1051  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
  1052  				return tbtSvc
  1053  			},
  1054  			setupTemplateRendererSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer {
  1055  				svc := &automock.TemplateRenderer{}
  1056  				for i := range appsInputs {
  1057  					svc.On("ApplicationRegisterInputFromTemplate", txtest.CtxWithDBMatcher(), systems[i]).Return(nil, testErr).Once()
  1058  				}
  1059  				return svc
  1060  			},
  1061  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
  1062  				systemSvc := &automock.SystemsService{}
  1063  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
  1064  					BaseEntity: &model.BaseEntity{
  1065  						ID: "id",
  1066  					},
  1067  				}, nil)
  1068  
  1069  				return systemSvc
  1070  			},
  1071  			setupSystemsSyncSvc: emptySystemsSyncSvc,
  1072  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
  1073  				sysAPIClient := &automock.SystemsAPIClient{}
  1074  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return([]systemfetcher.System{testSystems[0]}, nil).Once()
  1075  				return sysAPIClient
  1076  			},
  1077  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
  1078  				return &automock.DirectorClient{}
  1079  			},
  1080  		},
  1081  		{
  1082  			name: "Succeed when client fails to fetch systems only for some tenants",
  1083  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
  1084  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(4)
  1085  
  1086  				return mockedTx, transactioner
  1087  			},
  1088  			fixTestSystems: func() []systemfetcher.System {
  1089  				systems := fixSystems()
  1090  				systems[0].TemplateID = "type1"
  1091  				systems = append(systems, systemfetcher.System{
  1092  					SystemPayload: map[string]interface{}{
  1093  						"displayName":            "System2",
  1094  						"productDescription":     "System2 description",
  1095  						"baseUrl":                "http://example2.com",
  1096  						"infrastructureProvider": "test",
  1097  					},
  1098  					TemplateID:      "type2",
  1099  					StatusCondition: model.ApplicationStatusConditionInitial,
  1100  				})
  1101  				return systems
  1102  			},
  1103  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
  1104  				return fixAppsInputsWithTemplatesBySystems(t, systems)
  1105  			},
  1106  			setupTenantSvc: func() *automock.TenantService {
  1107  				tenants := []*model.BusinessTenantMapping{
  1108  					newModelBusinessTenantMapping("t1", "tenant1"),
  1109  					newModelBusinessTenantMapping("t2", "tenant2"),
  1110  					newModelBusinessTenantMapping("t3", "tenant3"),
  1111  				}
  1112  				tenantSvc := &automock.TenantService{}
  1113  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
  1114  				return tenantSvc
  1115  			},
  1116  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
  1117  				tbtSvc := &automock.TenantBusinessTypeService{}
  1118  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
  1119  				return tbtSvc
  1120  			},
  1121  			setupTemplateRendererSvc: setupSuccessfulTemplateRenderer,
  1122  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
  1123  				systemSvc := &automock.SystemsService{}
  1124  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationRegisterInput"), mock.Anything).Return(nil).Once()
  1125  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationRegisterInput"), mock.Anything).Return(nil).Once()
  1126  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
  1127  					BaseEntity: &model.BaseEntity{
  1128  						ID: "id",
  1129  					},
  1130  				}, nil)
  1131  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[1].SystemNumber).Return(&model.Application{
  1132  					BaseEntity: &model.BaseEntity{
  1133  						ID: "id",
  1134  					},
  1135  				}, nil)
  1136  				return systemSvc
  1137  			},
  1138  			setupSystemsSyncSvc: emptySystemsSyncSvc,
  1139  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
  1140  				sysAPIClient := &automock.SystemsAPIClient{}
  1141  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return([]systemfetcher.System{testSystems[0]}, nil).Once()
  1142  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return(nil, errors.New("expected")).Once()
  1143  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "external", &mutex).Return([]systemfetcher.System{testSystems[1]}, nil).Once()
  1144  				return sysAPIClient
  1145  			},
  1146  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
  1147  				return &automock.DirectorClient{}
  1148  			},
  1149  		},
  1150  		{
  1151  			name: "Do nothing if system is already being deleted",
  1152  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
  1153  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(2)
  1154  				persistTx := &pAutomock.PersistenceTx{}
  1155  
  1156  				transactioner.On("Begin").Return(persistTx, nil).Twice()
  1157  				persistTx.On("Commit").Return(nil).Once()
  1158  				transactioner.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(true).Twice()
  1159  
  1160  				return mockedTx, transactioner
  1161  			},
  1162  			fixTestSystems: func() []systemfetcher.System {
  1163  				systems := fixSystems()
  1164  				systems[0].TemplateID = "type1"
  1165  				systems = append(systems, systemfetcher.System{
  1166  					SystemPayload: map[string]interface{}{
  1167  						"displayName":            "System2",
  1168  						"productDescription":     "System2 description",
  1169  						"baseUrl":                "http://example2.com",
  1170  						"infrastructureProvider": "test",
  1171  						"additionalAttributes": map[string]string{
  1172  							systemfetcher.LifecycleAttributeName: systemfetcher.LifecycleDeleted,
  1173  						},
  1174  						"systemNumber": "sysNumber1",
  1175  					},
  1176  					TemplateID:      "type2",
  1177  					StatusCondition: model.ApplicationStatusConditionInitial,
  1178  				})
  1179  				return systems
  1180  			},
  1181  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
  1182  				return fixAppsInputsWithTemplatesBySystems(t, systems)
  1183  			},
  1184  			setupTenantSvc: func() *automock.TenantService {
  1185  				firstTenant := newModelBusinessTenantMapping("t1", "tenant1")
  1186  				firstTenant.ExternalTenant = "t1"
  1187  				secondTenant := newModelBusinessTenantMapping("t2", "tenant2")
  1188  				secondTenant.ExternalTenant = "t2"
  1189  				tenants := []*model.BusinessTenantMapping{firstTenant, secondTenant}
  1190  				tenantSvc := &automock.TenantService{}
  1191  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
  1192  				return tenantSvc
  1193  			},
  1194  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
  1195  				tbtSvc := &automock.TenantBusinessTypeService{}
  1196  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
  1197  				return tbtSvc
  1198  			},
  1199  			setupTemplateRendererSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer {
  1200  				svc := &automock.TemplateRenderer{}
  1201  				appInput := appsInputs[0] // appsInputs[1] belongs to a system with status "DELETED"
  1202  				svc.On("ApplicationRegisterInputFromTemplate", txtest.CtxWithDBMatcher(), systems[0]).Return(&appInput, nil)
  1203  				return svc
  1204  			},
  1205  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
  1206  				systemSvc := &automock.SystemsService{}
  1207  
  1208  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationRegisterInput"), mock.Anything).Return(nil).Once()
  1209  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
  1210  					BaseEntity: &model.BaseEntity{
  1211  						ID: "id",
  1212  					},
  1213  				}, nil)
  1214  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[1].SystemNumber).Return(&model.Application{
  1215  					BaseEntity: &model.BaseEntity{
  1216  						ID: "id",
  1217  					},
  1218  				}, nil)
  1219  				return systemSvc
  1220  			},
  1221  			setupSystemsSyncSvc: emptySystemsSyncSvc,
  1222  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
  1223  				sysAPIClient := &automock.SystemsAPIClient{}
  1224  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "t1", &mutex).Return([]systemfetcher.System{testSystems[0]}, nil).Once()
  1225  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "t2", &mutex).Return([]systemfetcher.System{testSystems[1]}, nil).Once()
  1226  				return sysAPIClient
  1227  			},
  1228  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
  1229  				directorClient := &automock.DirectorClient{}
  1230  				directorClient.On("DeleteSystemAsync", mock.Anything, "id", "t2").Return(nil).Once()
  1231  				return directorClient
  1232  			},
  1233  		},
  1234  		{
  1235  			name: "Do nothing if system has already been deleted",
  1236  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
  1237  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(2)
  1238  				persistTx := &pAutomock.PersistenceTx{}
  1239  
  1240  				transactioner.On("Begin").Return(persistTx, nil).Twice()
  1241  				persistTx.On("Commit").Return(nil).Once()
  1242  				transactioner.On("RollbackUnlessCommitted", mock.Anything, persistTx).Return(true).Twice()
  1243  
  1244  				return mockedTx, transactioner
  1245  			},
  1246  			fixTestSystems: func() []systemfetcher.System {
  1247  				systems := fixSystems()
  1248  				systems[0].TemplateID = "type1"
  1249  				systems = append(systems, systemfetcher.System{
  1250  					SystemPayload: map[string]interface{}{
  1251  						"displayName":            "System2",
  1252  						"productDescription":     "System2 description",
  1253  						"baseUrl":                "http://example2.com",
  1254  						"infrastructureProvider": "test",
  1255  						"additionalAttributes": map[string]string{
  1256  							systemfetcher.LifecycleAttributeName: systemfetcher.LifecycleDeleted,
  1257  						},
  1258  						"systemNumber": "sysNumber1",
  1259  					},
  1260  					TemplateID:      "type2",
  1261  					StatusCondition: model.ApplicationStatusConditionInitial,
  1262  				})
  1263  				return systems
  1264  			},
  1265  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
  1266  				return fixAppsInputsWithTemplatesBySystems(t, systems)
  1267  			},
  1268  			setupTenantSvc: func() *automock.TenantService {
  1269  				firstTenant := newModelBusinessTenantMapping("t1", "tenant1")
  1270  				firstTenant.ExternalTenant = "t1"
  1271  				secondTenant := newModelBusinessTenantMapping("t2", "tenant2")
  1272  				secondTenant.ExternalTenant = "t2"
  1273  				tenants := []*model.BusinessTenantMapping{firstTenant, secondTenant}
  1274  				tenantSvc := &automock.TenantService{}
  1275  				tenantSvc.On("ListByType", txtest.CtxWithDBMatcher(), tenantEntity.Account).Return(tenants, nil).Once()
  1276  				return tenantSvc
  1277  			},
  1278  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
  1279  				tbtSvc := &automock.TenantBusinessTypeService{}
  1280  				tbtSvc.On("ListAll", txtest.CtxWithDBMatcher()).Return([]*model.TenantBusinessType{}, nil)
  1281  				return tbtSvc
  1282  			},
  1283  			setupTemplateRendererSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer {
  1284  				svc := &automock.TemplateRenderer{}
  1285  				appInput := appsInputs[0] // appsInputs[1] belongs to a system with status "DELETED"
  1286  				svc.On("ApplicationRegisterInputFromTemplate", txtest.CtxWithDBMatcher(), systems[0]).Return(&appInput, nil)
  1287  				return svc
  1288  			},
  1289  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
  1290  				systemSvc := &automock.SystemsService{}
  1291  
  1292  				systemSvc.On("TrustedUpsertFromTemplate", txtest.CtxWithDBMatcher(), mock.AnythingOfType("model.ApplicationRegisterInput"), mock.Anything).Return(nil).Once()
  1293  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[0].SystemNumber).Return(&model.Application{
  1294  					BaseEntity: &model.BaseEntity{
  1295  						ID: "id",
  1296  					},
  1297  				}, nil)
  1298  				systemSvc.On("GetBySystemNumber", txtest.CtxWithDBMatcher(), *appsInputs[1].SystemNumber).Return(nil, nil)
  1299  				return systemSvc
  1300  			},
  1301  			setupSystemsSyncSvc: emptySystemsSyncSvc,
  1302  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
  1303  				sysAPIClient := &automock.SystemsAPIClient{}
  1304  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "t1", &mutex).Return([]systemfetcher.System{testSystems[0]}, nil).Once()
  1305  				sysAPIClient.On("FetchSystemsForTenant", mock.Anything, "t2", &mutex).Return([]systemfetcher.System{testSystems[1]}, nil).Once()
  1306  				return sysAPIClient
  1307  			},
  1308  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
  1309  				directorClient := &automock.DirectorClient{}
  1310  				directorClient.On("DeleteSystemAsync", mock.Anything, "id", "t2").Return(nil).Once()
  1311  				return directorClient
  1312  			},
  1313  		},
  1314  	}
  1315  
  1316  	for _, testCase := range tests {
  1317  		t.Run(testCase.name, func(t *testing.T) {
  1318  			mockedTx, transactioner := testCase.mockTransactioner()
  1319  			tenantSvc := testCase.setupTenantSvc()
  1320  			tbtSvc := testCase.setupTbtSvc()
  1321  			testSystems := testCase.fixTestSystems()
  1322  			appsInputs := testCase.fixAppInputs(testSystems)
  1323  			systemSvc := testCase.setupSystemSvc(testSystems, appsInputs)
  1324  			systemsSyncSvc := testCase.setupSystemsSyncSvc()
  1325  			appInputsWithoutTemplates := make([]model.ApplicationRegisterInput, 0)
  1326  			for _, in := range appsInputs {
  1327  				appInputsWithoutTemplates = append(appInputsWithoutTemplates, in.ApplicationRegisterInput)
  1328  			}
  1329  			templateAppResolver := testCase.setupTemplateRendererSvc(testSystems, appInputsWithoutTemplates)
  1330  			sysAPIClient := testCase.setupSysAPIClient(testSystems)
  1331  			directorClient := testCase.setupDirectorClient(testSystems, appsInputs)
  1332  			defer mock.AssertExpectationsForObjects(t, tenantSvc, tbtSvc, sysAPIClient, systemSvc, templateAppResolver, mockedTx, transactioner)
  1333  
  1334  			svc := systemfetcher.NewSystemFetcher(transactioner, tenantSvc, systemSvc, systemsSyncSvc, tbtSvc, templateAppResolver, sysAPIClient, directorClient, systemfetcher.Config{
  1335  				SystemsQueueSize:     100,
  1336  				FetcherParallellism:  30,
  1337  				EnableSystemDeletion: true,
  1338  				VerifyTenant:         testCase.verificationTenant,
  1339  			})
  1340  
  1341  			err := svc.SyncSystems(context.TODO())
  1342  			if testCase.expectedErr != nil {
  1343  				require.ErrorIs(t, err, testCase.expectedErr)
  1344  			} else {
  1345  				require.NoError(t, err)
  1346  			}
  1347  		})
  1348  	}
  1349  }
  1350  
  1351  func TestUpsertSystemsSyncTimestamps(t *testing.T) {
  1352  	testError := errors.New("testError")
  1353  
  1354  	systemfetcher.SystemSynchronizationTimestamps = map[string]map[string]systemfetcher.SystemSynchronizationTimestamp{
  1355  		"t": {
  1356  			"type1": {
  1357  				ID:                "time",
  1358  				LastSyncTimestamp: time.Date(2023, 5, 2, 20, 30, 0, 0, time.UTC).UTC(),
  1359  			},
  1360  		},
  1361  	}
  1362  
  1363  	type testCase struct {
  1364  		name                     string
  1365  		mockTransactioner        func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner)
  1366  		fixTestSystems           func() []systemfetcher.System
  1367  		fixAppInputs             func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate
  1368  		setupTenantSvc           func() *automock.TenantService
  1369  		setupTbtSvc              func() *automock.TenantBusinessTypeService
  1370  		setupTemplateRendererSvc func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer
  1371  		setupSystemSvc           func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService
  1372  		setupSystemsSyncSvc      func() *automock.SystemsSyncService
  1373  		setupSysAPIClient        func(testSystems []systemfetcher.System) *automock.SystemsAPIClient
  1374  		setupDirectorClient      func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient
  1375  		verificationTenant       string
  1376  		expectedErr              error
  1377  	}
  1378  
  1379  	tests := []testCase{
  1380  		{
  1381  			name: "Success",
  1382  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
  1383  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatSucceedsMultipleTimes(1)
  1384  				return mockedTx, transactioner
  1385  			},
  1386  			fixTestSystems: func() []systemfetcher.System {
  1387  				return []systemfetcher.System{}
  1388  			},
  1389  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
  1390  				return []model.ApplicationRegisterInputWithTemplate{}
  1391  			},
  1392  			setupTenantSvc: func() *automock.TenantService {
  1393  				return &automock.TenantService{}
  1394  			},
  1395  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
  1396  				return &automock.TenantBusinessTypeService{}
  1397  			},
  1398  			setupTemplateRendererSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer {
  1399  				return &automock.TemplateRenderer{}
  1400  			},
  1401  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
  1402  				return &automock.SystemsService{}
  1403  			},
  1404  			setupSystemsSyncSvc: func() *automock.SystemsSyncService {
  1405  				syncMock := &automock.SystemsSyncService{}
  1406  				syncMock.On("Upsert", mock.Anything, mock.Anything).Return(nil)
  1407  				return syncMock
  1408  			},
  1409  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
  1410  				return &automock.SystemsAPIClient{}
  1411  			},
  1412  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
  1413  				return &automock.DirectorClient{}
  1414  			},
  1415  		},
  1416  		{
  1417  			name: "Error while upserting",
  1418  			mockTransactioner: func() (*pAutomock.PersistenceTx, *pAutomock.Transactioner) {
  1419  				mockedTx, transactioner := txtest.NewTransactionContextGenerator(nil).ThatDoesntExpectCommit()
  1420  				return mockedTx, transactioner
  1421  			},
  1422  			fixTestSystems: func() []systemfetcher.System {
  1423  				return []systemfetcher.System{}
  1424  			},
  1425  			fixAppInputs: func(systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
  1426  				return []model.ApplicationRegisterInputWithTemplate{}
  1427  			},
  1428  			setupTenantSvc: func() *automock.TenantService {
  1429  				return &automock.TenantService{}
  1430  			},
  1431  			setupTbtSvc: func() *automock.TenantBusinessTypeService {
  1432  				return &automock.TenantBusinessTypeService{}
  1433  			},
  1434  			setupTemplateRendererSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInput) *automock.TemplateRenderer {
  1435  				return &automock.TemplateRenderer{}
  1436  			},
  1437  			setupSystemSvc: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.SystemsService {
  1438  				return &automock.SystemsService{}
  1439  			},
  1440  			setupSystemsSyncSvc: func() *automock.SystemsSyncService {
  1441  				syncMock := &automock.SystemsSyncService{}
  1442  				syncMock.On("Upsert", mock.Anything, mock.Anything).Return(testError)
  1443  				return syncMock
  1444  			},
  1445  			setupSysAPIClient: func(testSystems []systemfetcher.System) *automock.SystemsAPIClient {
  1446  				return &automock.SystemsAPIClient{}
  1447  			},
  1448  			setupDirectorClient: func(systems []systemfetcher.System, appsInputs []model.ApplicationRegisterInputWithTemplate) *automock.DirectorClient {
  1449  				return &automock.DirectorClient{}
  1450  			},
  1451  			expectedErr: testError,
  1452  		},
  1453  	}
  1454  
  1455  	for _, testCase := range tests {
  1456  		t.Run(testCase.name, func(t *testing.T) {
  1457  			mockedTx, transactioner := testCase.mockTransactioner()
  1458  			tenantSvc := testCase.setupTenantSvc()
  1459  			tbtSvc := testCase.setupTbtSvc()
  1460  			testSystems := testCase.fixTestSystems()
  1461  			appsInputs := testCase.fixAppInputs(testSystems)
  1462  			systemSvc := testCase.setupSystemSvc(testSystems, appsInputs)
  1463  			systemsSyncSvc := testCase.setupSystemsSyncSvc()
  1464  			appInputsWithoutTemplates := make([]model.ApplicationRegisterInput, 0)
  1465  			for _, in := range appsInputs {
  1466  				appInputsWithoutTemplates = append(appInputsWithoutTemplates, in.ApplicationRegisterInput)
  1467  			}
  1468  			templateAppResolver := testCase.setupTemplateRendererSvc(testSystems, appInputsWithoutTemplates)
  1469  			sysAPIClient := testCase.setupSysAPIClient(testSystems)
  1470  			directorClient := testCase.setupDirectorClient(testSystems, appsInputs)
  1471  			defer mock.AssertExpectationsForObjects(t, tenantSvc, sysAPIClient, systemSvc, templateAppResolver, mockedTx, transactioner)
  1472  
  1473  			svc := systemfetcher.NewSystemFetcher(transactioner, tenantSvc, systemSvc, systemsSyncSvc, tbtSvc, templateAppResolver, sysAPIClient, directorClient, systemfetcher.Config{
  1474  				SystemsQueueSize:     100,
  1475  				FetcherParallellism:  30,
  1476  				EnableSystemDeletion: true,
  1477  				VerifyTenant:         testCase.verificationTenant,
  1478  			})
  1479  
  1480  			err := svc.UpsertSystemsSyncTimestamps(context.TODO(), transactioner)
  1481  			if testCase.expectedErr != nil {
  1482  				require.ErrorIs(t, err, testCase.expectedErr)
  1483  			} else {
  1484  				require.NoError(t, err)
  1485  			}
  1486  		})
  1487  	}
  1488  
  1489  	systemfetcher.SystemSynchronizationTimestamps = nil
  1490  }
  1491  
  1492  func fixAppsInputsWithTemplatesBySystems(t *testing.T, systems []systemfetcher.System) []model.ApplicationRegisterInputWithTemplate {
  1493  	initStatusCond := model.ApplicationStatusConditionInitial
  1494  	result := make([]model.ApplicationRegisterInputWithTemplate, 0, len(systems))
  1495  	for _, s := range systems {
  1496  		systemPayload, err := json.Marshal(s.SystemPayload)
  1497  		require.NoError(t, err)
  1498  		input := model.ApplicationRegisterInputWithTemplate{
  1499  			ApplicationRegisterInput: model.ApplicationRegisterInput{
  1500  				Name:            gjson.GetBytes(systemPayload, "displayName").String(),
  1501  				Description:     str.Ptr(gjson.GetBytes(systemPayload, "productDescription").String()),
  1502  				BaseURL:         str.Ptr(gjson.GetBytes(systemPayload, "additionalUrls"+"."+mainURLKey).String()),
  1503  				ProviderName:    str.Ptr(gjson.GetBytes(systemPayload, "infrastructureProvider").String()),
  1504  				SystemNumber:    str.Ptr(gjson.GetBytes(systemPayload, "systemNumber").String()),
  1505  				StatusCondition: &initStatusCond,
  1506  				Labels: map[string]interface{}{
  1507  					"managed":              "true",
  1508  					"productId":            str.Ptr(gjson.GetBytes(systemPayload, "productId").String()),
  1509  					"ppmsProductVersionId": str.Ptr(gjson.GetBytes(systemPayload, "ppmsProductVersionId").String()),
  1510  				},
  1511  			},
  1512  			TemplateID: s.TemplateID,
  1513  		}
  1514  		if len(input.TemplateID) > 0 {
  1515  			input.Labels["applicationType"] = appType
  1516  		}
  1517  		result = append(result, input)
  1518  	}
  1519  	return result
  1520  }
  1521  
  1522  func emptySystemsSyncSvc() *automock.SystemsSyncService {
  1523  	return &automock.SystemsSyncService{}
  1524  }