1// Copyright The OpenTelemetry Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package configloader 16 17import ( 18 "os" 19 "path" 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 25 "go.opentelemetry.io/collector/component" 26 "go.opentelemetry.io/collector/config" 27 "go.opentelemetry.io/collector/config/confignet" 28 "go.opentelemetry.io/collector/config/configparser" 29 "go.opentelemetry.io/collector/internal/testcomponents" 30) 31 32func TestDecodeConfig(t *testing.T) { 33 factories, err := testcomponents.ExampleComponents() 34 assert.NoError(t, err) 35 36 // Load the config 37 cfg, err := loadConfigFile(t, path.Join(".", "testdata", "valid-config.yaml"), factories) 38 require.NoError(t, err, "Unable to load config") 39 40 // Verify extensions. 41 assert.Equal(t, 3, len(cfg.Extensions)) 42 assert.Equal(t, "some string", cfg.Extensions[config.NewIDWithName("exampleextension", "1")].(*testcomponents.ExampleExtensionCfg).ExtraSetting) 43 44 // Verify service. 45 assert.Equal(t, 2, len(cfg.Service.Extensions)) 46 assert.Equal(t, config.NewIDWithName("exampleextension", "0"), cfg.Service.Extensions[0]) 47 assert.Equal(t, config.NewIDWithName("exampleextension", "1"), cfg.Service.Extensions[1]) 48 49 // Verify receivers 50 assert.Equal(t, 2, len(cfg.Receivers), "Incorrect receivers count") 51 52 assert.Equal(t, 53 &testcomponents.ExampleReceiver{ 54 ReceiverSettings: config.NewReceiverSettings(config.NewID("examplereceiver")), 55 TCPAddr: confignet.TCPAddr{ 56 Endpoint: "localhost:1000", 57 }, 58 ExtraSetting: "some string", 59 }, 60 cfg.Receivers[config.NewID("examplereceiver")], 61 "Did not load receiver config correctly") 62 63 assert.Equal(t, 64 &testcomponents.ExampleReceiver{ 65 ReceiverSettings: config.NewReceiverSettings(config.NewIDWithName("examplereceiver", "myreceiver")), 66 TCPAddr: confignet.TCPAddr{ 67 Endpoint: "localhost:12345", 68 }, 69 ExtraSetting: "some string", 70 }, 71 cfg.Receivers[config.NewIDWithName("examplereceiver", "myreceiver")], 72 "Did not load receiver config correctly") 73 74 // Verify exporters 75 assert.Equal(t, 2, len(cfg.Exporters), "Incorrect exporters count") 76 77 assert.Equal(t, 78 &testcomponents.ExampleExporter{ 79 ExporterSettings: config.NewExporterSettings(config.NewID("exampleexporter")), 80 ExtraSetting: "some export string", 81 }, 82 cfg.Exporters[config.NewID("exampleexporter")], 83 "Did not load exporter config correctly") 84 85 assert.Equal(t, 86 &testcomponents.ExampleExporter{ 87 ExporterSettings: config.NewExporterSettings(config.NewIDWithName("exampleexporter", "myexporter")), 88 ExtraSetting: "some export string 2", 89 }, 90 cfg.Exporters[config.NewIDWithName("exampleexporter", "myexporter")], 91 "Did not load exporter config correctly") 92 93 // Verify Processors 94 assert.Equal(t, 1, len(cfg.Processors), "Incorrect processors count") 95 96 assert.Equal(t, 97 &testcomponents.ExampleProcessorCfg{ 98 ProcessorSettings: config.NewProcessorSettings(config.NewID("exampleprocessor")), 99 ExtraSetting: "some export string", 100 }, 101 cfg.Processors[config.NewID("exampleprocessor")], 102 "Did not load processor config correctly") 103 104 // Verify Pipelines 105 assert.Equal(t, 1, len(cfg.Service.Pipelines), "Incorrect pipelines count") 106 107 assert.Equal(t, 108 &config.Pipeline{ 109 Name: "traces", 110 InputType: config.TracesDataType, 111 Receivers: []config.ComponentID{config.NewID("examplereceiver")}, 112 Processors: []config.ComponentID{config.NewID("exampleprocessor")}, 113 Exporters: []config.ComponentID{config.NewID("exampleexporter")}, 114 }, 115 cfg.Service.Pipelines["traces"], 116 "Did not load pipeline config correctly") 117} 118 119func TestSimpleConfig(t *testing.T) { 120 var testCases = []struct { 121 name string // test case name (also file name containing config yaml) 122 }{ 123 {name: "simple-config-with-no-env"}, 124 {name: "simple-config-with-partial-env"}, 125 {name: "simple-config-with-all-env"}, 126 } 127 128 const extensionExtra = "some extension string" 129 const extensionExtraMapValue = "some extension map value" 130 const extensionExtraListElement = "some extension list value" 131 assert.NoError(t, os.Setenv("EXTENSIONS_EXAMPLEEXTENSION_EXTRA", extensionExtra)) 132 assert.NoError(t, os.Setenv("EXTENSIONS_EXAMPLEEXTENSION_EXTRA_MAP_EXT_VALUE_1", extensionExtraMapValue+"_1")) 133 assert.NoError(t, os.Setenv("EXTENSIONS_EXAMPLEEXTENSION_EXTRA_MAP_EXT_VALUE_2", extensionExtraMapValue+"_2")) 134 assert.NoError(t, os.Setenv("EXTENSIONS_EXAMPLEEXTENSION_EXTRA_LIST_VALUE_1", extensionExtraListElement+"_1")) 135 assert.NoError(t, os.Setenv("EXTENSIONS_EXAMPLEEXTENSION_EXTRA_LIST_VALUE_2", extensionExtraListElement+"_2")) 136 137 const receiverExtra = "some receiver string" 138 const receiverExtraMapValue = "some receiver map value" 139 const receiverExtraListElement = "some receiver list value" 140 assert.NoError(t, os.Setenv("RECEIVERS_EXAMPLERECEIVER_EXTRA", receiverExtra)) 141 assert.NoError(t, os.Setenv("RECEIVERS_EXAMPLERECEIVER_EXTRA_MAP_RECV_VALUE_1", receiverExtraMapValue+"_1")) 142 assert.NoError(t, os.Setenv("RECEIVERS_EXAMPLERECEIVER_EXTRA_MAP_RECV_VALUE_2", receiverExtraMapValue+"_2")) 143 assert.NoError(t, os.Setenv("RECEIVERS_EXAMPLERECEIVER_EXTRA_LIST_VALUE_1", receiverExtraListElement+"_1")) 144 assert.NoError(t, os.Setenv("RECEIVERS_EXAMPLERECEIVER_EXTRA_LIST_VALUE_2", receiverExtraListElement+"_2")) 145 146 const processorExtra = "some processor string" 147 const processorExtraMapValue = "some processor map value" 148 const processorExtraListElement = "some processor list value" 149 assert.NoError(t, os.Setenv("PROCESSORS_EXAMPLEPROCESSOR_EXTRA", processorExtra)) 150 assert.NoError(t, os.Setenv("PROCESSORS_EXAMPLEPROCESSOR_EXTRA_MAP_PROC_VALUE_1", processorExtraMapValue+"_1")) 151 assert.NoError(t, os.Setenv("PROCESSORS_EXAMPLEPROCESSOR_EXTRA_MAP_PROC_VALUE_2", processorExtraMapValue+"_2")) 152 assert.NoError(t, os.Setenv("PROCESSORS_EXAMPLEPROCESSOR_EXTRA_LIST_VALUE_1", processorExtraListElement+"_1")) 153 assert.NoError(t, os.Setenv("PROCESSORS_EXAMPLEPROCESSOR_EXTRA_LIST_VALUE_2", processorExtraListElement+"_2")) 154 155 const exporterExtra = "some exporter string" 156 const exporterExtraMapValue = "some exporter map value" 157 const exporterExtraListElement = "some exporter list value" 158 assert.NoError(t, os.Setenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA_INT", "65")) 159 assert.NoError(t, os.Setenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA", exporterExtra)) 160 assert.NoError(t, os.Setenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA_MAP_EXP_VALUE_1", exporterExtraMapValue+"_1")) 161 assert.NoError(t, os.Setenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA_MAP_EXP_VALUE_2", exporterExtraMapValue+"_2")) 162 assert.NoError(t, os.Setenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA_LIST_VALUE_1", exporterExtraListElement+"_1")) 163 assert.NoError(t, os.Setenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA_LIST_VALUE_2", exporterExtraListElement+"_2")) 164 165 defer func() { 166 assert.NoError(t, os.Unsetenv("EXTENSIONS_EXAMPLEEXTENSION_EXTRA")) 167 assert.NoError(t, os.Unsetenv("EXTENSIONS_EXAMPLEEXTENSION_EXTRA_MAP_EXT_VALUE")) 168 assert.NoError(t, os.Unsetenv("EXTENSIONS_EXAMPLEEXTENSION_EXTRA_LIST_VALUE_1")) 169 170 assert.NoError(t, os.Unsetenv("RECEIVERS_EXAMPLERECEIVER_EXTRA")) 171 assert.NoError(t, os.Unsetenv("RECEIVERS_EXAMPLERECEIVER_EXTRA_MAP_RECV_VALUE")) 172 assert.NoError(t, os.Unsetenv("RECEIVERS_EXAMPLERECEIVER_EXTRA_LIST_VALUE_1")) 173 174 assert.NoError(t, os.Unsetenv("PROCESSORS_EXAMPLEPROCESSOR_EXTRA")) 175 assert.NoError(t, os.Unsetenv("PROCESSORS_EXAMPLEPROCESSOR_EXTRA_MAP_PROC_VALUE")) 176 assert.NoError(t, os.Unsetenv("PROCESSORS_EXAMPLEPROCESSOR_EXTRA_LIST_VALUE_1")) 177 178 assert.NoError(t, os.Unsetenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA_INT")) 179 assert.NoError(t, os.Unsetenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA")) 180 assert.NoError(t, os.Unsetenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA_MAP_EXP_VALUE")) 181 assert.NoError(t, os.Unsetenv("EXPORTERS_EXAMPLEEXPORTER_EXTRA_LIST_VALUE_1")) 182 }() 183 184 for _, test := range testCases { 185 t.Run(test.name, func(t *testing.T) { 186 factories, err := testcomponents.ExampleComponents() 187 assert.NoError(t, err) 188 189 // Load the config 190 cfg, err := loadConfigFile(t, path.Join(".", "testdata", test.name+".yaml"), factories) 191 require.NoError(t, err, "Unable to load config") 192 193 // Verify extensions. 194 assert.Equalf(t, 1, len(cfg.Extensions), "TEST[%s]", test.name) 195 assert.Equalf(t, 196 &testcomponents.ExampleExtensionCfg{ 197 ExtensionSettings: config.NewExtensionSettings(config.NewID("exampleextension")), 198 ExtraSetting: extensionExtra, 199 ExtraMapSetting: map[string]string{"ext-1": extensionExtraMapValue + "_1", "ext-2": extensionExtraMapValue + "_2"}, 200 ExtraListSetting: []string{extensionExtraListElement + "_1", extensionExtraListElement + "_2"}, 201 }, 202 cfg.Extensions[config.NewID("exampleextension")], 203 "TEST[%s] Did not load extension config correctly", test.name) 204 205 // Verify service. 206 assert.Equalf(t, 1, len(cfg.Service.Extensions), "TEST[%s]", test.name) 207 assert.Equalf(t, config.NewID("exampleextension"), cfg.Service.Extensions[0], "TEST[%s]", test.name) 208 209 // Verify receivers 210 assert.Equalf(t, 1, len(cfg.Receivers), "TEST[%s]", test.name) 211 212 assert.Equalf(t, 213 &testcomponents.ExampleReceiver{ 214 ReceiverSettings: config.NewReceiverSettings(config.NewID("examplereceiver")), 215 TCPAddr: confignet.TCPAddr{ 216 Endpoint: "localhost:1234", 217 }, 218 ExtraSetting: receiverExtra, 219 ExtraMapSetting: map[string]string{"recv.1": receiverExtraMapValue + "_1", "recv.2": receiverExtraMapValue + "_2"}, 220 ExtraListSetting: []string{receiverExtraListElement + "_1", receiverExtraListElement + "_2"}, 221 }, 222 cfg.Receivers[config.NewID("examplereceiver")], 223 "TEST[%s] Did not load receiver config correctly", test.name) 224 225 // Verify exporters 226 assert.Equalf(t, 1, len(cfg.Exporters), "TEST[%s]", test.name) 227 228 assert.Equalf(t, 229 &testcomponents.ExampleExporter{ 230 ExporterSettings: config.NewExporterSettings(config.NewID("exampleexporter")), 231 ExtraInt: 65, 232 ExtraSetting: exporterExtra, 233 ExtraMapSetting: map[string]string{"exp_1": exporterExtraMapValue + "_1", "exp_2": exporterExtraMapValue + "_2"}, 234 ExtraListSetting: []string{exporterExtraListElement + "_1", exporterExtraListElement + "_2"}, 235 }, 236 cfg.Exporters[config.NewID("exampleexporter")], 237 "TEST[%s] Did not load exporter config correctly", test.name) 238 239 // Verify Processors 240 assert.Equalf(t, 1, len(cfg.Processors), "TEST[%s]", test.name) 241 242 assert.Equalf(t, 243 &testcomponents.ExampleProcessorCfg{ 244 ProcessorSettings: config.NewProcessorSettings(config.NewID("exampleprocessor")), 245 ExtraSetting: processorExtra, 246 ExtraMapSetting: map[string]string{"proc_1": processorExtraMapValue + "_1", "proc_2": processorExtraMapValue + "_2"}, 247 ExtraListSetting: []string{processorExtraListElement + "_1", processorExtraListElement + "_2"}, 248 }, 249 cfg.Processors[config.NewID("exampleprocessor")], 250 "TEST[%s] Did not load processor config correctly", test.name) 251 252 // Verify Pipelines 253 assert.Equalf(t, 1, len(cfg.Service.Pipelines), "TEST[%s]", test.name) 254 255 assert.Equalf(t, 256 &config.Pipeline{ 257 Name: "traces", 258 InputType: config.TracesDataType, 259 Receivers: []config.ComponentID{config.NewID("examplereceiver")}, 260 Processors: []config.ComponentID{config.NewID("exampleprocessor")}, 261 Exporters: []config.ComponentID{config.NewID("exampleexporter")}, 262 }, 263 cfg.Service.Pipelines["traces"], 264 "TEST[%s] Did not load pipeline config correctly", test.name) 265 }) 266 } 267} 268 269func TestEscapedEnvVars(t *testing.T) { 270 const receiverExtraMapValue = "some receiver map value" 271 assert.NoError(t, os.Setenv("RECEIVERS_EXAMPLERECEIVER_EXTRA_MAP_RECV_VALUE_2", receiverExtraMapValue)) 272 defer func() { 273 assert.NoError(t, os.Unsetenv("RECEIVERS_EXAMPLERECEIVER_EXTRA_MAP_RECV_VALUE_2")) 274 }() 275 276 factories, err := testcomponents.ExampleComponents() 277 assert.NoError(t, err) 278 279 // Load the config 280 cfg, err := loadConfigFile(t, path.Join(".", "testdata", "simple-config-with-escaped-env.yaml"), factories) 281 require.NoError(t, err, "Unable to load config") 282 283 // Verify extensions. 284 assert.Equal(t, 1, len(cfg.Extensions)) 285 assert.Equal(t, 286 &testcomponents.ExampleExtensionCfg{ 287 ExtensionSettings: config.NewExtensionSettings(config.NewID("exampleextension")), 288 ExtraSetting: "${EXTENSIONS_EXAMPLEEXTENSION_EXTRA}", 289 ExtraMapSetting: map[string]string{"ext-1": "${EXTENSIONS_EXAMPLEEXTENSION_EXTRA_MAP_EXT_VALUE_1}", "ext-2": "${EXTENSIONS_EXAMPLEEXTENSION_EXTRA_MAP_EXT_VALUE_2}"}, 290 ExtraListSetting: []string{"${EXTENSIONS_EXAMPLEEXTENSION_EXTRA_LIST_VALUE_1}", "${EXTENSIONS_EXAMPLEEXTENSION_EXTRA_LIST_VALUE_2}"}, 291 }, 292 cfg.Extensions[config.NewID("exampleextension")], 293 "Did not load extension config correctly") 294 295 // Verify service. 296 assert.Equal(t, 1, len(cfg.Service.Extensions)) 297 assert.Equal(t, config.NewID("exampleextension"), cfg.Service.Extensions[0]) 298 299 // Verify receivers 300 assert.Equal(t, 1, len(cfg.Receivers)) 301 302 assert.Equal(t, 303 &testcomponents.ExampleReceiver{ 304 ReceiverSettings: config.NewReceiverSettings(config.NewID("examplereceiver")), 305 TCPAddr: confignet.TCPAddr{ 306 Endpoint: "localhost:1234", 307 }, 308 ExtraSetting: "$RECEIVERS_EXAMPLERECEIVER_EXTRA", 309 ExtraMapSetting: map[string]string{ 310 // $$ -> escaped $ 311 "recv.1": "$RECEIVERS_EXAMPLERECEIVER_EXTRA_MAP_RECV_VALUE_1", 312 // $$$ -> escaped $ + substituted env var 313 "recv.2": "$" + receiverExtraMapValue, 314 // $$$$ -> two escaped $ 315 "recv.3": "$$RECEIVERS_EXAMPLERECEIVER_EXTRA_MAP_RECV_VALUE_3", 316 // escaped $ in the middle 317 "recv.4": "some${RECEIVERS_EXAMPLERECEIVER_EXTRA_MAP_RECV_VALUE_4}text", 318 // $$$$ -> two escaped $ 319 "recv.5": "${ONE}${TWO}", 320 // trailing escaped $ 321 "recv.6": "text$", 322 // escaped $ alone 323 "recv.7": "$", 324 }, 325 ExtraListSetting: []string{"$RECEIVERS_EXAMPLERECEIVER_EXTRA_LIST_VALUE_1", "$RECEIVERS_EXAMPLERECEIVER_EXTRA_LIST_VALUE_2"}, 326 }, 327 cfg.Receivers[config.NewID("examplereceiver")], 328 "Did not load receiver config correctly") 329 330 // Verify exporters 331 assert.Equal(t, 1, len(cfg.Exporters)) 332 333 assert.Equal(t, 334 &testcomponents.ExampleExporter{ 335 ExporterSettings: config.NewExporterSettings(config.NewID("exampleexporter")), 336 ExtraSetting: "${EXPORTERS_EXAMPLEEXPORTER_EXTRA}", 337 ExtraMapSetting: map[string]string{"exp_1": "${EXPORTERS_EXAMPLEEXPORTER_EXTRA_MAP_EXP_VALUE_1}", "exp_2": "${EXPORTERS_EXAMPLEEXPORTER_EXTRA_MAP_EXP_VALUE_2}"}, 338 ExtraListSetting: []string{"${EXPORTERS_EXAMPLEEXPORTER_EXTRA_LIST_VALUE_1}", "${EXPORTERS_EXAMPLEEXPORTER_EXTRA_LIST_VALUE_2}"}, 339 }, 340 cfg.Exporters[config.NewID("exampleexporter")], 341 "Did not load exporter config correctly") 342 343 // Verify Processors 344 assert.Equal(t, 1, len(cfg.Processors)) 345 346 assert.Equal(t, 347 &testcomponents.ExampleProcessorCfg{ 348 ProcessorSettings: config.NewProcessorSettings(config.NewID("exampleprocessor")), 349 ExtraSetting: "$PROCESSORS_EXAMPLEPROCESSOR_EXTRA", 350 ExtraMapSetting: map[string]string{"proc_1": "$PROCESSORS_EXAMPLEPROCESSOR_EXTRA_MAP_PROC_VALUE_1", "proc_2": "$PROCESSORS_EXAMPLEPROCESSOR_EXTRA_MAP_PROC_VALUE_2"}, 351 ExtraListSetting: []string{"$PROCESSORS_EXAMPLEPROCESSOR_EXTRA_LIST_VALUE_1", "$PROCESSORS_EXAMPLEPROCESSOR_EXTRA_LIST_VALUE_2"}, 352 }, 353 cfg.Processors[config.NewID("exampleprocessor")], 354 "Did not load processor config correctly") 355 356 // Verify Pipelines 357 assert.Equal(t, 1, len(cfg.Service.Pipelines)) 358 359 assert.Equal(t, 360 &config.Pipeline{ 361 Name: "traces", 362 InputType: config.TracesDataType, 363 Receivers: []config.ComponentID{config.NewID("examplereceiver")}, 364 Processors: []config.ComponentID{config.NewID("exampleprocessor")}, 365 Exporters: []config.ComponentID{config.NewID("exampleexporter")}, 366 }, 367 cfg.Service.Pipelines["traces"], 368 "Did not load pipeline config correctly") 369} 370 371func TestDecodeConfig_Invalid(t *testing.T) { 372 373 var testCases = []struct { 374 name string // test case name (also file name containing config yaml) 375 expected configErrorCode // expected error (if nil any error is acceptable) 376 expectedMessage string // string that the error must contain 377 }{ 378 {name: "invalid-extension-type", expected: errInvalidTypeAndNameKey}, 379 {name: "invalid-receiver-type", expected: errInvalidTypeAndNameKey}, 380 {name: "invalid-exporter-type", expected: errInvalidTypeAndNameKey}, 381 {name: "invalid-processor-type", expected: errInvalidTypeAndNameKey}, 382 {name: "invalid-pipeline-type", expected: errInvalidTypeAndNameKey}, 383 384 {name: "invalid-extension-name-after-slash", expected: errInvalidTypeAndNameKey}, 385 {name: "invalid-receiver-name-after-slash", expected: errInvalidTypeAndNameKey}, 386 {name: "invalid-exporter-name-after-slash", expected: errInvalidTypeAndNameKey}, 387 {name: "invalid-processor-name-after-slash", expected: errInvalidTypeAndNameKey}, 388 {name: "invalid-pipeline-name-after-slash", expected: errInvalidTypeAndNameKey}, 389 390 {name: "unknown-extension-type", expected: errUnknownType, expectedMessage: "extensions"}, 391 {name: "unknown-receiver-type", expected: errUnknownType, expectedMessage: "receivers"}, 392 {name: "unknown-exporter-type", expected: errUnknownType, expectedMessage: "exporters"}, 393 {name: "unknown-processor-type", expected: errUnknownType, expectedMessage: "processors"}, 394 {name: "unknown-pipeline-type", expected: errUnknownType, expectedMessage: "pipelines"}, 395 396 {name: "duplicate-extension", expected: errDuplicateName, expectedMessage: "extensions"}, 397 {name: "duplicate-receiver", expected: errDuplicateName, expectedMessage: "receivers"}, 398 {name: "duplicate-exporter", expected: errDuplicateName, expectedMessage: "exporters"}, 399 {name: "duplicate-processor", expected: errDuplicateName, expectedMessage: "processors"}, 400 {name: "duplicate-pipeline", expected: errDuplicateName, expectedMessage: "pipelines"}, 401 402 {name: "invalid-top-level-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "top level"}, 403 {name: "invalid-extension-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "extensions"}, 404 {name: "invalid-receiver-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "receivers"}, 405 {name: "invalid-processor-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "processors"}, 406 {name: "invalid-exporter-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "exporters"}, 407 {name: "invalid-service-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "service"}, 408 {name: "invalid-service-extensions-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "service"}, 409 {name: "invalid-pipeline-section", expected: errUnmarshalTopLevelStructureError, expectedMessage: "pipelines"}, 410 {name: "invalid-sequence-value", expected: errUnmarshalTopLevelStructureError, expectedMessage: "pipelines"}, 411 412 {name: "invalid-extension-sub-config", expected: errUnmarshalTopLevelStructureError}, 413 {name: "invalid-exporter-sub-config", expected: errUnmarshalTopLevelStructureError}, 414 {name: "invalid-processor-sub-config", expected: errUnmarshalTopLevelStructureError}, 415 {name: "invalid-receiver-sub-config", expected: errUnmarshalTopLevelStructureError}, 416 {name: "invalid-pipeline-sub-config", expected: errUnmarshalTopLevelStructureError}, 417 } 418 419 factories, err := testcomponents.ExampleComponents() 420 assert.NoError(t, err) 421 422 for _, test := range testCases { 423 t.Run(test.name, func(t *testing.T) { 424 _, err := loadConfigFile(t, path.Join(".", "testdata", test.name+".yaml"), factories) 425 require.Error(t, err) 426 if test.expected != 0 { 427 cfgErr, ok := err.(*configError) 428 if !ok { 429 t.Errorf("expected config error code %v but got a different error '%v'", test.expected, err) 430 } else { 431 assert.Equal(t, test.expected, cfgErr.code, err) 432 if test.expectedMessage != "" { 433 assert.Contains(t, cfgErr.Error(), test.expectedMessage) 434 } 435 assert.NotEmpty(t, cfgErr.Error(), "returned config error %v with empty error message", cfgErr.code) 436 } 437 } 438 }) 439 } 440} 441 442func TestLoadEmpty(t *testing.T) { 443 factories, err := testcomponents.ExampleComponents() 444 assert.NoError(t, err) 445 446 _, err = loadConfigFile(t, path.Join(".", "testdata", "empty-config.yaml"), factories) 447 assert.NoError(t, err) 448} 449 450func TestLoadEmptyAllSections(t *testing.T) { 451 factories, err := testcomponents.ExampleComponents() 452 assert.NoError(t, err) 453 454 _, err = loadConfigFile(t, path.Join(".", "testdata", "empty-all-sections.yaml"), factories) 455 assert.NoError(t, err) 456} 457 458func loadConfigFile(t *testing.T, fileName string, factories component.Factories) (*config.Config, error) { 459 v, err := configparser.NewParserFromFile(fileName) 460 require.NoError(t, err) 461 462 // Load the config from the configparser.Parser using the given factories. 463 return Load(v, factories) 464} 465 466type nestedConfig struct { 467 NestedStringValue string 468 NestedIntValue int 469} 470 471type testConfig struct { 472 config.ExporterSettings 473 474 NestedConfigPtr *nestedConfig 475 NestedConfigValue nestedConfig 476 StringValue string 477 StringPtrValue *string 478 IntValue int 479} 480 481func TestExpandEnvLoadedConfig(t *testing.T) { 482 assert.NoError(t, os.Setenv("NESTED_VALUE", "replaced_nested_value")) 483 assert.NoError(t, os.Setenv("VALUE", "replaced_value")) 484 assert.NoError(t, os.Setenv("PTR_VALUE", "replaced_ptr_value")) 485 486 defer func() { 487 assert.NoError(t, os.Unsetenv("NESTED_VALUE")) 488 assert.NoError(t, os.Unsetenv("VALUE")) 489 assert.NoError(t, os.Unsetenv("PTR_VALUE")) 490 }() 491 492 testString := "$PTR_VALUE" 493 494 cfg := &testConfig{ 495 ExporterSettings: config.NewExporterSettings(config.NewID("test")), 496 NestedConfigPtr: &nestedConfig{ 497 NestedStringValue: "$NESTED_VALUE", 498 NestedIntValue: 1, 499 }, 500 NestedConfigValue: nestedConfig{ 501 NestedStringValue: "$NESTED_VALUE", 502 NestedIntValue: 2, 503 }, 504 StringValue: "$VALUE", 505 StringPtrValue: &testString, 506 IntValue: 3, 507 } 508 509 expandEnvLoadedConfig(cfg) 510 511 replacedTestString := "replaced_ptr_value" 512 513 assert.Equal(t, &testConfig{ 514 ExporterSettings: config.NewExporterSettings(config.NewID("test")), 515 NestedConfigPtr: &nestedConfig{ 516 NestedStringValue: "replaced_nested_value", 517 NestedIntValue: 1, 518 }, 519 NestedConfigValue: nestedConfig{ 520 NestedStringValue: "replaced_nested_value", 521 NestedIntValue: 2, 522 }, 523 StringValue: "replaced_value", 524 StringPtrValue: &replacedTestString, 525 IntValue: 3, 526 }, cfg) 527} 528 529func TestExpandEnvLoadedConfigEscapedEnv(t *testing.T) { 530 assert.NoError(t, os.Setenv("NESTED_VALUE", "replaced_nested_value")) 531 assert.NoError(t, os.Setenv("ESCAPED_VALUE", "replaced_escaped_value")) 532 assert.NoError(t, os.Setenv("ESCAPED_PTR_VALUE", "replaced_escaped_pointer_value")) 533 534 defer func() { 535 assert.NoError(t, os.Unsetenv("NESTED_VALUE")) 536 assert.NoError(t, os.Unsetenv("ESCAPED_VALUE")) 537 assert.NoError(t, os.Unsetenv("ESCAPED_PTR_VALUE")) 538 }() 539 540 testString := "$$ESCAPED_PTR_VALUE" 541 542 cfg := &testConfig{ 543 ExporterSettings: config.NewExporterSettings(config.NewID("test")), 544 NestedConfigPtr: &nestedConfig{ 545 NestedStringValue: "$NESTED_VALUE", 546 NestedIntValue: 1, 547 }, 548 NestedConfigValue: nestedConfig{ 549 NestedStringValue: "$NESTED_VALUE", 550 NestedIntValue: 2, 551 }, 552 StringValue: "$$ESCAPED_VALUE", 553 StringPtrValue: &testString, 554 IntValue: 3, 555 } 556 557 expandEnvLoadedConfig(cfg) 558 559 replacedTestString := "$ESCAPED_PTR_VALUE" 560 561 assert.Equal(t, &testConfig{ 562 ExporterSettings: config.NewExporterSettings(config.NewID("test")), 563 NestedConfigPtr: &nestedConfig{ 564 NestedStringValue: "replaced_nested_value", 565 NestedIntValue: 1, 566 }, 567 NestedConfigValue: nestedConfig{ 568 NestedStringValue: "replaced_nested_value", 569 NestedIntValue: 2, 570 }, 571 StringValue: "$ESCAPED_VALUE", 572 StringPtrValue: &replacedTestString, 573 IntValue: 3, 574 }, cfg) 575} 576 577func TestExpandEnvLoadedConfigMissingEnv(t *testing.T) { 578 assert.NoError(t, os.Setenv("NESTED_VALUE", "replaced_nested_value")) 579 580 defer func() { 581 assert.NoError(t, os.Unsetenv("NESTED_VALUE")) 582 }() 583 584 testString := "$PTR_VALUE" 585 586 cfg := &testConfig{ 587 ExporterSettings: config.NewExporterSettings(config.NewID("test")), 588 NestedConfigPtr: &nestedConfig{ 589 NestedStringValue: "$NESTED_VALUE", 590 NestedIntValue: 1, 591 }, 592 NestedConfigValue: nestedConfig{ 593 NestedStringValue: "$NESTED_VALUE", 594 NestedIntValue: 2, 595 }, 596 StringValue: "$VALUE", 597 StringPtrValue: &testString, 598 IntValue: 3, 599 } 600 601 expandEnvLoadedConfig(cfg) 602 603 replacedTestString := "" 604 605 assert.Equal(t, &testConfig{ 606 ExporterSettings: config.NewExporterSettings(config.NewID("test")), 607 NestedConfigPtr: &nestedConfig{ 608 NestedStringValue: "replaced_nested_value", 609 NestedIntValue: 1, 610 }, 611 NestedConfigValue: nestedConfig{ 612 NestedStringValue: "replaced_nested_value", 613 NestedIntValue: 2, 614 }, 615 StringValue: "", 616 StringPtrValue: &replacedTestString, 617 IntValue: 3, 618 }, cfg) 619} 620 621func TestExpandEnvLoadedConfigNil(t *testing.T) { 622 var cfg *testConfig 623 624 // This should safely do nothing 625 expandEnvLoadedConfig(cfg) 626 627 assert.Equal(t, (*testConfig)(nil), cfg) 628} 629 630func TestExpandEnvLoadedConfigNoPointer(t *testing.T) { 631 assert.NoError(t, os.Setenv("VALUE", "replaced_value")) 632 633 cfg := testConfig{ 634 StringValue: "$VALUE", 635 } 636 637 // This should do nothing as cfg is not a pointer 638 expandEnvLoadedConfig(cfg) 639 640 assert.Equal(t, testConfig{StringValue: "$VALUE"}, cfg) 641} 642 643type testUnexportedConfig struct { 644 config.ExporterSettings 645 646 unexportedStringValue string 647 ExportedStringValue string 648} 649 650func TestExpandEnvLoadedConfigUnexportedField(t *testing.T) { 651 assert.NoError(t, os.Setenv("VALUE", "replaced_value")) 652 653 defer func() { 654 assert.NoError(t, os.Unsetenv("VALUE")) 655 }() 656 657 cfg := &testUnexportedConfig{ 658 unexportedStringValue: "$VALUE", 659 ExportedStringValue: "$VALUE", 660 } 661 662 expandEnvLoadedConfig(cfg) 663 664 assert.Equal(t, &testUnexportedConfig{ 665 unexportedStringValue: "$VALUE", 666 ExportedStringValue: "replaced_value", 667 }, cfg) 668} 669