1 /* Tests for persistence.
2 *
3 * FIXME - these need to be aggressive about finding failures, at the moment
4 * they are just confirming that good behaviour works. */
5
6 #include <CUnit/CUnit.h>
7 #include <CUnit/Basic.h>
8
9 #define WITH_BROKER
10 #define WITH_PERSISTENCE
11
12 #include "mosquitto_broker_internal.h"
13 #include "persist.h"
14
15 uint64_t last_retained;
16 char *last_sub = NULL;
17 int last_qos;
18
19
20 /* read entire file into memory */
file_read(const char * filename,uint8_t ** data,size_t * len)21 static int file_read(const char *filename, uint8_t **data, size_t *len)
22 {
23 FILE *fptr;
24 size_t rc;
25
26 fptr = fopen(filename, "rb");
27 if(!fptr) return 1;
28
29 fseek(fptr, 0, SEEK_END);
30 *len = ftell(fptr);
31 *data = malloc(*len);
32 if(!(*data)){
33 fclose(fptr);
34 return 1;
35 }
36 fseek(fptr, 0, SEEK_SET);
37 rc = fread(*data, 1, *len, fptr);
38 fclose(fptr);
39
40 if(rc == *len){
41 return 0;
42 }else{
43 *len = 0;
44 free(*data);
45 return 1;
46 }
47 }
48
49 /* Crude file diff, only for small files */
file_diff(const char * one,const char * two)50 static int file_diff(const char *one, const char *two)
51 {
52 size_t len1, len2;
53 uint8_t *data1 = NULL, *data2 = NULL;
54 int rc = 1;
55
56 if(file_read(one, &data1, &len1)){
57 return 1;
58 }
59
60 if(file_read(two, &data2, &len2)){
61 free(data1);
62 return 1;
63 }
64
65 if(len1 == len2){
66 rc = memcmp(data1, data2, len1);
67 }
68 free(data1);
69 free(data2);
70
71 return rc;
72 }
73
TEST_persistence_disabled(void)74 static void TEST_persistence_disabled(void)
75 {
76 struct mosquitto_db db;
77 struct mosquitto__config config;
78 int rc;
79
80 memset(&db, 0, sizeof(struct mosquitto_db));
81 memset(&config, 0, sizeof(struct mosquitto__config));
82 db.config = &config;
83
84 rc = persist__backup(&db, false);
85 CU_ASSERT_EQUAL(rc, MOSQ_ERR_INVAL);
86
87 config.persistence_filepath = "disabled.db";
88 rc = persist__backup(&db, false);
89 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
90 }
91
92
TEST_empty_file(void)93 static void TEST_empty_file(void)
94 {
95 struct mosquitto_db db;
96 struct mosquitto__config config;
97 int rc;
98
99 memset(&db, 0, sizeof(struct mosquitto_db));
100 memset(&config, 0, sizeof(struct mosquitto__config));
101 db.config = &config;
102
103 config.persistence = true;
104
105 config.persistence_filepath = "empty.db";
106 rc = persist__backup(&db, false);
107 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
108 CU_ASSERT_EQUAL(0, file_diff("files/persist_write/empty.test-db", "empty.db"));
109 unlink("empty.db");
110 }
111
112
TEST_v5_config_ok(void)113 static void TEST_v5_config_ok(void)
114 {
115 struct mosquitto_db db;
116 struct mosquitto__config config;
117 int rc;
118
119 memset(&db, 0, sizeof(struct mosquitto_db));
120 memset(&config, 0, sizeof(struct mosquitto__config));
121 db.config = &config;
122
123 config.persistence = true;
124 config.persistence_filepath = "files/persist_read/v5-cfg.test-db";
125 rc = persist__restore(&db);
126 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
127
128 config.persistence_filepath = "v5-cfg.db";
129 rc = persist__backup(&db, true);
130 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
131
132 CU_ASSERT_EQUAL(0, file_diff("files/persist_read/v5-cfg.test-db", "v5-cfg.db"));
133 unlink("v5-cfg.db");
134 }
135
136
TEST_v5_message_store_no_ref(void)137 static void TEST_v5_message_store_no_ref(void)
138 {
139 struct mosquitto_db db;
140 struct mosquitto__config config;
141 int rc;
142
143 memset(&db, 0, sizeof(struct mosquitto_db));
144 memset(&config, 0, sizeof(struct mosquitto__config));
145 db.config = &config;
146
147 config.persistence = true;
148 config.persistence_filepath = "files/persist_read/v5-message-store.test-db";
149 rc = persist__restore(&db);
150 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
151
152 config.persistence_filepath = "v5-message-store-no-ref.db";
153 rc = persist__backup(&db, true);
154 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
155
156 CU_ASSERT_EQUAL(0, file_diff("files/persist_write/v5-message-store-no-ref.test-db", "v5-message-store-no-ref.db"));
157 unlink("v5-message-store-no-ref.db");
158 }
159
160
TEST_v5_message_store_props(void)161 static void TEST_v5_message_store_props(void)
162 {
163 struct mosquitto_db db;
164 struct mosquitto__config config;
165 struct mosquitto__listener listener;
166 int rc;
167
168 memset(&db, 0, sizeof(struct mosquitto_db));
169 memset(&config, 0, sizeof(struct mosquitto__config));
170 memset(&listener, 0, sizeof(struct mosquitto__listener));
171 db.config = &config;
172 listener.port = 1883;
173 config.listeners = &listener;
174 config.listener_count = 1;
175
176 config.persistence = true;
177 config.persistence_filepath = "files/persist_read/v5-message-store-props.test-db";
178 rc = persist__restore(&db);
179 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
180
181 config.persistence_filepath = "v5-message-store-props.db";
182 rc = persist__backup(&db, true);
183 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
184
185 CU_ASSERT_EQUAL(0, file_diff("files/persist_read/v5-message-store-props.test-db", "v5-message-store-props.db"));
186 unlink("v5-message-store-props.db");
187 }
188
189
TEST_v5_client(void)190 static void TEST_v5_client(void)
191 {
192 struct mosquitto_db db;
193 struct mosquitto__config config;
194 int rc;
195
196 memset(&db, 0, sizeof(struct mosquitto_db));
197 memset(&config, 0, sizeof(struct mosquitto__config));
198 db.config = &config;
199
200 config.persistence = true;
201 config.persistence_filepath = "files/persist_read/v5-client.test-db";
202 rc = persist__restore(&db);
203 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
204
205 config.persistence_filepath = "v5-client.db";
206 rc = persist__backup(&db, true);
207 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
208
209 CU_ASSERT_EQUAL(0, file_diff("files/persist_read/v5-client.test-db", "v5-client.db"));
210 unlink("v5-client.db");
211 }
212
213
TEST_v5_client_message(void)214 static void TEST_v5_client_message(void)
215 {
216 struct mosquitto_db db;
217 struct mosquitto__config config;
218 struct mosquitto__listener listener;
219 int rc;
220
221 memset(&db, 0, sizeof(struct mosquitto_db));
222 memset(&config, 0, sizeof(struct mosquitto__config));
223 memset(&listener, 0, sizeof(struct mosquitto__listener));
224 db.config = &config;
225 listener.port = 1883;
226 config.listeners = &listener;
227 config.listener_count = 1;
228
229 config.persistence = true;
230 config.persistence_filepath = "files/persist_read/v5-client-message.test-db";
231 rc = persist__restore(&db);
232 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
233
234 config.persistence_filepath = "v5-client-message.db";
235 rc = persist__backup(&db, true);
236 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
237
238 CU_ASSERT_EQUAL(0, file_diff("files/persist_read/v5-client-message.test-db", "v5-client-message.db"));
239 unlink("v5-client-message.db");
240 }
241
242
TEST_v5_client_message_props(void)243 static void TEST_v5_client_message_props(void)
244 {
245 struct mosquitto_db db;
246 struct mosquitto__config config;
247 struct mosquitto__listener listener;
248 int rc;
249
250 memset(&db, 0, sizeof(struct mosquitto_db));
251 memset(&config, 0, sizeof(struct mosquitto__config));
252 memset(&listener, 0, sizeof(struct mosquitto__listener));
253 db.config = &config;
254 listener.port = 1883;
255 config.listeners = &listener;
256 config.listener_count = 1;
257
258 config.persistence = true;
259 config.persistence_filepath = "files/persist_read/v5-client-message-props.test-db";
260 rc = persist__restore(&db);
261 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
262
263 CU_ASSERT_PTR_NOT_NULL(db.msg_store);
264 if(db.msg_store){
265 CU_ASSERT_PTR_NOT_NULL(db.msg_store->source_listener);
266 if(db.msg_store->source_listener){
267 CU_ASSERT_EQUAL(db.msg_store->source_listener->port, 1883);
268 }
269 }
270
271 config.persistence_filepath = "v5-client-message-props.db";
272 rc = persist__backup(&db, true);
273 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
274
275 CU_ASSERT_EQUAL(0, file_diff("files/persist_read/v5-client-message-props.test-db", "v5-client-message-props.db"));
276 unlink("v5-client-message-props.db");
277 }
278
279
TEST_v5_sub(void)280 static void TEST_v5_sub(void)
281 {
282 struct mosquitto_db db;
283 struct mosquitto__config config;
284 struct mosquitto__listener listener;
285 int rc;
286
287 memset(&db, 0, sizeof(struct mosquitto_db));
288 memset(&config, 0, sizeof(struct mosquitto__config));
289 memset(&listener, 0, sizeof(struct mosquitto__listener));
290 db.config = &config;
291 listener.port = 1883;
292 config.listeners = &listener;
293 config.listener_count = 1;
294
295 db__open(&config, &db);
296
297 config.persistence = true;
298 config.persistence_filepath = "files/persist_read/v5-sub.test-db";
299 rc = persist__restore(&db);
300 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
301
302 config.persistence_filepath = "v5-sub.db";
303 rc = persist__backup(&db, true);
304 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
305
306 CU_ASSERT_EQUAL(0, file_diff("files/persist_read/v5-sub.test-db", "v5-sub.db"));
307 unlink("v5-sub.db");
308 }
309
310
311 #if 0
312 NOT WORKING
313 static void TEST_v5_full(void)
314 {
315 struct mosquitto_db db;
316 struct mosquitto__config config;
317 int rc;
318
319 memset(&db, 0, sizeof(struct mosquitto_db));
320 memset(&config, 0, sizeof(struct mosquitto__config));
321 db.config = &config;
322
323 db__open(&config, &db);
324
325 config.persistence = true;
326 config.persistence_filepath = "files/persist_write/v5-full.test-db";
327 rc = persist__restore(&db);
328 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
329
330 config.persistence_filepath = "v5-full.db";
331 rc = persist__backup(&db, true);
332 CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
333
334 CU_ASSERT_EQUAL(0, file_diff("files/persist_write/v5-full.test-db", "v5-full.db"));
335 unlink("v5-full.db");
336 }
337 #endif
338
339
340 /* ========================================================================
341 * TEST SUITE SETUP
342 * ======================================================================== */
343
344
main(int argc,char * argv[])345 int main(int argc, char *argv[])
346 {
347 CU_pSuite test_suite = NULL;
348 unsigned int fails;
349
350 if(CU_initialize_registry() != CUE_SUCCESS){
351 printf("Error initializing CUnit registry.\n");
352 return 1;
353 }
354
355 test_suite = CU_add_suite("Persist write", NULL, NULL);
356 if(!test_suite){
357 printf("Error adding CUnit persist write test suite.\n");
358 CU_cleanup_registry();
359 return 1;
360 }
361
362 if(0
363 || !CU_add_test(test_suite, "Persistence disabled", TEST_persistence_disabled)
364 || !CU_add_test(test_suite, "Empty file", TEST_empty_file)
365 || !CU_add_test(test_suite, "v5 config ok", TEST_v5_config_ok)
366 || !CU_add_test(test_suite, "v5 message store (message has no refs)", TEST_v5_message_store_no_ref)
367 || !CU_add_test(test_suite, "v5 message store + props", TEST_v5_message_store_props)
368 || !CU_add_test(test_suite, "v5 client", TEST_v5_client)
369 || !CU_add_test(test_suite, "v5 client message", TEST_v5_client_message)
370 || !CU_add_test(test_suite, "v5 client message+props", TEST_v5_client_message_props)
371 || !CU_add_test(test_suite, "v5 sub", TEST_v5_sub)
372 //|| !CU_add_test(test_suite, "v5 full", TEST_v5_full)
373 ){
374
375 printf("Error adding persist CUnit tests.\n");
376 CU_cleanup_registry();
377 return 1;
378 }
379
380 CU_basic_set_mode(CU_BRM_VERBOSE);
381 CU_basic_run_tests();
382 fails = CU_get_number_of_failures();
383 CU_cleanup_registry();
384
385 return (int)fails;
386 }
387