|
17 | 17 |
|
18 | 18 | package org.openqa.selenium.grid.docker;
|
19 | 19 |
|
20 |
| -import com.google.common.collect.ImmutableMap; |
21 | 20 | import org.openqa.selenium.Capabilities;
|
| 21 | +import org.openqa.selenium.Dimension; |
22 | 22 | import org.openqa.selenium.ImmutableCapabilities;
|
23 | 23 | import org.openqa.selenium.SessionNotCreatedException;
|
24 | 24 | import org.openqa.selenium.TimeoutException;
|
|
57 | 57 | import java.net.URL;
|
58 | 58 | import java.time.Duration;
|
59 | 59 | import java.time.Instant;
|
| 60 | +import java.util.Arrays; |
60 | 61 | import java.util.Collections;
|
61 | 62 | import java.util.HashMap;
|
62 | 63 | import java.util.Map;
|
63 | 64 | import java.util.Objects;
|
64 | 65 | import java.util.Optional;
|
| 66 | +import java.util.TimeZone; |
65 | 67 | import java.util.logging.Level;
|
66 | 68 | import java.util.logging.Logger;
|
67 | 69 |
|
| 70 | +import static java.util.Optional.ofNullable; |
68 | 71 | import static org.openqa.selenium.docker.ContainerConfig.image;
|
69 | 72 | import static org.openqa.selenium.remote.Dialect.W3C;
|
70 | 73 | import static org.openqa.selenium.remote.http.Contents.string;
|
@@ -130,7 +133,11 @@ public Optional<ActiveSession> apply(CreateSessionRequest sessionRequest) {
|
130 | 133 | attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(),
|
131 | 134 | EventAttribute.setValue(this.getClass().getName()));
|
132 | 135 | LOG.info("Creating container, mapping container port 4444 to " + port);
|
133 |
| - Container container = docker.create(image(browserImage).map(Port.tcp(4444), Port.tcp(port))); |
| 136 | + Map<String, String> browserContainerEnvVars = getBrowserContainerEnvVars(sessionRequest.getCapabilities()); |
| 137 | + Container container = docker.create( |
| 138 | + image(browserImage) |
| 139 | + .env(browserContainerEnvVars) |
| 140 | + .map(Port.tcp(4444), Port.tcp(port))); |
134 | 141 | container.start();
|
135 | 142 | ContainerInfo containerInfo = container.inspect();
|
136 | 143 |
|
@@ -188,9 +195,10 @@ public Optional<ActiveSession> apply(CreateSessionRequest sessionRequest) {
|
188 | 195 | Capabilities capabilities = new ImmutableCapabilities((Map<?, ?>) response.getValue());
|
189 | 196 | Container videoContainer = null;
|
190 | 197 | if (isVideoRecordingAvailable && recordVideoForSession(sessionRequest.getCapabilities())) {
|
191 |
| - Map<String, String> envVars = ImmutableMap.of( |
192 |
| - "DISPLAY_CONTAINER_NAME", containerInfo.getIp(), |
193 |
| - "FILE_NAME", String.format("%s.mp4", id)); |
| 198 | + Map<String, String> envVars = getVideoContainerEnvVars( |
| 199 | + sessionRequest.getCapabilities(), |
| 200 | + containerInfo.getIp(), |
| 201 | + id.toString()); |
194 | 202 | Map<String, String> volumeBinds = Collections.singletonMap(storagePath, "/videos");
|
195 | 203 | videoContainer = docker.create(image(videoImage).env(envVars).bind(volumeBinds));
|
196 | 204 | videoContainer.start();
|
@@ -223,13 +231,81 @@ public Optional<ActiveSession> apply(CreateSessionRequest sessionRequest) {
|
223 | 231 | }
|
224 | 232 | }
|
225 | 233 |
|
226 |
| - private boolean recordVideoForSession(Capabilities sessionRequestCapabilities) { |
227 |
| - Object rawSeleniumOptions = sessionRequestCapabilities.getCapability("se:options"); |
228 |
| - if (rawSeleniumOptions instanceof Map) { |
229 |
| - @SuppressWarnings("unchecked") Map<String, Object> seleniumOptions = (Map<String, Object>) rawSeleniumOptions; |
230 |
| - return Boolean.parseBoolean(seleniumOptions.getOrDefault("recordVideo", false).toString()); |
| 234 | + private Map<String, String> getBrowserContainerEnvVars(Capabilities sessionRequestCapabilities) { |
| 235 | + Optional<Dimension> screenResolution = |
| 236 | + ofNullable(getScreenResolution(sessionRequestCapabilities)); |
| 237 | + Map<String, String> envVars = new HashMap<>(); |
| 238 | + if (screenResolution.isPresent()) { |
| 239 | + envVars.put("SCREEN_WIDTH", String.valueOf(screenResolution.get().getWidth())); |
| 240 | + envVars.put("SCREEN_HEIGHT", String.valueOf(screenResolution.get().getHeight())); |
| 241 | + } |
| 242 | + Optional<TimeZone> timeZone = ofNullable(getTimeZone(sessionRequestCapabilities)); |
| 243 | + timeZone.ifPresent(zone -> envVars.put("TZ", zone.getID())); |
| 244 | + return envVars; |
| 245 | + } |
| 246 | + |
| 247 | + private Map<String, String> getVideoContainerEnvVars(Capabilities sessionRequestCapabilities, |
| 248 | + String containerIp, String fileName) { |
| 249 | + Map<String, String> envVars = new HashMap<>(); |
| 250 | + envVars.put("DISPLAY_CONTAINER_NAME", containerIp); |
| 251 | + envVars.put("FILE_NAME", String.format("%s.mp4", fileName)); |
| 252 | + Optional<Dimension> screenResolution = |
| 253 | + ofNullable(getScreenResolution(sessionRequestCapabilities)); |
| 254 | + screenResolution.ifPresent(dimension -> envVars |
| 255 | + .put("VIDEO_SIZE", String.format("%sx%s", dimension.getWidth(), dimension.getHeight()))); |
| 256 | + return envVars; |
| 257 | + } |
| 258 | + |
| 259 | + private TimeZone getTimeZone(Capabilities sessionRequestCapabilities) { |
| 260 | + Optional<Object> timeZone = |
| 261 | + ofNullable(getCapability(sessionRequestCapabilities, "timeZone")); |
| 262 | + if (timeZone.isPresent()) { |
| 263 | + String tz = timeZone.get().toString(); |
| 264 | + if (Arrays.asList(TimeZone.getAvailableIDs()).contains(tz)) { |
| 265 | + return TimeZone.getTimeZone(tz); |
231 | 266 | }
|
232 |
| - return false; |
| 267 | + } |
| 268 | + return null; |
| 269 | + } |
| 270 | + |
| 271 | + private Dimension getScreenResolution(Capabilities sessionRequestCapabilities) { |
| 272 | + Optional<Object> screenResolution = |
| 273 | + ofNullable(getCapability(sessionRequestCapabilities, "screenResolution")); |
| 274 | + if (screenResolution.isEmpty()) { |
| 275 | + return null; |
| 276 | + } |
| 277 | + try { |
| 278 | + String[] resolution = screenResolution.get().toString().split("x"); |
| 279 | + int screenWidth = Integer.parseInt(resolution[0]); |
| 280 | + int screenHeight = Integer.parseInt(resolution[1]); |
| 281 | + if (screenWidth > 0 && screenHeight > 0) { |
| 282 | + return new Dimension(screenWidth, screenHeight); |
| 283 | + } else { |
| 284 | + LOG.warning("One of the values provided for screenResolution is negative, " + |
| 285 | + "defaults will be used. Received value: " + screenResolution); |
| 286 | + } |
| 287 | + } catch (Exception e) { |
| 288 | + LOG.warning("Values provided for screenResolution are not valid integers or " + |
| 289 | + "either width or height are missing, defaults will be used." + |
| 290 | + "Received value: " + screenResolution); |
| 291 | + } |
| 292 | + return null; |
| 293 | + } |
| 294 | + |
| 295 | + private boolean recordVideoForSession(Capabilities sessionRequestCapabilities) { |
| 296 | + Optional<Object> recordVideo = |
| 297 | + ofNullable(getCapability(sessionRequestCapabilities, "recordVideo")); |
| 298 | + return recordVideo.isPresent() && Boolean.parseBoolean(recordVideo.get().toString()); |
| 299 | + } |
| 300 | + |
| 301 | + private Object getCapability(Capabilities sessionRequestCapabilities, String capabilityName) { |
| 302 | + Object rawSeleniumOptions = sessionRequestCapabilities.getCapability("se:options"); |
| 303 | + if (rawSeleniumOptions instanceof Map) { |
| 304 | + @SuppressWarnings("unchecked") |
| 305 | + Map<String, Object> seleniumOptions = (Map<String, Object>) rawSeleniumOptions; |
| 306 | + return seleniumOptions.get(capabilityName); |
| 307 | + } |
| 308 | + return null; |
233 | 309 | }
|
234 | 310 |
|
235 | 311 | private void waitForServerToStart(HttpClient client, Duration duration) {
|
|
0 commit comments