blob: 890e2f4b40bae5aab32c021edff2a70fdf6f5d1a [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 (
"bytes"
"context"
"path/filepath"
"time"
"github.com/golang/protobuf/ptypes/empty"
"go.chromium.org/tast-tests/cros/common/cswitch"
"go.chromium.org/tast-tests/cros/common/servo"
"go.chromium.org/tast-tests/cros/common/usbutils"
"go.chromium.org/tast-tests/cros/remote/powercontrol"
"go.chromium.org/tast-tests/cros/services/cros/power"
"go.chromium.org/tast/core/ctxutil"
"go.chromium.org/tast/core/dut"
"go.chromium.org/tast/core/errors"
"go.chromium.org/tast/core/rpc"
"go.chromium.org/tast/core/testing"
)
type usbPowerMode int
const (
warmboot usbPowerMode = iota
coldboot
)
type usbTypeATestParam struct {
powerMode usbPowerMode
usbSpeed string
cbmemSleepState int
cSwitchON string
}
func init() {
testing.AddTest(&testing.Test{
Func: USBTypeAStorageFunctionality,
LacrosStatus: testing.LacrosVariantUnneeded,
Desc: "Verifies USB type-A storage device functionality on warmboot/coldboot operation",
Contacts: []string{"intel.chrome.automation.team@intel.com", "ambalavanan.m.m@intel.com"},
BugComponent: "b:157291",
SoftwareDeps: []string{"chrome", "reboot"},
ServiceDeps: []string{"tast.cros.power.USBService"},
Attr: []string{"group:intel-cswitch-set1"},
Vars: []string{"servo", "intel.cSwitchPort", "intel.domainIP"},
Params: []testing.Param{{
Name: "usb2_warmboot",
Val: usbTypeATestParam{warmboot, "480M", 0, "4"},
Timeout: 5 * time.Minute,
}, {
Name: "usb2_coldboot",
Val: usbTypeATestParam{coldboot, "480M", 5, "4"},
Timeout: 5 * time.Minute,
}, {
Name: "usb3_warmboot",
Val: usbTypeATestParam{warmboot, "5000M", 0, "4"},
Timeout: 5 * time.Minute,
}, {
Name: "usb3_coldboot",
Val: usbTypeATestParam{coldboot, "5000M", 5, "4"},
Timeout: 5 * time.Minute,
}}})
}
func USBTypeAStorageFunctionality(ctx context.Context, s *testing.State) {
cleanupCtx := ctx
ctx, cancel := ctxutil.Shorten(ctx, 3*time.Minute)
defer cancel()
dut := s.DUT()
testParam := s.Param().(usbTypeATestParam)
// IP address of Tqc server hosting device.
domainIP := s.RequiredVar("intel.domainIP")
// The USB 2.0 and 3.0 pendrive is connected to C-Switch in P4 as per the intel_cswitch_set1 suite setup.
cswitchVar := testParam.cSwitchON
if cswitchON, ok := s.Var("intel.cSwitchPort"); ok {
cswitchVar = cswitchON
}
servoSpec := s.RequiredVar("servo")
pxy, err := servo.NewProxy(ctx, servoSpec, dut.KeyFile(), dut.KeyDir())
if err != nil {
s.Fatal("Failed to connect to servo: ", err)
}
defer pxy.Close(cleanupCtx)
// Connect to gRPC server.
cl, err := rpc.Dial(ctx, dut, s.RPCHint())
if err != nil {
s.Fatal("Failed to connect to the RPC service on the DUT: ", err)
}
client := power.NewUSBServiceClient(cl.Conn)
if _, err := client.NewChrome(ctx, &empty.Empty{}); err != nil {
s.Fatal("Failed to start Chrome: ", err)
}
defer client.CloseChrome(cleanupCtx, &empty.Empty{})
// Create C-Switch session that performs hot plug-unplug on TBT device.
sessionID, err := cswitch.CreateSession(ctx, domainIP)
if err != nil {
s.Fatal("Failed to create sessionID: ", err)
}
const cSwitchOFF = "0"
defer func(ctx context.Context) {
testing.ContextLog(ctx, "Performing cleanup")
if !dut.Connected(ctx) {
if err := powercontrol.PowerOntoDUT(ctx, pxy, dut); err != nil {
s.Error("Failed to power on DUT at cleanup: ", err)
}
}
if err := cswitch.ToggleCSwitchPort(ctx, sessionID, cSwitchOFF, domainIP); err != nil {
s.Fatal("Failed to disable c-switch port: ", err)
}
if err := cswitch.CloseSession(ctx, sessionID, domainIP); err != nil {
s.Error("Failed to close sessionID: ", err)
}
}(cleanupCtx)
if err := cswitch.ToggleCSwitchPort(ctx, sessionID, cswitchVar, domainIP); err != nil {
s.Fatal("Failed to enable c-switch port: ", err)
}
// Check for USB storage device detection before warmboot/coldboot.
if err := validateUSBStorageDetection(ctx, dut, testParam.usbSpeed); err != nil {
s.Fatal("Failed to detect connected USB storage device before warmboot/coldboot: ", err)
}
switch testParam.powerMode {
case warmboot:
s.Log("Performing warmboot")
if err := dut.Reboot(ctx); err != nil {
s.Fatal("Failed to warmboot DUT: ", err)
}
case coldboot:
s.Log("Performing coldboot")
powerState := "S5"
if err := powercontrol.ShutdownAndWaitForPowerState(ctx, pxy, dut, powerState); err != nil {
s.Fatalf("Failed to shutdown and wait for %q powerstate: %v", powerState, err)
}
if err := powercontrol.PowerOntoDUT(ctx, pxy, dut); err != nil {
s.Fatal("Failed to power on DUT: ", err)
}
}
// Login to Chrome after warmboot/coldboot.
cl, err = rpc.Dial(ctx, dut, s.RPCHint())
if err != nil {
s.Fatal("Failed to connect to the RPC service on the DUT: ", err)
}
client = power.NewUSBServiceClient(cl.Conn)
if _, err := client.NewChrome(ctx, &empty.Empty{}); err != nil {
s.Fatal("Failed to start Chrome: ", err)
}
defer client.CloseChrome(cleanupCtx, &empty.Empty{})
// Check for prev_sleep_state after warmboot/coldboot.
if err := powercontrol.ValidatePrevSleepState(ctx, dut, testParam.cbmemSleepState); err != nil {
s.Fatal("Failed to validate previous sleep state: ", err)
}
// Check for USB storage device detection after warmboot/coldboot.
if err := validateUSBStorageDetection(ctx, dut, testParam.usbSpeed); err != nil {
s.Fatal("Failed to detect connected USB storage device after warmboot/coldboot: ", err)
}
if err := cswitch.ToggleCSwitchPort(ctx, sessionID, cSwitchOFF, domainIP); err != nil {
s.Fatal("Failed to enable c-switch port: ", err)
}
// Check for USB storage device detection after unplug.
if err := validateUSBStorageDetection(ctx, dut, testParam.usbSpeed); err == nil {
s.Fatal("Failed USB storage device still detecting after unplug: ", err)
}
const fileName = "test_sample_file.txt"
const fileSize = 1 * 1024 * 1024
fileNameAndFileSize := &power.TestFileRequest{FileName: fileName, FileSize: int64(fileSize)}
sourceFilePath, err := client.GenerateTestFile(ctx, fileNameAndFileSize)
if err != nil {
s.Fatal("Failed to create temp file: ", err)
}
defer client.RemoveFile(cleanupCtx, &power.TestFileRequest{Path: sourceFilePath.Path})
// Again plug USB storage device and check for its detection.
// If detected tranfer file from DUT to USB device and vice-versa.
if err := cswitch.ToggleCSwitchPort(ctx, sessionID, cswitchVar, domainIP); err != nil {
s.Fatal("Failed to enable c-switch port: ", err)
}
var dirsAfterPlug *power.MountPathResponse
// Waits for USB pendrive detection till timeout.
if err := testing.Poll(ctx, func(ctx context.Context) error {
dirsAfterPlug, err = client.USBMountPaths(ctx, &empty.Empty{})
if err != nil {
return errors.Wrap(err, "failed to get removable devices")
}
return nil
}, &testing.PollOptions{Timeout: 10 * time.Second, Interval: 250 * time.Millisecond}); err != nil {
s.Fatal("Timeout waiting for USB pendrive mount path: ", err)
}
devicePath := dirsAfterPlug.MountPaths[0]
// Destination file path.
destinationFilePath := filepath.Join(devicePath, fileName)
defer client.RemoveFile(cleanupCtx, &power.TestFileRequest{Path: destinationFilePath})
localHash, err := client.FileChecksum(ctx, &power.TestFileRequest{Path: sourceFilePath.Path})
if err != nil {
s.Error("Failed to calculate hash of the source file: ", err)
}
// Tranferring file from DUT to USB storage device.
testing.ContextLogf(ctx, "Transferring file from %s to %s", sourceFilePath.Path, destinationFilePath)
transferFiles := &power.TestFileRequest{SourceFilePath: sourceFilePath.Path, DestinationFilePath: destinationFilePath}
if _, err := client.CopyFile(ctx, transferFiles); err != nil {
s.Fatal("Failed to copy file: ", err)
}
destHash, err := client.FileChecksum(ctx, &power.TestFileRequest{Path: destinationFilePath})
if err != nil {
s.Error("Failed to calculate hash of the destination file: ", err)
}
if !bytes.Equal(localHash.FileChecksumValue, destHash.FileChecksumValue) {
s.Errorf("Failed: The hash doesn't match: got %v, want %v", localHash.FileChecksumValue, destHash.FileChecksumValue)
}
// Tranferring file from USB storage device to DUT.
testing.ContextLogf(ctx, "Transferring file from %s to %s", destinationFilePath, sourceFilePath.Path)
transferFiles = &power.TestFileRequest{SourceFilePath: destinationFilePath, DestinationFilePath: sourceFilePath.Path}
if _, err := client.CopyFile(ctx, transferFiles); err != nil {
s.Fatal("Failed to copy file: ", err)
}
// Check for USB storage device detection after transferring file.
if err := validateUSBStorageDetection(ctx, dut, testParam.usbSpeed); err != nil {
s.Fatal("Failed to detect USB storage device after transferring file: ", err)
}
}
// validateUSBStorageDetection checks for connected USB storage detection.
func validateUSBStorageDetection(ctx context.Context, dut *dut.DUT, usbSpeed string) error {
usbDeviceClassName := "Mass Storage"
return testing.Poll(ctx, func(ctx context.Context) error {
usbDevicesList, err := usbutils.ListDevicesInfo(ctx, dut)
if err != nil {
return errors.Wrap(err, "failed to get USB devices list")
}
got := usbutils.NumberOfUSBDevicesConnected(usbDevicesList, usbDeviceClassName, usbSpeed)
if want := 1; got < want {
return errors.Errorf("unexpected number of %q devices connected with %q speed: got %d, want %d",
usbDeviceClassName, usbSpeed, got, want)
}
return nil
}, &testing.PollOptions{Timeout: 40 * time.Second})
}