blob: 13bfc78f364bca8187dd8e5bee8f5da71eaf913c [file] [log] [blame]
// Copyright 2021 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 cujrunner
import (
"context"
"encoding/json"
"time"
"chromiumos/tast/errors"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/chrome/uiauto"
"chromiumos/tast/local/chrome/uiauto/lockscreen"
"chromiumos/tast/local/chrome/uiauto/nodewith"
"chromiumos/tast/local/chrome/uiauto/role"
"chromiumos/tast/local/input"
"chromiumos/tast/testing"
)
func init() {
actionRegistry = make(map[string]actionFunc)
registerAction("OpenUrl", runActionOpenURL)
registerAction("LockScreen", runActionLockScreen)
registerAction("UnlockScreen", runActionUnlockScreen)
registerAction("ClickUI", runActionClickUI)
}
// action holds information parsed from json config.
type action struct {
Name string `json:"action"`
Args *json.RawMessage `json:"args,omitempty"`
Start string `json:"start,omitempty"`
}
// actionFunc defines an entry function type to run an action.
type actionFunc func(context.Context, *testing.State,
*chrome.Chrome, *chrome.TestConn,
*json.RawMessage) (func(context.Context) error, error)
var actionRegistry map[string]actionFunc
// registerAction associates an action name with its entry function.
func registerAction(n string, a actionFunc) {
actionRegistry[n] = a
}
// getAction looks up the entry function of the action identified by the name.
func getAction(n string) (actionFunc, bool) {
action, ok := actionRegistry[n]
return action, ok
}
// actionArgsOpenURL defines args in json for runActionOpenURL.
type actionArgsOpenURL struct {
URL string `json:"url"`
}
func runActionOpenURL(ctx context.Context, s *testing.State,
cr *chrome.Chrome, tconn *chrome.TestConn,
ad *json.RawMessage) (func(context.Context) error, error) {
args := &actionArgsOpenURL{}
if err := json.Unmarshal(*ad, args); err != nil {
return nil, errors.Wrap(err, "failed to parse args")
}
conn, err := cr.NewConn(ctx, args.URL)
if err != nil {
return nil, errors.Wrap(err, "failed to open url")
}
return func(context.Context) error {
return conn.Close()
}, nil
}
func runActionLockScreen(ctx context.Context, s *testing.State,
cr *chrome.Chrome, tconn *chrome.TestConn,
ad *json.RawMessage) (func(context.Context) error, error) {
return nil, lockscreen.Lock(ctx, tconn)
}
func runActionUnlockScreen(ctx context.Context, s *testing.State,
cr *chrome.Chrome, tconn *chrome.TestConn,
ad *json.RawMessage) (func(context.Context) error, error) {
kb, err := input.Keyboard(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to find keyboard")
}
defer kb.Close()
password := s.RequiredVar("ui.cuj_password")
if err := kb.Type(ctx, password+"\n"); err != nil {
return nil, errors.Wrap(err, "failed to type password")
}
const goodAuthTimeout = 30 * time.Second
if st, err := lockscreen.WaitState(ctx, tconn, func(st lockscreen.State) bool { return !st.Locked }, goodAuthTimeout); err != nil {
return nil, errors.Wrapf(err, "failed to wait for screen unlock (last status %+v)", st)
}
return nil, nil
}
type findParams struct {
Role role.Role
Name string
ClassName string
}
func runActionClickUI(ctx context.Context, s *testing.State,
cr *chrome.Chrome, tconn *chrome.TestConn,
ad *json.RawMessage) (func(context.Context) error, error) {
args := &findParams{}
if err := json.Unmarshal(*ad, args); err != nil {
return nil, errors.Wrap(err, "failed to parse args")
}
var f *nodewith.Finder
if args.Role != "" {
f = nodewith.Role(args.Role)
}
if args.Name != "" {
if f == nil {
f = nodewith.Name(args.Name)
} else {
f = f.Name(args.Name)
}
}
if args.ClassName != "" {
if f == nil {
f = nodewith.ClassName(args.ClassName)
} else {
f = f.ClassName(args.ClassName)
}
}
if f == nil {
return nil, errors.New("no data in args")
}
f = f.First()
ac := uiauto.New(tconn)
return nil, ac.LeftClick(f)(ctx)
}