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:
SubscriptionManagerTest()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
SetUp()49 void SetUp() override {
50 lastUnsubscribedProperty = -1;
51 }
52
53 hidl_vec<SubscribeOptions> subscrToProp1 = {
54 SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::EVENTS_FROM_CAR},
55 };
56
57 hidl_vec<SubscribeOptions> subscrToProp2 = {
58 SubscribeOptions{.propId = PROP2, .flags = SubscribeFlags::EVENTS_FROM_CAR},
59 };
60
61 hidl_vec<SubscribeOptions> subscrToProp1and2 = {
62 SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::EVENTS_FROM_CAR},
63 SubscribeOptions{.propId = PROP2, .flags = SubscribeFlags::EVENTS_FROM_CAR},
64 };
65
extractCallbacks(const std::list<sp<HalClient>> & clients)66 static std::list<sp<IVehicleCallback>> extractCallbacks(
67 const std::list<sp<HalClient>>& clients) {
68 std::list<sp<IVehicleCallback>> callbacks;
69 for (const auto& c : clients) {
70 callbacks.push_back(c->getCallback());
71 }
72 return callbacks;
73 }
74
clientsToProp1()75 std::list<sp<HalClient>> clientsToProp1() {
76 return manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR);
77 }
78
clientsToProp2()79 std::list<sp<HalClient>> clientsToProp2() {
80 return manager.getSubscribedClients(PROP2, SubscribeFlags::EVENTS_FROM_CAR);
81 }
82
onPropertyUnsubscribed(int propertyId)83 void onPropertyUnsubscribed(int propertyId) {
84 // Called when there are no clients who subscribed to particular property. This can happen
85 // because of explict unsubscribe call or when client (IVehicleCallback) was disconnected.
86 lastUnsubscribedProperty = propertyId;
87 }
88
assertOnPropertyUnsubscribedNotCalled()89 void assertOnPropertyUnsubscribedNotCalled() {
90 ASSERT_EQ(-1, lastUnsubscribedProperty);
91 }
92
assertLastUnsubscribedProperty(int expectedPropertyId)93 void assertLastUnsubscribedProperty(int expectedPropertyId) {
94 ASSERT_EQ(expectedPropertyId, lastUnsubscribedProperty);
95 lastUnsubscribedProperty = -1;
96 }
97
98 private:
99 int lastUnsubscribedProperty;
100 };
101
102
TEST_F(SubscriptionManagerTest,multipleClients)103 TEST_F(SubscriptionManagerTest, multipleClients) {
104 std::list<SubscribeOptions> updatedOptions;
105 ASSERT_EQ(StatusCode::OK,
106 manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions));
107 ASSERT_EQ(StatusCode::OK,
108 manager.addOrUpdateSubscription(2, cb2, subscrToProp1, &updatedOptions));
109
110 auto clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR);
111
112 ASSERT_ALL_EXISTS({cb1, cb2}, extractCallbacks(clients));
113 }
114
TEST_F(SubscriptionManagerTest,negativeCases)115 TEST_F(SubscriptionManagerTest, negativeCases) {
116 std::list<SubscribeOptions> updatedOptions;
117 ASSERT_EQ(StatusCode::OK,
118 manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions));
119
120 // Wrong prop
121 auto clients = manager.getSubscribedClients(toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
122 SubscribeFlags::EVENTS_FROM_CAR);
123 ASSERT_TRUE(clients.empty());
124
125 // Wrong flag
126 clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_ANDROID);
127 ASSERT_TRUE(clients.empty());
128 }
129
TEST_F(SubscriptionManagerTest,mulipleSubscriptions)130 TEST_F(SubscriptionManagerTest, mulipleSubscriptions) {
131 std::list<SubscribeOptions> updatedOptions;
132 ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(1, cb1, subscrToProp1,
133 &updatedOptions));
134
135 auto clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR);
136 ASSERT_EQ((size_t) 1, clients.size());
137 ASSERT_EQ(cb1, clients.front()->getCallback());
138
139 // Same property, but different zone, to make sure we didn't unsubscribe
140 // from previous zone.
141 ASSERT_EQ(
142 StatusCode::OK,
143 manager.addOrUpdateSubscription(
144 1, cb1, {SubscribeOptions{.propId = PROP1, .flags = SubscribeFlags::EVENTS_FROM_CAR}},
145 &updatedOptions));
146
147 clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR);
148 ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
149
150 clients = manager.getSubscribedClients(PROP1, SubscribeFlags::EVENTS_FROM_CAR);
151 ASSERT_ALL_EXISTS({cb1}, extractCallbacks(clients));
152 }
153
TEST_F(SubscriptionManagerTest,unsubscribe)154 TEST_F(SubscriptionManagerTest, unsubscribe) {
155 std::list<SubscribeOptions> updatedOptions;
156 ASSERT_EQ(StatusCode::OK,
157 manager.addOrUpdateSubscription(1, cb1, subscrToProp1, &updatedOptions));
158 ASSERT_EQ(StatusCode::OK,
159 manager.addOrUpdateSubscription(2, cb2, subscrToProp2, &updatedOptions));
160 ASSERT_EQ(StatusCode::OK,
161 manager.addOrUpdateSubscription(3, cb3, subscrToProp1and2, &updatedOptions));
162
163 ASSERT_ALL_EXISTS({ cb1, cb3 }, extractCallbacks(clientsToProp1()));
164 ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
165
166 manager.unsubscribe(1, PROP1);
167 assertOnPropertyUnsubscribedNotCalled();
168 ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1()));
169
170 // Make sure nothing changed in PROP2 so far.
171 ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
172
173 // No one subscribed to PROP1, subscription for PROP2 is not affected.
174 manager.unsubscribe(3, PROP1);
175 assertLastUnsubscribedProperty(PROP1);
176 ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
177
178 manager.unsubscribe(3, PROP2);
179 assertOnPropertyUnsubscribedNotCalled();
180 ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2()));
181
182 // The last client unsubscribed from this property.
183 manager.unsubscribe(2, PROP2);
184 assertLastUnsubscribedProperty(PROP2);
185
186 // No one subscribed anymore
187 manager.unsubscribe(1, PROP1);
188 assertLastUnsubscribedProperty(PROP1);
189 }
190
191 } // namespace anonymous
192
193 } // namespace V2_0
194 } // namespace vehicle
195 } // namespace automotive
196 } // namespace hardware
197 } // namespace android
198