diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Makefile.am | 24 | ||||
-rw-r--r-- | tests/README | 8 | ||||
-rw-r--r-- | tests/base64.c | 18 | ||||
-rw-r--r-- | tests/send_to_self.c | 192 | ||||
-rw-r--r-- | tests/xml_parse_and_print.c | 29 | ||||
-rw-r--r-- | tests/xml_print_and_parse.c | 64 |
6 files changed, 335 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 0000000..93c0b82 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,24 @@ +AM_CFLAGS = -Werror -Wall -Wextra -pedantic -std=gnu99 + +COMMON_FLAGS = $(AM_CFLAGS) $(LIBXML_CFLAGS) $(EXPAT_CFLAGS) \ + $(GNUTLS_CFLAGS) $(LIBDANE_CFLAGS) $(OPENSSL_CFLAGS) \ + $(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(CARES_CFLAGS) $(GPGME_CFLAGS) \ + $(ICU_I18N_CFLAGS) $(LIBGCRYPT_CFLAGS) $(CURL_CFLAGS) \ + $(NICE_CFLAGS) $(GLIB_CFLAGS) $(SRTP_CFLAGS) \ + $(PORTAUDIO_CFLAGS) $(OPUS_CFLAGS) $(NETTLE_CFLAGS) +COMMON_LDADD = -L$(top_builddir)/src -lrexmpp + +send_to_self_CFLAGS = $(COMMON_FLAGS) +xml_parse_and_print_CFLAGS = $(COMMON_FLAGS) +xml_print_and_parse_CFLAGS = $(COMMON_FLAGS) +base64_CFLAGS = $(COMMON_FLAGS) + +send_to_self_LDADD = $(COMMON_LDADD) +xml_parse_and_print_LDADD = $(COMMON_LDADD) +xml_print_and_parse_LDADD = $(COMMON_LDADD) +base64_LDADD = $(COMMON_LDADD) + +check_PROGRAMS = send_to_self \ + xml_parse_and_print xml_print_and_parse base64 +TESTS = send_to_self \ + xml_parse_and_print xml_print_and_parse base64 diff --git a/tests/README b/tests/README new file mode 100644 index 0000000..7e30213 --- /dev/null +++ b/tests/README @@ -0,0 +1,8 @@ +rexmpp tests + +These tests make use of an external XMPP server. Environment variables +used by the tests: + +- JID and PASS: credentials. + +- TLS_POLICY: "require", "prefer", or "avoid". diff --git a/tests/base64.c b/tests/base64.c new file mode 100644 index 0000000..b69ba0e --- /dev/null +++ b/tests/base64.c @@ -0,0 +1,18 @@ +#include <string.h> +#include "rexmpp_base64.h" + +int main () { + char *original_plain = "test string"; + char *original_base64 = "dGVzdCBzdHJpbmc="; + char *encoded, *decoded; + size_t encoded_len, decoded_len; + if (rexmpp_base64_to(original_plain, strlen(original_plain), + &encoded, &encoded_len)) { + return -1; + } + if (rexmpp_base64_from(original_base64, strlen(original_base64), + &decoded, &decoded_len)) { + return -1; + } + return strcmp(original_plain, decoded) || strcmp(original_base64, encoded); +} diff --git a/tests/send_to_self.c b/tests/send_to_self.c new file mode 100644 index 0000000..2fcb80f --- /dev/null +++ b/tests/send_to_self.c @@ -0,0 +1,192 @@ +/** + @file send_to_self.c + @brief A basic message sending test + @author defanor <defanor@uberspace.net> + @date 2022 + @copyright MIT license. + +Connects to a server, sends a message to itself, receives it, checks +that it's the expected message. + +*/ + +#define TIMEOUT 30 + +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <syslog.h> +#include <rexmpp.h> +#include <rexmpp_sasl.h> + +enum test_stage { + TEST_CONNECTING, + TEST_MESSAGE_SENT, + TEST_MESSAGE_RECEIVED, + TEST_DONE, + TEST_TIMEOUT +}; + +enum test_stage stage = TEST_CONNECTING; +char *jid, *pass, msg_text[256]; + +void my_logger (rexmpp_t *s, int priority, const char *fmt, va_list args) { + (void)s; + char *priority_str = "unknown"; + switch (priority) { + case LOG_EMERG: priority_str = "emerg"; break; + case LOG_ALERT: priority_str = "alert"; break; + case LOG_CRIT: priority_str = "crit"; break; + case LOG_ERR: priority_str = "err"; break; + case LOG_WARNING: priority_str = "warning"; break; + case LOG_NOTICE: priority_str = "notice"; break; + case LOG_INFO: priority_str = "info"; break; + case LOG_DEBUG: priority_str = "debug"; break; + } + fprintf(stdout, "[%s] ", priority_str); + vfprintf(stdout, fmt, args); + fprintf(stdout, "\n"); +} + +int my_sasl_property_cb (rexmpp_t *s, rexmpp_sasl_property prop) { + if (prop == REXMPP_SASL_PROP_PASSWORD) { + rexmpp_sasl_property_set (s, REXMPP_SASL_PROP_PASSWORD, pass); + return 0; + } + if (prop == REXMPP_SASL_PROP_AUTHID) { + rexmpp_sasl_property_set (s, REXMPP_SASL_PROP_AUTHID, s->initial_jid.local); + return 0; + } + printf("unhandled SASL property: %d\n", prop); + return -1; +} + +int my_xml_in_cb (rexmpp_t *s, rexmpp_xml_t *node) { + (void)s; + char *xml_buf = rexmpp_xml_serialize(node, 0); + printf("recv: %s\n", xml_buf); + free(xml_buf); + if (stage == TEST_MESSAGE_SENT && rexmpp_xml_match(node, "jabber:client", "message")) { + rexmpp_xml_t *body = rexmpp_xml_find_child(node, "jabber:client", "body"); + if (body != NULL) { + char *txt = rexmpp_xml_text_child(body); + if (txt != NULL) { + if (strcmp(txt, msg_text) == 0) { + stage = TEST_MESSAGE_RECEIVED; + } + } + } + } + return 0; +} + +int my_xml_out_cb (rexmpp_t *s, rexmpp_xml_t *node) { + (void)s; + char *xml_buf = rexmpp_xml_serialize(node, 0); + printf("send: %s\n", xml_buf); + free(xml_buf); + return 0; +} + +int main () { + jid = getenv("JID"); + pass = getenv("PASS"); + char *tls_policy = getenv("TLS_POLICY"); + + time_t t = time(NULL); + struct tm utc_time; + gmtime_r(&t, &utc_time); + strftime(msg_text, 256, "The current time is %FT%TZ", &utc_time); + + rexmpp_t s; + rexmpp_err_t err; + err = rexmpp_init(&s, jid, my_logger); + if (err != REXMPP_SUCCESS) { + puts("Failed to initialise rexmpp."); + return -1; + } + if (tls_policy != NULL) { + if (strcasecmp(tls_policy, "require") == 0) { + s.tls_policy = REXMPP_TLS_REQUIRE; + } else if (strcasecmp(tls_policy, "prefer") == 0) { + s.tls_policy = REXMPP_TLS_PREFER; + } else if (strcasecmp(tls_policy, "avoid") == 0) { + s.tls_policy = REXMPP_TLS_AVOID; + } + } + + s.sasl_property_cb = my_sasl_property_cb; + s.xml_in_cb = my_xml_in_cb; + s.xml_out_cb = my_xml_out_cb; + + fd_set read_fds, write_fds; + int nfds; + struct timespec tv; + struct timespec *mtv; + struct timeval tv_ms; + struct timeval *mtv_ms; + int n = 0; + + do { + err = rexmpp_run(&s, &read_fds, &write_fds); + if (err == REXMPP_SUCCESS) { + puts("done"); + break; + } + if (err != REXMPP_E_AGAIN) { + printf("error: %s\n", rexmpp_strerror(err)); + break; + } + + if (stage == TEST_CONNECTING && s.stream_state == REXMPP_STREAM_READY) { + rexmpp_xml_t *msg = + rexmpp_xml_add_id(rexmpp_xml_new_elem("message", "jabber:client")); + rexmpp_xml_add_attr(msg, "to", jid); + rexmpp_xml_add_attr(msg, "type", "chat"); + rexmpp_xml_t *body = rexmpp_xml_new_elem("body", NULL); + rexmpp_xml_add_text(body, msg_text); + rexmpp_xml_add_child(msg, body); + rexmpp_send(&s, msg); + stage = TEST_MESSAGE_SENT; + } else if (stage == TEST_MESSAGE_RECEIVED) { + rexmpp_stop(&s); + stage = TEST_DONE; + } + + time_t now = time(NULL); + if (stage != TEST_DONE) { + if (stage != TEST_TIMEOUT && difftime(now, t) > TIMEOUT) { + puts("Timeout"); + rexmpp_stop(&s); + stage = TEST_TIMEOUT; + } else if (stage == TEST_TIMEOUT && difftime(now, t) > TIMEOUT + 10) { + puts("Failed to close the stream properly, quitting"); + rexmpp_done(&s); + return -1; + } + } + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + nfds = rexmpp_fds(&s, &read_fds, &write_fds); + tv.tv_sec = TIMEOUT; + tv.tv_nsec = 0; + mtv = rexmpp_timeout(&s, &tv, &tv); + mtv_ms = NULL; + if (mtv != NULL) { + tv_ms.tv_sec = mtv->tv_sec; + tv_ms.tv_usec = mtv->tv_nsec / 1000; + mtv_ms = &tv_ms; + } + + n = select(nfds, &read_fds, &write_fds, NULL, mtv_ms); + if (n == -1) { + printf("select error: %s\n", strerror(errno)); + break; + } + printf("stage = %u\n", stage); + } while (1); + + rexmpp_done(&s); + return (stage != TEST_DONE); +} diff --git a/tests/xml_parse_and_print.c b/tests/xml_parse_and_print.c new file mode 100644 index 0000000..c76b06f --- /dev/null +++ b/tests/xml_parse_and_print.c @@ -0,0 +1,29 @@ +#include <string.h> +#include <stdlib.h> +#include "rexmpp_xml.h" + +int main () { + int ret = 0; + + char *str = "<foo bar=\"baz\">" + "<qux xmlns=\"urn:test\">a b c d</qux>" + "<quux e=\"f\" g=\"h\"/>" + "</foo>"; + rexmpp_xml_t *xml = rexmpp_xml_parse (str, strlen(str)); + + printf("Input:\n%s\n\n", str); + if (xml == NULL) { + ret = -1; + } else { + char *str_new = rexmpp_xml_serialize (xml, 0); + if (str_new == NULL) { + ret = -2; + } else { + printf("Output:\n%s\n", str_new); + ret = strcmp(str, str_new); + free(str_new); + } + rexmpp_xml_free(xml); + } + return ret; +} diff --git a/tests/xml_print_and_parse.c b/tests/xml_print_and_parse.c new file mode 100644 index 0000000..9bd7a3f --- /dev/null +++ b/tests/xml_print_and_parse.c @@ -0,0 +1,64 @@ +#include <string.h> +#include <stdlib.h> +#include "rexmpp_xml.h" + +int main () { + int ret = 0; + + rexmpp_xml_attr_t + foo_attributes = { .qname = {"bar", NULL}, + .value = "baz", + .next = NULL }, + quux_attributes_g = { .qname = {"g", NULL}, + .value = "h", + .next = NULL }, + quux_attributes = + { .qname = {"e", NULL}, + .value = "f", + .next = &quux_attributes_g }; + rexmpp_xml_t + quux = { .type = REXMPP_XML_ELEMENT, + .alt.elem = + { .qname = {"quux", NULL}, + .attributes = &quux_attributes, + .children = NULL + }, + .next = NULL + }, + qux_text = { .type = REXMPP_XML_TEXT, + .alt.text = "a b c d", + .next = NULL }, + qux = { .type = REXMPP_XML_ELEMENT, + .alt.elem = + { .qname = {"qux", "urn:dummy"}, + .attributes = NULL, + .children = &qux_text + }, + .next = &quux + }, + xml = + { .type = REXMPP_XML_ELEMENT, + .alt.elem = + { .qname = {"foo", NULL}, + .attributes = &foo_attributes, + .children = &qux + }, + .next = NULL + }; + + char *str_new = rexmpp_xml_serialize (&xml, 0); + if (str_new == NULL) { + ret = -1; + } else { + rexmpp_xml_t *xml_new = rexmpp_xml_parse (str_new, strlen(str_new)); + if (xml_new == NULL) { + ret = -2; + } else { + /* Compare the XML structures. */ + ret = (rexmpp_xml_eq(&xml, xml_new) == 0); + rexmpp_xml_free(xml_new); + } + free(str_new); + } + return ret; +} |