18#include <catch2/catch_test_macros.hpp>
19#include <catch2/matchers/catch_matchers_string.hpp>
35TEST_CASE(
"C-ECHO basic connectivity",
"[connectivity][echo]") {
36 SECTION(
"Echo SCP accepts connection and responds to C-ECHO") {
42 REQUIRE(server.
start());
51 {std::string(verification_sop_class_uid)}
54 REQUIRE(connect_result.is_ok());
55 auto& assoc = connect_result.value();
61 REQUIRE(context_id_opt.has_value());
62 uint8_t context_id = *context_id_opt;
66 auto send_result = assoc.send_dimse(context_id, echo_rq);
67 REQUIRE(send_result.is_ok());
71 REQUIRE(recv_result.is_ok());
73 auto& [recv_context_id, echo_rsp] = recv_result.value();
74 REQUIRE(echo_rsp.command() == command_field::c_echo_rsp);
75 REQUIRE(echo_rsp.status() == status_success);
79 REQUIRE(release_result.is_ok());
87TEST_CASE(
"Multiple sequential C-ECHO requests",
"[connectivity][echo]") {
92 REQUIRE(server.
start());
96 "localhost", port, server.
ae_title(),
"ECHO_SCU",
97 {std::string(verification_sop_class_uid)}
99 REQUIRE(connect_result.is_ok());
100 auto& assoc = connect_result.value();
105 constexpr int echo_count = 5;
106 for (
int i = 0; i < echo_count; ++i) {
108 auto send_result = assoc.send_dimse(context_id, echo_rq);
109 REQUIRE(send_result.is_ok());
112 REQUIRE(recv_result.is_ok());
114 auto& [recv_ctx, echo_rsp] = recv_result.value();
115 REQUIRE(echo_rsp.command() == command_field::c_echo_rsp);
116 REQUIRE(echo_rsp.status() == status_success);
123TEST_CASE(
"Multiple concurrent associations",
"[connectivity][echo]") {
128 REQUIRE(server.
start());
130 constexpr int num_associations = 5;
131 std::vector<std::thread> threads;
132 std::atomic<int> success_count{0};
134 for (
int i = 0; i < num_associations; ++i) {
135 threads.emplace_back([&server, &success_count, port, i]() {
137 "localhost", port, server.
ae_title(),
138 "ECHO_SCU_" + std::to_string(i),
139 {std::string(verification_sop_class_uid)}
142 if (connect_result.is_err()) {
146 auto& assoc = connect_result.value();
148 if (!context_id_opt) {
153 auto send_result = assoc.send_dimse(*context_id_opt, echo_rq);
154 if (send_result.is_err()) {
159 if (recv_result.is_ok()) {
160 auto& [ctx, rsp] = recv_result.value();
161 if (rsp.command() == command_field::c_echo_rsp &&
162 rsp.status() == status_success) {
172 for (
auto& t : threads) {
178 REQUIRE(success_count == num_associations);
181TEST_CASE(
"Connection to non-existent server fails gracefully",
"[connectivity][error]") {
191 REQUIRE(connect_result.is_err());
194TEST_CASE(
"Wrong AE title handling",
"[connectivity][ae_title]") {
199 REQUIRE(server.
start());
215 if (connect_result.is_ok()) {
216 auto& assoc = connect_result.value();
223TEST_CASE(
"Association timeout handling",
"[connectivity][timeout]") {
228 REQUIRE(server.
start());
231 "localhost", port, server.
ae_title(),
"ECHO_SCU",
232 {std::string(verification_sop_class_uid)}
234 REQUIRE(connect_result.is_ok());
235 auto& assoc = connect_result.value();
238 auto short_timeout = std::chrono::milliseconds{100};
239 auto recv_result = assoc.receive_dimse(short_timeout);
242 REQUIRE(recv_result.is_err());
static network::Result< network::association > connect(const std::string &host, uint16_t port, const std::string &called_ae, const std::string &calling_ae=test_scu_ae_title, const std::vector< std::string > &sop_classes={"1.2.840.10008.1.1"})
Connect to a test server.
RAII wrapper for a test DICOM server.
bool start()
Start the server and wait for it to be ready.
const std::string & ae_title() const noexcept
void stop()
Stop the server.
void register_service(std::shared_ptr< Service > service)
Register a service provider.
bool is_running() const noexcept
DIMSE message encoding and decoding.
uint16_t find_available_port(uint16_t start=default_test_port, int max_attempts=200)
Find an available port for testing.
std::chrono::milliseconds default_timeout()
Default timeout for test operations (5s normal, 30s CI)
auto make_c_echo_rq(uint16_t message_id, std::string_view sop_class_uid="1.2.840.10008.1.1") -> dimse_message
Create a C-ECHO request message.
constexpr std::string_view verification_sop_class_uid
Verification SOP Class UID (1.2.840.10008.1.1)
TEST_CASE("C-ECHO basic connectivity", "[connectivity][echo]")
Common test fixtures and utilities for integration tests.
DICOM Verification SCP service (C-ECHO handler)