org.openqa.grid.internal.ProxySet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of selenium-server Show documentation
Show all versions of selenium-server Show documentation
Selenium automates browsers. That's it! What you do with that power is entirely up to you.
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.openqa.grid.internal;
import net.jcip.annotations.ThreadSafe;
import org.openqa.grid.common.exception.CapabilityNotPresentOnTheGridException;
import org.openqa.grid.common.exception.GridException;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* A set of RemoteProxies.
*
* Obeys the iteration guarantees of CopyOnWriteArraySet
*/
@ThreadSafe
public class ProxySet implements Iterable {
private final Set proxies = new CopyOnWriteArraySet<>();
private static final Logger log = Logger.getLogger(ProxySet.class.getName());
private volatile boolean throwOnCapabilityNotPresent = true;
public ProxySet(boolean throwOnCapabilityNotPresent) {
this.throwOnCapabilityNotPresent = throwOnCapabilityNotPresent;
}
/**
* killing the timeout detection threads.
*/
public void teardown() {
proxies.forEach(RemoteProxy::teardown);
}
public boolean hasCapability(Map requestedCapability) {
return proxies.stream().anyMatch(remoteProxy -> remoteProxy.hasCapability(requestedCapability));
}
/**
* Removes the specified instance from the proxySet
* @param proxy The proxy to remove, must be present in this set
* @return The instance that was removed. Not null.
*/
public RemoteProxy remove(RemoteProxy proxy) {
// Find the original proxy. While the supplied one is logically equivalent, it may be a fresh object with
// an empty TestSlot list, which doesn't figure into the proxy equivalence check. Since we want to free up
// those test sessions, we need to operate on that original object.
for (RemoteProxy p : proxies) {
if (p.equals(proxy)) {
proxies.remove(p);
return p;
}
}
throw new IllegalStateException("Did not contain proxy" + proxy);
}
public void add(RemoteProxy proxy) {
proxies.add(proxy);
}
public boolean contains(RemoteProxy o) {
return proxies.contains(o);
}
public List getBusyProxies() {
return proxies.stream().filter(RemoteProxy::isBusy).collect(Collectors.toList());
}
public RemoteProxy getProxyById(String id) {
return proxies.stream().filter((proxy) -> proxy.getId().equals(id)).findFirst().orElse(null);
}
public boolean isEmpty() {
return proxies.isEmpty();
}
public List getSorted() {
List sorted = new ArrayList<>(proxies);
Collections.sort(sorted, proxyComparator);
return sorted;
}
private Comparator proxyComparator = (o1, o2) -> {
double p1used = o1.getResourceUsageInPercent();
double p2used = o2.getResourceUsageInPercent();
if (p1used == p2used) {
long time1lastUsed = o1.getLastSessionStart();
long time2lastUsed = o2.getLastSessionStart();
if (time1lastUsed == time2lastUsed) return 0;
return time1lastUsed < time2lastUsed? -1 : 1;
}
return p1used < p2used? -1 : 1;
};
public TestSession getNewSession(Map desiredCapabilities) {
// sort the proxies first, by default by total number of
// test running, to avoid putting all the load of the first
// proxies.
List sorted = getSorted();
log.fine("Available nodes: " + sorted);
return sorted.stream()
.map(proxy -> proxy.getNewSession(desiredCapabilities))
.filter(Objects::nonNull)
.findFirst().orElse(null);
}
public Iterator iterator() {
return proxies.iterator();
}
public int size() {
return proxies.size();
}
public void verifyAbilityToHandleDesiredCapabilities(Map desiredCapabilities) {
if (proxies.isEmpty()) {
if (throwOnCapabilityNotPresent) {
throw new GridException("Empty pool of VM for setup "
+ new DesiredCapabilities(desiredCapabilities));
}
log.warning("Empty pool of nodes.");
}
if (!hasCapability(desiredCapabilities)) {
if (throwOnCapabilityNotPresent) {
throw new CapabilityNotPresentOnTheGridException(desiredCapabilities);
}
log.warning("grid doesn't contain " + new DesiredCapabilities(desiredCapabilities) +
" at the moment.");
}
}
public void setThrowOnCapabilityNotPresent(boolean throwOnCapabilityNotPresent) {
this.throwOnCapabilityNotPresent = throwOnCapabilityNotPresent;
}
}