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