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