1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <functional> 18 #include <iostream> 19 #include <unordered_map> 20 21 #include <gtest/gtest.h> 22 23 #include "vhal_v2_0/SubscriptionManager.h" 24 25 #include "VehicleHalTestUtils.h" 26 27 namespace android { 28 namespace hardware { 29 namespace automotive { 30 namespace vehicle { 31 namespace V2_0 { 32 33 namespace { 34 35 using namespace std::placeholders; 36 37 class SubscriptionManagerTest : public ::testing::Test { 38 public: 39 SubscriptionManagerTest() : manager(([this](int x) { onPropertyUnsubscribed(x); })) {} 40 41 SubscriptionManager manager; 42 static constexpr int32_t PROP1 = toInt(VehicleProperty::HVAC_FAN_SPEED); 43 static constexpr int32_t PROP2 = toInt(VehicleProperty::DISPLAY_BRIGHTNESS); 44 45 sp<IVehicleCallback> cb1 = new MockedVehicleCallback(); 46 sp<IVehicleCallback> cb2 = new MockedVehicleCallback(); 47 sp<IVehicleCallback> cb3 = new MockedVehicleCallback(); 48 49 void SetUp() override { 50 lastUnsubscribedProperty = -1; 51 } 52 53 hidl_vec<SubscribeOptions> subscrToProp1 = { 54 SubscribeOptions { 55 .propId = PROP1, 56 .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT), 57 .flags = SubscribeFlags::HAL_EVENT 58 }, 59 }; 60 61 hidl_vec<SubscribeOptions> subscrToProp2 = { 62 SubscribeOptions { 63 .propId = PROP2, 64 .flags = SubscribeFlags::HAL_EVENT 65 }, 66 }; 67 68 hidl_vec<SubscribeOptions> subscrToProp1and2 = { 69 SubscribeOptions { 70 .propId = PROP1, 71 .vehicleAreas = toInt(VehicleAreaZone::ROW_1_LEFT), 72 .flags = SubscribeFlags::HAL_EVENT 73 }, 74 SubscribeOptions { 75 .propId = PROP2, 76 .flags = SubscribeFlags::HAL_EVENT 77 }, 78 }; 79 80 static std::list<sp<IVehicleCallback>> extractCallbacks( 81 const std::list<sp<HalClient>>& clients) { 82 std::list<sp<IVehicleCallback>> callbacks; 83 for (auto c : clients) { 84 callbacks.push_back(c->getCallback()); 85 } 86 return callbacks; 87 } 88 89 std::list<sp<HalClient>> clientsToProp1() { 90 return manager.getSubscribedClients(PROP1, 91 toInt(VehicleAreaZone::ROW_1_LEFT), 92 SubscribeFlags::DEFAULT); 93 } 94 95 std::list<sp<HalClient>> clientsToProp2() { 96 return manager.getSubscribedClients(PROP2, 0, 97 SubscribeFlags::DEFAULT); 98 } 99 100 void onPropertyUnsubscribed(int propertyId) { 101 // Called when there are no clients who subscribed to particular property. This can happen 102 // because of explict unsubscribe call or when client (IVehicleCallback) was disconnected. 103 lastUnsubscribedProperty = propertyId; 104 } 105 106 void assertOnPropertyUnsubscribedNotCalled() { 107 ASSERT_EQ(-1, lastUnsubscribedProperty); 108 } 109 110 void assertLastUnsubscribedProperty(int expectedPropertyId) { 111 ASSERT_EQ(expectedPropertyId, lastUnsubscribedProperty); 112 lastUnsubscribedProperty = -1; 113 } 114 115 private: 116 int lastUnsubscribedProperty; 117 }; 118 119 120 TEST_F(SubscriptionManagerTest, multipleClients) { 121 std::list<SubscribeOptions> updatedOptions; 122 ASSERT_EQ(StatusCode::OK, 123 manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions)); 124 ASSERT_EQ(StatusCode::OK, 125 manager.addOrUpdateSubscription(2, cb2, subscrToProp1, &updatedOptions)); 126 127 auto clients = manager.getSubscribedClients( 128 PROP1, 129 toInt(VehicleAreaZone::ROW_1_LEFT), 130 SubscribeFlags::HAL_EVENT); 131 132 ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients)); 133 } 134 135 TEST_F(SubscriptionManagerTest, negativeCases) { 136 std::list<SubscribeOptions> updatedOptions; 137 ASSERT_EQ(StatusCode::OK, 138 manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions)); 139 140 // Wrong zone 141 auto clients = manager.getSubscribedClients( 142 PROP1, 143 toInt(VehicleAreaZone::ROW_2_LEFT), 144 SubscribeFlags::HAL_EVENT); 145 ASSERT_TRUE(clients.empty()); 146 147 // Wrong prop 148 clients = manager.getSubscribedClients( 149 toInt(VehicleProperty::AP_POWER_BOOTUP_REASON), 150 toInt(VehicleAreaZone::ROW_1_LEFT), 151 SubscribeFlags::HAL_EVENT); 152 ASSERT_TRUE(clients.empty()); 153 154 // Wrong flag 155 clients = manager.getSubscribedClients( 156 PROP1, 157 toInt(VehicleAreaZone::ROW_1_LEFT), 158 SubscribeFlags::SET_CALL); 159 ASSERT_TRUE(clients.empty()); 160 } 161 162 TEST_F(SubscriptionManagerTest, mulipleSubscriptions) { 163 std::list<SubscribeOptions> updatedOptions; 164 ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, subscrToProp1, 165 &updatedOptions)); 166 167 auto clients = manager.getSubscribedClients( 168 PROP1, 169 toInt(VehicleAreaZone::ROW_1_LEFT), 170 SubscribeFlags::DEFAULT); 171 ASSERT_EQ((size_t) 1, clients.size()); 172 ASSERT_EQ(cb1, clients.front()->getCallback()); 173 174 // Same property, but different zone, to make sure we didn't unsubscribe 175 // from previous zone. 176 ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, { 177 SubscribeOptions { 178 .propId = PROP1, 179 .vehicleAreas = toInt(VehicleAreaZone::ROW_2), 180 .flags = SubscribeFlags::DEFAULT 181 } 182 }, &updatedOptions)); 183 184 clients = manager.getSubscribedClients(PROP1, 185 toInt(VehicleAreaZone::ROW_1_LEFT), 186 SubscribeFlags::DEFAULT); 187 ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients)); 188 189 clients = manager.getSubscribedClients(PROP1, 190 toInt(VehicleAreaZone::ROW_2), 191 SubscribeFlags::DEFAULT); 192 ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients)); 193 } 194 195 TEST_F(SubscriptionManagerTest, unsubscribe) { 196 std::list<SubscribeOptions> updatedOptions; 197 ASSERT_EQ(StatusCode::OK, 198 manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions)); 199 ASSERT_EQ(StatusCode::OK, 200 manager.addOrUpdateSubscription(2, cb2, subscrToProp2, &updatedOptions)); 201 ASSERT_EQ(StatusCode::OK, 202 manager.addOrUpdateSubscription(3, cb3, subscrToProp1and2, &updatedOptions)); 203 204 ASSERT_ALL_EXISTS({ cb1, cb3 }, extractCallbacks(clientsToProp1())); 205 ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); 206 207 manager.unsubscribe(1, PROP1); 208 assertOnPropertyUnsubscribedNotCalled(); 209 ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1())); 210 211 // Make sure nothing changed in PROP2 so far. 212 ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); 213 214 // No one subscribed to PROP1, subscription for PROP2 is not affected. 215 manager.unsubscribe(3, PROP1); 216 assertLastUnsubscribedProperty(PROP1); 217 ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2())); 218 219 manager.unsubscribe(3, PROP2); 220 assertOnPropertyUnsubscribedNotCalled(); 221 ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2())); 222 223 // The last client unsubscribed from this property. 224 manager.unsubscribe(2, PROP2); 225 assertLastUnsubscribedProperty(PROP2); 226 227 // No one subscribed anymore 228 manager.unsubscribe(1, PROP1); 229 assertLastUnsubscribedProperty(PROP1); 230 } 231 232 } // namespace anonymous 233 234 } // namespace V2_0 235 } // namespace vehicle 236 } // namespace automotive 237 } // namespace hardware 238 } // namespace android 239