blob: c066bff6b45c866c73bf2ca46a1390291be100c3 [file] [log] [blame]
// Copyright 2020 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.
#include "typecd/port.h"
#include <string>
#include <base/files/scoped_temp_dir.h>
#include <base/strings/stringprintf.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "typecd/test_constants.h"
#include "typecd/test_utils.h"
namespace {
constexpr char kInvalidDataRole1[] = "xsadft [hasdr]";
constexpr char kInvalidDataRole2[] = "]asdf[ dsdd";
constexpr char kValidDataRole1[] = "device";
constexpr char kValidDataRole2[] = "[host] device";
constexpr char kValidDataRole3[] = "host [device]";
} // namespace
namespace typecd {
class PortTest : public ::testing::Test {
protected:
void SetUp() override {
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
temp_dir_ = scoped_temp_dir_.GetPath();
}
public:
base::FilePath temp_dir_;
base::ScopedTempDir scoped_temp_dir_;
};
// Check that basic Port creation, partner addition/deletion works.
TEST_F(PortTest, TestBasicAdd) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
EXPECT_NE(nullptr, port);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
EXPECT_NE(nullptr, port->partner_);
port->RemovePartner();
EXPECT_EQ(nullptr, port->partner_);
}
// Check GetDataRole() for various sysfs values.
TEST_F(PortTest, TestGetDataRole) {
// Set up fake sysfs directory for the port..
auto port_path = temp_dir_.Append("port0");
ASSERT_TRUE(base::CreateDirectory(port_path));
auto data_role_path = port_path.Append("data_role");
ASSERT_TRUE(base::WriteFile(data_role_path, kValidDataRole1,
strlen(kValidDataRole1)));
// Create a port.
auto port = std::make_unique<Port>(base::FilePath(port_path), 0);
ASSERT_NE(nullptr, port);
EXPECT_EQ("device", port->GetDataRole());
ASSERT_TRUE(base::WriteFile(data_role_path, kValidDataRole2,
strlen(kValidDataRole2)));
EXPECT_EQ("host", port->GetDataRole());
ASSERT_TRUE(base::WriteFile(port_path.Append("data_role"), kValidDataRole3,
strlen(kValidDataRole3)));
EXPECT_EQ("device", port->GetDataRole());
ASSERT_TRUE(base::WriteFile(port_path.Append("data_role"), kInvalidDataRole1,
strlen(kInvalidDataRole1)));
EXPECT_EQ("", port->GetDataRole());
ASSERT_TRUE(base::WriteFile(port_path.Append("data_role"), kInvalidDataRole2,
strlen(kInvalidDataRole2)));
EXPECT_EQ("", port->GetDataRole());
}
// Check that DP Alt Mode Entry checks work as expected for a true case:
TEST_F(PortTest, TestDPAltModeEntryCheckTrue) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// Set up fake sysfs paths for 1 alt mode.
// Set the number of alt modes supported.
port->partner_->SetNumAltModes(1);
// Add the DP alt mode.
std::string mode0_dirname =
base::StringPrintf("port%d-partner.%d", 0, kDPAltModeIndex);
auto mode0_path = temp_dir_.Append(mode0_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode0_path, kDPSVID, kDPVDO_WD19TB,
kDPVDOIndex_WD19TB));
port->AddRemovePartnerAltMode(mode0_path, true);
EXPECT_TRUE(port->CanEnterDPAltMode());
}
// Check that DP Alt Mode Entry checks work as expected for a specific false
// case: The Startech dock DP VDO doesn't advertise DFP_D, so we *shouldn't*
// enter DP alternate mode, despite it supporting the DP SID.
TEST_F(PortTest, TestDPAltModeEntryCheckFalseWithDPSID) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// Set up fake sysfs paths for 2 alt modes.
// Set the number of alt modes supported.
port->partner_->SetNumAltModes(2);
// Add the DP alt mode.
std::string mode0_dirname =
base::StringPrintf("port%d-partner.%d", 0, kDPAltModeIndex);
auto mode0_path = temp_dir_.Append(mode0_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode0_path, kDPSVID, kDPVDO, kDPVDOIndex));
port->AddRemovePartnerAltMode(mode0_path, true);
// Add the TBT alt mode.
std::string mode1_dirname =
base::StringPrintf("port%d-partner.%d", 0, kTBTAltModeIndex);
auto mode1_path = temp_dir_.Append(mode1_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode1_path, kTBTSVID, kTBTVDO, kTBTVDOIndex));
port->AddRemovePartnerAltMode(mode1_path, true);
EXPECT_FALSE(port->CanEnterDPAltMode());
}
// Check that DP Alt Mode Entry checks work as expected for false cases.
TEST_F(PortTest, TestDPAltModeEntryCheckFalse) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
port->partner_->SetNumAltModes(0);
// Check the case where the partner doesn't support any alt modes.
EXPECT_FALSE(port->CanEnterDPAltMode());
port->partner_->SetNumAltModes(1);
// Set up fake sysfs paths for 1 alt mode.
// Add the TBT alt mode.
std::string mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, kTBTVDO, kTBTVDOIndex));
port->AddRemovePartnerAltMode(mode_path, true);
EXPECT_FALSE(port->CanEnterDPAltMode());
}
// Check that TBT Compat Mode Entry checks work as expected for the following
// working case:
// - Startech.com TB3DK2DPW Alpine Ridge Dock.
// - StarTech Passive Cable 40 Gbps PD 2.0
TEST_F(PortTest, TestTBTCompatibilityModeEntryCheckTrueStartech) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// PD ID VDOs for the Startech.com TB3DK2DPW Alpine Ridge Dock.
port->partner_->SetPDRevision(kPDRevision20);
port->partner_->SetIdHeaderVDO(0xd4008087);
port->partner_->SetCertStatVDO(0x0);
port->partner_->SetProductVDO(0x0);
port->partner_->SetProductTypeVDO1(0);
port->partner_->SetProductTypeVDO2(0);
port->partner_->SetProductTypeVDO3(0);
port->partner_->SetNumAltModes(1);
// Set up fake sysfs paths for 1 alt mode.
// Add the TBT alt mode.
std::string mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, kTBTVDO, 0));
port->AddRemovePartnerAltMode(mode_path, true);
// Set up fake sysfs paths and add a cable.
port->AddCable(base::FilePath(kFakePort0CableSysPath));
// StarTech Passive Cable 40 Gbps PD 2.0
port->cable_->SetPDRevision(kPDRevision20);
port->cable_->SetIdHeaderVDO(0x1c0020c2);
port->cable_->SetCertStatVDO(0x000000b6);
port->cable_->SetProductVDO(0x00010310);
port->cable_->SetProductTypeVDO1(0x11082052);
port->cable_->SetProductTypeVDO2(0x0);
port->cable_->SetProductTypeVDO3(0x0);
EXPECT_TRUE(port->CanEnterTBTCompatibilityMode());
}
// Check that TBT Compat Mode Entry checks work as expected for the following
// non-working case:
// - Startech.com TB3DK2DPW Alpine Ridge Dock.
// - Nekteck USB 2.0 cable (5A).
TEST_F(PortTest, TestTBTCompatibilityModeEntryCheckFalseStartech) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// PD ID VDOs for the Startech.com TB3DK2DPW Alpine Ridge Dock.
port->partner_->SetPDRevision(kPDRevision20);
port->partner_->SetIdHeaderVDO(0xd4008087);
port->partner_->SetCertStatVDO(0x0);
port->partner_->SetProductVDO(0x0);
port->partner_->SetProductTypeVDO1(0);
port->partner_->SetProductTypeVDO2(0);
port->partner_->SetProductTypeVDO3(0);
port->partner_->SetNumAltModes(1);
// Set up fake sysfs paths for 1 alt mode.
// Add the TBT alt mode.
std::string mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, kTBTVDO, 0));
port->AddRemovePartnerAltMode(mode_path, true);
// Set up fake sysfs paths and add a cable.
port->AddCable(base::FilePath(kFakePort0CableSysPath));
// Nekteck USB 2.0 cable (5A).
port->cable_->SetPDRevision(kPDRevision30);
port->cable_->SetIdHeaderVDO(0x18002e98);
port->cable_->SetCertStatVDO(0x00001533);
port->cable_->SetProductVDO(0x00010200);
port->cable_->SetProductTypeVDO1(0xc1082040);
port->cable_->SetProductTypeVDO2(0x0);
port->cable_->SetProductTypeVDO3(0x0);
EXPECT_FALSE(port->CanEnterTBTCompatibilityMode());
}
// Check that TBT Compat Mode Entry checks work as expected for the following
// working case:
// - Dell WD19TB dock.
TEST_F(PortTest, TestTBTCompatibilityModeEntryCheckTrueWD19TB) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// PD ID VDOs for the Dell WD19TB Titan Ridge Dock.
port->partner_->SetPDRevision(kPDRevision30);
port->partner_->SetIdHeaderVDO(0x4c0041c3);
port->partner_->SetCertStatVDO(0x0);
port->partner_->SetProductVDO(0xb0700712);
port->partner_->SetProductTypeVDO1(0x0);
port->partner_->SetProductTypeVDO2(0x0);
port->partner_->SetProductTypeVDO3(0x0);
port->partner_->SetNumAltModes(4);
// Set up fake sysfs paths for partner alt modes.
// Add the TBT alt mode.
std::string mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, kTBTVDO, kTBTVDOIndex));
port->AddRemovePartnerAltMode(mode_path, true);
// Add the DP alt mode.
mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 1);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kDPSVID, kDPVDO_WD19TB, 0));
port->AddRemovePartnerAltMode(mode_path, true);
// Add the Dell alt mode 1.
mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 2);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(
CreateFakeAltMode(mode_path, kDellSVID_WD19TB, kDell_WD19TB_VDO1, 0));
port->AddRemovePartnerAltMode(mode_path, true);
// Add the Dell alt mode 2.
mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 3);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(
CreateFakeAltMode(mode_path, kDellSVID_WD19TB, kDell_WD19TB_VDO2, 1));
port->AddRemovePartnerAltMode(mode_path, true);
// Set up fake sysfs paths and add a cable.
port->AddCable(base::FilePath(kFakePort0CableSysPath));
// Dell's cable is captive.
port->cable_->SetPDRevision(kPDRevision30);
port->cable_->SetIdHeaderVDO(0x1c00413c);
port->cable_->SetCertStatVDO(0x0);
port->cable_->SetProductVDO(0xb052000);
port->cable_->SetProductTypeVDO1(0x110c2042);
port->cable_->SetProductTypeVDO2(0x0);
port->cable_->SetProductTypeVDO3(0x0);
EXPECT_TRUE(port->CanEnterTBTCompatibilityMode());
}
// Check that USB4 mode checks work as expected for the following
// working case:
// - Intel Gatkex Creek USB4 dock.
// - Belkin TBT3 Passive Cable 40Gbps.
TEST_F(PortTest, TestUSB4EntryTrueGatkexPassiveTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// PD ID VDOs for the Gatkex creek USB4 dock..
port->partner_->SetPDRevision(kPDRevision30);
port->partner_->SetIdHeaderVDO(0x4c800000);
port->partner_->SetCertStatVDO(0x0);
port->partner_->SetProductVDO(0x0);
port->partner_->SetProductTypeVDO1(0xd00001b);
port->partner_->SetProductTypeVDO2(0x0);
port->partner_->SetProductTypeVDO3(0x0);
port->partner_->SetNumAltModes(2);
// Set up fake sysfs paths for partner alt modes.
// Add the DP alt mode.
auto mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kDPSVID, kDPVDO_GatkexCreek,
kDPVDOIndex_GatkexCreek));
port->AddRemovePartnerAltMode(mode_path, true);
// Add the TBT alt mode.
mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 1);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, kTBTVDO_GatkexCreek,
kTBTVDOIndex_GatkexCreek));
port->AddRemovePartnerAltMode(mode_path, true);
// Set up fake sysfs paths and add a cable.
port->AddCable(base::FilePath(kFakePort0CableSysPath));
port->cable_->SetPDRevision(kPDRevision30);
port->cable_->SetIdHeaderVDO(0x1c002b1d);
port->cable_->SetCertStatVDO(0x0);
port->cable_->SetProductVDO(0x150c0001);
port->cable_->SetProductTypeVDO1(0x11082042);
port->cable_->SetProductTypeVDO2(0x0);
port->cable_->SetProductTypeVDO3(0x0);
port->cable_->SetNumAltModes(1);
// Set up fake sysfs paths for cable alt modes.
mode_dirname = base::StringPrintf("port%d-plug0.%d", 0, 0);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, 0x30001, 0));
port->AddCableAltMode(mode_path);
EXPECT_TRUE(port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// working case:
// - Intel Gatkex Creek USB4 dock.
// - Hongju Full USB 3.1 Gen 1 5A passive cable..
TEST_F(PortTest, TestUSB4EntryTrueGatkexPassiveNonTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// PD ID VDOs for the Gatkex creek USB4 dock..
port->partner_->SetPDRevision(kPDRevision30);
port->partner_->SetIdHeaderVDO(0x4c800000);
port->partner_->SetCertStatVDO(0x0);
port->partner_->SetProductVDO(0x0);
port->partner_->SetProductTypeVDO1(0xd00001b);
port->partner_->SetProductTypeVDO2(0x0);
port->partner_->SetProductTypeVDO3(0x0);
port->partner_->SetNumAltModes(2);
// Set up fake sysfs paths for partner alt modes.
// Add the DP alt mode.
auto mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kDPSVID, kDPVDO_GatkexCreek,
kDPVDOIndex_GatkexCreek));
port->AddRemovePartnerAltMode(mode_path, true);
// Add the TBT alt mode.
mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 1);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, kTBTVDO_GatkexCreek,
kTBTVDOIndex_GatkexCreek));
port->AddRemovePartnerAltMode(mode_path, true);
// Set up fake sysfs paths and add a cable.
port->AddCable(base::FilePath(kFakePort0CableSysPath));
port->cable_->SetPDRevision(kPDRevision20);
port->cable_->SetIdHeaderVDO(0x18005694);
port->cable_->SetCertStatVDO(0x88);
port->cable_->SetProductVDO(0xce901a0);
port->cable_->SetProductTypeVDO1(0x84051);
port->cable_->SetProductTypeVDO2(0x0);
port->cable_->SetProductTypeVDO3(0x0);
port->cable_->SetNumAltModes(0);
EXPECT_TRUE(port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// non-working case:
// - Intel Gatkex Creek USB4 dock.
// - Nekteck USB 2.0 5A Passive Cable.
TEST_F(PortTest, TestUSB4EntryFalseGatkexPassiveNonTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// PD ID VDOs for the Gatkex creek USB4 dock..
port->partner_->SetPDRevision(kPDRevision30);
port->partner_->SetIdHeaderVDO(0x4c800000);
port->partner_->SetCertStatVDO(0x0);
port->partner_->SetProductVDO(0x0);
port->partner_->SetProductTypeVDO1(0xd00001b);
port->partner_->SetProductTypeVDO2(0x0);
port->partner_->SetProductTypeVDO3(0x0);
port->partner_->SetNumAltModes(2);
// Set up fake sysfs paths for partner alt modes.
// Add the DP alt mode.
auto mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kDPSVID, kDPVDO_GatkexCreek,
kDPVDOIndex_GatkexCreek));
port->AddRemovePartnerAltMode(mode_path, true);
// Add the TBT alt mode.
mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 1);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, kTBTVDO_GatkexCreek,
kTBTVDOIndex_GatkexCreek));
port->AddRemovePartnerAltMode(mode_path, true);
// Set up fake sysfs paths and add a cable.
port->AddCable(base::FilePath(kFakePort0CableSysPath));
port->cable_->SetPDRevision(kPDRevision30);
port->cable_->SetIdHeaderVDO(0x18002e98);
port->cable_->SetCertStatVDO(0x1533);
port->cable_->SetProductVDO(0x10200);
port->cable_->SetProductTypeVDO1(0xc1082040);
port->cable_->SetProductTypeVDO2(0x0);
port->cable_->SetProductTypeVDO3(0x0);
port->cable_->SetNumAltModes(0);
EXPECT_FALSE(port->CanEnterUSB4());
}
// Check that USB4 mode checks work as expected for the following
// non-working case:
// - Intel Gatkex Creek USB4 dock.
// - Belkin TBT3 Active Cable 40Gbps.
//
// NOTE: This case is interesting because the TBT3 cable fails as it doesn't
// support Rounded Data rates.
TEST_F(PortTest, TestUSB4EntryFalseGatkexActiveTBT3Cable) {
auto port = std::make_unique<Port>(base::FilePath(kFakePort0SysPath), 0);
port->AddPartner(base::FilePath(kFakePort0PartnerSysPath));
// PD ID VDOs for the Gatkex creek USB4 dock..
port->partner_->SetPDRevision(kPDRevision30);
port->partner_->SetIdHeaderVDO(0x4c800000);
port->partner_->SetCertStatVDO(0x0);
port->partner_->SetProductVDO(0x0);
port->partner_->SetProductTypeVDO1(0xd00001b);
port->partner_->SetProductTypeVDO2(0x0);
port->partner_->SetProductTypeVDO3(0x0);
port->partner_->SetNumAltModes(2);
// Set up fake sysfs paths for partner alt modes.
// Add the DP alt mode.
auto mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 0);
auto mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kDPSVID, kDPVDO_GatkexCreek,
kDPVDOIndex_GatkexCreek));
port->AddRemovePartnerAltMode(mode_path, true);
// Add the TBT alt mode.
mode_dirname = base::StringPrintf("port%d-partner.%d", 0, 1);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, kTBTVDO_GatkexCreek,
kTBTVDOIndex_GatkexCreek));
port->AddRemovePartnerAltMode(mode_path, true);
// Set up fake sysfs paths and add a cable.
port->AddCable(base::FilePath(kFakePort0CableSysPath));
port->cable_->SetPDRevision(kPDRevision20);
port->cable_->SetIdHeaderVDO(0x240020c2);
port->cable_->SetCertStatVDO(0x0);
port->cable_->SetProductVDO(0x40010);
port->cable_->SetProductTypeVDO1(0x21085858);
port->cable_->SetProductTypeVDO2(0x0);
port->cable_->SetProductTypeVDO3(0x0);
port->cable_->SetNumAltModes(2);
// Set up fake sysfs paths for cable alt modes.
mode_dirname = base::StringPrintf("port%d-plug0.%d", 0, 0);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, kTBTSVID, 0x430001, 0));
port->AddCableAltMode(mode_path);
mode_dirname = base::StringPrintf("port%d-plug0.%d", 0, 1);
mode_path = temp_dir_.Append(mode_dirname);
ASSERT_TRUE(CreateFakeAltMode(mode_path, 0x04b4, 0x1, 0));
port->AddCableAltMode(mode_path);
EXPECT_FALSE(port->CanEnterUSB4());
}
} // namespace typecd