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