libmultipath: avoid frequent messages from filter_property()
[multipath-tools/.git] / tests / blacklist.c
1 /*
2  * Copyright (c) 2018 Benjamin Marzinski, Redhat
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  *
17  */
18 #include <stdarg.h>
19 #include <stddef.h>
20 #include <setjmp.h>
21 #include <cmocka.h>
22 #include "globals.c"
23 #include "blacklist.h"
24 #include "log.h"
25
26 struct udev_device {
27         const char *sysname;
28         char *property_list[];
29 };
30
31 const char *
32 __wrap_udev_device_get_sysname(struct udev_device *udev_device)
33 {
34         assert_non_null(udev_device);
35         assert_non_null(udev_device->sysname);
36         return udev_device->sysname;
37 }
38
39 struct udev_list_entry *
40 __wrap_udev_device_get_properties_list_entry(struct udev_device *udev_device)
41 {
42         assert_non_null(udev_device);
43         if (!udev_device->property_list)
44                 return NULL;
45         if (!*udev_device->property_list)
46                 return NULL;
47         return (struct udev_list_entry *)udev_device->property_list;
48 }
49
50 struct udev_list_entry *
51 __wrap_udev_list_entry_get_next(struct udev_list_entry *list_entry)
52 {
53         assert_non_null(list_entry);
54         if (!*((char **)list_entry + 1))
55                 return NULL;
56         return (struct udev_list_entry *)(((char **)list_entry) + 1);
57 }
58
59 const char *
60 __wrap_udev_list_entry_get_name(struct udev_list_entry *list_entry)
61 {
62         return *(const char **)list_entry;
63 }
64
65 void __wrap_dlog (int sink, int prio, const char * fmt, ...)
66 {
67         char buff[MAX_MSG_SIZE];
68         va_list ap;
69
70         assert_int_equal(prio, mock_type(int));
71         va_start(ap, fmt);
72         vsnprintf(buff, MAX_MSG_SIZE, fmt, ap);
73         va_end(ap);
74         assert_string_equal(buff, mock_ptr_type(char *));
75 }
76
77 void expect_condlog(int prio, char *string)
78 {
79         will_return(__wrap_dlog, prio);
80         will_return(__wrap_dlog, string);
81 }
82
83 vector blist_devnode_sdb;
84 vector blist_all;
85 vector blist_device_foo_bar;
86 vector blist_device_all;
87 vector blist_wwid_xyzzy;
88 vector blist_protocol_fcp;
89 vector blist_property_wwn;
90
91 static int setup(void **state)
92 {
93         blist_devnode_sdb = vector_alloc();
94         if (!blist_devnode_sdb ||
95             store_ble(blist_devnode_sdb, strdup("sdb"), ORIGIN_CONFIG))
96                 return -1;
97
98         blist_all = vector_alloc();
99         if (!blist_all || store_ble(blist_all, strdup(".*"), ORIGIN_CONFIG))
100                 return -1;
101
102         blist_device_foo_bar = vector_alloc();
103         if (!blist_device_foo_bar || alloc_ble_device(blist_device_foo_bar) ||
104             set_ble_device(blist_device_foo_bar, strdup("foo"), strdup("bar"),
105                            ORIGIN_CONFIG))
106                 return -1;
107
108         blist_device_all = vector_alloc();
109         if (!blist_device_all || alloc_ble_device(blist_device_all) ||
110             set_ble_device(blist_device_all, strdup(".*"), strdup(".*"),
111                            ORIGIN_CONFIG))
112                 return -1;
113
114         blist_wwid_xyzzy = vector_alloc();
115         if (!blist_wwid_xyzzy ||
116             store_ble(blist_wwid_xyzzy, strdup("xyzzy"), ORIGIN_CONFIG))
117                 return -1;
118
119         blist_protocol_fcp = vector_alloc();
120         if (!blist_protocol_fcp ||
121             store_ble(blist_protocol_fcp, strdup("scsi:fcp"), ORIGIN_CONFIG))
122                 return -1;
123
124         blist_property_wwn = vector_alloc();
125         if (!blist_property_wwn ||
126             store_ble(blist_property_wwn, strdup("ID_WWN"), ORIGIN_CONFIG))
127                 return -1;
128
129         return 0;
130 }
131
132 static int teardown(void **state)
133 {
134         free_blacklist(blist_devnode_sdb);
135         free_blacklist(blist_all);
136         free_blacklist_device(blist_device_foo_bar);
137         free_blacklist_device(blist_device_all);
138         free_blacklist(blist_wwid_xyzzy);
139         free_blacklist(blist_protocol_fcp);
140         free_blacklist(blist_property_wwn);
141         return 0;
142 }
143
144 static int reset_blists(void **state)
145 {
146         conf.blist_devnode = NULL;
147         conf.blist_wwid = NULL;
148         conf.blist_property = NULL;
149         conf.blist_protocol = NULL;
150         conf.blist_device = NULL;
151         conf.elist_devnode = NULL;
152         conf.elist_wwid = NULL;
153         conf.elist_property = NULL;
154         conf.elist_protocol = NULL;
155         conf.elist_device = NULL;
156         return 0;
157 }
158
159 static void test_devnode_blacklist(void **state)
160 {
161         expect_condlog(3, "sdb: device node name blacklisted\n");
162         assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdb"),
163                          MATCH_DEVNODE_BLIST);
164 }
165
166 static void test_devnode_whitelist(void **state)
167 {
168         expect_condlog(3, "sdb: device node name whitelisted\n");
169         assert_int_equal(filter_devnode(blist_all, blist_devnode_sdb, "sdb"),
170                          MATCH_DEVNODE_BLIST_EXCEPT);
171         expect_condlog(3, "sdc: device node name blacklisted\n");
172         assert_int_equal(filter_devnode(blist_all, blist_devnode_sdb, "sdc"),
173                          MATCH_DEVNODE_BLIST);
174 }
175
176 static void test_devnode_missing(void **state)
177 {
178         assert_int_equal(filter_devnode(blist_devnode_sdb, NULL, "sdc"),
179                          MATCH_NOTHING);
180 }
181
182 static void test_device_blacklist(void **state)
183 {
184         expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
185         assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo",
186                                        "bar", "sdb"),
187                          MATCH_DEVICE_BLIST);
188 }
189
190 static void test_device_whitelist(void **state)
191 {
192         expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n");
193         assert_int_equal(filter_device(blist_device_all, blist_device_foo_bar,
194                                        "foo", "bar", "sdb"),
195                          MATCH_DEVICE_BLIST_EXCEPT);
196         expect_condlog(3, "sdb: (foo:baz) vendor/product blacklisted\n");
197         assert_int_equal(filter_device(blist_device_all, blist_device_foo_bar,
198                                        "foo", "baz", "sdb"),
199                          MATCH_DEVICE_BLIST);
200 }
201
202 static void test_device_missing(void **state)
203 {
204         assert_int_equal(filter_device(blist_device_foo_bar, NULL, "foo",
205                                        "baz", "sdb"),
206                          MATCH_NOTHING);
207 }
208
209 static void test_wwid_blacklist(void **state)
210 {
211         expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
212         assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "xyzzy", "sdb"),
213                          MATCH_WWID_BLIST);
214 }
215
216 static void test_wwid_whitelist(void **state)
217 {
218         expect_condlog(3, "sdb: wwid xyzzy whitelisted\n");
219         assert_int_equal(filter_wwid(blist_all, blist_wwid_xyzzy,
220                                      "xyzzy", "sdb"),
221                          MATCH_WWID_BLIST_EXCEPT);
222         expect_condlog(3, "sdb: wwid plugh blacklisted\n");
223         assert_int_equal(filter_wwid(blist_all, blist_wwid_xyzzy,
224                                      "plugh", "sdb"),
225                          MATCH_WWID_BLIST);
226 }
227
228 static void test_wwid_missing(void **state)
229 {
230         assert_int_equal(filter_wwid(blist_wwid_xyzzy, NULL, "plugh", "sdb"),
231                          MATCH_NOTHING);
232 }
233
234 static void test_protocol_blacklist(void **state)
235 {
236         struct path pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI,
237                            .sg_id.proto_id = SCSI_PROTOCOL_FCP };
238         expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
239         assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp),
240                          MATCH_PROTOCOL_BLIST);
241 }
242
243 static void test_protocol_whitelist(void **state)
244 {
245         struct path pp1 = { .dev = "sdb", .bus = SYSFS_BUS_SCSI,
246                            .sg_id.proto_id = SCSI_PROTOCOL_FCP };
247         struct path pp2 = { .dev = "sdb", .bus = SYSFS_BUS_SCSI,
248                            .sg_id.proto_id = SCSI_PROTOCOL_ISCSI };
249         expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n");
250         assert_int_equal(filter_protocol(blist_all, blist_protocol_fcp, &pp1),
251                          MATCH_PROTOCOL_BLIST_EXCEPT);
252         expect_condlog(3, "sdb: protocol scsi:iscsi blacklisted\n");
253         assert_int_equal(filter_protocol(blist_all, blist_protocol_fcp, &pp2),
254                          MATCH_PROTOCOL_BLIST);
255 }
256
257 static void test_protocol_missing(void **state)
258 {
259         struct path pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI,
260                            .sg_id.proto_id = SCSI_PROTOCOL_ISCSI };
261         assert_int_equal(filter_protocol(blist_protocol_fcp, NULL, &pp),
262                          MATCH_NOTHING);
263 }
264
265 static void test_property_blacklist(void **state)
266 {
267         static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
268         conf.blist_property = blist_property_wwn;
269         expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
270         assert_int_equal(filter_property(&conf, &udev, 3),
271                          MATCH_PROPERTY_BLIST);
272 }
273
274 /* the property check works different in that you check all the property
275  * names, so setting a blacklist value will blacklist the device if any
276  * of the property on the blacklist are found before the property names
277  * in the whitelist.  This might be worth changing. although it would
278  * force multipath to go through the properties twice */
279 static void test_property_whitelist(void **state)
280 {
281         static struct udev_device udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
282         conf.elist_property = blist_property_wwn;
283         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
284         assert_int_equal(filter_property(&conf, &udev, 3),
285                          MATCH_PROPERTY_BLIST_EXCEPT);
286 }
287
288 static void test_property_missing(void **state)
289 {
290         static struct udev_device udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", NULL } };
291         conf.blist_property = blist_property_wwn;
292         expect_condlog(3, "sdb: blacklisted, udev property missing\n");
293         assert_int_equal(filter_property(&conf, &udev, 3),
294                          MATCH_PROPERTY_BLIST_MISSING);
295 }
296
297 struct udev_device test_udev = { "sdb", { "ID_FOO", "ID_WWN", "ID_BAR", NULL } };
298
299 struct path test_pp = { .dev = "sdb", .bus = SYSFS_BUS_SCSI, .udev = &test_udev,
300                         .sg_id.proto_id = SCSI_PROTOCOL_FCP, .vendor_id = "foo",
301                         .product_id = "bar", .wwid = "xyzzy" };
302
303 static void test_filter_path_property(void **state)
304 {
305         conf.blist_property = blist_property_wwn;
306         expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
307         assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROPERTY_BLIST);
308 }
309
310 static void test_filter_path_devnode(void **state)
311 {
312         /* always must include property elist, to avoid "missing property"
313          * blacklisting */
314         conf.elist_property = blist_property_wwn;
315         conf.blist_devnode = blist_devnode_sdb;
316         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
317         expect_condlog(3, "sdb: device node name blacklisted\n");
318         assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVNODE_BLIST);
319 }
320
321 static void test_filter_path_device(void **state)
322 {
323         /* always must include property elist, to avoid "missing property"
324          * blacklisting */
325         conf.elist_property = blist_property_wwn;
326         conf.blist_device = blist_device_foo_bar;
327         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
328         expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
329         assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVICE_BLIST);
330 }
331
332 static void test_filter_path_protocol(void **state)
333 {
334         conf.elist_property = blist_property_wwn;
335         conf.blist_protocol = blist_protocol_fcp;
336         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
337         expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
338         assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROTOCOL_BLIST);
339 }
340
341 static void test_filter_path_wwid(void **state)
342 {
343         conf.elist_property = blist_property_wwn;
344         conf.blist_wwid = blist_wwid_xyzzy;
345         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
346         expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
347         assert_int_equal(filter_path(&conf, &test_pp), MATCH_WWID_BLIST);
348 }
349
350 struct udev_device miss_udev = { "sdb", { "ID_FOO", "ID_BAZ", "ID_BAR", NULL } };
351
352 struct path miss1_pp = { .dev = "sdc", .bus = SYSFS_BUS_SCSI,
353                         .udev = &miss_udev,
354                         .sg_id.proto_id = SCSI_PROTOCOL_ISCSI,
355                         .vendor_id = "foo", .product_id = "baz",
356                         .wwid = "plugh" };
357
358 struct path miss2_pp = { .dev = "sdc", .bus = SYSFS_BUS_SCSI,
359                         .udev = &test_udev,
360                         .sg_id.proto_id = SCSI_PROTOCOL_ISCSI,
361                         .vendor_id = "foo", .product_id = "baz",
362                         .wwid = "plugh" };
363
364 static void test_filter_path_missing1(void **state)
365 {
366         conf.blist_property = blist_property_wwn;
367         conf.blist_devnode = blist_devnode_sdb;
368         conf.blist_device = blist_device_foo_bar;
369         conf.blist_protocol = blist_protocol_fcp;
370         conf.blist_wwid = blist_wwid_xyzzy;
371         expect_condlog(3, "sdb: blacklisted, udev property missing\n");
372         assert_int_equal(filter_path(&conf, &miss1_pp),
373                          MATCH_PROPERTY_BLIST_MISSING);
374 }
375
376 /* This one matches the property whitelist, to test the other missing
377  * functions */
378 static void test_filter_path_missing2(void **state)
379 {
380         conf.elist_property = blist_property_wwn;
381         conf.blist_devnode = blist_devnode_sdb;
382         conf.blist_device = blist_device_foo_bar;
383         conf.blist_protocol = blist_protocol_fcp;
384         conf.blist_wwid = blist_wwid_xyzzy;
385         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
386         assert_int_equal(filter_path(&conf, &miss2_pp),
387                          MATCH_NOTHING);
388 }
389
390 static void test_filter_path_whitelist(void **state)
391 {
392         conf.elist_property = blist_property_wwn;
393         conf.elist_devnode = blist_devnode_sdb;
394         conf.elist_device = blist_device_foo_bar;
395         conf.elist_protocol = blist_protocol_fcp;
396         conf.elist_wwid = blist_wwid_xyzzy;
397         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
398         expect_condlog(3, "sdb: device node name whitelisted\n");
399         expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n");
400         expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n");
401         expect_condlog(3, "sdb: wwid xyzzy whitelisted\n");
402         assert_int_equal(filter_path(&conf, &test_pp),
403                          MATCH_WWID_BLIST_EXCEPT);
404 }
405
406 static void test_filter_path_whitelist_property(void **state)
407 {
408         conf.blist_property = blist_property_wwn;
409         conf.elist_devnode = blist_devnode_sdb;
410         conf.elist_device = blist_device_foo_bar;
411         conf.elist_protocol = blist_protocol_fcp;
412         conf.elist_wwid = blist_wwid_xyzzy;
413         expect_condlog(3, "sdb: udev property ID_WWN blacklisted\n");
414         assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROPERTY_BLIST);
415 }
416
417 static void test_filter_path_whitelist_devnode(void **state)
418 {
419         conf.elist_property = blist_property_wwn;
420         conf.blist_devnode = blist_devnode_sdb;
421         conf.elist_device = blist_device_foo_bar;
422         conf.elist_protocol = blist_protocol_fcp;
423         conf.elist_wwid = blist_wwid_xyzzy;
424         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
425         expect_condlog(3, "sdb: device node name blacklisted\n");
426         assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVNODE_BLIST);
427 }
428
429 static void test_filter_path_whitelist_device(void **state)
430 {
431         conf.elist_property = blist_property_wwn;
432         conf.elist_devnode = blist_devnode_sdb;
433         conf.blist_device = blist_device_foo_bar;
434         conf.elist_protocol = blist_protocol_fcp;
435         conf.elist_wwid = blist_wwid_xyzzy;
436         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
437         expect_condlog(3, "sdb: device node name whitelisted\n");
438         expect_condlog(3, "sdb: (foo:bar) vendor/product blacklisted\n");
439         assert_int_equal(filter_path(&conf, &test_pp), MATCH_DEVICE_BLIST);
440 }
441
442 static void test_filter_path_whitelist_protocol(void **state)
443 {
444         conf.elist_property = blist_property_wwn;
445         conf.elist_devnode = blist_devnode_sdb;
446         conf.elist_device = blist_device_foo_bar;
447         conf.blist_protocol = blist_protocol_fcp;
448         conf.elist_wwid = blist_wwid_xyzzy;
449         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
450         expect_condlog(3, "sdb: device node name whitelisted\n");
451         expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n");
452         expect_condlog(3, "sdb: protocol scsi:fcp blacklisted\n");
453         assert_int_equal(filter_path(&conf, &test_pp), MATCH_PROTOCOL_BLIST);
454 }
455
456 static void test_filter_path_whitelist_wwid(void **state)
457 {
458         conf.elist_property = blist_property_wwn;
459         conf.elist_devnode = blist_devnode_sdb;
460         conf.elist_device = blist_device_foo_bar;
461         conf.elist_protocol = blist_protocol_fcp;
462         conf.blist_wwid = blist_wwid_xyzzy;
463         expect_condlog(3, "sdb: udev property ID_WWN whitelisted\n");
464         expect_condlog(3, "sdb: device node name whitelisted\n");
465         expect_condlog(3, "sdb: (foo:bar) vendor/product whitelisted\n");
466         expect_condlog(3, "sdb: protocol scsi:fcp whitelisted\n");
467         expect_condlog(3, "sdb: wwid xyzzy blacklisted\n");
468         assert_int_equal(filter_path(&conf, &test_pp), MATCH_WWID_BLIST);
469 }
470
471 #define test_and_reset(x) cmocka_unit_test_teardown((x), reset_blists)
472
473 int test_blacklist(void)
474 {
475         const struct CMUnitTest tests[] = {
476                 cmocka_unit_test(test_devnode_blacklist),
477                 cmocka_unit_test(test_devnode_whitelist),
478                 cmocka_unit_test(test_devnode_missing),
479                 cmocka_unit_test(test_device_blacklist),
480                 cmocka_unit_test(test_device_whitelist),
481                 cmocka_unit_test(test_device_missing),
482                 cmocka_unit_test(test_wwid_blacklist),
483                 cmocka_unit_test(test_wwid_whitelist),
484                 cmocka_unit_test(test_wwid_missing),
485                 cmocka_unit_test(test_protocol_blacklist),
486                 cmocka_unit_test(test_protocol_whitelist),
487                 cmocka_unit_test(test_protocol_missing),
488                 test_and_reset(test_property_blacklist),
489                 test_and_reset(test_property_whitelist),
490                 test_and_reset(test_property_missing),
491                 test_and_reset(test_filter_path_property),
492                 test_and_reset(test_filter_path_devnode),
493                 test_and_reset(test_filter_path_device),
494                 test_and_reset(test_filter_path_protocol),
495                 test_and_reset(test_filter_path_wwid),
496                 test_and_reset(test_filter_path_missing1),
497                 test_and_reset(test_filter_path_missing2),
498                 test_and_reset(test_filter_path_whitelist),
499                 test_and_reset(test_filter_path_whitelist_property),
500                 test_and_reset(test_filter_path_whitelist_devnode),
501                 test_and_reset(test_filter_path_whitelist_device),
502                 test_and_reset(test_filter_path_whitelist_protocol),
503                 test_and_reset(test_filter_path_whitelist_wwid),
504         };
505         return cmocka_run_group_tests(tests, setup, teardown);
506 }
507
508 int main(void)
509 {
510         int ret = 0;
511         ret += test_blacklist();
512         return ret;
513 }