1 // Copyright (C) 2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
6 #include "e2e_test_client.hpp"
7
8 static bool is_remote_test = false;
9 static bool remote_client_allowed = true;
10 std::vector<std::vector<vsomeip::byte_t>> payloads_profile_01_;
11 std::vector<std::vector<vsomeip::byte_t>> event_payloads_profile_01_;
12
13 std::vector<std::vector<vsomeip::byte_t>> payloads_custom_profile_;
14 std::vector<std::vector<vsomeip::byte_t>> event_payloads_custom_profile_;
15
16 std::map<vsomeip::method_t, uint32_t> received_responses_counters_;
17
18
e2e_test_client(bool _test_external_communication,bool _is_remote_client_allowed)19 e2e_test_client::e2e_test_client(bool _test_external_communication,
20 bool _is_remote_client_allowed)
21 : app_(vsomeip::runtime::get()->create_application()),
22 is_available_(false),
23 sender_(std::bind(&e2e_test_client::run, this)),
24 received_responses_(0),
25 received_allowed_events_(0),
26 test_external_communication_(_test_external_communication),
27 is_remote_client_allowed_(_is_remote_client_allowed) {
28
29 }
30
init()31 bool e2e_test_client::init() {
32 if (!app_->init()) {
33 ADD_FAILURE() << "Couldn't initialize application";
34 return false;
35 }
36
37 app_->register_state_handler(
38 std::bind(&e2e_test_client::on_state, this,
39 std::placeholders::_1));
40
41 app_->register_message_handler(vsomeip::ANY_SERVICE,
42 vsomeip_test::TEST_SERVICE_INSTANCE_ID, vsomeip::ANY_METHOD,
43 std::bind(&e2e_test_client::on_message, this,
44 std::placeholders::_1));
45
46 app_->register_availability_handler(vsomeip_test::TEST_SERVICE_SERVICE_ID,
47 vsomeip_test::TEST_SERVICE_INSTANCE_ID,
48 std::bind(&e2e_test_client::on_availability, this,
49 std::placeholders::_1, std::placeholders::_2,
50 std::placeholders::_3));
51 return true;
52 }
53
start()54 void e2e_test_client::start() {
55 VSOMEIP_INFO << "Starting...";
56 app_->start();
57 }
58
stop()59 void e2e_test_client::stop() {
60 VSOMEIP_INFO << "Stopping...";
61 shutdown_service();
62 app_->clear_all_handler();
63 app_->stop();
64 }
65
on_state(vsomeip::state_type_e _state)66 void e2e_test_client::on_state(vsomeip::state_type_e _state) {
67 if(_state == vsomeip::state_type_e::ST_REGISTERED) {
68 app_->request_service(vsomeip_test::TEST_SERVICE_SERVICE_ID,
69 vsomeip_test::TEST_SERVICE_INSTANCE_ID, false);
70
71 // request events of eventgroup 0x01 which holds events 0x8001 (CRC8)
72 std::set<vsomeip::eventgroup_t> its_eventgroups;
73 its_eventgroups.insert(0x01);
74
75 // request events of eventgroup 0x02 which holds events 0x8002 (CRC32)
76 std::set<vsomeip::eventgroup_t> its_eventgroups_2;
77 its_eventgroups_2.insert(0x02);
78
79 app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID,
80 static_cast<vsomeip::event_t>(0x8001),
81 its_eventgroups, vsomeip::event_type_e::ET_FIELD,
82 vsomeip::reliability_type_e::RT_UNRELIABLE);
83 app_->request_event(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID,
84 static_cast<vsomeip::event_t>(0x8002),
85 its_eventgroups_2, vsomeip::event_type_e::ET_FIELD,
86 vsomeip::reliability_type_e::RT_UNRELIABLE);
87 }
88 }
89
on_availability(vsomeip::service_t _service,vsomeip::instance_t _instance,bool _is_available)90 void e2e_test_client::on_availability(vsomeip::service_t _service,
91 vsomeip::instance_t _instance, bool _is_available) {
92
93 VSOMEIP_INFO << std::hex << "Client 0x" << app_->get_client()
94 << " : Service [" << std::setw(4) << std::setfill('0') << std::hex
95 << _service << "." << _instance << "] is "
96 << (_is_available ? "available." : "NOT available.");
97
98 // check that correct service / instance ID gets available
99 if (_is_available) {
100 EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _service);
101 EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _instance);
102 }
103
104 if(vsomeip_test::TEST_SERVICE_SERVICE_ID == _service
105 && vsomeip_test::TEST_SERVICE_INSTANCE_ID == _instance) {
106 std::unique_lock<std::mutex> its_lock(mutex_);
107 if(is_available_ && !_is_available) {
108 is_available_ = false;
109 }
110 else if(_is_available && !is_available_) {
111 is_available_ = true;
112 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
113 app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, 0x01);
114 app_->subscribe(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID, 0x02);
115 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
116 condition_.notify_one();
117 }
118 }
119 }
120
on_message(const std::shared_ptr<vsomeip::message> & _response)121 void e2e_test_client::on_message(const std::shared_ptr<vsomeip::message> &_response) {
122 VSOMEIP_INFO << "Received a response from Service ["
123 << std::setw(4) << std::setfill('0') << std::hex << _response->get_service()
124 << "."
125 << std::setw(4) << std::setfill('0') << std::hex << _response->get_instance()
126 << "] to Client/Session ["
127 << std::setw(4) << std::setfill('0') << std::hex << _response->get_client()
128 << "/"
129 << std::setw(4) << std::setfill('0') << std::hex << _response->get_session()
130 << "]";
131 EXPECT_EQ(vsomeip_test::TEST_SERVICE_SERVICE_ID, _response->get_service());
132 EXPECT_EQ(vsomeip_test::TEST_SERVICE_INSTANCE_ID, _response->get_instance());
133
134 // check fixed payload / CRC in response for service: 1234 method: 8421
135 if (_response->get_message_type() == vsomeip::message_type_e::MT_RESPONSE
136 && vsomeip_test::TEST_SERVICE_METHOD_ID == _response->get_method()) {
137 // check for calculated CRC status OK for the predefined fixed payload sent by service
138 VSOMEIP_INFO << "Method ID 0x8421 -> IS_VALID_CRC 8 = " << std::hex << _response->is_valid_crc();
139 EXPECT_EQ(true, _response->is_valid_crc());
140
141 // check if payload is as expected as well (including CRC / counter / data ID nibble)
142 std::shared_ptr<vsomeip::payload> pl = _response->get_payload();
143 uint8_t* dataptr = pl->get_data(); //start after length field
144 for(uint32_t i = 0; i< pl->get_length(); i++) {
145 EXPECT_EQ(dataptr[i], payloads_profile_01_[received_responses_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND][i]);
146 }
147 received_responses_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID]++;
148 } else if (_response->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION
149 && 0x8001 == _response->get_method()) {
150 // check CRC / payload calculated by sender for event 0x8001 against expected payload
151 // check for calculated CRC status OK for the calculated CRC / payload sent by service
152 VSOMEIP_INFO << "Event ID 0x8001 -> IS_VALID_CRC 8 = " << std::hex << _response->is_valid_crc();
153 EXPECT_EQ(true, _response->is_valid_crc());
154
155 // check if payload is as expected as well (including CRC / counter / data ID nibble)
156 std::shared_ptr<vsomeip::payload> pl = _response->get_payload();
157 uint8_t* dataptr = pl->get_data(); //start after length field
158 for(uint32_t i = 0; i< pl->get_length(); i++) {
159 EXPECT_EQ(dataptr[i], event_payloads_profile_01_[received_responses_counters_[0x8001] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND][i]);
160 }
161 received_responses_counters_[0x8001]++;
162 } else if (_response->get_message_type() == vsomeip::message_type_e::MT_RESPONSE
163 && 0x6543 == _response->get_method()) {
164 // check for calculated CRC status OK for the predefined fixed payload sent by service
165 VSOMEIP_INFO << "Method ID 0x6543 -> IS_VALID_CRC 32 = " << std::hex << _response->is_valid_crc();
166 EXPECT_EQ(true, _response->is_valid_crc());
167
168 // check if payload is as expected as well (including CRC / counter / data ID nibble)
169 std::shared_ptr<vsomeip::payload> pl = _response->get_payload();
170 uint8_t* dataptr = pl->get_data(); //start after length field
171 for(uint32_t i = 0; i< pl->get_length(); i++) {
172 EXPECT_EQ(dataptr[i], payloads_custom_profile_[received_responses_counters_[0x6543] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND][i]);
173 }
174 received_responses_counters_[0x6543]++;
175 } else if (_response->get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION
176 && 0x8002 == _response->get_method()) {
177 VSOMEIP_INFO << "Event ID 0x8002 -> IS_VALID_CRC 32 = " << std::hex << _response->is_valid_crc();
178 EXPECT_EQ(true, _response->is_valid_crc());
179
180 // check if payload is as expected as well (including CRC)
181 std::shared_ptr<vsomeip::payload> pl = _response->get_payload();
182 uint8_t* dataptr = pl->get_data(); //start after length field
183 for(uint32_t i = 0; i< pl->get_length(); i++) {
184 EXPECT_EQ(dataptr[i], event_payloads_custom_profile_[received_responses_counters_[0x8002] % vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND][i]);
185 }
186 received_responses_counters_[0x8002]++;
187 }
188
189 received_responses_++;
190 if (received_responses_ == vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND * 4) {
191 VSOMEIP_WARNING << std::hex << app_->get_client()
192 << ": Received all messages ~> going down!";
193 }
194 }
195
run()196 void e2e_test_client::run() {
197 for (uint32_t i = 0; i < vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND; ++i) {
198 {
199 std::unique_lock<std::mutex> its_lock(mutex_);
200 while (!is_available_)
201 {
202 condition_.wait(its_lock);
203 }
204 }
205 auto request = vsomeip::runtime::get()->create_request(false);
206 request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID);
207 request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID);
208
209 // send a request which is not e2e protected and expect an
210 // protected answer holding a fixed payload (profile 01 CRC8)
211 // this call triggers also an event 0x8001 which holds a calculated payload
212 request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID);
213 app_->send(request);
214
215 // send a request which is not e2e protected and expect an
216 // protected answer holding a fixed payload (custom profile CRC32)
217 // this call triggers also an event 0x8002 which holds a calculated payload
218 request->set_method(0x6543);
219 app_->send(request);
220
221 std::this_thread::sleep_for(std::chrono::milliseconds(250));
222 }
223 stop();
224 }
225
join_sender_thread()226 void e2e_test_client::join_sender_thread()
227 {
228 if (sender_.joinable()) {
229 sender_.join();
230 }
231 }
232
shutdown_service()233 void e2e_test_client::shutdown_service() {
234 auto request = vsomeip::runtime::get()->create_request(false);
235 request->set_service(vsomeip_test::TEST_SERVICE_SERVICE_ID);
236 request->set_instance(vsomeip_test::TEST_SERVICE_INSTANCE_ID);
237 request->set_method(vsomeip_test::TEST_SERVICE_METHOD_ID_SHUTDOWN);
238 app_->send(request);
239 std::this_thread::sleep_for(std::chrono::milliseconds(250));
240
241 // expect 10 x response messages for both method IDs and events for both Event IDs
242 EXPECT_EQ(received_responses_, vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND * 4);
243 //EXPECT_EQ(received_allowed_events_, vsomeip_test::NUMBER_OF_MESSAGES_TO_SEND);
244 }
245
TEST(someip_e2e_test,basic_subscribe_request_response)246 TEST(someip_e2e_test, basic_subscribe_request_response)
247 {
248 e2e_test_client test_client(is_remote_test, remote_client_allowed);
249 if (test_client.init()) {
250 test_client.start();
251 test_client.join_sender_thread();
252 }
253 }
254
main(int argc,char ** argv)255 int main(int argc, char** argv) {
256
257 /*
258 e2e profile01 CRC8 protected fixed sample payloads sent by service
259 which must be received in client using the following config on client side:
260 "service_id" : "0x1234",
261 "event_id" : "0x8421",
262 "profile" : "CRC8",
263 "variant" : "checker",
264 "crc_offset" : "0",
265 "data_id_mode" : "3",
266 "data_length" : "56",
267 "data_id" : "0xA73"
268 */
269 payloads_profile_01_.push_back({{0x82, 0xa4, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}}); // initial event
270 payloads_profile_01_.push_back({{0x39, 0xa8, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}});
271 payloads_profile_01_.push_back({{0x87, 0xa4, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}});
272 payloads_profile_01_.push_back({{0x3c, 0xa8, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}});
273 payloads_profile_01_.push_back({{0x55, 0xac, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}});
274 payloads_profile_01_.push_back({{0x82, 0xa4, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}});
275 payloads_profile_01_.push_back({{0x39, 0xa8, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff}});
276 payloads_profile_01_.push_back({{0x87, 0xa4, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}});
277 payloads_profile_01_.push_back({{0x3c, 0xa8, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}});
278 payloads_profile_01_.push_back({{0x55, 0xac, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff}});
279
280 /*
281 e2e profile01 CRC8 protected payloads which shall be created by e2e module on
282 service side using the following config on client side:
283 "service_id" : "0x1234",
284 "event_id" : "0x8001",
285 "profile" : "CRC8",
286 "variant" : "checker",
287 "crc_offset" : "0",
288 "data_id_mode" : "3",
289 "data_length" : "56",
290 "data_id" : "0xA73"
291 */
292 event_payloads_profile_01_.push_back({{0xa4, 0xa1, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff}}); // initial event
293 event_payloads_profile_01_.push_back({{0x05, 0xa2, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff}});
294 event_payloads_profile_01_.push_back({{0x92, 0xa3, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff}});
295 event_payloads_profile_01_.push_back({{0x5a, 0xa4, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff}});
296 event_payloads_profile_01_.push_back({{0xc8, 0xa5, 0x04, 0xff, 0xff, 0xff, 0xff, 0xff}});
297 event_payloads_profile_01_.push_back({{0x69, 0xa6, 0x05, 0xff, 0xff, 0xff, 0xff, 0xff}});
298 event_payloads_profile_01_.push_back({{0xfe, 0xa7, 0x06, 0xff, 0xff, 0xff, 0xff, 0xff}});
299 event_payloads_profile_01_.push_back({{0xe4, 0xa8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff}});
300 event_payloads_profile_01_.push_back({{0x7c, 0xa9, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff}});
301 event_payloads_profile_01_.push_back({{0xdd, 0xaa, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff}});
302
303 /*
304 e2e custom profile CRR32 protected fixed sample payloads sent by service
305 which must be received in client using the following config on client side:
306 "service_id" : "0x1234",
307 "event_id" : "0x6543",
308 "profile" : "CRC32",
309 "variant" : "checker",
310 "crc_offset" : "0"
311 */
312 payloads_custom_profile_.push_back({{0xa4, 0xb2, 0x75, 0x1f, 0xff, 0x00, 0xff, 0x32}});
313 payloads_custom_profile_.push_back({{0xa5, 0x70, 0x1f, 0x28, 0xff, 0x01, 0xff, 0x32}});
314 payloads_custom_profile_.push_back({{0xa7, 0x36, 0xa1, 0x71, 0xff, 0x02, 0xff, 0x32}});
315 payloads_custom_profile_.push_back({{0xa6, 0xf4, 0xcb, 0x46, 0xff, 0x03, 0xff, 0x32}});
316 payloads_custom_profile_.push_back({{0xa3, 0xbb, 0xdd, 0xc3, 0xff, 0x04, 0xff, 0x32}});
317 payloads_custom_profile_.push_back({{0xa2, 0x79, 0xb7, 0xf4, 0xff, 0x05, 0xff, 0x32}});
318 payloads_custom_profile_.push_back({{0xa0, 0x3f, 0x09, 0xad, 0xff, 0x06, 0xff, 0x32}});
319 payloads_custom_profile_.push_back({{0xa1, 0xfd, 0x63, 0x9a, 0xff, 0x07, 0xff, 0x32}});
320 payloads_custom_profile_.push_back({{0xaa, 0xa1, 0x24, 0xa7, 0xff, 0x08, 0xff, 0x32}});
321 payloads_custom_profile_.push_back({{0xab, 0x63, 0x4e, 0x90, 0xff, 0x09, 0xff, 0x32}});
322
323 /*
324 e2e custom profile CRC32 protected payloads which shall be created by e2e module on
325 service side using the following config on client side for checking:
326 "service_id" : "0x1234",
327 "event_id" : "0x8002",
328 "profile" : "CRC32",
329 "variant" : "checker",
330 "crc_offset" : "0"
331 */
332 event_payloads_custom_profile_.push_back({{0x89, 0x0e, 0xbc, 0x80, 0xff, 0xff, 0x00, 0x32}});
333 event_payloads_custom_profile_.push_back({{0x90, 0x15, 0x8d, 0xc1, 0xff, 0xff, 0x01, 0x32}});
334 event_payloads_custom_profile_.push_back({{0xbb, 0x38, 0xde, 0x02, 0xff, 0xff, 0x02, 0x32}});
335 event_payloads_custom_profile_.push_back({{0xa2, 0x23, 0xef, 0x43, 0xff, 0xff, 0x03, 0x32}});
336 event_payloads_custom_profile_.push_back({{0xed, 0x62, 0x79, 0x84, 0xff, 0xff, 0x04, 0x32}});
337 event_payloads_custom_profile_.push_back({{0xf4, 0x79, 0x48, 0xc5, 0xff, 0xff, 0x05, 0x32}});
338 event_payloads_custom_profile_.push_back({{0xdf, 0x54, 0x1b, 0x06, 0xff, 0xff, 0x06, 0x32}});
339 event_payloads_custom_profile_.push_back({{0xc6, 0x4f, 0x2a, 0x47, 0xff, 0xff, 0x07, 0x32}});
340 event_payloads_custom_profile_.push_back({{0x41, 0xd7, 0x36, 0x88, 0xff, 0xff, 0x08, 0x32}});
341 event_payloads_custom_profile_.push_back({{0x58, 0xcc, 0x07, 0xc9, 0xff, 0xff, 0x09, 0x32}});
342
343 received_responses_counters_[vsomeip_test::TEST_SERVICE_METHOD_ID] = 0;
344 received_responses_counters_[0x8001] = 0;
345 received_responses_counters_[0x6543] = 0;
346 received_responses_counters_[0x8002] = 0;
347
348 std::string test_remote("--remote");
349 std::string test_local("--local");
350 std::string test_allow_remote_client("--allow");
351 std::string test_deny_remote_client("--deny");
352 std::string help("--help");
353
354 int i = 1;
355 while (i < argc)
356 {
357 if(test_remote == argv[i])
358 {
359 is_remote_test = true;
360 }
361 else if(test_local == argv[i])
362 {
363 is_remote_test = false;
364 }
365 else if(test_allow_remote_client == argv[i])
366 {
367 remote_client_allowed = true;
368 }
369 else if(test_deny_remote_client == argv[i])
370 {
371 remote_client_allowed = false;
372 }
373 else if(help == argv[i])
374 {
375 VSOMEIP_INFO << "Parameters:\n"
376 << "--remote: Run test between two hosts\n"
377 << "--local: Run test locally\n"
378 << "--allow: test is started with a policy that allows remote messages sent by this test client to the service\n"
379 << "--deny: test is started with a policy that denies remote messages sent by this test client to the service\n"
380 << "--help: print this help";
381 }
382 i++;
383 }
384
385 ::testing::InitGoogleTest(&argc, argv);
386 return RUN_ALL_TESTS();
387 }
388