opentelemetry-collector/service/internal/builder/pipelines_builder_test.go

271 lines
8.4 KiB
Go

// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package builder
import (
"context"
"path"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/component/componenttest"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/config/configtest"
"go.opentelemetry.io/collector/consumer"
"go.opentelemetry.io/collector/consumer/pdata"
"go.opentelemetry.io/collector/internal/testcomponents"
"go.opentelemetry.io/collector/internal/testdata"
)
func TestBuildPipelines(t *testing.T) {
tests := []struct {
name string
pipelineName string
exporterNames []string
}{
{
name: "one-exporter",
pipelineName: "traces",
exporterNames: []string{"exampleexporter"},
},
{
name: "multi-exporter",
pipelineName: "traces/2",
exporterNames: []string{"exampleexporter", "exampleexporter/2"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
testPipeline(t, test.pipelineName, test.exporterNames)
})
}
}
func createExampleConfig(dataType string) *configmodels.Config {
exampleReceiverFactory := testcomponents.ExampleReceiverFactory
exampleProcessorFactory := testcomponents.ExampleProcessorFactory
exampleExporterFactory := testcomponents.ExampleExporterFactory
cfg := &configmodels.Config{
Receivers: map[string]configmodels.Receiver{
string(exampleReceiverFactory.Type()): exampleReceiverFactory.CreateDefaultConfig(),
},
Processors: map[string]configmodels.Processor{
string(exampleProcessorFactory.Type()): exampleProcessorFactory.CreateDefaultConfig(),
},
Exporters: map[string]configmodels.Exporter{
string(exampleExporterFactory.Type()): exampleExporterFactory.CreateDefaultConfig(),
},
Service: configmodels.Service{
Pipelines: map[string]*configmodels.Pipeline{
dataType: {
Name: dataType,
InputType: configmodels.DataType(dataType),
Receivers: []string{string(exampleReceiverFactory.Type())},
Processors: []string{string(exampleProcessorFactory.Type())},
Exporters: []string{string(exampleExporterFactory.Type())},
},
},
},
}
return cfg
}
func TestBuildPipelines_BuildVarious(t *testing.T) {
factories := createTestFactories()
tests := []struct {
dataType string
shouldFail bool
}{
{
dataType: "logs",
shouldFail: false,
},
{
dataType: "nosuchdatatype",
shouldFail: true,
},
}
for _, test := range tests {
t.Run(test.dataType, func(t *testing.T) {
dataType := test.dataType
cfg := createExampleConfig(dataType)
// BuildProcessors the pipeline
allExporters, err := BuildExporters(zap.NewNop(), component.DefaultApplicationStartInfo(), cfg, factories.Exporters)
if test.shouldFail {
assert.Error(t, err)
return
}
require.NoError(t, err)
require.EqualValues(t, 1, len(allExporters))
pipelineProcessors, err := BuildPipelines(zap.NewNop(), component.DefaultApplicationStartInfo(), cfg, allExporters, factories.Processors)
assert.NoError(t, err)
require.NotNil(t, pipelineProcessors)
err = pipelineProcessors.StartProcessors(context.Background(), componenttest.NewNopHost())
assert.NoError(t, err)
pipelineName := dataType
processor := pipelineProcessors[cfg.Service.Pipelines[pipelineName]]
// Ensure pipeline has its fields correctly populated.
require.NotNil(t, processor)
assert.Nil(t, processor.firstTC)
assert.Nil(t, processor.firstMC)
assert.NotNil(t, processor.firstLC)
// Compose the list of created exporters.
exporterNames := []string{"exampleexporter"}
var exporters []*builtExporter
for _, name := range exporterNames {
// Ensure exporter is created.
exp := allExporters[cfg.Exporters[name]]
require.NotNil(t, exp)
exporters = append(exporters, exp)
}
// Send Logs via processor and verify that all exporters of the pipeline receive it.
// First check that there are no logs in the exporters yet.
var exporterConsumers []*testcomponents.ExampleExporterConsumer
for _, exporter := range exporters {
expConsumer := exporter.getLogExporter().(*testcomponents.ExampleExporterConsumer)
exporterConsumers = append(exporterConsumers, expConsumer)
require.Equal(t, len(expConsumer.Logs), 0)
}
// Send one custom data.
log := pdata.Logs{}
processor.firstLC.(consumer.Logs).ConsumeLogs(context.Background(), log)
// Now verify received data.
for _, expConsumer := range exporterConsumers {
// Check that the trace is received by exporter.
require.Equal(t, 1, len(expConsumer.Logs))
// Verify that span is successfully delivered.
assert.EqualValues(t, log, expConsumer.Logs[0])
}
err = pipelineProcessors.ShutdownProcessors(context.Background())
assert.NoError(t, err)
})
}
}
func testPipeline(t *testing.T, pipelineName string, exporterNames []string) {
factories, err := testcomponents.ExampleComponents()
assert.NoError(t, err)
cfg, err := configtest.LoadConfigFile(t, "testdata/pipelines_builder.yaml", factories)
// Load the config
require.Nil(t, err)
// BuildProcessors the pipeline
allExporters, err := BuildExporters(zap.NewNop(), component.DefaultApplicationStartInfo(), cfg, factories.Exporters)
assert.NoError(t, err)
pipelineProcessors, err := BuildPipelines(zap.NewNop(), component.DefaultApplicationStartInfo(), cfg, allExporters, factories.Processors)
assert.NoError(t, err)
require.NotNil(t, pipelineProcessors)
assert.NoError(t, pipelineProcessors.StartProcessors(context.Background(), componenttest.NewNopHost()))
processor := pipelineProcessors[cfg.Service.Pipelines[pipelineName]]
// Ensure pipeline has its fields correctly populated.
require.NotNil(t, processor)
assert.NotNil(t, processor.firstTC)
assert.Nil(t, processor.firstMC)
// Compose the list of created exporters.
var exporters []*builtExporter
for _, name := range exporterNames {
// Ensure exporter is created.
exp := allExporters[cfg.Exporters[name]]
require.NotNil(t, exp)
exporters = append(exporters, exp)
}
// Send TraceData via processor and verify that all exporters of the pipeline receive it.
// First check that there are no traces in the exporters yet.
var exporterConsumers []*testcomponents.ExampleExporterConsumer
for _, exporter := range exporters {
expConsumer := exporter.getTraceExporter().(*testcomponents.ExampleExporterConsumer)
exporterConsumers = append(exporterConsumers, expConsumer)
require.Equal(t, len(expConsumer.Traces), 0)
}
td := testdata.GenerateTraceDataOneSpan()
processor.firstTC.(consumer.Traces).ConsumeTraces(context.Background(), td)
// Now verify received data.
for _, expConsumer := range exporterConsumers {
// Check that the trace is received by exporter.
require.Equal(t, 1, len(expConsumer.Traces))
// Verify that span is successfully delivered.
assert.EqualValues(t, td, expConsumer.Traces[0])
}
err = pipelineProcessors.ShutdownProcessors(context.Background())
assert.NoError(t, err)
}
func TestBuildPipelines_NotSupportedDataType(t *testing.T) {
factories := createTestFactories()
tests := []struct {
configFile string
}{
{
configFile: "not_supported_processor_logs.yaml",
},
{
configFile: "not_supported_processor_metrics.yaml",
},
{
configFile: "not_supported_processor_traces.yaml",
},
}
for _, test := range tests {
t.Run(test.configFile, func(t *testing.T) {
cfg, err := configtest.LoadConfigFile(t, path.Join("testdata", test.configFile), factories)
require.Nil(t, err)
allExporters, err := BuildExporters(zap.NewNop(), component.DefaultApplicationStartInfo(), cfg, factories.Exporters)
assert.NoError(t, err)
pipelineProcessors, err := BuildPipelines(zap.NewNop(), component.DefaultApplicationStartInfo(), cfg, allExporters, factories.Processors)
assert.Error(t, err)
assert.Zero(t, len(pipelineProcessors))
})
}
}