Jar.pm 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package Selenium::Driver::SeleniumHQ::Jar;
  2. use strict;
  3. use warnings;
  4. no warnings 'experimental';
  5. use feature qw/signatures/;
  6. use Carp qw{confess};
  7. use File::Basename qw{basename};
  8. use File::Path qw{make_path};
  9. use File::Spec();
  10. use XML::LibXML();
  11. use HTTP::Tiny();
  12. #ABSTRACT: Download the latest version of seleniumHQ's selenium.jar, and tell Selenium::Client how to spawn it
  13. =head1 Mode of Operation
  14. Downloads the latest Selenium JAR (or the provided driver_version).
  15. Expects java to already be installed.
  16. Spawns a selnium server on the provided port (which the caller will assign randomly)
  17. Pipes log output to ~/.selenium/perl-client/$port.log
  18. Uses a config file ~/.selenium/perl-client/$port.toml if the selenium version supports this
  19. =head1 SUBROUTINES
  20. =head2 build_spawn_opts($class,$object)
  21. Builds a command string which can run the driver binary.
  22. All driver classes must build this.
  23. =cut
  24. our $index = 'http://selenium-release.storage.googleapis.com';
  25. sub build_spawn_opts($class,$object) {
  26. $object->{driver_class} = $class;
  27. $object->{driver_interpreter} //= 'java';
  28. $object->{driver_version} //= '';
  29. $object->{log_file} //= File::Spec->catfile($object->{client_dir},"perl-client","selenium-$object->{port}.log");
  30. ($object->{driver_file}, $object->{driver_major_version}) = find_and_fetch( File::Spec->catdir($object->{client_dir},"jars"), $object->{driver_version},$object->{ua});
  31. $object->{driver_config} //= _build_config($object);
  32. #XXX port in config is currently IGNORED
  33. my @java_opts;
  34. my @config = ((qw{standalone --config}), $object->{driver_config}, '--port', $object->{port});
  35. # Handle older seleniums that are WC3 compliant
  36. if ( $object->{driver_major_version} < 4 ) {
  37. $object->{prefix} = '/wd/hub';
  38. @java_opts = qw{-Dwebedriver.gecko.driver=geckodriver -Dwebdriver.chrome.driver=chromedriver};
  39. @config = ();
  40. }
  41. # Build command string
  42. # XXX relies on gecko/chromedriver in $PATH
  43. $object->{command} //= [
  44. $object->{driver_interpreter},
  45. @java_opts,
  46. qw{-jar},
  47. $object->{driver_file},
  48. @config,
  49. ];
  50. return $object;
  51. }
  52. sub _build_config($self) {
  53. my $dir = File::Spec->catdir($self->{client_dir},"perl-client");
  54. make_path( $dir ) unless -d $dir;
  55. my $file = File::Spec->catfile($dir,"config-$self->{port}.toml");
  56. return $file if -f $file;
  57. # TODO add some self-signed SSL to this
  58. my $config = <<~EOF;
  59. [node]
  60. detect-drivers = true
  61. [server]
  62. allow-cors = true
  63. hostname = "localhost"
  64. max-threads = 36
  65. port = --PORT--
  66. [logging]
  67. enable = true
  68. log-encoding = UTF-8
  69. log-file = --REPLACE--
  70. plain-logs = true
  71. structured-logs = false
  72. tracing = true
  73. EOF
  74. #XXX double escape backslash because windows; like YAML, TOML is a poor choice always
  75. #XXX so, you'll die if there are backslashes in your username or homedir choice (lunatic)
  76. my $log_corrected = $self->{log_file};
  77. $log_corrected =~ s/\\/\\\\/g;
  78. $config =~ s/--REPLACE--/\"$log_corrected\"/gm;
  79. $config =~ s/--PORT--/$self->{port}/gm;
  80. File::Slurper::write_text($file, $config);
  81. return $file;
  82. }
  83. =head2 find_and_fetch($dir STRING, $version STRING, $user_agent HTTP::Tiny)
  84. Does an index lookup of the various selenium JARs available and returns either the latest one
  85. or the version provided. Stores the JAR in the provided directory.
  86. =cut
  87. sub find_and_fetch($dir, $version='', $ua='') {
  88. $ua ||= HTTP::Tiny->new();
  89. my $res = $ua->get($index);
  90. confess "$res->{reason} :\n$res->{content}\n" unless $res->{success};
  91. my $parsed = XML::LibXML->load_xml(string => $res->{content});
  92. #XXX - XPATH NO WORKY, HURR DURR
  93. my @files;
  94. foreach my $element ($parsed->findnodes('//*')) {
  95. my $contents = $element->getChildrenByTagName("Contents");
  96. my @candidates = sort { $b cmp $a } grep { m/selenium-server/ && m/\.jar$/ } map {
  97. $_->getChildrenByTagName('Key')->to_literal().'';
  98. } @$contents;
  99. push(@files,@candidates);
  100. }
  101. @files = grep { m/\Q$version\E/ } @files if $version;
  102. my $jar = shift @files;
  103. my $url = "$index/$jar";
  104. make_path( $dir ) unless -d $dir;
  105. my $fname = File::Spec->catfile($dir, basename($jar));
  106. my ($v) = $fname =~ m/-(\d)\.\d\.\d.*\.jar$/;
  107. return ($fname,$v) if -f $fname;
  108. $res = $ua->mirror($url, $fname);
  109. confess "$res->{reason} :\n$res->{content}\n" unless $res->{success};
  110. return ($fname,$v);
  111. }
  112. 1;