summaryrefslogtreecommitdiff
path: root/test/network_tests/someip_tp_tests
diff options
context:
space:
mode:
Diffstat (limited to 'test/network_tests/someip_tp_tests')
-rw-r--r--test/network_tests/someip_tp_tests/conf/someip_tp_test_master.json.in45
-rwxr-xr-xtest/network_tests/someip_tp_tests/conf/someip_tp_test_master_starter.sh.in65
-rw-r--r--test/network_tests/someip_tp_tests/someip_tp_test_globals.hpp40
-rw-r--r--test/network_tests/someip_tp_tests/someip_tp_test_msg_sender.cpp1387
-rw-r--r--test/network_tests/someip_tp_tests/someip_tp_test_service.cpp413
5 files changed, 1950 insertions, 0 deletions
diff --git a/test/network_tests/someip_tp_tests/conf/someip_tp_test_master.json.in b/test/network_tests/someip_tp_tests/conf/someip_tp_test_master.json.in
new file mode 100644
index 0000000..a2f67a1
--- /dev/null
+++ b/test/network_tests/someip_tp_tests/conf/someip_tp_test_master.json.in
@@ -0,0 +1,45 @@
+{
+ "unicast":"@TEST_IP_MASTER@",
+ "logging":
+ {
+ "level":"info",
+ "console":"true"
+ },
+ "applications" :
+ [
+ {
+ "name" : "someip_tp_test_service",
+ "id" : "0xCAFE"
+ }
+ ],
+ "services":
+ [
+ {
+ "service":"0x4545",
+ "instance":"0x1",
+ "unreliable":"30001",
+ "someip-tp" : {
+ "service-to-client": [ "0x4545", "0x8001"]
+ }
+ },
+ {
+ "service":"0x6767",
+ "instance":"0x1",
+ "unicast" : "@TEST_IP_SLAVE@",
+ "unreliable":"40001",
+ "someip-tp" : {
+ "client-to-service": [ "0x6767", "0x8001" ]
+ }
+ }
+ ],
+ "max-payload-size-unreliable" : "8352",
+ "routing":"routingmanagerd",
+ "service-discovery":
+ {
+ "enable":"true",
+ "multicast":"224.0.77.1",
+ "port":"30490",
+ "protocol":"udp",
+ "cyclic_offer_delay" : "1000"
+ }
+} \ No newline at end of file
diff --git a/test/network_tests/someip_tp_tests/conf/someip_tp_test_master_starter.sh.in b/test/network_tests/someip_tp_tests/conf/someip_tp_test_master_starter.sh.in
new file mode 100755
index 0000000..0064899
--- /dev/null
+++ b/test/network_tests/someip_tp_tests/conf/someip_tp_test_master_starter.sh.in
@@ -0,0 +1,65 @@
+#!/bin/bash
+# Copyright (C) 2015-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+FAIL=0
+
+if [ $# -lt 1 ]
+then
+ echo "Please pass a test mode to this script."
+ echo "For example: $0 IN_SEQUENCE"
+ echo "Valid subscription types include:"
+ echo " [IN_SEQUENCE, MIXED, INCOMPLETE, DUPLICATE, OVERLAP, OVERLAP_FRONT_BACK]"
+ exit 1
+fi
+TESTMODE=$1
+export VSOMEIP_CONFIGURATION=someip_tp_test_master.json
+# start daemon
+../../examples/routingmanagerd/./routingmanagerd &
+PID_VSOMEIPD=$!
+# Start the services
+./someip_tp_test_service $1 &
+PID_SERIVCE=$!
+
+sleep 1
+
+if [ ! -z "$USE_LXC_TEST" ]; then
+ echo "Waiting for 5s"
+ sleep 5
+ ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests; ./someip_tp_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE\"" &
+ echo "remote ssh pid: $!"
+elif [ ! -z "$USE_DOCKER" ]; then
+ echo "Waiting for 5s"
+ sleep 5
+ docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./someip_tp_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE" &
+else
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** someip_tp_test_msg_sender @TEST_IP_MASTER@ @TEST_IP_SLAVE@ $TESTMODE
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** someip_tp_test_master.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+fi
+
+# Wait until all clients and services are finished
+for job in $PID_SERIVCE
+do
+ # Fail gets incremented if a client exits with a non-zero exit code
+ echo "waiting for $job"
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# kill the services
+kill $PID_VSOMEIPD
+sleep 1
+
+# Check if everything went well
+exit $FAIL
diff --git a/test/network_tests/someip_tp_tests/someip_tp_test_globals.hpp b/test/network_tests/someip_tp_tests/someip_tp_test_globals.hpp
new file mode 100644
index 0000000..723cfe1
--- /dev/null
+++ b/test/network_tests/someip_tp_tests/someip_tp_test_globals.hpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef SOMEIP_TP_TEST_GLOBALS_HPP_
+#define SOMEIP_TP_TEST_GLOBALS_HPP_
+
+#include <vsomeip/primitive_types.hpp>
+
+namespace someip_tp_test {
+
+struct service_info {
+ vsomeip::service_t service_id;
+ vsomeip::instance_t instance_id;
+ vsomeip::method_t method_id;
+ vsomeip::event_t event_id;
+ vsomeip::eventgroup_t eventgroup_id;
+ vsomeip::method_t shutdown_method_id;
+ vsomeip::method_t notify_method_id;
+};
+
+struct service_info service = { 0x4545, 0x1, 0x4545, 0x8001, 0x1, 0x4501, 0x4502 };
+struct service_info service_slave = { 0x6767, 0x1, 0x6767, 0x8001, 0x1, 0x6701, 0x6702 };
+
+enum test_mode_e {
+ IN_SEQUENCE,
+ MIXED,
+ INCOMPLETE,
+ DUPLICATE,
+ OVERLAP,
+ OVERLAP_FRONT_BACK
+};
+
+const std::uint32_t number_of_fragments = 6;
+const std::uint32_t max_segment_size = 1392;
+
+}
+
+#endif /* SOMEIP_TP_TEST_GLOBALS_HPP_ */
diff --git a/test/network_tests/someip_tp_tests/someip_tp_test_msg_sender.cpp b/test/network_tests/someip_tp_tests/someip_tp_test_msg_sender.cpp
new file mode 100644
index 0000000..f2e4f9e
--- /dev/null
+++ b/test/network_tests/someip_tp_tests/someip_tp_test_msg_sender.cpp
@@ -0,0 +1,1387 @@
+// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <iostream>
+#include <memory>
+#include <thread>
+#include <chrono>
+#include <cstring>
+#include <future>
+#include <numeric>
+#include <random>
+#include <algorithm>
+#include <list>
+
+#if defined(__linux__) || defined(ANDROID)
+#include <arpa/inet.h>
+#endif
+
+#include <gtest/gtest.h>
+
+#include <boost/asio.hpp>
+
+#include <vsomeip/vsomeip.hpp>
+
+#include "../../implementation/utility/include/byteorder.hpp"
+#include "../../implementation/message/include/deserializer.hpp"
+#include "../../implementation/message/include/serializer.hpp"
+#include "../../implementation/service_discovery/include/service_discovery.hpp"
+#include "../../implementation/service_discovery/include/message_impl.hpp"
+#include "../../implementation/service_discovery/include/constants.hpp"
+#include "../../implementation/service_discovery/include/enumeration_types.hpp"
+#include "../../implementation/service_discovery/include/eventgroupentry_impl.hpp"
+#include "../../implementation/service_discovery/include/serviceentry_impl.hpp"
+#include "../../implementation/message/include/message_impl.hpp"
+#include "../../implementation/service_discovery/include/option_impl.hpp"
+#include "../../implementation/service_discovery/include/ipv4_option_impl.hpp"
+#include "../../implementation/endpoints/include/tp.hpp"
+#include "../../implementation/endpoints/include/tp_reassembler.hpp"
+#include "../../implementation/message/include/payload_impl.hpp"
+
+#include "someip_tp_test_globals.hpp"
+
+static char* remote_address;
+static char* local_address;
+
+std::vector<someip_tp_test::test_mode_e> its_modes({
+ someip_tp_test::test_mode_e::IN_SEQUENCE,
+ someip_tp_test::test_mode_e::MIXED,
+ someip_tp_test::test_mode_e::INCOMPLETE,
+ someip_tp_test::test_mode_e::DUPLICATE,
+ someip_tp_test::test_mode_e::OVERLAP,
+ someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK,
+});
+
+class someip_tp : public ::testing::TestWithParam<someip_tp_test::test_mode_e> {
+public:
+ someip_tp() :
+ work_(std::make_shared<boost::asio::io_context::work>(io_)),
+ io_thread_(std::bind(&someip_tp::io_run, this)),
+ session_(0x0),
+ sd_session_(0x0),
+ address_remote_(boost::asio::ip::address::from_string(std::string(remote_address))),
+ address_local_(boost::asio::ip::address::from_string(std::string(local_address))),
+ runtime_(vsomeip::runtime::get()) {}
+protected:
+ void TearDown() {
+ work_.reset();
+ io_thread_.join();
+ io_.stop();
+ }
+
+ void call_shutdown_method() {
+ boost::system::error_code ec;
+ std::uint8_t shutdown_call[] = {
+ 0x45, 0x45, 0x45, 0x01,
+ 0x00, 0x00, 0x00, 0x08,
+ 0xDD, 0xDD, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x00 };
+ boost::asio::ip::udp::socket::endpoint_type target_service(address_remote_,
+ 30001);
+ boost::asio::ip::udp::socket udp_socket2(io_, boost::asio::ip::udp::v4());
+ udp_socket2.send_to(boost::asio::buffer(shutdown_call), target_service);
+ udp_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec);
+ udp_socket2.close(ec);
+ }
+
+ void io_run() {
+ io_.run();
+ }
+
+ void offer_service(boost::asio::ip::udp::socket* const _udp_socket) {
+ // offer the service
+ std::uint8_t its_offer_service_message[] = {
+ 0xff, 0xff, 0x81, 0x00,
+ 0x00, 0x00, 0x00, 0x30, // length
+ 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x01, 0x02, 0x00,
+ 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, // length entries array
+ 0x01, 0x00, 0x00, 0x20,
+ 0x67, 0x67, 0x00, 0x01, // service / instance
+ 0x00, 0xff, 0xff, 0xff, // major / ttl
+ 0x00, 0x00, 0x00, 0x00, // minor
+ 0x00, 0x00, 0x00, 0x0c, // length options array
+ 0x00, 0x09, 0x04, 0x00,
+ 0xff, 0xff, 0xff, 0xff, // slave address
+ 0x00, 0x11, 0x9c, 0x41,
+ };
+ std::memcpy(&its_offer_service_message[48], &address_local_.to_v4().to_bytes()[0], 4);
+ std::uint16_t its_session = htons(++sd_session_);
+ std::memcpy(&its_offer_service_message[10], &its_session, sizeof(its_session));
+
+ boost::asio::ip::udp::socket::endpoint_type target_sd(address_remote_,30490);
+ _udp_socket->send_to(boost::asio::buffer(its_offer_service_message), target_sd);
+ }
+
+ void subscribe_at_master(boost::asio::ip::udp::socket* const _udp_socket) {
+ std::uint8_t its_subscription[] = {
+ 0xff, 0xff, 0x81, 0x00,
+ 0x00, 0x00, 0x00, 0x30, // length
+ 0x00, 0x00, 0x00, 0x01,
+ 0x01, 0x01, 0x02, 0x00,
+ 0xc0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, // length entries array
+ 0x06, 0x00, 0x00, 0x10,
+ 0x45, 0x45, 0x00, 0x01, // service / instance
+ 0x00, 0xff, 0xff, 0xff, // major / ttl
+ 0x00, 0x00, 0x00, 0x01, // counter
+ 0x00, 0x00, 0x00, 0x0c, // length options array
+ 0x00, 0x09, 0x04, 0x00,
+ 0xff, 0xff, 0xff, 0xff, // slave address
+ 0x00, 0x11, 0x75, 0x31, // port 30001
+ };
+ std::memcpy(&its_subscription[48], &address_local_.to_v4().to_bytes()[0], 4);
+ std::uint16_t its_session = htons(++sd_session_);
+ std::memcpy(&its_subscription[10], &its_session, sizeof(its_session));
+
+ boost::asio::ip::udp::socket::endpoint_type target_sd(address_remote_,30490);
+ _udp_socket->send_to(boost::asio::buffer(its_subscription), target_sd);
+ }
+
+ /*
+ * @brief custom version of tp::tp_split_message with adjustable segment size
+ * needed to send overlapping segments within the 1392 byte segment size limit
+ */
+ vsomeip::tp::tp_split_messages_t split_message(const std::uint8_t * const _data,
+ std::uint32_t _size , std::uint32_t _segment_size) {
+ using namespace vsomeip::tp;
+ using namespace vsomeip;
+ tp_split_messages_t split_messages;
+
+ if (_size < VSOMEIP_MAX_UDP_MESSAGE_SIZE) {
+ std::cerr << __func__ << " called with size: " << std::dec << _size;
+ return split_messages;
+ }
+
+ const auto data_end = _data + _size;
+
+ for (auto current_offset = _data + 16; current_offset < data_end;) {
+ auto msg = std::make_shared<message_buffer_t>();
+ msg->reserve(VSOMEIP_FULL_HEADER_SIZE + sizeof(tp_header_t) + _segment_size);
+ // copy the header
+ msg->insert(msg->end(), _data, _data + VSOMEIP_FULL_HEADER_SIZE);
+ // change the message type
+ (*msg)[VSOMEIP_MESSAGE_TYPE_POS] = (*msg)[VSOMEIP_MESSAGE_TYPE_POS] | 0x20;
+ // check if last segment
+ const auto segment_end = current_offset + _segment_size;
+ const bool is_last_segment = (segment_end >= data_end);
+ // insert tp_header
+ const tp_header_t header = htonl(
+ static_cast<tp_header_t>((current_offset - VSOMEIP_FULL_HEADER_SIZE - _data)) |
+ static_cast<tp_header_t>((is_last_segment) ? 0x0u : 0x1u));
+
+ const byte_t * const headerp = reinterpret_cast<const byte_t*>(&header);
+ msg->insert(msg->end(), headerp, headerp + sizeof(tp_header_t));
+
+ // insert payload
+ if (is_last_segment) {
+ msg->insert(msg->end(), current_offset, data_end);
+ current_offset = data_end;
+ } else {
+ msg->insert(msg->end(), current_offset, segment_end);
+ current_offset += _segment_size;
+ }
+ // update length
+ const length_t its_length = static_cast<length_t>(msg->size()
+ - VSOMEIP_SOMEIP_HEADER_SIZE);
+ *(reinterpret_cast<length_t*>(&(*msg)[VSOMEIP_LENGTH_POS_MIN])) = htonl(its_length);
+ split_messages.emplace_back(std::move(msg));
+ }
+
+ return split_messages;
+ }
+
+ void create_fragments(std::uint32_t _count, vsomeip::service_t _service,
+ vsomeip::instance_t _instance,
+ vsomeip::method_t _method,
+ vsomeip::message_type_e _message_type,
+ vsomeip::client_t _client,
+ vsomeip::session_t _session,
+ std::vector<vsomeip::message_buffer_ptr_t>* _target,
+ std::uint32_t _segment_size) {
+ vsomeip::message_impl msg;
+ msg.set_reliable(false);
+ msg.set_service(_service);
+ msg.set_instance(_instance);
+ msg.set_method(_method);
+ msg.set_message_type(_message_type);
+ msg.set_return_code(vsomeip::return_code_e::E_OK);
+ if (_client == vsomeip::ANY_CLIENT) {
+ msg.set_client(0xDDDD);
+ } else {
+ msg.set_client(_client);
+ }
+ if (_session == 0xFFFF) {
+ msg.set_session(++session_);
+ } else {
+ msg.set_session(_session);
+ }
+ std::vector<vsomeip::byte_t> its_payload_data;
+ for (uint32_t i = 0; i < _count; i++) {
+ its_payload_data.resize((i * _segment_size) + _segment_size, static_cast<std::uint8_t>(i));
+ }
+ std::shared_ptr<vsomeip::payload> payload = std::make_shared<vsomeip::payload_impl>(its_payload_data);
+ msg.set_payload(payload);
+ vsomeip::serializer its_serializer(0);
+ msg.serialize(&its_serializer);
+
+ *_target = split_message(its_serializer.get_data(), its_serializer.get_size(), _segment_size);
+ its_serializer.reset();
+
+ }
+
+ vsomeip::message_buffer_t create_full_message(
+ const std::vector<vsomeip::message_buffer_ptr_t>& _fragments) {
+ auto its_reassembler = std::make_shared<vsomeip::tp::tp_reassembler>(
+ std::numeric_limits<std::uint32_t>::max(), io_);
+ vsomeip::message_buffer_t its_reassemlbed_msg;
+ for (const auto& frag : _fragments) {
+ const auto res = its_reassembler->process_tp_message(&(*frag)[0],
+ std::uint32_t(frag->size()), address_local_, 12345);
+ if (res.first) {
+ its_reassemlbed_msg = res.second;
+ }
+ }
+ its_reassembler->stop();
+ return its_reassemlbed_msg;
+ }
+
+ std::vector<int> create_shuffled_seqeuence(std::uint32_t _count) {
+ std::vector<int> its_indexes(_count);
+ std::iota(its_indexes.begin(), its_indexes.end(), 0);
+ std::random_device rd;
+ std::mt19937 its_twister(rd());
+ std::shuffle(its_indexes.begin(), its_indexes.end(), its_twister);
+ return its_indexes;
+ }
+ void increase_segment_back(const vsomeip::message_buffer_ptr_t& _seg,
+ std::uint32_t _amount) {
+ _seg->resize(_seg->size() + _amount, 0xff);
+ // update length
+ *(reinterpret_cast<vsomeip::length_t*>(&((*_seg)[VSOMEIP_LENGTH_POS_MIN]))) =
+ htonl(static_cast<vsomeip::length_t>(_seg->size() - VSOMEIP_SOMEIP_HEADER_SIZE));
+ }
+
+ void increase_segment_front(const vsomeip::message_buffer_ptr_t& _seg,
+ std::uint32_t _amount) {
+ // increase segment by amount
+ _seg->insert(_seg->begin() + VSOMEIP_TP_PAYLOAD_POS, _amount, 0xff);
+
+ // decrease offset by amount
+ const vsomeip::tp::tp_header_t its_tp_header = VSOMEIP_BYTES_TO_LONG(
+ (*_seg)[VSOMEIP_TP_HEADER_POS_MIN],
+ (*_seg)[VSOMEIP_TP_HEADER_POS_MIN + 1],
+ (*_seg)[VSOMEIP_TP_HEADER_POS_MIN + 2],
+ (*_seg)[VSOMEIP_TP_HEADER_POS_MAX]);
+ std::uint32_t its_offset = vsomeip::tp::tp::get_offset(its_tp_header);
+ its_offset -= _amount;
+ const vsomeip::tp::tp_header_t its_new_tp_header =
+ htonl(static_cast<vsomeip::tp::tp_header_t>(its_offset |
+ static_cast<vsomeip::tp::tp_header_t>(its_tp_header & 0x1)));
+ *(reinterpret_cast<vsomeip::tp::tp_header_t*>(
+ &((*_seg)[VSOMEIP_TP_HEADER_POS_MIN]))) = its_new_tp_header;
+
+ // update length
+ *(reinterpret_cast<vsomeip::length_t*>(&((*_seg)[VSOMEIP_LENGTH_POS_MIN]))) =
+ htonl(static_cast<vsomeip::length_t>(_seg->size() - VSOMEIP_SOMEIP_HEADER_SIZE));
+ }
+
+ void increase_segment_front_back(const vsomeip::message_buffer_ptr_t& _seg,
+ std::uint32_t _amount) {
+ increase_segment_front(_seg, _amount);
+ increase_segment_back(_seg, _amount);
+ }
+
+ void decrease_segment_back(const vsomeip::message_buffer_ptr_t& _seg,
+ std::uint32_t _amount) {
+ _seg->resize(_seg->size() - _amount, 0xff);
+ // update length
+ *(reinterpret_cast<vsomeip::length_t*>(&((*_seg)[VSOMEIP_LENGTH_POS_MIN]))) =
+ htonl(static_cast<vsomeip::length_t>(_seg->size() - VSOMEIP_SOMEIP_HEADER_SIZE));
+ }
+
+ void decrease_segment_front(const vsomeip::message_buffer_ptr_t& _seg,
+ std::uint32_t _amount) {
+ if (_amount % 16 != 0) {
+ std::cerr << __func__ << ":" << __LINE__ << std::endl;
+ return;
+ }
+ _seg->erase(_seg->begin() + VSOMEIP_TP_PAYLOAD_POS, _seg->begin() + VSOMEIP_TP_PAYLOAD_POS + _amount);
+ // increase offset by amount
+ const vsomeip::tp::tp_header_t its_tp_header = VSOMEIP_BYTES_TO_LONG(
+ (*_seg)[VSOMEIP_TP_HEADER_POS_MIN],
+ (*_seg)[VSOMEIP_TP_HEADER_POS_MIN + 1],
+ (*_seg)[VSOMEIP_TP_HEADER_POS_MIN + 2],
+ (*_seg)[VSOMEIP_TP_HEADER_POS_MAX]);
+ std::uint32_t its_offset = vsomeip::tp::tp::get_offset(its_tp_header);
+ its_offset += _amount;
+ const vsomeip::tp::tp_header_t its_new_tp_header =
+ htonl(static_cast<vsomeip::tp::tp_header_t>(its_offset |
+ static_cast<vsomeip::tp::tp_header_t>(its_tp_header & 0x1)));
+ *(reinterpret_cast<vsomeip::tp::tp_header_t*>(
+ &((*_seg)[VSOMEIP_TP_HEADER_POS_MIN]))) = its_new_tp_header;
+ // update length
+ *(reinterpret_cast<vsomeip::length_t*>(&((*_seg)[VSOMEIP_LENGTH_POS_MIN]))) =
+ htonl(static_cast<vsomeip::length_t>(_seg->size() - VSOMEIP_SOMEIP_HEADER_SIZE));
+ }
+
+ void decrease_segment_front_back(const vsomeip::message_buffer_ptr_t& _seg,
+ std::uint32_t _amount) {
+ if (_amount % 16 != 0) {
+ std::cerr << __func__ << ":" << __LINE__ << std::endl;
+ return;
+ }
+ decrease_segment_back(_seg, _amount);
+ decrease_segment_front(_seg, _amount);
+ }
+
+
+ enum order_e {
+ ASCENDING,
+ DESCENDING,
+ MIXED_PREDEFINED,
+ MIXED_RANDOM,
+ };
+
+ boost::asio::io_context io_;
+ std::shared_ptr<boost::asio::io_context::work> work_;
+ std::thread io_thread_;
+ std::vector<vsomeip::message_buffer_ptr_t> fragments_request_to_master_;
+ std::vector<vsomeip::message_buffer_ptr_t> fragments_response_of_master_;
+
+ std::vector<vsomeip::message_buffer_ptr_t> fragments_received_as_server_;
+ std::vector<vsomeip::message_buffer_ptr_t> fragments_response_to_master_;
+
+ std::vector<vsomeip::message_buffer_ptr_t> fragments_event_from_master_;
+ std::vector<vsomeip::message_buffer_ptr_t> fragments_event_to_master_;
+
+ std::atomic<std::uint16_t> session_;
+ std::atomic<std::uint16_t> sd_session_;
+ boost::asio::ip::address address_remote_;
+ boost::asio::ip::address address_local_;
+ std::shared_ptr<vsomeip::runtime> runtime_;
+ someip_tp_test::test_mode_e test_mode_ = GetParam();
+};
+
+INSTANTIATE_TEST_CASE_P(send_in_mode,
+ someip_tp,
+ ::testing::ValuesIn(its_modes));
+
+
+/*
+ * @test Send a big fragmented UDP request to the master and wait for the
+ * response. Check that the received response is the same as the request (server
+ * just echos the requests).
+ * Wait for a big fragmented UDP message request from the master and send back
+ * the response in the same size. Check that the request and response are
+ * identical.
+ * Do this two times one with fragments ordered ascending and one time descending.
+ * Wait for the master to subscribe and send back two big, fragmented
+ * notifications one with fragments ordered ascending and one descending
+ * Subscribe at master and wait for one fragmented event.
+ * With testmode INCOMPLETE incomplete fragments are send as well
+ * With testmode MIXED instead of ascending/descedning order the fragments are
+ * send in a predefined or in a random order
+ */
+TEST_P(someip_tp, send_in_mode)
+{
+ std::promise<void> remote_client_subscribed;
+ std::atomic<std::uint16_t> remote_client_subscription_port(0);
+ std::promise<void> offer_received;
+
+ std::mutex udp_sd_socket_mutex;
+ boost::asio::ip::udp::socket udp_sd_socket(io_,
+ boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30490));
+
+ boost::asio::ip::udp::socket udp_client_socket(io_,
+ boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30001));
+
+ boost::asio::ip::udp::socket udp_server_socket(io_,
+ boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 40001));
+
+ std::thread sd_receive_thread([&](){
+ std::atomic<bool> keep_receiving(true);
+ std::vector<std::uint8_t> receive_buffer(4096);
+ std::vector<vsomeip::event_t> its_received_events;
+ std::atomic<bool> service_offered(false);
+ std::atomic<bool> client_subscribed(false);
+
+ // join the sd multicast group 224.0.77.1
+ udp_sd_socket.set_option(boost::asio::ip::multicast::join_group(
+ boost::asio::ip::address::from_string("224.0.77.1").to_v4()));
+ while (keep_receiving) {
+ boost::system::error_code error;
+ std::size_t bytes_transferred = udp_sd_socket.receive(
+ boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error);
+ if (error) {
+ keep_receiving = false;
+ ADD_FAILURE() << __func__ << " error: " << error.message();
+ return;
+ } else {
+ vsomeip::deserializer its_deserializer(&receive_buffer[0], bytes_transferred, 0);
+ vsomeip::service_t its_service = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_SERVICE_POS_MIN],
+ receive_buffer[VSOMEIP_SERVICE_POS_MAX]);
+ vsomeip::method_t its_method = VSOMEIP_BYTES_TO_WORD(receive_buffer[VSOMEIP_METHOD_POS_MIN],
+ receive_buffer[VSOMEIP_METHOD_POS_MAX]);
+ if (its_service == vsomeip::sd::service && its_method == vsomeip::sd::method) {
+ vsomeip::sd::message_impl sd_msg;
+ EXPECT_TRUE(sd_msg.deserialize(&its_deserializer));
+ EXPECT_EQ(1u, sd_msg.get_entries().size());
+ for (const auto& e : sd_msg.get_entries()) {
+ if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP && !client_subscribed) {
+ EXPECT_TRUE(e->is_eventgroup_entry());
+ EXPECT_EQ(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP, e->get_type());
+ EXPECT_EQ(1,e->get_num_options(1));
+ EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl());
+ EXPECT_EQ(someip_tp_test::service_slave.service_id, e->get_service());
+ EXPECT_EQ(someip_tp_test::service_slave.instance_id, e->get_instance());
+ EXPECT_EQ(1u, sd_msg.get_options().size());
+ if (e->get_type() == vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP) {
+ std::shared_ptr<vsomeip::sd::eventgroupentry_impl> its_casted_entry =
+ std::static_pointer_cast<vsomeip::sd::eventgroupentry_impl>(e);
+ EXPECT_EQ(someip_tp_test::service_slave.eventgroup_id,
+ its_casted_entry->get_eventgroup());
+ std::shared_ptr<vsomeip::sd::option_impl> its_option =
+ sd_msg.get_options().at(its_casted_entry->get_options(1)[0]);
+ EXPECT_TRUE(its_option > 0);
+ if(its_option->get_type() == vsomeip::sd::option_type_e::IP4_ENDPOINT) {
+ std::shared_ptr<vsomeip::sd::ipv4_option_impl> its_ipv4_option =
+ std::dynamic_pointer_cast<vsomeip::sd::ipv4_option_impl> (its_option);
+ EXPECT_TRUE(its_ipv4_option > 0);
+ EXPECT_EQ(vsomeip::sd::layer_four_protocol_e::UDP, its_ipv4_option->get_layer_four_protocol());
+ EXPECT_EQ(address_remote_,
+ boost::asio::ip::address(
+ boost::asio::ip::address_v4(its_ipv4_option->get_address())));
+ remote_client_subscription_port = its_ipv4_option->get_port();
+ }
+ std::vector<vsomeip::byte_t> its_sub_ack(&receive_buffer[0], &receive_buffer[0] + VSOMEIP_FULL_HEADER_SIZE + 8 + (sd_msg.get_entries().size() * 16));
+ its_sub_ack[24] = static_cast<vsomeip::byte_t>(vsomeip::sd::entry_type_e::SUBSCRIBE_EVENTGROUP_ACK);
+ // fix length
+ const std::uint32_t its_length = htonl(static_cast<std::uint32_t>(its_sub_ack.size()) - VSOMEIP_SOMEIP_HEADER_SIZE);
+ std::memcpy(&its_sub_ack[4], &its_length, sizeof(its_length));
+ // set number of options to zero
+ its_sub_ack[27] = 0x0;
+ // update session
+ std::uint16_t its_session = htons(++sd_session_);
+ std::memcpy(&its_sub_ack[10], &its_session, sizeof(its_session));
+ boost::asio::ip::udp::socket::endpoint_type target_sd(address_remote_,30490);
+ {
+ std::lock_guard<std::mutex> its_lock(udp_sd_socket_mutex);
+ udp_sd_socket.send_to(boost::asio::buffer(its_sub_ack), target_sd);
+ }
+ std::cout << __LINE__ << ": master subscribed" << std::endl;
+ remote_client_subscribed.set_value();
+ client_subscribed = true;
+ }
+ } else if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE && !service_offered) {
+ EXPECT_TRUE(e->is_service_entry());
+ EXPECT_EQ(vsomeip::sd::entry_type_e::OFFER_SERVICE, e->get_type());
+ EXPECT_EQ(1u,e->get_num_options(1));
+ EXPECT_EQ(std::uint32_t(0xFFFFFF), e->get_ttl());
+ EXPECT_EQ(someip_tp_test::service.service_id, e->get_service());
+ EXPECT_EQ(someip_tp_test::service.instance_id, e->get_instance());
+ EXPECT_EQ(1u, sd_msg.get_options().size());
+ if (e->get_type() == vsomeip::sd::entry_type_e::OFFER_SERVICE) {
+ std::shared_ptr<vsomeip::sd::serviceentry_impl> its_casted_entry =
+ std::static_pointer_cast<vsomeip::sd::serviceentry_impl>(e);
+ EXPECT_EQ(0u, its_casted_entry->get_minor_version());
+ }
+ offer_received.set_value();
+ service_offered = true;
+ }
+ }
+ if (service_offered && client_subscribed) {
+ keep_receiving = false;
+ }
+ } else {
+ ADD_FAILURE() << " received non-sd message";
+ return;
+ }
+ }
+ }
+ });
+
+ std::thread send_thread([&]() {
+ boost::system::error_code ec;
+ try {
+
+ // wait until a offer was received
+ if (std::future_status::timeout == offer_received.get_future().wait_for(std::chrono::seconds(10))) {
+ ADD_FAILURE() << "Didn't receive offer within time";
+ return;
+ }
+
+ {
+ std::lock_guard<std::mutex> its_lock(udp_sd_socket_mutex);
+ subscribe_at_master(&udp_sd_socket);
+ }
+
+ std::mutex all_fragments_received_mutex_;
+ std::condition_variable all_fragments_received_cond_;
+ bool wait_for_all_response_fragments_received_(true);
+ std::uint32_t received_responses(0);
+ bool wait_for_all_event_fragments_received_(true);
+
+ std::thread udp_client_receive_thread([&]() {
+ bool keep_receiving(true);
+ std::vector<std::uint8_t> receive_buffer(4096);
+ while (keep_receiving) {
+ boost::system::error_code error;
+ std::size_t bytes_transferred = udp_client_socket.receive(
+ boost::asio::buffer(receive_buffer, receive_buffer.capacity()), 0, error);
+ if (error) {
+ keep_receiving = false;
+ ADD_FAILURE() << __func__ << " error: " << error.message();
+ return;
+ } else {
+ std::uint32_t its_pos = 0;
+
+ while (bytes_transferred > 0) {
+ const std::uint32_t its_message_size = VSOMEIP_BYTES_TO_LONG(
+ receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN],
+ receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN + 1],
+ receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN + 2],
+ receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN + 3]) + VSOMEIP_SOMEIP_HEADER_SIZE;
+ std::cout << __LINE__ << ": received response " << its_message_size << std::endl;
+ vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0);
+
+ vsomeip::service_t its_service = VSOMEIP_BYTES_TO_WORD(receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN],
+ receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MAX]);
+ vsomeip::method_t its_method = VSOMEIP_BYTES_TO_WORD(receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN],
+ receive_buffer[its_pos + VSOMEIP_METHOD_POS_MAX]);
+
+ vsomeip::message_impl msg;
+ EXPECT_TRUE(msg.deserialize(&its_deserializer));
+ if (msg.get_message_type() == vsomeip::message_type_e::MT_RESPONSE) {
+ EXPECT_EQ(vsomeip::message_type_e::MT_RESPONSE, msg.get_message_type());
+ EXPECT_EQ(someip_tp_test::service.service_id, msg.get_service());
+ } else if (msg.get_message_type() == vsomeip::message_type_e::MT_NOTIFICATION) {
+ std::cout << __LINE__ << ": received event" << std::endl;
+ } else if (vsomeip::tp::tp::tp_flag_is_set(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS]) &&
+ vsomeip::tp::tp::tp_flag_unset(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS]) == vsomeip::message_type_e::MT_RESPONSE) {
+ EXPECT_EQ(someip_tp_test::service.service_id, its_service);
+ EXPECT_EQ(someip_tp_test::service.method_id, its_method);
+ auto its_buffer = std::make_shared<vsomeip::message_buffer_t>(&receive_buffer[its_pos], &receive_buffer[its_pos] + its_message_size);
+
+ fragments_response_of_master_.push_back(its_buffer);
+ if (fragments_response_of_master_.size() == someip_tp_test::number_of_fragments) {
+ std::lock_guard<std::mutex> its_lock(all_fragments_received_mutex_);
+ wait_for_all_response_fragments_received_ = false;
+ std::cout << __LINE__ << ": received all response fragments as client" << std::endl;
+ all_fragments_received_cond_.notify_one();
+ if (++received_responses == 2 && !wait_for_all_event_fragments_received_) {
+ std::cout << __LINE__ << ": received all responses as client --> Finished" << std::endl;
+ keep_receiving = false;
+ }
+ }
+ } else if (vsomeip::tp::tp::tp_flag_is_set(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS]) &&
+ vsomeip::tp::tp::tp_flag_unset(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS]) == vsomeip::message_type_e::MT_NOTIFICATION) {
+ std::cout << __LINE__ << ": received event fragment" << std::endl;
+ EXPECT_EQ(someip_tp_test::service.service_id, its_service);
+ EXPECT_EQ(someip_tp_test::service.event_id, its_method);
+ auto its_buffer = std::make_shared<vsomeip::message_buffer_t>(&receive_buffer[its_pos], &receive_buffer[its_pos] + its_message_size);
+ fragments_event_from_master_.push_back(its_buffer);
+ if (fragments_event_from_master_.size() == someip_tp_test::number_of_fragments) {
+ std::lock_guard<std::mutex> its_lock(all_fragments_received_mutex_);
+ wait_for_all_event_fragments_received_ = false;
+ std::cout << __LINE__ << ": received all event fragments as client --> Finished" << std::endl;
+ all_fragments_received_cond_.notify_one();
+ if (received_responses == 2) {
+ keep_receiving = false;
+ }
+ }
+
+ }
+ its_pos += its_message_size;
+ bytes_transferred -= its_message_size;
+ }
+ }
+ }
+ });
+
+ // send SOMEI-TP message fragmented into 6 parts to service:
+ boost::asio::ip::udp::socket::endpoint_type target_service(address_remote_, 30001);
+
+ std::unique_lock<std::mutex> its_lock(all_fragments_received_mutex_);
+ for (const order_e mode : {order_e::ASCENDING, order_e::DESCENDING}) {
+ create_fragments(someip_tp_test::number_of_fragments, someip_tp_test::service.service_id,
+ someip_tp_test::service.instance_id,
+ someip_tp_test::service.method_id,
+ vsomeip::message_type_e::MT_REQUEST,
+ vsomeip::ANY_CLIENT, 0xffff,
+ &fragments_request_to_master_,
+ (test_mode_ == someip_tp_test::test_mode_e::OVERLAP ||
+ test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ?
+ vsomeip::tp::tp::tp_max_segment_length_ - 160 :
+ vsomeip::tp::tp::tp_max_segment_length_);
+ if (mode == order_e::ASCENDING) {
+ if (test_mode_ == someip_tp_test::test_mode_e::MIXED) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ } else {
+ auto its_indexes = {4, 1, 3, 5, 2, 0};
+ std::cout << __LINE__ << ": using following predefined sequence to send request to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ for (int i : its_indexes) {
+ udp_client_socket.send_to(boost::asio::buffer(*fragments_request_to_master_[i]), target_service);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ } else {
+ auto its_indexes = {0,1,3,5,2,4};
+ std::cout << __LINE__ << ": using following predefined sequence to send request to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ // increase third segment by 16 byte at front and back
+ increase_segment_front_back(fragments_request_to_master_[2], 16);
+ increase_segment_front(fragments_request_to_master_[4], 16);
+ for (int i : its_indexes) {
+ udp_client_socket.send_to(boost::asio::buffer(*fragments_request_to_master_[i]), target_service);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ for (auto iter = fragments_request_to_master_.begin();
+ iter != fragments_request_to_master_.end(); iter++) {
+ udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service);
+ // send insert 2nd fragment twice
+ if (iter == fragments_request_to_master_.begin() + 1) {
+ udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service);
+ }
+ }
+ } else {
+ if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) {
+ if (someip_tp_test::number_of_fragments < 3) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // send a request fragment with a different session ID first
+ vsomeip::message_buffer_t msg_incomplete(*fragments_request_to_master_[2]);
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x33;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x33;
+ udp_client_socket.send_to(boost::asio::buffer(msg_incomplete), target_service);
+ // send a request from a different src port as well to test cleanup
+ boost::asio::ip::udp::socket udp_client_socket2(io_,
+ boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30004));
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xcc;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xcc;
+ udp_client_socket2.send_to(boost::asio::buffer(msg_incomplete), target_service);
+ boost::system::error_code ec;
+ udp_client_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec);
+ udp_client_socket2.close(ec);
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ increase_segment_back(fragments_request_to_master_[1], 16);
+ }
+ for (const auto& fragment : fragments_request_to_master_) {
+ udp_client_socket.send_to(boost::asio::buffer(*fragment), target_service);
+ }
+ }
+ } else if (mode == order_e::DESCENDING) {
+ if (test_mode_ == someip_tp_test::test_mode_e::MIXED) {
+ std::vector<int> its_indexes = create_shuffled_seqeuence(someip_tp_test::number_of_fragments);
+ std::cout << __LINE__ << ": using following random sequence to send request to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ for (int i : its_indexes) {
+ udp_client_socket.send_to(boost::asio::buffer(*fragments_request_to_master_[i]), target_service);
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ } else {
+ auto its_indexes = {5,3,2,4,1,0};
+ std::cout << __LINE__ << ": using following predefined sequence to send request to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ // increase third segment by 16 byte at front and back
+ increase_segment_front_back(fragments_request_to_master_[4], 16);
+ for (int i : its_indexes) {
+ udp_client_socket.send_to(boost::asio::buffer(*fragments_request_to_master_[i]), target_service);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ for (auto iter = fragments_request_to_master_.rbegin();
+ iter != fragments_request_to_master_.rend(); iter++) {
+ udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service);
+ // send insert 2nd last fragment twice
+ if (iter == fragments_request_to_master_.rbegin() + 1) {
+ udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service);
+ }
+ }
+ } else {
+ if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) {
+ if (someip_tp_test::number_of_fragments < 4) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // send a request fragment with a different session ID first
+ vsomeip::message_buffer_t msg_incomplete(*fragments_request_to_master_[3]);
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x77;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x77;
+ udp_client_socket.send_to(boost::asio::buffer(msg_incomplete), target_service);
+
+ // send a request from a different src port as well to test cleanup
+ boost::asio::ip::udp::socket udp_client_socket2(io_,
+ boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 30005));
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xdd;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xdd;
+ udp_client_socket2.send_to(boost::asio::buffer(msg_incomplete), target_service);
+ boost::system::error_code ec;
+ udp_client_socket2.shutdown(boost::asio::socket_base::shutdown_both, ec);
+ udp_client_socket2.close(ec);
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (someip_tp_test::number_of_fragments < 5) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // increase second last segment by 16 byte
+ increase_segment_back(fragments_request_to_master_[4], 16);
+ }
+ for (auto iter = fragments_request_to_master_.rbegin(); iter != fragments_request_to_master_.rend(); iter++) {
+ udp_client_socket.send_to(boost::asio::buffer(*(*iter)), target_service);
+ }
+ }
+ }
+ {
+ while (wait_for_all_response_fragments_received_) {
+ if (std::cv_status::timeout ==
+ all_fragments_received_cond_.wait_for(its_lock,
+ std::chrono::seconds(20))) {
+ ADD_FAILURE() << "Didn't receive response to"
+ " fragmented message within time: " << std::uint32_t(mode);
+ return;
+ } else {
+ EXPECT_EQ(someip_tp_test::number_of_fragments, fragments_request_to_master_.size());
+ // create complete message from request
+ if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (mode == ASCENDING) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // decrease second segment by 16 byte
+ decrease_segment_back(fragments_request_to_master_[1], 16);
+ } else if (mode == DESCENDING) {
+ if (someip_tp_test::number_of_fragments < 5) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // decrease fourth segment by 16 byte
+ decrease_segment_back(fragments_request_to_master_[4], 16);
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ // remove the additional inserted bytes which weren't accepted on
+ // test masterside as they were overlapping
+ if (mode == ASCENDING) {
+ decrease_segment_front_back(fragments_request_to_master_[2], 16);
+ decrease_segment_front(fragments_request_to_master_[4], 16);
+ } else {
+ decrease_segment_front_back(fragments_request_to_master_[4], 16);
+ }
+ }
+ vsomeip::message_buffer_t its_request = create_full_message(fragments_request_to_master_);
+ if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP ||
+ test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE +
+ someip_tp_test::number_of_fragments * (someip_tp_test::max_segment_size - 160),
+ its_request.size());
+ } else {
+ EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE +
+ someip_tp_test::number_of_fragments * someip_tp_test::max_segment_size,
+ its_request.size());
+ }
+ if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP && mode == ASCENDING) {
+ // response contains the additional 16 bytes of 2nd fragment instead
+ // of beginning of the 3rd fragment
+ for (std::uint32_t i = 0; i < 16; i++) {
+ its_request[VSOMEIP_PAYLOAD_POS + 2 * (someip_tp_test::max_segment_size - 160) + i] = 0xff;
+ }
+ }
+
+ // create complete message from response
+ vsomeip::message_buffer_t its_response = create_full_message(fragments_response_of_master_);
+ if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP ||
+ test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE +
+ someip_tp_test::number_of_fragments * (someip_tp_test::max_segment_size - 160),
+ its_response.size());
+ } else {
+ EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE +
+ someip_tp_test::number_of_fragments * someip_tp_test::max_segment_size,
+ its_response.size());
+ }
+ // change message type of response to request again
+ its_response[VSOMEIP_MESSAGE_TYPE_POS] = static_cast<vsomeip::byte_t>(vsomeip::message_type_e::MT_REQUEST);
+ // request and response should now be equal
+ EXPECT_EQ(its_response.size(), its_request.size());
+ EXPECT_EQ(its_response, its_request);
+ EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_response[0]),
+ static_cast<void*>(&its_request[0]),
+ its_response.size()));
+ fragments_response_of_master_.clear();
+ }
+ }
+ wait_for_all_response_fragments_received_ = true;
+ }
+ fragments_request_to_master_.clear();
+ }
+
+ while (wait_for_all_event_fragments_received_) {
+ if (std::cv_status::timeout ==
+ all_fragments_received_cond_.wait_for(its_lock,
+ std::chrono::seconds(20))) {
+ ADD_FAILURE() << "Didn't receive fragmented event from "
+ " master within time";
+ }
+ }
+ // check if received event is correct
+ {
+ EXPECT_EQ(someip_tp_test::number_of_fragments, fragments_event_from_master_.size());
+ // create complete message from event
+ vsomeip::message_buffer_t its_event = create_full_message(fragments_event_from_master_);
+ vsomeip::session_t its_event_session =
+ VSOMEIP_BYTES_TO_WORD(its_event[VSOMEIP_SESSION_POS_MIN],
+ its_event[VSOMEIP_SESSION_POS_MAX]);
+
+ std::vector<vsomeip::message_buffer_ptr_t> its_cmp_event_fragments;
+ create_fragments(someip_tp_test::number_of_fragments,
+ someip_tp_test::service.service_id,
+ someip_tp_test::service.instance_id,
+ someip_tp_test::service.event_id,
+ vsomeip::message_type_e::MT_NOTIFICATION,
+ 0x0, its_event_session, &its_cmp_event_fragments,
+ (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) ?
+ vsomeip::tp::tp::tp_max_segment_length_ - 160 :
+ vsomeip::tp::tp::tp_max_segment_length_);
+ vsomeip::message_buffer_t its_cmp_event = create_full_message(its_cmp_event_fragments);
+ EXPECT_EQ(its_cmp_event.size(), its_event.size());
+ EXPECT_EQ(its_cmp_event, its_event);
+ EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_cmp_event[0]),
+ static_cast<void*>(&its_event[0]),
+ its_cmp_event.size()));
+ }
+ its_lock.unlock();
+ udp_client_receive_thread.join();
+ } catch (const std::exception& _e) {
+ ADD_FAILURE() << "catched exception: " << _e.what();
+ }
+ });
+
+ std::mutex all_fragments_received_as_server_mutex_;
+ std::unique_lock<std::mutex> all_fragments_received_as_server_lock(all_fragments_received_as_server_mutex_);
+ std::condition_variable all_fragments_received_as_server_cond_;
+ bool wait_for_all_fragments_received_as_server_(true);
+ std::atomic<std::uint16_t> remote_client_request_port(0);
+
+ std::thread udp_server_send_thread([&]() {
+ // wait until client subscribed
+ if (std::future_status::timeout == remote_client_subscribed.get_future().wait_for(std::chrono::seconds(10))) {
+ ADD_FAILURE() << "Client didn't subscribe within time";
+ return;
+ }
+
+ // send fragmented event to the master
+ boost::asio::ip::udp::socket::endpoint_type master_client(address_remote_, remote_client_subscription_port);
+ for (const order_e mode : {order_e::ASCENDING, order_e::DESCENDING}) {
+ create_fragments(someip_tp_test::number_of_fragments,
+ someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id,
+ someip_tp_test::service_slave.event_id,
+ vsomeip::message_type_e::MT_NOTIFICATION,
+ vsomeip::ANY_CLIENT, 0xffff,
+ &fragments_event_to_master_,
+ (test_mode_ == someip_tp_test::test_mode_e::OVERLAP ||
+ test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ?
+ vsomeip::tp::tp::tp_max_segment_length_ - 160 :
+ vsomeip::tp::tp::tp_max_segment_length_);
+ if (mode == order_e::ASCENDING) {
+ if (test_mode_ == someip_tp_test::test_mode_e::MIXED) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ } else {
+ auto its_indexes = {2, 3, 5, 1, 4, 0};
+ std::cout << __LINE__ << ": using following predefined sequence to send event to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ for (int i : its_indexes) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragments_event_to_master_[i]), master_client);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ } else {
+ auto its_indexes = {0,2,4,5,1,3};
+ std::cout << __LINE__ << ": using following predefined sequence to send event to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ // increase second segment by 16 byte at front and back
+ increase_segment_front_back(fragments_event_to_master_[1], 16);
+ increase_segment_front(fragments_event_to_master_[3], 16);
+
+ for (int i : its_indexes) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragments_event_to_master_[i]), master_client);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ for (auto iter = fragments_event_to_master_.begin();
+ iter != fragments_event_to_master_.end(); iter++) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ // send insert 2nd fragment twice
+ if (iter == fragments_event_to_master_.begin() + 1) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ // send oversized fragment as well
+ increase_segment_back(*iter, 4);
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ decrease_segment_back(*iter, 4);
+ }
+ }
+ } else {
+ if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) {
+ if (someip_tp_test::number_of_fragments < 3) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // send an event fragment with a different session ID first
+ vsomeip::message_buffer_t msg_incomplete(*fragments_event_to_master_[2]);
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x44;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x44;
+ udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client);
+ // send a request with a different service ID as well to test cleanup
+ msg_incomplete[VSOMEIP_SERVICE_POS_MIN] = 0xdd;
+ msg_incomplete[VSOMEIP_SERVICE_POS_MAX] = 0xdd;
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xdd;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xdd;
+ udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client);
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // increase second segment by 16 byte
+ increase_segment_back(fragments_event_to_master_[1], 16);
+
+ // send one oversize message as well
+ std::vector<vsomeip::message_buffer_ptr_t> oversized_event;
+ create_fragments(someip_tp_test::number_of_fragments + 1,
+ someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id,
+ someip_tp_test::service_slave.event_id,
+ vsomeip::message_type_e::MT_NOTIFICATION,
+ vsomeip::ANY_CLIENT, 0xffff,
+ &oversized_event,
+ vsomeip::tp::tp::tp_max_segment_length_);
+ for (const auto& fragment : oversized_event) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragment), master_client);
+ }
+ }
+ for (const auto& fragment : fragments_event_to_master_) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragment), master_client);
+ }
+ }
+ } else if (mode == order_e::DESCENDING) {
+ if (test_mode_ == someip_tp_test::test_mode_e::MIXED) {
+ std::vector<int> its_indexes = create_shuffled_seqeuence(someip_tp_test::number_of_fragments);
+ std::cout << __LINE__ << ": using following random sequence to send event to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ for ( int i : its_indexes) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragments_event_to_master_[i]), master_client);
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ } else {
+ auto its_indexes = {5,3,2,1,0,4};
+ std::cout << __LINE__ << ": using following predefined sequence to send event to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ // increase second last segment by 16 byte at front and back
+ increase_segment_front_back(fragments_event_to_master_[4], 16);
+ // update length
+ *(reinterpret_cast<vsomeip::length_t*>(&((*fragments_event_to_master_[4])[VSOMEIP_LENGTH_POS_MIN]))) =
+ htonl(static_cast<vsomeip::length_t>(fragments_event_to_master_[4]->size() - VSOMEIP_SOMEIP_HEADER_SIZE));
+ for (int i : its_indexes) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragments_event_to_master_[i]), master_client);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ for (auto iter = fragments_event_to_master_.rbegin();
+ iter != fragments_event_to_master_.rend(); iter++) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ // send insert 2nd last fragment twice
+ if (iter == fragments_event_to_master_.rbegin() + 1) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ }
+ }
+ } else {
+ if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) {
+ if (someip_tp_test::number_of_fragments < 4) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // send an event fragment with a different session ID first
+ vsomeip::message_buffer_t msg_incomplete(*fragments_event_to_master_[3]);
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x55;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x55;
+ udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client);
+ // send a request with a different service ID as well to test cleanup
+ msg_incomplete[VSOMEIP_SERVICE_POS_MIN] = 0xbb;
+ msg_incomplete[VSOMEIP_SERVICE_POS_MAX] = 0xbb;
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xbb;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xbb;
+ udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client);
+
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (someip_tp_test::number_of_fragments < 5) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // increase second last segment by 16 byte
+ increase_segment_back(fragments_event_to_master_[4], 16);
+ }
+ for (auto iter = fragments_event_to_master_.rbegin(); iter != fragments_event_to_master_.rend(); iter++) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ }
+ }
+ }
+ std::cout << __LINE__ << ": send event to master " << std::uint32_t(mode) << std::endl;
+ }
+
+ for (const order_e mode : {order_e::ASCENDING, order_e::DESCENDING}) {
+ while (wait_for_all_fragments_received_as_server_) {
+ if (std::cv_status::timeout ==
+ all_fragments_received_as_server_cond_.wait_for(all_fragments_received_as_server_lock,
+ std::chrono::seconds(20))) {
+ ADD_FAILURE() << "Didn't receive request from client within time: " << std::uint32_t(mode);
+ return;
+ } else {
+ EXPECT_EQ(someip_tp_test::number_of_fragments, fragments_received_as_server_.size());
+ // create complete message from request of client
+ vsomeip::message_buffer_t its_request = create_full_message(fragments_received_as_server_);
+ if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP ||
+ test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE +
+ someip_tp_test::number_of_fragments * (someip_tp_test::max_segment_size - 160),
+ its_request.size());
+ } else {
+ EXPECT_EQ(VSOMEIP_FULL_HEADER_SIZE +
+ someip_tp_test::number_of_fragments * someip_tp_test::max_segment_size,
+ its_request.size());
+ }
+ const vsomeip::client_t its_request_client =
+ VSOMEIP_BYTES_TO_WORD(its_request[VSOMEIP_CLIENT_POS_MIN],
+ its_request[VSOMEIP_CLIENT_POS_MAX]);
+ const vsomeip::session_t its_request_session =
+ VSOMEIP_BYTES_TO_WORD(its_request[VSOMEIP_SESSION_POS_MIN],
+ its_request[VSOMEIP_SESSION_POS_MAX]);
+ create_fragments(someip_tp_test::number_of_fragments,
+ someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id,
+ someip_tp_test::service_slave.method_id,
+ vsomeip::message_type_e::MT_RESPONSE,
+ its_request_client,
+ its_request_session,
+ &fragments_response_to_master_,
+ (test_mode_ == someip_tp_test::test_mode_e::OVERLAP ||
+ test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ?
+ vsomeip::tp::tp::tp_max_segment_length_ - 160:
+ vsomeip::tp::tp::tp_max_segment_length_);
+ // create complete message from response
+ vsomeip::message_buffer_t its_response = create_full_message(fragments_response_to_master_);
+ // change the message type of the response to request for comparison
+ its_response[VSOMEIP_MESSAGE_TYPE_POS] = static_cast<vsomeip::byte_t>(vsomeip::message_type_e::MT_REQUEST);
+
+ EXPECT_EQ(its_response.size(), its_request.size());
+ EXPECT_EQ(its_response, its_request);
+ EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_response[0]),
+ static_cast<void*>(&its_request[0]),
+ its_response.size()));
+ // send back response
+ fragments_received_as_server_.clear();
+ EXPECT_GT(remote_client_request_port, 0);
+ boost::asio::ip::udp::socket::endpoint_type master_client(address_remote_, remote_client_request_port);
+ if (mode == order_e::ASCENDING) {
+ if (test_mode_ == someip_tp_test::test_mode_e::MIXED) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ } else {
+ auto its_indexes = {4,2,0,1,3,5};
+ std::cout << __LINE__ << ": using following predefined sequence to send back response to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ for (int i : its_indexes) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragments_response_to_master_[i]), master_client);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ } else {
+ auto its_indexes = {0,2,4,3,5,1};
+ std::cout << __LINE__ << ": using following predefined sequence to send response to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ // increase fourth segment by 16 byte at front and back
+ increase_segment_front_back(fragments_response_to_master_[3], 16);
+ increase_segment_front(fragments_response_to_master_[1], 16);
+ for (int i : its_indexes) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragments_response_to_master_[i]), master_client);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ for (auto iter = fragments_response_to_master_.begin();
+ iter != fragments_response_to_master_.end(); iter++) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ // send 2nd fragment twice
+ if (iter == fragments_response_to_master_.begin() + 1) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ // send a fragment with invalid segment size as well
+ decrease_segment_back(*iter, 16);
+ increase_segment_back(*iter, 7);
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ increase_segment_back(*iter, 9);
+ }
+ }
+ } else {
+ if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) {
+ if (someip_tp_test::number_of_fragments < 5) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // send an event fragment with a different session ID first
+ vsomeip::message_buffer_t msg_incomplete(*fragments_response_to_master_[4]);
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x99;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x99;
+ udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client);
+ // send a request with a different service ID as well to test cleanup
+ msg_incomplete[VSOMEIP_SERVICE_POS_MIN] = 0xaa;
+ msg_incomplete[VSOMEIP_SERVICE_POS_MAX] = 0xaa;
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xaa;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xaa;
+ udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client);
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // increase second segment by 16 byte
+ increase_segment_back(fragments_response_to_master_[1], 16);
+ }
+ for (const auto& frag : fragments_response_to_master_) {
+ udp_server_socket.send_to(boost::asio::buffer(*frag), master_client);
+ }
+ }
+ } else if (mode == order_e::DESCENDING) {
+ if (test_mode_ == someip_tp_test::test_mode_e::MIXED) {
+ std::vector<int> its_indexes = create_shuffled_seqeuence(someip_tp_test::number_of_fragments);
+ std::cout << __LINE__ << ": using following random sequence to send back response to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ for ( int i : its_indexes) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragments_response_to_master_[i]), master_client);
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) {
+ if (someip_tp_test::number_of_fragments != 6) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ } else {
+ auto its_indexes = {5,3,2,1,4,0};
+ std::cout << __LINE__ << ": using following predefined sequence to send response to master: ";
+ for (auto i : its_indexes) { std::cout << i << ", "; }
+ std::cout << std::endl;
+ // increase fith segment by 16 byte at front and back
+ increase_segment_front_back(fragments_response_to_master_[4], 16);
+ for (int i : its_indexes) {
+ udp_server_socket.send_to(boost::asio::buffer(*fragments_response_to_master_[i]), master_client);
+ }
+ }
+ } else if (test_mode_ == someip_tp_test::test_mode_e::DUPLICATE) {
+ if (someip_tp_test::number_of_fragments < 2) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ for (auto iter = fragments_response_to_master_.rbegin();
+ iter != fragments_response_to_master_.rend(); iter++) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ // send insert 2nd last fragment twice
+ if (iter == fragments_response_to_master_.rbegin() + 1) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ }
+ }
+ } else {
+ if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) {
+ if (someip_tp_test::number_of_fragments < 4) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // send an event fragment with a different session ID first
+ vsomeip::message_buffer_t msg_incomplete(*fragments_response_to_master_[3]);
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0x66;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0x66;
+ udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client);
+ // send a request with a different service ID as well to test cleanup
+ msg_incomplete[VSOMEIP_SERVICE_POS_MIN] = 0xef;
+ msg_incomplete[VSOMEIP_SERVICE_POS_MAX] = 0xef;
+ msg_incomplete[VSOMEIP_SESSION_POS_MIN] = 0xef;
+ msg_incomplete[VSOMEIP_SESSION_POS_MAX] = 0xef;
+ udp_server_socket.send_to(boost::asio::buffer(msg_incomplete), master_client);
+ } else if (test_mode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (someip_tp_test::number_of_fragments < 5) {
+ ADD_FAILURE() << "line: " << __LINE__ << " needs adaption as number_of_fragments changed";
+ return;
+ }
+ // increase second last segment by 16 byte
+ increase_segment_back(fragments_response_to_master_[4], 16);
+ }
+ for (auto iter = fragments_response_to_master_.rbegin();
+ iter != fragments_response_to_master_.rend(); iter++) {
+ udp_server_socket.send_to(boost::asio::buffer(*(*iter)), master_client);
+ }
+ }
+ }
+ }
+ }
+ wait_for_all_fragments_received_as_server_ = true;
+ }
+ });
+
+ std::thread udp_server_receive_thread([&]() {
+ {
+ std::lock_guard<std::mutex> its_lock(udp_sd_socket_mutex);
+ offer_service(&udp_sd_socket);
+ }
+
+ bool keep_receiving(true);
+ std::vector<std::uint8_t> receive_buffer(4096);
+ while (keep_receiving) {
+ boost::system::error_code error;
+ boost::asio::ip::udp::socket::endpoint_type its_remote_endpoint;
+ std::size_t bytes_transferred = udp_server_socket.receive_from(
+ boost::asio::buffer(receive_buffer, receive_buffer.capacity()), its_remote_endpoint, 0, error);
+ if (error) {
+ keep_receiving = false;
+ ADD_FAILURE() << __func__ << " error: " << error.message();
+ return;
+ } else {
+ remote_client_request_port = its_remote_endpoint.port();
+ std::uint32_t its_pos = 0;
+ while (bytes_transferred > 0) {
+ const std::uint32_t its_message_size = VSOMEIP_BYTES_TO_LONG(
+ receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN],
+ receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN + 1],
+ receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN + 2],
+ receive_buffer[its_pos + VSOMEIP_LENGTH_POS_MIN + 3]) + VSOMEIP_SOMEIP_HEADER_SIZE;
+ std::cout << __LINE__ << ": received request from master " << its_message_size << std::endl;
+ vsomeip::deserializer its_deserializer(&receive_buffer[its_pos], its_message_size, 0);
+
+ vsomeip::service_t its_service = VSOMEIP_BYTES_TO_WORD(receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MIN],
+ receive_buffer[its_pos + VSOMEIP_SERVICE_POS_MAX]);
+ vsomeip::method_t its_method = VSOMEIP_BYTES_TO_WORD(receive_buffer[its_pos + VSOMEIP_METHOD_POS_MIN],
+ receive_buffer[its_pos + VSOMEIP_METHOD_POS_MAX]);
+ EXPECT_EQ(someip_tp_test::service_slave.service_id, its_service);
+ EXPECT_EQ(someip_tp_test::service_slave.method_id, its_method);
+ vsomeip::message_impl msg;
+ EXPECT_TRUE(msg.deserialize(&its_deserializer));
+ if (vsomeip::tp::tp::tp_flag_is_set(receive_buffer[its_pos + VSOMEIP_MESSAGE_TYPE_POS])) {
+ auto its_buffer = std::make_shared<vsomeip::message_buffer_t>(&receive_buffer[its_pos], &receive_buffer[its_pos] + its_message_size);
+
+ fragments_received_as_server_.push_back(its_buffer);
+ if (fragments_received_as_server_.size() == someip_tp_test::number_of_fragments) {
+ std::lock_guard<std::mutex> its_lock(all_fragments_received_as_server_mutex_);
+ wait_for_all_fragments_received_as_server_ = false;
+ std::cout << __LINE__ << ": received all fragments as server" << std::endl;
+ all_fragments_received_as_server_cond_.notify_one();
+ static int received_requests = 0;
+ if (++received_requests == 2) {
+ std::cout << __LINE__ << ": received all requests as server --> Finished" << std::endl;
+ keep_receiving = false;
+ }
+ }
+ }
+ its_pos += its_message_size;
+ bytes_transferred -= its_message_size;
+ }
+ }
+ }
+ });
+
+ send_thread.join();
+ sd_receive_thread.join();
+ udp_server_receive_thread.join();
+ udp_server_send_thread.join();
+
+ if (test_mode_ == someip_tp_test::test_mode_e::INCOMPLETE) {
+ std::cout << "Sleeping to let cleanup for unfinished TP message "
+ "trigger on master side..." << std::endl;
+ std::this_thread::sleep_for(std::chrono::seconds(11));
+ }
+ // shutdown the server
+ call_shutdown_method();
+
+ boost::system::error_code ec;
+ udp_sd_socket.shutdown(boost::asio::socket_base::shutdown_both, ec);
+ udp_sd_socket.close(ec);
+ udp_client_socket.shutdown(boost::asio::socket_base::shutdown_both, ec);
+ udp_client_socket.close(ec);
+ udp_server_socket.shutdown(boost::asio::socket_base::shutdown_both, ec);
+ udp_server_socket.close(ec);
+}
+
+#if defined(__linux__) || defined(ANDROID)
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ if(argc < 3) {
+ std::cerr << "Please pass an target, local IP address and test mode to this binary like: "
+ << argv[0] << " 10.0.3.1 10.0.3.202 TP_IN_SEQUENCE" << std::endl;
+ std::cerr << "Testmodes are [ IN_SEQUENCE, MIXED, INCOMPLETE, OVERLAP, OVERLAP_FRONT_BACK ]" << std::endl;
+ } else {
+ remote_address = argv[1];
+ local_address = argv[2];
+ std::string its_testmode = argv[3];
+ if (its_testmode == std::string("IN_SEQUENCE")) {
+ ::testing::GTEST_FLAG(filter) = "*send_in_mode/0";
+ } else if (its_testmode == std::string("MIXED")) {
+ ::testing::GTEST_FLAG(filter) = "*send_in_mode/1";
+ } else if (its_testmode == std::string("INCOMPLETE")) {
+ ::testing::GTEST_FLAG(filter) = "*send_in_mode/2";
+ } else if (its_testmode == std::string("DUPLICATE")) {
+ ::testing::GTEST_FLAG(filter) = "*send_in_mode/3";
+ } else if (its_testmode == std::string("OVERLAP")) {
+ ::testing::GTEST_FLAG(filter) = "*send_in_mode/4";
+ } else if (its_testmode == std::string("OVERLAP_FRONT_BACK")) {
+ ::testing::GTEST_FLAG(filter) = "*send_in_mode/5";
+ }
+ }
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/network_tests/someip_tp_tests/someip_tp_test_service.cpp b/test/network_tests/someip_tp_tests/someip_tp_test_service.cpp
new file mode 100644
index 0000000..26fdf6d
--- /dev/null
+++ b/test/network_tests/someip_tp_tests/someip_tp_test_service.cpp
@@ -0,0 +1,413 @@
+// Copyright (C) 2014-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <chrono>
+#include <condition_variable>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <thread>
+#include <map>
+#include <algorithm>
+#include <atomic>
+#include <future>
+#include <cstring>
+
+#include <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+#include <vsomeip/internal/logger.hpp>
+#include "../../implementation/endpoints/include/tp.hpp"
+
+#include "someip_tp_test_globals.hpp"
+
+class someip_tp_test_service {
+public:
+ someip_tp_test_service(struct someip_tp_test::service_info _service_info, someip_tp_test::test_mode_e _testmode) :
+ service_info_(_service_info),
+ testmode_(_testmode),
+ app_(vsomeip::runtime::get()->create_application("someip_tp_test_service")),
+ wait_until_registered_(true),
+ wait_until_shutdown_method_called_(true),
+ wait_for_slave_subscription_(true),
+ number_notifications_of_slave_(0x0),
+ wait_for_slave_service_available_(true),
+ wait_for_two_responses_of_slave_(true),
+ number_responses_of_slave_(0),
+ wait_for_two_requests_of_slave_(true),
+ number_requests_from_slave_(0),
+ wait_for_two_notifications_of_slave_(true),
+ offer_thread_(std::bind(&someip_tp_test_service::run, this)) {
+ if (!app_->init()) {
+ ADD_FAILURE() << "Couldn't initialize application";
+ return;
+ }
+ app_->register_state_handler(
+ std::bind(&someip_tp_test_service::on_state, this,
+ std::placeholders::_1));
+
+ // offer field
+ std::set<vsomeip::eventgroup_t> its_eventgroups;
+ its_eventgroups.insert(_service_info.eventgroup_id);
+ app_->offer_event(service_info_.service_id, service_info_.instance_id,
+ service_info_.event_id, its_eventgroups,
+ vsomeip::event_type_e::ET_EVENT, std::chrono::milliseconds::zero(),
+ false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE);
+
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, service_info_.shutdown_method_id,
+ std::bind(&someip_tp_test_service::on_shutdown_method_called, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, service_info_.notify_method_id,
+ std::bind(&someip_tp_test_service::on_notify_method_called, this,
+ std::placeholders::_1));
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, service_info_.method_id,
+ std::bind(&someip_tp_test_service::on_message, this,
+ std::placeholders::_1));
+
+ app_->register_async_subscription_handler(service_info_.service_id,
+ 0x1, service_info_.eventgroup_id,
+ std::bind(&someip_tp_test_service::subscription_handler_async,
+ this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
+ std::placeholders::_4, std::placeholders::_5));
+
+ // request remote service
+ app_->request_service(someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id);
+ its_eventgroups.clear();
+ its_eventgroups.insert(someip_tp_test::service_slave.eventgroup_id);
+ app_->request_event(someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id,
+ someip_tp_test::service_slave.event_id, its_eventgroups,
+ vsomeip::event_type_e::ET_EVENT,
+ vsomeip::reliability_type_e::RT_UNRELIABLE);
+ app_->register_message_handler(someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id,
+ someip_tp_test::service_slave.event_id,
+ std::bind(&someip_tp_test_service::on_notification, this,
+ std::placeholders::_1));
+ app_->subscribe(someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id,
+ someip_tp_test::service_slave.eventgroup_id, 0x0,
+ someip_tp_test::service_slave.event_id);
+ app_->register_availability_handler(someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id,
+ std::bind(&someip_tp_test_service::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
+ app_->register_message_handler(
+ someip_tp_test::service_slave.service_id,
+ someip_tp_test::service_slave.instance_id,
+ someip_tp_test::service_slave.method_id,
+ std::bind(&someip_tp_test_service::on_response_from_slave, this,
+ std::placeholders::_1));
+ app_->start();
+ }
+
+ ~someip_tp_test_service() {
+ offer_thread_.join();
+ }
+
+ void offer() {
+ app_->offer_service(service_info_.service_id, 0x1);
+ }
+
+ void stop() {
+ app_->stop_offer_service(service_info_.service_id, service_info_.instance_id);
+ app_->clear_all_handler();
+ app_->stop();
+ }
+
+ void on_state(vsomeip::state_type_e _state) {
+ VSOMEIP_INFO << "Application " << app_->get_name() << " is "
+ << (_state == vsomeip::state_type_e::ST_REGISTERED ?
+ "registered." : "deregistered.");
+
+ if (_state == vsomeip::state_type_e::ST_REGISTERED) {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_until_registered_ = false;
+ condition_.notify_one();
+ }
+ }
+
+ void on_availability(vsomeip::service_t _service, vsomeip::instance_t _instance, bool _available) {
+ if (_service == someip_tp_test::service_slave.service_id &&
+ _instance == someip_tp_test::service_slave.instance_id &&
+ _available) {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_slave_service_available_ = false;
+ condition_.notify_one();
+ VSOMEIP_INFO << "Service available Service/Instance ["
+ << std::setw(4) << std::setfill('0') << std::hex << _service << "/"
+ << std::setw(4) << std::setfill('0') << std::hex << _instance << "]";
+ }
+ }
+
+ void on_message(const std::shared_ptr<vsomeip::message>& _message) {
+ VSOMEIP_INFO << "Received a message with Client/Session ["
+ << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/"
+ << std::setw(4) << std::setfill('0') << std::hex << _message->get_session()
+ << "] size: " << std::dec << _message->get_payload()->get_length();
+ auto response = vsomeip::runtime::get()->create_response(_message);
+ auto payload = vsomeip::runtime::get()->create_payload(_message->get_payload()->get_data(), _message->get_payload()->get_length());
+ response->set_payload(payload);
+ app_->send(response);
+ if (++number_requests_from_slave_ == 2) {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_two_requests_of_slave_ = false;
+ condition_.notify_one();
+ }
+ }
+
+ void on_notification(const std::shared_ptr<vsomeip::message>& _message) {
+ VSOMEIP_INFO << "Received a notification with Client/Session ["
+ << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/"
+ << std::setw(4) << std::setfill('0') << std::hex << _message->get_session()
+ << "] size: " << std::dec << _message->get_payload()->get_length();
+ EXPECT_EQ(someip_tp_test::service_slave.service_id, _message->get_service());
+ EXPECT_EQ(someip_tp_test::service_slave.event_id, _message->get_method());
+ std::vector<vsomeip::byte_t> its_cmp_data =
+ generate_payload(someip_tp_test::number_of_fragments,
+ (testmode_ == someip_tp_test::test_mode_e::OVERLAP
+ || testmode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ?
+ someip_tp_test::max_segment_size - 160 :
+ someip_tp_test::max_segment_size);
+
+ std::vector<vsomeip::byte_t> its_rcv_data(_message->get_payload()->get_data(),
+ _message->get_payload()->get_data() + _message->get_payload()->get_length());
+ EXPECT_EQ(its_cmp_data.size(), its_rcv_data.size());
+ if (testmode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (number_notifications_of_slave_ == 0) { //ASCENDING with 2nd segment too big
+ for (std::uint32_t i = 0; i < 16; i++) {
+ its_cmp_data[2 * (someip_tp_test::max_segment_size - 160) + i] = 0xff;
+ }
+ } else if (number_notifications_of_slave_ == 1) {
+ // DESCENDING with 2nd last segment too big
+ // no action as successive 4 byte at end of message would
+ // overwrite the beginning of the last segment which was received first
+ }
+ }
+ EXPECT_EQ(its_cmp_data, its_rcv_data);
+ EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_cmp_data[0]),
+ static_cast<void*>(&its_rcv_data[0]),
+ its_cmp_data.size()));
+ if (++number_notifications_of_slave_ == 2) {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_two_notifications_of_slave_ = false;
+ condition_.notify_one();
+ }
+ }
+
+ void on_shutdown_method_called(const std::shared_ptr<vsomeip::message> &_message) {
+ app_->send(vsomeip::runtime::get()->create_response(_message));
+ VSOMEIP_WARNING << "************************************************************";
+ VSOMEIP_WARNING << "Shutdown method called -> going down!";
+ VSOMEIP_WARNING << "************************************************************";
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_until_shutdown_method_called_ = false;
+ condition_.notify_one();
+ }
+
+ void on_notify_method_called(const std::shared_ptr<vsomeip::message> &_message) {
+ (void)_message;
+ std::vector<vsomeip::byte_t> its_data = generate_payload(someip_tp_test::number_of_fragments,
+ (testmode_ == someip_tp_test::test_mode_e::OVERLAP) ?
+ someip_tp_test::max_segment_size - 160 :
+ someip_tp_test::max_segment_size);
+ std::shared_ptr<vsomeip::payload> its_payload = vsomeip::runtime::get()->create_payload();
+ its_payload->set_data(its_data);
+ app_->notify(service_info_.service_id, service_info_.instance_id,
+ service_info_.event_id, its_payload);
+ VSOMEIP_INFO << __func__ << " send event";
+ notify_method_called_.set_value(true);
+ }
+
+ void send_fragmented_request_to_slave() {
+ auto its_req = vsomeip::runtime::get()->create_request();
+ its_req->set_service(someip_tp_test::service_slave.service_id);
+ its_req->set_instance(someip_tp_test::service_slave.instance_id);
+ its_req->set_method(someip_tp_test::service_slave.method_id);
+ std::vector<vsomeip::byte_t> its_data = generate_payload(someip_tp_test::number_of_fragments,
+ (testmode_ == someip_tp_test::test_mode_e::OVERLAP
+ || testmode_ == someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK) ?
+ someip_tp_test::max_segment_size - 160 :
+ someip_tp_test::max_segment_size);
+ auto its_payload = vsomeip::runtime::get()->create_payload();
+ its_payload->set_data(its_data);
+ its_req->set_payload(its_payload);
+ request_send_to_slave_ = its_req;
+ app_->send(its_req);
+ }
+
+ void on_response_from_slave(const std::shared_ptr<vsomeip::message> &_message) {
+ VSOMEIP_INFO << "Received a response from the slave with Client/Session ["
+ << std::setw(4) << std::setfill('0') << std::hex << _message->get_client() << "/"
+ << std::setw(4) << std::setfill('0') << std::hex << _message->get_session()
+ << "] size: " << std::dec << _message->get_payload()->get_length();
+ EXPECT_EQ(someip_tp_test::service_slave.service_id, _message->get_service());
+ EXPECT_EQ(someip_tp_test::service_slave.instance_id, _message->get_instance());
+ EXPECT_EQ(someip_tp_test::service_slave.method_id, _message->get_method());
+ std::vector<vsomeip::byte_t> its_resp_payload(_message->get_payload()->get_data(),
+ _message->get_payload()->get_data() + _message->get_payload()->get_length());
+ std::vector<vsomeip::byte_t> its_req_payload(request_send_to_slave_->get_payload()->get_data(),
+ request_send_to_slave_->get_payload()->get_data() + request_send_to_slave_->get_payload()->get_length());
+ if (testmode_ == someip_tp_test::test_mode_e::OVERLAP) {
+ if (number_responses_of_slave_ == 0) { //ASCENDING with 2nd segment too big
+ for (std::uint32_t i = 0; i < 16; i++) {
+ its_req_payload[2 * (someip_tp_test::max_segment_size - 160) + i] = 0xff;
+ }
+ } else if (number_responses_of_slave_ == 1) {
+ // DESCENDING with 2nd last segment too big
+ // no action as successive 4 byte at end of message would
+ // overwrite the beginning of the last segment which was received first
+ }
+ }
+
+ EXPECT_EQ(its_req_payload.size(), its_resp_payload.size());
+ EXPECT_EQ(its_req_payload, its_resp_payload);
+ EXPECT_EQ(0, std::memcmp(static_cast<void*>(&its_req_payload[0]),
+ static_cast<void*>(&its_resp_payload[0]),
+ its_req_payload.size()));
+
+ if (++number_responses_of_slave_ < 2) {
+ send_fragmented_request_to_slave();
+ } else {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_two_responses_of_slave_ = false;
+ condition_.notify_one();
+ }
+ }
+
+ std::vector<vsomeip::byte_t> generate_payload(std::uint32_t _number_of_fragments,
+ std::uint32_t _segment_size) {
+ std::vector<vsomeip::byte_t> its_data;
+ for (std::uint32_t i = 0; i < _number_of_fragments; i++) {
+ its_data.resize((i * _segment_size) + _segment_size,
+ static_cast<std::uint8_t>(i));
+ }
+ return its_data;
+ }
+
+ void run() {
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Running";
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (wait_until_registered_) {
+ condition_.wait(its_lock);
+ }
+
+ VSOMEIP_DEBUG << "[" << std::setw(4) << std::setfill('0') << std::hex
+ << service_info_.service_id << "] Offering";
+ offer();
+
+ while (wait_for_slave_service_available_) {
+ condition_.wait(its_lock);
+ }
+ send_fragmented_request_to_slave();
+
+ while (wait_for_two_responses_of_slave_) {
+ condition_.wait(its_lock);
+ }
+ EXPECT_EQ(2u, number_responses_of_slave_);
+
+ while (wait_for_two_requests_of_slave_) {
+ condition_.wait(its_lock);
+ }
+ EXPECT_EQ(2u, number_requests_from_slave_);
+
+ while (wait_for_two_notifications_of_slave_) {
+ condition_.wait(its_lock);
+ }
+ EXPECT_EQ(2u, number_notifications_of_slave_);
+
+ while (wait_for_slave_subscription_) {
+ condition_.wait(its_lock);
+ }
+ // slave subscribed --> sent a notification
+ on_notify_method_called(vsomeip::runtime::get()->create_message());
+
+ while (wait_until_shutdown_method_called_) {
+ condition_.wait(its_lock);
+ }
+ stop();
+ }
+
+ void subscription_handler_async(vsomeip::client_t _client, std::uint32_t _uid, std::uint32_t _gid,
+ bool _subscribed, const std::function<void(const bool)>& _cbk) {
+ (void)_uid;
+ (void)_gid;
+ VSOMEIP_WARNING << __func__ << " " << std::hex << _client << " subscribed." << _subscribed;
+ static int was_called = 0;
+ was_called++;
+ EXPECT_EQ(1, was_called);
+ EXPECT_TRUE(_subscribed);
+ _cbk(true);
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_slave_subscription_ = false;
+ condition_.notify_one();
+ }
+
+
+private:
+ struct someip_tp_test::service_info service_info_;
+ someip_tp_test::test_mode_e testmode_;
+ std::shared_ptr<vsomeip::application> app_;
+
+ bool wait_until_registered_;
+ bool wait_until_shutdown_method_called_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ std::atomic<bool> wait_for_slave_subscription_;
+ std::atomic<std::uint32_t> number_notifications_of_slave_;
+ std::promise<bool> notify_method_called_;
+ bool wait_for_slave_service_available_;
+ bool wait_for_two_responses_of_slave_;
+ std::uint32_t number_responses_of_slave_;
+ bool wait_for_two_requests_of_slave_;
+ std::uint32_t number_requests_from_slave_;
+ bool wait_for_two_notifications_of_slave_;
+ std::shared_ptr<vsomeip::message> request_send_to_slave_;
+ std::thread offer_thread_;
+};
+
+someip_tp_test::test_mode_e its_testmode(someip_tp_test::test_mode_e::IN_SEQUENCE);
+
+TEST(someip_someip_tp_test, echo_requests)
+{
+ someip_tp_test_service its_sample(someip_tp_test::service, its_testmode);
+}
+
+
+#if defined(__linux__) || defined(ANDROID)
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc < 2) {
+ std::cerr << "Please pass a test mode to this binary like: "
+ << argv[0] << " IN_SEQUENCE" << std::endl;
+ std::cerr << "Testmodes are [ IN_SEQUENCE, MIXED, INCOMPLETE, DUPLICATE, OVERLAP, OVERLAP_FRONT_BACK ]" << std::endl;
+ exit(1);
+ }
+
+ std::string its_pased_testmode = argv[1];
+ if (its_pased_testmode == std::string("IN_SEQUENCE")) {
+ its_testmode = someip_tp_test::test_mode_e::IN_SEQUENCE;
+ } else if (its_pased_testmode == std::string("MIXED")) {
+ its_testmode = someip_tp_test::test_mode_e::MIXED;
+ } else if (its_pased_testmode == std::string("INCOMPLETE")) {
+ its_testmode = someip_tp_test::test_mode_e::INCOMPLETE;
+ } else if (its_pased_testmode == std::string("DUPLICATE")) {
+ its_testmode = someip_tp_test::test_mode_e::DUPLICATE;
+ } else if (its_pased_testmode == std::string("OVERLAP")) {
+ its_testmode = someip_tp_test::test_mode_e::OVERLAP;
+ } else if (its_pased_testmode == std::string("OVERLAP_FRONT_BACK")) {
+ its_testmode = someip_tp_test::test_mode_e::OVERLAP_FRONT_BACK;
+ }
+
+ return RUN_ALL_TESTS();
+}
+#endif