github.com/Jeffail/benthos/v3@v3.65.0/public/service/config_test.go (about)

     1  package service
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/Jeffail/benthos/v3/internal/docs"
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  	"gopkg.in/yaml.v3"
    10  )
    11  
    12  func TestConfigFromStructYAML(t *testing.T) {
    13  	type confNestedType struct {
    14  		D bool   `yaml:"d"`
    15  		E string `yaml:"e"`
    16  	}
    17  	type confType struct {
    18  		A string         `yaml:"a"`
    19  		B int            `yaml:"b"`
    20  		C confNestedType `yaml:"c"`
    21  	}
    22  
    23  	spec, err := NewStructConfigSpec(func() interface{} {
    24  		return &confType{
    25  			A: "avalue",
    26  			B: 11,
    27  			C: confNestedType{
    28  				D: true,
    29  				E: "evalue",
    30  			},
    31  		}
    32  	})
    33  	require.NoError(t, err)
    34  
    35  	tests := []struct {
    36  		name      string
    37  		config    string
    38  		lints     []docs.Lint
    39  		sanitized string
    40  	}{
    41  		{
    42  			name:   "no fields",
    43  			config: "{}",
    44  			sanitized: `a: avalue
    45  b: 11
    46  c:
    47      d: true
    48      e: evalue
    49  `,
    50  		},
    51  		{
    52  			name: "fields set",
    53  			config: `a: newavalue
    54  c:
    55    d: false
    56  `,
    57  			sanitized: `a: newavalue
    58  b: 11
    59  c:
    60      d: false
    61      e: evalue
    62  `,
    63  		},
    64  		{
    65  			name: "fields set unrecognized field",
    66  			config: `a: newavalue
    67  not_real: this doesnt exist in the spec
    68  c:
    69    d: false
    70  `,
    71  			sanitized: `a: newavalue
    72  b: 11
    73  c:
    74      d: false
    75      e: evalue
    76  `,
    77  			lints: []docs.Lint{
    78  				docs.NewLintError(2, "field not_real not recognised"),
    79  			},
    80  		},
    81  		{
    82  			name: "fields set nested unrecognized field",
    83  			config: `a: newavalue
    84  c:
    85    d: false
    86    not_real: this doesnt exist in the spec
    87  `,
    88  			sanitized: `a: newavalue
    89  b: 11
    90  c:
    91      d: false
    92      e: evalue
    93  `,
    94  			lints: []docs.Lint{
    95  				docs.NewLintError(4, "field not_real not recognised"),
    96  			},
    97  		},
    98  	}
    99  
   100  	for _, test := range tests {
   101  		t.Run(test.name, func(t *testing.T) {
   102  			confBytes := []byte(test.config)
   103  
   104  			node, err := getYAMLNode(confBytes)
   105  			require.NoError(t, err)
   106  
   107  			assert.Equal(t, test.lints, spec.component.Config.Children.LintYAML(docs.NewLintContext(), node))
   108  
   109  			pConf, err := spec.configFromNode(nil, node)
   110  			require.NoError(t, err)
   111  
   112  			var sanitNode yaml.Node
   113  			require.NoError(t, sanitNode.Encode(pConf.AsStruct()))
   114  
   115  			require.NoError(t, spec.component.Config.Children.SanitiseYAML(&sanitNode, docs.SanitiseConfig{
   116  				RemoveTypeField:  true,
   117  				RemoveDeprecated: true,
   118  			}))
   119  
   120  			sanitConfOutBytes, err := yaml.Marshal(sanitNode)
   121  			require.NoError(t, err)
   122  			assert.Equal(t, test.sanitized, string(sanitConfOutBytes))
   123  		})
   124  	}
   125  }
   126  
   127  func TestConfigGeneric(t *testing.T) {
   128  	spec := NewConfigSpec().
   129  		Field(NewStringField("a")).
   130  		Field(NewIntField("b").Default(11)).
   131  		Field(NewObjectField("c",
   132  			NewBoolField("d").Default(true),
   133  			NewStringField("e").Default("evalue"),
   134  		))
   135  
   136  	tests := []struct {
   137  		name      string
   138  		config    string
   139  		lints     []docs.Lint
   140  		sanitized string
   141  	}{
   142  		{
   143  			name:   "no fields except mandatory",
   144  			config: `a: foovalue`,
   145  			sanitized: `a: foovalue
   146  b: 11
   147  c:
   148      d: true
   149      e: evalue
   150  `,
   151  		},
   152  		{
   153  			name: "fields set",
   154  			config: `a: newavalue
   155  c:
   156    d: false
   157  `,
   158  			sanitized: `a: newavalue
   159  b: 11
   160  c:
   161      d: false
   162      e: evalue
   163  `,
   164  		},
   165  		{
   166  			name: "fields set unrecognized field",
   167  			config: `a: newavalue
   168  not_real: this doesnt exist in the spec
   169  c:
   170    d: false
   171  `,
   172  			sanitized: `a: newavalue
   173  b: 11
   174  c:
   175      d: false
   176      e: evalue
   177  `,
   178  			lints: []docs.Lint{
   179  				docs.NewLintError(2, "field not_real not recognised"),
   180  			},
   181  		},
   182  		{
   183  			name: "fields set nested unrecognized field",
   184  			config: `a: newavalue
   185  c:
   186    d: false
   187    not_real: this doesnt exist in the spec
   188  `,
   189  			sanitized: `a: newavalue
   190  b: 11
   191  c:
   192      d: false
   193      e: evalue
   194  `,
   195  			lints: []docs.Lint{
   196  				docs.NewLintError(4, "field not_real not recognised"),
   197  			},
   198  		},
   199  	}
   200  
   201  	for _, test := range tests {
   202  		t.Run(test.name, func(t *testing.T) {
   203  			confBytes := []byte(test.config)
   204  
   205  			node, err := getYAMLNode(confBytes)
   206  			require.NoError(t, err)
   207  
   208  			assert.Equal(t, test.lints, spec.component.Config.Children.LintYAML(docs.NewLintContext(), node))
   209  
   210  			pConf, err := spec.configFromNode(nil, node)
   211  			require.NoError(t, err)
   212  
   213  			var sanitNode yaml.Node
   214  			require.NoError(t, sanitNode.Encode(pConf.generic))
   215  
   216  			require.NoError(t, spec.component.Config.Children.SanitiseYAML(&sanitNode, docs.SanitiseConfig{
   217  				RemoveTypeField:  true,
   218  				RemoveDeprecated: true,
   219  			}))
   220  
   221  			sanitConfOutBytes, err := yaml.Marshal(sanitNode)
   222  			require.NoError(t, err)
   223  			assert.Equal(t, test.sanitized, string(sanitConfOutBytes))
   224  		})
   225  	}
   226  }
   227  
   228  func TestConfigTypedFields(t *testing.T) {
   229  	spec := NewConfigSpec().
   230  		Field(NewStringField("a")).
   231  		Field(NewIntField("b").Default(11)).
   232  		Field(NewObjectField("c",
   233  			NewBoolField("d").Default(true),
   234  			NewStringField("e").Default("evalue"),
   235  			NewObjectField("f",
   236  				NewIntField("g").Default(12),
   237  				NewStringField("h"),
   238  				NewFloatField("i").Default(13.0),
   239  				NewStringListField("j"),
   240  				NewStringMapField("k"),
   241  				NewIntListField("l"),
   242  				NewIntMapField("m"),
   243  			),
   244  		))
   245  
   246  	parsedConfig, err := spec.ParseYAML(`
   247  a: setavalue
   248  c:
   249    f:
   250      g: 22
   251      h: sethvalue
   252      i: 23.1
   253      j:
   254        - first in list
   255        - second in list
   256      k:
   257        first: one
   258        second: two
   259      l:
   260        - 11
   261        - 12
   262      m:
   263        first: 21
   264        second: 22
   265  `, nil)
   266  	require.NoError(t, err)
   267  
   268  	s, err := parsedConfig.FieldString("a")
   269  	assert.NoError(t, err)
   270  	assert.Equal(t, "setavalue", s)
   271  
   272  	_, err = parsedConfig.FieldString("z")
   273  	assert.Error(t, err)
   274  
   275  	_, err = parsedConfig.FieldInt("c", "z")
   276  	assert.Error(t, err)
   277  
   278  	_, err = parsedConfig.FieldFloat("c", "d", "z")
   279  	assert.Error(t, err)
   280  
   281  	_, err = parsedConfig.FieldBool("c", "z")
   282  	assert.Error(t, err)
   283  
   284  	i, err := parsedConfig.FieldInt("b")
   285  	assert.NoError(t, err)
   286  	assert.Equal(t, 11, i)
   287  
   288  	b, err := parsedConfig.FieldBool("c", "d")
   289  	assert.NoError(t, err)
   290  	assert.Equal(t, true, b)
   291  
   292  	i, err = parsedConfig.FieldInt("c", "f", "g")
   293  	assert.NoError(t, err)
   294  	assert.Equal(t, 22, i)
   295  
   296  	f, err := parsedConfig.FieldFloat("c", "f", "i")
   297  	assert.NoError(t, err)
   298  	assert.Equal(t, 23.1, f)
   299  
   300  	ll, err := parsedConfig.FieldStringList("c", "f", "j")
   301  	assert.NoError(t, err)
   302  	assert.Equal(t, []string{"first in list", "second in list"}, ll)
   303  
   304  	sm, err := parsedConfig.FieldStringMap("c", "f", "k")
   305  	assert.NoError(t, err)
   306  	assert.Equal(t, map[string]string{"first": "one", "second": "two"}, sm)
   307  
   308  	il, err := parsedConfig.FieldIntList("c", "f", "l")
   309  	assert.NoError(t, err)
   310  	assert.Equal(t, []int{11, 12}, il)
   311  
   312  	im, err := parsedConfig.FieldIntMap("c", "f", "m")
   313  	assert.NoError(t, err)
   314  	assert.Equal(t, map[string]int{"first": 21, "second": 22}, im)
   315  
   316  	// Testing namespaces
   317  	nsC := parsedConfig.Namespace("c")
   318  	nsFOne := nsC.Namespace("f")
   319  	nsFTwo := parsedConfig.Namespace("c", "f")
   320  
   321  	b, err = nsC.FieldBool("d")
   322  	assert.NoError(t, err)
   323  	assert.Equal(t, true, b)
   324  
   325  	i, err = nsFOne.FieldInt("g")
   326  	assert.NoError(t, err)
   327  	assert.Equal(t, 22, i)
   328  
   329  	f, err = nsFTwo.FieldFloat("i")
   330  	assert.NoError(t, err)
   331  	assert.Equal(t, 23.1, f)
   332  }
   333  
   334  func TestConfigRootString(t *testing.T) {
   335  	spec := NewConfigSpec().
   336  		Field(NewStringField(""))
   337  
   338  	parsedConfig, err := spec.ParseYAML(`"hello world"`, nil)
   339  	require.NoError(t, err)
   340  
   341  	v, err := parsedConfig.FieldString()
   342  	require.NoError(t, err)
   343  
   344  	assert.Equal(t, "hello world", v)
   345  }
   346  
   347  func TestConfigListOfObjects(t *testing.T) {
   348  	spec := NewConfigSpec().
   349  		Field(NewObjectListField("objects",
   350  			NewStringField("foo"),
   351  			NewStringField("bar").Default("bar value"),
   352  			NewIntField("baz"),
   353  		))
   354  
   355  	_, err := spec.ParseYAML(`objects:
   356  - foo: "foo value 1"
   357    bar: "bar value 1"
   358  `, nil)
   359  	require.Error(t, err)
   360  
   361  	_, err = spec.ParseYAML(`objects:
   362  - bar: "bar value 1"
   363    baz: 11
   364  `, nil)
   365  	require.Error(t, err)
   366  
   367  	_, err = spec.ParseYAML(`objects: []`, nil)
   368  	require.NoError(t, err)
   369  
   370  	parsedConfig, err := spec.ParseYAML(`objects:
   371  - foo: "foo value 1"
   372    bar: "bar value 1"
   373    baz: 11
   374  
   375  - foo: "foo value 2"
   376    bar: "bar value 2"
   377    baz: 12
   378  
   379  - foo: "foo value 3"
   380    baz: 13
   381  `, nil)
   382  	require.NoError(t, err)
   383  
   384  	objs, err := parsedConfig.FieldObjectList("objects")
   385  	require.NoError(t, err)
   386  	require.Len(t, objs, 3)
   387  
   388  	strValue, err := objs[0].FieldString("foo")
   389  	require.NoError(t, err)
   390  	assert.Equal(t, "foo value 1", strValue)
   391  
   392  	strValue, err = objs[0].FieldString("bar")
   393  	require.NoError(t, err)
   394  	assert.Equal(t, "bar value 1", strValue)
   395  
   396  	intValue, err := objs[0].FieldInt("baz")
   397  	require.NoError(t, err)
   398  	assert.Equal(t, 11, intValue)
   399  
   400  	strValue, err = objs[1].FieldString("foo")
   401  	require.NoError(t, err)
   402  	assert.Equal(t, "foo value 2", strValue)
   403  
   404  	strValue, err = objs[1].FieldString("bar")
   405  	require.NoError(t, err)
   406  	assert.Equal(t, "bar value 2", strValue)
   407  
   408  	intValue, err = objs[1].FieldInt("baz")
   409  	require.NoError(t, err)
   410  	assert.Equal(t, 12, intValue)
   411  
   412  	strValue, err = objs[2].FieldString("foo")
   413  	require.NoError(t, err)
   414  	assert.Equal(t, "foo value 3", strValue)
   415  
   416  	strValue, err = objs[2].FieldString("bar")
   417  	require.NoError(t, err)
   418  	assert.Equal(t, "bar value", strValue)
   419  
   420  	intValue, err = objs[2].FieldInt("baz")
   421  	require.NoError(t, err)
   422  	assert.Equal(t, 13, intValue)
   423  }
   424  
   425  func TestConfigTLS(t *testing.T) {
   426  	spec := NewConfigSpec().
   427  		Field(NewTLSField("a")).
   428  		Field(NewStringField("b"))
   429  
   430  	parsedConfig, err := spec.ParseYAML(`
   431  a:
   432    skip_cert_verify: true
   433  b: and this
   434  `, nil)
   435  	require.NoError(t, err)
   436  
   437  	_, err = parsedConfig.FieldTLS("b")
   438  	require.Error(t, err)
   439  
   440  	_, err = parsedConfig.FieldTLS("c")
   441  	require.Error(t, err)
   442  
   443  	tConf, err := parsedConfig.FieldTLS("a")
   444  	require.NoError(t, err)
   445  
   446  	assert.True(t, tConf.InsecureSkipVerify)
   447  }
   448  
   449  func TestConfigInterpolatedString(t *testing.T) {
   450  	spec := NewConfigSpec().
   451  		Field(NewInterpolatedStringField("a")).
   452  		Field(NewStringField("b"))
   453  
   454  	parsedConfig, err := spec.ParseYAML(`
   455  a: foo ${! content() } bar
   456  b: this is ${! json } an invalid interp string
   457  `, nil)
   458  	require.NoError(t, err)
   459  
   460  	_, err = parsedConfig.FieldInterpolatedString("b")
   461  	require.Error(t, err)
   462  
   463  	_, err = parsedConfig.FieldInterpolatedString("c")
   464  	require.Error(t, err)
   465  
   466  	iConf, err := parsedConfig.FieldInterpolatedString("a")
   467  	require.NoError(t, err)
   468  
   469  	res := iConf.String(NewMessage([]byte("hello world")))
   470  	assert.Equal(t, "foo hello world bar", res)
   471  }