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