Best Selenium code snippet using org.openqa.selenium.grid.node.docker.DockerAssetsPath
Source:SauceNode.java
...51import org.openqa.selenium.grid.node.HealthCheck;52import org.openqa.selenium.grid.node.Node;53import org.openqa.selenium.grid.node.SessionFactory;54import org.openqa.selenium.grid.node.config.NodeOptions;55import org.openqa.selenium.grid.node.docker.DockerAssetsPath;56import org.openqa.selenium.grid.node.local.LocalNode;57import org.openqa.selenium.grid.node.local.SessionSlot;58import org.openqa.selenium.grid.security.Secret;59import org.openqa.selenium.internal.Debug;60import org.openqa.selenium.internal.Either;61import org.openqa.selenium.internal.Require;62import org.openqa.selenium.io.TemporaryFilesystem;63import org.openqa.selenium.io.Zip;64import org.openqa.selenium.json.Json;65import org.openqa.selenium.remote.SessionId;66import org.openqa.selenium.remote.http.HttpMethod;67import org.openqa.selenium.remote.http.HttpRequest;68import org.openqa.selenium.remote.http.HttpResponse;69import org.openqa.selenium.remote.tracing.AttributeKey;70import org.openqa.selenium.remote.tracing.EventAttribute;71import org.openqa.selenium.remote.tracing.EventAttributeValue;72import org.openqa.selenium.remote.tracing.Span;73import org.openqa.selenium.remote.tracing.Status;74import org.openqa.selenium.remote.tracing.Tracer;75import java.io.File;76import java.io.IOException;77import java.io.InputStreamReader;78import java.io.UncheckedIOException;79import java.net.URI;80import java.net.URISyntaxException;81import java.nio.file.Files;82import java.nio.file.Paths;83import java.nio.file.StandardCopyOption;84import java.time.Duration;85import java.time.Instant;86import java.util.Collections;87import java.util.HashMap;88import java.util.List;89import java.util.Map;90import java.util.Optional;91import java.util.Set;92import java.util.UUID;93import java.util.concurrent.ExecutionException;94import java.util.concurrent.atomic.AtomicInteger;95import java.util.logging.Level;96import java.util.logging.Logger;97import java.util.stream.Collectors;98@ManagedService(objectName = "com.saucelabs.grid:type=Node,name=SauceNode",99 description = "SauceNode running the webdriver sessions and uploading results to Sauce.")100public class SauceNode extends Node {101 private static final Logger LOG = Logger.getLogger(LocalNode.class.getName());102 private final EventBus bus;103 private final URI externalUri;104 private final URI gridUri;105 private final Duration heartbeatPeriod;106 private final HealthCheck healthCheck;107 private final int maxSessionCount;108 private final List<SessionSlot> factories;109 private final Cache<SessionId, SessionSlot> currentSessions;110 private final Cache<SessionId, TemporaryFilesystem> tempFileSystems;111 private final AtomicInteger pendingSessions = new AtomicInteger();112 private SauceNode(113 Tracer tracer,114 EventBus bus,115 URI uri,116 URI gridUri,117 HealthCheck healthCheck,118 int maxSessionCount,119 Ticker ticker,120 Duration sessionTimeout,121 Duration heartbeatPeriod,122 List<SessionSlot> factories,123 Secret registrationSecret) {124 super(tracer, new NodeId(UUID.randomUUID()), uri, registrationSecret);125 this.bus = Require.nonNull("Event bus", bus);126 this.externalUri = Require.nonNull("Remote node URI", uri);127 this.gridUri = Require.nonNull("Grid URI", gridUri);128 this.maxSessionCount = Math.min(Require.positive("Max session count", maxSessionCount), factories.size());129 this.heartbeatPeriod = heartbeatPeriod;130 this.factories = ImmutableList.copyOf(factories);131 Require.nonNull("Registration secret", registrationSecret);132 this.healthCheck = healthCheck == null ?133 () -> new HealthCheck.Result(134 isDraining() ? DRAINING : UP,135 String.format("%s is %s", uri, isDraining() ? "draining" : "up")) :136 healthCheck;137 this.currentSessions = CacheBuilder.newBuilder()138 .expireAfterAccess(sessionTimeout)139 .ticker(ticker)140 .removalListener((RemovalListener<SessionId, SessionSlot>) notification -> {141 // Attempt to stop the session142 LOG.log(Debug.getDebugLogLevel(), "Stopping session {0}", notification.getKey().toString());143 SessionSlot slot = notification.getValue();144 if (!slot.isAvailable()) {145 slot.stop();146 }147 })148 .build();149 this.tempFileSystems = CacheBuilder.newBuilder()150 .expireAfterAccess(sessionTimeout)151 .ticker(ticker)152 .removalListener((RemovalListener<SessionId, TemporaryFilesystem>) notification -> {153 TemporaryFilesystem tempFS = notification.getValue();154 tempFS.deleteTemporaryFiles();155 tempFS.deleteBaseDir();156 })157 .build();158 Regularly sessionCleanup = new Regularly("Session Cleanup Node: " + externalUri);159 sessionCleanup.submit(currentSessions::cleanUp, Duration.ofSeconds(30), Duration.ofSeconds(30));160 Regularly tmpFileCleanup = new Regularly("TempFile Cleanup Node: " + externalUri);161 tmpFileCleanup.submit(tempFileSystems::cleanUp, Duration.ofSeconds(30), Duration.ofSeconds(30));162 Regularly regularHeartBeat = new Regularly("Heartbeat Node: " + externalUri);163 regularHeartBeat.submit(() -> bus.fire(new NodeHeartBeatEvent(getStatus())), heartbeatPeriod,164 heartbeatPeriod);165 bus.addListener(SessionClosedEvent.listener(id -> {166 // Listen to session terminated events so we know when to fire the NodeDrainComplete event167 if (this.isDraining()) {168 int done = pendingSessions.decrementAndGet();169 if (done <= 0) {170 LOG.info("Firing node drain complete message");171 bus.fire(new NodeDrainComplete(this.getId()));172 }173 }174 }));175 Runtime.getRuntime().addShutdownHook(new Thread(this::stopAllSessions));176 new JMXHelper().register(this);177 }178 public static SauceNode.Builder builder(179 Tracer tracer,180 EventBus bus,181 URI uri,182 URI gridUri,183 Secret registrationSecret) {184 return new SauceNode.Builder(tracer, bus, uri, gridUri, registrationSecret);185 }186 @Override187 public boolean isReady() {188 return bus.isReady();189 }190 @VisibleForTesting191 public int getCurrentSessionCount() {192 // It seems wildly unlikely we'll overflow an int193 return Math.toIntExact(currentSessions.size());194 }195 @ManagedAttribute(name = "MaxSessions")196 public int getMaxSessionCount() {197 return maxSessionCount;198 }199 @ManagedAttribute(name = "Status")200 public Availability getAvailability() {201 return isDraining() ? DRAINING : UP;202 }203 @ManagedAttribute(name = "TotalSlots")204 public int getTotalSlots() {205 return factories.size();206 }207 @ManagedAttribute(name = "UsedSlots")208 public long getUsedSlots() {209 return factories.stream().filter(sessionSlot -> !sessionSlot.isAvailable()).count();210 }211 @ManagedAttribute(name = "Load")212 public float getLoad() {213 long inUse = factories.stream().filter(sessionSlot -> !sessionSlot.isAvailable()).count();214 return inUse / (float) maxSessionCount * 100f;215 }216 @ManagedAttribute(name = "RemoteNodeUri")217 public URI getExternalUri() {218 return this.getUri();219 }220 @ManagedAttribute(name = "GridUri")221 public URI getGridUri() {222 return this.gridUri;223 }224 @ManagedAttribute(name = "NodeId")225 public String getNodeId() {226 return getId().toString();227 }228 @Override229 public boolean isSupporting(Capabilities capabilities) {230 return factories.parallelStream().anyMatch(factory -> factory.test(capabilities));231 }232 @Override233 public Either<WebDriverException, CreateSessionResponse> newSession(CreateSessionRequest sessionRequest) {234 Require.nonNull("Session request", sessionRequest);235 try (Span span = tracer.getCurrentContext().createSpan("node.new_session")) {236 Map<String, EventAttributeValue> attributeMap = new HashMap<>();237 attributeMap238 .put(AttributeKey.LOGGER_CLASS.getKey(), EventAttribute.setValue(getClass().getName()));239 LOG.fine("Creating new session using span: " + span);240 attributeMap.put("session.request.capabilities",241 EventAttribute.setValue(sessionRequest.getDesiredCapabilities().toString()));242 attributeMap.put("session.request.downstreamdialect",243 EventAttribute.setValue(sessionRequest.getDownstreamDialects().toString()));244 int currentSessionCount = getCurrentSessionCount();245 span.setAttribute("current.session.count", currentSessionCount);246 attributeMap.put("current.session.count", EventAttribute.setValue(currentSessionCount));247 if (getCurrentSessionCount() >= maxSessionCount) {248 span.setAttribute("error", true);249 span.setStatus(Status.RESOURCE_EXHAUSTED);250 attributeMap.put("max.session.count", EventAttribute.setValue(maxSessionCount));251 span.addEvent("Max session count reached", attributeMap);252 return Either.left(new RetrySessionRequestException("Max session count reached."));253 }254 if (isDraining()) {255 span.setStatus(Status.UNAVAILABLE.withDescription("The node is draining. Cannot accept new sessions."));256 return Either.left(257 new RetrySessionRequestException("The node is draining. Cannot accept new sessions."));258 }259 // Identify possible slots to use as quickly as possible to enable concurrent session starting260 SessionSlot slotToUse = null;261 synchronized(factories) {262 for (SessionSlot factory : factories) {263 if (!factory.isAvailable() || !factory.test(sessionRequest.getDesiredCapabilities())) {264 continue;265 }266 factory.reserve();267 slotToUse = factory;268 break;269 }270 }271 if (slotToUse == null) {272 span.setAttribute("error", true);273 span.setStatus(Status.NOT_FOUND);274 span.addEvent("No slot matched capabilities ", attributeMap);275 return Either.left(276 new RetrySessionRequestException("No slot matched the requested capabilities."));277 }278 Either<WebDriverException, ActiveSession> possibleSession = slotToUse.apply(sessionRequest);279 if (possibleSession.isRight()) {280 ActiveSession session = possibleSession.right();281 currentSessions.put(session.getId(), slotToUse);282 SessionId sessionId = session.getId();283 Capabilities caps = session.getCapabilities();284 SESSION_ID.accept(span, sessionId);285 CAPABILITIES.accept(span, caps);286 String downstream = session.getDownstreamDialect().toString();287 String upstream = session.getUpstreamDialect().toString();288 String sessionUri = session.getUri().toString();289 span.setAttribute(AttributeKey.DOWNSTREAM_DIALECT.getKey(), downstream);290 span.setAttribute(AttributeKey.UPSTREAM_DIALECT.getKey(), upstream);291 span.setAttribute(AttributeKey.SESSION_URI.getKey(), sessionUri);292 // The session we return has to look like it came from the node, since we might be dealing293 // with a webdriver implementation that only accepts connections from localhost294 boolean isSupportingCdp = slotToUse.isSupportingCdp() ||295 caps.getCapability("se:cdp") != null;296 Session externalSession = createExternalSession(session, externalUri, isSupportingCdp);297 return Either.right(new CreateSessionResponse(298 externalSession,299 getEncoder(session.getDownstreamDialect()).apply(externalSession)));300 } else {301 slotToUse.release();302 span.setAttribute("error", true);303 span.addEvent("Unable to create session with the driver", attributeMap);304 return Either.left(possibleSession.left());305 }306 }307 }308 @Override309 public boolean isSessionOwner(SessionId id) {310 Require.nonNull("Session ID", id);311 return currentSessions.getIfPresent(id) != null;312 }313 @Override314 public Session getSession(SessionId id) throws NoSuchSessionException {315 Require.nonNull("Session ID", id);316 SessionSlot slot = currentSessions.getIfPresent(id);317 if (slot == null) {318 throw new NoSuchSessionException("Cannot find session with id: " + id);319 }320 return createExternalSession(slot.getSession(), externalUri, slot.isSupportingCdp());321 }322 @Override323 public TemporaryFilesystem getTemporaryFilesystem(SessionId id) throws IOException {324 try {325 return tempFileSystems.get(id, () -> TemporaryFilesystem.getTmpFsBasedOn(326 TemporaryFilesystem.getDefaultTmpFS().createTempDir("session", id.toString())));327 } catch (ExecutionException e) {328 throw new IOException(e);329 }330 }331 @Override332 public HttpResponse executeWebDriverCommand(HttpRequest req) {333 // True enough to be good enough334 SessionId id = getSessionId(req.getUri()).map(SessionId::new)335 .orElseThrow(() -> new NoSuchSessionException("Cannot find session: " + req));336 SessionSlot slot = currentSessions.getIfPresent(id);337 if (slot == null) {338 throw new NoSuchSessionException("Cannot find session with id: " + id);339 }340 ActiveSession activeSession = slot.getSession();341 if (activeSession.getClass().getName().contains("RelaySessionFactory")) {342 HttpResponse toReturn = slot.execute(req);343 if (req.getMethod() == DELETE && req.getUri().equals("/session/" + id)) {344 stop(id);345 }346 return toReturn;347 }348 SauceDockerSession session = (SauceDockerSession) activeSession;349 SauceCommandInfo.Builder builder = new SauceCommandInfo.Builder();350 builder.setStartTime(Instant.now().toEpochMilli());351 HttpResponse toReturn = slot.execute(req);352 if (req.getMethod() == DELETE && req.getUri().equals("/session/" + id)) {353 stop(id);354 builder.setScreenshotId(-1);355 } else {356 // Only taking screenshots after a url has been loaded357 if (!session.canTakeScreenshot() && req.getMethod() == POST358 && req.getUri().endsWith("/url")) {359 session.enableScreenshots();360 }361 int screenshotId = takeScreenshot(session, req, slot);362 builder.setScreenshotId(screenshotId);363 }364 Map<String, Object> parsedResponse =365 JSON.toType(new InputStreamReader(toReturn.getContent().get()), MAP_TYPE);366 builder.setRequest(getRequestContents(req))367 .setResult(parsedResponse)368 .setPath(req.getUri().replace(String.format("/session/%s", id), ""))369 .setHttpStatus(toReturn.getStatus())370 .setHttpMethod(req.getMethod().name())371 .setStatusCode(0);372 if (parsedResponse.containsKey("value") && parsedResponse.get("value") != null373 && parsedResponse.get("value").toString().contains("error")) {374 builder.setStatusCode(1);375 }376 builder.setEndTime(Instant.now().toEpochMilli());377 session.addSauceCommandInfo(builder.build());378 return toReturn;379 }380 @Override381 public HttpResponse uploadFile(HttpRequest req, SessionId id) {382 // When the session is running in a Docker container, the upload file command383 // needs to be forwarded to the container as well.384 SessionSlot slot = currentSessions.getIfPresent(id);385 if (slot != null && slot.getSession() instanceof SauceDockerSession) {386 return executeWebDriverCommand(req);387 }388 Map<String, Object> incoming = JSON.toType(string(req), Json.MAP_TYPE);389 File tempDir;390 try {391 TemporaryFilesystem tempfs = getTemporaryFilesystem(id);392 tempDir = tempfs.createTempDir("upload", "file");393 Zip.unzip((String) incoming.get("file"), tempDir);394 } catch (IOException e) {395 throw new UncheckedIOException(e);396 }397 // Select the first file398 File[] allFiles = tempDir.listFiles();399 if (allFiles == null) {400 throw new WebDriverException(401 String.format("Cannot access temporary directory for uploaded files %s", tempDir));402 }403 if (allFiles.length != 1) {404 throw new WebDriverException(405 String.format("Expected there to be only 1 file. There were: %s", allFiles.length));406 }407 ImmutableMap<String, Object> result = ImmutableMap.of(408 "value", allFiles[0].getAbsolutePath());409 return new HttpResponse().setContent(asJson(result));410 }411 @Override412 public void stop(SessionId id) throws NoSuchSessionException {413 Require.nonNull("Session ID", id);414 SessionSlot slot = currentSessions.getIfPresent(id);415 if (slot == null) {416 throw new NoSuchSessionException("Cannot find session with id: " + id);417 }418 currentSessions.invalidate(id);419 tempFileSystems.invalidate(id);420 }421 private void stopAllSessions() {422 if (currentSessions.size() > 0) {423 LOG.info("Trying to stop all running sessions before shutting down...");424 currentSessions.invalidateAll();425 }426 }427 private Session createExternalSession(ActiveSession other, URI externalUri, boolean isSupportingCdp) {428 Capabilities toUse = ImmutableCapabilities.copyOf(other.getCapabilities());429 // Rewrite the se:options if necessary to send the cdp url back430 if (isSupportingCdp) {431 String cdpPath = String.format("/session/%s/se/cdp", other.getId());432 toUse = new PersistentCapabilities(toUse).setCapability("se:cdp", rewrite(cdpPath));433 }434 return new Session(other.getId(), externalUri, other.getStereotype(), toUse, Instant.now());435 }436 private URI rewrite(String path) {437 try {438 String scheme = "https".equals(gridUri.getScheme()) ? "wss" : "ws";439 return new URI(440 scheme,441 gridUri.getUserInfo(),442 gridUri.getHost(),443 gridUri.getPort(),444 path,445 null,446 null);447 } catch (URISyntaxException e) {448 throw new RuntimeException(e);449 }450 }451 @Override452 public NodeStatus getStatus() {453 Set<Slot> slots = factories.stream()454 .map(slot -> {455 Instant lastStarted = Instant.EPOCH;456 Session session = null;457 if (!slot.isAvailable()) {458 ActiveSession activeSession = slot.getSession();459 if (activeSession != null) {460 lastStarted = activeSession.getStartTime();461 session = new Session(462 activeSession.getId(),463 activeSession.getUri(),464 slot.getStereotype(),465 activeSession.getCapabilities(),466 activeSession.getStartTime());467 }468 }469 return new Slot(470 new SlotId(getId(), slot.getId()),471 slot.getStereotype(),472 lastStarted,473 session);474 })475 .collect(toImmutableSet());476 return new NodeStatus(477 getId(),478 externalUri,479 maxSessionCount,480 slots,481 isDraining() ? DRAINING : UP,482 heartbeatPeriod,483 getNodeVersion(),484 getOsInfo());485 }486 @Override487 public HealthCheck getHealthCheck() {488 return healthCheck;489 }490 @Override491 public void drain() {492 bus.fire(new NodeDrainStarted(getId()));493 draining = true;494 int currentSessionCount = getCurrentSessionCount();495 if (currentSessionCount == 0) {496 LOG.info("Firing node drain complete message");497 bus.fire(new NodeDrainComplete(getId()));498 } else {499 pendingSessions.set(currentSessionCount);500 }501 }502 private Map<String, Object> toJson() {503 return ImmutableMap.of(504 "id", getId(),505 "uri", externalUri,506 "maxSessions", maxSessionCount,507 "draining", isDraining(),508 "capabilities", factories.stream()509 .map(SessionSlot::getStereotype)510 .collect(Collectors.toSet()));511 }512 public static class Builder {513 private final Tracer tracer;514 private final EventBus bus;515 private final URI uri;516 private final URI gridUri;517 private final Secret registrationSecret;518 private final ImmutableList.Builder<SessionSlot> factories;519 private int maxCount = Runtime.getRuntime().availableProcessors() * 5;520 private Ticker ticker = Ticker.systemTicker();521 private Duration sessionTimeout = Duration.ofMinutes(5);522 private HealthCheck healthCheck;523 private Duration heartbeatPeriod = Duration.ofSeconds(NodeOptions.DEFAULT_HEARTBEAT_PERIOD);524 private Builder(525 Tracer tracer,526 EventBus bus,527 URI uri,528 URI gridUri,529 Secret registrationSecret) {530 this.tracer = Require.nonNull("Tracer", tracer);531 this.bus = Require.nonNull("Event bus", bus);532 this.uri = Require.nonNull("Remote node URI", uri);533 this.gridUri = Require.nonNull("Grid URI", gridUri);534 this.registrationSecret = Require.nonNull("Registration secret", registrationSecret);535 this.factories = ImmutableList.builder();536 }537 public SauceNode.Builder add(Capabilities stereotype, SessionFactory factory) {538 Require.nonNull("Capabilities", stereotype);539 Require.nonNull("Session factory", factory);540 factories.add(new SessionSlot(bus, stereotype, factory));541 return this;542 }543 public SauceNode.Builder maximumConcurrentSessions(int maxCount) {544 this.maxCount = Require.positive("Max session count", maxCount);545 return this;546 }547 public SauceNode.Builder sessionTimeout(Duration timeout) {548 sessionTimeout = timeout;549 return this;550 }551 public SauceNode.Builder heartbeatPeriod(Duration heartbeatPeriod) {552 this.heartbeatPeriod = heartbeatPeriod;553 return this;554 }555 public SauceNode build() {556 return new SauceNode(557 tracer,558 bus,559 uri,560 gridUri,561 healthCheck,562 maxCount,563 ticker,564 sessionTimeout,565 heartbeatPeriod,566 factories.build(),567 registrationSecret);568 }569 }570 private Object getRequestContents(HttpRequest httpRequest) {571 String reqContents = string(httpRequest);572 if (reqContents.isEmpty()) {573 return Collections.emptyMap();574 }575 return JSON.toType(reqContents, MAP_TYPE);576 }577 private int takeScreenshot(SauceDockerSession session, HttpRequest req, SessionSlot slot) {578 Optional<DockerAssetsPath> path = ofNullable(session.getAssetsPath());579 if (session.canTakeScreenshot() && shouldTakeScreenshot(req.getMethod(), req.getUri())580 && path.isPresent()) {581 HttpRequest screenshotRequest =582 new HttpRequest(GET, String.format("/session/%s/screenshot", session.getId()));583 HttpResponse screenshotResponse = slot.execute(screenshotRequest);584 int screenshotId = session.increaseScreenshotCount();585 String containerPath = path.get().getContainerPath(session.getId());586 String filePathPng = String.format(587 "%s/%s%s.png",588 containerPath,589 formatScreenshotId(screenshotId),590 "screenshot");591 String screenshotContent = string(screenshotResponse).trim();592 Map<String, Object> parsed = JSON.toType(screenshotContent, MAP_TYPE);...
Source:SauceDockerSessionFactory.java
...27import org.openqa.selenium.docker.Port;28import org.openqa.selenium.grid.data.CreateSessionRequest;29import org.openqa.selenium.grid.node.ActiveSession;30import org.openqa.selenium.grid.node.SessionFactory;31import org.openqa.selenium.grid.node.docker.DockerAssetsPath;32import org.openqa.selenium.internal.Either;33import org.openqa.selenium.internal.Require;34import org.openqa.selenium.net.PortProber;35import org.openqa.selenium.remote.Command;36import org.openqa.selenium.remote.Dialect;37import org.openqa.selenium.remote.DriverCommand;38import org.openqa.selenium.remote.ProtocolHandshake;39import org.openqa.selenium.remote.Response;40import org.openqa.selenium.remote.SessionId;41import org.openqa.selenium.remote.http.HttpClient;42import org.openqa.selenium.remote.http.HttpRequest;43import org.openqa.selenium.remote.http.HttpResponse;44import org.openqa.selenium.remote.tracing.AttributeKey;45import org.openqa.selenium.remote.tracing.EventAttribute;46import org.openqa.selenium.remote.tracing.EventAttributeValue;47import org.openqa.selenium.remote.tracing.Span;48import org.openqa.selenium.remote.tracing.Status;49import org.openqa.selenium.remote.tracing.Tracer;50import org.openqa.selenium.support.ui.FluentWait;51import org.openqa.selenium.support.ui.Wait;52import java.io.IOException;53import java.io.UncheckedIOException;54import java.net.MalformedURLException;55import java.net.URI;56import java.net.URL;57import java.nio.charset.Charset;58import java.nio.file.Files;59import java.nio.file.Paths;60import java.time.Duration;61import java.time.Instant;62import java.util.Arrays;63import java.util.Collections;64import java.util.HashMap;65import java.util.Map;66import java.util.Objects;67import java.util.Optional;68import java.util.TimeZone;69import java.util.TreeMap;70import java.util.logging.Level;71import java.util.logging.Logger;72public class SauceDockerSessionFactory implements SessionFactory {73 private static final Logger LOG = Logger.getLogger(SauceDockerSessionFactory.class.getName());74 private final Tracer tracer;75 private final HttpClient.Factory clientFactory;76 private final Docker docker;77 private final URI dockerUri;78 private final Image browserImage;79 private final Capabilities stereotype;80 private final Image videoImage;81 private final Image assetsUploaderImage;82 private final DockerAssetsPath assetsPath;83 private final String networkName;84 private final boolean runningInDocker;85 public SauceDockerSessionFactory(86 Tracer tracer,87 HttpClient.Factory clientFactory,88 Docker docker,89 URI dockerUri,90 Image browserImage,91 Capabilities stereotype,92 Image videoImage,93 Image assetsUploaderImage,94 DockerAssetsPath assetsPath,95 String networkName,96 boolean runningInDocker) {97 this.tracer = Require.nonNull("Tracer", tracer);98 this.clientFactory = Require.nonNull("HTTP client", clientFactory);99 this.docker = Require.nonNull("Docker command", docker);100 this.dockerUri = Require.nonNull("Docker URI", dockerUri);101 this.browserImage = Require.nonNull("Docker browser image", browserImage);102 this.networkName = Require.nonNull("Docker network name", networkName);103 this.stereotype = copyOf(Require.nonNull("Stereotype", stereotype));104 this.videoImage = videoImage;105 this.assetsUploaderImage = assetsUploaderImage;106 this.assetsPath = assetsPath;107 this.runningInDocker = runningInDocker;108 }109 @Override110 public boolean test(Capabilities capabilities) {111 return stereotype.getCapabilityNames().stream()112 .map(113 name ->114 Objects.equals(stereotype.getCapability(name), capabilities.getCapability(name)))115 .reduce(Boolean::logicalAnd)116 .orElse(false);117 }118 @Override119 public Either<WebDriverException, ActiveSession> apply(CreateSessionRequest sessionRequest) {120 Optional<Object> accessKey =121 getSauceCapability(sessionRequest.getDesiredCapabilities(), "accessKey");122 Optional<Object> userName =123 getSauceCapability(sessionRequest.getDesiredCapabilities(), "username");124 if (!accessKey.isPresent() && !userName.isPresent()) {125 String message = String.format("Unable to create session. No Sauce Labs accessKey and "126 + "username were found in the '%s' block.", SAUCE_OPTIONS);127 LOG.log(Level.WARNING, message);128 return Either.left(new SessionNotCreatedException(message));129 }130 @SuppressWarnings("OptionalGetWithoutIsPresent")131 UsernameAndPassword usernameAndPassword =132 new UsernameAndPassword(userName.get().toString(), accessKey.get().toString());133 Optional<Object> dc =134 getSauceCapability(sessionRequest.getDesiredCapabilities(), "dataCenter");135 DataCenter dataCenter = DataCenter.US_WEST;136 if (dc.isPresent()) {137 dataCenter = DataCenter.fromString(String.valueOf(dc.get()));138 }139 Capabilities sessionReqCaps = removeSauceKey(sessionRequest.getDesiredCapabilities());140 LOG.info("Starting session for " + sessionReqCaps);141 int port = runningInDocker ? 4444 : PortProber.findFreePort();142 try (Span span = tracer.getCurrentContext().createSpan("docker_session_factory.apply")) {143 Map<String, EventAttributeValue> attributeMap = new HashMap<>();144 attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(),145 EventAttribute.setValue(this.getClass().getName()));146 String logMessage = runningInDocker ? "Creating container..." :147 "Creating container, mapping container port 4444 to " + port;148 LOG.info(logMessage);149 Container container = createBrowserContainer(port, sessionReqCaps);150 container.start();151 ContainerInfo containerInfo = container.inspect();152 String containerIp = containerInfo.getIp();153 URL remoteAddress = getUrl(port, containerIp);154 HttpClient client = clientFactory.createClient(remoteAddress);155 attributeMap.put("docker.browser.image", EventAttribute.setValue(browserImage.toString()));156 attributeMap.put("container.port", EventAttribute.setValue(port));157 attributeMap.put("container.id", EventAttribute.setValue(container.getId().toString()));158 attributeMap.put("container.ip", EventAttribute.setValue(containerInfo.getIp()));159 attributeMap.put("docker.server.url", EventAttribute.setValue(remoteAddress.toString()));160 LOG.info(161 String.format("Waiting for server to start (container id: %s, url %s)",162 container.getId(),163 remoteAddress));164 try {165 waitForServerToStart(client, Duration.ofMinutes(1));166 } catch (TimeoutException e) {167 span.setAttribute("error", true);168 span.setStatus(Status.CANCELLED);169 EXCEPTION.accept(attributeMap, e);170 attributeMap.put(AttributeKey.EXCEPTION_MESSAGE.getKey(),171 EventAttribute.setValue(172 "Unable to connect to docker server. Stopping container: " +173 e.getMessage()));174 span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);175 container.stop(Duration.ofMinutes(1));176 String message = String.format(177 "Unable to connect to docker server (container id: %s)", container.getId());178 LOG.warning(message);179 return Either.left(new RetrySessionRequestException(message));180 }181 LOG.info(String.format("Server is ready (container id: %s)", container.getId()));182 Command command = new Command(183 null,184 DriverCommand.NEW_SESSION(sessionReqCaps));185 ProtocolHandshake.Result result;186 Response response;187 try {188 result = new ProtocolHandshake().createSession(client, command);189 response = result.createResponse();190 attributeMap.put(191 AttributeKey.DRIVER_RESPONSE.getKey(),192 EventAttribute.setValue(response.toString()));193 } catch (IOException | RuntimeException e) {194 span.setAttribute("error", true);195 span.setStatus(Status.CANCELLED);196 EXCEPTION.accept(attributeMap, e);197 attributeMap.put(198 AttributeKey.EXCEPTION_MESSAGE.getKey(),199 EventAttribute200 .setValue("Unable to create session. Stopping and container: " + e.getMessage()));201 span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);202 container.stop(Duration.ofMinutes(1));203 String message = "Unable to create session: " + e.getMessage();204 LOG.log(Level.WARNING, message);205 return Either.left(new SessionNotCreatedException(message));206 }207 SessionId id = new SessionId(response.getSessionId());208 Capabilities capabilities = new ImmutableCapabilities((Map<?, ?>) response.getValue());209 Capabilities mergedCapabilities = capabilities.merge(sessionReqCaps);210 Container videoContainer = null;211 Optional<DockerAssetsPath> path = ofNullable(this.assetsPath);212 if (path.isPresent()) {213 // Seems we can store session assets214 String containerPath = path.get().getContainerPath(id);215 saveSessionCapabilities(mergedCapabilities, containerPath);216 String hostPath = path.get().getHostPath(id);217 videoContainer = startVideoContainer(mergedCapabilities, containerInfo.getIp(), hostPath);218 }219 Instant startTime = Instant.now();220 Instant videoStartTime = Instant.now();221 Dialect downstream = sessionRequest.getDownstreamDialects().contains(result.getDialect()) ?222 result.getDialect() :223 W3C;224 attributeMap.put(225 AttributeKey.DOWNSTREAM_DIALECT.getKey(),...
Source:DockerSessionFactory.java
...87 private final URI dockerUri;88 private final Image browserImage;89 private final Capabilities stereotype;90 private final Image videoImage;91 private final DockerAssetsPath assetsPath;92 private final String networkName;93 private final boolean runningInDocker;94 private final SlotMatcher slotMatcher;95 public DockerSessionFactory(96 Tracer tracer,97 HttpClient.Factory clientFactory,98 Docker docker,99 URI dockerUri,100 Image browserImage,101 Capabilities stereotype,102 Image videoImage,103 DockerAssetsPath assetsPath,104 String networkName,105 boolean runningInDocker) {106 this.tracer = Require.nonNull("Tracer", tracer);107 this.clientFactory = Require.nonNull("HTTP client", clientFactory);108 this.docker = Require.nonNull("Docker command", docker);109 this.dockerUri = Require.nonNull("Docker URI", dockerUri);110 this.browserImage = Require.nonNull("Docker browser image", browserImage);111 this.networkName = Require.nonNull("Docker network name", networkName);112 this.stereotype = ImmutableCapabilities.copyOf(113 Require.nonNull("Stereotype", stereotype));114 this.videoImage = videoImage;115 this.assetsPath = assetsPath;116 this.runningInDocker = runningInDocker;117 this.slotMatcher = new DefaultSlotMatcher();118 }119 @Override120 public boolean test(Capabilities capabilities) {121 return slotMatcher.matches(stereotype, capabilities);122 }123 @Override124 public Either<WebDriverException, ActiveSession> apply(CreateSessionRequest sessionRequest) {125 LOG.info("Starting session for " + sessionRequest.getDesiredCapabilities());126 int port = runningInDocker ? 4444 : PortProber.findFreePort();127 try (Span span = tracer.getCurrentContext().createSpan("docker_session_factory.apply")) {128 Map<String, EventAttributeValue> attributeMap = new HashMap<>();129 attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(),130 EventAttribute.setValue(this.getClass().getName()));131 String logMessage = runningInDocker ? "Creating container..." :132 "Creating container, mapping container port 4444 to " + port;133 LOG.info(logMessage);134 Container container = createBrowserContainer(port, sessionRequest.getDesiredCapabilities());135 container.start();136 ContainerInfo containerInfo = container.inspect();137 String containerIp = containerInfo.getIp();138 URL remoteAddress = getUrl(port, containerIp);139 HttpClient client = clientFactory.createClient(remoteAddress);140 attributeMap.put("docker.browser.image", EventAttribute.setValue(browserImage.toString()));141 attributeMap.put("container.port", EventAttribute.setValue(port));142 attributeMap.put("container.id", EventAttribute.setValue(container.getId().toString()));143 attributeMap.put("container.ip", EventAttribute.setValue(containerIp));144 attributeMap.put("docker.server.url", EventAttribute.setValue(remoteAddress.toString()));145 LOG.info(146 String.format("Waiting for server to start (container id: %s, url %s)",147 container.getId(),148 remoteAddress));149 try {150 waitForServerToStart(client, Duration.ofMinutes(1));151 } catch (TimeoutException e) {152 span.setAttribute("error", true);153 span.setStatus(Status.CANCELLED);154 EXCEPTION.accept(attributeMap, e);155 attributeMap.put(AttributeKey.EXCEPTION_MESSAGE.getKey(),156 EventAttribute.setValue(157 "Unable to connect to docker server. Stopping container: " +158 e.getMessage()));159 span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);160 container.stop(Duration.ofMinutes(1));161 String message = String.format(162 "Unable to connect to docker server (container id: %s)", container.getId());163 LOG.warning(message);164 return Either.left(new RetrySessionRequestException(message));165 }166 LOG.info(String.format("Server is ready (container id: %s)", container.getId()));167 Command command = new Command(168 null,169 DriverCommand.NEW_SESSION(sessionRequest.getDesiredCapabilities()));170 ProtocolHandshake.Result result;171 Response response;172 try {173 result = new ProtocolHandshake().createSession(client, command);174 response = result.createResponse();175 attributeMap.put(AttributeKey.DRIVER_RESPONSE.getKey(),176 EventAttribute.setValue(response.toString()));177 } catch (IOException | RuntimeException e) {178 span.setAttribute("error", true);179 span.setStatus(Status.CANCELLED);180 EXCEPTION.accept(attributeMap, e);181 attributeMap.put(182 AttributeKey.EXCEPTION_MESSAGE.getKey(),183 EventAttribute184 .setValue("Unable to create session. Stopping and container: " + e.getMessage()));185 span.addEvent(AttributeKey.EXCEPTION_EVENT.getKey(), attributeMap);186 container.stop(Duration.ofMinutes(1));187 String message = "Unable to create session: " + e.getMessage();188 LOG.log(Level.WARNING, message, e);189 return Either.left(new SessionNotCreatedException(message));190 }191 SessionId id = new SessionId(response.getSessionId());192 Capabilities capabilities = new ImmutableCapabilities((Map<?, ?>) response.getValue());193 Capabilities mergedCapabilities = sessionRequest.getDesiredCapabilities().merge(capabilities);194 mergedCapabilities = addForwardCdpEndpoint(mergedCapabilities,195 containerIp,196 port,197 id.toString());198 Container videoContainer = null;199 Optional<DockerAssetsPath> path = ofNullable(this.assetsPath);200 if (path.isPresent()) {201 // Seems we can store session assets202 String containerPath = path.get().getContainerPath(id);203 saveSessionCapabilities(mergedCapabilities, containerPath);204 String hostPath = path.get().getHostPath(id);205 videoContainer = startVideoContainer(mergedCapabilities, containerIp, hostPath);206 }207 Dialect downstream = sessionRequest.getDownstreamDialects().contains(result.getDialect()) ?208 result.getDialect() :209 W3C;210 attributeMap.put(211 AttributeKey.DOWNSTREAM_DIALECT.getKey(),212 EventAttribute.setValue(downstream.toString()));213 attributeMap.put(...
Source:DockerOptions.java
...124 // to get the information from it.125 // Since Docker 1.12, the env var HOSTNAME has the container id (unless the user overwrites it)126 String hostname = HostIdentifier.getHostName();127 Optional<ContainerInfo> info = docker.inspect(new ContainerId(hostname));128 DockerAssetsPath assetsPath = getAssetsPath(info);129 String networkName = getDockerNetworkName(info);130 loadImages(docker, kinds.keySet().toArray(new String[0]));131 Image videoImage = getVideoImage(docker);132 loadImages(docker, videoImage.getName());133 // Hard coding the config section value "node" to avoid an extra dependency134 int maxContainerCount = Math.min(config.getInt("node", "max-sessions")135 .orElse(DEFAULT_MAX_SESSIONS), DEFAULT_MAX_SESSIONS);136 ImmutableMultimap.Builder<Capabilities, SessionFactory> factories = ImmutableMultimap.builder();137 kinds.forEach((name, caps) -> {138 Image image = docker.getImage(name);139 for (int i = 0; i < maxContainerCount; i++) {140 factories.put(141 caps,142 new DockerSessionFactory(143 tracer,144 clientFactory,145 docker,146 getDockerUri(),147 image,148 caps,149 videoImage,150 assetsPath,151 networkName,152 info.isPresent()));153 }154 LOG.info(String.format(155 "Mapping %s to docker image %s %d times",156 caps,157 name,158 maxContainerCount));159 });160 return factories.build().asMap();161 }162 private Image getVideoImage(Docker docker) {163 String videoImage = config.get(DOCKER_SECTION, "video-image").orElse(DEFAULT_VIDEO_IMAGE);164 return docker.getImage(videoImage);165 }166 @SuppressWarnings("OptionalUsedAsFieldOrParameterType")167 private String getDockerNetworkName(Optional<ContainerInfo> info) {168 if (info.isPresent()) {169 return info.get().getNetworkName();170 }171 return DEFAULT_DOCKER_NETWORK;172 }173 @SuppressWarnings("OptionalUsedAsFieldOrParameterType")174 private DockerAssetsPath getAssetsPath(Optional<ContainerInfo> info) {175 if (info.isPresent()) {176 Optional<Map<String, Object>> mountedVolume = info.get().getMountedVolumes()177 .stream()178 .filter(179 mounted ->180 DEFAULT_ASSETS_PATH.equalsIgnoreCase(String.valueOf(mounted.get("Destination"))))181 .findFirst();182 if (mountedVolume.isPresent()) {183 String hostPath = String.valueOf(mountedVolume.get().get("Source"));184 return new DockerAssetsPath(hostPath, DEFAULT_ASSETS_PATH);185 }186 }187 Optional<String> assetsPath = config.get(DOCKER_SECTION, "assets-path");188 // We assume the user is not running the Selenium Server inside a Docker container189 // Therefore, we have access to the assets path on the host190 return assetsPath.map(path -> new DockerAssetsPath(path, path)).orElse(null);191 }192 private void loadImages(Docker docker, String... imageNames) {193 CompletableFuture<Void> cd = CompletableFuture.allOf(194 Arrays.stream(imageNames)195 .map(name -> CompletableFuture.supplyAsync(() -> docker.getImage(name)))196 .toArray(CompletableFuture[]::new));197 try {198 cd.get();199 } catch (InterruptedException e) {200 Thread.currentThread().interrupt();201 throw new RuntimeException(e);202 } catch (ExecutionException e) {203 Throwable cause = e.getCause() != null ? e.getCause() : e;204 if (cause instanceof RuntimeException) {...
Source:SauceDockerSession.java
...12import org.openqa.selenium.docker.Container;13import org.openqa.selenium.docker.Docker;14import org.openqa.selenium.docker.Image;15import org.openqa.selenium.grid.node.ProtocolConvertingSession;16import org.openqa.selenium.grid.node.docker.DockerAssetsPath;17import org.openqa.selenium.internal.Require;18import org.openqa.selenium.remote.CapabilityType;19import org.openqa.selenium.remote.Dialect;20import org.openqa.selenium.remote.SessionId;21import org.openqa.selenium.remote.http.Contents;22import org.openqa.selenium.remote.http.HttpClient;23import org.openqa.selenium.remote.http.HttpMethod;24import org.openqa.selenium.remote.http.HttpRequest;25import org.openqa.selenium.remote.http.HttpResponse;26import org.openqa.selenium.remote.tracing.Tracer;27import java.net.URL;28import java.nio.file.Files;29import java.nio.file.Paths;30import java.time.Duration;31import java.time.Instant;32import java.util.ArrayList;33import java.util.Collections;34import java.util.HashMap;35import java.util.List;36import java.util.Map;37import java.util.concurrent.atomic.AtomicBoolean;38import java.util.concurrent.atomic.AtomicInteger;39import java.util.logging.Level;40import java.util.logging.Logger;41public class SauceDockerSession extends ProtocolConvertingSession {42 private static final Logger LOG = Logger.getLogger(SauceDockerSession.class.getName());43 private final Docker docker;44 private final Container container;45 private final Container videoContainer;46 private final AtomicInteger screenshotCount;47 private final AtomicBoolean screenshotsEnabled;48 private final DockerAssetsPath assetsPath;49 private final List<SauceCommandInfo> webDriverCommands;50 private final UsernameAndPassword usernameAndPassword;51 private final Image assetsUploaderImage;52 private final DataCenter dataCenter;53 private final AtomicBoolean tearDownTriggered;54 SauceDockerSession(55 Container container,56 Container videoContainer,57 Tracer tracer,58 HttpClient client,59 SessionId id,60 URL url,61 Capabilities stereotype,62 Capabilities capabilities,63 Dialect downstream,64 Dialect upstream,65 Instant startTime,66 DockerAssetsPath assetsPath,67 UsernameAndPassword usernameAndPassword,68 DataCenter dataCenter,69 Image assetsUploaderImage,70 SauceCommandInfo firstCommand,71 Docker docker) {72 super(tracer, client, id, url, downstream, upstream, stereotype, capabilities, startTime);73 this.container = Require.nonNull("Container", container);74 this.videoContainer = videoContainer;75 this.assetsPath = Require.nonNull("Assets path", assetsPath);76 this.screenshotCount = new AtomicInteger(0);77 this.screenshotsEnabled = new AtomicBoolean(false);78 this.usernameAndPassword = Require.nonNull("Sauce user & key", usernameAndPassword);79 this.webDriverCommands = new ArrayList<>();80 this.webDriverCommands.add(firstCommand);81 this.assetsUploaderImage = assetsUploaderImage;82 this.dataCenter = dataCenter;83 this.docker = Require.nonNull("Docker", docker);84 this.tearDownTriggered = new AtomicBoolean(false);85 }86 public int increaseScreenshotCount() {87 return screenshotCount.getAndIncrement();88 }89 public boolean canTakeScreenshot() {90 return screenshotsEnabled.get();91 }92 public void enableScreenshots() {93 screenshotsEnabled.set(true);94 }95 public void addSauceCommandInfo(SauceCommandInfo commandInfo) {96 if (!webDriverCommands.isEmpty()) {97 // Get when the last command ended to calculate times between commands98 SauceCommandInfo lastCommand = webDriverCommands.get(webDriverCommands.size() - 1);99 long betweenCommands = commandInfo.getStartTime() - lastCommand.getEndTime();100 commandInfo.setBetweenCommands(betweenCommands);101 commandInfo.setVideoStartTime(lastCommand.getVideoStartTime());102 }103 this.webDriverCommands.add(commandInfo);104 }105 public DockerAssetsPath getAssetsPath() {106 return assetsPath;107 }108 @Override109 public void stop() {110 new Thread(() -> {111 if (!tearDownTriggered.getAndSet(true)) {112 if (videoContainer != null) {113 videoContainer.stop(Duration.ofSeconds(10));114 }115 saveLogs();116 container.stop(Duration.ofMinutes(1));117 integrateWithSauce();118 }119 }).start();...
Source:SauceDockerOptions.java
...13import org.openqa.selenium.docker.Image;14import org.openqa.selenium.grid.config.Config;15import org.openqa.selenium.grid.config.ConfigException;16import org.openqa.selenium.grid.node.SessionFactory;17import org.openqa.selenium.grid.node.docker.DockerAssetsPath;18import org.openqa.selenium.internal.Require;19import org.openqa.selenium.net.HostIdentifier;20import org.openqa.selenium.remote.http.ClientConfig;21import org.openqa.selenium.remote.http.HttpClient;22import org.openqa.selenium.remote.tracing.Tracer;23import java.net.URI;24import java.net.URISyntaxException;25import java.util.Arrays;26import java.util.Collection;27import java.util.List;28import java.util.Map;29import java.util.Optional;30import java.util.concurrent.CompletableFuture;31import java.util.concurrent.ExecutionException;32import java.util.logging.Logger;33public class SauceDockerOptions {34 private static final String DOCKER_SECTION = "docker";35 private static final String DEFAULT_DOCKER_URL = "unix:/var/run/docker.sock";36 private static final String DEFAULT_VIDEO_IMAGE = "saucelabs/stg-video:latest";37 private static final String DEFAULT_ASSETS_PATH = "/opt/selenium/assets";38 private static final String DEFAULT_ASSETS_UPLOADER_IMAGE = "saucelabs/stg-assets-uploader:latest";39 private static final String DEFAULT_DOCKER_NETWORK = "bridge";40 private static final Logger LOG = Logger.getLogger(SauceDockerOptions.class.getName());41 private final Config config;42 public SauceDockerOptions(Config config) {43 this.config = Require.nonNull("Config", config);44 }45 private URI getDockerUri() {46 try {47 Optional<String> possibleUri = config.get(DOCKER_SECTION, "url");48 if (possibleUri.isPresent()) {49 return new URI(possibleUri.get());50 }51 Optional<String> possibleHost = config.get(DOCKER_SECTION, "host");52 Optional<Integer> possiblePort = config.getInt(DOCKER_SECTION, "port");53 if (possibleHost.isPresent() && possiblePort.isPresent()) {54 String host = possibleHost.get();55 int port = possiblePort.get();56 if (!(host.startsWith("tcp:") || host.startsWith("http:") || host.startsWith("https"))) {57 host = String.format("http://%s:%s", host, port);58 } else {59 host = String.format("%s:%s", host, port);60 }61 URI uri = new URI(host);62 return new URI(63 "http",64 uri.getUserInfo(),65 uri.getHost(),66 uri.getPort(),67 uri.getPath(),68 null,69 null);70 }71 // Default for the system we're running on.72 if (Platform.getCurrent().is(WINDOWS)) {73 return new URI("http://localhost:2376");74 }75 return new URI(DEFAULT_DOCKER_URL);76 } catch (URISyntaxException e) {77 throw new ConfigException("Unable to determine docker url", e);78 }79 }80 private boolean isEnabled(Docker docker) {81 if (!config.getAll(DOCKER_SECTION, "configs").isPresent()) {82 return false;83 }84 // Is the daemon up and running?85 return docker.isSupported();86 }87 public Map<Capabilities, Collection<SessionFactory>> getDockerSessionFactories(88 Tracer tracer,89 HttpClient.Factory clientFactory) {90 HttpClient client = clientFactory.createClient(ClientConfig.defaultConfig().baseUri(getDockerUri()));91 Docker docker = new Docker(client);92 if (!isEnabled(docker)) {93 throw new DockerException("Unable to reach the Docker daemon at " + getDockerUri());94 }95 List<String> allConfigs = config.getAll(DOCKER_SECTION, "configs")96 .orElseThrow(() -> new DockerException("Unable to find docker configs"));97 Multimap<String, Capabilities> kinds = HashMultimap.create();98 for (int i = 0; i < allConfigs.size(); i++) {99 String imageName = allConfigs.get(i);100 i++;101 if (i == allConfigs.size()) {102 throw new DockerException("Unable to find JSON config");103 }104 Capabilities stereotype = JSON.toType(allConfigs.get(i), Capabilities.class);105 kinds.put(imageName, stereotype);106 }107 // If Selenium Server is running inside a Docker container, we can inspect that container108 // to get the information from it.109 // Since Docker 1.12, the env var HOSTNAME has the container id (unless the user overwrites it)110 String hostname = HostIdentifier.getHostName();111 Optional<ContainerInfo> info = docker.inspect(new ContainerId(hostname));112 DockerAssetsPath assetsPath = getAssetsPath(info);113 String networkName = getDockerNetworkName(info);114 loadImages(docker, kinds.keySet().toArray(new String[0]));115 Image videoImage = getVideoImage(docker);116 loadImages(docker, videoImage.getName());117 Image assetsUploaderImage = getAssetsUploaderImage(docker);118 loadImages(docker, assetsUploaderImage.getName());119 int maxContainerCount = Runtime.getRuntime().availableProcessors();120 ImmutableMultimap.Builder<Capabilities, SessionFactory> factories = ImmutableMultimap.builder();121 kinds.forEach((name, caps) -> {122 Image image = docker.getImage(name);123 for (int i = 0; i < maxContainerCount; i++) {124 factories.put(125 caps,126 new SauceDockerSessionFactory(127 tracer,128 clientFactory,129 docker,130 getDockerUri(),131 image,132 caps,133 videoImage,134 assetsUploaderImage,135 assetsPath,136 networkName,137 info.isPresent()));138 }139 LOG.info(String.format(140 "Mapping %s to docker image %s %d times",141 caps,142 name,143 maxContainerCount));144 });145 return factories.build().asMap();146 }147 private Image getVideoImage(Docker docker) {148 String videoImage = config.get(DOCKER_SECTION, "video-image").orElse(DEFAULT_VIDEO_IMAGE);149 return docker.getImage(videoImage);150 }151 @SuppressWarnings("OptionalUsedAsFieldOrParameterType")152 private String getDockerNetworkName(Optional<ContainerInfo> info) {153 if (info.isPresent()) {154 return info.get().getNetworkName();155 }156 return DEFAULT_DOCKER_NETWORK;157 }158 private Image getAssetsUploaderImage(Docker docker) {159 String assetsUploadImage =160 config161 .get(DOCKER_SECTION, "assets-uploader-image")162 .orElse(DEFAULT_ASSETS_UPLOADER_IMAGE);163 return docker.getImage(assetsUploadImage);164 }165 @SuppressWarnings("OptionalUsedAsFieldOrParameterType")166 private DockerAssetsPath getAssetsPath(Optional<ContainerInfo> info) {167 if (info.isPresent()) {168 Optional<Map<String, Object>> mountedVolume = info.get().getMountedVolumes()169 .stream()170 .filter(171 mounted ->172 DEFAULT_ASSETS_PATH.equalsIgnoreCase(String.valueOf(mounted.get("Destination"))))173 .findFirst();174 if (mountedVolume.isPresent()) {175 String hostPath = String.valueOf(mountedVolume.get().get("Source"));176 return new DockerAssetsPath(hostPath, DEFAULT_ASSETS_PATH);177 }178 }179 Optional<String> assetsPath = config.get(DOCKER_SECTION, "assets-path");180 // We assume the user is not running the Selenium Server inside a Docker container181 // Therefore, we have access to the assets path on the host182 return assetsPath.map(path -> new DockerAssetsPath(path, path)).orElse(null);183 }184 private void loadImages(Docker docker, String... imageNames) {185 CompletableFuture<Void> cd = CompletableFuture.allOf(186 Arrays.stream(imageNames)187 .map(name -> CompletableFuture.supplyAsync(() -> docker.getImage(name)))188 .toArray(CompletableFuture[]::new));189 try {190 cd.get();191 } catch (InterruptedException e) {192 Thread.currentThread().interrupt();193 throw new RuntimeException(e);194 } catch (ExecutionException e) {195 Throwable cause = e.getCause() != null ? e.getCause() : e;196 if (cause instanceof RuntimeException) {...
Source:DockerAssetsPath.java
...16// under the License.17package org.openqa.selenium.grid.node.docker;18import org.openqa.selenium.remote.SessionId;19import java.io.File;20public class DockerAssetsPath {21 private final String hostPath;22 private final String containerPath;23 public DockerAssetsPath(String hostPath, String containerPath) {24 this.hostPath = hostPath;25 this.containerPath = containerPath;26 }27 public String getHostPath(SessionId id) {28 return this.hostPath + File.separator + id;29 }30 public String getContainerPath(SessionId id) {31 return this.containerPath + File.separator + id;32 }33}...
DockerAssetsPath
Using AI Code Generation
1package org.openqa.selenium.grid.node;2import org.openqa.selenium.grid.config.Config;3import org.openqa.selenium.grid.config.MemoizedConfig;4import org.openqa.selenium.grid.docker.DockerAssetsPath;5import org.openqa.selenium.grid.node.config.NodeOptions;6import org.openqa.selenium.grid.node.local.LocalNode;7import org.openqa.selenium.grid.security.Secret;8import org.openqa.selenium.grid.security.SecretOptions;9import org.openqa.selenium.grid.server.BaseServerOptions;10import org.openqa.selenium.grid.server.Server;11import org.openqa.selenium.grid.server.ServerOptions;12import org.openqa.selenium.remote.http.HttpClient;13import org.openqa.selenium.remote.http.HttpClient.Factory;14import org.openqa.selenium.remote.tracing.Tracer;15import org.openqa.selenium.remote.tracing.TracerBuilder;16import org.openqa.selenium.remote.tracing.opentelemetry.OpenTelemetryOptions;17import org.openqa.selenium.remote.tracing.opentelemetry.OpenTelemetryTracer;18import java.io.IOException;19import java.net.URI;20import java.nio.file.Path;21import java.time.Duration;22import java.util.Objects;23import java.util.logging.Logger;24import static org.openqa.selenium.grid.config.StandardGridRoles.NODE_ROLE;25public class Node {26 private static final Logger LOG = Logger.getLogger(Node.class.getName());27 public static void main(String[] args) throws IOException {28 Config config = new MemoizedConfig(new NodeOptions(new BaseServerOptions(new ServerOptions(new SecretOptions(new OpenTelemetryOptions())))));29 Tracer tracer = new TracerBuilder()30 .addTracer(new OpenTelemetryTracer(config))31 .build();32 Secret registrationSecret = config.get(SECRET).orElseThrow(() -> new ConfigException("Missing registration secret"));33 URI registration = config.get(URI.class, REGISTRATION).orElseThrow(() -> new ConfigException("Missing registration URL"));34 Path assets = new DockerAssetsPath(config).get();35 try (Server<?> server = new LocalNode(36 Factory.createDefault()).asServer()) {37 server.start();38 LOG.info("Started Selenium node");39 server.join();40 }41 }42}
DockerAssetsPath
Using AI Code Generation
1public class DockerAssetsPathTest {2 public void testDockerAssetsPath() {3 DockerAssetsPath dockerAssetsPath = new DockerAssetsPath("foo");4 Assert.assertEquals(dockerAssetsPath.getPath(), "foo");5 }6}7[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ docker-asset-path ---8[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ docker-asset-path ---9[INFO] --- maven-compiler-plugin:3.8.0:compile (default-compile) @ docker-asset-path ---10[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ docker-asset-path ---11[INFO] --- maven-compiler-plugin:3.8.0:testCompile (default-testCompile) @ docker-asset-path ---12[INFO] --- maven-surefire-plugin:2.22.0:test (default-test) @ docker-asset-path ---13[INFO] --- maven-jar-plugin:3.1.0:jar (default-jar) @ docker-asset-path ---
DockerAssetsPath
Using AI Code Generation
1import org.openqa.selenium.grid.node.docker.DockerAssetsPath;2import java.nio.file.Path;3DockerAssetsPath assetsPath = new DockerAssetsPath();4Path path = assetsPath.getPath("path/to/file");5import org.openqa.selenium.grid.node.docker.DockerAssets;6import java.nio.file.Path;7DockerAssets assets = new DockerAssets();8Path path = assets.getPath("path/to/file");9import org.openqa.selenium.grid.node.docker.DockerImage;10import java.util.Map;11DockerImage image = new DockerImage("image-name");12Map<String, String> env = image.getEnv();13import org.openqa.selenium.grid.node.docker.DockerContainer;14import java.util.Map;15DockerContainer container = new DockerContainer("container-name");16Map<String, String> env = container.getEnv();17import org.openqa.selenium.grid.node.docker.DockerContainerInfo;18import java.util.Map;19DockerContainerInfo containerInfo = new DockerContainerInfo("container-name");20Map<String, String> env = containerInfo.getEnv();21import org.openqa.selenium.grid.node.docker.DockerContainerFactory;22import org.openqa.selenium.grid.node.config.NodeOptions;23import java.util.Map;24NodeOptions nodeOptions = NodeOptions.create();25DockerContainerFactory factory = new DockerContainerFactory(nodeOptions);26Map<String, String> env = factory.getEnv();27import org.openqa.selenium.grid.node.docker.DockerContainerInfo;28import org.openqa.selenium.grid.node.config.NodeOptions;29import java.util.Map;30NodeOptions nodeOptions = NodeOptions.create();31DockerContainerInfo info = new DockerContainerInfo(nodeOptions);32Map<String, String> env = info.getEnv();33import org.openqa.selenium.grid.node.docker.DockerContainerInfo;34import org.openqa.selenium.grid.node.config.NodeOptions;35import java.util.Map;36NodeOptions nodeOptions = NodeOptions.create();37DockerContainerInfo info = new DockerContainerInfo(nodeOptions);38Map<String, String> env = info.getEnv();
DockerAssetsPath
Using AI Code Generation
1DockerAssetsPath dockerAssetsPath = new DockerAssetsPath();2DockerContainer container = new DockerContainer(dockerAssetsPath, "selenium/standalone-chrome-debug", "3.141.59");3container.start();4String port = container.getPort();5String host = container.getHost();6String id = container.getId();7container.stop();8container.remove();9container.remove(id);10container.remove(host, port);11container.remove(host, port, id);12boolean isRunning = container.isRunning();13boolean isRunning = container.isRunning(id);14boolean isRunning = container.isRunning(host, port);15boolean isRunning = container.isRunning(host, port, id);16boolean isStopped = container.isStopped();17boolean isStopped = container.isStopped(id);18boolean isStopped = container.isStopped(host, port);19boolean isStopped = container.isStopped(host, port, id);20boolean isRemoved = container.isRemoved();21boolean isRemoved = container.isRemoved(id);22boolean isRemoved = container.isRemoved(host, port);23boolean isRemoved = container.isRemoved(host, port, id);24boolean isCreated = container.isCreated();25boolean isCreated = container.isCreated(id);
DockerAssetsPath
Using AI Code Generation
1String dockerAssetsPath = DockerAssetsPath.get();2System.out.println(dockerAssetsPath);3String dockerContainerName = DockerContainerName.get();4System.out.println(dockerContainerName);5String dockerImageName = DockerImageName.get();6System.out.println(dockerImageName);7String dockerImageTag = DockerImageTag.get();8System.out.println(dockerImageTag);9String dockerNetworkName = DockerNetworkName.get();10System.out.println(dockerNetworkName);11String dockerNetworkSubnet = DockerNetworkSubnet.get();12System.out.println(dockerNetworkSubnet);
LambdaTest’s Selenium 4 tutorial is covering every aspects of Selenium 4 testing with examples and best practices. Here you will learn basics, such as how to upgrade from Selenium 3 to Selenium 4, to some advanced concepts, such as Relative locators and Selenium Grid 4 for Distributed testing. Also will learn new features of Selenium 4, such as capturing screenshots of specific elements, opening a new tab or window on the browser, and new protocol adoptions.
Upgrading From Selenium 3 To Selenium 4?: In this chapter, learn in detail how to update Selenium 3 to Selenium 4 for Java binding. Also, learn how to upgrade while using different build tools such as Maven or Gradle and get comprehensive guidance for upgrading Selenium.
What’s New In Selenium 4 & What’s Being Deprecated? : Get all information about new implementations in Selenium 4, such as W3S protocol adaption, Optimized Selenium Grid, and Enhanced Selenium IDE. Also, learn what is deprecated for Selenium 4, such as DesiredCapabilites and FindsBy methods, etc.
Selenium 4 With Python: Selenium supports all major languages, such as Python, C#, Ruby, and JavaScript. In this chapter, learn how to install Selenium 4 for Python and the features of Python in Selenium 4, such as Relative locators, Browser manipulation, and Chrom DevTool protocol.
Selenium 4 Is Now W3C Compliant: JSON Wireframe protocol is retiring from Selenium 4, and they are adopting W3C protocol to learn in detail about the advantages and impact of these changes.
How To Use Selenium 4 Relative Locator? : Selenium 4 came with new features such as Relative Locators that allow constructing locators with reference and easily located constructors nearby. Get to know its different use cases with examples.
Selenium Grid 4 Tutorial For Distributed Testing: Selenium Grid 4 allows you to perform tests over different browsers, OS, and device combinations. It also enables parallel execution browser testing, reads up on various features of Selenium Grid 4 and how to download it, and runs a test on Selenium Grid 4 with best practices.
Selenium Video Tutorials: Binge on video tutorials on Selenium by industry experts to get step-by-step direction from automating basic to complex test scenarios with Selenium.
LambdaTest also provides certification for Selenium testing to accelerate your career in Selenium automation testing.
Get 100 minutes of automation test minutes FREE!!