Skip to content

Commit

Permalink
Add a smoke test that configures all components (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
evan-bradley authored Feb 12, 2024
1 parent ba5190d commit cc1003e
Show file tree
Hide file tree
Showing 3 changed files with 273 additions and 35 deletions.
5 changes: 4 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ The following commands delete generated files and compiled binaries:
- `make clean-tools` removes all build tools
- `make clean-all` removes all generated files and build tools

### Updating collector components
### Updating Collector components

The file [`manifest.yaml`](./manifest.yaml) describes all components in the collector distribution.
See https://github.com/open-telemetry/opentelemetry-collector/tree/main/cmd/builder#configuration for details on the format of this file.

When adding a component, an example configuration for the component must be added to `testbed/testdata/config-allcomponents.yaml`
to test that it works with a basic configuration.
138 changes: 104 additions & 34 deletions testbed/smoke/smoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,104 @@ import (
var execPath = "../../bin/dynatrace-otel-collector"

func TestCollectorStarts(t *testing.T) {
col := testbed.NewChildProcessCollector(testbed.WithAgentExePath(execPath))

cfg, err := os.ReadFile("../testdata/config-smoke.yaml")
require.NoError(t, err)

col.PrepareConfig(string(cfg))
tests := []struct {
name string
configFile string
preCheck func(t *testing.T)
}{
{
name: "Basic test",
configFile: "config-smoke.yaml",
},
{
name: "All components",
configFile: "config-allcomponents.yaml",
preCheck: func(t *testing.T) {
components := getComponents(t)

b, err := os.ReadFile("../testdata/config-allcomponents.yaml")
require.NoError(t, err)
testdataComponents := collectorConf{}
err = yaml.Unmarshal(b, &testdataComponents)
require.NoError(t, err)

for _, c := range components.Receivers {
_, ok := testdataComponents.Receivers[string(c.Name)]
require.True(t, ok, "config-allcomponents.yaml is missing receiver "+c.Name)
}

for _, c := range components.Processors {
_, ok := testdataComponents.Processors[string(c.Name)]
require.True(t, ok, "config-allcomponents.yaml is missing processor "+c.Name)
}

for _, c := range components.Exporters {
_, ok := testdataComponents.Exporters[string(c.Name)]
require.True(t, ok, "config-allcomponents.yaml is missing exporter "+c.Name)
}

for _, c := range components.Connectors {
_, ok := testdataComponents.Connectors[string(c.Name)]
require.True(t, ok, "config-allcomponents.yaml is missing connector "+c.Name)
}

for _, c := range components.Extensions {
_, ok := testdataComponents.Extensions[string(c.Name)]
require.True(t, ok, "config-allcomponents.yaml is missing extension "+c.Name)
}
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.preCheck != nil {
tt.preCheck(t)
}

col := testbed.NewChildProcessCollector(testbed.WithAgentExePath(execPath))

cfg, err := os.ReadFile("../testdata/" + tt.configFile)
require.NoError(t, err)

col.PrepareConfig(string(cfg))

err = col.Start(testbed.StartParams{
Name: "dynatrace-otel-collector",
LogFilePath: "col.log",
})
require.NoError(t, err)

var resp *http.Response
require.Eventually(t, func() bool {
resp, err = http.Get("http://localhost:9090/metrics")

return err == nil
}, 3*time.Second, 1*time.Second)

body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Contains(t, string(body), "otelcol_process_uptime")

stopped, _ := col.Stop()
require.True(t, stopped)
})
}
}

err = col.Start(testbed.StartParams{
Name: "dynatrace-otel-collector",
LogFilePath: "col.log",
})
func TestCollectorIsBuiltFromManifest(t *testing.T) {
components := getComponents(t)
b, err := os.ReadFile("../../manifest.yaml")
require.NoError(t, err)

var resp *http.Response
require.Eventually(t, func() bool {
resp, err = http.Get("http://localhost:9090/metrics")

return err == nil
}, 3*time.Second, 1*time.Second)

body, err := io.ReadAll(resp.Body)
manifestComponents := manifest{}
err = yaml.Unmarshal(b, &manifestComponents)
require.NoError(t, err)
require.Contains(t, string(body), "otelcol_process_uptime")

stopped, _ := col.Stop()
require.True(t, stopped)
assert.Equal(t, len(components.Connectors), len(manifestComponents.Connectors))
assert.Equal(t, len(components.Exporters), len(manifestComponents.Exporters))
assert.Equal(t, len(components.Extensions), len(manifestComponents.Extensions))
assert.Equal(t, len(components.Processors), len(manifestComponents.Processors))
assert.Equal(t, len(components.Receivers), len(manifestComponents.Receivers))
}

type componentMetadata struct {
Expand Down Expand Up @@ -73,7 +145,15 @@ type manifest struct {
Extensions []gomod
}

func TestCollectorIsBuiltFromManifest(t *testing.T) {
type collectorConf struct {
Receivers map[string]any
Processors map[string]any
Exporters map[string]any
Connectors map[string]any
Extensions map[string]any
}

func getComponents(t *testing.T) componentsOutput {
cmd := exec.Command(execPath, "components")
var stdout bytes.Buffer

Expand All @@ -87,15 +167,5 @@ func TestCollectorIsBuiltFromManifest(t *testing.T) {
err = yaml.Unmarshal(output, &components)
require.NoError(t, err)

b, err := os.ReadFile("../../manifest.yaml")
require.NoError(t, err)
manifestComponents := manifest{}
err = yaml.Unmarshal(b, &manifestComponents)
require.NoError(t, err)

assert.Equal(t, len(components.Connectors), len(manifestComponents.Connectors))
assert.Equal(t, len(components.Exporters), len(manifestComponents.Exporters))
assert.Equal(t, len(components.Extensions), len(manifestComponents.Extensions))
assert.Equal(t, len(components.Processors), len(manifestComponents.Processors))
assert.Equal(t, len(components.Receivers), len(manifestComponents.Receivers))
return components
}
165 changes: 165 additions & 0 deletions testbed/testdata/config-allcomponents.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
receivers:
filelog:
include: [/dev/null]
fluentforward:
endpoint: 0.0.0.0:8006
hostmetrics:
scrapers:
cpu:
jaeger:
protocols:
grpc:
prometheus:
config:
scrape_configs:
- job_name: 'otel-collector'
scrape_interval: 5s
static_configs:
- targets: ['0.0.0.0:8888']
- job_name: k8s
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
regex: "true"
action: keep
metric_relabel_configs:
- source_labels: [__name__]
regex: "(request_duration_seconds.*|response_duration_seconds.*)"
action: keep
syslog:
tcp:
listen_address: "0.0.0.0:54526"
protocol: rfc5424
httpcheck:
targets:
- endpoint: http://endpoint:80
method: GET
- endpoint: http://localhost:8080/health
method: GET
- endpoint: http://localhost:8081/health
method: POST
headers:
test-header: "test-value"
collection_interval: 10s
otlp:
protocols:
grpc:
endpoint: localhost:4317
http:
endpoint: localhost:4318

processors:
attributes:
actions:
- key: db.table
action: delete
- key: redacted_span
value: true
action: upsert
- key: copy_key
from_attribute: key_original
action: update
- key: account_id
value: 2245
action: insert
- key: account_password
action: delete
- key: account_email
action: hash
- key: http.status_code
action: convert
converted_type: int
batch:
cumulativetodelta:
filter:
error_mode: ignore
traces:
span:
- 'attributes["container.name"] == "app_container_1"'
- 'resource.attributes["host.name"] == "localhost"'
- 'name == "app_3"'
spanevent:
- 'attributes["grpc"] == true'
- 'IsMatch(name, ".*grpc.*")'
metrics:
metric:
- 'name == "my.metric" and resource.attributes["my_label"] == "abc123"'
- 'type == METRIC_DATA_TYPE_HISTOGRAM'
datapoint:
- 'metric.type == METRIC_DATA_TYPE_SUMMARY'
- 'resource.attributes["service.name"] == "my_service_name"'
logs:
log_record:
- 'IsMatch(body, ".*password.*")'
- 'severity_number < SEVERITY_NUMBER_WARN'
k8sattributes:
memory_limiter:
check_interval: 1s
limit_mib: 4000
spike_limit_mib: 800
probabilistic_sampler:
resourcedetection:
detectors: [env]
timeout: 2s
override: false
resource:
attributes:
- key: cloud.availability_zone
value: "zone-1"
action: upsert
- key: k8s.cluster.name
from_attribute: k8s-cluster
action: insert
- key: redundant-attribute
action: delete
tail_sampling:
policies:
- name: keep-errors
type: status_code
status_code: {status_codes: [ERROR, UNSET]}
- name: keep-slow-traces
type: latency
latency: {threshold_ms: 500}
transform:
error_mode: ignore
trace_statements:
- context: span
statements:
- set(attributes["dt.test"], "otel-collector")

exporters:
debug:
verbosity: detailed
otlp:
endpoint: https://localhost:4312
otlphttp:
endpoint: https://localhost:7821

connectors:
forward:
spanmetrics:

extensions:
zpages:
health_check:
endpoint: "localhost:13000"
tls:
ca_file: "/path/to/ca.crt"
cert_file: "/path/to/cert.crt"
key_file: "/path/to/key.key"
path: "/health/status"
check_collector_pipeline:
enabled: true
interval: "5m"
exporter_failure_threshold: 5

service:
pipelines:
logs:
receivers: [filelog]
exporters: [debug]
telemetry:
metrics:
level: normal
address: localhost:9090

0 comments on commit cc1003e

Please sign in to comment.