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