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 #include "property_mosq.h"
15 
16 uint64_t last_retained;
17 char *last_sub = NULL;
18 int last_qos;
19 uint32_t last_identifier;
20 
TEST_persistence_disabled(void)21 static void TEST_persistence_disabled(void)
22 {
23 	struct mosquitto_db db;
24 	struct mosquitto__config config;
25 	int rc;
26 
27 	memset(&db, 0, sizeof(struct mosquitto_db));
28 	memset(&config, 0, sizeof(struct mosquitto__config));
29 	db.config = &config;
30 
31 	rc = persist__restore(&db);
32 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
33 }
34 
35 
TEST_empty_file(void)36 static void TEST_empty_file(void)
37 {
38 	struct mosquitto_db db;
39 	struct mosquitto__config config;
40 	int rc;
41 
42 	memset(&db, 0, sizeof(struct mosquitto_db));
43 	memset(&config, 0, sizeof(struct mosquitto__config));
44 	db.config = &config;
45 
46 	config.persistence = true;
47 
48 	config.persistence_filepath = "files/persist_read/empty.test-db";
49 	rc = persist__restore(&db);
50 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
51 }
52 
53 
TEST_corrupt_header(void)54 static void TEST_corrupt_header(void)
55 {
56 	struct mosquitto_db db;
57 	struct mosquitto__config config;
58 	int rc;
59 
60 	memset(&db, 0, sizeof(struct mosquitto_db));
61 	memset(&config, 0, sizeof(struct mosquitto__config));
62 	db.config = &config;
63 
64 	config.persistence = true;
65 
66 	config.persistence_filepath = "files/persist_read/corrupt-header-short.test-db";
67 	rc = persist__restore(&db);
68 	CU_ASSERT_EQUAL(rc, 1);
69 
70 	config.persistence_filepath = "files/persist_read/corrupt-header-long.test-db";
71 	rc = persist__restore(&db);
72 	CU_ASSERT_EQUAL(rc, 1);
73 }
74 
TEST_unsupported_version(void)75 static void TEST_unsupported_version(void)
76 {
77 	struct mosquitto_db db;
78 	struct mosquitto__config config;
79 	int rc;
80 
81 	memset(&db, 0, sizeof(struct mosquitto_db));
82 	memset(&config, 0, sizeof(struct mosquitto__config));
83 	db.config = &config;
84 
85 	config.persistence = true;
86 	config.persistence_filepath = "files/persist_read/unsupported-version.test-db";
87 
88 	rc = persist__restore(&db);
89 	CU_ASSERT_EQUAL(rc, 1);
90 }
91 
92 
TEST_v3_config_ok(void)93 static void TEST_v3_config_ok(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 	config.persistence_filepath = "files/persist_read/v3-cfg.test-db";
105 
106 	rc = persist__restore(&db);
107 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
108 	CU_ASSERT_EQUAL(db.last_db_id, 0x7856341200000000);
109 }
110 
111 
TEST_v4_config_ok(void)112 static void TEST_v4_config_ok(void)
113 {
114 	struct mosquitto_db db;
115 	struct mosquitto__config config;
116 	int rc;
117 
118 	memset(&db, 0, sizeof(struct mosquitto_db));
119 	memset(&config, 0, sizeof(struct mosquitto__config));
120 	db.config = &config;
121 
122 	config.persistence = true;
123 	config.persistence_filepath = "files/persist_read/v4-cfg.test-db";
124 
125 	rc = persist__restore(&db);
126 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
127 	CU_ASSERT_EQUAL(db.last_db_id, 0x7856341200000000);
128 }
129 
130 
TEST_v3_config_truncated(void)131 static void TEST_v3_config_truncated(void)
132 {
133 	struct mosquitto_db db;
134 	struct mosquitto__config config;
135 	int rc;
136 
137 	memset(&db, 0, sizeof(struct mosquitto_db));
138 	memset(&config, 0, sizeof(struct mosquitto__config));
139 	db.config = &config;
140 
141 	config.persistence = true;
142 	config.persistence_filepath = "files/persist_read/v3-cfg-truncated.test-db";
143 
144 	rc = persist__restore(&db);
145 	CU_ASSERT_EQUAL(rc, 1);
146 	CU_ASSERT_EQUAL(db.last_db_id, 0);
147 }
148 
149 
TEST_v3_config_bad_dbid(void)150 static void TEST_v3_config_bad_dbid(void)
151 {
152 	struct mosquitto_db db;
153 	struct mosquitto__config config;
154 	int rc;
155 
156 	memset(&db, 0, sizeof(struct mosquitto_db));
157 	memset(&config, 0, sizeof(struct mosquitto__config));
158 	db.config = &config;
159 
160 	config.persistence = true;
161 	config.persistence_filepath = "files/persist_read/v3-cfg-bad-dbid.test-db";
162 
163 	rc = persist__restore(&db);
164 	CU_ASSERT_EQUAL(rc, 1);
165 	CU_ASSERT_EQUAL(db.last_db_id, 0);
166 }
167 
168 
TEST_v3_bad_chunk(void)169 static void TEST_v3_bad_chunk(void)
170 {
171 	struct mosquitto_db db;
172 	struct mosquitto__config config;
173 	int rc;
174 
175 	memset(&db, 0, sizeof(struct mosquitto_db));
176 	memset(&config, 0, sizeof(struct mosquitto__config));
177 	db.config = &config;
178 
179 	config.persistence = true;
180 	config.persistence_filepath = "files/persist_read/v3-bad-chunk.test-db";
181 
182 	rc = persist__restore(&db);
183 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
184 	CU_ASSERT_EQUAL(db.last_db_id, 0x17);
185 }
186 
187 
TEST_v3_message_store(void)188 static void TEST_v3_message_store(void)
189 {
190 	struct mosquitto_db db;
191 	struct mosquitto__config config;
192 	int rc;
193 
194 	memset(&db, 0, sizeof(struct mosquitto_db));
195 	memset(&config, 0, sizeof(struct mosquitto__config));
196 	db.config = &config;
197 
198 	config.persistence = true;
199 	config.persistence_filepath = "files/persist_read/v3-message-store.test-db";
200 
201 	rc = persist__restore(&db);
202 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
203 	CU_ASSERT_EQUAL(db.msg_store_count, 1);
204 	CU_ASSERT_EQUAL(db.msg_store_bytes, 7);
205 	CU_ASSERT_PTR_NOT_NULL(db.msg_store);
206 	if(db.msg_store){
207 		CU_ASSERT_EQUAL(db.msg_store->db_id, 1);
208 		CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id");
209 		CU_ASSERT_EQUAL(db.msg_store->source_mid, 2);
210 		CU_ASSERT_EQUAL(db.msg_store->mid, 0);
211 		CU_ASSERT_EQUAL(db.msg_store->qos, 2);
212 		CU_ASSERT_EQUAL(db.msg_store->retain, 1);
213 		CU_ASSERT_PTR_NOT_NULL(db.msg_store->topic);
214 		if(db.msg_store->topic){
215 			CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic");
216 		}
217 		CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7);
218 		if(db.msg_store->payloadlen == 7){
219 			CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7);
220 		}
221 	}
222 }
223 
TEST_v3_client(void)224 static void TEST_v3_client(void)
225 {
226 	struct mosquitto_db db;
227 	struct mosquitto__config config;
228 	struct mosquitto *context;
229 	int rc;
230 
231 	memset(&db, 0, sizeof(struct mosquitto_db));
232 	memset(&config, 0, sizeof(struct mosquitto__config));
233 	db.config = &config;
234 
235 	config.persistence = true;
236 	config.persistence_filepath = "files/persist_read/v3-client.test-db";
237 
238 	rc = persist__restore(&db);
239 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
240 
241 	CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id);
242 	HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context);
243 	CU_ASSERT_PTR_NOT_NULL(context);
244 	if(context){
245 		CU_ASSERT_PTR_NULL(context->msgs_in.inflight);
246 		CU_ASSERT_PTR_NULL(context->msgs_out.inflight);
247 		CU_ASSERT_EQUAL(context->last_mid, 0x5287);
248 	}
249 }
250 
TEST_v3_client_message(void)251 static void TEST_v3_client_message(void)
252 {
253 	struct mosquitto_db db;
254 	struct mosquitto__config config;
255 	struct mosquitto *context;
256 	int rc;
257 
258 	memset(&db, 0, sizeof(struct mosquitto_db));
259 	memset(&config, 0, sizeof(struct mosquitto__config));
260 	db.config = &config;
261 
262 	config.persistence = true;
263 	config.persistence_filepath = "files/persist_read/v3-client-message.test-db";
264 	config.max_inflight_messages = 20;
265 
266 	rc = persist__restore(&db);
267 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
268 
269 	CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id);
270 	HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context);
271 	CU_ASSERT_PTR_NOT_NULL(context);
272 	if(context){
273 		CU_ASSERT_PTR_NOT_NULL(context->msgs_out.inflight);
274 		if(context->msgs_out.inflight){
275 			CU_ASSERT_PTR_NULL(context->msgs_out.inflight->next);
276 			CU_ASSERT_PTR_NOT_NULL(context->msgs_out.inflight->store);
277 			if(context->msgs_out.inflight->store){
278 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->ref_count, 1);
279 				CU_ASSERT_STRING_EQUAL(context->msgs_out.inflight->store->source_id, "source_id");
280 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->source_mid, 2);
281 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->mid, 0);
282 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->qos, 2);
283 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->retain, 1);
284 				CU_ASSERT_PTR_NOT_NULL(context->msgs_out.inflight->store->topic);
285 				if(context->msgs_out.inflight->store->topic){
286 					CU_ASSERT_STRING_EQUAL(context->msgs_out.inflight->store->topic, "topic");
287 				}
288 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->payloadlen, 7);
289 				if(context->msgs_out.inflight->store->payloadlen == 7){
290 					CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(context->msgs_out.inflight->store), "payload", 7);
291 				}
292 			}
293 			CU_ASSERT_EQUAL(context->msgs_out.inflight->mid, 0x73);
294 			CU_ASSERT_EQUAL(context->msgs_out.inflight->qos, 1);
295 			CU_ASSERT_EQUAL(context->msgs_out.inflight->retain, 0);
296 			CU_ASSERT_EQUAL(context->msgs_out.inflight->direction, mosq_md_out);
297 			CU_ASSERT_EQUAL(context->msgs_out.inflight->state, mosq_ms_wait_for_puback);
298 			CU_ASSERT_EQUAL(context->msgs_out.inflight->dup, 0);
299 			CU_ASSERT_PTR_NULL(context->msgs_out.inflight->properties);
300 		}
301 	}
302 }
303 
TEST_v3_retain(void)304 static void TEST_v3_retain(void)
305 {
306 	struct mosquitto_db db;
307 	struct mosquitto__config config;
308 	int rc;
309 
310 	last_retained = 0;
311 
312 	memset(&db, 0, sizeof(struct mosquitto_db));
313 	memset(&config, 0, sizeof(struct mosquitto__config));
314 	db.config = &config;
315 
316 	config.persistence = true;
317 	config.persistence_filepath = "files/persist_read/v3-retain.test-db";
318 
319 	rc = persist__restore(&db);
320 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
321 	CU_ASSERT_EQUAL(db.msg_store_count, 1);
322 	CU_ASSERT_EQUAL(db.msg_store_bytes, 7);
323 	CU_ASSERT_PTR_NOT_NULL(db.msg_store);
324 	if(db.msg_store){
325 		CU_ASSERT_EQUAL(db.msg_store->db_id, 0x54);
326 		CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id");
327 		CU_ASSERT_EQUAL(db.msg_store->source_mid, 2);
328 		CU_ASSERT_EQUAL(db.msg_store->mid, 0);
329 		CU_ASSERT_EQUAL(db.msg_store->qos, 2);
330 		CU_ASSERT_EQUAL(db.msg_store->retain, 1);
331 		CU_ASSERT_PTR_NOT_NULL(db.msg_store->topic);
332 		if(db.msg_store->topic){
333 			CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic");
334 		}
335 		CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7);
336 		if(db.msg_store->payloadlen == 7){
337 			CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7);
338 		}
339 	}
340 	CU_ASSERT_EQUAL(last_retained, 0x54);
341 }
342 
TEST_v3_sub(void)343 static void TEST_v3_sub(void)
344 {
345 	struct mosquitto_db db;
346 	struct mosquitto__config config;
347 	struct mosquitto *context;
348 	int rc;
349 
350 	last_sub = NULL;
351 	last_qos = -1;
352 
353 	memset(&db, 0, sizeof(struct mosquitto_db));
354 	memset(&config, 0, sizeof(struct mosquitto__config));
355 	db.config = &config;
356 
357 	config.persistence = true;
358 	config.persistence_filepath = "files/persist_read/v3-sub.test-db";
359 
360 	rc = persist__restore(&db);
361 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
362 
363 	CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id);
364 	HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context);
365 	CU_ASSERT_PTR_NOT_NULL(context);
366 	if(context){
367 		CU_ASSERT_PTR_NOT_NULL(last_sub);
368 		if(last_sub){
369 			CU_ASSERT_STRING_EQUAL(last_sub, "subscription")
370 			free(last_sub);
371 		}
372 		CU_ASSERT_EQUAL(last_qos, 1);
373 	}
374 }
375 
TEST_v4_message_store(void)376 static void TEST_v4_message_store(void)
377 {
378 	struct mosquitto_db db;
379 	struct mosquitto__config config;
380 	int rc;
381 
382 	memset(&db, 0, sizeof(struct mosquitto_db));
383 	memset(&config, 0, sizeof(struct mosquitto__config));
384 	db.config = &config;
385 
386 	config.persistence = true;
387 	config.persistence_filepath = "files/persist_read/v4-message-store.test-db";
388 
389 	rc = persist__restore(&db);
390 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
391 	CU_ASSERT_EQUAL(db.msg_store_count, 1);
392 	CU_ASSERT_EQUAL(db.msg_store_bytes, 7);
393 	CU_ASSERT_PTR_NOT_NULL(db.msg_store);
394 	if(db.msg_store){
395 		CU_ASSERT_EQUAL(db.msg_store->db_id, 0xFEDCBA9876543210);
396 		CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id");
397 		CU_ASSERT_EQUAL(db.msg_store->source_mid, 0x88);
398 		CU_ASSERT_EQUAL(db.msg_store->mid, 0);
399 		CU_ASSERT_EQUAL(db.msg_store->qos, 1);
400 		CU_ASSERT_EQUAL(db.msg_store->retain, 0);
401 		CU_ASSERT_PTR_NOT_NULL(db.msg_store->topic);
402 		if(db.msg_store->topic){
403 			CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic");
404 		}
405 		CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7);
406 		if(db.msg_store->payloadlen == 7){
407 			CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7);
408 		}
409 	}
410 }
411 
TEST_v5_config_ok(void)412 static void TEST_v5_config_ok(void)
413 {
414 	struct mosquitto_db db;
415 	struct mosquitto__config config;
416 	int rc;
417 
418 	memset(&db, 0, sizeof(struct mosquitto_db));
419 	memset(&config, 0, sizeof(struct mosquitto__config));
420 	db.config = &config;
421 
422 	config.persistence = true;
423 	config.persistence_filepath = "files/persist_read/v5-cfg.test-db";
424 
425 	rc = persist__restore(&db);
426 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
427 	CU_ASSERT_EQUAL(db.last_db_id, 0x7856341200000000);
428 }
429 
430 
TEST_v5_config_truncated(void)431 static void TEST_v5_config_truncated(void)
432 {
433 	struct mosquitto_db db;
434 	struct mosquitto__config config;
435 	int rc;
436 
437 	memset(&db, 0, sizeof(struct mosquitto_db));
438 	memset(&config, 0, sizeof(struct mosquitto__config));
439 	db.config = &config;
440 
441 	config.persistence = true;
442 	config.persistence_filepath = "files/persist_read/v5-cfg-truncated.test-db";
443 
444 	rc = persist__restore(&db);
445 	CU_ASSERT_EQUAL(rc, 1);
446 	CU_ASSERT_EQUAL(db.last_db_id, 0);
447 }
448 
449 
TEST_v5_bad_chunk(void)450 static void TEST_v5_bad_chunk(void)
451 {
452 	struct mosquitto_db db;
453 	struct mosquitto__config config;
454 	int rc;
455 
456 	memset(&db, 0, sizeof(struct mosquitto_db));
457 	memset(&config, 0, sizeof(struct mosquitto__config));
458 	db.config = &config;
459 
460 	config.persistence = true;
461 	config.persistence_filepath = "files/persist_read/v5-bad-chunk.test-db";
462 
463 	rc = persist__restore(&db);
464 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
465 	CU_ASSERT_EQUAL(db.last_db_id, 0x17);
466 }
467 
468 
TEST_v5_message_store(void)469 static void TEST_v5_message_store(void)
470 {
471 	struct mosquitto_db db;
472 	struct mosquitto__config config;
473 	int rc;
474 
475 	memset(&db, 0, sizeof(struct mosquitto_db));
476 	memset(&config, 0, sizeof(struct mosquitto__config));
477 	db.config = &config;
478 
479 	config.persistence = true;
480 	config.persistence_filepath = "files/persist_read/v5-message-store.test-db";
481 
482 	rc = persist__restore(&db);
483 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
484 	CU_ASSERT_EQUAL(db.msg_store_count, 1);
485 	CU_ASSERT_EQUAL(db.msg_store_bytes, 7);
486 	CU_ASSERT_PTR_NOT_NULL(db.msg_store);
487 	if(db.msg_store){
488 		CU_ASSERT_EQUAL(db.msg_store->db_id, 1);
489 		CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id");
490 		CU_ASSERT_EQUAL(db.msg_store->source_mid, 2);
491 		CU_ASSERT_EQUAL(db.msg_store->mid, 0);
492 		CU_ASSERT_EQUAL(db.msg_store->qos, 2);
493 		CU_ASSERT_EQUAL(db.msg_store->retain, 1);
494 		CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic");
495 		CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7);
496 		if(db.msg_store->payloadlen == 7){
497 			CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7);
498 		}
499 		CU_ASSERT_PTR_NULL(db.msg_store->properties);
500 	}
501 }
502 
503 
TEST_v5_message_store_props(void)504 static void TEST_v5_message_store_props(void)
505 {
506 	struct mosquitto_db db;
507 	struct mosquitto__config config;
508 	struct mosquitto__listener listener;
509 	int rc;
510 
511 	memset(&db, 0, sizeof(struct mosquitto_db));
512 	memset(&config, 0, sizeof(struct mosquitto__config));
513 	memset(&listener, 0, sizeof(struct mosquitto__listener));
514 	db.config = &config;
515 
516 	listener.port = 1883;
517 	config.listeners = &listener;
518 	config.listener_count = 1;
519 
520 	config.persistence = true;
521 	config.persistence_filepath = "files/persist_read/v5-message-store-props.test-db";
522 
523 	rc = persist__restore(&db);
524 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
525 	CU_ASSERT_EQUAL(db.msg_store_count, 1);
526 	CU_ASSERT_EQUAL(db.msg_store_bytes, 7);
527 	CU_ASSERT_PTR_NOT_NULL(db.msg_store);
528 	if(db.msg_store){
529 		CU_ASSERT_EQUAL(db.msg_store->db_id, 1);
530 		CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id");
531 		CU_ASSERT_EQUAL(db.msg_store->source_mid, 2);
532 		CU_ASSERT_EQUAL(db.msg_store->mid, 0);
533 		CU_ASSERT_EQUAL(db.msg_store->qos, 2);
534 		CU_ASSERT_EQUAL(db.msg_store->retain, 1);
535 		CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic");
536 		CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7);
537 		if(db.msg_store->payloadlen == 7){
538 			CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7);
539 		}
540 		CU_ASSERT_PTR_NOT_NULL(db.msg_store->properties);
541 		if(db.msg_store->properties){
542 			CU_ASSERT_EQUAL(db.msg_store->properties->identifier, 1);
543 			CU_ASSERT_EQUAL(db.msg_store->properties->value.i8, 1);
544 		}
545 		CU_ASSERT_PTR_NOT_NULL(db.msg_store->source_listener);
546 	}
547 }
548 
TEST_v5_client(void)549 static void TEST_v5_client(void)
550 {
551 	struct mosquitto_db db;
552 	struct mosquitto__config config;
553 	struct mosquitto *context;
554 	int rc;
555 
556 	memset(&db, 0, sizeof(struct mosquitto_db));
557 	memset(&config, 0, sizeof(struct mosquitto__config));
558 	db.config = &config;
559 
560 	config.persistence = true;
561 	config.persistence_filepath = "files/persist_read/v5-client.test-db";
562 
563 	rc = persist__restore(&db);
564 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
565 
566 	CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id);
567 	HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context);
568 	CU_ASSERT_PTR_NOT_NULL(context);
569 	if(context){
570 		CU_ASSERT_PTR_NULL(context->msgs_in.inflight);
571 		CU_ASSERT_PTR_NULL(context->msgs_out.inflight);
572 		CU_ASSERT_EQUAL(context->last_mid, 0x5287);
573 	}
574 }
575 
TEST_v5_client_message(void)576 static void TEST_v5_client_message(void)
577 {
578 	struct mosquitto_db db;
579 	struct mosquitto__config config;
580 	struct mosquitto *context;
581 	int rc;
582 
583 	memset(&db, 0, sizeof(struct mosquitto_db));
584 	memset(&config, 0, sizeof(struct mosquitto__config));
585 	db.config = &config;
586 
587 	config.persistence = true;
588 	config.persistence_filepath = "files/persist_read/v5-client-message.test-db";
589 
590 	rc = persist__restore(&db);
591 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
592 
593 	CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id);
594 	HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context);
595 	CU_ASSERT_PTR_NOT_NULL(context);
596 	if(context){
597 		CU_ASSERT_PTR_NOT_NULL(context->msgs_out.inflight);
598 		if(context->msgs_out.inflight){
599 			CU_ASSERT_PTR_NULL(context->msgs_out.inflight->next);
600 			CU_ASSERT_PTR_NOT_NULL(context->msgs_out.inflight->store);
601 			if(context->msgs_out.inflight->store){
602 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->ref_count, 1);
603 				CU_ASSERT_STRING_EQUAL(context->msgs_out.inflight->store->source_id, "source_id");
604 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->source_mid, 2);
605 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->mid, 0);
606 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->qos, 2);
607 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->retain, 1);
608 				CU_ASSERT_STRING_EQUAL(context->msgs_out.inflight->store->topic, "topic");
609 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->payloadlen, 7);
610 				if(context->msgs_out.inflight->store->payloadlen == 7){
611 					CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(context->msgs_out.inflight->store), "payload", 7);
612 				}
613 			}
614 			CU_ASSERT_EQUAL(context->msgs_out.inflight->mid, 0x73);
615 			CU_ASSERT_EQUAL(context->msgs_out.inflight->qos, 1);
616 			CU_ASSERT_EQUAL(context->msgs_out.inflight->retain, 0);
617 			CU_ASSERT_EQUAL(context->msgs_out.inflight->direction, mosq_md_out);
618 			CU_ASSERT_EQUAL(context->msgs_out.inflight->state, mosq_ms_wait_for_puback);
619 			CU_ASSERT_EQUAL(context->msgs_out.inflight->dup, 0);
620 			CU_ASSERT_PTR_NULL(context->msgs_out.inflight->properties);
621 		}
622 	}
623 }
624 
TEST_v5_client_message_props(void)625 static void TEST_v5_client_message_props(void)
626 {
627 	struct mosquitto_db db;
628 	struct mosquitto__config config;
629 	struct mosquitto *context;
630 	int rc;
631 
632 	memset(&db, 0, sizeof(struct mosquitto_db));
633 	memset(&config, 0, sizeof(struct mosquitto__config));
634 	db.config = &config;
635 
636 	config.persistence = true;
637 	config.persistence_filepath = "files/persist_read/v5-client-message-props.test-db";
638 
639 	rc = persist__restore(&db);
640 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
641 
642 	CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id);
643 	HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context);
644 	CU_ASSERT_PTR_NOT_NULL(context);
645 	if(context){
646 		CU_ASSERT_PTR_NOT_NULL(context->msgs_out.inflight);
647 		if(context->msgs_out.inflight){
648 			CU_ASSERT_PTR_NULL(context->msgs_out.inflight->next);
649 			CU_ASSERT_PTR_NOT_NULL(context->msgs_out.inflight->store);
650 			if(context->msgs_out.inflight->store){
651 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->ref_count, 1);
652 				CU_ASSERT_STRING_EQUAL(context->msgs_out.inflight->store->source_id, "source_id");
653 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->source_mid, 2);
654 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->mid, 0);
655 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->qos, 2);
656 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->retain, 1);
657 				CU_ASSERT_STRING_EQUAL(context->msgs_out.inflight->store->topic, "topic");
658 				CU_ASSERT_EQUAL(context->msgs_out.inflight->store->payloadlen, 7);
659 				if(context->msgs_out.inflight->store->payloadlen == 7){
660 					CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(context->msgs_out.inflight->store), "payload", 7);
661 				}
662 			}
663 			CU_ASSERT_EQUAL(context->msgs_out.inflight->mid, 0x73);
664 			CU_ASSERT_EQUAL(context->msgs_out.inflight->qos, 1);
665 			CU_ASSERT_EQUAL(context->msgs_out.inflight->retain, 0);
666 			CU_ASSERT_EQUAL(context->msgs_out.inflight->direction, mosq_md_out);
667 			CU_ASSERT_EQUAL(context->msgs_out.inflight->state, mosq_ms_wait_for_puback);
668 			CU_ASSERT_EQUAL(context->msgs_out.inflight->dup, 0);
669 			CU_ASSERT_PTR_NOT_NULL(context->msgs_out.inflight->properties);
670 			if(context->msgs_out.inflight->properties){
671 				CU_ASSERT_EQUAL(context->msgs_out.inflight->properties->identifier, 1);
672 				CU_ASSERT_EQUAL(context->msgs_out.inflight->properties->value.i8, 1);
673 			}
674 		}
675 	}
676 }
677 
TEST_v5_retain(void)678 static void TEST_v5_retain(void)
679 {
680 	struct mosquitto_db db;
681 	struct mosquitto__config config;
682 	int rc;
683 
684 	last_retained = 0;
685 
686 	memset(&db, 0, sizeof(struct mosquitto_db));
687 	memset(&config, 0, sizeof(struct mosquitto__config));
688 	db.config = &config;
689 
690 	config.persistence = true;
691 	config.persistence_filepath = "files/persist_read/v5-retain.test-db";
692 
693 	rc = persist__restore(&db);
694 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
695 	CU_ASSERT_EQUAL(db.msg_store_count, 1);
696 	CU_ASSERT_EQUAL(db.msg_store_bytes, 7);
697 	CU_ASSERT_PTR_NOT_NULL(db.msg_store);
698 	if(db.msg_store){
699 		CU_ASSERT_EQUAL(db.msg_store->db_id, 0x54);
700 		CU_ASSERT_STRING_EQUAL(db.msg_store->source_id, "source_id");
701 		CU_ASSERT_EQUAL(db.msg_store->source_mid, 2);
702 		CU_ASSERT_EQUAL(db.msg_store->mid, 0);
703 		CU_ASSERT_EQUAL(db.msg_store->qos, 2);
704 		CU_ASSERT_EQUAL(db.msg_store->retain, 1);
705 		CU_ASSERT_STRING_EQUAL(db.msg_store->topic, "topic");
706 		CU_ASSERT_EQUAL(db.msg_store->payloadlen, 7);
707 		if(db.msg_store->payloadlen == 7){
708 			CU_ASSERT_NSTRING_EQUAL(UHPA_ACCESS_PAYLOAD(db.msg_store), "payload", 7);
709 		}
710 	}
711 	CU_ASSERT_EQUAL(last_retained, 0x54);
712 }
713 
TEST_v5_sub(void)714 static void TEST_v5_sub(void)
715 {
716 	struct mosquitto_db db;
717 	struct mosquitto__config config;
718 	struct mosquitto *context;
719 	int rc;
720 
721 	last_sub = NULL;
722 	last_qos = -1;
723 
724 	memset(&db, 0, sizeof(struct mosquitto_db));
725 	memset(&config, 0, sizeof(struct mosquitto__config));
726 	db.config = &config;
727 
728 	config.persistence = true;
729 	config.persistence_filepath = "files/persist_read/v5-sub.test-db";
730 
731 	rc = persist__restore(&db);
732 	CU_ASSERT_EQUAL(rc, MOSQ_ERR_SUCCESS);
733 
734 	CU_ASSERT_PTR_NOT_NULL(db.contexts_by_id);
735 	HASH_FIND(hh_id, db.contexts_by_id, "client-id", strlen("client-id"), context);
736 	CU_ASSERT_PTR_NOT_NULL(context);
737 	if(context){
738 		CU_ASSERT_PTR_NOT_NULL(last_sub);
739 		if(last_sub){
740 			CU_ASSERT_STRING_EQUAL(last_sub, "subscription")
741 			free(last_sub);
742 		}
743 		CU_ASSERT_EQUAL(last_qos, 1);
744 		CU_ASSERT_EQUAL(last_identifier, 0x7623);
745 	}
746 }
747 
748 /* ========================================================================
749  * TEST SUITE SETUP
750  * ======================================================================== */
751 
init_persist_read_tests(void)752 int init_persist_read_tests(void)
753 {
754 	CU_pSuite test_suite = NULL;
755 
756 	test_suite = CU_add_suite("Persist read", NULL, NULL);
757 	if(!test_suite){
758 		printf("Error adding CUnit persist read test suite.\n");
759 		return 1;
760 	}
761 
762 	if(0
763 			|| !CU_add_test(test_suite, "Persistence disabled", TEST_persistence_disabled)
764 			|| !CU_add_test(test_suite, "Empty file", TEST_empty_file)
765 			|| !CU_add_test(test_suite, "Corrupt header", TEST_corrupt_header)
766 			|| !CU_add_test(test_suite, "Unsupported version", TEST_unsupported_version)
767 			|| !CU_add_test(test_suite, "v3 config ok", TEST_v3_config_ok)
768 			|| !CU_add_test(test_suite, "v3 config bad truncated", TEST_v3_config_truncated)
769 			|| !CU_add_test(test_suite, "v3 config bad dbid", TEST_v3_config_bad_dbid)
770 			|| !CU_add_test(test_suite, "v3 bad chunk", TEST_v3_bad_chunk)
771 			|| !CU_add_test(test_suite, "v3 message store", TEST_v3_message_store)
772 			|| !CU_add_test(test_suite, "v3 client", TEST_v3_client)
773 			|| !CU_add_test(test_suite, "v3 client message", TEST_v3_client_message)
774 			|| !CU_add_test(test_suite, "v3 retain", TEST_v3_retain)
775 			|| !CU_add_test(test_suite, "v3 sub", TEST_v3_sub)
776 			|| !CU_add_test(test_suite, "v4 config ok", TEST_v4_config_ok)
777 			|| !CU_add_test(test_suite, "v4 message store", TEST_v4_message_store)
778 			|| !CU_add_test(test_suite, "v5 config ok", TEST_v5_config_ok)
779 			|| !CU_add_test(test_suite, "v5 config bad truncated", TEST_v5_config_truncated)
780 			|| !CU_add_test(test_suite, "v5 bad chunk", TEST_v5_bad_chunk)
781 			|| !CU_add_test(test_suite, "v5 message store", TEST_v5_message_store)
782 			|| !CU_add_test(test_suite, "v5 message store+props", TEST_v5_message_store_props)
783 			|| !CU_add_test(test_suite, "v5 client", TEST_v5_client)
784 			|| !CU_add_test(test_suite, "v5 client message", TEST_v5_client_message)
785 			|| !CU_add_test(test_suite, "v5 client message+props", TEST_v5_client_message_props)
786 			|| !CU_add_test(test_suite, "v5 retain", TEST_v5_retain)
787 			|| !CU_add_test(test_suite, "v5 sub", TEST_v5_sub)
788 			){
789 
790 		printf("Error adding persist CUnit tests.\n");
791 		return 1;
792 	}
793 
794 	return 0;
795 }
796 
main(int argc,char * argv[])797 int main(int argc, char *argv[])
798 {
799 	int fails;
800 
801     if(CU_initialize_registry() != CUE_SUCCESS){
802         printf("Error initializing CUnit registry.\n");
803         return 1;
804     }
805 
806     if(0
807 			|| init_persist_read_tests()
808 			){
809 
810         CU_cleanup_registry();
811         return 1;
812     }
813 
814     CU_basic_set_mode(CU_BRM_VERBOSE);
815     CU_basic_run_tests();
816 	fails = CU_get_number_of_failures();
817     CU_cleanup_registry();
818 
819     return (int)fails;
820 }
821