blob: 92385761b8a43925adf28782a8a21aaf4cb8707b [file] [log] [blame]
// Copyright 2019 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 crostini
import (
"context"
"path/filepath"
"time"
"chromiumos/tast/common/testexec"
"chromiumos/tast/errors"
"chromiumos/tast/local/apps"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/chrome/ash"
"chromiumos/tast/local/chrome/uiauto"
"chromiumos/tast/local/screenshot"
"chromiumos/tast/shutil"
"chromiumos/tast/testing"
)
func exitIfShown(ctx context.Context, tconn *chrome.TestConn, appID string) error {
if visible, err := ash.AppShown(ctx, tconn, appID); err != nil {
return err
} else if !visible {
return nil
}
return apps.Close(ctx, tconn, appID)
}
func findNewShelfItem(before, after []*ash.ShelfItem) (string, error) {
if len(before) == len(after) {
return "", errors.New("no new shelf item")
}
if len(before)+1 != len(after) {
return "", errors.Errorf("item number mismatch, got %d wanted %d", len(after), len(before)+1)
}
beforeMap := map[string]bool{}
for _, beforeItem := range before {
beforeMap[beforeItem.AppID] = true
}
for _, afterItem := range after {
if !beforeMap[afterItem.AppID] {
return afterItem.AppID, nil
}
}
return "", errors.New("could not find the new shelf item")
}
// LaunchGUIApp runs the given command, which is meant to be a crostini
// application with a GUI, and returns:
// - A string, containing the ID of the app that was ran (i.e., a handle which
// can be used to inspect/close the app).
// - A callback which can be executed to close the application. Users of this
// function should immediately defer the callback if one is returned.
// - An error, which indicates something went wrong, or nil otherwise.
func LaunchGUIApp(ctx context.Context, tconn *chrome.TestConn, cmd *testexec.Cmd) (string, func(), error) {
beforeItems, err := ash.ShelfItems(ctx, tconn)
if err != nil {
return "", func() {}, err
}
if err := cmd.Start(); err != nil {
return "", func() {}, errors.Wrapf(err, "failed to start %q", shutil.EscapeSlice(cmd.Args))
}
var newID string
if err := testing.Poll(ctx, func(ctx context.Context) error {
if currentItems, err := ash.ShelfItems(ctx, tconn); err != nil {
return err
} else if newID, err = findNewShelfItem(beforeItems, currentItems); err != nil {
return err
}
return nil
}, &testing.PollOptions{Timeout: 30 * time.Second}); err != nil {
cmd.Kill()
cmd.Wait(testexec.DumpLogOnError)
return "", func() {}, err
}
return newID, func() {
exitIfShown(ctx, tconn, newID)
cmd.Wait(testexec.DumpLogOnError)
}, nil
}
// TakeAppScreenshot takes a screenshot and saves it to the test context output
// directory. On error will print a message and continue.
func TakeAppScreenshot(appName string) uiauto.Action {
return func(ctx context.Context) error {
dir, ok := testing.ContextOutDir(ctx)
if !ok || dir == "" {
testing.ContextLog(ctx, "Failed to get name of directory for screenshot")
} else {
path := filepath.Join(dir, "crostini_app_"+appName+".png")
if err := screenshot.Capture(ctx, path); err != nil {
testing.ContextLog(ctx, "Failed to take screenshot: ", err)
}
}
return nil
}
}