blob: c86828eac8c8717a4a2e536dc429fff94d91227f [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 arc
import (
"context"
"time"
"chromiumos/tast/errors"
"chromiumos/tast/local/arc"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/chrome/ash"
"chromiumos/tast/testing"
)
// windowStateTest is used to represent a single window state transition test.
type windowStateTest struct {
name string // Name of test case.
initialWindowState arc.WindowState // Activity's initial window state.
expectedInitialArcWindowState arc.WindowState // Activity's expected, initial ARC window state.
expectedInitialAshWindowState ash.WindowStateType // Activity's expected, initial ASH window state.
finalWindowState arc.WindowState // Activity's final window state.
expectedFinalArcWindowState arc.WindowState // Activity's expected, final ARC window state.
expectedFinalAshWindowState ash.WindowStateType // Activity's expected, final ASH window state.
}
// windowStateParams is used to represent a collection of tests to run in tablet mode or clamshell mode.
type windowStateParams struct {
tabletMode bool // True, if device should be in tablet mode.
testIterations int // Number of test iterations.
tests []windowStateTest // Activity's initial window state.
}
// clamshellWindowStateTests contains list of clamshell mode test cases.
var clamshellWindowStateTests = []windowStateTest{
{"MAXIMIZE <--> FULLSCREEN", arc.WindowStateMaximized, arc.WindowStateMaximized, ash.WindowStateMaximized, arc.WindowStateFullscreen, arc.WindowStateFullscreen, ash.WindowStateFullscreen},
{"MAXIMIZE <--> MINIMIZE", arc.WindowStateMaximized, arc.WindowStateMaximized, ash.WindowStateMaximized, arc.WindowStateMinimized, arc.WindowStateMinimized, ash.WindowStateMinimized},
{"MAXIMIZE <--> NORMAL", arc.WindowStateMaximized, arc.WindowStateMaximized, ash.WindowStateMaximized, arc.WindowStateNormal, arc.WindowStateNormal, ash.WindowStateNormal},
{"FULLSCREEN <--> MINIMIZE", arc.WindowStateFullscreen, arc.WindowStateFullscreen, ash.WindowStateFullscreen, arc.WindowStateMinimized, arc.WindowStateMinimized, ash.WindowStateMinimized},
{"FULLSCREEN <--> NORMAL", arc.WindowStateFullscreen, arc.WindowStateFullscreen, ash.WindowStateFullscreen, arc.WindowStateNormal, arc.WindowStateNormal, ash.WindowStateNormal},
{"NORMAL <--> MINIMIZE", arc.WindowStateNormal, arc.WindowStateNormal, ash.WindowStateNormal, arc.WindowStateMinimized, arc.WindowStateMinimized, ash.WindowStateMinimized},
}
// tabletWindowStateTests contains list of tablet mode test cases.
var tabletWindowStateTests = []windowStateTest{
{"MAXIMIZE <--> FULLSCREEN", arc.WindowStateMaximized, arc.WindowStateMaximized, ash.WindowStateMaximized, arc.WindowStateFullscreen, arc.WindowStateFullscreen, ash.WindowStateFullscreen},
{"MAXIMIZE <--> MINIMIZE", arc.WindowStateMaximized, arc.WindowStateMaximized, ash.WindowStateMaximized, arc.WindowStateMinimized, arc.WindowStateMinimized, ash.WindowStateMinimized},
{"FULLSCREEN <--> MINIMIZE", arc.WindowStateFullscreen, arc.WindowStateFullscreen, ash.WindowStateFullscreen, arc.WindowStateMinimized, arc.WindowStateMinimized, ash.WindowStateMinimized},
}
// tabletWindowStateTestsForP contains list of tablet mode test cases that are only for P.
// In R or later, freeform mode in tablet is no longer supported.
var tabletWindowStateTestsForP = []windowStateTest{
{"MAXIMIZE <--> NORMAL", arc.WindowStateMaximized, arc.WindowStateMaximized, ash.WindowStateMaximized, arc.WindowStateMaximized, arc.WindowStateMaximized, ash.WindowStateMaximized},
{"FULLSCREEN <--> NORMAL", arc.WindowStateFullscreen, arc.WindowStateFullscreen, ash.WindowStateFullscreen, arc.WindowStateNormal, arc.WindowStateMaximized, ash.WindowStateMaximized},
{"NORMAL <--> MINIMIZE", arc.WindowStateNormal, arc.WindowStateMaximized, ash.WindowStateMaximized, arc.WindowStateMinimized, arc.WindowStateMinimized, ash.WindowStateMinimized},
}
func init() {
testing.AddTest(&testing.Test{
Func: WindowState,
Desc: "Checks that ARC applications correctly change the window state",
Contacts: []string{"phshah@chromium.org", "arc-framework+tast@google.com"},
Attr: []string{"group:mainline", "informational"},
SoftwareDeps: []string{"chrome"},
Fixture: "arcBooted",
Timeout: 4 * time.Minute,
Params: []testing.Param{{
Name: "clamshell",
Val: windowStateParams{
false, // Clamshell mode.
1, // Num test iterations.
clamshellWindowStateTests,
},
ExtraSoftwareDeps: []string{"android_p"},
}, {
Name: "clamshell_vm",
Val: windowStateParams{
false, // Clamshell mode.
1, // Num test iterations.
clamshellWindowStateTests,
},
ExtraSoftwareDeps: []string{"android_vm"},
}, {
Name: "clamshell_stress",
Val: windowStateParams{
false, // Clamshell mode.
25, // Num test iterations.
clamshellWindowStateTests,
},
ExtraSoftwareDeps: []string{"android_p"},
}, {
Name: "clamshell_stress_vm",
Val: windowStateParams{
false, // Clamshell mode.
25, // Num test iterations.
clamshellWindowStateTests,
},
ExtraSoftwareDeps: []string{"android_vm"},
}, {
Name: "tablet",
Val: windowStateParams{
true, // Tablet Mode.
1, // Num test iterations.
append(tabletWindowStateTests, tabletWindowStateTestsForP...),
},
ExtraSoftwareDeps: []string{"android_p"},
}, {
Name: "tablet_vm",
Val: windowStateParams{
true, // Tablet Mode.
1, // Num test iterations.
tabletWindowStateTests,
},
ExtraSoftwareDeps: []string{"android_vm"},
}, {
Name: "tablet_stress",
Val: windowStateParams{
true, // Tablet Mode.
25, // Num test iterations.
append(tabletWindowStateTests, tabletWindowStateTestsForP...),
},
ExtraSoftwareDeps: []string{"android_p"},
}, {
Name: "tablet_stress_vm",
Val: windowStateParams{
true, // Tablet Mode.
25, // Num test iterations.
tabletWindowStateTests,
},
ExtraSoftwareDeps: []string{"android_vm"},
}},
})
}
func WindowState(ctx context.Context, s *testing.State) {
a := s.FixtValue().(*arc.PreData).ARC
cr := s.FixtValue().(*arc.PreData).Chrome
tconn, err := cr.TestAPIConn(ctx)
if err != nil {
s.Fatal("Failed to create Test API connection: ", err)
}
// Restore tablet mode to its original state on exit.
tabletModeEnabled, err := ash.TabletModeEnabled(ctx, tconn)
if err != nil {
s.Fatal("Failed to get tablet mode: ", err)
}
defer ash.SetTabletModeEnabled(ctx, tconn, tabletModeEnabled)
testParams := s.Param().(windowStateParams)
deviceMode := "clamshell"
if testParams.tabletMode {
deviceMode = "tablet"
}
s.Logf("Setting device to %v mode", deviceMode)
if err := ash.SetTabletModeEnabled(ctx, tconn, testParams.tabletMode); err != nil {
s.Fatalf("Failed to set tablet mode enabled to %t: %v", testParams.tabletMode, err)
}
// Run the different test cases.
for _, test := range testParams.tests {
s.Log("Testing ", test.name)
if err := func() error {
// Start the Settings app.
act, err := arc.NewActivity(a, "com.android.settings", ".Settings")
if err != nil {
return errors.Wrap(err, "failed to create new activity")
}
// Close the resources associated with the Activity instance.
defer act.Close()
if err := act.Start(ctx, tconn); err != nil {
return errors.Wrap(err, "failed to start the Settings activity")
}
// Stop the activity for each test case
defer act.Stop(ctx, tconn)
// Set the activity to the initial WindowState.
if err := setAndVerifyWindowState(ctx, act, tconn, test.initialWindowState, test.expectedInitialAshWindowState, test.expectedInitialArcWindowState); err != nil {
return errors.Wrap(err, "failed to set initial window state")
}
for i := 0; i < testParams.testIterations; i++ {
// Initial WindowState transition.
if err := setAndVerifyWindowState(ctx, act, tconn, test.initialWindowState, test.expectedInitialAshWindowState, test.expectedInitialArcWindowState); err != nil {
return errors.Wrapf(err, "failed to set the initial window state in iter %d", i)
}
// Final WindowState transition.
if err := setAndVerifyWindowState(ctx, act, tconn, test.finalWindowState, test.expectedFinalAshWindowState, test.expectedFinalArcWindowState); err != nil {
return errors.Wrapf(err, "failed to set the final window state in iter %d", i)
}
}
return nil
}(); err != nil {
s.Fatalf("%q subtest failed: %v", test.name, err)
}
}
}
// setAndVerifyWindowState sets and verifies the desired window state transition.
func setAndVerifyWindowState(ctx context.Context, act *arc.Activity, tconn *chrome.TestConn, arcWindowState arc.WindowState, expectedAshWindowState ash.WindowStateType, expectedArcWindowState arc.WindowState) error {
if err := act.SetWindowState(ctx, tconn, arcWindowState); err != nil {
return errors.Wrapf(err, "failed to set window state (%v)", arcWindowState)
}
if err := ash.WaitForARCAppWindowState(ctx, tconn, act.PackageName(), expectedAshWindowState); err != nil {
return errors.Wrapf(err, "failed to wait for a window state to appear on the Chrome side (%v)", expectedAshWindowState)
}
if err := testing.Poll(ctx, func(ctx context.Context) error {
actualArcWindowState, err := act.GetWindowState(ctx)
if err != nil {
return testing.PollBreak(errors.Wrap(err, "could not get ARC window state"))
}
if actualArcWindowState != expectedArcWindowState {
return errors.Errorf("unexpected ARC window state: got %v; want %v", actualArcWindowState, expectedArcWindowState)
}
return nil
}, &testing.PollOptions{Timeout: 10 * time.Second}); err != nil {
return errors.Wrap(err, "timed out waiting for ARC window state transition")
}
return nil
}