blob: 31bdf92047871e2e975ef13ee87078cc7716fd09 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package intel
import (
"context"
"regexp"
"time"
"go.chromium.org/tast-tests/cros/remote/firmware/fixture"
"go.chromium.org/tast-tests/cros/remote/firmware/reporters"
"go.chromium.org/tast-tests/cros/remote/firmware/suspend"
"go.chromium.org/tast-tests/cros/remote/powercontrol"
"go.chromium.org/tast/core/ctxutil"
"go.chromium.org/tast/core/errors"
"go.chromium.org/tast/core/testing"
"go.chromium.org/tast/core/testing/hwdep"
)
func init() {
testing.AddTest(&testing.Test{
Func: S0ixSwitchLaptopTablet,
LacrosStatus: testing.LacrosVariantUnneeded,
Desc: "During S0ix switch between laptop and tablet mode to resume DUT",
Contacts: []string{"intel.chrome.automation.team@intel.com", "ambalavanan.m.m@intel.com"},
BugComponent: "b:157291",
ServiceDeps: []string{"tast.cros.security.BootLockboxService"},
SoftwareDeps: []string{"chrome"},
Attr: []string{"group:intel-sleep"},
Fixture: fixture.NormalMode,
HardwareDeps: hwdep.D(hwdep.ChromeEC(), hwdep.FormFactor(hwdep.Convertible)),
Timeout: 10 * time.Minute,
})
}
func S0ixSwitchLaptopTablet(ctx context.Context, s *testing.State) {
h := s.FixtValue().(*fixture.Value).Helper
if err := h.RequireServo(ctx); err != nil {
s.Fatal("Failed to connect to servo: ", err)
}
dut := s.DUT()
cleanupCtx := ctx
ctx, cancel := ctxutil.Shorten(ctx, 3*time.Minute)
defer cancel()
r := h.Reporter
if err := r.ClearEventlog(ctx); err != nil {
s.Fatal("Failed to clear event log: ", err)
}
// This Coldboot is required to get uniform results and remove any flakiness.
if err := powercontrol.PerformColdboot(ctx, dut, h.ServoProxy); err != nil {
s.Fatal("Failed to perform coldboot: ", err)
}
// Perform a Chrome login.
s.Log("Login to Chrome")
if err := powercontrol.ChromeOSLogin(ctx, h.DUT, s.RPCHint()); err != nil {
s.Fatal("Failed to login to chrome: ", err)
}
// Create our suspend context.
suspendCtx, err := suspend.NewContext(ctx, h)
if err != nil {
s.Fatalf("Failed to create suspend context: %s", err)
}
defer suspendCtx.Close()
defer func(ctx context.Context) {
s.Log("Performing cleanup")
if err := h.EnsureDUTBooted(ctx); err != nil {
s.Fatal("Failed to ensure the DUT is booted: ", err)
}
if err := h.Servo.RunECCommand(ctx, "tabletmode reset"); err != nil {
s.Fatal("Failed to restore DUT to the original laptop mode setting: ", err)
}
}(cleanupCtx)
slpOpSetPre, pkgOpSetPre, err := powercontrol.SlpAndC10PackageValues(ctx, h.DUT)
if err != nil {
s.Fatal("Failed to get SLP counter and C10 package values before suspend-resume: ", err)
}
s.Log("Suspending DUT")
// DON'T DO THIS, LEAVE THE SUSPEND MODE AT IT'S DEFAULT
if err := suspendCtx.SuspendDUT(suspend.StateS0ix, suspend.DefaultSuspendArgs()); err != nil {
s.Fatalf("Failed to suspend DUT: %s", err)
}
// Run EC command to put DUT in tablet mode.
if err := h.Servo.RunECCommand(ctx, "tabletmode on"); err != nil {
s.Fatal("Failed to set DUT into tablet mode: ", err)
}
if err := verifyEvents(ctx, r); err != nil {
s.Fatal("Failed to verify events: ", err)
}
slpOpSetPost, pkgOpSetPost, err := powercontrol.SlpAndC10PackageValues(ctx, h.DUT)
if err != nil {
s.Fatal("Failed to get SLP counter and C10 package values after suspend-resume: ", err)
}
if err := powercontrol.AssertSLPAndC10(slpOpSetPre, slpOpSetPost, pkgOpSetPre, pkgOpSetPost); err != nil {
s.Fatal("Failed to verify SLP and C10 state values: ", err)
}
s.Log("Suspending DUT")
// DON'T DO THIS, LEAVE THE SUSPEND MODE AT IT'S DEFAULT
if err := suspendCtx.SuspendDUT(suspend.StateS0ix, suspend.DefaultSuspendArgs()); err != nil {
s.Fatalf("Failed to suspend DUT: %s", err)
}
// Run EC command to put DUT in normal mode.
if err := h.Servo.RunECCommand(ctx, "tabletmode off"); err != nil {
s.Fatal("Failed to set DUT into tablet mode: ", err)
}
if err := verifyEvents(ctx, r); err != nil {
s.Fatal("Failed to verify events: ", err)
}
slpOpSetPostL, pkgOpSetPostL, err := powercontrol.SlpAndC10PackageValues(ctx, h.DUT)
if err != nil {
s.Fatal("Failed to get SLP counter and C10 package values after suspend-resume: ", err)
}
if err := powercontrol.AssertSLPAndC10(slpOpSetPre, slpOpSetPostL, pkgOpSetPre, pkgOpSetPostL); err != nil {
s.Fatal("Failed to verify SLP and C10 state values: ", err)
}
}
// verifyEvents verifies the required event set for S0ix and EC Mode change.
func verifyEvents(ctx context.Context, r *reporters.Reporter) error {
var requiredEventSets = [][]string{{`S0ix Enter`, `S0ix Exit`}, {`EC Event \| Mode change`}}
events, err := r.EventlogList(ctx)
if err != nil {
return errors.Wrap(err, "failed gathering events")
}
requiredEventsFound := false
for _, requiredEventSet := range requiredEventSets {
foundAllRequiredEventsInSet := true
for _, requiredEvent := range requiredEventSet {
reRequiredEvent := regexp.MustCompile(requiredEvent)
if !eventMessagesContainMatch(ctx, events, reRequiredEvent) {
foundAllRequiredEventsInSet = false
break
}
}
if foundAllRequiredEventsInSet {
requiredEventsFound = true
break
}
}
if !requiredEventsFound {
return errors.New("failed as required event missing")
}
return nil
}
// eventMessagesContainMatch verifies whether event log contains matching eventlog.
func eventMessagesContainMatch(ctx context.Context, events []reporters.Event, re *regexp.Regexp) bool {
for _, event := range events {
if re.MatchString(event.Message) {
return true
}
}
return false
}