
com.infotel.seleniumrobot.grid.distributor.SeleniumRobotSlotSelector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of seleniumRobot-grid4 Show documentation
Show all versions of seleniumRobot-grid4 Show documentation
Selenium grid extension for mobile testing
The newest version!
package com.infotel.seleniumrobot.grid.distributor;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import java.util.Comparator;
import java.util.Set;
import java.util.logging.Logger;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.grid.config.Config;
import org.openqa.selenium.grid.data.Availability;
import org.openqa.selenium.grid.data.NodeStatus;
import org.openqa.selenium.grid.data.Slot;
import org.openqa.selenium.grid.data.SlotId;
import org.openqa.selenium.grid.data.SlotMatcher;
import org.openqa.selenium.grid.distributor.selector.SlotSelector;
import com.google.common.annotations.VisibleForTesting;
import com.infotel.seleniumrobot.grid.config.LaunchConfig;
import com.infotel.seleniumrobot.grid.servlets.client.NodeStatusServletClient;
import com.infotel.seleniumrobot.grid.servlets.client.entities.SeleniumRobotNode;
import com.infotel.seleniumrobot.grid.utils.GridStatus;
import com.seleniumtests.browserfactory.SeleniumRobotCapabilityType;
public class SeleniumRobotSlotSelector implements SlotSelector {
private static final Logger LOG = Logger.getLogger(SeleniumRobotSlotSelector.class.getName());
public static SlotSelector create(Config config) {
return new SeleniumRobotSlotSelector();
}
@Override
public Set selectSlot(Capabilities capabilities, Set nodes, SlotMatcher slotMatcher) {
// First, filter the Nodes that support the required capabilities. Then, the filtered Nodes
// get ordered in ascendant order by the number of browsers they support.
// With this, Nodes with diverse configurations (supporting many browsers, e.g. Chrome,
// Firefox, Safari) are placed at the bottom so they have more availability when a session
// requests a browser supported only by a few Nodes (e.g. Safari only supported on macOS
// Nodes).
// After that, Nodes are ordered by their load, last session creation, and their id.
Set slotIds = nodes.stream()
.filter(node -> node.hasCapacity(capabilities, slotMatcher))
.filter(node -> acceptNewSession(node, capabilities))
.sorted(
Comparator.comparingLong(this::getNumberOfSupportedBrowsers)
// Now sort by node which has the lowest load (natural ordering)
.thenComparingDouble(NodeStatus::getLoad)
// Then last session created (oldest first), so natural ordering again
.thenComparingLong(NodeStatus::getLastSessionCreated)
// And use the node id as a tie-breaker.
.thenComparing(NodeStatus::getNodeId))
.flatMap(node -> node.getSlots().stream()
.filter(slot -> slot.getSession() == null)
.filter(slot -> slot.isSupporting(capabilities, slotMatcher))
.map(Slot::getId))
.collect(toImmutableSet());
return slotIds;
}
/**
* is the node accepting new session
* On node startup, we define a maxSession (number of test sessions in parallel) which is different from selenium maxSession (number of browsers in parallel)
* as we allow attaching to existing browsers inside the same test session
* @return
*/
private boolean acceptNewSession(NodeStatus nodeStatus, Capabilities capabilities) {
int maxTestSessions = 0;
try {
maxTestSessions = Integer.parseInt(nodeStatus.getSlots().stream().findFirst().get().getStereotype().getCapability(LaunchConfig.MAX_SESSIONS).toString());
} catch (Exception e) {
// in case there is no slot
return false;
}
// in case node is marked as INACTIVE (set to DRAINING in NodeAction.java), we reply that it's not supporting any capabilities so that no new session are affected
if (nodeStatus.getAvailability() != Availability.UP) {
return false;
}
long sessions = nodeStatus.getSlots().stream().filter(slot -> slot.getSession() != null).count();
// do not accept new sessions if the number of test sessions is reached and 'attachSessionOnNode' capability does not correspond to this node
if (sessions >= maxTestSessions
&& (capabilities.getCapability(SeleniumRobotCapabilityType.ATTACH_SESSION_ON_NODE) == null
|| !capabilities.getCapability(SeleniumRobotCapabilityType.ATTACH_SESSION_ON_NODE).toString().equals(nodeStatus.getExternalUri().toString()))
) {
LOG.fine(String.format("Max session reached for node %s", nodeStatus.getExternalUri()));
return false;
}
LOG.fine(String.format("Slots available for node %s", nodeStatus.getExternalUri()));
return true;
}
@VisibleForTesting
long getNumberOfSupportedBrowsers(NodeStatus nodeStatus) {
return nodeStatus.getSlots()
.stream()
.map(slot -> slot.getStereotype().getBrowserName().toLowerCase())
.distinct()
.count();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy