diff --git a/comp/process/status/statusimpl/fixtures/json_response.tmpl b/comp/process/status/statusimpl/fixtures/json_response.tmpl new file mode 100644 index 00000000000000..b106576ccd0ce2 --- /dev/null +++ b/comp/process/status/statusimpl/fixtures/json_response.tmpl @@ -0,0 +1,126 @@ +{ + "core": { + "build_arch": "arm64", + "config": { + "log_level": "info" + }, + "go_version": "go1.21.5", + "metadata": { + "agent-flavor": "process_agent", + "host-tags": { + "system": [] + }, + "install-method": { + "installer_version": null, + "tool": null, + "tool_version": "undefined" + }, + "logs": { + "auto_multi_line_detection_enabled": false, + "transport": "" + }, + "meta": { + "ec2-hostname": "", + "host_aliases": [], + "hostname": "COMP-VQHPF4W6GY", + "instance-id": "", + "socket-fqdn": "COMP-VQHPF4W6GY", + "socket-hostname": "COMP-VQHPF4W6GY", + "timezones": [ + "CET" + ] + }, + "network": null, + "os": "darwin", + "otlp": { + "enabled": false + }, + "proxy-info": { + "no-proxy-nonexact-match": false, + "no-proxy-nonexact-match-explicitly-set": false, + "proxy-behavior-changed": false + }, + "python": "n/a", + "systemStats": { + "cpuCores": 10, + "fbsdV": [ + "", + "", + "" + ], + "macV": [ + "14.2.1", + [ + "", + "", + "" + ], + "arm64" + ], + "machine": "arm64", + "nixV": [ + "", + "", + "" + ], + "platform": "darwin", + "processor": "Apple M1 Max", + "pythonV": "n/a", + "winV": [ + "", + "", + "" + ] + } + }, + "version": "7.51.0-rc.1+git.416.0d1edc1" + }, + "date": 1706892483712089000, + "expvars": { + "connections_queue_bytes": 0, + "connections_queue_size": 0, + "container_count": 0, + "container_id": "", + "docker_socket": "/var/run/docker.sock", + "drop_check_payloads": [], + "enabled_checks": [ + "process", + "rtprocess" + ], + "endpoints": { + "https://process.datadoghq.eu": [ + "72724" + ] + }, + "event_queue_bytes": 0, + "event_queue_size": 0, + "language_detection_enabled": false, + "last_collect_time": "2024-02-02 17:47:57", + "log_file": "", + "memstats": { + "alloc": 30387880 + }, + "pid": 72211, + "pod_queue_bytes": 0, + "pod_queue_size": 0, + "process_count": 757, + "process_queue_bytes": 0, + "process_queue_size": 0, + "proxy_url": "", + "rtprocess_queue_bytes": 0, + "rtprocess_queue_size": 0, + "system_probe_process_module_enabled": false, + "uptime": 18, + "uptime_nano": 1706892464835469000, + "version": { + "BuildDate": "", + "GitBranch": "", + "GitCommit": "", + "GoVersion": "", + "Version": "" + }, + "workloadmeta_extractor_cache_size": 0, + "workloadmeta_extractor_diffs_dropped": 0, + "workloadmeta_extractor_stale_diffs": 0 + } +} diff --git a/comp/process/status/statusimpl/fixtures/text_error_response.tmpl b/comp/process/status/statusimpl/fixtures/text_error_response.tmpl new file mode 100644 index 00000000000000..29cf3ab6fdcab3 --- /dev/null +++ b/comp/process/status/statusimpl/fixtures/text_error_response.tmpl @@ -0,0 +1,2 @@ + + Status: Not running or unreachable diff --git a/comp/process/status/statusimpl/fixtures/text_response.tmpl b/comp/process/status/statusimpl/fixtures/text_response.tmpl new file mode 100644 index 00000000000000..76089de0141e57 --- /dev/null +++ b/comp/process/status/statusimpl/fixtures/text_response.tmpl @@ -0,0 +1,48 @@ + + Version: 7.51.0-rc.1+git.416.0d1edc1 + Status date: 2024-02-02 16:48:03.712 UTC (1706892483712) + Process Agent Start: 2024-02-02 16:47:44.835 UTC (1706892464835) + Pid: 72211 + Go Version: go1.21.5 + Build arch: arm64 + Log Level: info + Enabled Checks: [process rtprocess] + Allocated Memory: 30,387,880 bytes + Hostname: COMP-VQHPF4W6GY + System Probe Process Module Status: Not running + Process Language Detection Enabled: False + + ================= + Process Endpoints + ================= + https://process.datadoghq.eu - API Key ending with: + - 72724 + + ========= + Collector + ========= + Last collection time: 2024-02-02 17:47:57 + Docker socket: /var/run/docker.sock + Number of processes: 757 + Number of containers: 0 + Process Queue length: 0 + RTProcess Queue length: 0 + Connections Queue length: 0 + Event Queue length: 0 + Pod Queue length: 0 + Process Bytes enqueued: 0 + RTProcess Bytes enqueued: 0 + Connections Bytes enqueued: 0 + Event Bytes enqueued: 0 + Pod Bytes enqueued: 0 + Drop Check Payloads: [] + + ========== + Extractors + ========== + + Workloadmeta + ============ + Cache size: 0 + Stale diffs discarded: 0 + Diffs dropped: 0 diff --git a/comp/process/status/statusimpl/status.go b/comp/process/status/statusimpl/status.go index 50a3e7d9a06267..c57ce33ee6d4d2 100644 --- a/comp/process/status/statusimpl/status.go +++ b/comp/process/status/statusimpl/status.go @@ -51,7 +51,9 @@ func Module() fxutil.Module { fx.Provide(newStatus)) } -type statusProvider struct{} +type statusProvider struct { + testServerURL string +} func newStatus() provides { return provides{ @@ -84,24 +86,33 @@ func (s statusProvider) getStatusInfo() map[string]interface{} { func (s statusProvider) populateStatus() map[string]interface{} { status := make(map[string]interface{}) - addressPort, err := config.GetProcessAPIAddressPort() - if err != nil { - status["error"] = fmt.Sprintf("%v", err.Error()) - return status - } c := client() - statusEndpoint := fmt.Sprintf("http://%s/agent/status", addressPort) - b, err := apiutil.DoGet(c, statusEndpoint, apiutil.CloseConnection) + + var url string + if s.testServerURL != "" { + url = s.testServerURL + } else { + addressPort, err := config.GetProcessAPIAddressPort() + if err != nil { + status["error"] = fmt.Sprintf("%v", err.Error()) + return status + } + url = fmt.Sprintf("http://%s/agent/status", addressPort) + } + + b, err := apiutil.DoGet(c, url, apiutil.CloseConnection) + if err != nil { status["error"] = fmt.Sprintf("%v", err.Error()) return status } - err = json.Unmarshal(b, &s) + err = json.Unmarshal(b, &status) if err != nil { - status["error"] = fmt.Sprintf("%v", err.Error()) - return status + return map[string]interface{}{ + "error": fmt.Sprintf("%v", err.Error()), + } } return status diff --git a/comp/process/status/statusimpl/status_templates/processagent.tmpl b/comp/process/status/statusimpl/status_templates/processagent.tmpl index 54a9974b3b82b9..bde6eecd106bb2 100644 --- a/comp/process/status/statusimpl/status_templates/processagent.tmpl +++ b/comp/process/status/statusimpl/status_templates/processagent.tmpl @@ -1,9 +1,7 @@ {{- with .processAgentStatus }} {{- if .error }} - Status: Not running or unreachable {{- else }} - Version: {{ .core.version }} Status date: {{ formatUnixTime .date }} Process Agent Start: {{ formatUnixTime .expvars.uptime_nano }} diff --git a/comp/process/status/statusimpl/status_test.go b/comp/process/status/statusimpl/status_test.go index cf07f6eddc4c88..33e76e203497d2 100644 --- a/comp/process/status/statusimpl/status_test.go +++ b/comp/process/status/statusimpl/status_test.go @@ -7,15 +7,54 @@ package statusimpl import ( "bytes" + "embed" + "net/http" + "net/http/httptest" + "os" + "strings" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -func TestStatusOut(t *testing.T) { - provides := newStatus() +//go:embed fixtures +var fixturesTemplates embed.FS - headerProvider := provides.StatusProvider.Provider +func fakeStatusServer(t *testing.T, errCode int, response []byte) *httptest.Server { + handler := func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + + if errCode != 200 { + http.NotFound(w, r) + } else { + _, err := w.Write(response) + require.NoError(t, err) + } + } + + return httptest.NewServer(http.HandlerFunc(handler)) +} + +func TestStatus(t *testing.T) { + originalTZ := os.Getenv("TZ") + os.Setenv("TZ", "UTC") + defer func() { + os.Setenv("TZ", originalTZ) + }() + + jsonBytes, err := fixturesTemplates.ReadFile("fixtures/json_response.tmpl") + assert.NoError(t, err) + + textResponse, err := fixturesTemplates.ReadFile("fixtures/text_response.tmpl") + assert.NoError(t, err) + + server := fakeStatusServer(t, 200, jsonBytes) + defer server.Close() + + headerProvider := statusProvider{ + testServerURL: server.URL, + } tests := []struct { name string @@ -24,8 +63,13 @@ func TestStatusOut(t *testing.T) { {"JSON", func(t *testing.T) { stats := make(map[string]interface{}) headerProvider.JSON(false, stats) + processStats := stats["processAgentStatus"] + + val, ok := processStats.(map[string]interface{}) + assert.True(t, ok) - assert.NotEmpty(t, stats) + assert.NotEmpty(t, val["core"]) + assert.Empty(t, val["error"]) }}, {"Text", func(t *testing.T) { b := new(bytes.Buffer) @@ -33,7 +77,11 @@ func TestStatusOut(t *testing.T) { assert.NoError(t, err) - assert.NotEmpty(t, b.String()) + // We replace windows line break by linux so the tests pass on every OS + expected := strings.Replace(string(textResponse), "\r\n", "\n", -1) + output := strings.Replace(b.String(), "\r\n", "\n", -1) + + assert.Equal(t, expected, output) }}, {"HTML", func(t *testing.T) { b := new(bytes.Buffer) @@ -51,3 +99,55 @@ func TestStatusOut(t *testing.T) { }) } } + +func TestStatusError(t *testing.T) { + server := fakeStatusServer(t, 500, []byte{}) + defer server.Close() + + originalTZ := os.Getenv("TZ") + os.Setenv("TZ", "UTC") + defer func() { + os.Setenv("TZ", originalTZ) + }() + + errorResponse, err := fixturesTemplates.ReadFile("fixtures/text_error_response.tmpl") + assert.NoError(t, err) + + headerProvider := statusProvider{ + testServerURL: server.URL, + } + + tests := []struct { + name string + assertFunc func(t *testing.T) + }{ + {"JSON", func(t *testing.T) { + stats := make(map[string]interface{}) + headerProvider.JSON(false, stats) + processStats := stats["processAgentStatus"] + + val, ok := processStats.(map[string]interface{}) + assert.True(t, ok) + + assert.NotEmpty(t, val["error"]) + }}, + {"Text", func(t *testing.T) { + b := new(bytes.Buffer) + err := headerProvider.Text(false, b) + + assert.NoError(t, err) + + // We replace windows line break by linux so the tests pass on every OS + expected := strings.Replace(string(errorResponse), "\r\n", "\n", -1) + output := strings.Replace(b.String(), "\r\n", "\n", -1) + + assert.Equal(t, expected, output) + }}, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.assertFunc(t) + }) + } +} diff --git a/test/new-e2e/tests/process/linux_test.go b/test/new-e2e/tests/process/linux_test.go index 85a29803665c8c..d232be330c1488 100644 --- a/test/new-e2e/tests/process/linux_test.go +++ b/test/new-e2e/tests/process/linux_test.go @@ -24,7 +24,6 @@ type linuxTestSuite struct { } func TestLinuxTestSuite(t *testing.T) { - t.Skip("PROCS-3574: consistent failures on process tests") e2e.Run(t, &linuxTestSuite{}, e2e.WithProvisioner(awshost.Provisioner(awshost.WithAgentOptions(agentparams.WithAgentConfig(processCheckConfigStr))))) } diff --git a/test/new-e2e/tests/process/windows_test.go b/test/new-e2e/tests/process/windows_test.go index 69c2abddd327c0..3b38b92ba72c13 100644 --- a/test/new-e2e/tests/process/windows_test.go +++ b/test/new-e2e/tests/process/windows_test.go @@ -26,7 +26,6 @@ type windowsTestSuite struct { } func TestWindowsTestSuite(t *testing.T) { - t.Skip("PROCS-3644: consistent failures on process tests") e2e.Run(t, &windowsTestSuite{}, e2e.WithProvisioner( awshost.Provisioner(