Class: Tlopo::SeleniumDocker
- Inherits:
-
Object
- Object
- Tlopo::SeleniumDocker
- Defined in:
- lib/tlopo/selenium_docker.rb,
lib/tlopo/selenium_docker/version.rb
Constant Summary collapse
- VERSION =
"0.1.2"
Instance Method Summary collapse
- #best_effort ⇒ Object
- #copy_video ⇒ Object
- #create_network ⇒ Object
- #driver ⇒ Object
- #find_free_port(from, to) ⇒ Object
- #gen_short_id ⇒ Object
- #get_container(container_name) ⇒ Object
- #get_port_lock(port) ⇒ Object
-
#initialize(opts = {}) ⇒ SeleniumDocker
constructor
A new instance of SeleniumDocker.
- #lock_chrome_data_dir ⇒ Object
- #pull_images ⇒ Object
- #remove_network ⇒ Object
- #run ⇒ Object
- #start ⇒ Object
- #start_selenium ⇒ Object
- #start_video ⇒ Object
- #stop ⇒ Object
- #stop_container(container_name, timeout = 30) ⇒ Object
- #stop_selenium ⇒ Object
- #stop_video ⇒ Object
Constructor Details
#initialize(opts = {}) ⇒ SeleniumDocker
Returns a new instance of SeleniumDocker.
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/tlopo/selenium_docker.rb', line 17 def initialize(opts = {}) @selenium_image = opts[:selenium_image] || "selenium/standalone-chrome:4.8.3" @video_image = opts[:video_image] || "selenium/video:ffmpeg-4.3.1-20220726" @chrome_data_dir = opts[:chrome_data_dir] || nil @video_path = opts[:video_path] || nil @name = "selenium-#{gen_short_id}" @ws = "/tmp/#{@name}" FileUtils.mkdir_p @ws FileUtils.mkdir_p @chrome_data_dir if @chrome_data_dir end |
Instance Method Details
#best_effort ⇒ Object
36 37 38 39 40 41 |
# File 'lib/tlopo/selenium_docker.rb', line 36 def best_effort begin yield rescue end end |
#copy_video ⇒ Object
77 78 79 80 81 82 83 |
# File 'lib/tlopo/selenium_docker.rb', line 77 def copy_video return unless @video_path path = @video_path =~ /\.mp4$/ ? @video_path : "#{@video_path}.mp4" FileUtils.cp "#{@ws}/video/video.mp4", path LOGGER.debug "Recorded video saved to '#{path}''" end |
#create_network ⇒ Object
104 105 106 107 108 109 110 |
# File 'lib/tlopo/selenium_docker.rb', line 104 def create_network network_name = @name.to_s return if Docker::Network.all.map(&:info).any? { |n| n["Name"] == network_name } LOGGER.debug "Creating network #{network_name}" Docker::Network.create network_name end |
#driver ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/tlopo/selenium_docker.rb', line 181 def driver return @driver unless @driver.nil? Timeout.timeout(60) do loop do TCPSocket.new("localhost", @port).close url = "http://localhost:#{@port}/wd/hub" = Selenium::WebDriver::Chrome::Options.new .add_argument("--no-first-run") .add_argument("--user-data-dir=/tmp/chrome-data-dir") @driver = Selenium::WebDriver.for :remote, url: url, capabilities: LOGGER.debug "driver created for #{@name}" break rescue Errno::ECONNREFUSED sleep 0.5 rescue EOFError sleep 0.5 rescue Selenium::WebDriver::Error::UnknownError sleep 0.5 end end @driver end |
#find_free_port(from, to) ⇒ Object
85 86 87 88 89 90 91 92 93 |
# File 'lib/tlopo/selenium_docker.rb', line 85 def find_free_port(from, to) (from..to).each do |port| next if Tlopo::Futex.new("/tmp/.selenium-docker-#{port}").locked? Timeout.timeout(1) { TCPSocket.new("127.0.0.1", port).close } rescue Errno::ECONNREFUSED return port end end |
#gen_short_id ⇒ Object
43 44 45 |
# File 'lib/tlopo/selenium_docker.rb', line 43 def gen_short_id Zlib.crc32(Time.now.strftime("%s.%N")).to_s(36) end |
#get_container(container_name) ⇒ Object
120 121 122 123 124 |
# File 'lib/tlopo/selenium_docker.rb', line 120 def get_container(container_name) Docker::Container.get(container_name) rescue Docker::Error::NotFoundError nil end |
#get_port_lock(port) ⇒ Object
47 48 49 50 51 52 |
# File 'lib/tlopo/selenium_docker.rb', line 47 def get_port_lock(port) filename = "/tmp/.selenium-docker-#{port}" f = Tlopo::Futex.new(filename) f.lock f end |
#lock_chrome_data_dir ⇒ Object
134 135 136 137 |
# File 'lib/tlopo/selenium_docker.rb', line 134 def lock_chrome_data_dir @chrome_data_dir_lock = Tlopo::Futex.new("#{@chrome_data_dir}/.chrome_data_dir.lock") @chrome_data_dir_lock.lock end |
#pull_images ⇒ Object
95 96 97 98 99 100 101 102 |
# File 'lib/tlopo/selenium_docker.rb', line 95 def pull_images [@selenium_image, @video_image].each do |image| unless Docker::Image.exist? image LOGGER.debug "Pulling image #{image}" Docker::Image.create("fromImage" => image) end end end |
#remove_network ⇒ Object
112 113 114 115 116 117 118 |
# File 'lib/tlopo/selenium_docker.rb', line 112 def remove_network network_name = @name.to_s return unless Docker::Network.all.map(&:info).any? { |n| n["Name"] == network_name } LOGGER.debug "Removing network #{network_name}" Docker::Network.get(network_name).remove end |
#run ⇒ Object
28 29 30 31 32 33 34 |
# File 'lib/tlopo/selenium_docker.rb', line 28 def run start yield driver ensure best_effort { driver.quit } stop end |
#start ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/tlopo/selenium_docker.rb', line 54 def start pull_images lock_chrome_data_dir if @chrome_data_dir @port = find_free_port 8100, 8150 @port_lock = get_port_lock @port @vnc_port = find_free_port 5900, 5950 @vnc_port_lock = get_port_lock @vnc_port create_network start_selenium start_video if @video_path end |
#start_selenium ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/tlopo/selenium_docker.rb', line 139 def start_selenium ws = @chrome_data_dir || "/#{@ws}/chrome-data-dir" LOGGER.debug "Starting selenium, container name: #{@name}, vnc port: #{@vnc_port}" Docker::Container.create( Image: @selenium_image, name: @name.to_s, HostConfig: { NetworkMode: @name.to_s, AutoRemove: true, PortBindings: { "4444/tcp": [{ HostPort: @port.to_s }], "5900/tcp": [{ HostPort: @vnc_port.to_s }] }, "Binds" => ["#{ws}:/tmp/chrome-data-dir"], "ShmSize" => 2 * 1024 * 1024 * 1024 # 2 GB in bytes }, Env: ["VIDEO=true"] ).start end |
#start_video ⇒ Object
163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/tlopo/selenium_docker.rb', line 163 def start_video LOGGER.debug "Starting video, container name: #{@name}-video" Docker::Container.create( Image: @video_image, name: "#{@name}-video", HostConfig: { NetworkMode: @name.to_s, AutoRemove: true, "Binds" => ["#{@ws}/video:/videos"] }, Env: ["DISPLAY_CONTAINER_NAME=#{@name}"] ).start end |
#stop ⇒ Object
66 67 68 69 70 71 72 73 74 75 |
# File 'lib/tlopo/selenium_docker.rb', line 66 def stop stop_video if @video_path stop_selenium remove_network @port_lock.release @vnc_port_lock.release @chrome_data_dir_lock&.release copy_video FileUtils.rm_rf @ws end |
#stop_container(container_name, timeout = 30) ⇒ Object
126 127 128 129 130 131 132 |
# File 'lib/tlopo/selenium_docker.rb', line 126 def stop_container(container_name, timeout = 30) c = get_container(container_name) return if c.nil? LOGGER.debug "Stopping container '#{container_name}'" c.stop t: timeout end |
#stop_selenium ⇒ Object
159 160 161 |
# File 'lib/tlopo/selenium_docker.rb', line 159 def stop_selenium stop_container @name.to_s end |
#stop_video ⇒ Object
177 178 179 |
# File 'lib/tlopo/selenium_docker.rb', line 177 def stop_video stop_container "#{@name}-video" end |