Skip to content

Commit 2f907e7

Browse files
committed
iox-#2408 Add integration test and delegate call to the new client / server ctor
1 parent 2195a32 commit 2f907e7

File tree

18 files changed

+414
-19
lines changed

18 files changed

+414
-19
lines changed

iceoryx_examples/experimental/node/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,15 @@ iox_add_executable(
4040
FILES ./iox_cpp_node_subscriber.cpp
4141
LIBS iceoryx_posh::iceoryx_posh
4242
)
43+
44+
iox_add_executable(
45+
TARGET iox-cpp-node-server
46+
FILES ./iox_cpp_node_server.cpp
47+
LIBS iceoryx_posh::iceoryx_posh
48+
)
49+
50+
iox_add_executable(
51+
TARGET iox-cpp-node-client
52+
FILES ./iox_cpp_node_client.cpp
53+
LIBS iceoryx_posh::iceoryx_posh
54+
)
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Copyright (c) 2025 by Valour Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
//! [iceoryx includes]
18+
#include "request_and_response_types.hpp"
19+
20+
#include "topic_data.hpp"
21+
22+
#include "iox/optional.hpp"
23+
#include "iox/posh/experimental/node.hpp"
24+
#include "iox/signal_watcher.hpp"
25+
26+
#include <iostream>
27+
28+
constexpr char APP_NAME[] = "iox-cpp-node-client";
29+
volatile bool keepRunning = {true};
30+
31+
using WaitSet = iox::popo::WaitSet<>;
32+
volatile WaitSet* waitsetSigHandlerAccess{nullptr};
33+
34+
//! [context data to store Fibonacci numbers and sequence ids]
35+
struct ContextData
36+
{
37+
uint64_t fibonacciLast = 0;
38+
uint64_t fibonacciCurrent = 1;
39+
int64_t requestSequenceId = 0;
40+
int64_t expectedResponseSequenceId = requestSequenceId;
41+
};
42+
//! [context data to store Fibonacci numbers and sequence ids]
43+
44+
static void signalHandler(int sig [[maybe_unused]])
45+
{
46+
keepRunning = false;
47+
if (waitsetSigHandlerAccess)
48+
{
49+
waitsetSigHandlerAccess->markForDestruction();
50+
}
51+
}
52+
53+
int main()
54+
{
55+
auto sigTermGuard =
56+
iox::registerSignalHandler(iox::PosixSignal::TERM, signalHandler).expect("failed to register SIGTERM");
57+
auto sigIntGuard =
58+
iox::registerSignalHandler(iox::PosixSignal::INT, signalHandler).expect("failed to register SIGINT");
59+
60+
//! [create the node]
61+
auto node_result = iox::posh::experimental::NodeBuilder(APP_NAME).domain_id_from_env_or_default().create();
62+
63+
while (keepRunning && node_result.has_error())
64+
{
65+
std::cout << "Could not create the node!" << std::endl;
66+
67+
node_result = iox::posh::experimental::NodeBuilder(APP_NAME)
68+
.domain_id_from_env_or_default()
69+
.roudi_registration_timeout(iox::units::Duration::fromSeconds(1))
70+
.create();
71+
}
72+
73+
auto node = std::move(node_result.value());
74+
//! [create the node]
75+
76+
77+
//! [create waitset]
78+
auto waitset = node.wait_set().create().expect("Getting a wait set");
79+
waitsetSigHandlerAccess = waitset.get();
80+
81+
//! [create client]
82+
auto client = node.client({"Example", "Request-Response", "Add"})
83+
.response_queue_capacity(2)
84+
.create<AddRequest, AddResponse>()
85+
.expect("Getting a client");
86+
//! [create client]
87+
88+
// attach client to waitset
89+
waitset->attachState(*client.get(), iox::popo::ClientState::HAS_RESPONSE).or_else([](auto) {
90+
std::cerr << "failed to attach client" << std::endl;
91+
std::exit(EXIT_FAILURE);
92+
});
93+
//! [create waitset]
94+
95+
ContextData ctx;
96+
97+
//! [mainloop]
98+
while (keepRunning)
99+
{
100+
//! [send request]
101+
client->loan()
102+
.and_then([&](auto& request) {
103+
request.getRequestHeader().setSequenceId(ctx.requestSequenceId);
104+
ctx.expectedResponseSequenceId = ctx.requestSequenceId;
105+
ctx.requestSequenceId += 1;
106+
request->augend = ctx.fibonacciLast;
107+
request->addend = ctx.fibonacciCurrent;
108+
std::cout << APP_NAME << " Send Request: " << ctx.fibonacciLast << " + " << ctx.fibonacciCurrent
109+
<< std::endl;
110+
request.send().or_else(
111+
[&](auto& error) { std::cout << "Could not send Request! Error: " << error << std::endl; });
112+
})
113+
.or_else([](auto& error) { std::cout << "Could not allocate Request! Error: " << error << std::endl; });
114+
//! [send request]
115+
116+
117+
// We block and wait for samples to arrive, when the time is up we send the request again
118+
//! [wait and check if the client triggered]
119+
auto notificationVector = waitset->timedWait(iox::units::Duration::fromSeconds(5));
120+
121+
for (auto& notification : notificationVector)
122+
{
123+
if (notification->doesOriginateFrom(client.get()))
124+
{
125+
//! [take response]
126+
while (client->take().and_then([&](const auto& response) {
127+
auto receivedSequenceId = response.getResponseHeader().getSequenceId();
128+
if (receivedSequenceId == ctx.expectedResponseSequenceId)
129+
{
130+
ctx.fibonacciLast = ctx.fibonacciCurrent;
131+
ctx.fibonacciCurrent = response->sum;
132+
std::cout << APP_NAME << " Got Response : " << ctx.fibonacciCurrent << std::endl;
133+
}
134+
else
135+
{
136+
std::cout << "Got Response with outdated sequence ID! Expected = "
137+
<< ctx.expectedResponseSequenceId << "; Actual = " << receivedSequenceId
138+
<< "! -> skip" << std::endl;
139+
}
140+
}))
141+
{
142+
}
143+
//! [take response]
144+
}
145+
}
146+
//! [wait and check if the client triggered]
147+
constexpr std::chrono::milliseconds SLEEP_TIME{950U};
148+
std::this_thread::sleep_for(SLEEP_TIME);
149+
}
150+
//! [mainloop]
151+
152+
std::cout << "shutting down" << std::endl;
153+
154+
waitsetSigHandlerAccess = nullptr; // invalidate for signal handler
155+
156+
return (EXIT_SUCCESS);
157+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright (c) 2025 by Valour Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
//! [iceoryx includes]
18+
#include "request_and_response_types.hpp"
19+
20+
#include "iox/optional.hpp"
21+
#include "iox/posh/experimental/node.hpp"
22+
#include "iox/signal_watcher.hpp"
23+
//! [iceoryx includes]
24+
25+
#include <iostream>
26+
27+
constexpr char APP_NAME[] = "iox-cpp-node-server";
28+
29+
//! [request callback]
30+
void onRequestReceived(iox::popo::Server<AddRequest, AddResponse>* server)
31+
{
32+
//! [take request]
33+
while (server->take().and_then([&](const auto& request) {
34+
std::cout << APP_NAME << " Got Request: " << request->augend << " + " << request->addend << std::endl;
35+
36+
//! [send response]
37+
server->loan(request)
38+
.and_then([&](auto& response) {
39+
response->sum = request->augend + request->addend;
40+
std::cout << APP_NAME << " Send Response: " << response->sum << std::endl;
41+
response.send().or_else(
42+
[&](auto& error) { std::cout << "Could not send Response! Error: " << error << std::endl; });
43+
})
44+
.or_else([](auto& error) { std::cout << "Could not allocate Response! Error: " << error << std::endl; });
45+
//! [send response]
46+
}))
47+
{
48+
}
49+
//! [take request]
50+
}
51+
//! [request callback]
52+
53+
int main()
54+
{
55+
//! [create the node]
56+
auto node_result = iox::posh::experimental::NodeBuilder(APP_NAME)
57+
.domain_id_from_env_or_default()
58+
.roudi_registration_timeout(iox::units::Duration::fromSeconds(1))
59+
.create();
60+
if (node_result.has_error())
61+
{
62+
std::cout << "Could not create the node!" << std::endl;
63+
return -1;
64+
}
65+
auto node = std::move(node_result.value());
66+
//! [create the node]
67+
68+
//! [create server]
69+
auto server = node.server({"Example", "Request-Response", "Add"})
70+
.request_queue_capacity(10u)
71+
.create<AddRequest, AddResponse>()
72+
.expect("Getting a listener");
73+
//! [create server]
74+
75+
//! [create listener]
76+
auto listener = node.listener().create().expect("Getting a listener");
77+
//! [create listener]
78+
79+
//! [attach listener]
80+
listener
81+
->attachEvent(*server.get(),
82+
iox::popo::ServerEvent::REQUEST_RECEIVED,
83+
iox::popo::createNotificationCallback(onRequestReceived))
84+
.or_else([](auto) {
85+
std::cerr << "unable to attach server" << std::endl;
86+
std::exit(EXIT_FAILURE);
87+
});
88+
//! [attach listener]
89+
90+
//! [wait for termination]
91+
iox::waitForTerminationRequest();
92+
//! [wait for termination]
93+
94+
//! [cleanup]
95+
listener->detachEvent(*server.get(), iox::popo::ServerEvent::REQUEST_RECEIVED);
96+
//! [cleanup]
97+
98+
return EXIT_SUCCESS;
99+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright (c) 2022 by Apex.AI Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
//
15+
// SPDX-License-Identifier: Apache-2.0
16+
17+
#ifndef IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP
18+
#define IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP
19+
20+
#include <cstdint>
21+
22+
//! [request]
23+
struct AddRequest
24+
{
25+
uint64_t augend{0};
26+
uint64_t addend{0};
27+
};
28+
//! [request]
29+
30+
//! [response]
31+
struct AddResponse
32+
{
33+
uint64_t sum{0};
34+
};
35+
//! [response]
36+
37+
#endif // IOX_EXAMPLES_REQUEST_AND_RESPONSE_TYPES_HPP

iceoryx_integrationtest/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ if(BUILD_TESTING)
3232
)
3333

3434
if(IOX_EXPERIMENTAL_POSH)
35-
list(APPEND IOX_INT_TESTS test_experimental_node)
35+
list(APPEND IOX_INT_TESTS test_experimental_node_publish_subscribe test_experimental_node_request_response)
3636
else()
3737
message(FATAL_ERROR "Please run colcon with '--meta=path/to/iceoryx_integrationtest/colcon.meta' to enable the experimental feature flag for the integration tests")
3838
endif()

0 commit comments

Comments
 (0)