Skip to content

Commit

Permalink
[grid] Removing SlotMatcher from Slot, so it can be configured in an …
Browse files Browse the repository at this point in the history
…easier way
  • Loading branch information
diemol committed Jun 28, 2023
1 parent fcfb21b commit 48b5659
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 17 deletions.
9 changes: 5 additions & 4 deletions java/src/org/openqa/selenium/grid/data/NodeStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ public static NodeStatus fromJson(JsonInput input) {
nodeId, externalUri, maxSessions, slots, availability, heartbeatPeriod, version, osInfo);
}

public boolean hasCapability(Capabilities caps) {
return slots.stream().anyMatch(slot -> slot.isSupporting(caps));
public boolean hasCapability(Capabilities caps, SlotMatcher slotMatcher) {
return slots.stream().anyMatch(slot -> slot.isSupporting(caps, slotMatcher));
}

public boolean hasCapacity() {
Expand All @@ -132,9 +132,10 @@ public boolean hasCapacity() {

// Check if the Node's max session limit is not exceeded and has a free slot that supports the
// capability.
public boolean hasCapacity(Capabilities caps) {
public boolean hasCapacity(Capabilities caps, SlotMatcher slotMatcher) {
return slots.stream().filter(slot -> slot.getSession() != null).count() < maxSessionCount
&& slots.stream().anyMatch(slot -> slot.getSession() == null && slot.isSupporting(caps));
&& slots.stream()
.anyMatch(slot -> slot.getSession() == null && slot.isSupporting(caps, slotMatcher));
}

public int getMaxSessionCount() {
Expand Down
4 changes: 1 addition & 3 deletions java/src/org/openqa/selenium/grid/data/Slot.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,12 @@ public class Slot implements Serializable {
private final Capabilities stereotype;
private final Session session;
private final Instant lastStarted;
private final SlotMatcher slotMatcher;

public Slot(SlotId id, Capabilities stereotype, Instant lastStarted, Session session) {
this.id = Require.nonNull("Slot ID", id);
this.stereotype = ImmutableCapabilities.copyOf(Require.nonNull("Stereotype", stereotype));
this.lastStarted = Require.nonNull("Last started", lastStarted);
this.session = session;
this.slotMatcher = new DefaultSlotMatcher();
}

private static Slot fromJson(JsonInput input) {
Expand Down Expand Up @@ -106,7 +104,7 @@ public Session getSession() {
return session;
}

public boolean isSupporting(Capabilities caps) {
public boolean isSupporting(Capabilities caps, SlotMatcher slotMatcher) {
return slotMatcher.matches(getStereotype(), caps);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.openqa.selenium.grid.data.Availability;
import org.openqa.selenium.grid.data.CreateSessionRequest;
import org.openqa.selenium.grid.data.CreateSessionResponse;
import org.openqa.selenium.grid.data.DefaultSlotMatcher;
import org.openqa.selenium.grid.data.DistributorStatus;
import org.openqa.selenium.grid.data.NodeAddedEvent;
import org.openqa.selenium.grid.data.NodeDrainComplete;
Expand Down Expand Up @@ -661,7 +662,8 @@ private SlotId reserveSlot(RequestId requestId, Capabilities caps) {
Lock writeLock = lock.writeLock();
writeLock.lock();
try {
Set<SlotId> slotIds = slotSelector.selectSlot(caps, getAvailableNodes());
Set<SlotId> slotIds =
slotSelector.selectSlot(caps, getAvailableNodes(), new DefaultSlotMatcher());
if (slotIds.isEmpty()) {
LOG.log(
getDebugLogLevel(),
Expand All @@ -682,7 +684,8 @@ private SlotId reserveSlot(RequestId requestId, Capabilities caps) {
}

private boolean isNotSupported(Capabilities caps) {
return getAvailableNodes().stream().noneMatch(node -> node.hasCapability(caps));
return getAvailableNodes().stream()
.noneMatch(node -> node.hasCapability(caps, new DefaultSlotMatcher()));
}

private boolean reserve(SlotId id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
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;

public class DefaultSlotSelector implements SlotSelector {

Expand All @@ -35,7 +36,8 @@ public static SlotSelector create(Config config) {
}

@Override
public Set<SlotId> selectSlot(Capabilities capabilities, Set<NodeStatus> nodes) {
public Set<SlotId> selectSlot(
Capabilities capabilities, Set<NodeStatus> 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,
Expand All @@ -44,7 +46,7 @@ public Set<SlotId> selectSlot(Capabilities capabilities, Set<NodeStatus> nodes)
// Nodes).
// After that, Nodes are ordered by their load, last session creation, and their id.
return nodes.stream()
.filter(node -> node.hasCapacity(capabilities))
.filter(node -> node.hasCapacity(capabilities, slotMatcher))
.sorted(
Comparator.comparingLong(this::getNumberOfSupportedBrowsers)
// Now sort by node which has the lowest load (natural ordering)
Expand All @@ -57,7 +59,7 @@ public Set<SlotId> selectSlot(Capabilities capabilities, Set<NodeStatus> nodes)
node ->
node.getSlots().stream()
.filter(slot -> slot.getSession() == null)
.filter(slot -> slot.isSupporting(capabilities))
.filter(slot -> slot.isSupporting(capabilities, slotMatcher))
.map(Slot::getId))
.collect(toImmutableSet());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.grid.data.NodeStatus;
import org.openqa.selenium.grid.data.SlotId;
import org.openqa.selenium.grid.data.SlotMatcher;

/**
* Used to determine which {@link org.openqa.selenium.grid.node.Node} to send a particular New
* Session request to.
*/
@FunctionalInterface
public interface SlotSelector {
Set<SlotId> selectSlot(Capabilities capabilities, Set<NodeStatus> nodes);
Set<SlotId> selectSlot(Capabilities capabilities, Set<NodeStatus> nodes, SlotMatcher slotMatcher);
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.events.EventBus;
import org.openqa.selenium.events.local.GuavaEventBus;
import org.openqa.selenium.grid.data.DefaultSlotMatcher;
import org.openqa.selenium.grid.data.NodeId;
import org.openqa.selenium.grid.data.NodeStatus;
import org.openqa.selenium.grid.data.Session;
Expand Down Expand Up @@ -99,7 +100,7 @@ void nodesAreOrderedNodesByNumberOfSupportedBrowsers() {
nodes.add(twoBrowsers);
nodes.add(oneBrowser);

Set<SlotId> slots = selector.selectSlot(caps, nodes);
Set<SlotId> slots = selector.selectSlot(caps, nodes, new DefaultSlotMatcher());

ImmutableSet<NodeId> nodeIds =
slots.stream().map(SlotId::getOwningNodeId).distinct().collect(toImmutableSet());
Expand All @@ -123,7 +124,9 @@ void theMostLightlyLoadedNodeIsSelectedFirst() {
NodeStatus heavy = createNode(Collections.singletonList(caps), 10, 6);
NodeStatus massive = createNode(Collections.singletonList(caps), 10, 8);

Set<SlotId> ids = selector.selectSlot(caps, ImmutableSet.of(heavy, medium, lightest, massive));
Set<SlotId> ids =
selector.selectSlot(
caps, ImmutableSet.of(heavy, medium, lightest, massive), new DefaultSlotMatcher());
SlotId expected = ids.iterator().next();

assertThat(lightest.getSlots().stream()).anyMatch(slot -> expected.equals(slot.getId()));
Expand All @@ -138,7 +141,8 @@ void theNodeWhichHasExceededMaxSessionsIsNotSelected() {
NodeStatus maximumLoad = createNode(ImmutableList.of(chrome), 12, 12);

Set<SlotId> ids =
selector.selectSlot(chrome, ImmutableSet.of(maximumLoad, mediumLoad, lightLoad));
selector.selectSlot(
chrome, ImmutableSet.of(maximumLoad, mediumLoad, lightLoad), new DefaultSlotMatcher());
SlotId expected = ids.iterator().next();

// The slot should belong to the Node with light load
Expand Down Expand Up @@ -172,7 +176,8 @@ void nodesAreOrderedByNumberOfSupportedBrowsersAndLoad() {
lightLoadAndThreeBrowsers,
mediumLoadAndTwoBrowsers,
mediumLoadAndOtherTwoBrowsers,
highLoadAndOneBrowser));
highLoadAndOneBrowser),
new DefaultSlotMatcher());

// The slot should belong to the Node with high load because it only supports Chrome, leaving
// the other Nodes with more availability for other browsers
Expand Down

0 comments on commit 48b5659

Please sign in to comment.