From fad184c9c25cc988fb87a591ecb638b6f6b24daa Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 3 Oct 2019 16:46:15 +0100 Subject: [PATCH] Bridge remapping refactoring and tests. --- .gitignore | 1 + src/Makefile | 4 + src/bridge.c | 59 --------- src/bridge_topic.c | 214 ++++++++++++++++++++++++++++++++ src/conf.c | 118 +++--------------- src/handle_publish.c | 2 +- src/mosquitto_broker_internal.h | 3 +- test/unit/Makefile | 20 ++- test/unit/bridge_topic_test.c | 124 ++++++++++++++++++ 9 files changed, 380 insertions(+), 165 deletions(-) create mode 100644 src/bridge_topic.c create mode 100644 test/unit/bridge_topic_test.c diff --git a/.gitignore b/.gitignore index 443be88c..e20dc3cb 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,7 @@ test/ssl/signingCA/ test/lib/c/*.test test/lib/cpp/*.test +test/unit/bridge_topic_test test/unit/coverage.info test/unit/mosq_test test/unit/persist_read_test diff --git a/src/Makefile b/src/Makefile index 2517cb65..f204102b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,6 +11,7 @@ endif OBJS= mosquitto.o \ alias_mosq.o \ bridge.o \ + bridge_topic.o \ conf.o \ conf_includedir.o \ context.o \ @@ -83,6 +84,9 @@ alias_mosq.o : ../lib/alias_mosq.c ../lib/alias_mosq.h bridge.o : bridge.c mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@ +bridge_topic.o : bridge_topic.c mosquitto_broker_internal.h + ${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@ + conf.o : conf.c mosquitto_broker_internal.h ${CROSS_COMPILE}${CC} $(BROKER_CPPFLAGS) $(BROKER_CFLAGS) -c $< -o $@ diff --git a/src/bridge.c b/src/bridge.c index 1907baae..471b7155 100644 --- a/src/bridge.c +++ b/src/bridge.c @@ -760,63 +760,4 @@ void bridge_check(struct mosquitto_db *db, struct pollfd *pollfds, int *pollfd_i } } - -int bridge__remap_topic(struct mosquitto *context, char **topic) -{ - struct mosquitto__bridge_topic *cur_topic; - char *topic_temp; - int i; - int len; - int rc; - bool match; - - if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){ - for(i=0; ibridge->topic_count; i++){ - cur_topic = &context->bridge->topics[i]; - if((cur_topic->direction == bd_both || cur_topic->direction == bd_in) - && (cur_topic->remote_prefix || cur_topic->local_prefix)){ - - /* Topic mapping required on this topic if the message matches */ - - rc = mosquitto_topic_matches_sub(cur_topic->remote_topic, *topic, &match); - if(rc){ - mosquitto__free(*topic); - return rc; - } - if(match){ - if(cur_topic->remote_prefix){ - /* This prefix needs removing. */ - if(!strncmp(cur_topic->remote_prefix, *topic, strlen(cur_topic->remote_prefix))){ - topic_temp = mosquitto__strdup((*topic)+strlen(cur_topic->remote_prefix)); - if(!topic_temp){ - mosquitto__free(*topic); - return MOSQ_ERR_NOMEM; - } - mosquitto__free(*topic); - *topic = topic_temp; - } - } - - if(cur_topic->local_prefix){ - /* This prefix needs adding. */ - len = strlen(*topic) + strlen(cur_topic->local_prefix)+1; - topic_temp = mosquitto__malloc(len+1); - if(!topic_temp){ - mosquitto__free(*topic); - return MOSQ_ERR_NOMEM; - } - snprintf(topic_temp, len, "%s%s", cur_topic->local_prefix, *topic); - topic_temp[len] = '\0'; - - mosquitto__free(*topic); - *topic = topic_temp; - } - break; - } - } - } - } - - return MOSQ_ERR_SUCCESS; -} #endif diff --git a/src/bridge_topic.c b/src/bridge_topic.c new file mode 100644 index 00000000..d9ad8e21 --- /dev/null +++ b/src/bridge_topic.c @@ -0,0 +1,214 @@ +/* +Copyright (c) 2009-2019 Roger Light + +All rights reserved. This program and the accompanying materials +are made available under the terms of the Eclipse Public License v1.0 +and Eclipse Distribution License v1.0 which accompany this distribution. + +The Eclipse Public License is available at + http://www.eclipse.org/legal/epl-v10.html +and the Eclipse Distribution License is available at + http://www.eclipse.org/org/documents/edl-v10.php. + +Contributors: + Roger Light - initial implementation and documentation. +*/ + +#include "config.h" + +#include "mosquitto.h" +#include "mosquitto_broker_internal.h" +#include "memory_mosq.h" + +#ifdef WITH_BRIDGE + + +/* topic [[[out | in | both] qos-level] local-prefix remote-prefix] */ +int bridge__add_topic(struct mosquitto__bridge *bridge, const char *topic, enum mosquitto__bridge_direction direction, int qos, const char *local_prefix, const char *remote_prefix) +{ + struct mosquitto__bridge_topic *topics; + struct mosquitto__bridge_topic *cur_topic; + int len; + + + if(bridge == NULL) return MOSQ_ERR_INVAL; + if(direction != bd_out && direction != bd_in && direction != bd_both){ + return MOSQ_ERR_INVAL; + } + if(qos < 0 || qos > 2){ + return MOSQ_ERR_INVAL; + } + if(local_prefix && mosquitto_pub_topic_check(local_prefix)){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic local prefix '%s'.", local_prefix); + return MOSQ_ERR_INVAL; + } + if(remote_prefix && mosquitto_pub_topic_check(remote_prefix)){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic remote prefix '%s'.", remote_prefix); + return MOSQ_ERR_INVAL; + } + if((topic == NULL || !strcmp(topic, "\"\"")) && + (local_prefix == NULL || remote_prefix == NULL)){ + + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge remapping."); + return MOSQ_ERR_INVAL; + } + + + bridge->topic_count++; + topics = mosquitto__realloc(bridge->topics, + sizeof(struct mosquitto__bridge_topic)*bridge->topic_count); + + if(topics == NULL){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + bridge->topics = topics; + + cur_topic = &bridge->topics[bridge->topic_count-1]; + cur_topic->direction = direction; + cur_topic->qos = qos; + cur_topic->local_prefix = NULL; + cur_topic->remote_prefix = NULL; + + if(topic == NULL || !strcmp(topic, "\"\"")){ + cur_topic->topic = NULL; + }else{ + cur_topic->topic = mosquitto__strdup(topic); + if(cur_topic->topic == NULL){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + } + + if(local_prefix || remote_prefix){ + bridge->topic_remapping = true; + if(local_prefix){ + cur_topic->local_prefix = mosquitto__strdup(local_prefix); + if(cur_topic->local_prefix == NULL){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + } + if(remote_prefix){ + cur_topic->remote_prefix = mosquitto__strdup(remote_prefix); + if(cur_topic->remote_prefix == NULL){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + } + } + + if(cur_topic->local_prefix){ + if(cur_topic->topic){ + len = strlen(cur_topic->topic) + strlen(cur_topic->local_prefix)+1; + cur_topic->local_topic = mosquitto__malloc(len+1); + if(!cur_topic->local_topic){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + snprintf(cur_topic->local_topic, len+1, "%s%s", cur_topic->local_prefix, cur_topic->topic); + cur_topic->local_topic[len] = '\0'; + }else{ + cur_topic->local_topic = mosquitto__strdup(cur_topic->local_prefix); + if(!cur_topic->local_topic){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + } + }else{ + cur_topic->local_topic = mosquitto__strdup(cur_topic->topic); + if(!cur_topic->local_topic){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + } + + if(cur_topic->remote_prefix){ + if(cur_topic->topic){ + len = strlen(cur_topic->topic) + strlen(cur_topic->remote_prefix)+1; + cur_topic->remote_topic = mosquitto__malloc(len+1); + if(!cur_topic->remote_topic){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + snprintf(cur_topic->remote_topic, len, "%s%s", cur_topic->remote_prefix, cur_topic->topic); + cur_topic->remote_topic[len] = '\0'; + }else{ + cur_topic->remote_topic = mosquitto__strdup(cur_topic->remote_prefix); + if(!cur_topic->remote_topic){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + } + }else{ + cur_topic->remote_topic = mosquitto__strdup(cur_topic->topic); + if(!cur_topic->remote_topic){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); + return MOSQ_ERR_NOMEM; + } + } + + return MOSQ_ERR_SUCCESS; +} + + +int bridge__remap_topic_in(struct mosquitto *context, char **topic) +{ + struct mosquitto__bridge_topic *cur_topic; + char *topic_temp; + int i; + int len; + int rc; + bool match; + + if(context->bridge && context->bridge->topics && context->bridge->topic_remapping){ + for(i=0; ibridge->topic_count; i++){ + cur_topic = &context->bridge->topics[i]; + if((cur_topic->direction == bd_both || cur_topic->direction == bd_in) + && (cur_topic->remote_prefix || cur_topic->local_prefix)){ + + /* Topic mapping required on this topic if the message matches */ + + rc = mosquitto_topic_matches_sub(cur_topic->remote_topic, *topic, &match); + if(rc){ + mosquitto__free(*topic); + return rc; + } + if(match){ + if(cur_topic->remote_prefix){ + /* This prefix needs removing. */ + if(!strncmp(cur_topic->remote_prefix, *topic, strlen(cur_topic->remote_prefix))){ + topic_temp = mosquitto__strdup((*topic)+strlen(cur_topic->remote_prefix)); + if(!topic_temp){ + mosquitto__free(*topic); + return MOSQ_ERR_NOMEM; + } + mosquitto__free(*topic); + *topic = topic_temp; + } + } + + if(cur_topic->local_prefix){ + /* This prefix needs adding. */ + len = strlen(*topic) + strlen(cur_topic->local_prefix)+1; + topic_temp = mosquitto__malloc(len+1); + if(!topic_temp){ + mosquitto__free(*topic); + return MOSQ_ERR_NOMEM; + } + snprintf(topic_temp, len, "%s%s", cur_topic->local_prefix, *topic); + topic_temp[len] = '\0'; + + mosquitto__free(*topic); + *topic = topic_temp; + } + break; + } + } + } + } + + return MOSQ_ERR_SUCCESS; +} + +#endif diff --git a/src/conf.c b/src/conf.c index 53c622cf..ace524c5 100644 --- a/src/conf.c +++ b/src/conf.c @@ -785,8 +785,6 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct #ifdef WITH_BRIDGE char *tmp_char; struct mosquitto__bridge *cur_bridge = NULL; - struct mosquitto__bridge_topic *cur_topic; - int len; #endif struct mosquitto__auth_plugin_config *cur_auth_plugin_config = NULL; @@ -1973,29 +1971,14 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge configuration."); return MOSQ_ERR_INVAL; } + char *topic = NULL; + enum mosquitto__bridge_direction direction = bd_out; + int qos = 0; + char *local_prefix = NULL, *remote_prefix = NULL; + token = strtok_r(NULL, " ", &saveptr); if(token){ - cur_bridge->topic_count++; - cur_bridge->topics = mosquitto__realloc(cur_bridge->topics, - sizeof(struct mosquitto__bridge_topic)*cur_bridge->topic_count); - if(!cur_bridge->topics){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - cur_topic = &cur_bridge->topics[cur_bridge->topic_count-1]; - if(!strcmp(token, "\"\"")){ - cur_topic->topic = NULL; - }else{ - cur_topic->topic = mosquitto__strdup(token); - if(!cur_topic->topic){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - } - cur_topic->direction = bd_out; - cur_topic->qos = 0; - cur_topic->local_prefix = NULL; - cur_topic->remote_prefix = NULL; + topic = token; }else{ log__printf(NULL, MOSQ_LOG_ERR, "Error: Empty topic value in configuration."); return MOSQ_ERR_INVAL; @@ -2003,11 +1986,11 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct token = strtok_r(NULL, " ", &saveptr); if(token){ if(!strcasecmp(token, "out")){ - cur_topic->direction = bd_out; + direction = bd_out; }else if(!strcasecmp(token, "in")){ - cur_topic->direction = bd_in; + direction = bd_in; }else if(!strcasecmp(token, "both")){ - cur_topic->direction = bd_both; + direction = bd_both; }else{ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic direction '%s'.", token); return MOSQ_ERR_INVAL; @@ -2017,106 +2000,37 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct if (token[0] == '#'){ strtok_r(NULL, "", &saveptr); } - cur_topic->qos = atoi(token); - if(cur_topic->qos < 0 || cur_topic->qos > 2){ + qos = atoi(token); + if(qos < 0 || qos > 2){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge QoS level '%s'.", token); return MOSQ_ERR_INVAL; } token = strtok_r(NULL, " ", &saveptr); if(token){ - cur_bridge->topic_remapping = true; if(!strcmp(token, "\"\"") || token[0] == '#'){ - cur_topic->local_prefix = NULL; + local_prefix = NULL; if (token[0] == '#'){ strtok_r(NULL, "", &saveptr); } }else{ - if(mosquitto_pub_topic_check(token) != MOSQ_ERR_SUCCESS){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic local prefix '%s'.", token); - return MOSQ_ERR_INVAL; - } - cur_topic->local_prefix = mosquitto__strdup(token); - if(!cur_topic->local_prefix){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } + local_prefix = token; } token = strtok_r(NULL, " ", &saveptr); if(token){ if(!strcmp(token, "\"\"") || token[0] == '#'){ - cur_topic->remote_prefix = NULL; + remote_prefix = NULL; }else{ - if(mosquitto_pub_topic_check(token) != MOSQ_ERR_SUCCESS){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic remote prefix '%s'.", token); - return MOSQ_ERR_INVAL; - } - cur_topic->remote_prefix = mosquitto__strdup(token); - if(!cur_topic->remote_prefix){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } + remote_prefix = mosquitto__strdup(token); } } } } } - if(cur_topic->topic == NULL && - (cur_topic->local_prefix == NULL || cur_topic->remote_prefix == NULL)){ - - log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge remapping."); + if(bridge__add_topic(cur_bridge, topic, direction, qos, local_prefix, remote_prefix)){ return MOSQ_ERR_INVAL; } - if(cur_topic->local_prefix){ - if(cur_topic->topic){ - len = strlen(cur_topic->topic) + strlen(cur_topic->local_prefix)+1; - cur_topic->local_topic = mosquitto__malloc(len+1); - if(!cur_topic->local_topic){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - snprintf(cur_topic->local_topic, len+1, "%s%s", cur_topic->local_prefix, cur_topic->topic); - cur_topic->local_topic[len] = '\0'; - }else{ - cur_topic->local_topic = mosquitto__strdup(cur_topic->local_prefix); - if(!cur_topic->local_topic){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - } - }else{ - cur_topic->local_topic = mosquitto__strdup(cur_topic->topic); - if(!cur_topic->local_topic){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - } - - if(cur_topic->remote_prefix){ - if(cur_topic->topic){ - len = strlen(cur_topic->topic) + strlen(cur_topic->remote_prefix)+1; - cur_topic->remote_topic = mosquitto__malloc(len+1); - if(!cur_topic->remote_topic){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - snprintf(cur_topic->remote_topic, len, "%s%s", cur_topic->remote_prefix, cur_topic->topic); - cur_topic->remote_topic[len] = '\0'; - }else{ - cur_topic->remote_topic = mosquitto__strdup(cur_topic->remote_prefix); - if(!cur_topic->remote_topic){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - } - }else{ - cur_topic->remote_topic = mosquitto__strdup(cur_topic->topic); - if(!cur_topic->remote_topic){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory."); - return MOSQ_ERR_NOMEM; - } - } #else log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Bridge support not available."); #endif diff --git a/src/handle_publish.c b/src/handle_publish.c index bc414037..9932c5ab 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -184,7 +184,7 @@ int handle__publish(struct mosquitto_db *db, struct mosquitto *context) } #ifdef WITH_BRIDGE - rc = bridge__remap_topic(context, &topic); + rc = bridge__remap_topic_in(context, &topic); if(rc) return rc; #endif diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 651cef15..ea2ecbf8 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -685,7 +685,8 @@ void bridge_check(struct mosquitto_db *db); void bridge_check(struct mosquitto_db *db, struct pollfd *pollfds, int *pollfd_index); #endif int bridge__register_local_connections(struct mosquitto_db *db); -int bridge__remap_topic(struct mosquitto *context, char **topic); +int bridge__add_topic(struct mosquitto__bridge *bridge, const char *topic, enum mosquitto__bridge_direction direction, int qos, const char *local_prefix, const char *remote_prefix); +int bridge__remap_topic_in(struct mosquitto *context, char **topic); #endif /* ============================================================ diff --git a/test/unit/Makefile b/test/unit/Makefile index 9d422428..98af7eb1 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -24,6 +24,15 @@ LIB_OBJS = memory_mosq.o \ util_topic.o \ utf8_mosq.o +BRIDGE_TOPIC_TEST_OBJS = \ + bridge_topic_test.o \ + stubs.o \ + +BRIDGE_TOPIC_OBJS = \ + bridge_topic.o \ + memory_mosq.o \ + util_topic.o \ + PERSIST_READ_TEST_OBJS = \ persist_read_test.o \ persist_read_stubs.o @@ -63,6 +72,9 @@ check : test mosq_test : ${TEST_OBJS} ${LIB_OBJS} $(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^ $(LDADD) +bridge_topic_test : ${BRIDGE_TOPIC_TEST_OBJS} ${BRIDGE_TOPIC_OBJS} + $(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^ $(LDADD) + persist_read_test : ${PERSIST_READ_TEST_OBJS} ${PERSIST_READ_OBJS} $(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^ $(LDADD) @@ -70,6 +82,9 @@ persist_write_test : ${PERSIST_WRITE_TEST_OBJS} ${PERSIST_WRITE_OBJS} $(CROSS_COMPILE)$(CC) $(LDFLAGS) -o $@ $^ $(LDADD) +bridge_topic.o : ../../src/bridge_topic.c + $(CROSS_COMPILE)$(CC) $(CPPFLAGS) $(CFLAGS) -DWITH_BROKER -DWITH_BRIDGE -c -o $@ $^ + database.o : ../../src/database.c $(CROSS_COMPILE)$(CC) $(CPPFLAGS) $(CFLAGS) -DWITH_BROKER -DWITH_PERSISTENCE -c -o $@ $^ @@ -112,14 +127,15 @@ utf8_mosq.o : ../../lib/utf8_mosq.c test-lib : mosq_test ./mosq_test -test-broker : persist_read_test persist_write_test +test-broker : bridge_topic_test persist_read_test persist_write_test + ./bridge_topic_test ./persist_read_test ./persist_write_test test : test-broker test-lib clean : - -rm -rf mosq_test persist_read_test persist_write_test + -rm -rf mosq_test bridge_topic_test persist_read_test persist_write_test -rm -rf *.o *.gcda *.gcno coverage.info out/ coverage : diff --git a/test/unit/bridge_topic_test.c b/test/unit/bridge_topic_test.c new file mode 100644 index 00000000..14992af8 --- /dev/null +++ b/test/unit/bridge_topic_test.c @@ -0,0 +1,124 @@ +#include "config.h" +#include + +#include +#include + +#define WITH_BRIDGE +#define WITH_BROKER + +#include "mosquitto_broker_internal.h" +#include "property_mosq.h" +#include "packet_mosq.h" + +static void map_valid_helper(const char *topic, const char *local_prefix, const char *remote_prefix, const char *incoming, const char *expected) +{ + struct mosquitto mosq; + struct mosquitto__bridge bridge; + char *map_topic; + int rc; + + memset(&mosq, 0, sizeof(struct mosquitto)); + memset(&bridge, 0, sizeof(struct mosquitto__bridge)); + + mosq.bridge = &bridge; + + rc = bridge__add_topic(&bridge, topic, bd_in, 0, local_prefix, remote_prefix); + CU_ASSERT_EQUAL(rc, 0); + + map_topic = strdup(incoming); + rc = bridge__remap_topic_in(&mosq, &map_topic); + CU_ASSERT_EQUAL(rc, 0); + CU_ASSERT_PTR_NOT_NULL(map_topic); + if(topic){ + CU_ASSERT_STRING_EQUAL(map_topic, expected); + free(map_topic); + } +} + +static void map_invalid_helper(const char *topic, const char *local_prefix, const char *remote_prefix) +{ + struct mosquitto mosq; + struct mosquitto__bridge bridge; + int rc; + + memset(&mosq, 0, sizeof(struct mosquitto)); + memset(&bridge, 0, sizeof(struct mosquitto__bridge)); + + mosq.bridge = &bridge; + + rc = bridge__add_topic(&bridge, topic, bd_in, 0, local_prefix, remote_prefix); + CU_ASSERT_NOT_EQUAL(rc, 0); +} + + +static void TEST_remap_valid(void) +{ + /* Examples from man page */ + map_valid_helper("pattern", "L/", "R/", "R/pattern", "L/pattern"); + map_valid_helper("pattern", "L/", NULL, "pattern", "L/pattern"); + map_valid_helper("pattern", NULL, "R/", "R/pattern", "pattern"); + map_valid_helper("pattern", NULL, NULL, "pattern", "pattern"); + map_valid_helper(NULL, "local", "remote", "local", "remote"); +} + +static void TEST_remap_invalid(void) +{ + /* Examples from man page */ + map_invalid_helper(NULL, "L/", NULL); + map_invalid_helper(NULL, NULL, "R/"); + map_invalid_helper(NULL, NULL, NULL); +} + + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_bridge_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Bridge remap", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit Bridge remap test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Remap valid", TEST_remap_valid) + || !CU_add_test(test_suite, "Remap invalid", TEST_remap_invalid) + ){ + + printf("Error adding Bridge remap CUnit tests.\n"); + return 1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + unsigned int fails; + + if(CU_initialize_registry() != CUE_SUCCESS){ + printf("Error initializing CUnit registry.\n"); + return 1; + } + + if(0 + || init_bridge_tests() + ){ + + CU_cleanup_registry(); + return 1; + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + fails = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return (int)fails; +} +