| #!/usr/bin/env perl |
| # Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. |
| # |
| # SPDX-License-Identifier: curl |
| # |
| # Input: number of seconds to run. |
| # |
| # 1. Figure out all existing command line options |
| # 2. Generate random command line using supported options |
| # 3. Run the command line |
| # 4. Verify that it does not return an unexpected return code |
| # 5. Iterate until the time runs out |
| # |
| # Do the same with regular command lines as well as reading the options from a |
| # -K config file |
| # |
| # BEWARE: this may create a large amount of files using random names in the |
| # directory where it runs. |
| # |
| |
| use strict; |
| use warnings; |
| |
| my $curl = "../src/curl"; |
| my $url = "localhost:7777"; # not listening to this |
| |
| my $seconds = $ARGV[0]; |
| if($ARGV[1]) { |
| $curl = $ARGV[1]; |
| } |
| |
| if(!$seconds) { |
| $seconds = 10; |
| } |
| print "Run $curl for $seconds seconds\n"; |
| |
| my @opt; |
| my %arg; |
| my %uniq; |
| my %allrc; |
| |
| my $totalargs = 0; |
| my $totalcmds = 0; |
| |
| my $counter = 0xabcdef + time(); |
| sub getnum { |
| my ($max) = @_; |
| return int(rand($max)); |
| } |
| |
| sub storedata { |
| my ($short, $long, $arg) = @_; |
| push @opt, "-$short" if($short); |
| push @opt, "--$long"; |
| |
| if($arg =~ /^</) { |
| # these take an argument |
| $arg{"-$short"} = $arg if($short); |
| $arg{"--$long"} = $arg; |
| } |
| } |
| |
| sub getoptions { |
| my @all = `$curl --help all`; |
| for my $o (@all) { |
| chomp $o; |
| if($o =~ /^ -(.), --([^ ]*) (.*)/) { |
| storedata($1, $2, $3); |
| } |
| elsif($o =~ /^ --([^ ]*) (.*)/) { |
| storedata("", $1, $2); |
| } |
| } |
| } |
| |
| # this adds a fake randomly generated command line option |
| sub addarg { |
| my $nice = "abcdefhijklmnopqrstuvwqxyz". |
| "ABCDEFHIJKLMNOPQRSTUVWQXYZ". |
| "0123456789-"; |
| my $len = getnum(20) + 2; |
| my $o; |
| for (1 .. $len) { |
| $o .= substr($nice, getnum(length($nice)), 1); |
| } |
| return "--$o"; |
| } |
| |
| sub randarg { |
| my $nice = "abcdefhijklmnopqrstuvwqxyz". |
| "ABCDEFHIJKLMNOPQRSTUVWQXYZ". |
| "0123456789". |
| ",-?#$%!@ "; |
| my $len = getnum(20); |
| my $o = ''; |
| for (1 .. $len) { |
| $o .= substr($nice, getnum(length($nice)), 1); |
| } |
| return "\'$o\'"; |
| } |
| |
| getoptions(); |
| |
| my $nopts = scalar(@opt); |
| |
| my %useropt = ( |
| '-U' => 1, |
| '-u' => 1, |
| '--user' => 1, |
| '--proxy-user' => 1); |
| |
| my %commonrc = ( |
| '0' => 1, |
| '1' => 1, |
| '2' => 1, |
| '26' => 1, |
| ); |
| |
| sub runone { |
| my $a; |
| my $nargs = getnum(60) + 1; |
| |
| $totalargs += $nargs; |
| $totalcmds++; |
| for (1 .. $nargs) { |
| my $o = getnum($nopts); |
| my $option = $opt[$o]; |
| my $ar = ""; |
| $uniq{$option}++; |
| if($arg{$option}) { |
| $ar = " ".randarg(); |
| |
| if($useropt{$option}) { |
| # append password to avoid prompting |
| $ar .= ":".randarg(); |
| } |
| } |
| $a .= sprintf(" %s%s", $option, $ar); |
| } |
| if(getnum(100) < 15) { |
| # add a fake arg |
| $a .= " ".addarg(); |
| } |
| |
| my $cmd="$curl$a $url"; |
| |
| my $rc = system("$cmd >curl-output 2>&1 </dev/null -M 0.1") >> 8; |
| #my $rc = system("valgrind -q $cmd >/dev/null 2>&1 </dev/null -M 0.1") >> 8; |
| |
| $allrc{$rc}++; |
| |
| #print "CMD: $cmd\n"; |
| if(!$commonrc{$rc}) { |
| print "CMD: $cmd\n"; |
| print "RC: $rc\n"; |
| print "== curl-output == \n"; |
| open(D, "<curl-output"); |
| my @out = <D>; |
| print @out; |
| close(D); |
| exit; |
| } |
| } |
| |
| sub runconfig { |
| my $a; |
| my $nargs = getnum(80) + 1; |
| |
| open(C, ">config"); |
| |
| $totalargs += $nargs; |
| $totalcmds++; |
| for (1 .. $nargs) { |
| my $o = getnum($nopts); |
| my $option = $opt[$o]; |
| my $ar = ""; |
| $uniq{$option} = 0 if(!exists $uniq{$option}); |
| $uniq{$option}++; |
| if($arg{$option}) { |
| $ar = " ".randarg(); |
| |
| if($useropt{$option}) { |
| # append password |
| $ar .= ":".randarg(); |
| } |
| } |
| $a .= sprintf("\n%s%s", $option, $ar); |
| } |
| if(getnum(100) < 15) { |
| # add a fake arg |
| $a .= "\n".addarg(); |
| } |
| |
| print C "$a\n"; |
| close(C); |
| |
| my $cmd="$curl -K config $url"; |
| |
| my $rc = system("$cmd >curl-output 2>&1 </dev/null -M 0.1") >> 8; |
| |
| $allrc{$rc}++; |
| |
| if(!$commonrc{$rc}) { |
| print "CMD: $cmd\n"; |
| print "RC: $rc\n"; |
| print "== config == \n"; |
| open(D, "<config"); |
| my @all = <D>; |
| print @all; |
| close(D); |
| print "\n== curl-output == \n"; |
| open(D, "<curl-output"); |
| my @out = <D>; |
| print @out; |
| close(D); |
| exit 2; |
| } |
| } |
| |
| # run curl command lines using -K |
| my $end = time() + $seconds/2; |
| my $c = 0; |
| print "Running command lines\n"; |
| do { |
| runconfig(); |
| $c++; |
| } while(time() <= $end); |
| print "$c command lines\n"; |
| |
| # run curl command lines |
| $end = time() + $seconds/2; |
| $c = 0; |
| print "Running config lines\n"; |
| do { |
| runone(); |
| $c++; |
| } while(time() <= $end); |
| |
| print "$c config line uses\n"; |
| |
| print "Recorded exit codes:\n"; |
| for my $rc (keys %allrc) { |
| printf " %2d: %d times\n", $rc, $allrc{$rc}; |
| } |
| printf "Number or command lines tested:\n". |
| " $totalcmds (%.1f/second)\n", $totalcmds/$seconds; |
| printf "Number or command line options tested:\n". |
| " $totalargs (average %.1f per command line)\n", |
| $totalargs/$totalcmds; |
| printf "Number or different options tested:\n". |
| " %u out of %u\n", scalar(keys %uniq), $nopts; |