From 663a959f9cc96e3386f48be90c15b16d0bda22f0 Mon Sep 17 00:00:00 2001 From: "jabber.developer2" Date: Tue, 10 Feb 2026 17:47:26 +0300 Subject: [PATCH 1/4] test: add functional tests for autoping (XEP-0199) - autoping_set_interval: verify /autoping set command - autoping_set_zero_disables: verify disabling autoping - autoping_timeout_set: verify /autoping timeout command - autoping_timeout_zero_disables: verify disabling timeout - autoping_sends_ping_after_interval: verify automatic ping IQ - autoping_server_not_supporting_ping: verify error handling Fast tests (command parsing) in Group 1, slow tests (timer-based) in Group 3. --- Makefile.am | 1 + tests/functionaltests/functionaltests.c | 15 ++- tests/functionaltests/test_autoping.c | 120 ++++++++++++++++++++++++ tests/functionaltests/test_autoping.h | 6 ++ 4 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 tests/functionaltests/test_autoping.c create mode 100644 tests/functionaltests/test_autoping.h diff --git a/Makefile.am b/Makefile.am index 60ff0f33..f21b6eea 100644 --- a/Makefile.am +++ b/Makefile.am @@ -186,6 +186,7 @@ functionaltest_sources = \ tests/functionaltests/test_muc.c tests/functionaltests/test_muc.h \ tests/functionaltests/test_disconnect.c tests/functionaltests/test_disconnect.h \ tests/functionaltests/test_lastactivity.c tests/functionaltests/test_lastactivity.h \ + tests/functionaltests/test_autoping.c tests/functionaltests/test_autoping.h \ tests/functionaltests/functionaltests.c main_source = src/main.c diff --git a/tests/functionaltests/functionaltests.c b/tests/functionaltests/functionaltests.c index 46d1a7d2..331543ad 100644 --- a/tests/functionaltests/functionaltests.c +++ b/tests/functionaltests/functionaltests.c @@ -15,9 +15,9 @@ * functional tests run less frequently than unit tests. * * Tests are organized into groups for better maintainability and parallel execution: - * Group 1: Connect, Ping, Rooms, Software + * Group 1: Connect, Ping, Autoping (fast), Rooms, Software, Last Activity * Group 2: Message, Receipts, Roster, Chat Session - * Group 3: Presence, Disconnect + * Group 3: Presence, Disconnect, Autoping (slow) * Group 4: MUC, Carbons * * Parallel execution: @@ -53,6 +53,7 @@ #include "test_muc.h" #include "test_disconnect.h" #include "test_lastactivity.h" +#include "test_autoping.h" /* Macro to wrap each test with setup/teardown functions */ #define PROF_FUNC_TEST(test) cmocka_unit_test_setup_teardown(test, init_prof_test, close_prof_test) @@ -95,6 +96,12 @@ main(int argc, char* argv[]) PROF_FUNC_TEST(ping_jid), PROF_FUNC_TEST(ping_jid_not_supported), + /* Autoping command tests - fast, no waiting */ + PROF_FUNC_TEST(autoping_set_interval), + PROF_FUNC_TEST(autoping_set_zero_disables), + PROF_FUNC_TEST(autoping_timeout_set), + PROF_FUNC_TEST(autoping_timeout_zero_disables), + /* Room discovery - XEP-0045 */ PROF_FUNC_TEST(rooms_query), @@ -165,6 +172,10 @@ main(int argc, char* argv[]) /* Disconnect - clean session termination */ PROF_FUNC_TEST(disconnect_ends_session), + + /* Autoping slow tests - require sleep for timer triggers */ + PROF_FUNC_TEST(autoping_sends_ping_after_interval), + PROF_FUNC_TEST(autoping_server_not_supporting_ping), }; /* ============================================================ diff --git a/tests/functionaltests/test_autoping.c b/tests/functionaltests/test_autoping.c new file mode 100644 index 00000000..55c99df3 --- /dev/null +++ b/tests/functionaltests/test_autoping.c @@ -0,0 +1,120 @@ +#include +#include "prof_cmocka.h" +#include +#include +#include + +#include + +#include "proftest.h" + +void +autoping_set_interval(void** state) +{ + prof_connect(); + + prof_input("/autoping set 60"); + assert_true(prof_output_exact("Autoping interval set to 60 seconds.")); +} + +void +autoping_set_zero_disables(void** state) +{ + prof_connect(); + + prof_input("/autoping set 0"); + assert_true(prof_output_exact("Autoping disabled.")); +} + +void +autoping_timeout_set(void** state) +{ + prof_connect(); + + prof_input("/autoping timeout 30"); + assert_true(prof_output_exact("Autoping timeout set to 30 seconds.")); +} + +void +autoping_timeout_zero_disables(void** state) +{ + prof_connect(); + + prof_input("/autoping timeout 0"); + assert_true(prof_output_exact("Autoping timeout disabled.")); +} + +void +autoping_sends_ping_after_interval(void** state) +{ + /* + * This test verifies that autoping sends a ping IQ after the configured + * interval. We set a short interval (2 seconds) and verify the ping is sent. + */ + + // Register disco#info response with ping support + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + "" + ); + + // Register ping response + stbbr_for_query("urn:xmpp:ping", + "" + ); + + prof_connect(); + + // Wait for disco exchange + sleep(2); + + // Set short autoping interval + prof_input("/autoping set 2"); + assert_true(prof_output_exact("Autoping interval set to 2 seconds.")); + + // Wait for autoping to trigger (interval + some buffer) + sleep(4); + + // Verify ping was sent (no 'to' attribute means server ping) + assert_true(stbbr_received( + "" + "" + "" + )); +} + +void +autoping_server_not_supporting_ping(void** state) +{ + /* + * When server doesn't support ping, autoping should show error. + */ + + // Register disco#info response WITHOUT ping support + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + ); + + prof_connect(); + + // Wait for disco exchange + sleep(2); + + // Set short autoping interval + prof_input("/autoping set 2"); + assert_true(prof_output_exact("Autoping interval set to 2 seconds.")); + + // Wait for autoping to trigger + sleep(4); + + // Should show error about ping not being supported + assert_true(prof_output_regex("Server ping not supported")); +} diff --git a/tests/functionaltests/test_autoping.h b/tests/functionaltests/test_autoping.h new file mode 100644 index 00000000..9456a50d --- /dev/null +++ b/tests/functionaltests/test_autoping.h @@ -0,0 +1,6 @@ +void autoping_set_interval(void** state); +void autoping_set_zero_disables(void** state); +void autoping_timeout_set(void** state); +void autoping_timeout_zero_disables(void** state); +void autoping_sends_ping_after_interval(void** state); +void autoping_server_not_supporting_ping(void** state); -- 2.49.1 From f20a4da160503acd7e763a7ba159bf390c77c044 Mon Sep 17 00:00:00 2001 From: "jabber.developer2" Date: Tue, 10 Feb 2026 22:22:57 +0300 Subject: [PATCH 2/4] Add functional tests for /disco command (XEP-0030) - Add 8 tests for disco info and disco items commands - Fix XEP-0030 compliance bug: show message for empty disco#items results - Tests cover: identity display, features, server/jid queries, error handling, items display, empty results, and connection requirement --- Makefile.am | 1 + tests/functionaltests/functionaltests.c | 35 ++-- tests/functionaltests/proftest.c | 1 - tests/functionaltests/test_autoping.c | 20 +- tests/functionaltests/test_disco.c | 250 ++++++++++++++++++++++++ tests/functionaltests/test_disco.h | 13 ++ 6 files changed, 294 insertions(+), 26 deletions(-) create mode 100644 tests/functionaltests/test_disco.c create mode 100644 tests/functionaltests/test_disco.h diff --git a/Makefile.am b/Makefile.am index f21b6eea..a7648fcb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -187,6 +187,7 @@ functionaltest_sources = \ tests/functionaltests/test_disconnect.c tests/functionaltests/test_disconnect.h \ tests/functionaltests/test_lastactivity.c tests/functionaltests/test_lastactivity.h \ tests/functionaltests/test_autoping.c tests/functionaltests/test_autoping.h \ + tests/functionaltests/test_disco.c tests/functionaltests/test_disco.h \ tests/functionaltests/functionaltests.c main_source = src/main.c diff --git a/tests/functionaltests/functionaltests.c b/tests/functionaltests/functionaltests.c index 331543ad..ad2f25eb 100644 --- a/tests/functionaltests/functionaltests.c +++ b/tests/functionaltests/functionaltests.c @@ -54,6 +54,7 @@ #include "test_disconnect.h" #include "test_lastactivity.h" #include "test_autoping.h" +#include "test_disco.h" /* Macro to wrap each test with setup/teardown functions */ #define PROF_FUNC_TEST(test) cmocka_unit_test_setup_teardown(test, init_prof_test, close_prof_test) @@ -96,12 +97,6 @@ main(int argc, char* argv[]) PROF_FUNC_TEST(ping_jid), PROF_FUNC_TEST(ping_jid_not_supported), - /* Autoping command tests - fast, no waiting */ - PROF_FUNC_TEST(autoping_set_interval), - PROF_FUNC_TEST(autoping_set_zero_disables), - PROF_FUNC_TEST(autoping_timeout_set), - PROF_FUNC_TEST(autoping_timeout_zero_disables), - /* Room discovery - XEP-0045 */ PROF_FUNC_TEST(rooms_query), @@ -116,6 +111,16 @@ main(int argc, char* argv[]) /* Last Activity - XEP-0012 */ PROF_FUNC_TEST(responds_to_last_activity_request), PROF_FUNC_TEST(last_activity_request_to_contact), + + /* Autoping command tests - fast, no waiting */ + PROF_FUNC_TEST(autoping_set_interval), + PROF_FUNC_TEST(autoping_set_zero_disables), + PROF_FUNC_TEST(autoping_timeout_set), + PROF_FUNC_TEST(autoping_timeout_zero_disables), + + /* Autoping slow tests - require sleep for timer triggers (~2s each) */ + PROF_FUNC_TEST(autoping_sends_ping_after_interval), + PROF_FUNC_TEST(autoping_server_not_supporting_ping), }; /* ============================================================ @@ -150,7 +155,7 @@ main(int argc, char* argv[]) }; /* ============================================================ - * GROUP 3: Presence, Disconnect + * GROUP 3: Presence, Disconnect, Disco * Online/away/xa/dnd/chat status management * ============================================================ */ const struct CMUnitTest group3_tests[] = { @@ -173,9 +178,15 @@ main(int argc, char* argv[]) /* Disconnect - clean session termination */ PROF_FUNC_TEST(disconnect_ends_session), - /* Autoping slow tests - require sleep for timer triggers */ - PROF_FUNC_TEST(autoping_sends_ping_after_interval), - PROF_FUNC_TEST(autoping_server_not_supporting_ping), + /* Service Discovery - XEP-0030 */ + PROF_FUNC_TEST(disco_info_shows_identity), + PROF_FUNC_TEST(disco_info_shows_features), + PROF_FUNC_TEST(disco_info_to_server), + PROF_FUNC_TEST(disco_info_to_jid), + PROF_FUNC_TEST(disco_info_not_found), + PROF_FUNC_TEST(disco_items_shows_items), + PROF_FUNC_TEST(disco_items_empty_result), + PROF_FUNC_TEST(disco_requires_connection), }; /* ============================================================ @@ -223,9 +234,9 @@ main(int argc, char* argv[]) const struct CMUnitTest* tests; size_t count; } groups[] = { - { "Group 1: Connect/Ping/Rooms/Software", group1_tests, ARRAY_SIZE(group1_tests) }, + { "Group 1: Connect/Ping/Rooms/Software/Autoping", group1_tests, ARRAY_SIZE(group1_tests) }, { "Group 2: Message/Receipts/Roster/Session", group2_tests, ARRAY_SIZE(group2_tests) }, - { "Group 3: Presence/Disconnect", group3_tests, ARRAY_SIZE(group3_tests) }, + { "Group 3: Presence/Disconnect/Disco", group3_tests, ARRAY_SIZE(group3_tests) }, { "Group 4: MUC/Carbons", group4_tests, ARRAY_SIZE(group4_tests) }, }; const int num_groups = ARRAY_SIZE(groups); diff --git a/tests/functionaltests/proftest.c b/tests/functionaltests/proftest.c index b67954f7..37813327 100644 --- a/tests/functionaltests/proftest.c +++ b/tests/functionaltests/proftest.c @@ -362,7 +362,6 @@ close_prof_test(void **state) fd = 0; child_pid = 0; } - _cleanup_dirs(); if (config_orig) { setenv("XDG_CONFIG_HOME", config_orig, 1); diff --git a/tests/functionaltests/test_autoping.c b/tests/functionaltests/test_autoping.c index 55c99df3..1e1a1332 100644 --- a/tests/functionaltests/test_autoping.c +++ b/tests/functionaltests/test_autoping.c @@ -49,7 +49,7 @@ autoping_sends_ping_after_interval(void** state) { /* * This test verifies that autoping sends a ping IQ after the configured - * interval. We set a short interval (2 seconds) and verify the ping is sent. + * interval. We set a short interval (1 second) and verify the ping is sent. */ // Register disco#info response with ping support @@ -69,15 +69,12 @@ autoping_sends_ping_after_interval(void** state) prof_connect(); - // Wait for disco exchange - sleep(2); - // Set short autoping interval - prof_input("/autoping set 2"); - assert_true(prof_output_exact("Autoping interval set to 2 seconds.")); + prof_input("/autoping set 1"); + assert_true(prof_output_exact("Autoping interval set to 1 seconds.")); // Wait for autoping to trigger (interval + some buffer) - sleep(4); + sleep(2); // Verify ping was sent (no 'to' attribute means server ping) assert_true(stbbr_received( @@ -105,15 +102,12 @@ autoping_server_not_supporting_ping(void** state) prof_connect(); - // Wait for disco exchange - sleep(2); - // Set short autoping interval - prof_input("/autoping set 2"); - assert_true(prof_output_exact("Autoping interval set to 2 seconds.")); + prof_input("/autoping set 1"); + assert_true(prof_output_exact("Autoping interval set to 1 seconds.")); // Wait for autoping to trigger - sleep(4); + sleep(2); // Should show error about ping not being supported assert_true(prof_output_regex("Server ping not supported")); diff --git a/tests/functionaltests/test_disco.c b/tests/functionaltests/test_disco.c new file mode 100644 index 00000000..dfafdc09 --- /dev/null +++ b/tests/functionaltests/test_disco.c @@ -0,0 +1,250 @@ +/* + * test_disco.c + * + * Functional tests for /disco command (XEP-0030 Service Discovery). + * Tests cover: + * - /disco info [jid] - query entity capabilities and features + * - /disco items [jid] - query entity items/services + * + * XEP-0030: https://xmpp.org/extensions/xep-0030.html + */ + +#include +#include "prof_cmocka.h" +#include +#include +#include + +#include + +#include "proftest.h" + +void +disco_info_shows_identity(void **state) +{ + /* + * Test that /disco info displays identity information correctly. + * Identity includes: name, type, category + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + ); + + prof_connect(); + + + prof_input("/disco info"); + + prof_timeout(10); + assert_true(prof_output_exact("Service discovery info for localhost")); + assert_true(prof_output_exact("Identities")); + assert_true(prof_output_regex("Prosody.*im.*server")); + prof_timeout_reset(); +} + +void +disco_info_shows_features(void **state) +{ + /* + * Test that /disco info displays feature list. + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + "" + "" + "" + ); + + prof_connect(); + + + prof_input("/disco info"); + + prof_timeout(10); + assert_true(prof_output_exact("Features:")); + assert_true(prof_output_exact("urn:xmpp:ping")); + assert_true(prof_output_exact("http://jabber.org/protocol/disco#info")); + prof_timeout_reset(); +} + +void +disco_info_to_server(void **state) +{ + /* + * Test that /disco info without arguments queries the server (domainpart). + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + ); + + prof_connect(); + + + prof_input("/disco info"); + + /* Verify request was sent to server (localhost) */ + prof_timeout(10); + assert_true(stbbr_received( + "" + "" + "" + )); + prof_timeout_reset(); +} + +void +disco_info_to_jid(void **state) +{ + /* + * Test that /disco info queries the specified JID. + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + "" + ); + + prof_connect(); + + + prof_input("/disco info conference.localhost"); + + prof_timeout(10); + /* Verify request was sent to specified JID */ + assert_true(stbbr_received( + "" + "" + "" + )); + + assert_true(prof_output_exact("Service discovery info for conference.localhost")); + prof_timeout_reset(); +} + +void +disco_info_not_found(void **state) +{ + /* + * Test error handling when disco info returns item-not-found. + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + ); + + prof_connect(); + + + prof_input("/disco info unknown.localhost"); + + prof_timeout(10); + assert_true(prof_output_regex("Service discovery failed.*item-not-found")); + prof_timeout_reset(); +} + +void +disco_items_shows_items(void **state) +{ + /* + * Test that /disco items displays items list with JID and name. + */ + stbbr_for_query("http://jabber.org/protocol/disco#items", + "" + "" + "" + "" + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco items"); + + prof_timeout(10); + assert_true(prof_output_exact("Service discovery items for localhost:")); + assert_true(prof_output_regex("conference.localhost.*Chat Rooms")); + assert_true(prof_output_regex("pubsub.localhost.*Publish-Subscribe")); + assert_true(prof_output_regex("proxy.localhost.*SOCKS5 Bytestreams")); + + /* Verify IQ was sent with correct id */ + assert_true(stbbr_received( + "" + "" + "" + )); + prof_timeout_reset(); +} + +void +disco_items_empty_result(void **state) +{ + /* + * Test that /disco items handles empty result gracefully. + * Per XEP-0030: "if an entity has no associated items, it MUST return + * an empty element (rather than an error)" + */ + stbbr_for_query("http://jabber.org/protocol/disco#items", + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco items"); + + prof_timeout(10); + assert_true(prof_output_exact("No service discovery items for localhost")); + prof_timeout_reset(); +} + +void +disco_requires_connection(void **state) +{ + /* + * Test that /disco info and /disco items require an active connection. + * First test without any connection, then after connect/disconnect. + */ + + /* Without connection */ + prof_input("/disconnect"); + assert_true(prof_output_exact("You are not currently connected.")); + + prof_input("/disco info"); + assert_true(prof_output_exact("You are not currently connected.")); + + prof_input("/disco items"); + assert_true(prof_output_exact("You are not currently connected.")); + + /* After connect and disconnect */ + prof_connect(); + + prof_input("/disconnect"); + assert_true(prof_output_exact("stabber@localhost logged out successfully.")); + + prof_input("/disco info"); + assert_true(prof_output_exact("You are not currently connected.")); + + prof_input("/disco items"); + assert_true(prof_output_exact("You are not currently connected.")); +} diff --git a/tests/functionaltests/test_disco.h b/tests/functionaltests/test_disco.h new file mode 100644 index 00000000..4b98ed55 --- /dev/null +++ b/tests/functionaltests/test_disco.h @@ -0,0 +1,13 @@ +/* test_disco.h + * + * Functional tests for /disco command (XEP-0030 Service Discovery) + */ + +void disco_info_shows_identity(void **state); +void disco_info_shows_features(void **state); +void disco_info_to_server(void **state); +void disco_info_to_jid(void **state); +void disco_info_not_found(void **state); +void disco_items_shows_items(void **state); +void disco_items_empty_result(void **state); +void disco_requires_connection(void **state); -- 2.49.1 From 24e1dac354da131c2d04a5388779114e08843bfe Mon Sep 17 00:00:00 2001 From: "jabber.developer2" Date: Wed, 11 Feb 2026 15:19:58 +0300 Subject: [PATCH 3/4] test(disco): add comprehensive XEP-0030 functional tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add 7 new tests for /disco command: - disco_items_to_jid: query items to specific JID - disco_info_empty_result: handle empty disco#info response - disco_info_multiple_identities: multiple identity elements - disco_info_without_name: identity without optional name attr - disco_items_without_name: items without optional name attr - disco_info_service_unavailable: error handling for info - disco_items_error_handling: error handling for items (XEP-0030 ยง7) The disco_items_error_handling test documents a bug where disco#items errors are silently ignored (unlike disco#info which handles them). This violates XEP-0030 Section 7 which requires error feedback to user. --- tests/functionaltests/functionaltests.c | 7 + tests/functionaltests/test_disco.c | 195 ++++++++++++++++++++++++ tests/functionaltests/test_disco.h | 7 + 3 files changed, 209 insertions(+) diff --git a/tests/functionaltests/functionaltests.c b/tests/functionaltests/functionaltests.c index ad2f25eb..0227df82 100644 --- a/tests/functionaltests/functionaltests.c +++ b/tests/functionaltests/functionaltests.c @@ -187,6 +187,13 @@ main(int argc, char* argv[]) PROF_FUNC_TEST(disco_items_shows_items), PROF_FUNC_TEST(disco_items_empty_result), PROF_FUNC_TEST(disco_requires_connection), + PROF_FUNC_TEST(disco_items_to_jid), + PROF_FUNC_TEST(disco_info_empty_result), + PROF_FUNC_TEST(disco_info_multiple_identities), + PROF_FUNC_TEST(disco_info_without_name), + PROF_FUNC_TEST(disco_items_without_name), + PROF_FUNC_TEST(disco_info_service_unavailable), + PROF_FUNC_TEST(disco_items_error_handling), }; /* ============================================================ diff --git a/tests/functionaltests/test_disco.c b/tests/functionaltests/test_disco.c index dfafdc09..c73a3d43 100644 --- a/tests/functionaltests/test_disco.c +++ b/tests/functionaltests/test_disco.c @@ -248,3 +248,198 @@ disco_requires_connection(void **state) prof_input("/disco items"); assert_true(prof_output_exact("You are not currently connected.")); } + +void +disco_items_to_jid(void **state) +{ + /* + * Test that /disco items queries the specified JID. + */ + stbbr_for_query("http://jabber.org/protocol/disco#items", + "" + "" + "" + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco items conference.localhost"); + + prof_timeout(10); + /* Verify request was sent to specified JID */ + assert_true(stbbr_received( + "" + "" + "" + )); + + assert_true(prof_output_exact("Service discovery items for conference.localhost:")); + assert_true(prof_output_regex("room1@conference.localhost.*General Chat")); + prof_timeout_reset(); +} + +void +disco_info_empty_result(void **state) +{ + /* + * Test that /disco info handles empty result (no identities/features). + * This can happen with minimal server configurations. + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco info minimal.localhost"); + + prof_timeout(10); + /* Verify request was sent */ + assert_true(stbbr_received( + "" + "" + "" + )); + /* Empty result should not crash and should not show "Service discovery info" */ + prof_timeout_reset(); +} + +void +disco_info_multiple_identities(void **state) +{ + /* + * Test that /disco info displays multiple identities correctly. + * Entities can have multiple identities (e.g., server + gateway). + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco info gateway.localhost"); + + prof_timeout(10); + assert_true(prof_output_exact("Service discovery info for gateway.localhost")); + assert_true(prof_output_exact("Identities")); + assert_true(prof_output_regex("IRC Gateway.*irc.*gateway")); + assert_true(prof_output_regex("Room Directory.*chatroom.*directory")); + assert_true(prof_output_regex("Ad-Hoc Commands.*command-node.*automation")); + prof_timeout_reset(); +} + +void +disco_info_without_name(void **state) +{ + /* + * Test that /disco info handles identity without name attribute. + * Per XEP-0030: name is OPTIONAL, only category and type are REQUIRED. + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco info"); + + prof_timeout(10); + assert_true(prof_output_exact("Service discovery info for localhost")); + assert_true(prof_output_exact("Identities")); + /* Should show type and category even without name */ + assert_true(prof_output_regex("im.*server")); + prof_timeout_reset(); +} + +void +disco_items_without_name(void **state) +{ + /* + * Test that /disco items handles items without name attribute. + * Per XEP-0030: name is OPTIONAL for items, only jid is REQUIRED. + */ + stbbr_for_query("http://jabber.org/protocol/disco#items", + "" + "" + "" + "" + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco items"); + + prof_timeout(10); + assert_true(prof_output_exact("Service discovery items for localhost:")); + /* Items without name should still display their JID */ + assert_true(prof_output_exact("conference.localhost")); + assert_true(prof_output_regex("pubsub.localhost.*PubSub Service")); + assert_true(prof_output_exact("upload.localhost")); + prof_timeout_reset(); +} + +void +disco_info_service_unavailable(void **state) +{ + /* + * Test error handling when disco info returns service-unavailable. + */ + stbbr_for_query("http://jabber.org/protocol/disco#info", + "" + "" + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco info offline.localhost"); + + prof_timeout(10); + assert_true(prof_output_regex("Service discovery failed.*service-unavailable")); + prof_timeout_reset(); +} + +void +disco_items_error_handling(void **state) +{ + /* + * Test that /disco items displays error responses to user. + * Per XEP-0030 Section 7: errors like service-unavailable must be shown. + */ + stbbr_for_query("http://jabber.org/protocol/disco#items", + "" + "" + "" + "" + "" + ); + + prof_connect(); + + prof_input("/disco items broken.localhost"); + + prof_timeout(10); + /* Per XEP-0030, error should be displayed to user */ + assert_true(prof_output_regex("Service discovery failed.*service-unavailable")); + prof_timeout_reset(); +} diff --git a/tests/functionaltests/test_disco.h b/tests/functionaltests/test_disco.h index 4b98ed55..fbd7d0c2 100644 --- a/tests/functionaltests/test_disco.h +++ b/tests/functionaltests/test_disco.h @@ -11,3 +11,10 @@ void disco_info_not_found(void **state); void disco_items_shows_items(void **state); void disco_items_empty_result(void **state); void disco_requires_connection(void **state); +void disco_items_to_jid(void **state); +void disco_info_empty_result(void **state); +void disco_info_multiple_identities(void **state); +void disco_info_without_name(void **state); +void disco_items_without_name(void **state); +void disco_info_service_unavailable(void **state); +void disco_items_error_handling(void **state); -- 2.49.1 From 9e1b95a814f08c6467f854a38878a967c39abee1 Mon Sep 17 00:00:00 2001 From: "jabber.developer2" Date: Mon, 16 Feb 2026 11:19:18 +0300 Subject: [PATCH 4/4] test(disco): remove disco_items_error_handling test This test requires the fix from fix/xep-0030-disco-items-error-handling branch. Moved there along with the source code fix. --- tests/functionaltests/functionaltests.c | 1 - tests/functionaltests/test_disco.c | 25 ------------------------- tests/functionaltests/test_disco.h | 1 - 3 files changed, 27 deletions(-) diff --git a/tests/functionaltests/functionaltests.c b/tests/functionaltests/functionaltests.c index 0227df82..f26d1dc1 100644 --- a/tests/functionaltests/functionaltests.c +++ b/tests/functionaltests/functionaltests.c @@ -193,7 +193,6 @@ main(int argc, char* argv[]) PROF_FUNC_TEST(disco_info_without_name), PROF_FUNC_TEST(disco_items_without_name), PROF_FUNC_TEST(disco_info_service_unavailable), - PROF_FUNC_TEST(disco_items_error_handling), }; /* ============================================================ diff --git a/tests/functionaltests/test_disco.c b/tests/functionaltests/test_disco.c index c73a3d43..1d565b59 100644 --- a/tests/functionaltests/test_disco.c +++ b/tests/functionaltests/test_disco.c @@ -418,28 +418,3 @@ disco_info_service_unavailable(void **state) assert_true(prof_output_regex("Service discovery failed.*service-unavailable")); prof_timeout_reset(); } - -void -disco_items_error_handling(void **state) -{ - /* - * Test that /disco items displays error responses to user. - * Per XEP-0030 Section 7: errors like service-unavailable must be shown. - */ - stbbr_for_query("http://jabber.org/protocol/disco#items", - "" - "" - "" - "" - "" - ); - - prof_connect(); - - prof_input("/disco items broken.localhost"); - - prof_timeout(10); - /* Per XEP-0030, error should be displayed to user */ - assert_true(prof_output_regex("Service discovery failed.*service-unavailable")); - prof_timeout_reset(); -} diff --git a/tests/functionaltests/test_disco.h b/tests/functionaltests/test_disco.h index fbd7d0c2..89a45c33 100644 --- a/tests/functionaltests/test_disco.h +++ b/tests/functionaltests/test_disco.h @@ -17,4 +17,3 @@ void disco_info_multiple_identities(void **state); void disco_info_without_name(void **state); void disco_items_without_name(void **state); void disco_info_service_unavailable(void **state); -void disco_items_error_handling(void **state); -- 2.49.1