github.com/Axway/agent-sdk@v1.1.101/pkg/apic/provisioning/propertybuilder_test.go (about)

     1  package provisioning
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  )
     9  
    10  func TestNewSchemaPropertyBuilder(t *testing.T) {
    11  	builder := NewSchemaPropertyBuilder()
    12  	assert.NotNil(t, builder)
    13  
    14  	schemaProperty := builder.(*schemaProperty)
    15  
    16  	// test all the default values
    17  	assert.Nil(t, schemaProperty.err)
    18  	assert.Empty(t, schemaProperty.name)
    19  	assert.Empty(t, schemaProperty.description)
    20  	//assert.Len(t, schemaProperty.enums, 0)
    21  	assert.False(t, schemaProperty.required)
    22  	assert.False(t, schemaProperty.readOnly)
    23  	assert.Empty(t, schemaProperty.dataType)
    24  }
    25  
    26  func TestSubscriptionSchemaPropertyBuilderSetters(t *testing.T) {
    27  	// No name
    28  	prop, err := NewSchemaPropertyBuilder().Build()
    29  
    30  	assert.NotNil(t, err)
    31  	assert.Nil(t, prop)
    32  
    33  	// No datatype
    34  	prop, err = NewSchemaPropertyBuilder().
    35  		SetName("name").
    36  		Build()
    37  
    38  	assert.NotNil(t, err)
    39  	assert.Nil(t, prop)
    40  
    41  	// Datatype twice
    42  	//prop, err = NewSchemaPropertyBuilder().
    43  	//	SetName("name").
    44  	//	IsString().
    45  	//	Build()
    46  
    47  	//assert.NotNil(t, err)
    48  	//assert.Nil(t, prop)
    49  
    50  	// No datatype in dependent property
    51  	builder := NewSchemaPropertyBuilder().
    52  		SetName("name").
    53  		IsString().
    54  		SetEnumValues([]string{"a", "b"}).
    55  		AddDependency("a", NewSchemaPropertyBuilder().
    56  			SetName("noDataType"))
    57  
    58  	prop, err = builder.Build()
    59  	assert.Nil(t, err)
    60  	assert.NotNil(t, prop)
    61  
    62  	dep, err := builder.BuildDependencies()
    63  	assert.NotNil(t, err)
    64  	assert.Nil(t, dep)
    65  
    66  	// No datatype in child dependent property
    67  	builder = NewSchemaPropertyBuilder().
    68  		SetName("name").
    69  		IsString().
    70  		SetEnumValues([]string{"a", "b"}).
    71  		AddDependency("a", NewSchemaPropertyBuilder().
    72  			SetName("child").
    73  			IsString().
    74  			SetEnumValues([]string{"c", "d"}).
    75  			AddDependency("c", NewSchemaPropertyBuilder().
    76  				SetName("child")))
    77  
    78  	prop, err = builder.Build()
    79  	assert.Nil(t, err)
    80  	assert.NotNil(t, prop)
    81  
    82  	dep, err = builder.BuildDependencies()
    83  	assert.NotNil(t, err)
    84  	assert.Nil(t, dep)
    85  
    86  	// good path, no enums
    87  	prop, err = NewSchemaPropertyBuilder().
    88  		SetName("name").
    89  		SetDescription("description").
    90  		SetRequired().
    91  		SetReadOnly().
    92  		SetHidden().
    93  		IsString().
    94  		Build()
    95  
    96  	assert.Nil(t, err)
    97  	assert.NotNil(t, prop)
    98  	assert.Len(t, prop.Enum, 0)
    99  	assert.Equal(t, "name", prop.Name)
   100  	assert.Equal(t, "description", prop.Description)
   101  	assert.True(t, prop.Required)
   102  	assert.True(t, prop.ReadOnly)
   103  	assert.Equal(t, prop.Format, "hidden")
   104  
   105  	// good path, set enums
   106  	prop, err = NewSchemaPropertyBuilder().
   107  		SetName("name").
   108  		IsString().
   109  		SetEnumValues([]string{"a", "b", "c", "c"}).
   110  		Build()
   111  
   112  	assert.Nil(t, err)
   113  	assert.NotNil(t, prop)
   114  	assert.Len(t, prop.Enum, 3)
   115  	assert.Equal(t, "name", prop.Name)
   116  	assert.Equal(t, "", prop.Description)
   117  	assert.False(t, prop.Required)
   118  	assert.False(t, prop.ReadOnly)
   119  	assert.Equal(t, prop.Format, "")
   120  
   121  	// good path, add enums
   122  	prop, err = NewSchemaPropertyBuilder().
   123  		SetName("name").
   124  		IsString().
   125  		AddEnumValue("a").
   126  		AddEnumValue("b").
   127  		AddEnumValue("c").
   128  		AddEnumValue("c").
   129  		Build()
   130  
   131  	assert.Nil(t, err)
   132  	assert.NotNil(t, prop)
   133  	assert.Len(t, prop.Enum, 3)
   134  	assert.Equal(t, "name", prop.Name)
   135  	assert.Equal(t, "", prop.Description)
   136  	assert.False(t, prop.Required)
   137  	assert.False(t, prop.ReadOnly)
   138  	assert.Equal(t, prop.Format, "")
   139  
   140  	// good path, sort enums & add first item
   141  	prop, err = NewSchemaPropertyBuilder().
   142  		SetName("name").
   143  		IsString().
   144  		AddEnumValue("c").
   145  		AddEnumValue("a").
   146  		AddEnumValue("b").
   147  		SetSortEnumValues().
   148  		SetFirstEnumValue("xxx").
   149  		Build()
   150  
   151  	assert.Nil(t, err)
   152  	assert.NotNil(t, prop)
   153  	assert.Len(t, prop.Enum, 4)
   154  	assert.Equal(t, "name", prop.Name)
   155  	assert.Equal(t, "", prop.Description)
   156  	assert.False(t, prop.Required)
   157  	assert.False(t, prop.ReadOnly)
   158  	assert.Equal(t, prop.Format, "")
   159  	assert.Equal(t, "xxx", prop.Enum[0])
   160  	assert.Equal(t, "a", prop.Enum[1])
   161  }
   162  
   163  func getFloat64Pointer(value float64) *float64 {
   164  	return &value
   165  }
   166  
   167  func getUintPointer(value uint) *uint {
   168  	return &value
   169  }
   170  
   171  func Test_SubscriptionPropertyBuilder_Build_with_valid_values(t *testing.T) {
   172  	tests := []struct {
   173  		name                 string
   174  		builder              PropertyBuilder
   175  		expectedDef          propertyDefinition
   176  		expectedDependencies *oneOfPropertyDefinitions
   177  	}{
   178  		{"Minimal String property",
   179  			NewSchemaPropertyBuilder().
   180  				SetName("TheName").
   181  				SetLabel("The Label").
   182  				IsString(),
   183  			propertyDefinition{
   184  				Name:  "TheName",
   185  				Title: "The Label",
   186  				Type:  DataTypeString,
   187  			},
   188  			nil},
   189  		{"String property with dependencies",
   190  			NewSchemaPropertyBuilder().
   191  				SetName("TheName").
   192  				SetLabel("The Label").
   193  				IsString().
   194  				SetEnumValues([]string{"a", "b", "c"}).
   195  				AddDependency("a", NewSchemaPropertyBuilder().
   196  					SetName("TheDependent").
   197  					SetLabel("The Dependent").IsString()),
   198  			propertyDefinition{
   199  				Name:  "TheName",
   200  				Title: "The Label",
   201  				Type:  DataTypeString,
   202  				Enum:  []string{"a", "b", "c"},
   203  			},
   204  			&oneOfPropertyDefinitions{
   205  				OneOf: []*propertyDefinition{
   206  					{
   207  						Properties: map[string]propertyDefinition{
   208  							"TheName": {
   209  								Enum: []string{"a"},
   210  							},
   211  							"TheDependent": {
   212  								Type:  DataTypeString,
   213  								Name:  "TheDependent",
   214  								Title: "The Dependent",
   215  							},
   216  						},
   217  					},
   218  					{
   219  						Properties: map[string]propertyDefinition{
   220  							"TheName": {
   221  								Enum: []string{"b"},
   222  							},
   223  						},
   224  					},
   225  					{
   226  						Properties: map[string]propertyDefinition{
   227  							"TheName": {
   228  								Enum: []string{"c"},
   229  							},
   230  						},
   231  					},
   232  				},
   233  			},
   234  		},
   235  		{"String child property with dependencies",
   236  			NewSchemaPropertyBuilder().
   237  				SetName("TheName").
   238  				SetLabel("The Label").
   239  				IsString().
   240  				SetEnumValues([]string{"a", "b"}).
   241  				AddDependency("a", NewSchemaPropertyBuilder().
   242  					SetName("TheChild").
   243  					SetLabel("The Child").
   244  					IsString().
   245  					SetEnumValues([]string{"a", "b"}).
   246  					AddDependency("a", NewSchemaPropertyBuilder().
   247  						SetName("TheDependent").
   248  						SetLabel("The Dependent").
   249  						IsString()),
   250  				),
   251  			propertyDefinition{
   252  				Name:  "TheName",
   253  				Title: "The Label",
   254  				Type:  DataTypeString,
   255  				Enum:  []string{"a", "b"},
   256  			},
   257  			&oneOfPropertyDefinitions{
   258  				OneOf: []*propertyDefinition{
   259  					{
   260  						Properties: map[string]propertyDefinition{
   261  							"TheName": {
   262  								Enum: []string{"a"},
   263  							},
   264  							"TheChild": {
   265  								Type:  DataTypeString,
   266  								Name:  "TheChild",
   267  								Title: "The Child",
   268  								Enum:  []string{"a", "b"},
   269  							},
   270  						},
   271  						Dependencies: map[string]*oneOfPropertyDefinitions{
   272  							"TheChild": {
   273  								OneOf: []*propertyDefinition{
   274  									{
   275  										Properties: map[string]propertyDefinition{
   276  											"TheChild": {
   277  												Enum: []string{"a"},
   278  											},
   279  											"TheDependent": {
   280  												Type:  DataTypeString,
   281  												Name:  "TheDependent",
   282  												Title: "The Dependent",
   283  											},
   284  										},
   285  									},
   286  								},
   287  							},
   288  						},
   289  					},
   290  					{
   291  						Properties: map[string]propertyDefinition{
   292  							"TheName": {
   293  								Enum: []string{"b"},
   294  							},
   295  						},
   296  					},
   297  				},
   298  			},
   299  		},
   300  		{"Full String property with unsorted enum and first value",
   301  			NewSchemaPropertyBuilder().
   302  				SetName("TheName").
   303  				SetLabel("The Label").
   304  				SetDescription("TheDescription").
   305  				SetRequired().
   306  				SetHidden().
   307  				SetReadOnly().
   308  				IsString().
   309  				IsEncrypted().
   310  				SetAsTextArea().
   311  				SetEnumValues([]string{"c", "a", "b"}).
   312  				AddEnumValue("addedValue").
   313  				SetFirstEnumValue("firstValue").
   314  				SetDefaultValue("a"),
   315  			propertyDefinition{
   316  				Name:         "TheName",
   317  				Title:        "The Label",
   318  				Description:  "TheDescription",
   319  				Required:     true,
   320  				Format:       "hidden",
   321  				ReadOnly:     true,
   322  				IsEncrypted:  true,
   323  				Widget:       "textArea",
   324  				Type:         DataTypeString,
   325  				Enum:         []string{"firstValue", "c", "a", "b", "addedValue"},
   326  				DefaultValue: "a",
   327  			},
   328  			nil},
   329  		{"Full String property with sorted enum and first value",
   330  			NewSchemaPropertyBuilder().
   331  				SetName("TheName").
   332  				SetLabel("The Label").
   333  				SetDescription("TheDescription").
   334  				SetRequired().
   335  				SetHidden().
   336  				SetReadOnly().
   337  				IsString().
   338  				IsEncrypted().
   339  				SetAsTextArea().
   340  				SetEnumValues([]string{"c", "a", "b"}).
   341  				AddEnumValue("addedValue").
   342  				SetFirstEnumValue("firstValue").
   343  				SetSortEnumValues().
   344  				SetDefaultValue("a"),
   345  			propertyDefinition{
   346  				Name:         "TheName",
   347  				Title:        "The Label",
   348  				Description:  "TheDescription",
   349  				Required:     true,
   350  				Format:       "hidden",
   351  				ReadOnly:     true,
   352  				IsEncrypted:  true,
   353  				Widget:       "textArea",
   354  				Type:         DataTypeString,
   355  				Enum:         []string{"firstValue", "a", "addedValue", "b", "c"},
   356  				DefaultValue: "a",
   357  			},
   358  			nil},
   359  		{"Minimal Number property",
   360  			NewSchemaPropertyBuilder().
   361  				SetName("TheName").
   362  				SetLabel("The Label").
   363  				IsNumber(),
   364  			propertyDefinition{
   365  				Name:  "TheName",
   366  				Title: "The Label",
   367  				Type:  DataTypeNumber,
   368  			},
   369  			nil},
   370  		{"Full Number property",
   371  			NewSchemaPropertyBuilder().
   372  				SetName("TheName").
   373  				SetLabel("The Label").
   374  				SetDescription("TheDescription").
   375  				SetRequired().
   376  				SetHidden().
   377  				SetReadOnly().
   378  				IsNumber().
   379  				SetMinValue(0.0).
   380  				SetMaxValue(100.5).
   381  				SetDefaultValue(50.5),
   382  			propertyDefinition{
   383  				Name:         "TheName",
   384  				Title:        "The Label",
   385  				Description:  "TheDescription",
   386  				Required:     true,
   387  				Format:       "hidden",
   388  				ReadOnly:     true,
   389  				Type:         DataTypeNumber,
   390  				Minimum:      getFloat64Pointer(0.0),
   391  				Maximum:      getFloat64Pointer(100.5),
   392  				DefaultValue: getFloat64Pointer(50.5),
   393  			},
   394  			nil},
   395  		{"Minimal Integer property",
   396  			NewSchemaPropertyBuilder().
   397  				SetName("TheName").
   398  				SetLabel("The Label").
   399  				IsInteger(),
   400  			propertyDefinition{
   401  				Name:  "TheName",
   402  				Title: "The Label",
   403  				Type:  DataTypeInteger,
   404  			},
   405  			nil},
   406  		{"Full Integer property",
   407  			NewSchemaPropertyBuilder().
   408  				SetName("TheName").
   409  				SetLabel("The Label").
   410  				SetDescription("TheDescription").
   411  				SetRequired().
   412  				SetHidden().
   413  				SetReadOnly().
   414  				IsInteger().
   415  				SetMinValue(0).
   416  				SetMaxValue(100).
   417  				SetDefaultValue(50),
   418  			propertyDefinition{
   419  				Name:         "TheName",
   420  				Title:        "The Label",
   421  				Description:  "TheDescription",
   422  				Required:     true,
   423  				Format:       "hidden",
   424  				ReadOnly:     true,
   425  				Type:         DataTypeInteger,
   426  				Minimum:      getFloat64Pointer(0),
   427  				Maximum:      getFloat64Pointer(100),
   428  				DefaultValue: getFloat64Pointer(50),
   429  			},
   430  			nil},
   431  		{"Minimal Array property",
   432  			NewSchemaPropertyBuilder().
   433  				SetName("TheName").
   434  				SetLabel("The Label").
   435  				IsArray(),
   436  			propertyDefinition{
   437  				Name:  "TheName",
   438  				Title: "The Label",
   439  				Type:  DataTypeArray,
   440  			},
   441  			nil},
   442  		{"Full Array property",
   443  			NewSchemaPropertyBuilder().
   444  				SetName("TheName").
   445  				SetLabel("The Label").
   446  				SetDescription("TheDescription").
   447  				SetRequired().
   448  				SetHidden().
   449  				SetReadOnly().
   450  				IsArray().
   451  				AddItem(NewSchemaPropertyBuilder().
   452  					SetName("ItemName").
   453  					SetLabel("Item Label").
   454  					IsString()).
   455  				SetMinItems(0).
   456  				SetMaxItems(1),
   457  			propertyDefinition{
   458  				Name:        "TheName",
   459  				Title:       "The Label",
   460  				Description: "TheDescription",
   461  				Required:    true,
   462  				Format:      "hidden",
   463  				ReadOnly:    true,
   464  				Type:        DataTypeArray,
   465  				Items: &anyOfPropertyDefinitions{
   466  					AnyOf: []propertyDefinition{
   467  						{
   468  							Name:  "ItemName",
   469  							Title: "Item Label",
   470  							Type:  DataTypeString,
   471  						},
   472  					},
   473  				},
   474  				MinItems:    getUintPointer(0),
   475  				MaxItems:    getUintPointer(1),
   476  				UniqueItems: true,
   477  			},
   478  			nil},
   479  		{"Minimal Object property",
   480  			NewSchemaPropertyBuilder().
   481  				SetName("TheName").
   482  				IsObject(),
   483  			propertyDefinition{
   484  				Name: "TheName",
   485  				Type: DataTypeObject,
   486  			},
   487  			nil},
   488  		{"Full Object property",
   489  			NewSchemaPropertyBuilder().
   490  				SetName("TheName").
   491  				SetLabel("The Label").
   492  				SetDescription("TheDescription").
   493  				SetRequired().
   494  				SetHidden().
   495  				SetReadOnly().
   496  				IsObject().
   497  				AddProperty(NewSchemaPropertyBuilder().
   498  					SetName("PropertyName").
   499  					SetLabel("Property Label").
   500  					SetRequired().
   501  					IsString()),
   502  			propertyDefinition{
   503  				Name:        "TheName",
   504  				Title:       "The Label",
   505  				Description: "TheDescription",
   506  				Required:    true,
   507  				Format:      "hidden",
   508  				ReadOnly:    true,
   509  				Type:        DataTypeObject,
   510  				Properties: map[string]propertyDefinition{
   511  					"PropertyName": {
   512  						Name:     "PropertyName",
   513  						Title:    "Property Label",
   514  						Type:     DataTypeString,
   515  						Required: true,
   516  					},
   517  				},
   518  				RequiredProperties: []string{
   519  					"PropertyName",
   520  				},
   521  			},
   522  			nil},
   523  	}
   524  	for _, tt := range tests {
   525  		t.Run(tt.name, func(t *testing.T) {
   526  			def, err := tt.builder.Build()
   527  			assert.Nil(t, err)
   528  			assert.Equal(t, tt.expectedDef, *def)
   529  			deps, err := tt.builder.BuildDependencies()
   530  			assert.Nil(t, err)
   531  			assertDependencies(t, def.Name, tt.expectedDependencies, deps)
   532  		})
   533  	}
   534  }
   535  
   536  func assertDependencies(t *testing.T, propName string, expectedDependencies, deps *oneOfPropertyDefinitions) {
   537  	if expectedDependencies == nil {
   538  		assert.Nil(t, deps)
   539  		return
   540  	}
   541  	assert.NotNil(t, deps)
   542  	for index, expectedDepDef := range expectedDependencies.OneOf {
   543  		depDef := deps.OneOf[index]
   544  		expectedEnumDepProps := make(map[string]propertyDefinition)
   545  		enumDepProps := make(map[string]propertyDefinition)
   546  		for name, expectedProperty := range expectedDepDef.Properties {
   547  			assert.Contains(t, depDef.Properties, name)
   548  			if expectedProperty.Name == propName {
   549  				expectedEnumDepProps[expectedProperty.Enum[0]] = expectedProperty
   550  			}
   551  		}
   552  
   553  		for _, expectedProperty := range depDef.Properties {
   554  			if expectedProperty.Name == propName {
   555  				enumDepProps[expectedProperty.Enum[0]] = expectedProperty
   556  			}
   557  		}
   558  		assert.Equal(t, len(enumDepProps), len(expectedEnumDepProps))
   559  		for enum, expectedProperty := range expectedEnumDepProps {
   560  			depProp := enumDepProps[enum]
   561  			assert.Equal(t, expectedProperty, depProp)
   562  		}
   563  		if expectedDepDef.Dependencies != nil {
   564  			assert.NotNil(t, depDef.Dependencies)
   565  		}
   566  		for name, expectedChildDependencies := range expectedDepDef.Dependencies {
   567  			childDeps, ok := depDef.Dependencies[name]
   568  			assert.True(t, ok)
   569  			assertDependencies(t, expectedDepDef.Name, expectedChildDependencies, childDeps)
   570  		}
   571  	}
   572  }
   573  
   574  func Test_SubscriptionPropertyBuilder_Build_with_error(t *testing.T) {
   575  	tests := []struct {
   576  		name         string
   577  		builder      PropertyBuilder
   578  		errorPattern string
   579  	}{
   580  		{"String property without name", NewSchemaPropertyBuilder().
   581  			IsString(), "without a name"},
   582  		{"String property with default value not present in enum list", NewSchemaPropertyBuilder().
   583  			SetName("aString").
   584  			IsString().
   585  			SetEnumValues([]string{"a", "b"}).
   586  			SetDefaultValue("z"), "must be present in the enum list"},
   587  		{"Number property without name", NewSchemaPropertyBuilder().
   588  			IsNumber(), "without a name"},
   589  		{"Number property with min greater than max", NewSchemaPropertyBuilder().
   590  			SetName("aNumber").
   591  			IsNumber().
   592  			SetMinValue(2).
   593  			SetMaxValue(1), "greater than"},
   594  		{"Number property with default value greater than max", NewSchemaPropertyBuilder().
   595  			SetName("aNumber").
   596  			IsNumber().
   597  			SetMaxValue(1).
   598  			SetDefaultValue(2), "must be equal or lower than max value"},
   599  		{"Number property with default value lower than min", NewSchemaPropertyBuilder().
   600  			SetName("aNumber").
   601  			IsNumber().
   602  			SetMinValue(2).
   603  			SetDefaultValue(1), "must be equal or greater than min value"},
   604  		{"Integer property without name", NewSchemaPropertyBuilder().
   605  			IsInteger(),
   606  			"without a name"},
   607  		{"Integer property with min greater than max", NewSchemaPropertyBuilder().
   608  			SetName("anInteger").
   609  			IsInteger().
   610  			SetMinValue(2).
   611  			SetMaxValue(1), "greater than"},
   612  		{"Integer property with default value greater than max", NewSchemaPropertyBuilder().
   613  			SetName("aNumber").
   614  			IsInteger().
   615  			SetMaxValue(1).
   616  			SetDefaultValue(2), "must be equal or lower than max value"},
   617  		{"Integer property with default value lower than min", NewSchemaPropertyBuilder().
   618  			SetName("aNumber").
   619  			IsInteger().
   620  			SetMinValue(2).
   621  			SetDefaultValue(1), "must be equal or greater than min value"},
   622  		{"Array property without name", NewSchemaPropertyBuilder().
   623  			IsArray(), "without a name"},
   624  		{"Array property with min items greater than max items", NewSchemaPropertyBuilder().
   625  			SetName("anArray").
   626  			IsArray().
   627  			SetMinItems(2).
   628  			SetMaxItems(1), "greater than"},
   629  		{"Array property with wrong max items", NewSchemaPropertyBuilder().
   630  			SetName("anArray").
   631  			IsArray().
   632  			SetMaxItems(0), "greater than 0"},
   633  		{"Array property with error on added item", NewSchemaPropertyBuilder().
   634  			SetName("anArray").
   635  			IsArray().
   636  			AddItem(NewSchemaPropertyBuilder()), "without a name"},
   637  		{"Object property without name", NewSchemaPropertyBuilder().
   638  			IsObject(), "without a name"},
   639  		{"Object property with error on added property", NewSchemaPropertyBuilder().
   640  			SetName("anObject").
   641  			IsObject().
   642  			AddProperty(NewSchemaPropertyBuilder()), "without a name"},
   643  	}
   644  	for _, tt := range tests {
   645  		t.Run(tt.name, func(t *testing.T) {
   646  			prop, err := tt.builder.Build()
   647  			assert.NotNil(t, err)
   648  			assert.True(t, strings.Contains(err.Error(), tt.errorPattern))
   649  			assert.Nil(t, prop)
   650  		})
   651  	}
   652  }