blob: 2d7cc0b38a3e1e2a2c4cad4cb36c6485c5471d41 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package faillog provides a post-test hook to save "faillog" on test failures.
// A faillog is a collection of log files which can be used to debug test failures.
package faillog
import (
"context"
"os"
"os/exec"
"path/filepath"
"chromiumos/tast/errors"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/chrome/cdputil"
"chromiumos/tast/local/screenshot"
"chromiumos/tast/local/upstart"
"chromiumos/tast/testing"
)
// Save saves a faillog unconditionally.
func Save(ctx context.Context) {
// If test setup failed, then the output dir may not exist.
dir, ok := testing.ContextOutDir(ctx)
if !ok || dir == "" {
testing.ContextLog(ctx, "Failed to get name of directory")
return
}
if _, err := os.Stat(dir); err != nil {
return
}
dir = filepath.Join(dir, "faillog")
if err := os.MkdirAll(dir, 0755); err != nil {
return
}
SaveToDir(ctx, dir)
}
// SaveToDir saves fail log to a specific directory.
func SaveToDir(ctx context.Context, dir string) {
saveProcessList(dir)
saveUpstartJobs(ctx, dir)
saveScreenshot(ctx, dir)
}
// saveProcessList saves "ps" output.
func saveProcessList(dir string) {
path := filepath.Join(dir, "ps.txt")
f, err := os.Create(path)
if err != nil {
return
}
defer f.Close()
cmd := exec.Command("ps", "auxwwfZ")
cmd.Stdout = f
cmd.Run()
}
// saveScreenshot saves a screenshot.
func saveScreenshot(ctx context.Context, dir string) {
if err := saveScreenshotCDP(ctx, dir); err != nil {
testing.ContextLog(ctx, "Failed to take screenshot by Chrome API: ", err)
} else {
return
}
// Fallback to built-in screenshot command.
if err := saveScreenshotBuiltIn(ctx, dir); err != nil {
testing.ContextLog(ctx, "Failed to take screenshot by a command: ", err)
}
}
// saveScreenshotBuiltIn saves a screenshot by using "screenshot" command.
func saveScreenshotBuiltIn(ctx context.Context, dir string) error {
path := filepath.Join(dir, "screenshot_builtin.png")
return screenshot.Capture(ctx, path)
}
// saveScreenshotCDP saves a screenshot by using Chrome API.
func saveScreenshotCDP(ctx context.Context, dir string) error {
sm, err := cdputil.NewSession(ctx, cdputil.DebuggingPortPath, cdputil.NoWaitPort)
if err != nil {
return errors.Wrap(err, "failed to create a new Chrome Devtools Protocol session")
}
bgURL := chrome.ExtensionBackgroundPageURL(chrome.TestExtensionID)
all, err := sm.FindTargets(ctx, chrome.MatchTargetURL(bgURL))
if len(all) == 0 {
// Target not found.
return errors.New("the background page of the test extension not found")
}
co, err := sm.NewConn(ctx, all[0].TargetID)
if err != nil {
return errors.Wrap(err, "failed to make a new Conn")
}
path := filepath.Join(dir, "screenshot_chrome.png")
testing.ContextLog(ctx, "Taking screenshot via chrome API")
return screenshot.CaptureCDP(ctx, co, path)
}
func saveUpstartJobs(ctx context.Context, dir string) {
path := filepath.Join(dir, "initctl_list.log")
if err := upstart.DumpJobs(ctx, path); err != nil {
testing.ContextLog(ctx, "Failed to take a snapshot of all upstart jobs' status: ", err)
}
}