diff --git a/generator/test_case_generator.go b/generator/test_case_generator.go index a0021e438..925878746 100644 --- a/generator/test_case_generator.go +++ b/generator/test_case_generator.go @@ -114,6 +114,10 @@ var testTypeToTestConfig = map[string][]testConfig{ testDir: "./test/amp", targets: map[string]map[string]struct{}{"os": {"al2": {}}, "arc": {"amd64": {}}}, }, + { + testDir: "./test/agent_otel_merging", + targets: map[string]map[string]struct{}{"os": {"al2": {}}, "arc": {"amd64": {}}}, + }, }, /* You can only place 1 mac instance on a dedicate host a single time. diff --git a/test/agent_otel_merging/agent_configs/config.json b/test/agent_otel_merging/agent_configs/config.json new file mode 100644 index 000000000..f5e4dcadf --- /dev/null +++ b/test/agent_otel_merging/agent_configs/config.json @@ -0,0 +1,11 @@ +{ + "metrics": { + "metrics_collected": { + "cpu": { + "measurement": [ + "cpu_usage_idle" + ] + } + } + } +} \ No newline at end of file diff --git a/test/agent_otel_merging/agent_otel_merging_test.go b/test/agent_otel_merging/agent_otel_merging_test.go new file mode 100644 index 000000000..e86252e1d --- /dev/null +++ b/test/agent_otel_merging/agent_otel_merging_test.go @@ -0,0 +1,129 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT + +package agent_otel_merging + +import ( + "bytes" + "fmt" + "net/http" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" + "github.com/stretchr/testify/require" + + "github.com/aws/amazon-cloudwatch-agent-test/environment" + "github.com/aws/amazon-cloudwatch-agent-test/util/awsservice" + "github.com/aws/amazon-cloudwatch-agent-test/util/common" +) + +func init() { + environment.RegisterEnvironmentMetaDataFlags() +} + +// Tests merging of agent and OTEL yaml +// Merges OTLP receiver to Agent yaml +// And Checks if test_metric was generated(YAML merged successfully) +func TestOtelMerging(t *testing.T) { + startAgent(t) + appendOtelConfig(t) + sendPayload(t) + verifyMetricsInCloudWatch(t) + verifyHealthCheck(t) +} + +func startAgent(t *testing.T) { + common.CopyFile(filepath.Join("agent_configs", "config.json"), common.ConfigOutputPath) + require.NoError(t, common.StartAgent(common.ConfigOutputPath, true, false)) + time.Sleep(10 * time.Second) // Wait for the agent to start properly +} + +func appendOtelConfig(t *testing.T) { + cmd := exec.Command("sudo", "/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl", + "-a", "append-config", "-s", "-m", "ec2", "-c", "file:"+filepath.Join("resources", "otel.yaml")) + output, err := cmd.CombinedOutput() + require.NoError(t, err, "Failed to append OTEL config: %s", output) + time.Sleep(10 * time.Second) // Wait for the agent to apply the new configuration +} + +func sendPayload(t *testing.T) { + currentTimestamp := time.Now().UnixNano() + + payload, err := os.ReadFile(filepath.Join("resources", "metrics.json")) + require.NoError(t, err, "Failed to read JSON payload from metrics.json") + + payloadStr := string(payload) + payloadStr = strings.ReplaceAll(payloadStr, "$CURRENT_TIMESTAMP", fmt.Sprintf("%d", currentTimestamp)) + payloadStr = strings.ReplaceAll(payloadStr, "$INSTANCE_ID", environment.GetEnvironmentMetaData().InstanceId) + + req, err := http.NewRequest("POST", "http://localhost:4318/v1/metrics", bytes.NewBuffer([]byte(payloadStr))) + require.NoError(t, err, "Failed to create HTTP request") + + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + require.NoError(t, err, "Failed to send HTTP request") + + defer resp.Body.Close() + + require.True(t, resp.StatusCode >= 200 && resp.StatusCode < 300, "Unexpected status code: %d", resp.StatusCode) + time.Sleep(2 * time.Minute) +} + +func verifyMetricsInCloudWatch(t *testing.T) { + metricName := "test_metric" + namespace := "CWAgent-testing-otel" + + serviceDimName := "service.name" + serviceDimValue := "test-service" + instanceDimName := "instance_id" + instanceDimValue := environment.GetEnvironmentMetaData().InstanceId + + dimensions := []types.Dimension{ + { + Name: &serviceDimName, + Value: &serviceDimValue, + }, + { + Name: &instanceDimName, + Value: &instanceDimValue, + }, + } + + startTime := time.Now().Add(-5 * time.Minute) + endTime := time.Now() + periodInSeconds := int32(1) + statType := []types.Statistic{types.StatisticAverage} + + resp, err := awsservice.GetMetricStatistics( + metricName, + namespace, + dimensions, + startTime, + endTime, + periodInSeconds, + statType, + nil, + ) + + require.NoError(t, err, "Failed to fetch metric from CloudWatch") + require.NotEmpty(t, resp.Datapoints, "No data points found for the metric") + +} + +func verifyHealthCheck(t *testing.T) { + endpoint := "http://localhost:13133/health/status" + + resp, err := http.Get(endpoint) + require.NoError(t, err, "Failed to send HTTP request") + + defer resp.Body.Close() + + require.Equal(t, 200, resp.StatusCode, "Expected HTTP status code 200, got %d", resp.StatusCode) +} diff --git a/test/agent_otel_merging/resources/metrics.json b/test/agent_otel_merging/resources/metrics.json new file mode 100644 index 000000000..3afba52a0 --- /dev/null +++ b/test/agent_otel_merging/resources/metrics.json @@ -0,0 +1,47 @@ +{ + "resourceMetrics": [ + { + "resource": { + "attributes": [ + { + "key": "service.name", + "value": { + "stringValue": "test-service" + } + }, + { + "key": "instance_id", + "value": { + "stringValue": "$INSTANCE_ID" + } + } + ] + }, + "scopeMetrics": [ + { + "scope": { + "name": "my.library", + "version": "1.0.0" + }, + "metrics": [ + { + "name": "test_metric", + "unit": "1", + "sum": { + "aggregationTemporality": 1, + "isMonotonic": true, + "dataPoints": [ + { + "asDouble": 0.0, + "startTimeUnixNano": "$CURRENT_TIMESTAMP", + "timeUnixNano": "$CURRENT_TIMESTAMP" + } + ] + } + } + ] + } + ] + } + ] +} diff --git a/test/agent_otel_merging/resources/otel.yaml b/test/agent_otel_merging/resources/otel.yaml new file mode 100644 index 000000000..a77e70fbb --- /dev/null +++ b/test/agent_otel_merging/resources/otel.yaml @@ -0,0 +1,27 @@ +receivers: + otlp: + protocols: + grpc: + http: + +exporters: + awsemf/otel-merging: + namespace: "CWAgent-testing-otel" + log_group_name: "CWA" + dimension_rollup_option: "NoDimensionRollup" + log_stream_name: "Testing-otel" + resource_to_telemetry_conversion: + enabled: true + version: "0" + +extensions: + health_check: + +service: + extensions: + - health_check + pipelines: + metrics: + receivers: [otlp] + exporters: [awsemf/otel-merging] +