chiark / gitweb /
e81aadd938a69fd56cf7b71b1fad6b584d410a2b
[elogind.git] / test / udevd-test / udevd-test.pl
1 #!/usr/bin/perl -w
2 #
3 # udevd-test
4 #
5 # Copyright (C) Intel Corp, 2004
6 #
7 # Author: Yin Hu <hu.yin@intel.com> 
8 #
9 # Provides automated testing of the udevd binary.This test script is self-contained.
10 # Before you run this script please modify $sysfs to locate your sysfs filesystem, 
11 # modify $udevsend_bin to locate your udevsend binary,
12 # modify $udev_bin to locate dummy udev script,
13 # modify $udev_bin2 to locate another dummy udev script ( amplify the execution time for test),
14 # modify $log_file to locate where udev script have placed the log file,
15 # modify $time_out to decide the time out for events,
16 # modify $udev_exe_time to decide the execution time for dummy udev script.
17 #
18 # Detail information of each test case please refer to the header of corresponding
19 # test case function.
20 #
21 #
22 #       This program is free software; you can redistribute it and/or modify it
23 #       under the terms of the GNU General Public License as published by the
24 #       Free Software Foundation version 2 of the License.
25 #
26 #       This program is distributed in the hope that it will be useful, but
27 #       WITHOUT ANY WARRANTY; without even the implied warranty of
28 #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29 #       General Public License for more details.
30 #
31 #       You should have received a copy of the GNU General Public License along
32 #       with this program; if not, write to the Free Software Foundation, Inc.,
33 #       675 Mass Ave, Cambridge, MA 02139, USA.
34 #
35
36 use warnings;
37 use strict;
38
39 # modifiable settings
40 my $sysfs     =         "../sys";
41 my $udevd_bin = "../../udevd";
42 my $udevsend_bin =      "../../udevsend";
43 my $udev_bin  =         "$ENV{'PWD'}/udev-log-script.pl";
44 my $udev_bin2 =         "$ENV{'PWD'}/udev-log-amplify.pl";
45 my $log_file  =         "/tmp/udev_log.txt";
46 my $time_out  =         10;
47 my $udev_exe_time =     5;
48
49 # global variables
50 my $test_case = 0;
51
52 # common functions
53
54 sub restart_daemon {
55         my ($udev_binary) = @_;
56
57         system("killall udevd");
58         system("rm -f $log_file");
59         sleep 1;
60
61         if (!defined($udev_binary)) {
62                 $udev_binary = $udev_bin;
63         }
64
65         $ENV{'UDEV_BIN'} = $udev_binary;
66         system("/bin/sh -c $udevd_bin&");
67         sleep(1);
68 }
69
70 sub udevsend {
71         # This function prepares corresponding environment variables
72         # and then call $udevsend_bin to send event.
73
74         my ($seqnum, $devpath, $action, $subsystem, $script) = @_;
75
76         %ENV = ();
77         $ENV{'DEVPATH'} = $devpath;
78         $ENV{'ACTION'} = $action;
79         $ENV{'SUBSYSTEM'} = $subsystem;
80
81         if ( $seqnum != -1) {
82                 $ENV{SEQNUM} = $seqnum;
83         }
84
85         return system("$udevsend_bin $subsystem");
86 }
87
88 sub getDate {
89         # Get current date function
90         # If we want GTM time, simply pass GMT as first argument to this function.
91
92         my $format = @_;
93         my $date;
94
95         if( $format =~ /GMT/i ) {
96                 $date = gmtime() . " GMT";
97         } else {
98                 $date = localtime();
99         }
100
101         return $date;
102 }
103
104 sub cmpDate {
105         # This function should return a difference betweent date1 and date2
106
107         my ($date1, $date2) = @_;
108         my @monList = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
109                           "Aug", "Sep", "Oct", "Nov", "Dec" );
110         my ( $m1, $m2, $tmp );
111
112         $date1 =~ s/([\D]*)$//g;
113         $date2 =~ s/([\D]*)$//g;
114
115         return if( (not $date1) or (not $date2) );
116
117         my $mon = 0;
118
119         my ( @T1 ) =
120          ( $date1 =~ /([\d]+)[\s]+([\d]+):([\d]+):([\d]+)[\s]+([\d]+)/g );
121         my ( @T2 ) = 
122          ( $date2 =~ /([\d]+)[\s]+([\d]+):([\d]+):([\d]+)[\s]+([\d]+)/g );
123
124         foreach $tmp (@monList) {
125                 $m1 = sprintf("%2.2d",$mon) if( $date1 =~ /$tmp/i );
126                 $m2 = sprintf("%2.2d",$mon) if( $date2 =~ /$tmp/i );
127                 $mon++;
128         }
129
130         my $dt1 = sprintf("%4.4d%s%2.2d%2.2d%2.2d%2.2d", $T1[4], $m1, $T1[0],
131                                         $T1[1], $T1[2], $T1[3]);
132         my $dt2 = sprintf("%4.4d%s%2.2d%2.2d%2.2d%2.2d", $T2[4], $m2, $T2[0],
133                                         $T2[1], $T2[2], $T2[3]);
134
135         my $ret = $dt1 - $dt2;
136
137         if ( $ret > 40 ) {
138                 $ret = abs($ret-40);
139         }
140
141         return $ret;
142 }
143
144 sub check_count_and_time { 
145         my $event_recv_time;
146         my $udev_fork_time;
147         my $log_ln_count = 0;
148         my $line;
149         my @content;
150         my @line_items;
151         my $diff;
152
153         ($event_recv_time) = @_;
154
155         print "   event receiving time:  $event_recv_time\n\n";
156
157         open(LOGF, $log_file) || die "Opening file $log_file: $!";
158         @content = <LOGF>;
159         foreach $line ( @content ) {
160                 @line_items = split(/,/,$line);
161                 print "   device: $line_items[0], action: $line_items[1] \n";
162                 print "   forking udev time:     $line_items[-1]";
163                 $diff = cmpDate($line_items[-1], $event_recv_time);
164                 print "   the delay time is:     $diff s \n\n";
165                 if ( $diff > $time_out+10 ) {
166                         print "   the delay time is: $diff \n";
167                         print "   udevd doesn't act properly. \n";
168                         exit 1;
169                 }
170                 $log_ln_count++;
171         }
172         close(LOGF);
173
174         return $log_ln_count;
175 }
176
177 sub check_sysfs_device_exist {
178         # check if the designated devices exist
179         my @dev_list = @_;
180         my $dev;
181
182         foreach $dev (@dev_list) {
183                 if (! -e $dev) {
184                         print "the designated device $dev doesn't exist. please change a device!\n";
185                         exit 1;
186                 }
187         }
188 }
189
190 sub show_result {
191         my $event_recv_time;
192         my $udev_fork_time;
193         my $line;
194         my @content;
195         my @line_items;
196         my $diff;
197
198         ($event_recv_time) = @_;
199
200         print "   event receiving time:  $event_recv_time\n\n";
201
202         open(LOGF, $log_file) || die "Opening file $log_file: $!";
203         @content = <LOGF>;
204         foreach $line ( @content ) {
205                 @line_items = split(/,/,$line);
206                 print "   device: $line_items[0], action: $line_items[1] \n";
207                 print "   forking udev time:     $line_items[-1]";
208                 $diff = cmpDate($line_items[-1], $event_recv_time);
209                 print "   the delay time is:     $diff s \n\n";
210         }
211         close(LOGF);
212 }
213
214 sub show_result_tm_out {
215         my $event_recv_time;
216         my $udev_fork_time;
217         my $line;
218         my @content;
219         my @line_items;
220         my $diff;
221
222         ($event_recv_time) = @_;
223
224         print "   event receiving time:  $event_recv_time\n\n";
225
226         open(LOGF, $log_file) || die "Opening file $log_file: $!";
227         @content = <LOGF>;
228         foreach $line ( @content ) {
229                 @line_items = split(/,/,$line);
230                 print "   device: $line_items[0], action: $line_items[1] \n";
231                 print "   forking udev time:     $line_items[-1]";
232                 $diff = cmpDate($line_items[-1], $event_recv_time);
233                 print "   the delay time is:     $diff s \n\n";
234                 if ( $diff < $time_out ) {
235                         print "   the delay time is:     $diff \n";
236                         print "   udevd doesn't act properly. \n";
237                         exit 1;
238                 }
239         }
240         close(LOGF);
241 }
242
243 sub show_result_immediate {
244         my $event_recv_time;
245         my $udev_fork_time;
246         my $line;
247         my @content;
248         my @line_items;
249         my $diff;
250
251         ($event_recv_time) = @_;
252
253         print "   event receiving time:  $event_recv_time\n\n";
254
255         open(LOGF, $log_file) || die "Opening file $log_file: $!";
256         @content = <LOGF>;
257         foreach $line ( @content ) {
258                 @line_items = split(/,/,$line);
259                 print "   device: $line_items[0], action: $line_items[1] \n";
260                 print "   forking udev time:     $line_items[-1]";
261                 $diff = cmpDate($line_items[-1], $event_recv_time);
262                 print "   the delay time is:     $diff s \n\n";
263                 if ( $diff > $time_out ) {
264                         print "   the delay time is:     $diff \n";
265                         print "   udevd doesn't act properly. \n";
266                         exit 1;
267                 }
268         }
269         close(LOGF);
270 }
271
272 sub check_exe_time {
273         my @exe_time;
274         my $i = 0;
275         my $line;
276         my @content;
277         my @line_items;
278         my $diff;
279
280         open(LOGF, $log_file) || die "Opening file $log_file: $!";
281         @content = <LOGF>;
282         close(LOGF);
283         foreach $line ( @content ) {
284                 @line_items = split(/,/,$line);
285                 $exe_time[$i] = $line_items[-1];
286                 $i++;
287         }
288         $diff = cmpDate($exe_time[1], $exe_time[0]);
289         if ( $diff < $udev_exe_time ) {
290                 print "   there are more than one udev instance for a single device at the same time. \n";
291                 exit 1;
292         } else {
293                 print "   there is just one udev instance for a single device at the same time. \n";
294         }
295 }
296
297 # test case functions
298 sub run_no_seq_test {
299         print "Test case name:     no sequence number test\n";
300         print "Test case purpose:  check whether udevd forks udev immediately when environment variable SEQNUM is null.\n";
301         print "Test expected visible results: \n";
302         print "   the delay time between event receiving and forking udev for udevd should be negligible, \n";
303         print "   that is, udev should be forked at once. please notice the following time...\n\n";
304
305         my $time;
306
307         #
308         # add devices event test
309         #
310         restart_daemon();
311
312         # check if devices /block/sda exist
313         check_sysfs_device_exist("$sysfs/block/sda");
314
315         # log current system date/time
316         $time = getDate();
317
318         udevsend(-1, "/block/sda", "add", "block");
319
320         # check if execution is successful in time
321         sleep 1;
322         show_result_immediate($time);
323         print "   fork udev (add device) at once successfully.\n\n";
324
325         #
326         # remove devices event test
327         #
328         system("rm -f $log_file");
329
330         # log current system date/time
331         $time = getDate();
332
333         udevsend(-1, "/block/sda", "remove", "block");
334
335         # check if execution is successful in time
336         sleep 1;
337         show_result_immediate($time);
338         print "   fork udev (remove device) at once successfully.\n\n";
339         print "this case is ok\n\n";
340 }
341
342 sub run_normal_seq_test {
343         print "Test case name:    normal sequence number stress test\n";
344         print "Test case purpose: check whether udevd can fork massive udev instances for \n";
345         print "                   massive sequential events successfully. \n";
346         print "Test expected visible results: \n";
347         print "   Populate all the devices in directory $sysfs/class/tty, fork udved to send add/remove \n";
348         print "   event to udev for each device. \n";
349         print "   We can see the delay time for each device should be negligible. \n\n";
350
351         my @file_list;
352         my $file;
353         my $seq = 0;
354         my $time;
355         my $ret_seq;
356
357         restart_daemon();
358         @file_list = glob "$sysfs/class/tty/*";
359
360         # log current system date/time for device add events
361         $time = getDate();
362
363         #
364         # add devices event test
365         #
366         print "add device events test: \n";
367         foreach $file (@file_list) {
368                 udevsend($seq, substr($file, length($sysfs), length($file)-length($sysfs)), "add", "tty");
369                 # check if execution is successful
370                 if ($? == 0) {
371                         $seq++;
372                 } else {
373                         print "add event: error\n\n";
374                         exit 1;
375                 }
376         }
377
378         # we'd better wait the udev to create all the device for a few seconds
379         print "   wait for udevd processing about $time_out s... \n\n";
380         sleep $time_out + 5;
381
382         $ret_seq = check_count_and_time($time);
383         if ( $ret_seq != $seq ) {
384                 print "   add event: failed. some device-adding events fail to execute.\n\n";
385                 exit 1;
386         } else {
387                 print "   $seq pieces of device-adding events have executed successfully.\n\n";
388         }
389
390         # log current system date/time for device remove events
391         $time = getDate();
392
393         #
394         # remove devices event test
395         #
396         print "remove device events test: \n";
397         restart_daemon();
398         @file_list = glob "$sysfs/class/tty/*"; 
399         $seq = 0;
400         foreach $file (@file_list) {
401                 udevsend($seq, substr($file, length($sysfs), length($file)-length($sysfs)), "remove", "tty");
402                 # check if execution is successful
403                 if ($? == 0) {
404                         $seq++;
405                 } else {
406                         print "remove event: error\n\n";
407                         exit 1;
408                 }
409         }
410
411         # we'd better wait the udev to create all the device for a few seconds
412         print "   waiting for udev removing devices (about $time_out s)...\n";
413         sleep $time_out + 5;
414
415         # show results
416         $ret_seq = check_count_and_time($time);
417         if ( $ret_seq != $seq ) {
418                 print "   remove event: failed. some device-removing events fail to execute.\n\n";
419                 exit 1;
420         } else {
421                 print "   $seq pieces of device-removing events have executed successfully.\n\n";
422                 print "this case is ok.\n\n";
423         }
424 }
425
426 sub run_random_seq_test {
427         print "Test case name:    random sequence number test case,\n";
428         print "Test case purpose: check whether udevd can order the events with random sequence number \n";
429         print "                   and fork udev correctly. \n";
430         print "Test expected visible results: \n";
431         print "   We have disordered the events sent to udevd, if udevd can order them correctly, the devices' \n";
432         print "   add/remove sequence should be tty0, tty1, tty2. \n\n";
433
434         my $time;
435
436         # check if devices /class/tty/tty0, tty1, tty2 exist
437         check_sysfs_device_exist("$sysfs/class/tty/tty0", "$sysfs/class/tty/tty1", "$sysfs/class/tty/tty2");
438
439         #
440         # add device events test
441         #
442         print "add device events test: \n";
443         restart_daemon();
444
445         # log current system date/time for device remove events
446         $time = getDate();
447
448         # parameters: 1 sequence number, 2 device, 3 action, 4 subsystem
449         udevsend(3, "/class/tty/tty2", "add", "tty");
450         udevsend(1, "/class/tty/tty0", "add", "tty");
451         udevsend(2, "/class/tty/tty1", "add", "tty");
452         print "   wait for udevd processing about $time_out s... \n\n";
453         sleep $time_out+1;
454         show_result_tm_out($time);
455
456         #
457         # remove device events test
458         #
459         print "\nremove device events test: \n";
460         restart_daemon();
461
462         # log current system date/time for device remove events
463         $time = getDate();
464
465         udevsend(3, "/class/tty/tty2", "remove", "tty");
466         udevsend(2, "/class/tty/tty1", "remove", "tty");
467         udevsend(1, "/class/tty/tty0", "remove", "tty");
468
469         # show results
470         print "   wait for udevd processing about $time_out s... \n\n";
471         sleep $time_out+1;
472         show_result_tm_out($time);
473         print "this case is ok.\n\n";
474 }
475
476 sub run_expected_seq_test { 
477         print "Test case name:    expected sequence number test \n";
478         print "Test case purpose: check whether udevd fork udev immediately when the incoming event\n";
479         print "                   is exactly the expected event sequence number.\n";
480         print "Test expected visible results:\n";
481         print "   first, udevd disposes disorder events(sequence number is 3,1,2,5,4,6),\n";
482         print "   thus after disposed the expected event number for udevd is 7, when incoming event is 7, udevd\n";
483         print "   should fork udev immediately, the delay time should be negligible. \n";
484         print "   where: event 7 is (add device /class/tty/tty2) \n\n";
485
486         my $time;
487
488         # check if devices /class/tty0, tty1, tty2 exist
489         check_sysfs_device_exist("$sysfs/class/tty/tty0", "$sysfs/class/tty/tty1", "$sysfs/class/tty/tty2");
490
491         restart_daemon();
492
493         # parameters: 1 sequence number, 2 device, 3 action, 4 subsystem
494         udevsend(3, "/class/tty/tty2", "add", "tty");
495         udevsend(1, "/class/tty/tty0", "add", "tty");
496         udevsend(2, "/class/tty/tty1", "add", "tty");
497         udevsend(5, "/class/tty/tty1", "remove", "tty");
498         udevsend(4, "/class/tty/tty0", "remove", "tty");
499         udevsend(6, "/class/tty/tty2", "remove", "tty");
500
501         print "   wait for udevd timing out for disorder events (about $time_out s) \n\n";
502         sleep $udev_exe_time + $time_out+1;
503         system("rm -f $log_file");
504
505         # log current system date/time for device remove events
506         $time = getDate();
507
508         # show results
509         udevsend(7, "/class/tty/tty2", "add", "tty");
510         sleep 1;
511         print "   event sequence number: 7 \n";
512         show_result_immediate($time);
513
514         print "this case is ok.\n\n";
515 }
516
517 sub run_single_instance_test { 
518         print "Test case name:    single instance running for a single device test \n";
519         print "Test case purpose: check whether udevd only fork one udev instance for a single\n";
520         print "                   device at the same time. For each event a udev instance is \n";
521         print "                   executed in the background. All further events for the same \n";
522         print "                   device are delayed until the execution is finished. This way \n";
523         print "                   there will never be more than one instance running for a single \n";
524         print "                   device at the same time.\n";
525         print "Test expected visible results:\n";
526         print "   In this test we amplify the execution time of udev (about 5 seconds), first, \n";
527         print "   we send a add event for device /block/sda, and then we send a remove event, so the \n";
528         print "   execution of remove event should be delayed until add is finished. \n\n";
529
530         my $time;
531
532         restart_daemon($udev_bin2);
533
534         # check if device exists
535         check_sysfs_device_exist("$sysfs/block/sda");
536
537         # log current system date/time
538         $time = getDate();
539
540         udevsend(-1, "/block/sda", "add", "block");
541         udevsend(-1, "/block/sda", "remove", "block");
542
543         # show results
544         print "   wait for udevd processing about $udev_exe_time s... \n\n";
545         sleep $udev_exe_time+1;
546         show_result_immediate($time);
547         check_exe_time();
548         print "this case is ok\n\n";
549 }
550
551 sub run_same_events_test { 
552         print "Test case name:    event sequence number overlap test \n";
553         print "Test case purpose: check whether udevd doesn't fork udev untill time out\n";
554         print "                   when encountering a event with sequence number same as the pevious event. \n";
555         print "Test expected visible results:\n";
556         print "   event ( remove device /block/sda ) should be no delay, \n";
557         print "   event ( add device /class/tty/tty1 ) should be delayed for $time_out s than its previous \n";
558         print "   event ( remove device /block/sda ) \n\n";
559
560         my $time;
561
562         restart_daemon();
563
564         # check if device exist
565         check_sysfs_device_exist("$sysfs/block/sda", "$sysfs/class/tty/tty1");
566
567         udevsend(0, "/block/sda", "add", "block");
568
569         # log current system date/time
570         sleep 1;
571         $time = getDate();
572         system("rm -f $log_file");
573
574         udevsend(1, "/block/sda", "remove", "block");
575         udevsend(1, "/class/tty/tty1", "add", "tty");
576
577         # show results
578         print "   wait for udevd processing about $time_out s... \n\n";
579         sleep $time_out+1;
580         show_result($time);
581         print "this case is ok\n\n";
582 }
583
584 sub run_missing_seq_test {
585         print "Test case name:    missing sequence number test \n";
586         print "Test case purpose: check whether udevd doesn't fork udev untill time out\n";
587         print "                   when certain event sequence number is missing.\n";
588         print "Test expected visible results:\n";
589         print "   the delay time for event(add device /block/sda) should be about $time_out s.\n\n";
590
591         my $time;
592
593         restart_daemon();
594
595         # check if device exist
596         check_sysfs_device_exist("$sysfs/block/sda", "$sysfs/class/tty/tty1");
597
598         udevsend(0, "/class/tty/tty1", "add", "tty");
599         udevsend(1, "/class/tty/tty1", "remove", "tty");
600         sleep 1;
601
602         # log current system date/time
603         $time = getDate();
604         system("rm -f $log_file");
605
606         udevsend(3, "/block/sda", "add", "block");
607
608         # show results
609         print "   wait for udevd processing about $time_out s... \n\n";
610         sleep $time_out+1;
611         show_result($time);
612         print "this case is ok\n\n";
613 }
614
615 sub run_all_cases_test { 
616         run_no_seq_test();
617         run_normal_seq_test();
618         run_random_seq_test();
619         run_missing_seq_test();
620         run_expected_seq_test();
621         run_same_events_test();
622         run_single_instance_test();
623 }
624
625 # main program
626 if ($ARGV[0]) {
627         $test_case = $ARGV[0];
628
629         if ($test_case == 1) {
630                 run_no_seq_test();
631         } elsif ($test_case == 2) {
632                 run_normal_seq_test();
633         } elsif ($test_case == 3) {
634                 run_random_seq_test();
635         } elsif ($test_case == 4) {
636                 run_missing_seq_test();
637         } elsif ($test_case == 5) {
638                 run_expected_seq_test();
639         } elsif ($test_case == 6) {
640                 run_single_instance_test();
641         } elsif ($test_case == 7) {
642                 run_same_events_test();
643         } else {
644                 run_all_cases_test();
645         }
646 } else {
647         # echo usage
648         print "command format: perl udevd-test.pl <case number>\n";
649         print "   test case:\n";
650         print "           1: no event sequence number\n";
651         print "           2: sequential event sequence number\n";
652         print "           3: random event sequence number\n";
653         print "           4: missing event sequence number\n";
654         print "           5: the incoming event sequence number is right the expected sequence number\n";
655         print "           6: single udev instance on a single device at the same time\n";
656         print "           7: test event sequence number overlap\n";
657         print "           9: all the cases\n\n";
658 }