1use strict; 2use Test::More tests => 82; 3use POSIX qw(dup2); 4use IO::Handle; 5use FileHandle; 6 7use Net::FTPServer::InMem::Server; 8 9pipe INFD0, OUTFD0 or die "pipe: $!"; 10pipe INFD1, OUTFD1 or die "pipe: $!"; 11my $pid = fork (); 12die unless defined $pid; 13unless ($pid) { # Child process (the server). 14 POSIX::dup2 (fileno INFD0, 0); 15 POSIX::dup2 (fileno OUTFD1, 1); 16 close INFD0; 17 close OUTFD0; 18 close INFD1; 19 close OUTFD1; 20 my $ftps = Net::FTPServer::InMem::Server->run 21 (['--test', '-d', '-C', '/dev/null']); 22 exit; 23} 24 25# Parent process (the test script). 26close INFD0; 27close OUTFD1; 28OUTFD0->autoflush (1); 29 30$_ = <INFD1>; 31print OUTFD0 "USER rich\r\n"; 32$_ = <INFD1>; 33ok (/^331/); 34 35print OUTFD0 "PASS 123456\r\n"; 36$_ = <INFD1>; 37ok (/^230 Welcome rich\./); 38 39# Enter passive mode and get a port number. 40print OUTFD0 "PASV\r\n"; 41$_ = <INFD1>; 42ok (/^227 Entering Passive Mode \(127,0,0,1,(.*),(.*)\)/); 43 44my $port = $1 * 256 + $2; 45 46# Upload some files. 47ok (upload ("test1", "Oh I can see them now")); 48ok (upload ("test2", "Clutching a hankerchief")); 49ok (upload ("test3", "And blowing me a kiss")); 50ok (upload ("test4", "Discreetly asking how")); 51ok (upload ("test5", "How came he died so young")); 52ok (upload ("test6", "Or was he very old")); 53 54# Create some subdirectories. 55print OUTFD0 "MKD sub1\r\n"; 56$_ = <INFD1>; 57ok (/^250/); 58 59print OUTFD0 "MKD sub2\r\n"; 60$_ = <INFD1>; 61ok (/^250/); 62 63print OUTFD0 "MKD sub3\r\n"; 64$_ = <INFD1>; 65ok (/^250/); 66 67# LIST the files. 68print OUTFD0 "LIST\r\n"; 69$_ = <INFD1>; 70ok (/^150/); 71 72my $sock = new IO::Socket::INET 73 (PeerAddr => "127.0.0.1:$port", 74 Proto => "tcp") 75 or die "socket: $!"; 76 77# Read the synthetic lines first. 78$_ = $sock->getline; 79ok ($_ && /^total/); 80$_ = $sock->getline; 81ok ($_ && / \.\r\n$/); 82$_ = $sock->getline; 83ok ($_ && / \.\.\r\n$/); 84 85# Read the files -- they aren't necessarily in alphabetical order (but 86# ought they to be?) [XXX] 87my @filenames = (); 88for (my $i = 0; $i < 9; ++$i) 89 { 90 $_ = $sock->getline; 91 ok ($_ && / ((test|sub)[1-9])\r\n$/); 92 push @filenames, $1; 93 } 94 95$_ = $sock->getline; 96ok (!$_); 97 98@filenames = sort @filenames; 99ok (join (" ", @filenames) eq 100 "sub1 sub2 sub3 test1 test2 test3 test4 test5 test6"); 101 102# Check return code. 103$_ = <INFD1>; 104ok (/^226/); 105 106# LIST * the files. 107print OUTFD0 "LIST *\r\n"; 108$_ = <INFD1>; 109ok (/^150/); 110 111$sock = new IO::Socket::INET 112 (PeerAddr => "127.0.0.1:$port", 113 Proto => "tcp") 114 or die "socket: $!"; 115 116# Read the files -- they aren't necessarily in alphabetical order (but 117# ought they to be?) [XXX] 118@filenames = (); 119for (my $i = 0; $i < 9; ++$i) 120 { 121 $_ = $sock->getline; 122 ok ($_ && / ((test|sub)[1-9])\r\n$/); 123 push @filenames, $1; 124 } 125 126$_ = $sock->getline; 127ok (!$_); 128 129@filenames = sort @filenames; 130ok (join (" ", @filenames) eq 131 "sub1 sub2 sub3 test1 test2 test3 test4 test5 test6"); 132 133# Check return code. 134$_ = <INFD1>; 135ok (/^226/); 136 137# LIST s* the files. 138print OUTFD0 "LIST s*\r\n"; 139$_ = <INFD1>; 140ok (/^150/); 141 142$sock = new IO::Socket::INET 143 (PeerAddr => "127.0.0.1:$port", 144 Proto => "tcp") 145 or die "socket: $!"; 146 147# Read the files -- they aren't necessarily in alphabetical order (but 148# ought they to be?) [XXX] 149@filenames = (); 150for (my $i = 0; $i < 3; ++$i) 151 { 152 $_ = $sock->getline; 153 ok ($_ && / (sub[1-9])\r\n$/); 154 push @filenames, $1; 155 } 156 157$_ = $sock->getline; 158ok (!$_); 159 160@filenames = sort @filenames; 161ok (join (" ", @filenames) eq 162 "sub1 sub2 sub3"); 163 164# Check return code. 165$_ = <INFD1>; 166ok (/^226/); 167 168# NLST the files. 169print OUTFD0 "NLST\r\n"; 170$_ = <INFD1>; 171ok (/^150/); 172 173$sock = new IO::Socket::INET 174 (PeerAddr => "127.0.0.1:$port", 175 Proto => "tcp") 176 or die "socket: $!"; 177 178# Read the files -- they aren't necessarily in alphabetical order (but 179# ought they to be?) [XXX] 180@filenames = (); 181for (my $i = 0; $i < 9; ++$i) 182 { 183 $_ = $sock->getline; 184 ok ($_ && /^((test|sub)[1-9])\r\n$/); 185 push @filenames, $1; 186 } 187 188$_ = $sock->getline; 189ok (!$_); 190 191@filenames = sort @filenames; 192ok (join (" ", @filenames) eq 193 "sub1 sub2 sub3 test1 test2 test3 test4 test5 test6"); 194 195# Check return code. 196$_ = <INFD1>; 197ok (/^226/); 198 199# NLST * the files. 200print OUTFD0 "NLST *\r\n"; 201$_ = <INFD1>; 202ok (/^150/); 203 204$sock = new IO::Socket::INET 205 (PeerAddr => "127.0.0.1:$port", 206 Proto => "tcp") 207 or die "socket: $!"; 208 209# Read the files -- they aren't necessarily in alphabetical order (but 210# ought they to be?) [XXX] 211@filenames = (); 212for (my $i = 0; $i < 9; ++$i) 213 { 214 $_ = $sock->getline; 215 ok ($_ && /^((test|sub)[1-9])\r\n$/); 216 push @filenames, $1; 217 } 218 219@filenames = sort @filenames; 220ok (join (" ", @filenames) eq 221 "sub1 sub2 sub3 test1 test2 test3 test4 test5 test6"); 222 223# Check return code. 224$_ = <INFD1>; 225ok (/^226/); 226 227# NLST t* the files. 228print OUTFD0 "NLST t*\r\n"; 229$_ = <INFD1>; 230ok (/^150/); 231 232$sock = new IO::Socket::INET 233 (PeerAddr => "127.0.0.1:$port", 234 Proto => "tcp") 235 or die "socket: $!"; 236 237# Read the files -- they aren't necessarily in alphabetical order (but 238# ought they to be?) [XXX] 239@filenames = (); 240for (my $i = 0; $i < 6; ++$i) 241 { 242 $_ = $sock->getline; 243 ok ($_ && /^(test[1-9])\r\n$/); 244 push @filenames, $1; 245 } 246 247@filenames = sort @filenames; 248ok (join (" ", @filenames) eq 249 "test1 test2 test3 test4 test5 test6"); 250 251# Check return code. 252$_ = <INFD1>; 253ok (/^226/); 254 255print OUTFD0 "QUIT\r\n"; 256$_ = <INFD1>; 257 258sub upload 259 { 260 my $filename = shift; 261 my $content = join "", @_; 262 263 print OUTFD0 "STOR $filename\r\n"; 264 $_ = <INFD1>; 265 return 0 unless /^150/; 266 267 # Connect to passive mode port. 268 my $sock = new IO::Socket::INET 269 (PeerAddr => "127.0.0.1:$port", 270 Proto => "tcp") 271 or die "socket: $!"; 272 273 # Store some data. 274 $sock->print ($content); 275 $sock->close; 276 277 # Check return code. 278 $_ = <INFD1>; 279 return /^226/; 280 } 281 282__END__ 283