Skip to content

Commit da59d1e

Browse files
authored
Add process dump for failed integration tests (#4304)
* Add process dump for failed integration tests * add json artifact for processes
1 parent 993b786 commit da59d1e

File tree

1 file changed

+58
-21
lines changed

1 file changed

+58
-21
lines changed

pkg/testing/fixture_install.go

+58-21
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package testing
77
import (
88
"archive/zip"
99
"context"
10+
"encoding/json"
1011
"errors"
1112
"fmt"
1213
"io"
@@ -23,7 +24,6 @@ import (
2324
"github.com/stretchr/testify/require"
2425

2526
"github.com/elastic/elastic-agent-libs/mapstr"
26-
"github.com/elastic/elastic-agent-libs/opt"
2727
agentsystemprocess "github.com/elastic/elastic-agent-system-metrics/metric/system/process"
2828
"github.com/elastic/elastic-agent/internal/pkg/agent/application/paths"
2929
"github.com/elastic/elastic-agent/pkg/control/v2/client"
@@ -170,6 +170,38 @@ func (f *Fixture) Install(ctx context.Context, installOpts *InstallOpts, opts ..
170170
c := client.New(client.WithAddress(socketPath))
171171
f.setClient(c)
172172

173+
f.t.Cleanup(func() {
174+
if f.t.Failed() {
175+
procs := getProcesses(f.t, `.*`)
176+
dir, err := findProjectRoot(f.caller)
177+
if err != nil {
178+
f.t.Logf("failed to dump process; failed to find project root: %s", err)
179+
return
180+
}
181+
182+
// Sub-test names are separated by "/" characters which are not valid filenames on Linux.
183+
sanitizedTestName := strings.ReplaceAll(f.t.Name(), "/", "-")
184+
185+
filePath := filepath.Join(dir, "build", "diagnostics", fmt.Sprintf("TEST-%s-%s-%s-ProcessDump.json", sanitizedTestName, f.operatingSystem, f.architecture))
186+
f.t.Logf("Dumping running processes in %s", filePath)
187+
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
188+
if err != nil {
189+
f.t.Logf("failed to dump process; failed to create output file %s root: %s", file.Name(), err)
190+
return
191+
}
192+
defer func(file *os.File) {
193+
err := file.Close()
194+
if err != nil {
195+
f.t.Logf("error closing file %s: %s", file.Name(), err)
196+
}
197+
}(file)
198+
err = json.NewEncoder(file).Encode(procs)
199+
if err != nil {
200+
f.t.Logf("error serializing processes: %s", err)
201+
}
202+
}
203+
})
204+
173205
f.t.Cleanup(func() {
174206
// check for running agents after uninstall had a chance to run
175207
assert.Empty(f.t, getElasticAgentProcesses(f.t), "there should be no running agent at the end of the test")
@@ -235,19 +267,19 @@ func (f *Fixture) Install(ctx context.Context, installOpts *InstallOpts, opts ..
235267

236268
type runningProcess struct {
237269
// Basic Process data
238-
Name string
239-
State agentsystemprocess.PidState
240-
Username string
241-
Pid opt.Int
242-
Ppid opt.Int
243-
Pgid opt.Int
270+
Name string `json:"name,omitempty"`
271+
State agentsystemprocess.PidState `json:"state,omitempty"`
272+
Username string `json:"username,omitempty"`
273+
Pid int `json:"pid"`
274+
Ppid int `json:"ppid"`
275+
Pgid int `json:"pgid"`
244276

245277
// Extended Process Data
246-
Args []string
247-
Cmdline string
248-
Cwd string
249-
Exe string
250-
Env mapstr.M
278+
Args []string `json:"args,omitempty"`
279+
Cmdline string `json:"cmdline,omitempty"`
280+
Cwd string `json:"cwd,omitempty"`
281+
Exe string `json:"exe,omitempty"`
282+
Env mapstr.M `json:"env,omitempty"`
251283
}
252284

253285
func (p runningProcess) String() string {
@@ -260,14 +292,15 @@ func mapProcess(p agentsystemprocess.ProcState) runningProcess {
260292
Name: p.Name,
261293
State: p.State,
262294
Username: p.Username,
263-
Pid: p.Pid,
264-
Ppid: p.Ppid,
265-
Pgid: p.Pgid,
266-
Cmdline: p.Cmdline,
267-
Cwd: p.Cwd,
268-
Exe: p.Exe,
269-
Args: make([]string, len(p.Args)),
270-
Env: make(mapstr.M),
295+
// map pid/gid to int and default to an obvious impossible pid if we don't have a value
296+
Pid: p.Pid.ValueOr(-1),
297+
Ppid: p.Ppid.ValueOr(-1),
298+
Pgid: p.Pgid.ValueOr(-1),
299+
Cmdline: p.Cmdline,
300+
Cwd: p.Cwd,
301+
Exe: p.Exe,
302+
Args: make([]string, len(p.Args)),
303+
Env: make(mapstr.M),
271304
}
272305
copy(mappedProcess.Args, p.Args)
273306
for k, v := range p.Env {
@@ -277,8 +310,12 @@ func mapProcess(p agentsystemprocess.ProcState) runningProcess {
277310
}
278311

279312
func getElasticAgentProcesses(t *gotesting.T) []runningProcess {
313+
return getProcesses(t, `.*elastic\-agent.*`)
314+
}
315+
316+
func getProcesses(t *gotesting.T, regex string) []runningProcess {
280317
procStats := agentsystemprocess.Stats{
281-
Procs: []string{`.*elastic\-agent.*`},
318+
Procs: []string{regex},
282319
}
283320

284321
err := procStats.Init()

0 commit comments

Comments
 (0)