/* * Copyright (C) 2016 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 <functional> #include <iostream> #include <unordered_map> #include <gtest/gtest.h> #include "vhal_v2_0/SubscriptionManager.h" #include "VehicleHalTestUtils.h" namespace android { namespace hardware { namespace automotive { namespace vehicle { namespace V2_0 { namespace { using namespace std::placeholders; class SubscriptionManagerTest : public ::testing::Test { public: SubscriptionManagerTest() : manager(([this](int x) { onPropertyUnsubscribed(x); })) {} SubscriptionManager manager; static constexpr int32_t PROP1 = toInt(VehicleProperty::HVAC_FAN_SPEED); static constexpr int32_t PROP2 = toInt(VehicleProperty::DISPLAY_BRIGHTNESS); sp<IVehicleCallback> cb1 = new MockedVehicleCallback(); sp<IVehicleCallback> cb2 = new MockedVehicleCallback(); sp<IVehicleCallback> cb3 = new MockedVehicleCallback(); void SetUp() override { lastUnsubscribedProperty = -1; } hidl_vec<SubscribeOptions> subscrToProp1 = { SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::EVENTS_FROM_CAR}, }; hidl_vec<SubscribeOptions> subscrToProp2 = { SubscribeOptions{.propId = PROP2, .flags = SubscribeFlags::EVENTS_FROM_CAR}, }; hidl_vec<SubscribeOptions> subscrToProp1and2 = { SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::EVENTS_FROM_CAR}, SubscribeOptions{.propId = PROP2, .flags = SubscribeFlags::EVENTS_FROM_CAR}, }; static std::list<sp<IVehicleCallback>> extractCallbacks( const std::list<sp<HalClient>>& clients) { std::list<sp<IVehicleCallback>> callbacks; for (const auto& c : clients) { callbacks.push_back(c->getCallback()); } return callbacks; } std::list<sp<HalClient>> clientsToProp1() { return manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR); } std::list<sp<HalClient>> clientsToProp2() { return manager.getSubscribedClients(PROP2, SubscribeFlags::EVENTS_FROM_CAR); } void onPropertyUnsubscribed(int propertyId) { // Called when there are no clients who subscribed to particular property. This can happen // because of explict unsubscribe call or when client (IVehicleCallback) was disconnected. lastUnsubscribedProperty = propertyId; } void assertOnPropertyUnsubscribedNotCalled() { ASSERT_EQ(-1, lastUnsubscribedProperty); } void assertLastUnsubscribedProperty(int expectedPropertyId) { ASSERT_EQ(expectedPropertyId, lastUnsubscribedProperty); lastUnsubscribedProperty = -1; } private: int lastUnsubscribedProperty; }; TEST_F(SubscriptionManagerTest, multipleClients) { std::list<SubscribeOptions> updatedOptions; ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions)); ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(2, cb2, subscrToProp1, &updatedOptions)); auto clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR); ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients)); } TEST_F(SubscriptionManagerTest, negativeCases) { std::list<SubscribeOptions> updatedOptions; ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions)); // Wrong prop auto clients = manager.getSubscribedClients(toInt(VehicleProperty::AP_POWER_BOOTUP_REASON), SubscribeFlags::EVENTS_FROM_CAR); ASSERT_TRUE(clients.empty()); // Wrong flag clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_ANDROID); ASSERT_TRUE(clients.empty()); } TEST_F(SubscriptionManagerTest, mulipleSubscriptions) { std::list<SubscribeOptions> updatedOptions; ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions)); auto clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR); ASSERT_EQ((size_t) 1, clients.size()); ASSERT_EQ(cb1, clients.front()->getCallback()); // Same property, but different zone, to make sure we didn't unsubscribe // from previous zone. ASSERT_EQ( StatusCode::OK, manager.addOrUpdateSubscription( 1, cb1, {SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::EVENTS_FROM_CAR}}, &updatedOptions)); clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR); ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients)); clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR); ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients)); } TEST_F(SubscriptionManagerTest, unsubscribe) { std::list<SubscribeOptions> updatedOptions; ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions)); ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(2, cb2, subscrToProp2, &updatedOptions)); ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(3, cb3, subscrToProp1and2, &updatedOptions)); ASSERT_ALL_EXISTS({ cb1, cb3 }, extractCallbacks(clientsToProp1())); ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); manager.unsubscribe(1, PROP1); assertOnPropertyUnsubscribedNotCalled(); ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1())); // Make sure nothing changed in PROP2 so far. ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); // No one subscribed to PROP1, subscription for PROP2 is not affected. manager.unsubscribe(3, PROP1); assertLastUnsubscribedProperty(PROP1); ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); manager.unsubscribe(3, PROP2); assertOnPropertyUnsubscribedNotCalled(); ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2())); // The last client unsubscribed from this property. manager.unsubscribe(2, PROP2); assertLastUnsubscribedProperty(PROP2); // No one subscribed anymore manager.unsubscribe(1, PROP1); assertLastUnsubscribedProperty(PROP1); } } // namespace anonymous } // namespace V2_0 } // namespace vehicle } // namespace automotive } // namespace hardware } // namespace android