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

     1  package systemfetcher_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/kyma-incubator/compass/components/director/pkg/str"
     8  
     9  	"github.com/kyma-incubator/compass/components/director/internal/model"
    10  	"github.com/kyma-incubator/compass/components/director/internal/systemfetcher"
    11  	"github.com/kyma-incubator/compass/components/director/internal/systemfetcher/automock"
    12  	"github.com/pkg/errors"
    13  	"github.com/stretchr/testify/mock"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestNewTemplateRenderer(t *testing.T) {
    18  	t.Run("Creates a new renderer", func(t *testing.T) {
    19  		appInputOverride := `{"name":"{{name}}"}`
    20  		templateSvc := &automock.ApplicationTemplateService{}
    21  		convSvc := &automock.ApplicationConverter{}
    22  		convSvc.On("CreateInputJSONToModel", context.TODO(), appInputOverride).Return(model.ApplicationRegisterInput{}, nil).Once()
    23  		defer mock.AssertExpectationsForObjects(t, templateSvc, convSvc)
    24  		tr, err := systemfetcher.NewTemplateRenderer(templateSvc, convSvc, appInputOverride, []systemfetcher.PlaceholderMapping{})
    25  
    26  		require.NoError(t, err)
    27  		require.NotNil(t, tr)
    28  	})
    29  	t.Run("Fails to create a new renderer when the override application input is not valid", func(t *testing.T) {
    30  		invalidOverrides := "invalid"
    31  		expectedErr := errors.New("test err")
    32  
    33  		templateSvc := &automock.ApplicationTemplateService{}
    34  		convSvc := &automock.ApplicationConverter{}
    35  		convSvc.On("CreateInputJSONToModel", context.TODO(), invalidOverrides).Return(model.ApplicationRegisterInput{}, expectedErr).Once()
    36  		defer mock.AssertExpectationsForObjects(t, templateSvc, convSvc)
    37  
    38  		tr, err := systemfetcher.NewTemplateRenderer(templateSvc, convSvc, invalidOverrides, []systemfetcher.PlaceholderMapping{})
    39  		require.ErrorIs(t, err, expectedErr)
    40  		require.Nil(t, tr)
    41  	})
    42  }
    43  func TestApplicationRegisterInputFromTemplate(t *testing.T) {
    44  	const (
    45  		appTemplateID        = "appTmp1"
    46  		appRegisterInputJSON = `{"name":"test"}`
    47  		appInputOverride     = `{"name":"testtest"}`
    48  	)
    49  	var (
    50  		optionalFalse = false
    51  	)
    52  
    53  	placeholdersMappings := []systemfetcher.PlaceholderMapping{
    54  		{
    55  			PlaceholderName: "name",
    56  			SystemKey:       "$.displayName",
    57  		},
    58  	}
    59  
    60  	appTemplate := &model.ApplicationTemplate{
    61  		ID:                   appTemplateID,
    62  		ApplicationInputJSON: `{"name":"testtest"}`,
    63  	}
    64  
    65  	appTemplateWithOverrides := &model.ApplicationTemplate{
    66  		ID: appTemplateID,
    67  		Placeholders: []model.ApplicationTemplatePlaceholder{
    68  			{Name: "name", JSONPath: str.Ptr("$.displayName"), Optional: &optionalFalse},
    69  		},
    70  		ApplicationInputJSON: appInputOverride,
    71  	}
    72  
    73  	testSystem := systemfetcher.System{
    74  		SystemPayload: map[string]interface{}{
    75  			"systemNumber":           "123",
    76  			"displayName":            "test",
    77  			"productDescription":     "test",
    78  			"baseUrl":                "http://test",
    79  			"infrastructureProvider": "test",
    80  		},
    81  		TemplateID: "123",
    82  	}
    83  
    84  	appTemplateSvcNoErrors := func(testSystem systemfetcher.System, _ error) *automock.ApplicationTemplateService {
    85  		svc := &automock.ApplicationTemplateService{}
    86  		inputValues := fixInputValuesForSystem(t, testSystem)
    87  		template := &model.ApplicationTemplate{
    88  			ID:                   appTemplateID,
    89  			ApplicationInputJSON: `{ "name": "testtest"}`,
    90  		}
    91  		svc.On("Get", context.TODO(), testSystem.TemplateID).Return(template, nil).Once()
    92  		svc.On("PrepareApplicationCreateInputJSON", appTemplateWithOverrides, inputValues).Return(appRegisterInputJSON, nil).Once()
    93  		return svc
    94  	}
    95  	appConvSvcNoErrors := func(testSystem systemfetcher.System, _ error) *automock.ApplicationConverter {
    96  		appInput := fixAppInputBySystem(t, testSystem)
    97  		conv := &automock.ApplicationConverter{}
    98  		conv.On("CreateInputJSONToModel", context.TODO(), appRegisterInputJSON).Return(appInput, nil).Once()
    99  		return conv
   100  	}
   101  
   102  	type testCase struct {
   103  		name                string
   104  		system              systemfetcher.System
   105  		expectedErr         error
   106  		appInputOverride    string
   107  		placeholderMappings []systemfetcher.PlaceholderMapping
   108  		setupAppTemplateSvc func(testSystem systemfetcher.System, potentialErr error) *automock.ApplicationTemplateService
   109  		setupAppConverter   func(testSystem systemfetcher.System, potentialErr error) *automock.ApplicationConverter
   110  	}
   111  	tests := []testCase{
   112  		{
   113  			name:                "Succeeds",
   114  			system:              testSystem,
   115  			appInputOverride:    appInputOverride,
   116  			placeholderMappings: placeholdersMappings,
   117  			setupAppTemplateSvc: appTemplateSvcNoErrors,
   118  			setupAppConverter:   appConvSvcNoErrors,
   119  		},
   120  		{
   121  			name:                "Succeeds when app template should be enriched with additional labels",
   122  			system:              testSystem,
   123  			appInputOverride:    `{"name":"{{name}}","labels":{"legacy":"true"}}`,
   124  			placeholderMappings: placeholdersMappings,
   125  			setupAppTemplateSvc: func(testSystem systemfetcher.System, _ error) *automock.ApplicationTemplateService {
   126  				resultTemplate := *appTemplateWithOverrides
   127  				resultTemplate.ApplicationInputJSON = `{"integrationSystemID":"a8396508-66be-4dc7-b463-577809289941","labels":{"legacy":"true","tenant":"123"},"name":"test1"}`
   128  				appTemplateFromDB := model.ApplicationTemplate{
   129  					ID:                   appTemplateID,
   130  					ApplicationInputJSON: `{ "name": "testtest"}`,
   131  				}
   132  				appTemplateFromDB.ApplicationInputJSON = `{"name": "test1","labels":{"tenant":"123"},"integrationSystemID":"a8396508-66be-4dc7-b463-577809289941"}`
   133  
   134  				svc := &automock.ApplicationTemplateService{}
   135  				svc.On("Get", context.TODO(), testSystem.TemplateID).Return(&appTemplateFromDB, nil).Once()
   136  				svc.On("PrepareApplicationCreateInputJSON", &resultTemplate, fixInputValuesForSystem(t, testSystem)).Return(appRegisterInputJSON, nil).Once()
   137  				return svc
   138  			},
   139  			setupAppConverter: appConvSvcNoErrors,
   140  		},
   141  		{
   142  			name:                "Succeeds when app template has placeholders",
   143  			system:              testSystem,
   144  			appInputOverride:    `{"name":"{{name}}"}`,
   145  			placeholderMappings: placeholdersMappings,
   146  			setupAppTemplateSvc: func(testSystem systemfetcher.System, _ error) *automock.ApplicationTemplateService {
   147  				resultTemplate := model.ApplicationTemplate{
   148  					ID: appTemplateID,
   149  					Placeholders: []model.ApplicationTemplatePlaceholder{
   150  						{Name: "name", JSONPath: str.Ptr("$.displayName"), Optional: &optionalFalse},
   151  					},
   152  					ApplicationInputJSON: `{"integrationSystemID":"a8396508-66be-4dc7-b463-577809289941","labels":{"tenant":"123"},"name":"test1"}`,
   153  				}
   154  				appTemplateFromDB := model.ApplicationTemplate{
   155  					ID: appTemplateID,
   156  					Placeholders: []model.ApplicationTemplatePlaceholder{
   157  						{Name: "name", JSONPath: str.Ptr("$.displayName"), Optional: &optionalFalse},
   158  					},
   159  					ApplicationInputJSON: `{ "name": "test1","labels":{"tenant":"123"},"integrationSystemID":"a8396508-66be-4dc7-b463-577809289941"}`,
   160  				}
   161  
   162  				svc := &automock.ApplicationTemplateService{}
   163  				svc.On("Get", context.TODO(), testSystem.TemplateID).Return(&appTemplateFromDB, nil).Once()
   164  				svc.On("PrepareApplicationCreateInputJSON", &resultTemplate, fixInputValuesForSystemWhichAppTemplateHasPlaceholders(t, testSystem)).Return(`{"name":"test"}`, nil).Once()
   165  				return svc
   166  			},
   167  			setupAppConverter: func(testSystem systemfetcher.System, _ error) *automock.ApplicationConverter {
   168  				appInput := fixAppInputBySystem(t, testSystem)
   169  				conv := &automock.ApplicationConverter{}
   170  				conv.On("CreateInputJSONToModel", context.TODO(), `{"name":"test"}`).Return(appInput, nil).Once()
   171  				return conv
   172  			},
   173  		},
   174  		{
   175  			name:             "Fails when app template has placeholders without assigned values",
   176  			system:           testSystem,
   177  			expectedErr:      errors.New("missing or empty key \"$.nonexistentKey\" in system payload"),
   178  			appInputOverride: appInputOverride,
   179  			placeholderMappings: []systemfetcher.PlaceholderMapping{
   180  				{
   181  					PlaceholderName: "name",
   182  					SystemKey:       "$.displayName",
   183  				},
   184  				{
   185  					PlaceholderName: "description",
   186  					SystemKey:       "$.nonexistentKey",
   187  				},
   188  			},
   189  			setupAppTemplateSvc: func(testSystem systemfetcher.System, _ error) *automock.ApplicationTemplateService {
   190  				svc := &automock.ApplicationTemplateService{}
   191  				//inputValues := fixInputValuesForSystem(testSystem)
   192  				svc.On("Get", context.TODO(), testSystem.TemplateID).Return(appTemplate, nil).Once()
   193  				return svc
   194  			},
   195  			setupAppConverter: func(testSystem systemfetcher.System, _ error) *automock.ApplicationConverter {
   196  				return &automock.ApplicationConverter{}
   197  			},
   198  		},
   199  		{
   200  			name:                "Fails when app input from template cannot be unmarshalled into a map",
   201  			system:              testSystem,
   202  			expectedErr:         errors.New("while unmarshaling original application input"),
   203  			appInputOverride:    `{"description":"{{description}}","labels":"hello"}`,
   204  			placeholderMappings: placeholdersMappings,
   205  			setupAppTemplateSvc: func(testSystem systemfetcher.System, _ error) *automock.ApplicationTemplateService {
   206  				appTemplateFromDB := *appTemplate
   207  				appTemplateFromDB.ApplicationInputJSON = ``
   208  
   209  				svc := &automock.ApplicationTemplateService{}
   210  				svc.On("Get", context.TODO(), testSystem.TemplateID).Return(&appTemplateFromDB, nil).Once()
   211  				return svc
   212  			},
   213  			setupAppConverter: func(testSystem systemfetcher.System, _ error) *automock.ApplicationConverter {
   214  				return &automock.ApplicationConverter{}
   215  			},
   216  		},
   217  		{
   218  			name:                "Fails when app input from override cannot be unmarshalled into a map",
   219  			system:              testSystem,
   220  			expectedErr:         errors.New("while unmarshaling override application input"),
   221  			appInputOverride:    ``,
   222  			placeholderMappings: placeholdersMappings,
   223  			setupAppTemplateSvc: func(testSystem systemfetcher.System, _ error) *automock.ApplicationTemplateService {
   224  				appTemplateFromDB := *appTemplate
   225  				appTemplateFromDB.ApplicationInputJSON = `{"name": "{{display-name}}"}`
   226  
   227  				svc := &automock.ApplicationTemplateService{}
   228  				svc.On("Get", context.TODO(), testSystem.TemplateID).Return(&appTemplateFromDB, nil).Once()
   229  				return svc
   230  			},
   231  			setupAppConverter: func(testSystem systemfetcher.System, _ error) *automock.ApplicationConverter {
   232  				return &automock.ApplicationConverter{}
   233  			},
   234  		},
   235  		{
   236  			name:                "Fails when template cannot be fetched",
   237  			system:              testSystem,
   238  			appInputOverride:    appInputOverride,
   239  			placeholderMappings: placeholdersMappings,
   240  			expectedErr:         errors.New("cannot get template"),
   241  			setupAppTemplateSvc: func(testSystem systemfetcher.System, err error) *automock.ApplicationTemplateService {
   242  				svc := &automock.ApplicationTemplateService{}
   243  				svc.On("Get", context.TODO(), testSystem.TemplateID).Return(nil, err).Once()
   244  				return svc
   245  			},
   246  			setupAppConverter: func(testSystem systemfetcher.System, _ error) *automock.ApplicationConverter {
   247  				return &automock.ApplicationConverter{}
   248  			},
   249  		},
   250  		{
   251  			name:                "Fails when app input JSON cannot be prepared",
   252  			system:              testSystem,
   253  			appInputOverride:    appInputOverride,
   254  			placeholderMappings: placeholdersMappings,
   255  			expectedErr:         errors.New("cannot prepare input json"),
   256  			setupAppTemplateSvc: func(testSystem systemfetcher.System, err error) *automock.ApplicationTemplateService {
   257  				svc := &automock.ApplicationTemplateService{}
   258  				inputValues := fixInputValuesForSystem(t, testSystem)
   259  				template := &model.ApplicationTemplate{
   260  					ID:                   appTemplateID,
   261  					ApplicationInputJSON: `{ "name": "testtest"}`,
   262  				}
   263  				svc.On("Get", context.TODO(), testSystem.TemplateID).Return(template, nil).Once()
   264  				svc.On("PrepareApplicationCreateInputJSON", appTemplateWithOverrides, inputValues).Return("", err).Once()
   265  				return svc
   266  			},
   267  			setupAppConverter: func(testSystem systemfetcher.System, _ error) *automock.ApplicationConverter {
   268  				return &automock.ApplicationConverter{}
   269  			},
   270  		},
   271  		{
   272  			name:                "Fails when app input cannot be prepared",
   273  			system:              testSystem,
   274  			appInputOverride:    appInputOverride,
   275  			placeholderMappings: placeholdersMappings,
   276  			expectedErr:         errors.New("cannot prepare input"),
   277  			setupAppTemplateSvc: appTemplateSvcNoErrors,
   278  			setupAppConverter: func(testSystem systemfetcher.System, err error) *automock.ApplicationConverter {
   279  				conv := &automock.ApplicationConverter{}
   280  				conv.On("CreateInputJSONToModel", context.TODO(), appRegisterInputJSON).Return(model.ApplicationRegisterInput{}, err).Once()
   281  				return conv
   282  			},
   283  		},
   284  	}
   285  	for _, test := range tests {
   286  		t.Run(test.name, func(t *testing.T) {
   287  			// GIVEN
   288  			templateSvc := test.setupAppTemplateSvc(test.system, test.expectedErr)
   289  			convSvc := test.setupAppConverter(test.system, test.expectedErr)
   290  			convSvc.On("CreateInputJSONToModel", context.TODO(), test.appInputOverride).Return(model.ApplicationRegisterInput{}, nil).Once()
   291  			tr, err := systemfetcher.NewTemplateRenderer(templateSvc, convSvc, test.appInputOverride, test.placeholderMappings)
   292  			require.NoError(t, err)
   293  
   294  			defer mock.AssertExpectationsForObjects(t, templateSvc, convSvc)
   295  
   296  			// WHEN
   297  			regIn, err := tr.ApplicationRegisterInputFromTemplate(context.TODO(), testSystem)
   298  
   299  			// THEN
   300  			if test.expectedErr != nil {
   301  				require.Error(t, err)
   302  				require.Contains(t, err.Error(), test.expectedErr.Error())
   303  			} else {
   304  				require.NoError(t, err)
   305  				require.Equal(t, fixAppInputBySystem(t, test.system), *regIn)
   306  			}
   307  		})
   308  	}
   309  }