blow up after failing to start the selenium server - no point continuing
[scpubgit/Test-Harness-Selenium.git] / lib / Test / Harness / Selenium.pm
index 678556f..99ffe43 100644 (file)
@@ -7,6 +7,9 @@ use HTML::TableExtract;
 use IO::All;
 use Alien::SeleniumRC;
 use LWP::Simple;
+use Child;
+
+our $VERSION = '0.01';
 
 use Test::More;
 BEGIN {
@@ -30,71 +33,121 @@ BEGIN {
 }
 
 sub new {
-  my ($class, $self) = @_;
-  if($self->{xvnc}) {
-    $ENV{DISPLAY} = $self->{xvnc};
-    my $xvnc_pid = fork();
-    if(!defined $xvnc_pid) {
-      die "couldn't fork xvnc: $!";
+  my $class = shift;
+  my %args = @_;
+  my $selrc = ($args{selenium_rc} ||={});
+  $selrc->{$_} = $ENV{"SELENIUM_RC_${\uc $_}"}
+    for grep exists $ENV{"SELENIUM_RC_${\uc $_}"},
+      qw(host port start start_xvnc xvnc_display);
+  $selrc->{xvnc_display} ||= '0';
+  $selrc->{host} ||= 'localhost';
+  $selrc->{port} ||= 4444;
+  $args{browser} ||= '*firefox';
+  my $self = \%args;
+  bless $self, $class;
+}
+
+sub start_selenium_server {
+  my($self) = @_;
+  my $selrc = $self->{selenium_rc};
+  if($selrc->{start}) {
+    my ($host, $display, $port) = @{$selrc}{qw(host xvnc_display port)};
+    my @do_ssh = $host eq 'localhost' ? () : ('ssh', $host);
+    if ($selrc->{start_xvnc}) {
+      $selrc->{xvnc_server_proc} = Child->new(
+          sub {
+            exec(
+              @do_ssh,
+              'vncserver', ":${display}",
+            );
+          }
+        )->start;
+      $selrc->{xvnc_started} = 1;
+      sleep 3;
     }
-    elsif($xvnc_pid) {
-      $self->{xvnc_pid} = $xvnc_pid;
+    $selrc->{selenium_server_proc} = Child->new(
+      sub {
+        exec(
+          @do_ssh,
+          'env', "DISPLAY=:${display}", 'selenium-rc', '-port', $port
+        )
+      }
+    )->start;
+    sleep 1;
+  }
+  my $tries = 0;
+  while($tries < 5) {
+    eval {
+      # if we don't create the ::Selenium object ourselves, then
+      # wikifixture shuts the session down after the first test table
+      # is run, at which point KABOOM when you try and run a second one.
+      $self->{src} = Socialtext::WikiFixture::Selenese->new(
+        selenium => Test::WWW::Selenium->new(
+          host => $self->{selenium_rc}{host},
+          port => $self->{selenium_rc}{port},
+          browser => $self->{browser},
+          browser_url => $self->{app_base},
+        )
+      );
+    };
+    $tries++;
+    if(!defined $self->{src}) {
+      sleep 10;
     }
     else {
-      exec("vncserver", $self->{xvnc});
+      last;
     }
   }
-  bless $self, $class;
+  if($tries == 5) {
+    diag "timed out waiting for selenium server to start at
+    http://$self->{selenium_rc}{host}:$self->{selenium_rc}{port}" if $tries == 5;
+    $self->done;
+    die;
+  }
 }
 
-sub start_server {
+sub stop_selenium_server {
   my($self) = @_;
-  $self->{server_pid} = fork();
-  if(!defined $self->{server_pid}) {
-    die "can't fork: $!";
+  if (my $proc = delete $self->{selenium_rc}{selenium_server_proc}) {
+    my $url = sprintf
+      "http://%s:%s/selenium-server/driver/?cmd=shutDownSeleniumServer",
+      $self->{selenium_rc}{host}, $self->{selenium_rc}{port};
+    eval { get($url); }; # will fail if it never started
+    delete $self->{src};
+    $proc->kill("KILL");
   }
-  if($self->{server_pid} > 0) {
-    my $tries = 0;
-    while($tries < 5) {
-      eval {
-        $self->{src} = Socialtext::WikiFixture::Selenese->new(
-          host => $self->{host},
-          port => $self->{port},
-          browser => $self->{browser},
-          browser_url => $self->{browser_url},
-        );
-      };
-      $tries++;
-      if(!defined $self->{src}) {
-        sleep 10;
-      }
-      else {
-        last;
-      }
-    }
-    die "timed out waiting for selenium server to start" if $tries == 5;
-  }
-  elsif($self->{server_pid} == 0) {
-    # muttermutter, can't specify a host for selenium
-    exec("$^X -MAlien::SeleniumRC -e 'Alien::SeleniumRC::start(q{-port $self->{port}})'");
+  if (delete $self->{selenium_rc}{xvnc_started}) {
+    my $host = $self->{selenium_rc}{host};
+    my @do_ssh = $host eq 'localhost' ? () : ('ssh', $host);
+    Child->new(sub {
+      exec(@do_ssh, 'vncserver', '-kill',
+        ":$self->{selenium_rc}{xvnc_display}");
+    })->start->wait;
   }
 }
 
-sub stop_server {
+sub start_app_server {
   my($self) = @_;
-  # okay, we're done, kill the server.
-  get("http://localhost:$self->{port}/selenium-server/driver/?cmd=shutDownSeleniumServer");
-  delete $self->{src};
-  wait;
+  my $child = Child->new(sub { exec($self->{app_server_cmd}) } );
+  $self->{app_server_proc} = $child->start;
+}
+
+sub stop_app_server {
+  my($self) = @_;
+  $self->{app_server_proc}->kill("KILL");
 }
 
 sub test_directory {
   my ($self, $dir) = @_;
+  if(!exists $self->{app_server_proc}) {
+    $self->start_app_server;
+  }
+  if($self->{selenium_rc}{start} && !$self->{selenium_rc}{selenium_server_proc}) {
+    $self->start_selenium_server;
+  }
   my @tests = File::Find::Rule->file()->name('*.html')->in($dir);
   for my $test (@tests) {
-    $self->start_server;
     $self->run_tests_for($test);
-    $self->stop_server;
   }
 }
 
@@ -116,11 +169,13 @@ sub get_rows_for {
   return \@rows;
 }
 
-sub DESTROY {
+sub done {
   my($self) = @_;
-  if(exists $self->{xvnc_pid}) {
-    kill("KILL", $self->{xvnc_pid});
+  if(exists $self->{selenium_rc}{xvnc_server_proc} and 
+    exists $self->{selenium_rc}{selenium_server_proc}) {
+    $self->stop_selenium_server;
   }
+  $self->stop_app_server;
 }
 
 1;