android13/hardware/interfaces/automotive/can/1.0/vts/functional/VtsHalCanControllerV1_0Targ...

353 lines
12 KiB
C++

/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <android/hardware/automotive/can/1.0/ICanBus.h>
#include <android/hardware/automotive/can/1.0/ICanController.h>
#include <android/hardware/automotive/can/1.0/types.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <can-vts-utils/bus-enumerator.h>
#include <can-vts-utils/can-hal-printers.h>
#include <gmock/gmock.h>
#include <hidl-utils/hidl-utils.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
namespace android::hardware::automotive::can::V1_0::vts {
using hardware::hidl_vec;
using InterfaceType = ICanController::InterfaceType;
using IfId = ICanController::BusConfig::InterfaceId;
struct Bus {
DISALLOW_COPY_AND_ASSIGN(Bus);
Bus(sp<ICanController> controller, const ICanController::BusConfig& config)
: mIfname(config.name), mController(controller) {
// Don't bring up the bus, we just need a wrapper for the ICanBus object
/* Not using ICanBus::getService here, since it ignores interfaces not in the manifest
* file -- this is a test, so we don't want to add fake services to a device manifest. */
auto manager = hidl::manager::V1_2::IServiceManager::getService();
auto service = manager->get(ICanBus::descriptor, config.name);
mBus = ICanBus::castFrom(service);
}
ICanBus* operator->() const { return mBus.get(); }
sp<ICanBus> get() { return mBus; }
Return<Result> send(const CanMessage& msg) { return mBus->send(msg); }
private:
const std::string mIfname;
sp<ICanController> mController;
sp<ICanBus> mBus;
};
class CanControllerHalTest : public ::testing::TestWithParam<std::string> {
protected:
virtual void SetUp() override;
virtual void TearDown() override;
static void SetUpTestCase();
Bus makeBus(const std::string ifaceName);
hidl_vec<InterfaceType> getSupportedInterfaceTypes();
bool isSupported(InterfaceType iftype);
bool up(InterfaceType iftype, const std::string srvname, std::string ifname,
ICanController::Result expected);
void assertRegistered(const std::string srvname, const std::string ifaceName,
bool expectRegistered);
sp<ICanController> mCanController;
static hidl_vec<hidl_string> mBusNames;
private:
static bool mTestCaseInitialized;
};
hidl_vec<hidl_string> CanControllerHalTest::mBusNames;
bool CanControllerHalTest::mTestCaseInitialized = false;
void CanControllerHalTest::SetUp() {
ASSERT_TRUE(mTestCaseInitialized);
mCanController = ICanController::getService(GetParam());
ASSERT_TRUE(mCanController) << "Couldn't open CAN Controller: " << GetParam();
}
void CanControllerHalTest::TearDown() {
mCanController.clear();
}
void CanControllerHalTest::SetUpTestCase() {
mBusNames = utils::getBusNames();
ASSERT_NE(0u, mBusNames.size()) << "No ICanBus HALs defined in device manifest";
mTestCaseInitialized = true;
}
hidl_vec<InterfaceType> CanControllerHalTest::getSupportedInterfaceTypes() {
hidl_vec<InterfaceType> iftypesResult;
mCanController->getSupportedInterfaceTypes(hidl_utils::fill(&iftypesResult)).assertOk();
return iftypesResult;
}
bool CanControllerHalTest::isSupported(InterfaceType iftype) {
const auto supported = getSupportedInterfaceTypes();
return std::find(supported.begin(), supported.end(), iftype) != supported.end();
}
bool CanControllerHalTest::up(InterfaceType iftype, std::string srvname, std::string ifname,
ICanController::Result expected) {
ICanController::BusConfig config = {};
config.name = srvname;
// TODO(b/146214370): move interfaceId constructors to a library
if (iftype == InterfaceType::SOCKETCAN) {
IfId::Socketcan socketcan = {};
socketcan.ifname(ifname);
config.interfaceId.socketcan(socketcan);
} else if (iftype == InterfaceType::SLCAN) {
IfId::Slcan slcan = {};
slcan.ttyname(ifname);
config.interfaceId.slcan(slcan);
} else if (iftype == InterfaceType::VIRTUAL) {
config.interfaceId.virtualif({ifname});
} else {
EXPECT_TRUE(false) << "Unexpected iftype: " << toString(iftype);
}
const auto upresult = mCanController->upInterface(config);
if (!isSupported(iftype)) {
LOG(INFO) << iftype << " interfaces not supported";
EXPECT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
return false;
}
EXPECT_EQ(expected, upresult);
return true;
}
void CanControllerHalTest::assertRegistered(const std::string srvname, const std::string ifaceName,
bool expectRegistered) {
/* Not using ICanBus::tryGetService here, since it ignores interfaces not in the manifest
* file -- this is a test, so we don't want to add fake services to a device manifest. */
auto manager = hidl::manager::V1_2::IServiceManager::getService();
auto busService = manager->get(ICanBus::descriptor, srvname);
if (!expectRegistered) {
/* We can't unregister a HIDL interface defined in the manifest, so we'll just check to make
* sure that the interface behind it is down */
auto bus = makeBus(ifaceName);
const auto result = bus->send({});
ASSERT_EQ(Result::INTERFACE_DOWN, result);
return;
}
ASSERT_EQ(expectRegistered, busService.withDefault(nullptr) != nullptr)
<< "ICanBus/" << srvname << (expectRegistered ? " is not " : " is ") << "registered"
<< " (should be otherwise)";
}
Bus CanControllerHalTest::makeBus(const std::string ifaceName) {
ICanController::BusConfig config = {};
config.name = mBusNames[0];
config.interfaceId.virtualif({ifaceName});
return Bus(mCanController, config);
}
TEST_P(CanControllerHalTest, SupportsSomething) {
const auto supported = getSupportedInterfaceTypes();
ASSERT_GT(supported.size(), 0u);
}
TEST_P(CanControllerHalTest, BringUpDown) {
const std::string name = mBusNames[0];
const std::string iface = "vcan57";
mCanController->downInterface(name);
assertRegistered(name, iface, false);
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::OK)) GTEST_SKIP();
assertRegistered(name, iface, true);
const auto dnresult = mCanController->downInterface(name);
ASSERT_TRUE(dnresult);
assertRegistered(name, iface, false);
}
TEST_P(CanControllerHalTest, DownFake) {
const auto result = mCanController->downInterface("imnotup");
ASSERT_FALSE(result);
}
TEST_P(CanControllerHalTest, UpTwice) {
const std::string name = mBusNames[0];
const std::string iface = "vcan72";
assertRegistered(name, iface, false);
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::OK)) GTEST_SKIP();
assertRegistered(name, iface, true);
if (!up(InterfaceType::VIRTUAL, name, "vcan73", ICanController::Result::INVALID_STATE)) {
GTEST_SKIP();
}
assertRegistered(name, iface, true);
const auto result = mCanController->downInterface(name);
ASSERT_TRUE(result);
assertRegistered(name, iface, false);
}
TEST_P(CanControllerHalTest, ConfigCompatibility) {
// using random-ish addresses, which may not be valid - we can't test the success case
// TODO(b/146214370): move interfaceId constructors to a library
IfId virtualCfg = {};
virtualCfg.virtualif({"vcan70"});
IfId::Socketcan socketcanIfname = {};
socketcanIfname.ifname("can0");
IfId socketcanIfnameCfg = {};
socketcanIfnameCfg.socketcan(socketcanIfname);
IfId::Socketcan socketcanSerial = {};
socketcanSerial.serialno({"1234", "2345"});
IfId socketcanSerialCfg = {};
socketcanSerialCfg.socketcan(socketcanSerial);
IfId::Slcan slcanTtyname = {};
slcanTtyname.ttyname("/dev/ttyUSB0");
IfId slcanTtynameCfg = {};
slcanTtynameCfg.slcan(slcanTtyname);
IfId::Slcan slcanSerial = {};
slcanSerial.serialno({"dead", "beef"});
IfId slcanSerialCfg = {};
slcanSerialCfg.slcan(slcanSerial);
IfId indexedCfg = {};
indexedCfg.indexed({0});
static const std::vector<std::pair<InterfaceType, IfId>> compatMatrix = {
{InterfaceType::VIRTUAL, virtualCfg},
{InterfaceType::SOCKETCAN, socketcanIfnameCfg},
{InterfaceType::SOCKETCAN, socketcanSerialCfg},
{InterfaceType::SLCAN, slcanTtynameCfg},
{InterfaceType::SLCAN, slcanSerialCfg},
{InterfaceType::INDEXED, indexedCfg},
};
for (const auto [iftype, cfg] : compatMatrix) {
LOG(INFO) << "Compatibility testing: " << iftype << " / " << cfg;
ICanController::BusConfig config = {};
config.name = "compattestsrv";
config.bitrate = 125000;
config.interfaceId = cfg;
const auto upresult = mCanController->upInterface(config);
if (!isSupported(iftype)) {
ASSERT_EQ(ICanController::Result::NOT_SUPPORTED, upresult);
continue;
}
ASSERT_NE(ICanController::Result::NOT_SUPPORTED, upresult);
if (upresult == ICanController::Result::OK) {
const auto dnresult = mCanController->downInterface(config.name);
ASSERT_TRUE(dnresult);
continue;
}
}
}
TEST_P(CanControllerHalTest, FailEmptyName) {
const std::string name = "";
const std::string iface = "vcan57";
assertRegistered(name, iface, false);
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::BAD_SERVICE_NAME)) {
GTEST_SKIP();
}
assertRegistered(name, iface, false);
}
TEST_P(CanControllerHalTest, FailBadName) {
// 33 characters (name can be at most 32 characters long)
const std::string name = "ab012345678901234567890123456789c";
const std::string iface = "vcan57";
assertRegistered(name, iface, false);
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::BAD_SERVICE_NAME)) {
GTEST_SKIP();
}
assertRegistered(name, iface, false);
}
TEST_P(CanControllerHalTest, FailBadVirtualAddress) {
const std::string name = mBusNames[0];
const std::string iface = "";
assertRegistered(name, iface, false);
if (!up(InterfaceType::VIRTUAL, name, iface, ICanController::Result::BAD_INTERFACE_ID)) {
GTEST_SKIP();
}
assertRegistered(name, iface, false);
}
TEST_P(CanControllerHalTest, FailBadSocketcanAddress) {
const std::string name = mBusNames[0];
const std::string iface = "can87";
assertRegistered(name, iface, false);
if (!up(InterfaceType::SOCKETCAN, name, iface, ICanController::Result::BAD_INTERFACE_ID)) {
GTEST_SKIP();
}
assertRegistered(name, iface, false);
auto supported =
up(InterfaceType::SOCKETCAN, name, "", ICanController::Result::BAD_INTERFACE_ID);
ASSERT_TRUE(supported);
assertRegistered(name, iface, false);
}
TEST_P(CanControllerHalTest, FailBadSlcanAddress) {
const std::string name = mBusNames[0];
const std::string iface = "/dev/shouldnotexist123";
assertRegistered(name, iface, false);
if (!up(InterfaceType::SLCAN, name, iface, ICanController::Result::BAD_INTERFACE_ID)) {
GTEST_SKIP();
}
assertRegistered(name, iface, false);
auto supported = up(InterfaceType::SLCAN, name, "", ICanController::Result::BAD_INTERFACE_ID);
ASSERT_TRUE(supported);
assertRegistered(name, iface, false);
}
/**
* Example manual invocation:
* adb shell /data/nativetest64/VtsHalCanControllerV1_0TargetTest/VtsHalCanControllerV1_0TargetTest
*/
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CanControllerHalTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, CanControllerHalTest,
testing::ValuesIn(getAllHalInstanceNames(ICanController::descriptor)),
PrintInstanceNameToString);
} // namespace android::hardware::automotive::can::V1_0::vts