/* * 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.")); }