From 9411d9484227c9d4955902875e938ce6b37ba5ad Mon Sep 17 00:00:00 2001 From: "Roger A. Light" Date: Thu, 14 Mar 2019 20:57:25 +0000 Subject: [PATCH] Start of tests for persistence reading. --- .gitignore | 3 +- src/database.c | 4 +- src/persist_read.c | 5 +- test/unit/Makefile | 32 +- .../persist_read/corrupt-header-long.test-db | 1 + .../persist_read/corrupt-header-short.test-db | 1 + test/unit/files/persist_read/empty.test-db | 0 .../persist_read/unsupported-version.test-db | Bin 0 -> 23 bytes .../files/persist_read/v3-bad-chunk.test-db | Bin 0 -> 52 bytes .../persist_read/v3-cfg-bad-dbid.test-db | Bin 0 -> 39 bytes .../persist_read/v3-cfg-truncated.test-db | Bin 0 -> 38 bytes test/unit/files/persist_read/v3-cfg.test-db | Bin 0 -> 39 bytes .../persist_read/v3-client-message.test-db | Bin 0 -> 147 bytes .../unit/files/persist_read/v3-client.test-db | Bin 0 -> 66 bytes .../persist_read/v3-message-store.test-db | Bin 0 -> 88 bytes .../unit/files/persist_read/v3-retain.test-db | Bin 0 -> 102 bytes test/unit/files/persist_read/v3-sub.test-db | Bin 0 -> 98 bytes .../persist_read/v4-message-store.test-db | Bin 0 -> 100 bytes test/unit/persist_read_stubs.c | 133 ++++++ test/unit/persist_read_test.c | 436 ++++++++++++++++++ 20 files changed, 606 insertions(+), 9 deletions(-) create mode 100644 test/unit/files/persist_read/corrupt-header-long.test-db create mode 100644 test/unit/files/persist_read/corrupt-header-short.test-db create mode 100644 test/unit/files/persist_read/empty.test-db create mode 100644 test/unit/files/persist_read/unsupported-version.test-db create mode 100644 test/unit/files/persist_read/v3-bad-chunk.test-db create mode 100644 test/unit/files/persist_read/v3-cfg-bad-dbid.test-db create mode 100644 test/unit/files/persist_read/v3-cfg-truncated.test-db create mode 100644 test/unit/files/persist_read/v3-cfg.test-db create mode 100644 test/unit/files/persist_read/v3-client-message.test-db create mode 100644 test/unit/files/persist_read/v3-client.test-db create mode 100644 test/unit/files/persist_read/v3-message-store.test-db create mode 100644 test/unit/files/persist_read/v3-retain.test-db create mode 100644 test/unit/files/persist_read/v3-sub.test-db create mode 100644 test/unit/files/persist_read/v4-message-store.test-db create mode 100644 test/unit/persist_read_stubs.c create mode 100644 test/unit/persist_read_test.c diff --git a/.gitignore b/.gitignore index c11faa12..f2bce9a9 100644 --- a/.gitignore +++ b/.gitignore @@ -62,7 +62,8 @@ test/lib/cpp/*.test test/unit/coverage.info test/unit/mosq_test -test/unit/out +test/unit/persist_read_test +test/unit/out/ www/cache/ __pycache__ diff --git a/src/database.c b/src/database.c index 4c80479e..99b9dfef 100644 --- a/src/database.c +++ b/src/database.c @@ -129,9 +129,7 @@ int db__open(struct mosquitto__config *config, struct mosquitto_db *db) db->unpwd = NULL; #ifdef WITH_PERSISTENCE - if(config->persistence && config->persistence_filepath){ - if(persist__restore(db)) return 1; - } + if(persist__restore(db)) return 1; #endif return MOSQ_ERR_SUCCESS; diff --git a/src/persist_read.c b/src/persist_read.c index 7b08ce13..6efb2fb8 100644 --- a/src/persist_read.c +++ b/src/persist_read.c @@ -438,7 +438,10 @@ int persist__restore(struct mosquitto_db *db) assert(db); assert(db->config); - assert(db->config->persistence_filepath); + + if(!db->config->persistence || db->config->persistence_filepath == NULL){ + return MOSQ_ERR_SUCCESS; + } db->msg_store_load = NULL; diff --git a/test/unit/Makefile b/test/unit/Makefile index b627cbde..b6640b39 100644 --- a/test/unit/Makefile +++ b/test/unit/Makefile @@ -1,8 +1,8 @@ include ../../config.mk -.PHONY: all test clean coverage +.PHONY: all test test-broker test-lib clean coverage -CFLAGS=-I../.. -I../../lib -coverage -Wall -ggdb +CFLAGS=-I../.. -I../../lib -I../../src -coverage -Wall -ggdb TEST_LDFLAGS=-lcunit -coverage TEST_OBJS = test.o \ @@ -22,31 +22,55 @@ LIB_OBJS = memory_mosq.o \ util_topic.o \ utf8_mosq.o +PERSIST_READ_TEST_OBJS = \ + persist_read_test.o \ + persist_read_stubs.o + +PERSIST_READ_OBJS = \ + memory_mosq.o \ + persist_read.o \ + util_mosq.o + all : test mosq_test : ${TEST_OBJS} ${LIB_OBJS} $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} +persist_read_test : ${PERSIST_READ_TEST_OBJS} ${PERSIST_READ_OBJS} + $(CROSS_COMPILE)$(CC) -o $@ $^ ${TEST_LDFLAGS} + memory_mosq.o : ../../lib/memory_mosq.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ packet_datatypes.o : ../../lib/packet_datatypes.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ +persist_read.o : ../../src/persist_read.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -DWITH_BROKER -DWITH_PERSISTENCE -c -o $@ $^ + property_mosq.o : ../../lib/property_mosq.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ +util_mosq.o : ../../lib/util_mosq.c + $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ + util_topic.o : ../../lib/util_topic.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ utf8_mosq.o : ../../lib/utf8_mosq.c $(CROSS_COMPILE)$(CC) $(CFLAGS) -c -o $@ $^ -test : mosq_test +test-lib : mosq_test ./mosq_test +test-broker : persist_read_test + ./persist_read_test + +test : test-broker test-lib + clean : - -rm -rf mosq_test *.o *.gcda *.gcno coverage.info out/ + -rm -rf mosq_test persist_read_test + -rm -rf *.o *.gcda *.gcno coverage.info out/ coverage : lcov --capture --directory . --output-file coverage.info diff --git a/test/unit/files/persist_read/corrupt-header-long.test-db b/test/unit/files/persist_read/corrupt-header-long.test-db new file mode 100644 index 00000000..7fa94b12 --- /dev/null +++ b/test/unit/files/persist_read/corrupt-header-long.test-db @@ -0,0 +1 @@ +corruptcorruptcorruptcorruptcorruptcorrupt diff --git a/test/unit/files/persist_read/corrupt-header-short.test-db b/test/unit/files/persist_read/corrupt-header-short.test-db new file mode 100644 index 00000000..4d5a80d5 --- /dev/null +++ b/test/unit/files/persist_read/corrupt-header-short.test-db @@ -0,0 +1 @@ +corrupt diff --git a/test/unit/files/persist_read/empty.test-db b/test/unit/files/persist_read/empty.test-db new file mode 100644 index 00000000..e69de29b diff --git a/test/unit/files/persist_read/unsupported-version.test-db b/test/unit/files/persist_read/unsupported-version.test-db new file mode 100644 index 0000000000000000000000000000000000000000..1d3177d9d0d92986d9f0d76f7407035b1e61ef30 GIT binary patch literal 23 bcmZSB%8;91Tv(b}Qj)KblEeT6|A7DiVU!7t literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-bad-chunk.test-db b/test/unit/files/persist_read/v3-bad-chunk.test-db new file mode 100644 index 0000000000000000000000000000000000000000..9936a8f7948b3ada905f5328f817c3994b3aa842 GIT binary patch literal 52 vcmZSB%8;91Tv(b}Qj)KblEeT3%>Vxb8SHua$r+`2*$j+84i_VbI8+t@Z<`9b literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-cfg-bad-dbid.test-db b/test/unit/files/persist_read/v3-cfg-bad-dbid.test-db new file mode 100644 index 0000000000000000000000000000000000000000..d85dace9d96c6e12e7570b7a443d22fd8f4fe85a GIT binary patch literal 39 jcmZSB%8;91Tv(b}Qj)KblEeT3%nXb`1{WhIl+OSFvAG4Q literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-cfg-truncated.test-db b/test/unit/files/persist_read/v3-cfg-truncated.test-db new file mode 100644 index 0000000000000000000000000000000000000000..9a8943b6e0ddd43b9f90be9a4b963eef81912cf8 GIT binary patch literal 38 icmZSB%8;91Tv(b}Qj)KblEeT3%nXb`1{Wg-ln(%`2nDDB literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-cfg.test-db b/test/unit/files/persist_read/v3-cfg.test-db new file mode 100644 index 0000000000000000000000000000000000000000..78d0ec5a52ac42c5ed705b5981f6ef10004ab6fb GIT binary patch literal 39 mcmZSB%8;91Tv(b}Qj)KblEeT3%nXb`1{Wg-h%00gRsjIBxCXoc literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-client-message.test-db b/test/unit/files/persist_read/v3-client-message.test-db new file mode 100644 index 0000000000000000000000000000000000000000..01a83e58ceb8a87798a27c9135cd9835ebcabde3 GIT binary patch literal 147 zcmZSB%8;91Tv(b}Qj)KblEeT3%nXb`1{Wg-h%00gR>8moVugSR5a2A%FD*(=jn7O0 zN-#69mgE;?CNqKbuoom&=Hw@)Ft9-sCg)_P=9TDXrUbPsgGGP@Gny3K*kVQoMrH;8 Db#@ra literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-client.test-db b/test/unit/files/persist_read/v3-client.test-db new file mode 100644 index 0000000000000000000000000000000000000000..378601e59235de8abf03904b601e2856e4732d91 GIT binary patch literal 66 zcmZSB%8;91Tv(b}Qj)KblEeT3%nXb`1{Wg-h%00gR>8mqmf%dz$xO{F(alT=YF7q} HFfafBsCx@Q literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-message-store.test-db b/test/unit/files/persist_read/v3-message-store.test-db new file mode 100644 index 0000000000000000000000000000000000000000..beceeda9f94d2e43caa11a6129226510ca683c9c GIT binary patch literal 88 zcmZSB%8;91Tv(b}Qj)KblEeT3%nXb`1{Wg-h%00gR>8moVu1v~fU`Kiv?w_>J~IU< Y!OXx~l3$RS%mk8VFG#G+$xloH0GpQ&q5uE@ literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-retain.test-db b/test/unit/files/persist_read/v3-retain.test-db new file mode 100644 index 0000000000000000000000000000000000000000..0265060f78873f9b401cf2e4d71a4cd5b3519d10 GIT binary patch literal 102 zcmZSB%8;91Tv(b}Qj)KblEeT3%nXb`1{Wg-h%00gR>8moVugSR5a2A%FD*(=jn7O0 fN-#69mgE;?CNqKbuoom&=Hw@)FtC8s!88B>i_s8G literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v3-sub.test-db b/test/unit/files/persist_read/v3-sub.test-db new file mode 100644 index 0000000000000000000000000000000000000000..dc2cda7bc3064a22df317ce2640f7be612fbf4a1 GIT binary patch literal 98 zcmZSB%8;91Tv(b}Qj)KblEeT3%nXb`1{Wg-h%00oR>8mqmf%dz$xO{F(alT=YF7q} Y00~w!DF&Y6(xl?#qRfJl%=|n?0DpiJ`Tzg` literal 0 HcmV?d00001 diff --git a/test/unit/files/persist_read/v4-message-store.test-db b/test/unit/files/persist_read/v4-message-store.test-db new file mode 100644 index 0000000000000000000000000000000000000000..a3059b527fecfa71c1b92cbd0020bcb4949ddff7 GIT binary patch literal 100 zcmZSB%8;91Tv(b}Qj)KblEeT3EDVf51{Wg-h%00gR>8moVhI?9l+D<6=N|)Saeir0 qa%y~L3Ij)JacWUsVs0vXG(!ha4Qok$L1r>YI|F+`Vr5Q#VhR9jS{Nk& literal 0 HcmV?d00001 diff --git a/test/unit/persist_read_stubs.c b/test/unit/persist_read_stubs.c new file mode 100644 index 00000000..267cdb12 --- /dev/null +++ b/test/unit/persist_read_stubs.c @@ -0,0 +1,133 @@ +#include + +#define WITH_BROKER + +#include +#include +#include +#include +#include +#include + +extern uint64_t last_retained; +extern char *last_sub; +extern int last_qos; + +struct mosquitto *context__init(struct mosquitto_db *db, mosq_sock_t sock) +{ + return mosquitto__calloc(1, sizeof(struct mosquitto)); +} + +int db__message_store(struct mosquitto_db *db, const struct mosquitto *source, uint16_t source_mid, char *topic, int qos, uint32_t payloadlen, mosquitto__payload_uhpa *payload, int retain, struct mosquitto_msg_store **stored, uint32_t message_expiry_interval, mosquitto_property *properties, dbid_t store_id) +{ + struct mosquitto_msg_store *temp = NULL; + int rc = MOSQ_ERR_SUCCESS; + + temp = mosquitto__calloc(1, sizeof(struct mosquitto_msg_store)); + if(!temp){ + rc = MOSQ_ERR_NOMEM; + goto error; + } + + if(source && source->id){ + temp->source_id = mosquitto__strdup(source->id); + }else{ + temp->source_id = mosquitto__strdup(""); + } + if(!temp->source_id){ + rc = MOSQ_ERR_NOMEM; + goto error; + } + + if(source && source->username){ + temp->source_username = mosquitto__strdup(source->username); + if(!temp->source_username){ + rc = MOSQ_ERR_NOMEM; + goto error; + } + } + if(source){ + temp->source_listener = source->listener; + } + temp->source_mid = source_mid; + temp->mid = 0; + temp->qos = qos; + temp->retain = retain; + temp->topic = topic; + topic = NULL; + temp->payloadlen = payloadlen; + temp->properties = properties; + if(payloadlen){ + UHPA_MOVE(temp->payload, *payload, payloadlen); + }else{ + temp->payload.ptr = NULL; + } + if(message_expiry_interval > 0){ + temp->message_expiry_time = time(NULL) + message_expiry_interval; + }else{ + temp->message_expiry_time = 0; + } + + temp->dest_ids = NULL; + temp->dest_id_count = 0; + db->msg_store_count++; + db->msg_store_bytes += payloadlen; + (*stored) = temp; + + if(!store_id){ + temp->db_id = ++db->last_db_id; + }else{ + temp->db_id = store_id; + } + + db->msg_store = temp; + + return MOSQ_ERR_SUCCESS; +error: + mosquitto__free(topic); + if(temp){ + mosquitto__free(temp->source_id); + mosquitto__free(temp->source_username); + mosquitto__free(temp->topic); + mosquitto__free(temp); + } + UHPA_FREE(*payload, payloadlen); + return rc; +} + +int log__printf(struct mosquitto *mosq, int priority, const char *fmt, ...) +{ + return 0; +} + +time_t mosquitto_time(void) +{ + return 123; +} + +int net__socket_close(struct mosquitto_db *db, struct mosquitto *mosq) +{ + return MOSQ_ERR_SUCCESS; +} + +int send__pingreq(struct mosquitto *mosq) +{ + return MOSQ_ERR_SUCCESS; +} + +int sub__add(struct mosquitto_db *db, struct mosquitto *context, const char *sub, int qos, uint32_t identifier, int options, struct mosquitto__subhier **root) +{ + last_sub = strdup(sub); + last_qos = qos; + + return MOSQ_ERR_SUCCESS; +} + +int sub__messages_queue(struct mosquitto_db *db, const char *source_id, const char *topic, int qos, int retain, struct mosquitto_msg_store **stored) +{ + if(retain){ + last_retained = (*stored)->db_id; + } + return MOSQ_ERR_SUCCESS; +} + diff --git a/test/unit/persist_read_test.c b/test/unit/persist_read_test.c new file mode 100644 index 00000000..942ee35e --- /dev/null +++ b/test/unit/persist_read_test.c @@ -0,0 +1,436 @@ +/* Tests for persistence. + * + * FIXME - these need to be aggressive about finding failures, at the moment + * they are just confirming that good behaviour works. */ + +#include +#include + +#define WITH_BROKER +#define WITH_PERSISTENCE + +#include "mosquitto_broker_internal.h" +#include "persist.h" + +uint64_t last_retained; +char *last_sub = NULL; +int last_qos; + +static void TEST_persistence_disabled(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); +} + + +static void TEST_empty_file(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + + config.persistence_filepath = "files/persist_read/empty.test-db"; + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); +} + + +static void TEST_corrupt_header(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + + config.persistence_filepath = "files/persist_read/corrupt-header-short.test-db"; + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, 1); + + config.persistence_filepath = "files/persist_read/corrupt-header-long.test-db"; + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, 1); +} + +static void TEST_unsupported_version(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/unsupported-version.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, 1); +} + + +static void TEST_v3_config_ok(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-cfg.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(db.last_db_id, 0x7856341200000000); +} + + +static void TEST_v3_config_truncated(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-cfg-truncated.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, 1); + CU_ASSERT_EQUAL(db.last_db_id, 0); +} + + +static void TEST_v3_config_bad_dbid(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-cfg-bad-dbid.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, 1); + CU_ASSERT_EQUAL(db.last_db_id, 0); +} + + +static void TEST_v3_bad_chunk(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-bad-chunk.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(db.last_db_id, 0x17); +} + + +static void TEST_v3_message_store(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-message-store.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(db.msg_store_count, 1); + CU_ASSERT_EQUAL(db.msg_store_bytes, 7); + CU_ASSERT_PTR_NOT_NULL(db.msg_store); + if(db.msg_store){ + CU_ASSERT_EQUAL(db.msg_store->db_id, 1); + CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id"); + CU_ASSERT_EQUAL(db.msg_store->source_mid, 2); + CU_ASSERT_EQUAL(db.msg_store->mid, 0); + CU_ASSERT_EQUAL(db.msg_store->qos, 2); + CU_ASSERT_EQUAL(db.msg_store->retain, 1); + CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic"); + CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7); + if(db.msg_store->payloadlen == 7){ + CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7); + } + } +} + +static void TEST_v3_client(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + struct mosquitto *context; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-client.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + + CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id); + HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context); + CU_ASSERT_PTR_NOT_NULL(context); + if(context){ + CU_ASSERT_PTR_NULL(context->inflight_msgs); + CU_ASSERT_EQUAL(context->last_mid, 0x5287); + CU_ASSERT_EQUAL(context->disconnect_t, 0x23); + } +} + +static void TEST_v3_client_message(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + struct mosquitto *context; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-client-message.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + + CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id); + HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context); + CU_ASSERT_PTR_NOT_NULL(context); + if(context){ + CU_ASSERT_PTR_NOT_NULL(context->inflight_msgs); + if(context->inflight_msgs){ + CU_ASSERT_PTR_NULL(context->inflight_msgs->next); + CU_ASSERT_PTR_NOT_NULL(context->inflight_msgs->store); + if(context->inflight_msgs->store){ + CU_ASSERT_EQUAL(context->inflight_msgs->store->ref_count, 1); + CU_ASSERT_STRING_EQUAL(context->inflight_msgs->store->source_id, "source_id"); + CU_ASSERT_EQUAL(context->inflight_msgs->store->source_mid, 2); + CU_ASSERT_EQUAL(context->inflight_msgs->store->mid, 0); + CU_ASSERT_EQUAL(context->inflight_msgs->store->qos, 2); + CU_ASSERT_EQUAL(context->inflight_msgs->store->retain, 1); + CU_ASSERT_STRING_EQUAL(context->inflight_msgs->store->topic, "topic"); + CU_ASSERT_EQUAL(context->inflight_msgs->store->payloadlen, 7); + if(context->inflight_msgs->store->payloadlen == 7){ + CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(context->inflight_msgs->store), "payload", 7); + } + } + CU_ASSERT_EQUAL(context->inflight_msgs->mid, 0x73); + CU_ASSERT_EQUAL(context->inflight_msgs->qos, 1); + CU_ASSERT_EQUAL(context->inflight_msgs->retain, 0); + CU_ASSERT_EQUAL(context->inflight_msgs->direction, mosq_md_out); + CU_ASSERT_EQUAL(context->inflight_msgs->state, mosq_ms_wait_for_puback); + CU_ASSERT_EQUAL(context->inflight_msgs->dup, 0); + } + } +} + +static void TEST_v3_retain(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + last_retained = 0; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-retain.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(db.msg_store_count, 1); + CU_ASSERT_EQUAL(db.msg_store_bytes, 7); + CU_ASSERT_PTR_NOT_NULL(db.msg_store); + if(db.msg_store){ + CU_ASSERT_EQUAL(db.msg_store->db_id, 0x54); + CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id"); + CU_ASSERT_EQUAL(db.msg_store->source_mid, 2); + CU_ASSERT_EQUAL(db.msg_store->mid, 0); + CU_ASSERT_EQUAL(db.msg_store->qos, 2); + CU_ASSERT_EQUAL(db.msg_store->retain, 1); + CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic"); + CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7); + if(db.msg_store->payloadlen == 7){ + CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7); + } + } + CU_ASSERT_EQUAL(last_retained, 0x54); +} + +static void TEST_v3_sub(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + struct mosquitto *context; + int rc; + + last_sub = NULL; + last_qos = -1; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v3-sub.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + + CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id); + HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context); + CU_ASSERT_PTR_NOT_NULL(context); + if(context){ + CU_ASSERT_PTR_NOT_NULL(last_sub); + if(last_sub){ + CU_ASSERT_STRING_EQUAL(last_sub, "subscription") + free(last_sub); + } + CU_ASSERT_EQUAL(last_qos, 1); + } +} + +static void TEST_v4_message_store(void) +{ + struct mosquitto_db db; + struct mosquitto__config config; + int rc; + + memset(&db, 0, sizeof(struct mosquitto_db)); + memset(&config, 0, sizeof(struct mosquitto__config)); + db.config = &config; + + config.persistence = true; + config.persistence_filepath = "files/persist_read/v4-message-store.test-db"; + + rc = persist__restore(&db); + CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS); + CU_ASSERT_EQUAL(db.msg_store_count, 1); + CU_ASSERT_EQUAL(db.msg_store_bytes, 7); + CU_ASSERT_PTR_NOT_NULL(db.msg_store); + if(db.msg_store){ + CU_ASSERT_EQUAL(db.msg_store->db_id, 0xFEDCBA9876543210); + CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id"); + CU_ASSERT_EQUAL(db.msg_store->source_mid, 0x88); + CU_ASSERT_EQUAL(db.msg_store->mid, 0); + CU_ASSERT_EQUAL(db.msg_store->qos, 1); + CU_ASSERT_EQUAL(db.msg_store->retain, 0); + CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic"); + CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7); + if(db.msg_store->payloadlen == 7){ + CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7); + } + } +} + +/* ======================================================================== + * TEST SUITE SETUP + * ======================================================================== */ + +int init_persist_read_tests(void) +{ + CU_pSuite test_suite = NULL; + + test_suite = CU_add_suite("Persist read", NULL, NULL); + if(!test_suite){ + printf("Error adding CUnit persist read test suite.\n"); + return 1; + } + + if(0 + || !CU_add_test(test_suite, "Persistence disabled", TEST_persistence_disabled) + || !CU_add_test(test_suite, "Empty file", TEST_empty_file) + || !CU_add_test(test_suite, "Corrupt header", TEST_corrupt_header) + || !CU_add_test(test_suite, "Unsupported version", TEST_unsupported_version) + || !CU_add_test(test_suite, "v3 config ok", TEST_v3_config_ok) + || !CU_add_test(test_suite, "v3 config bad truncated", TEST_v3_config_truncated) + || !CU_add_test(test_suite, "v3 config bad dbid", TEST_v3_config_bad_dbid) + || !CU_add_test(test_suite, "v3 bad chunk", TEST_v3_bad_chunk) + || !CU_add_test(test_suite, "v3 message store", TEST_v3_message_store) + || !CU_add_test(test_suite, "v3 client", TEST_v3_client) + || !CU_add_test(test_suite, "v3 client message", TEST_v3_client_message) + || !CU_add_test(test_suite, "v3 retain", TEST_v3_retain) + || !CU_add_test(test_suite, "v3 sub", TEST_v3_sub) + || !CU_add_test(test_suite, "v4 message store", TEST_v4_message_store) + ){ + + printf("Error adding persist CUnit tests.\n"); + return 1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + + if(CU_initialize_registry() != CUE_SUCCESS){ + printf("Error initializing CUnit registry.\n"); + return 1; + } + + if(0 + || init_persist_read_tests() + ){ + + CU_cleanup_registry(); + return 1; + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + CU_cleanup_registry(); + + return 0; +}