1 // Copyright (C) 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "GRPCVehicleHardware.h"
16 #include "VehicleServer.grpc.pb.h"
17 #include "VehicleServer.pb.h"
18 #include "VehicleServer_mock.grpc.pb.h"
19
20 #include <gmock/gmock.h>
21 #include <grpc++/grpc++.h>
22 #include <gtest/gtest.h>
23
24 #include <chrono>
25 #include <memory>
26 #include <string>
27
28 namespace android::hardware::automotive::vehicle::virtualization {
29
30 namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
31
32 using ::testing::_;
33 using ::testing::DoAll;
34 using ::testing::NiceMock;
35 using ::testing::Return;
36 using ::testing::SaveArg;
37 using ::testing::SetArgPointee;
38
39 using proto::MockVehicleServerStub;
40
41 const std::string kFakeServerAddr = "0.0.0.0:54321";
42
43 class FakeVehicleServer : public proto::VehicleServer::Service {
44 public:
StartPropertyValuesStream(::grpc::ServerContext * context,const::google::protobuf::Empty * request,::grpc::ServerWriter<proto::VehiclePropValues> * stream)45 ::grpc::Status StartPropertyValuesStream(
46 ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
47 ::grpc::ServerWriter<proto::VehiclePropValues>* stream) override {
48 stream->Write(proto::VehiclePropValues());
49 // A fake disconnection.
50 return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
51 }
52
53 // Functions that we do not care.
GetAllPropertyConfig(::grpc::ServerContext * context,const::google::protobuf::Empty * request,::grpc::ServerWriter<proto::VehiclePropConfig> * stream)54 ::grpc::Status GetAllPropertyConfig(
55 ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
56 ::grpc::ServerWriter<proto::VehiclePropConfig>* stream) override {
57 return ::grpc::Status::OK;
58 }
59
SetValues(::grpc::ServerContext * context,const proto::VehiclePropValueRequests * requests,proto::SetValueResults * results)60 ::grpc::Status SetValues(::grpc::ServerContext* context,
61 const proto::VehiclePropValueRequests* requests,
62 proto::SetValueResults* results) override {
63 return ::grpc::Status::OK;
64 }
65
GetValues(::grpc::ServerContext * context,const proto::VehiclePropValueRequests * requests,proto::GetValueResults * results)66 ::grpc::Status GetValues(::grpc::ServerContext* context,
67 const proto::VehiclePropValueRequests* requests,
68 proto::GetValueResults* results) override {
69 return ::grpc::Status::OK;
70 }
71 };
72
TEST(GRPCVehicleHardwareUnitTest,Reconnect)73 TEST(GRPCVehicleHardwareUnitTest, Reconnect) {
74 auto receivedUpdate = std::make_shared<std::atomic<int>>(0);
75 auto vehicleHardware = std::make_unique<GRPCVehicleHardware>(kFakeServerAddr);
76 vehicleHardware->registerOnPropertyChangeEvent(
77 std::make_unique<const IVehicleHardware::PropertyChangeCallback>(
78 [receivedUpdate](const auto&) { receivedUpdate->fetch_add(1); }));
79
80 constexpr size_t kServerRestartTimes = 5;
81 for (size_t serverStart = 0; serverStart < kServerRestartTimes; ++serverStart) {
82 EXPECT_EQ(receivedUpdate->load(), 0);
83 auto fakeServer = std::make_unique<FakeVehicleServer>();
84 ::grpc::ServerBuilder builder;
85 builder.RegisterService(fakeServer.get());
86 builder.AddListeningPort(kFakeServerAddr, ::grpc::InsecureServerCredentials());
87 auto grpcServer = builder.BuildAndStart();
88
89 // Wait until the vehicle hardware received the second update (after one fake
90 // disconnection).
91 constexpr auto kMaxWaitTime = std::chrono::seconds(5);
92 auto startTime = std::chrono::steady_clock::now();
93 while (receivedUpdate->load() <= 1 &&
94 std::chrono::steady_clock::now() - startTime < kMaxWaitTime)
95 ;
96
97 grpcServer->Shutdown();
98 grpcServer->Wait();
99 EXPECT_GT(receivedUpdate->load(), 1);
100
101 // Reset for the next round.
102 receivedUpdate->store(0);
103 }
104 }
105
106 class GRPCVehicleHardwareMockServerUnitTest : public ::testing::Test {
107 protected:
108 NiceMock<MockVehicleServerStub>* mGrpcStub;
109 std::unique_ptr<GRPCVehicleHardware> mHardware;
110
SetUp()111 void SetUp() override {
112 auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
113 ;
114 mGrpcStub = stub.get();
115 mHardware = std::make_unique<GRPCVehicleHardware>(std::move(stub));
116 }
117
TearDown()118 void TearDown() override { mHardware.reset(); }
119 };
120
121 MATCHER_P(RepeatedInt32Eq, expected_values, "") {
122 return std::vector<int32_t>(arg.begin(), arg.end()) == expected_values;
123 }
124
TEST_F(GRPCVehicleHardwareMockServerUnitTest,Subscribe)125 TEST_F(GRPCVehicleHardwareMockServerUnitTest, Subscribe) {
126 proto::VehicleHalCallStatus protoStatus;
127 protoStatus.set_status_code(proto::StatusCode::OK);
128 proto::SubscribeRequest actualRequest;
129
130 EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
131 .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
132 Return(::grpc::Status::OK)));
133
134 aidlvhal::SubscribeOptions options = {.propId = 1,
135 .areaIds = {1, 2, 3, 4},
136 .sampleRate = 1.234,
137 .resolution = 0.01,
138 .enableVariableUpdateRate = true};
139 auto status = mHardware->subscribe(options);
140
141 EXPECT_EQ(status, aidlvhal::StatusCode::OK);
142 const auto& protoOptions = actualRequest.options();
143 EXPECT_EQ(protoOptions.prop_id(), 1);
144 EXPECT_THAT(protoOptions.area_ids(), RepeatedInt32Eq(std::vector<int32_t>({1, 2, 3, 4})));
145 EXPECT_FLOAT_EQ(protoOptions.sample_rate(), 1.234);
146 EXPECT_FLOAT_EQ(protoOptions.resolution(), 0.01);
147 EXPECT_EQ(protoOptions.enable_variable_update_rate(), true);
148 }
149
TEST_F(GRPCVehicleHardwareMockServerUnitTest,SubscribeLegacyServer)150 TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeLegacyServer) {
151 EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
152 .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
153
154 aidlvhal::SubscribeOptions options;
155 auto status = mHardware->subscribe(options);
156
157 EXPECT_EQ(status, aidlvhal::StatusCode::OK);
158 }
159
TEST_F(GRPCVehicleHardwareMockServerUnitTest,SubscribeGrpcFailure)160 TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeGrpcFailure) {
161 EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
162 .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
163
164 aidlvhal::SubscribeOptions options;
165 auto status = mHardware->subscribe(options);
166
167 EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
168 }
169
TEST_F(GRPCVehicleHardwareMockServerUnitTest,SubscribeProtoFailure)170 TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeProtoFailure) {
171 proto::VehicleHalCallStatus protoStatus;
172 protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
173
174 EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
175 .WillOnce(DoAll(SetArgPointee<2>(protoStatus), // Set the output status
176 Return(::grpc::Status::OK)));
177
178 aidlvhal::SubscribeOptions options;
179 auto status = mHardware->subscribe(options);
180
181 EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
182 }
183
TEST_F(GRPCVehicleHardwareMockServerUnitTest,Unsubscribe)184 TEST_F(GRPCVehicleHardwareMockServerUnitTest, Unsubscribe) {
185 proto::VehicleHalCallStatus protoStatus;
186 protoStatus.set_status_code(proto::StatusCode::OK);
187 proto::UnsubscribeRequest actualRequest;
188
189 EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
190 .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
191 Return(::grpc::Status::OK)));
192
193 int32_t propId = 1;
194 int32_t areaId = 2;
195 auto status = mHardware->unsubscribe(propId, areaId);
196
197 EXPECT_EQ(status, aidlvhal::StatusCode::OK);
198 EXPECT_EQ(actualRequest.prop_id(), propId);
199 EXPECT_EQ(actualRequest.area_id(), areaId);
200 }
201
TEST_F(GRPCVehicleHardwareMockServerUnitTest,UnsubscribeLegacyServer)202 TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeLegacyServer) {
203 EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
204 .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
205
206 auto status = mHardware->unsubscribe(1, 2);
207
208 EXPECT_EQ(status, aidlvhal::StatusCode::OK);
209 }
210
TEST_F(GRPCVehicleHardwareMockServerUnitTest,UnsubscribeGrpcFailure)211 TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeGrpcFailure) {
212 EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
213 .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
214
215 auto status = mHardware->unsubscribe(1, 2);
216
217 EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
218 }
219
TEST_F(GRPCVehicleHardwareMockServerUnitTest,UnsubscribeProtoFailure)220 TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeProtoFailure) {
221 proto::VehicleHalCallStatus protoStatus;
222 protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
223
224 EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
225 .WillOnce(DoAll(SetArgPointee<2>(protoStatus), // Set the output status
226 Return(::grpc::Status::OK)));
227
228 auto status = mHardware->unsubscribe(1, 2);
229
230 EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
231 }
232
233 } // namespace android::hardware::automotive::vehicle::virtualization
234