From 38de96d1b9cb4092103fd0d54a5e26bfc87fbcdb Mon Sep 17 00:00:00 2001 From: Dmitry Anoshin Date: Mon, 4 Mar 2024 11:38:02 -0800 Subject: [PATCH] [cmd/mdatagen] Pull new changes from contrib --- .chloggen/mdatagen-tests.yaml | 27 ++++ cmd/mdatagen/doc.go | 7 - cmd/mdatagen/go.mod | 3 +- cmd/mdatagen/internal/samplereceiver/doc.go | 10 ++ .../samplereceiver}/documentation.md | 2 +- .../internal/samplereceiver/factory.go | 43 ++++++ .../generated_component_test.go | 76 ++++++++++ .../internal}/metadata/generated_config.go | 6 +- .../metadata/generated_config_test.go | 0 .../internal}/metadata/generated_metrics.go | 2 +- .../metadata/generated_metrics_test.go | 0 .../internal}/metadata/generated_resource.go | 0 .../metadata/generated_resource_test.go | 0 .../internal}/metadata/generated_status.go | 6 +- .../internal}/metadata/testdata/config.yaml | 0 .../samplereceiver/metadata.yaml} | 11 +- .../internal/samplereceiver/metrics_test.go | 21 +++ cmd/mdatagen/lint_test.go | 2 +- cmd/mdatagen/loader.go | 3 +- cmd/mdatagen/loader_test.go | 28 ++-- cmd/mdatagen/main.go | 20 ++- cmd/mdatagen/main_test.go | 101 +++++-------- cmd/mdatagen/metadata-schema.yaml | 4 + cmd/mdatagen/metricdata.go | 4 +- cmd/mdatagen/package_test.go | 14 ++ cmd/mdatagen/statusdata.go | 47 +++++- cmd/mdatagen/templates/component_test.go.tmpl | 137 ++++++++++++------ cmd/mdatagen/templates/readme.md.tmpl | 6 +- cmd/mdatagen/templates/status.go.tmpl | 4 +- cmd/mdatagen/testdata/metrics_and_type.yaml | 4 + .../testdata/resource_attributes_only.yaml | 4 + cmd/mdatagen/testdata/status_only.yaml | 4 + cmd/mdatagen/validate.go | 11 +- cmd/mdatagen/validate_test.go | 6 +- .../generated_component_test.go | 76 ++++++++++ connector/forwardconnector/go.mod | 2 +- .../debugexporter/generated_component_test.go | 137 ++++++++++++++++++ exporter/debugexporter/go.mod | 2 +- .../generated_component_test.go | 137 ++++++++++++++++++ exporter/loggingexporter/go.mod | 2 +- exporter/otlpexporter/metadata.yaml | 5 + exporter/otlphttpexporter/metadata.yaml | 5 + .../generated_component_test.go | 43 ++++++ .../generated_component_test.go | 37 +++++ extension/memorylimiterextension/go.mod | 2 +- .../memorylimiterextension/metadata.yaml | 8 + .../generated_component_test.go | 43 ++++++ .../generated_component_test.go | 103 +++++++++++++ processor/batchprocessor/metadata.yaml | 4 + .../generated_component_test.go | 130 +++++++++++++++++ processor/memorylimiterprocessor/go.mod | 2 +- .../memorylimiterprocessor/metadata.yaml | 8 + .../otlpreceiver/generated_component_test.go | 76 ++++++++++ 53 files changed, 1250 insertions(+), 185 deletions(-) create mode 100644 .chloggen/mdatagen-tests.yaml delete mode 100644 cmd/mdatagen/doc.go create mode 100644 cmd/mdatagen/internal/samplereceiver/doc.go rename cmd/mdatagen/{ => internal/samplereceiver}/documentation.md (99%) create mode 100644 cmd/mdatagen/internal/samplereceiver/factory.go create mode 100644 cmd/mdatagen/internal/samplereceiver/generated_component_test.go rename cmd/mdatagen/internal/{ => samplereceiver/internal}/metadata/generated_config.go (94%) rename cmd/mdatagen/internal/{ => samplereceiver/internal}/metadata/generated_config_test.go (100%) rename cmd/mdatagen/internal/{ => samplereceiver/internal}/metadata/generated_metrics.go (99%) rename cmd/mdatagen/internal/{ => samplereceiver/internal}/metadata/generated_metrics_test.go (100%) rename cmd/mdatagen/internal/{ => samplereceiver/internal}/metadata/generated_resource.go (100%) rename cmd/mdatagen/internal/{ => samplereceiver/internal}/metadata/generated_resource_test.go (100%) rename cmd/mdatagen/internal/{ => samplereceiver/internal}/metadata/generated_status.go (85%) rename cmd/mdatagen/internal/{ => samplereceiver/internal}/metadata/testdata/config.yaml (100%) rename cmd/mdatagen/{metadata-sample.yaml => internal/samplereceiver/metadata.yaml} (95%) create mode 100644 cmd/mdatagen/internal/samplereceiver/metrics_test.go create mode 100644 cmd/mdatagen/package_test.go create mode 100644 connector/forwardconnector/generated_component_test.go create mode 100644 exporter/debugexporter/generated_component_test.go create mode 100644 exporter/loggingexporter/generated_component_test.go create mode 100644 extension/ballastextension/generated_component_test.go create mode 100644 extension/memorylimiterextension/generated_component_test.go create mode 100644 extension/zpagesextension/generated_component_test.go create mode 100644 processor/batchprocessor/generated_component_test.go create mode 100644 processor/memorylimiterprocessor/generated_component_test.go create mode 100644 receiver/otlpreceiver/generated_component_test.go diff --git a/.chloggen/mdatagen-tests.yaml b/.chloggen/mdatagen-tests.yaml new file mode 100644 index 00000000000..4eea0fa6a92 --- /dev/null +++ b/.chloggen/mdatagen-tests.yaml @@ -0,0 +1,27 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: enhancement + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: cmd/mdatagen + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Generate the lifecycle tests for components by default. + +# One or more tracking issues or pull requests related to the change +issues: [9683] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: | + It's encouraged to have lifecycle tests for all components enadled, but they can be disabled if needed + in metadata.yaml with `skip_lifecycle: true` and `skip_shutdown: true` under `tests` section. + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/cmd/mdatagen/doc.go b/cmd/mdatagen/doc.go deleted file mode 100644 index 8f1fc6a7176..00000000000 --- a/cmd/mdatagen/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// Generate a test metrics builder from a sample metrics set covering all configuration options. -//go:generate mdatagen metadata-sample.yaml - -package main diff --git a/cmd/mdatagen/go.mod b/cmd/mdatagen/go.mod index e654d0832c7..5f6aec6722d 100644 --- a/cmd/mdatagen/go.mod +++ b/cmd/mdatagen/go.mod @@ -8,11 +8,13 @@ require ( go.opentelemetry.io/collector/component v0.96.0 go.opentelemetry.io/collector/confmap v0.96.0 go.opentelemetry.io/collector/confmap/provider/fileprovider v0.96.0 + go.opentelemetry.io/collector/consumer v0.96.0 go.opentelemetry.io/collector/pdata v1.3.0 go.opentelemetry.io/collector/receiver v0.96.0 go.opentelemetry.io/collector/semconv v0.96.0 go.opentelemetry.io/otel/metric v1.24.0 go.opentelemetry.io/otel/trace v1.24.0 + go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/text v0.14.0 @@ -41,7 +43,6 @@ require ( github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.96.0 // indirect - go.opentelemetry.io/collector/consumer v0.96.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.46.0 // indirect go.opentelemetry.io/otel/sdk v1.24.0 // indirect diff --git a/cmd/mdatagen/internal/samplereceiver/doc.go b/cmd/mdatagen/internal/samplereceiver/doc.go new file mode 100644 index 00000000000..12febf6e4aa --- /dev/null +++ b/cmd/mdatagen/internal/samplereceiver/doc.go @@ -0,0 +1,10 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Generate a test metrics builder from a sample metrics set covering all configuration options. +//go:generate mdatagen metadata.yaml + +// Deprecated: This package is moving to https://github.com/open-telemetry/opentelemetry-collector and will eventually be removed. +// Please see https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/30497 +// This is a sample receiver package used to showcase how mdatagen is applied. +package samplereceiver diff --git a/cmd/mdatagen/documentation.md b/cmd/mdatagen/internal/samplereceiver/documentation.md similarity index 99% rename from cmd/mdatagen/documentation.md rename to cmd/mdatagen/internal/samplereceiver/documentation.md index 1955e081535..0e29d896d66 100644 --- a/cmd/mdatagen/documentation.md +++ b/cmd/mdatagen/internal/samplereceiver/documentation.md @@ -1,6 +1,6 @@ [comment]: <> (Code generated by mdatagen. DO NOT EDIT.) -# file +# sample ## Default Metrics diff --git a/cmd/mdatagen/internal/samplereceiver/factory.go b/cmd/mdatagen/internal/samplereceiver/factory.go new file mode 100644 index 00000000000..d23d962ed89 --- /dev/null +++ b/cmd/mdatagen/internal/samplereceiver/factory.go @@ -0,0 +1,43 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package samplereceiver + +import ( + "context" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/consumer" + "go.opentelemetry.io/collector/receiver" + + "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver/internal/metadata" +) + +// NewFactory returns a receiver.Factory for sample receiver. +func NewFactory() receiver.Factory { + return receiver.NewFactory( + metadata.Type, + func() component.Config { return &struct{}{} }, + receiver.WithTraces(createTraces, metadata.TracesStability), + receiver.WithMetrics(createMetrics, metadata.MetricsStability), + receiver.WithLogs(createLogs, metadata.LogsStability)) +} + +func createTraces(context.Context, receiver.CreateSettings, component.Config, consumer.Traces) (receiver.Traces, error) { + return nopInstance, nil +} + +func createMetrics(context.Context, receiver.CreateSettings, component.Config, consumer.Metrics) (receiver.Metrics, error) { + return nopInstance, nil +} + +func createLogs(context.Context, receiver.CreateSettings, component.Config, consumer.Logs) (receiver.Logs, error) { + return nopInstance, nil +} + +var nopInstance = &nopReceiver{} + +type nopReceiver struct { + component.StartFunc + component.ShutdownFunc +} diff --git a/cmd/mdatagen/internal/samplereceiver/generated_component_test.go b/cmd/mdatagen/internal/samplereceiver/generated_component_test.go new file mode 100644 index 00000000000..8eb4377792f --- /dev/null +++ b/cmd/mdatagen/internal/samplereceiver/generated_component_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package samplereceiver + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + name string + createFn func(ctx context.Context, set receiver.CreateSettings, cfg component.Config) (component.Component, error) + }{ + + { + name: "logs", + createFn: func(ctx context.Context, set receiver.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateLogsReceiver(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "metrics", + createFn: func(ctx context.Context, set receiver.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateMetricsReceiver(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "traces", + createFn: func(ctx context.Context, set receiver.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateTracesReceiver(ctx, set, cfg, consumertest.NewNop()) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), receivertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + host := componenttest.NewNopHost() + require.NoError(t, err) + require.NoError(t, firstRcvr.Start(context.Background(), host)) + require.NoError(t, firstRcvr.Shutdown(context.Background())) + secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, secondRcvr.Start(context.Background(), host)) + require.NoError(t, secondRcvr.Shutdown(context.Background())) + }) + } +} diff --git a/cmd/mdatagen/internal/metadata/generated_config.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config.go similarity index 94% rename from cmd/mdatagen/internal/metadata/generated_config.go rename to cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config.go index 92937f48dbf..eb00e302065 100644 --- a/cmd/mdatagen/internal/metadata/generated_config.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config.go @@ -23,7 +23,7 @@ func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { return nil } -// MetricsConfig provides config for file metrics. +// MetricsConfig provides config for sample metrics. type MetricsConfig struct { DefaultMetric MetricConfig `mapstructure:"default.metric"` DefaultMetricToBeRemoved MetricConfig `mapstructure:"default.metric.to_be_removed"` @@ -67,7 +67,7 @@ func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { return nil } -// ResourceAttributesConfig provides config for file resource attributes. +// ResourceAttributesConfig provides config for sample resource attributes. type ResourceAttributesConfig struct { MapResourceAttr ResourceAttributeConfig `mapstructure:"map.resource.attr"` OptionalResourceAttr ResourceAttributeConfig `mapstructure:"optional.resource.attr"` @@ -108,7 +108,7 @@ func DefaultResourceAttributesConfig() ResourceAttributesConfig { } } -// MetricsBuilderConfig is a configuration for file metrics builder. +// MetricsBuilderConfig is a configuration for sample metrics builder. type MetricsBuilderConfig struct { Metrics MetricsConfig `mapstructure:"metrics"` ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` diff --git a/cmd/mdatagen/internal/metadata/generated_config_test.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config_test.go similarity index 100% rename from cmd/mdatagen/internal/metadata/generated_config_test.go rename to cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_config_test.go diff --git a/cmd/mdatagen/internal/metadata/generated_metrics.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go similarity index 99% rename from cmd/mdatagen/internal/metadata/generated_metrics.go rename to cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go index a6d8a7e4169..bf87c2d8854 100644 --- a/cmd/mdatagen/internal/metadata/generated_metrics.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics.go @@ -368,7 +368,7 @@ func (mb *MetricsBuilder) EmitForResource(rmo ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() rm.SetSchemaUrl(conventions.SchemaURL) ils := rm.ScopeMetrics().AppendEmpty() - ils.Scope().SetName("go.opentelemetry.io/collector") + ils.Scope().SetName("go.opentelemetry.io/collector/samplereceiver") ils.Scope().SetVersion(mb.buildInfo.Version) ils.Metrics().EnsureCapacity(mb.metricsCapacity) mb.metricDefaultMetric.emit(ils.Metrics()) diff --git a/cmd/mdatagen/internal/metadata/generated_metrics_test.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics_test.go similarity index 100% rename from cmd/mdatagen/internal/metadata/generated_metrics_test.go rename to cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_metrics_test.go diff --git a/cmd/mdatagen/internal/metadata/generated_resource.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_resource.go similarity index 100% rename from cmd/mdatagen/internal/metadata/generated_resource.go rename to cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_resource.go diff --git a/cmd/mdatagen/internal/metadata/generated_resource_test.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_resource_test.go similarity index 100% rename from cmd/mdatagen/internal/metadata/generated_resource_test.go rename to cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_resource_test.go diff --git a/cmd/mdatagen/internal/metadata/generated_status.go b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_status.go similarity index 85% rename from cmd/mdatagen/internal/metadata/generated_status.go rename to cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_status.go index 7e332e5ba4a..b042c7e2f49 100644 --- a/cmd/mdatagen/internal/metadata/generated_status.go +++ b/cmd/mdatagen/internal/samplereceiver/internal/metadata/generated_status.go @@ -10,13 +10,13 @@ import ( ) var ( - Type = component.MustNewType("file") - scopeName = "go.opentelemetry.io/collector" + Type = component.MustNewType("sample") + scopeName = "go.opentelemetry.io/collector/samplereceiver" ) const ( - TracesStability = component.StabilityLevelBeta LogsStability = component.StabilityLevelDevelopment + TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelStable ) diff --git a/cmd/mdatagen/internal/metadata/testdata/config.yaml b/cmd/mdatagen/internal/samplereceiver/internal/metadata/testdata/config.yaml similarity index 100% rename from cmd/mdatagen/internal/metadata/testdata/config.yaml rename to cmd/mdatagen/internal/samplereceiver/internal/metadata/testdata/config.yaml diff --git a/cmd/mdatagen/metadata-sample.yaml b/cmd/mdatagen/internal/samplereceiver/metadata.yaml similarity index 95% rename from cmd/mdatagen/metadata-sample.yaml rename to cmd/mdatagen/internal/samplereceiver/metadata.yaml index b9a5f8f6c90..8c32d9f382b 100644 --- a/cmd/mdatagen/metadata-sample.yaml +++ b/cmd/mdatagen/internal/samplereceiver/metadata.yaml @@ -1,6 +1,6 @@ -# Sample metric metadata file with all available configurations. +# Sample metadata file with all available configurations for a receiver. -type: file +type: sample sem_conv_version: 1.9.0 @@ -10,7 +10,9 @@ status: development: [logs] beta: [traces] stable: [metrics] - distributions: [contrib] + distributions: [] + codeowners: + active: [dmitryax] warnings: - Any additional information that should be brought to the consumer's attention @@ -134,3 +136,6 @@ metrics: aggregation_temporality: delta warnings: if_enabled: This metric is deprecated and will be removed soon. + +tests: + config: diff --git a/cmd/mdatagen/internal/samplereceiver/metrics_test.go b/cmd/mdatagen/internal/samplereceiver/metrics_test.go new file mode 100644 index 00000000000..f073d9d6ee8 --- /dev/null +++ b/cmd/mdatagen/internal/samplereceiver/metrics_test.go @@ -0,0 +1,21 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package samplereceiver + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/receiver/receivertest" + + "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver/internal/metadata" +) + +// TestGeneratedMetrics verifies that the internal/metadata API is generated correctly. +func TestGeneratedMetrics(t *testing.T) { + mb := metadata.NewMetricsBuilder(metadata.DefaultMetricsBuilderConfig(), receivertest.NewNopCreateSettings()) + m := mb.Emit() + require.Equal(t, 0, m.ResourceMetrics().Len()) +} diff --git a/cmd/mdatagen/lint_test.go b/cmd/mdatagen/lint_test.go index 5c470f302d7..f05d6615ea3 100644 --- a/cmd/mdatagen/lint_test.go +++ b/cmd/mdatagen/lint_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" ) -func Test_formatIdentifier(t *testing.T) { +func TestFormatIdentifier(t *testing.T) { var tests = []struct { input string want string diff --git a/cmd/mdatagen/loader.go b/cmd/mdatagen/loader.go index 8b4b996a5e2..50191b9353c 100644 --- a/cmd/mdatagen/loader.go +++ b/cmd/mdatagen/loader.go @@ -202,6 +202,7 @@ func (a attribute) TestValue() string { type tests struct { Config any `mapstructure:"config"` SkipLifecycle bool `mapstructure:"skip_lifecycle"` + SkipShutdown bool `mapstructure:"skip_shutdown"` ExpectConsumerError bool `mapstructure:"expect_consumer_error"` } @@ -225,7 +226,7 @@ type metadata struct { // ShortFolderName is the shortened folder name of the component, removing class if present ShortFolderName string `mapstructure:"-"` - Tests *tests `mapstructure:"tests"` + Tests tests `mapstructure:"tests"` } func setAttributesFullName(attrs map[attributeName]attribute) { diff --git a/cmd/mdatagen/loader_test.go b/cmd/mdatagen/loader_test.go index aafacc8f252..5562955b99c 100644 --- a/cmd/mdatagen/loader_test.go +++ b/cmd/mdatagen/loader_test.go @@ -8,30 +8,34 @@ import ( "github.com/stretchr/testify/require" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" ) -func Test_loadMetadata(t *testing.T) { +func TestLoadMetadata(t *testing.T) { tests := []struct { name string want metadata wantErr string }{ { - name: "metadata-sample.yaml", + name: "internal/samplereceiver/metadata.yaml", want: metadata{ - Type: "file", + Type: "sample", SemConvVersion: "1.9.0", Status: &Status{ Class: "receiver", - Stability: map[string][]string{ - "development": {"logs"}, - "beta": {"traces"}, - "stable": {"metrics"}, + Stability: map[component.StabilityLevel][]string{ + component.StabilityLevelDevelopment: {"logs"}, + component.StabilityLevelBeta: {"traces"}, + component.StabilityLevelStable: {"metrics"}, }, - Distributions: []string{"contrib"}, - Warnings: []string{"Any additional information that should be brought to the consumer's attention"}, + Distributions: []string{}, + Codeowners: &Codeowners{ + Active: []string{"dmitryax"}, + }, + Warnings: []string{"Any additional information that should be brought to the consumer's attention"}, }, ResourceAttributes: map[attributeName]attribute{ "string.resource.attr": { @@ -214,8 +218,8 @@ func Test_loadMetadata(t *testing.T) { }, }, }, - ScopeName: "go.opentelemetry.io/collector", - ShortFolderName: ".", + ScopeName: "otelcol/samplereceiver", + ShortFolderName: "sample", }, }, { @@ -223,7 +227,7 @@ func Test_loadMetadata(t *testing.T) { want: metadata{ Type: "subcomponent", Parent: "parentComponent", - ScopeName: "go.opentelemetry.io/collector", + ScopeName: "otelcol", ShortFolderName: "testdata", }, }, diff --git a/cmd/mdatagen/main.go b/cmd/mdatagen/main.go index 4d04bd0696f..aae55b79ade 100644 --- a/cmd/mdatagen/main.go +++ b/cmd/mdatagen/main.go @@ -43,6 +43,7 @@ func run(ymlPath string) error { } ymlDir := filepath.Dir(ymlPath) + packageName := filepath.Base(ymlDir) md, err := loadMetadata(ymlPath) if err != nil { @@ -61,6 +62,12 @@ func run(ymlPath string) error { filepath.Join(codeDir, "generated_status.go"), md, "metadata"); err != nil { return err } + if !md.Tests.SkipLifecycle || !md.Tests.SkipShutdown { + if err = generateFile(filepath.Join(tmplDir, "component_test.go.tmpl"), + filepath.Join(ymlDir, "generated_component_test.go"), md, packageName); err != nil { + return err + } + } } if _, err = os.Stat(filepath.Join(ymlDir, "README.md")); err == nil { @@ -73,13 +80,6 @@ func run(ymlPath string) error { } } - if md.Tests != nil { - if err = generateFile(filepath.Join(tmplDir, "component_test.go.tmpl"), - filepath.Join(ymlDir, "generated_component_test.go"), md, md.ShortFolderName+md.Status.Class); err != nil { - return err - } - } - if len(md.Metrics) == 0 && len(md.ResourceAttributes) == 0 { return nil } @@ -164,7 +164,8 @@ func templatize(tmplFile string, md metadata) *template.Template { } return result }, - "casesTitle": cases.Title(language.English).String, + "casesTitle": cases.Title(language.English).String, + "toLowerCase": strings.ToLower, "toCamelCase": func(s string) string { caser := cases.Title(language.English).String parts := strings.Split(s, "_") @@ -193,9 +194,6 @@ func templatize(tmplFile string, md metadata) *template.Template { "isConnector": func() bool { return md.Status.Class == "connector" }, - "skipLifecycle": func() bool { - return md.Tests.SkipLifecycle - }, "supportsLogs": func() bool { for _, signals := range md.Status.Stability { for _, s := range signals { diff --git a/cmd/mdatagen/main_test.go b/cmd/mdatagen/main_test.go index df3387fd167..0d8b3c6c6e0 100644 --- a/cmd/mdatagen/main_test.go +++ b/cmd/mdatagen/main_test.go @@ -12,17 +12,15 @@ import ( "github.com/stretchr/testify/require" - md "go.opentelemetry.io/collector/cmd/mdatagen/internal/metadata" - "go.opentelemetry.io/collector/receiver/receivertest" + "go.opentelemetry.io/collector/component" ) -func Test_runContents(t *testing.T) { +func TestRunContents(t *testing.T) { tests := []struct { yml string wantMetricsGenerated bool wantConfigGenerated bool wantStatusGenerated bool - wantTestsGenerated bool wantErr bool }{ { @@ -44,37 +42,10 @@ func Test_runContents(t *testing.T) { yml: "status_only.yaml", wantStatusGenerated: true, }, - { - yml: "with_tests_receiver.yaml", - wantTestsGenerated: true, - wantStatusGenerated: true, - }, - { - yml: "with_tests_exporter.yaml", - wantTestsGenerated: true, - wantStatusGenerated: true, - }, - { - yml: "with_tests_processor.yaml", - wantTestsGenerated: true, - wantStatusGenerated: true, - }, - { - yml: "with_tests_extension.yaml", - wantTestsGenerated: true, - wantStatusGenerated: true, - }, - { - yml: "with_tests_connector.yaml", - wantTestsGenerated: true, - wantStatusGenerated: true, - }, } for _, tt := range tests { t.Run(tt.yml, func(t *testing.T) { - tmpdir := filepath.Join(t.TempDir(), "shortname") - err := os.MkdirAll(tmpdir, 0750) - require.NoError(t, err) + tmpdir := t.TempDir() ymlContent, err := os.ReadFile(filepath.Join("testdata", tt.yml)) require.NoError(t, err) metadataFile := filepath.Join(tmpdir, "metadata.yaml") @@ -111,29 +82,20 @@ foo if tt.wantStatusGenerated { require.FileExists(t, filepath.Join(tmpdir, "internal/metadata/generated_status.go")) - contents, err := os.ReadFile(filepath.Join(tmpdir, "README.md")) // nolint: gosec + contents, err := os.ReadFile(filepath.Join(tmpdir, "README.md")) require.NoError(t, err) require.NotContains(t, string(contents), "foo") } else { require.NoFileExists(t, filepath.Join(tmpdir, "internal/metadata/generated_status.go")) - contents, err := os.ReadFile(filepath.Join(tmpdir, "README.md")) // nolint: gosec + contents, err := os.ReadFile(filepath.Join(tmpdir, "README.md")) require.NoError(t, err) require.Contains(t, string(contents), "foo") } - - if tt.wantTestsGenerated { - require.FileExists(t, filepath.Join(tmpdir, "generated_component_test.go")) - contents, err := os.ReadFile(filepath.Join(tmpdir, "generated_component_test.go")) // nolint: gosec - require.NoError(t, err) - require.Contains(t, string(contents), "func Test") - } else { - require.NoFileExists(t, filepath.Join(tmpdir, "generated_component_test.go")) - } }) } } -func Test_run(t *testing.T) { +func TestRun(t *testing.T) { type args struct { ymlPath string } @@ -162,14 +124,14 @@ func Test_run(t *testing.T) { } } -func Test_inlineReplace(t *testing.T) { +func TestInlineReplace(t *testing.T) { tests := []struct { name string markdown string outputFile string componentClass string warnings []string - stability map[string][]string + stability map[component.StabilityLevel][]string distros []string codeowners *Codeowners }{ @@ -200,7 +162,7 @@ Some info about a component distros: []string{"contrib"}, }, { - name: "readme with status with codeowners and seeking new", + name: "readme with status with codeowners and emeritus", markdown: `# Some component @@ -208,16 +170,16 @@ Some info about a component Some info about a component `, - outputFile: "readme_with_status_codeowners_and_seeking_new.md", + outputFile: "readme_with_status_codeowners_and_emeritus.md", componentClass: "receiver", distros: []string{"contrib"}, codeowners: &Codeowners{ - Active: []string{"foo"}, - SeekingNew: true, + Active: []string{"foo"}, + Emeritus: []string{"bar"}, }, }, { - name: "readme with status with codeowners and emeritus", + name: "readme with status with codeowners and seeking new", markdown: `# Some component @@ -225,12 +187,12 @@ Some info about a component Some info about a component `, - outputFile: "readme_with_status_codeowners_and_emeritus.md", + outputFile: "readme_with_status_codeowners_and_seeking_new.md", componentClass: "receiver", distros: []string{"contrib"}, codeowners: &Codeowners{ - Active: []string{"foo"}, - Emeritus: []string{"bar"}, + Active: []string{"foo"}, + SeekingNew: true, }, }, { @@ -298,8 +260,11 @@ Some warning there. Some info about a component `, outputFile: "readme_with_multiple_signals.md", - stability: map[string][]string{"beta": {"metrics"}, "alpha": {"logs"}}, - distros: []string{"contrib"}, + stability: map[component.StabilityLevel][]string{ + component.StabilityLevelBeta: {"metrics"}, + component.StabilityLevelAlpha: {"logs"}, + }, + distros: []string{"contrib"}, }, { name: "readme with cmd class", @@ -310,15 +275,18 @@ Some info about a component Some info about a component `, - outputFile: "readme_with_cmd_class.md", - stability: map[string][]string{"beta": {"metrics"}, "alpha": {"logs"}}, + outputFile: "readme_with_cmd_class.md", + stability: map[component.StabilityLevel][]string{ + component.StabilityLevelBeta: {"metrics"}, + component.StabilityLevelAlpha: {"logs"}, + }, componentClass: "cmd", distros: []string{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - stability := map[string][]string{"beta": {"metrics"}} + stability := map[component.StabilityLevel][]string{component.StabilityLevelBeta: {"metrics"}} if len(tt.stability) > 0 { stability = tt.stability } @@ -367,7 +335,9 @@ func TestGenerateStatusMetadata(t *testing.T) { md: metadata{ Type: "foo", Status: &Status{ - Stability: map[string][]string{"beta": {"metrics"}}, + Stability: map[component.StabilityLevel][]string{ + component.StabilityLevelBeta: {"metrics"}, + }, Distributions: []string{"contrib"}, Class: "receiver", }, @@ -405,7 +375,9 @@ func Tracer(settings component.TelemetrySettings) trace.Tracer { md: metadata{ Type: "foo", Status: &Status{ - Stability: map[string][]string{"alpha": {"metrics"}}, + Stability: map[component.StabilityLevel][]string{ + component.StabilityLevelAlpha: {"metrics"}, + }, Distributions: []string{"contrib"}, Class: "receiver", }, @@ -452,10 +424,3 @@ func Tracer(settings component.TelemetrySettings) trace.Tracer { }) } } - -// TestGenerated verifies that the internal/metadata API is generated correctly. -func TestGenerated(t *testing.T) { - mb := md.NewMetricsBuilder(md.DefaultMetricsBuilderConfig(), receivertest.NewNopCreateSettings()) - m := mb.Emit() - require.Equal(t, 0, m.ResourceMetrics().Len()) -} diff --git a/cmd/mdatagen/metadata-schema.yaml b/cmd/mdatagen/metadata-schema.yaml index 879307fdd3d..2a42a7191e8 100644 --- a/cmd/mdatagen/metadata-schema.yaml +++ b/cmd/mdatagen/metadata-schema.yaml @@ -109,5 +109,9 @@ metrics: # Lifecycle tests generated for this component. tests: config: # {} by default, specific testing configuration for lifecycle tests. + # Skip lifecycle tests for this component. Not recommended for components that are not in development. skip_lifecycle: false # false by default + # Skip shutdown tests for this component. Not recommended for components that are not in development. + skip_shutdown: false # false by default + # Whether it's expected that the Consume[Logs|Metrics|Traces] method will return an error with the given configuration. expect_consumer_error: true # false by default diff --git a/cmd/mdatagen/metricdata.go b/cmd/mdatagen/metricdata.go index f4515136aae..5bf77985cc9 100644 --- a/cmd/mdatagen/metricdata.go +++ b/cmd/mdatagen/metricdata.go @@ -125,7 +125,7 @@ func (d *gauge) Unmarshal(parser *confmap.Conf) error { if err := d.MetricValueType.Unmarshal(parser); err != nil { return err } - return parser.Unmarshal(d) + return parser.Unmarshal(d, confmap.WithIgnoreUnused()) } func (d gauge) Type() string { @@ -155,7 +155,7 @@ func (d *sum) Unmarshal(parser *confmap.Conf) error { if err := d.MetricValueType.Unmarshal(parser); err != nil { return err } - return parser.Unmarshal(d) + return parser.Unmarshal(d, confmap.WithIgnoreUnused()) } // TODO: Currently, this func will not be called because of https://github.com/open-telemetry/opentelemetry-collector/issues/6671. Uncomment function and diff --git a/cmd/mdatagen/package_test.go b/cmd/mdatagen/package_test.go new file mode 100644 index 00000000000..5cd502ca564 --- /dev/null +++ b/cmd/mdatagen/package_test.go @@ -0,0 +1,14 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "testing" + + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/cmd/mdatagen/statusdata.go b/cmd/mdatagen/statusdata.go index d65a5c20f58..05ca2b16471 100644 --- a/cmd/mdatagen/statusdata.go +++ b/cmd/mdatagen/statusdata.go @@ -4,7 +4,12 @@ package main import ( + "errors" "sort" + "strings" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/confmap" ) // distros is a collection of distributions that can be referenced in the metadata.yaml files. @@ -32,13 +37,15 @@ type Codeowners struct { SeekingNew bool `mapstructure:"seeking_new"` } +type StabilityMap map[component.StabilityLevel][]string + type Status struct { - Stability map[string][]string `mapstructure:"stability"` - Distributions []string `mapstructure:"distributions"` - Class string `mapstructure:"class"` - Warnings []string `mapstructure:"warnings"` - Codeowners *Codeowners `mapstructure:"codeowners"` - UnsupportedPlatforms []string `mapstructure:"unsupported_platforms"` + Stability StabilityMap `mapstructure:"stability"` + Distributions []string `mapstructure:"distributions"` + Class string `mapstructure:"class"` + Warnings []string `mapstructure:"warnings"` + Codeowners *Codeowners `mapstructure:"codeowners"` + UnsupportedPlatforms []string `mapstructure:"unsupported_platforms"` } func (s *Status) SortedDistributions() []string { @@ -60,3 +67,31 @@ func (s *Status) SortedDistributions() []string { }) return sorted } + +func (ms *StabilityMap) Unmarshal(parser *confmap.Conf) error { + *ms = make(StabilityMap) + raw := make(map[string][]string) + err := parser.Unmarshal(&raw) + if err != nil { + return err + } + for k, v := range raw { + switch strings.ToLower(k) { + case strings.ToLower(component.StabilityLevelUnmaintained.String()): + (*ms)[component.StabilityLevelUnmaintained] = v + case strings.ToLower(component.StabilityLevelDeprecated.String()): + (*ms)[component.StabilityLevelDeprecated] = v + case strings.ToLower(component.StabilityLevelDevelopment.String()): + (*ms)[component.StabilityLevelDevelopment] = v + case strings.ToLower(component.StabilityLevelAlpha.String()): + (*ms)[component.StabilityLevelAlpha] = v + case strings.ToLower(component.StabilityLevelBeta.String()): + (*ms)[component.StabilityLevelBeta] = v + case strings.ToLower(component.StabilityLevelStable.String()): + (*ms)[component.StabilityLevelStable] = v + default: + return errors.New("invalid stability level: " + k) + } + } + return nil +} diff --git a/cmd/mdatagen/templates/component_test.go.tmpl b/cmd/mdatagen/templates/component_test.go.tmpl index 3c82b1ed2d2..3a8fd72dd3c 100644 --- a/cmd/mdatagen/templates/component_test.go.tmpl +++ b/cmd/mdatagen/templates/component_test.go.tmpl @@ -1,6 +1,6 @@ // Code generated by mdatagen. DO NOT EDIT. -{{ if len .Status.UnsupportedPlatforms -}} +{{- if len .Status.UnsupportedPlatforms }} //go:build {{ range $i, $v := .Status.UnsupportedPlatforms }}{{ if $i }} && {{ end }}!{{ . }}{{ end }} {{- end }} @@ -9,43 +9,47 @@ package {{ .Package }} import ( "context" "testing" + {{- if or isExporter isProcessor }} + "time" + {{- end }} "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" + {{- if not .Tests.SkipLifecycle }} "go.opentelemetry.io/collector/component/componenttest" -{{ if isExporter }} + {{- end }} + {{- if isExporter }} "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" -{{ end }} -{{ if isProcessor }} + {{- end }} + {{- if isProcessor }} "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" -{{ end }} -{{ if isReceiver }} + {{- end }} + {{- if isReceiver }} "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" -{{ end }} -{{ if isExtension }} + {{- end }} + {{- if isExtension }} "go.opentelemetry.io/collector/extension/extensiontest" -{{ end }} -{{ if isConnector }} + {{- end }} + {{- if isConnector }} "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" -{{ end }} + {{- end }} "go.opentelemetry.io/collector/confmap/confmaptest" -{{ if or (isExporter) (isProcessor) }} - "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/testdata" -{{ end }} + {{- if or isExporter isProcessor }} + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/ptrace" + {{- end }} ) -func TestCheckConfigStruct(t *testing.T) { - componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig()) -} - -{{ if isExporter }} +{{ if isExporter -}} func TestComponentLifecycle(t *testing.T) { factory := NewFactory() @@ -87,18 +91,17 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, component.UnmarshalConfig(sub, cfg)) for _, test := range tests { + {{- if not .Tests.SkipShutdown }} t.Run(test.name + "-shutdown", func(t *testing.T) { c, err := test.createFn(context.Background(), exportertest.NewNopCreateSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) + {{- end }} + {{- if not .Tests.SkipLifecycle }} t.Run(test.name + "-lifecycle", func(t *testing.T) { - {{ if skipLifecycle }} - // TODO support lifecycle - t.SkipNow() - {{ end }} c, err := test.createFn(context.Background(), exportertest.NewNopCreateSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() @@ -107,19 +110,19 @@ func TestComponentLifecycle(t *testing.T) { require.NotPanics(t, func() { switch e := c.(type) { case exporter.Logs: - logs := testdata.GenerateLogsManyLogRecordsSameResource(2) + logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case exporter.Metrics: - metrics := testdata.GenerateMetricsTwoMetrics() + metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case exporter.Traces: - traces := testdata.GenerateTracesTwoSpansSameResource() + traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } @@ -132,6 +135,7 @@ func TestComponentLifecycle(t *testing.T) { err = c.Shutdown(context.Background()) require.NoError(t, err) }) + {{- end }} } } {{ end }} @@ -178,18 +182,17 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, component.UnmarshalConfig(sub, cfg)) for _, test := range tests { + {{- if not .Tests.SkipShutdown }} t.Run(test.name + "-shutdown", func(t *testing.T) { c, err := test.createFn(context.Background(), processortest.NewNopCreateSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) + {{- end }} + {{- if not .Tests.SkipLifecycle }} t.Run(test.name + "-lifecycle", func(t *testing.T) { - {{ if skipLifecycle }} - // TODO support lifecycle - t.SkipNow() - {{ end }} c, err := test.createFn(context.Background(), processortest.NewNopCreateSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() @@ -198,19 +201,19 @@ func TestComponentLifecycle(t *testing.T) { require.NotPanics(t, func() { switch e := c.(type) { case processor.Logs: - logs := testdata.GenerateLogsManyLogRecordsSameResource(2) + logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case processor.Metrics: - metrics := testdata.GenerateMetricsTwoMetrics() + metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case processor.Traces: - traces := testdata.GenerateTracesTwoSpansSameResource() + traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } @@ -221,6 +224,7 @@ func TestComponentLifecycle(t *testing.T) { err = c.Shutdown(context.Background()) require.NoError(t, err) }) + {{- end }} } } {{ end }} @@ -267,18 +271,17 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, component.UnmarshalConfig(sub, cfg)) for _, test := range tests { + {{- if not .Tests.SkipShutdown }} t.Run(test.name + "-shutdown", func(t *testing.T) { c, err := test.createFn(context.Background(), receivertest.NewNopCreateSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) + {{- end }} + {{- if not .Tests.SkipLifecycle }} t.Run(test.name + "-lifecycle", func(t *testing.T) { - {{ if skipLifecycle }} - // TODO support lifecycle - t.SkipNow() - {{ end }} firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopCreateSettings(), cfg) require.NoError(t, err) host := componenttest.NewNopHost() @@ -290,6 +293,7 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) + {{- end }} } } {{ end }} @@ -305,28 +309,28 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, err) require.NoError(t, component.UnmarshalConfig(sub, cfg)) + {{- if not .Tests.SkipShutdown }} t.Run("shutdown", func(t *testing.T) { e, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) require.NoError(t, err) err = e.Shutdown(context.Background()) require.NoError(t, err) }) + {{- end }} + {{- if not .Tests.SkipLifecycle }} t.Run("lifecycle", func(t *testing.T) { - {{ if skipLifecycle }} - // TODO support lifecycle - t.SkipNow() - {{ end }} firstExt, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) require.NoError(t, err) require.NoError(t, firstExt.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, firstExt.Shutdown(context.Background())) - + secondExt, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) require.NoError(t, err) require.NoError(t, secondExt.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, secondExt.Shutdown(context.Background())) }) + {{- end }} } {{ end }} @@ -420,21 +424,20 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, component.UnmarshalConfig(sub, cfg)) for _, test := range tests { + {{- if not .Tests.SkipShutdown }} t.Run(test.name + "-shutdown", func(t *testing.T) { c, err := test.createFn(context.Background(), connectortest.NewNopCreateSettings(), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) + {{- end }} + {{- if not .Tests.SkipLifecycle }} t.Run(test.name + "-lifecycle", func(t *testing.T) { - {{ if skipLifecycle }} - // TODO support lifecycle - t.SkipNow() - {{ end }} firstConnector, err := test.createFn(context.Background(), connectortest.NewNopCreateSettings(), cfg) require.NoError(t, err) - host := newAssertNoErrorHost(t) + host := componenttest.NewNopHost() require.NoError(t, err) require.NoError(t, firstConnector.Start(context.Background(), host)) require.NoError(t, firstConnector.Shutdown(context.Background())) @@ -443,6 +446,44 @@ func TestComponentLifecycle(t *testing.T) { require.NoError(t, secondConnector.Start(context.Background(), host)) require.NoError(t, secondConnector.Shutdown(context.Background())) }) + {{- end }} } } -{{ end }} \ No newline at end of file +{{ end }} + +{{ if or isExporter isProcessor -}} +func generateLifecycleTestLogs() plog.Logs { + logs := plog.NewLogs() + rl := logs.ResourceLogs().AppendEmpty() + rl.Resource().Attributes().PutStr("resource", "R1") + l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() + l.Body().SetStr("test log message") + l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return logs +} + +func generateLifecycleTestMetrics() pmetric.Metrics { + metrics := pmetric.NewMetrics() + rm := metrics.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resource", "R1") + m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() + m.SetName("test_metric") + dp := m.SetEmptyGauge().DataPoints().AppendEmpty() + dp.Attributes().PutStr("test_attr", "value_1") + dp.SetIntValue(123) + dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return metrics +} + +func generateLifecycleTestTraces() ptrace.Traces { + traces := ptrace.NewTraces() + rs := traces.ResourceSpans().AppendEmpty() + rs.Resource().Attributes().PutStr("resource", "R1") + span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() + span.Attributes().PutStr("test_attr", "value_1") + span.SetName("test_span") + span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) + span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return traces +} +{{- end }} diff --git a/cmd/mdatagen/templates/readme.md.tmpl b/cmd/mdatagen/templates/readme.md.tmpl index ad41f11dd42..268ff5888e5 100644 --- a/cmd/mdatagen/templates/readme.md.tmpl +++ b/cmd/mdatagen/templates/readme.md.tmpl @@ -7,7 +7,7 @@ {{- if ne $class "connector" }} {{- $idx := 0 }} {{- range $stability, $value := .Status.Stability }} -| {{ if not $idx }}Stability{{ else }} {{ end }} | [{{ $stability }}]{{ if ne $class "extension" }}: {{ stringsJoin $value ", " }} {{ end }} | +| {{ if not $idx }}Stability{{ else }} {{ end }} | [{{ toLowerCase $stability.String }}]{{ if ne $class "extension" }}: {{ stringsJoin $value ", " }} {{ end }} | {{- $idx = inc $idx }} {{- end }} {{- end}} @@ -29,7 +29,7 @@ {{- end }} {{- end }} {{range $stability, $val := .Status.Stability}} -[{{ $stability }}]: https://github.com/open-telemetry/opentelemetry-collector#{{ $stability }} +[{{ toLowerCase $stability.String }}]: https://github.com/open-telemetry/opentelemetry-collector#{{ toLowerCase $stability.String }} {{- end }} {{- range .Status.SortedDistributions }} [{{.}}]: {{ distroURL . }} @@ -43,7 +43,7 @@ {{- range $stability, $pipelines := .Status.Stability }} {{- range $pipeline := $pipelines }} {{- $parts := stringsSplit $pipeline "_to_" }} -| {{index $parts 0}} | {{index $parts 1}} | [{{$stability}}] | +| {{index $parts 0}} | {{index $parts 1}} | [{{ toLowerCase $stability.String }}] | {{- end }} {{- end }} diff --git a/cmd/mdatagen/templates/status.go.tmpl b/cmd/mdatagen/templates/status.go.tmpl index d35cf76ff01..27c2d6fa7ed 100644 --- a/cmd/mdatagen/templates/status.go.tmpl +++ b/cmd/mdatagen/templates/status.go.tmpl @@ -3,7 +3,7 @@ package {{ .Package }} import ( - "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" ) @@ -16,7 +16,7 @@ var ( const ( {{- range $stability, $signals := .Status.Stability }} {{- range $signal := $signals }} - {{ toCamelCase $signal }}Stability = component.StabilityLevel{{ casesTitle $stability }} + {{ toCamelCase $signal }}Stability = component.StabilityLevel{{ casesTitle $stability.String }} {{- end }} {{- end }} ) diff --git a/cmd/mdatagen/testdata/metrics_and_type.yaml b/cmd/mdatagen/testdata/metrics_and_type.yaml index 81d66bde9c1..2306a08b35e 100644 --- a/cmd/mdatagen/testdata/metrics_and_type.yaml +++ b/cmd/mdatagen/testdata/metrics_and_type.yaml @@ -17,3 +17,7 @@ metrics: unit: s gauge: value_type: double + +tests: + skip_lifecycle: true + skip_shutdown: true diff --git a/cmd/mdatagen/testdata/resource_attributes_only.yaml b/cmd/mdatagen/testdata/resource_attributes_only.yaml index 05e031bcf45..a6fe611fe86 100644 --- a/cmd/mdatagen/testdata/resource_attributes_only.yaml +++ b/cmd/mdatagen/testdata/resource_attributes_only.yaml @@ -15,3 +15,7 @@ resource_attributes: description: Resource attribute 1. type: string enabled: true + +tests: + skip_lifecycle: true + skip_shutdown: true diff --git a/cmd/mdatagen/testdata/status_only.yaml b/cmd/mdatagen/testdata/status_only.yaml index 2365b43f1d9..d66977249dd 100644 --- a/cmd/mdatagen/testdata/status_only.yaml +++ b/cmd/mdatagen/testdata/status_only.yaml @@ -4,3 +4,7 @@ status: stability: beta: [traces, metrics, logs] distributions: [contrib] + +tests: + skip_lifecycle: true + skip_shutdown: true diff --git a/cmd/mdatagen/validate.go b/cmd/mdatagen/validate.go index bc56375baf9..5871adca83d 100644 --- a/cmd/mdatagen/validate.go +++ b/cmd/mdatagen/validate.go @@ -33,6 +33,7 @@ func (md *metadata) Validate() error { // typeRegexp is used to validate the type of a component. // A type must start with an ASCII alphabetic character and // can only contain ASCII alphanumeric characters and '_'. +// We allow '/' for subcomponents. // This must be kept in sync with the regex in component/config.go. var typeRegexp = regexp.MustCompile(`^[a-zA-Z][0-9a-zA-Z_]*$`) @@ -41,6 +42,11 @@ func (md *metadata) validateType() error { return errors.New("missing type") } + if md.Parent != "" { + // subcomponents are allowed to have a '/' in their type. + return nil + } + if !typeRegexp.MatchString(md.Type) { return fmt.Errorf("invalid character(s) in type %q", md.Type) } @@ -84,10 +90,7 @@ func (s *Status) validateStability() error { return errors.New("missing stability") } for stability, component := range s.Stability { - if stability != "development" && stability != "alpha" && stability != "beta" && stability != "stable" && stability != "deprecated" && stability != "unmaintained" { - errs = multierr.Append(errs, fmt.Errorf("invalid stability: %v", stability)) - } - if component == nil { + if len(component) == 0 { errs = multierr.Append(errs, fmt.Errorf("missing component for stability: %v", stability)) } for _, c := range component { diff --git a/cmd/mdatagen/validate_test.go b/cmd/mdatagen/validate_test.go index 4c2ddea5741..8a4e94f5b37 100644 --- a/cmd/mdatagen/validate_test.go +++ b/cmd/mdatagen/validate_test.go @@ -40,11 +40,11 @@ func TestValidate(t *testing.T) { }, { name: "testdata/invalid_stability.yaml", - wantErr: "invalid stability: incorrectstability", + wantErr: "1 error(s) decoding:\n\n* error decoding 'status.stability': invalid stability level: incorrectstability", }, { name: "testdata/no_stability_component.yaml", - wantErr: "missing component for stability: beta", + wantErr: "missing component for stability: Beta", }, { name: "testdata/invalid_stability_component.yaml", @@ -113,7 +113,7 @@ func TestValidateMetricDuplicates(t *testing.T) { "container.uptime": {"docker_stats", "kubeletstats"}, } allMetrics := map[string][]string{} - err := filepath.Walk("../../receiver", func(path string, info fs.FileInfo, _ error) error { + err := filepath.Walk("../../receiver", func(path string, info fs.FileInfo, err error) error { if info.Name() == "metadata.yaml" { md, err := loadMetadata(path) require.NoError(t, err) diff --git a/connector/forwardconnector/generated_component_test.go b/connector/forwardconnector/generated_component_test.go new file mode 100644 index 00000000000..27af252dad1 --- /dev/null +++ b/connector/forwardconnector/generated_component_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package forwardconnector + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/connector" + "go.opentelemetry.io/collector/connector/connectortest" + "go.opentelemetry.io/collector/consumer/consumertest" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + name string + createFn func(ctx context.Context, set connector.CreateSettings, cfg component.Config) (component.Component, error) + }{ + + { + name: "logs_to_logs", + createFn: func(ctx context.Context, set connector.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateLogsToLogs(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "metrics_to_metrics", + createFn: func(ctx context.Context, set connector.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateMetricsToMetrics(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "traces_to_traces", + createFn: func(ctx context.Context, set connector.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateTracesToTraces(ctx, set, cfg, consumertest.NewNop()) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), connectortest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + firstConnector, err := test.createFn(context.Background(), connectortest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + host := componenttest.NewNopHost() + require.NoError(t, err) + require.NoError(t, firstConnector.Start(context.Background(), host)) + require.NoError(t, firstConnector.Shutdown(context.Background())) + secondConnector, err := test.createFn(context.Background(), connectortest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, secondConnector.Start(context.Background(), host)) + require.NoError(t, secondConnector.Shutdown(context.Background())) + }) + } +} diff --git a/connector/forwardconnector/go.mod b/connector/forwardconnector/go.mod index 656652fbfe1..b96e48c4e9a 100644 --- a/connector/forwardconnector/go.mod +++ b/connector/forwardconnector/go.mod @@ -5,6 +5,7 @@ go 1.21 require ( github.com/stretchr/testify v1.8.4 go.opentelemetry.io/collector/component v0.96.0 + go.opentelemetry.io/collector/confmap v0.96.0 go.opentelemetry.io/collector/connector v0.96.0 go.opentelemetry.io/collector/consumer v0.96.0 go.opentelemetry.io/collector/pdata v1.3.0 @@ -37,7 +38,6 @@ require ( github.com/prometheus/procfs v0.12.0 // indirect go.opentelemetry.io/collector v0.96.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.96.0 // indirect - go.opentelemetry.io/collector/confmap v0.96.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.46.0 // indirect go.opentelemetry.io/otel/sdk v1.24.0 // indirect diff --git a/exporter/debugexporter/generated_component_test.go b/exporter/debugexporter/generated_component_test.go new file mode 100644 index 00000000000..7efad327751 --- /dev/null +++ b/exporter/debugexporter/generated_component_test.go @@ -0,0 +1,137 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package debugexporter + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/exporter/exportertest" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/ptrace" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + name string + createFn func(ctx context.Context, set exporter.CreateSettings, cfg component.Config) (component.Component, error) + }{ + + { + name: "logs", + createFn: func(ctx context.Context, set exporter.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateLogsExporter(ctx, set, cfg) + }, + }, + + { + name: "metrics", + createFn: func(ctx context.Context, set exporter.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateMetricsExporter(ctx, set, cfg) + }, + }, + + { + name: "traces", + createFn: func(ctx context.Context, set exporter.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateTracesExporter(ctx, set, cfg) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), exportertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + c, err := test.createFn(context.Background(), exportertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + host := componenttest.NewNopHost() + err = c.Start(context.Background(), host) + require.NoError(t, err) + require.NotPanics(t, func() { + switch e := c.(type) { + case exporter.Logs: + logs := generateLifecycleTestLogs() + if !e.Capabilities().MutatesData { + logs.MarkReadOnly() + } + err = e.ConsumeLogs(context.Background(), logs) + case exporter.Metrics: + metrics := generateLifecycleTestMetrics() + if !e.Capabilities().MutatesData { + metrics.MarkReadOnly() + } + err = e.ConsumeMetrics(context.Background(), metrics) + case exporter.Traces: + traces := generateLifecycleTestTraces() + if !e.Capabilities().MutatesData { + traces.MarkReadOnly() + } + err = e.ConsumeTraces(context.Background(), traces) + } + }) + + require.NoError(t, err) + + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + } +} + +func generateLifecycleTestLogs() plog.Logs { + logs := plog.NewLogs() + rl := logs.ResourceLogs().AppendEmpty() + rl.Resource().Attributes().PutStr("resource", "R1") + l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() + l.Body().SetStr("test log message") + l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return logs +} + +func generateLifecycleTestMetrics() pmetric.Metrics { + metrics := pmetric.NewMetrics() + rm := metrics.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resource", "R1") + m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() + m.SetName("test_metric") + dp := m.SetEmptyGauge().DataPoints().AppendEmpty() + dp.Attributes().PutStr("test_attr", "value_1") + dp.SetIntValue(123) + dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return metrics +} + +func generateLifecycleTestTraces() ptrace.Traces { + traces := ptrace.NewTraces() + rs := traces.ResourceSpans().AppendEmpty() + rs.Resource().Attributes().PutStr("resource", "R1") + span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() + span.Attributes().PutStr("test_attr", "value_1") + span.SetName("test_span") + span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) + span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return traces +} diff --git a/exporter/debugexporter/go.mod b/exporter/debugexporter/go.mod index 6f838aa9ba2..4f237eca819 100644 --- a/exporter/debugexporter/go.mod +++ b/exporter/debugexporter/go.mod @@ -8,6 +8,7 @@ require ( go.opentelemetry.io/collector/config/configtelemetry v0.96.0 go.opentelemetry.io/collector/confmap v0.96.0 go.opentelemetry.io/collector/exporter v0.96.0 + go.opentelemetry.io/collector/pdata v1.3.0 go.opentelemetry.io/otel/metric v1.24.0 go.opentelemetry.io/otel/trace v1.24.0 go.uber.org/goleak v1.3.0 @@ -40,7 +41,6 @@ require ( go.opentelemetry.io/collector/config/configretry v0.96.0 // indirect go.opentelemetry.io/collector/consumer v0.96.0 // indirect go.opentelemetry.io/collector/extension v0.96.0 // indirect - go.opentelemetry.io/collector/pdata v1.3.0 // indirect go.opentelemetry.io/collector/receiver v0.96.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.46.0 // indirect diff --git a/exporter/loggingexporter/generated_component_test.go b/exporter/loggingexporter/generated_component_test.go new file mode 100644 index 00000000000..9f8771a9da0 --- /dev/null +++ b/exporter/loggingexporter/generated_component_test.go @@ -0,0 +1,137 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package loggingexporter + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/exporter" + "go.opentelemetry.io/collector/exporter/exportertest" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/ptrace" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + name string + createFn func(ctx context.Context, set exporter.CreateSettings, cfg component.Config) (component.Component, error) + }{ + + { + name: "logs", + createFn: func(ctx context.Context, set exporter.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateLogsExporter(ctx, set, cfg) + }, + }, + + { + name: "metrics", + createFn: func(ctx context.Context, set exporter.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateMetricsExporter(ctx, set, cfg) + }, + }, + + { + name: "traces", + createFn: func(ctx context.Context, set exporter.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateTracesExporter(ctx, set, cfg) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), exportertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + c, err := test.createFn(context.Background(), exportertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + host := componenttest.NewNopHost() + err = c.Start(context.Background(), host) + require.NoError(t, err) + require.NotPanics(t, func() { + switch e := c.(type) { + case exporter.Logs: + logs := generateLifecycleTestLogs() + if !e.Capabilities().MutatesData { + logs.MarkReadOnly() + } + err = e.ConsumeLogs(context.Background(), logs) + case exporter.Metrics: + metrics := generateLifecycleTestMetrics() + if !e.Capabilities().MutatesData { + metrics.MarkReadOnly() + } + err = e.ConsumeMetrics(context.Background(), metrics) + case exporter.Traces: + traces := generateLifecycleTestTraces() + if !e.Capabilities().MutatesData { + traces.MarkReadOnly() + } + err = e.ConsumeTraces(context.Background(), traces) + } + }) + + require.NoError(t, err) + + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + } +} + +func generateLifecycleTestLogs() plog.Logs { + logs := plog.NewLogs() + rl := logs.ResourceLogs().AppendEmpty() + rl.Resource().Attributes().PutStr("resource", "R1") + l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() + l.Body().SetStr("test log message") + l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return logs +} + +func generateLifecycleTestMetrics() pmetric.Metrics { + metrics := pmetric.NewMetrics() + rm := metrics.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resource", "R1") + m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() + m.SetName("test_metric") + dp := m.SetEmptyGauge().DataPoints().AppendEmpty() + dp.Attributes().PutStr("test_attr", "value_1") + dp.SetIntValue(123) + dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return metrics +} + +func generateLifecycleTestTraces() ptrace.Traces { + traces := ptrace.NewTraces() + rs := traces.ResourceSpans().AppendEmpty() + rs.Resource().Attributes().PutStr("resource", "R1") + span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() + span.Attributes().PutStr("test_attr", "value_1") + span.SetName("test_span") + span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) + span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return traces +} diff --git a/exporter/loggingexporter/go.mod b/exporter/loggingexporter/go.mod index 97dac63f6aa..3302cf364ec 100644 --- a/exporter/loggingexporter/go.mod +++ b/exporter/loggingexporter/go.mod @@ -9,6 +9,7 @@ require ( go.opentelemetry.io/collector/config/configtelemetry v0.96.0 go.opentelemetry.io/collector/confmap v0.96.0 go.opentelemetry.io/collector/exporter v0.96.0 + go.opentelemetry.io/collector/pdata v1.3.0 go.opentelemetry.io/otel/metric v1.24.0 go.opentelemetry.io/otel/trace v1.24.0 go.uber.org/goleak v1.3.0 @@ -42,7 +43,6 @@ require ( go.opentelemetry.io/collector/config/configretry v0.96.0 // indirect go.opentelemetry.io/collector/consumer v0.96.0 // indirect go.opentelemetry.io/collector/extension v0.96.0 // indirect - go.opentelemetry.io/collector/pdata v1.3.0 // indirect go.opentelemetry.io/collector/receiver v0.96.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.46.0 // indirect diff --git a/exporter/otlpexporter/metadata.yaml b/exporter/otlpexporter/metadata.yaml index 820930b1dc5..86ba7ca8a41 100644 --- a/exporter/otlpexporter/metadata.yaml +++ b/exporter/otlpexporter/metadata.yaml @@ -6,3 +6,8 @@ status: stable: [traces, metrics] beta: [logs] distributions: [core, contrib] + +# TODO: The tests take a long time to run for this exporter, see if it needs to be fixed. +tests: + skip_lifecycle: true + skip_shutdown: true diff --git a/exporter/otlphttpexporter/metadata.yaml b/exporter/otlphttpexporter/metadata.yaml index 14cae78d175..a0ae32d48ab 100644 --- a/exporter/otlphttpexporter/metadata.yaml +++ b/exporter/otlphttpexporter/metadata.yaml @@ -6,3 +6,8 @@ status: stable: [traces, metrics] beta: [logs] distributions: [core, contrib] + +# TODO: The tests take a long time to run for this exporter, see if it needs to be fixed. +tests: + skip_lifecycle: true + skip_shutdown: true diff --git a/extension/ballastextension/generated_component_test.go b/extension/ballastextension/generated_component_test.go new file mode 100644 index 00000000000..f43cef29af4 --- /dev/null +++ b/extension/ballastextension/generated_component_test.go @@ -0,0 +1,43 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package ballastextension + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/extension/extensiontest" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + t.Run("shutdown", func(t *testing.T) { + e, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + err = e.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run("lifecycle", func(t *testing.T) { + firstExt, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, firstExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, firstExt.Shutdown(context.Background())) + + secondExt, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, secondExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, secondExt.Shutdown(context.Background())) + }) +} diff --git a/extension/memorylimiterextension/generated_component_test.go b/extension/memorylimiterextension/generated_component_test.go new file mode 100644 index 00000000000..ef808e120ac --- /dev/null +++ b/extension/memorylimiterextension/generated_component_test.go @@ -0,0 +1,37 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package memorylimiterextension + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/extension/extensiontest" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + t.Run("lifecycle", func(t *testing.T) { + firstExt, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, firstExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, firstExt.Shutdown(context.Background())) + + secondExt, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, secondExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, secondExt.Shutdown(context.Background())) + }) +} diff --git a/extension/memorylimiterextension/go.mod b/extension/memorylimiterextension/go.mod index b44b779bdc9..0d0b93813eb 100644 --- a/extension/memorylimiterextension/go.mod +++ b/extension/memorylimiterextension/go.mod @@ -6,6 +6,7 @@ require ( github.com/stretchr/testify v1.8.4 go.opentelemetry.io/collector v0.96.0 go.opentelemetry.io/collector/component v0.96.0 + go.opentelemetry.io/collector/confmap v0.96.0 go.opentelemetry.io/collector/extension v0.96.0 go.opentelemetry.io/otel/metric v1.24.0 go.opentelemetry.io/otel/trace v1.24.0 @@ -39,7 +40,6 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.96.0 // indirect - go.opentelemetry.io/collector/confmap v0.96.0 // indirect go.opentelemetry.io/collector/pdata v1.3.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.46.0 // indirect diff --git a/extension/memorylimiterextension/metadata.yaml b/extension/memorylimiterextension/metadata.yaml index 75f16b8f750..ab4436bec86 100644 --- a/extension/memorylimiterextension/metadata.yaml +++ b/extension/memorylimiterextension/metadata.yaml @@ -5,3 +5,11 @@ status: stability: development: [extension] distributions: [] + +tests: + config: + check_interval: 5s + limit_mib: 400 + spike_limit_mib: 50 + # TODO: Fix the Shutdown func: no existing monitoring routine is running + skip_shutdown: true diff --git a/extension/zpagesextension/generated_component_test.go b/extension/zpagesextension/generated_component_test.go new file mode 100644 index 00000000000..f8c9f634b3c --- /dev/null +++ b/extension/zpagesextension/generated_component_test.go @@ -0,0 +1,43 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package zpagesextension + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/extension/extensiontest" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + t.Run("shutdown", func(t *testing.T) { + e, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + err = e.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run("lifecycle", func(t *testing.T) { + firstExt, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, firstExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, firstExt.Shutdown(context.Background())) + + secondExt, err := factory.CreateExtension(context.Background(), extensiontest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, secondExt.Start(context.Background(), componenttest.NewNopHost())) + require.NoError(t, secondExt.Shutdown(context.Background())) + }) +} diff --git a/processor/batchprocessor/generated_component_test.go b/processor/batchprocessor/generated_component_test.go new file mode 100644 index 00000000000..3c2313b4115 --- /dev/null +++ b/processor/batchprocessor/generated_component_test.go @@ -0,0 +1,103 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package batchprocessor + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/collector/processor" + "go.opentelemetry.io/collector/processor/processortest" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + name string + createFn func(ctx context.Context, set processor.CreateSettings, cfg component.Config) (component.Component, error) + }{ + + { + name: "logs", + createFn: func(ctx context.Context, set processor.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateLogsProcessor(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "metrics", + createFn: func(ctx context.Context, set processor.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateMetricsProcessor(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "traces", + createFn: func(ctx context.Context, set processor.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateTracesProcessor(ctx, set, cfg, consumertest.NewNop()) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), processortest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + } +} + +func generateLifecycleTestLogs() plog.Logs { + logs := plog.NewLogs() + rl := logs.ResourceLogs().AppendEmpty() + rl.Resource().Attributes().PutStr("resource", "R1") + l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() + l.Body().SetStr("test log message") + l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return logs +} + +func generateLifecycleTestMetrics() pmetric.Metrics { + metrics := pmetric.NewMetrics() + rm := metrics.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resource", "R1") + m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() + m.SetName("test_metric") + dp := m.SetEmptyGauge().DataPoints().AppendEmpty() + dp.Attributes().PutStr("test_attr", "value_1") + dp.SetIntValue(123) + dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return metrics +} + +func generateLifecycleTestTraces() ptrace.Traces { + traces := ptrace.NewTraces() + rs := traces.ResourceSpans().AppendEmpty() + rs.Resource().Attributes().PutStr("resource", "R1") + span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() + span.Attributes().PutStr("test_attr", "value_1") + span.SetName("test_span") + span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) + span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return traces +} diff --git a/processor/batchprocessor/metadata.yaml b/processor/batchprocessor/metadata.yaml index f535dc6c6c7..257fda56563 100644 --- a/processor/batchprocessor/metadata.yaml +++ b/processor/batchprocessor/metadata.yaml @@ -5,3 +5,7 @@ status: stability: beta: [traces, metrics, logs] distributions: [core, contrib] + +tests: + # TODO: Fix the failing test + skip_lifecycle: true \ No newline at end of file diff --git a/processor/memorylimiterprocessor/generated_component_test.go b/processor/memorylimiterprocessor/generated_component_test.go new file mode 100644 index 00000000000..5c13dde733c --- /dev/null +++ b/processor/memorylimiterprocessor/generated_component_test.go @@ -0,0 +1,130 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package memorylimiterprocessor + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/pdata/pcommon" + "go.opentelemetry.io/collector/pdata/plog" + "go.opentelemetry.io/collector/pdata/pmetric" + "go.opentelemetry.io/collector/pdata/ptrace" + "go.opentelemetry.io/collector/processor" + "go.opentelemetry.io/collector/processor/processortest" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + name string + createFn func(ctx context.Context, set processor.CreateSettings, cfg component.Config) (component.Component, error) + }{ + + { + name: "logs", + createFn: func(ctx context.Context, set processor.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateLogsProcessor(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "metrics", + createFn: func(ctx context.Context, set processor.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateMetricsProcessor(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "traces", + createFn: func(ctx context.Context, set processor.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateTracesProcessor(ctx, set, cfg, consumertest.NewNop()) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + for _, test := range tests { + t.Run(test.name+"-lifecycle", func(t *testing.T) { + c, err := test.createFn(context.Background(), processortest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + host := componenttest.NewNopHost() + err = c.Start(context.Background(), host) + require.NoError(t, err) + require.NotPanics(t, func() { + switch e := c.(type) { + case processor.Logs: + logs := generateLifecycleTestLogs() + if !e.Capabilities().MutatesData { + logs.MarkReadOnly() + } + err = e.ConsumeLogs(context.Background(), logs) + case processor.Metrics: + metrics := generateLifecycleTestMetrics() + if !e.Capabilities().MutatesData { + metrics.MarkReadOnly() + } + err = e.ConsumeMetrics(context.Background(), metrics) + case processor.Traces: + traces := generateLifecycleTestTraces() + if !e.Capabilities().MutatesData { + traces.MarkReadOnly() + } + err = e.ConsumeTraces(context.Background(), traces) + } + }) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + } +} + +func generateLifecycleTestLogs() plog.Logs { + logs := plog.NewLogs() + rl := logs.ResourceLogs().AppendEmpty() + rl.Resource().Attributes().PutStr("resource", "R1") + l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() + l.Body().SetStr("test log message") + l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return logs +} + +func generateLifecycleTestMetrics() pmetric.Metrics { + metrics := pmetric.NewMetrics() + rm := metrics.ResourceMetrics().AppendEmpty() + rm.Resource().Attributes().PutStr("resource", "R1") + m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() + m.SetName("test_metric") + dp := m.SetEmptyGauge().DataPoints().AppendEmpty() + dp.Attributes().PutStr("test_attr", "value_1") + dp.SetIntValue(123) + dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return metrics +} + +func generateLifecycleTestTraces() ptrace.Traces { + traces := ptrace.NewTraces() + rs := traces.ResourceSpans().AppendEmpty() + rs.Resource().Attributes().PutStr("resource", "R1") + span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() + span.Attributes().PutStr("test_attr", "value_1") + span.SetName("test_span") + span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) + span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) + return traces +} diff --git a/processor/memorylimiterprocessor/go.mod b/processor/memorylimiterprocessor/go.mod index a82f08150c3..bb00e9ae581 100644 --- a/processor/memorylimiterprocessor/go.mod +++ b/processor/memorylimiterprocessor/go.mod @@ -6,6 +6,7 @@ require ( github.com/stretchr/testify v1.8.4 go.opentelemetry.io/collector v0.96.0 go.opentelemetry.io/collector/component v0.96.0 + go.opentelemetry.io/collector/confmap v0.96.0 go.opentelemetry.io/collector/consumer v0.96.0 go.opentelemetry.io/collector/pdata v1.3.0 go.opentelemetry.io/collector/processor v0.96.0 @@ -44,7 +45,6 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.96.0 // indirect - go.opentelemetry.io/collector/confmap v0.96.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.46.0 // indirect go.opentelemetry.io/otel/sdk v1.24.0 // indirect diff --git a/processor/memorylimiterprocessor/metadata.yaml b/processor/memorylimiterprocessor/metadata.yaml index bc9e1829149..1734632e84a 100644 --- a/processor/memorylimiterprocessor/metadata.yaml +++ b/processor/memorylimiterprocessor/metadata.yaml @@ -5,3 +5,11 @@ status: stability: beta: [traces, metrics, logs] distributions: [core, contrib] + +tests: + config: + check_interval: 5s + limit_mib: 400 + spike_limit_mib: 50 + # TODO: Fix the Shutdown func: no existing monitoring routine is running + skip_shutdown: true diff --git a/receiver/otlpreceiver/generated_component_test.go b/receiver/otlpreceiver/generated_component_test.go new file mode 100644 index 00000000000..310eaa3d6b0 --- /dev/null +++ b/receiver/otlpreceiver/generated_component_test.go @@ -0,0 +1,76 @@ +// Code generated by mdatagen. DO NOT EDIT. + +package otlpreceiver + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + + "go.opentelemetry.io/collector/component" + "go.opentelemetry.io/collector/component/componenttest" + "go.opentelemetry.io/collector/confmap/confmaptest" + "go.opentelemetry.io/collector/consumer/consumertest" + "go.opentelemetry.io/collector/receiver" + "go.opentelemetry.io/collector/receiver/receivertest" +) + +func TestComponentLifecycle(t *testing.T) { + factory := NewFactory() + + tests := []struct { + name string + createFn func(ctx context.Context, set receiver.CreateSettings, cfg component.Config) (component.Component, error) + }{ + + { + name: "logs", + createFn: func(ctx context.Context, set receiver.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateLogsReceiver(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "metrics", + createFn: func(ctx context.Context, set receiver.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateMetricsReceiver(ctx, set, cfg, consumertest.NewNop()) + }, + }, + + { + name: "traces", + createFn: func(ctx context.Context, set receiver.CreateSettings, cfg component.Config) (component.Component, error) { + return factory.CreateTracesReceiver(ctx, set, cfg, consumertest.NewNop()) + }, + }, + } + + cm, err := confmaptest.LoadConf("metadata.yaml") + require.NoError(t, err) + cfg := factory.CreateDefaultConfig() + sub, err := cm.Sub("tests::config") + require.NoError(t, err) + require.NoError(t, component.UnmarshalConfig(sub, cfg)) + + for _, test := range tests { + t.Run(test.name+"-shutdown", func(t *testing.T) { + c, err := test.createFn(context.Background(), receivertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + err = c.Shutdown(context.Background()) + require.NoError(t, err) + }) + t.Run(test.name+"-lifecycle", func(t *testing.T) { + firstRcvr, err := test.createFn(context.Background(), receivertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + host := componenttest.NewNopHost() + require.NoError(t, err) + require.NoError(t, firstRcvr.Start(context.Background(), host)) + require.NoError(t, firstRcvr.Shutdown(context.Background())) + secondRcvr, err := test.createFn(context.Background(), receivertest.NewNopCreateSettings(), cfg) + require.NoError(t, err) + require.NoError(t, secondRcvr.Start(context.Background(), host)) + require.NoError(t, secondRcvr.Shutdown(context.Background())) + }) + } +}