Run Selenium automation tests on LambdaTest cloud grid
Perform automation testing on 3000+ real desktop and mobile devices online.
// 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.selenium.grid.router.httpd;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.openqa.selenium.BuildInfo;
import org.openqa.selenium.cli.CliCommand;
import org.openqa.selenium.grid.TemplateGridCommand;
import org.openqa.selenium.grid.config.Config;
import org.openqa.selenium.grid.config.MapConfig;
import org.openqa.selenium.grid.config.Role;
import org.openqa.selenium.grid.distributor.Distributor;
import org.openqa.selenium.grid.distributor.config.DistributorOptions;
import org.openqa.selenium.grid.distributor.remote.RemoteDistributor;
import org.openqa.selenium.grid.graphql.GraphqlHandler;
import org.openqa.selenium.grid.log.LoggingOptions;
import org.openqa.selenium.grid.router.ProxyCdpIntoGrid;
import org.openqa.selenium.grid.router.Router;
import org.openqa.selenium.grid.server.BaseServerOptions;
import org.openqa.selenium.grid.server.NetworkOptions;
import org.openqa.selenium.grid.server.Server;
import org.openqa.selenium.grid.sessionmap.SessionMap;
import org.openqa.selenium.grid.sessionmap.config.SessionMapOptions;
import org.openqa.selenium.netty.server.NettyServer;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.http.Route;
import org.openqa.selenium.remote.tracing.Tracer;
import java.net.URL;
import java.util.Collections;
import java.util.Set;
import java.util.logging.Logger;
import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static org.openqa.selenium.grid.config.StandardGridRoles.DISTRIBUTOR_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.ROUTER_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.SESSION_MAP_ROLE;
import static org.openqa.selenium.net.Urls.fromUri;
import static org.openqa.selenium.remote.http.Route.get;
@AutoService(CliCommand.class)
public class RouterServer extends TemplateGridCommand {
private static final Logger LOG = Logger.getLogger(RouterServer.class.getName());
@Override
public String getName() {
return "router";
}
@Override
public String getDescription() {
return "Creates a router to front the selenium grid.";
}
@Override
public Set<Role> getConfigurableRoles() {
return ImmutableSet.of(DISTRIBUTOR_ROLE, HTTPD_ROLE, ROUTER_ROLE, SESSION_MAP_ROLE);
}
@Override
public Set<Object> getFlagObjects() {
return Collections.emptySet();
}
@Override
protected String getSystemPropertiesConfigPrefix() {
return "router";
}
@Override
protected Config getDefaultConfig() {
return new MapConfig(ImmutableMap.of("server", ImmutableMap.of("port", 4444)));
}
@Override
protected void execute(Config config) {
LoggingOptions loggingOptions = new LoggingOptions(config);
Tracer tracer = loggingOptions.getTracer();
NetworkOptions networkOptions = new NetworkOptions(config);
HttpClient.Factory clientFactory = networkOptions.getHttpClientFactory(tracer);
SessionMapOptions sessionsOptions = new SessionMapOptions(config);
SessionMap sessions = sessionsOptions.getSessionMap();
BaseServerOptions serverOptions = new BaseServerOptions(config);
DistributorOptions distributorOptions = new DistributorOptions(config);
URL distributorUrl = fromUri(distributorOptions.getDistributorUri());
Distributor distributor = new RemoteDistributor(
tracer,
clientFactory,
distributorUrl,
serverOptions.getRegistrationSecret());
GraphqlHandler graphqlHandler = new GraphqlHandler(distributor, serverOptions.getExternalUri());
Route handler = Route.combine(
new Router(tracer, clientFactory, sessions, distributor).with(networkOptions.getSpecComplianceChecks()),
Route.post("/graphql").to(() -> graphqlHandler),
get("/readyz").to(() -> req -> new HttpResponse().setStatus(HTTP_NO_CONTENT)));
Server<?> server = new NettyServer(serverOptions, handler, new ProxyCdpIntoGrid(clientFactory, sessions));
server.start();
BuildInfo info = new BuildInfo();
LOG.info(String.format(
"Started Selenium router %s (revision %s): %s",
info.getReleaseLabel(),
info.getBuildRevision(),
server.getUrl()));
}
}
// 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.selenium.grid.commands;
import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.openqa.selenium.BuildInfo;
import org.openqa.selenium.cli.CliCommand;
import org.openqa.selenium.events.Event;
import org.openqa.selenium.events.EventBus;
import org.openqa.selenium.events.EventListener;
import org.openqa.selenium.events.EventName;
import org.openqa.selenium.grid.TemplateGridCommand;
import org.openqa.selenium.grid.config.CompoundConfig;
import org.openqa.selenium.grid.config.Config;
import org.openqa.selenium.grid.config.MapConfig;
import org.openqa.selenium.grid.config.MemoizedConfig;
import org.openqa.selenium.grid.config.Role;
import org.openqa.selenium.grid.server.BaseServerOptions;
import org.openqa.selenium.grid.server.EventBusOptions;
import org.openqa.selenium.grid.server.Server;
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.netty.server.NettyServer;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.http.Route;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import static java.net.HttpURLConnection.HTTP_NO_CONTENT;
import static org.openqa.selenium.grid.config.StandardGridRoles.EVENT_BUS_ROLE;
import static org.openqa.selenium.grid.config.StandardGridRoles.HTTPD_ROLE;
import static org.openqa.selenium.json.Json.JSON_UTF_8;
import static org.openqa.selenium.remote.http.Contents.asJson;
@AutoService(CliCommand.class)
public class EventBusCommand extends TemplateGridCommand {
private static final Logger LOG = Logger.getLogger(EventBusCommand.class.getName());
@Override
public String getName() {
return "event-bus";
}
@Override
public String getDescription() {
return "Standalone instance of the event bus.";
}
@Override
public Set<Role> getConfigurableRoles() {
return ImmutableSet.of(EVENT_BUS_ROLE, HTTPD_ROLE);
}
@Override
public boolean isShown() {
return false;
}
@Override
public Set<Object> getFlagObjects() {
return Collections.emptySet();
}
@Override
protected String getSystemPropertiesConfigPrefix() {
return "selenium";
}
@Override
protected Config getDefaultConfig() {
return new MapConfig(ImmutableMap.of(
"events", ImmutableMap.of(
"bind", true,
"publish", "tcp://*:4442",
"subscribe", "tcp://*:4443"),
"server", ImmutableMap.of(
"port", 5557)));
}
public Server<?> asServer(Config initialConfig) {
Require.nonNull("Config", initialConfig);
Config config = new MemoizedConfig(new CompoundConfig(initialConfig, getDefaultConfig()));
EventBusOptions events = new EventBusOptions(config);
EventBus bus = events.getEventBus();
BaseServerOptions serverOptions = new BaseServerOptions(config);
return new NettyServer(
serverOptions,
Route.combine(
Route.get("/status").to(() -> req -> {
CountDownLatch latch = new CountDownLatch(1);
EventName healthCheck = new EventName("healthcheck");
bus.addListener(new EventListener<>(healthCheck, Object.class, obj -> latch.countDown()));
bus.fire(new Event(healthCheck, "ping"));
try {
if (latch.await(5, TimeUnit.SECONDS)) {
return httpResponse(true, "Event bus running");
} else {
return httpResponse(false, "Event bus could not deliver a test message in 5 seconds");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return httpResponse(false, "Status checking was interrupted");
}
}),
Route.get("/readyz").to(() -> req -> new HttpResponse().setStatus(HTTP_NO_CONTENT)))
);
}
@Override
protected void execute(Config config) {
Require.nonNull("Config", config);
Server<?> server = asServer(config);
server.start();
BuildInfo info = new BuildInfo();
LOG.info(String.format(
"Started Selenium event bus %s (revision %s): %s",
info.getReleaseLabel(),
info.getBuildRevision(),
server.getUrl()));
}
private HttpResponse httpResponse(boolean ready, String message) {
return new HttpResponse()
.addHeader("Content-Type", JSON_UTF_8)
.setContent(asJson(ImmutableMap.of(
"value", ImmutableMap.of(
"ready", ready,
"message", message))));
}
}
Stream.of(input).toMap(e -> e.getKey().substring(subLength),
e -> AttributeType.GetByName(e.getValue()));
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
int subLength = prefix.length();
return EntryStream.of(input)
.mapKeys(key -> key.substring(subLength))
.mapValues(AttributeType::GetByName)
.toMap();
}
private Map<String, AttributeType> mapConfig(Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream().map(e ->
Map.entry(e.getKey().substring(subLength), AttributeType.GetByName(e.getValue()))
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private Map<String, AttributeType> mapConfig(
Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet()
.stream()
.map(e -> new AbstractMap.SimpleEntry<>(
e.getKey().substring(subLength),
AttributeType.GetByName(e.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
<K, V> Collector<? super Map.Entry<K, V>, ?, Map<K, V>> toMap() {
return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
}
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getKey().substring(subLength),
entry -> AttributeType.GetByName(entry.getValue())));
}
Stream.of(input).toMap(e -> e.getKey().substring(subLength),
e -> AttributeType.GetByName(e.getValue()));
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
int subLength = prefix.length();
return EntryStream.of(input)
.mapKeys(key -> key.substring(subLength))
.mapValues(AttributeType::GetByName)
.toMap();
}
private Map<String, AttributeType> mapConfig(Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream().map(e ->
Map.entry(e.getKey().substring(subLength), AttributeType.GetByName(e.getValue()))
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private Map<String, AttributeType> mapConfig(
Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet()
.stream()
.map(e -> new AbstractMap.SimpleEntry<>(
e.getKey().substring(subLength),
AttributeType.GetByName(e.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
<K, V> Collector<? super Map.Entry<K, V>, ?, Map<K, V>> toMap() {
return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
}
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getKey().substring(subLength),
entry -> AttributeType.GetByName(entry.getValue())));
}
Stream.of(input).toMap(e -> e.getKey().substring(subLength),
e -> AttributeType.GetByName(e.getValue()));
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
int subLength = prefix.length();
return EntryStream.of(input)
.mapKeys(key -> key.substring(subLength))
.mapValues(AttributeType::GetByName)
.toMap();
}
private Map<String, AttributeType> mapConfig(Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream().map(e ->
Map.entry(e.getKey().substring(subLength), AttributeType.GetByName(e.getValue()))
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private Map<String, AttributeType> mapConfig(
Map<String, String> input, String prefix) {
int subLength = prefix.length();
return input.entrySet()
.stream()
.map(e -> new AbstractMap.SimpleEntry<>(
e.getKey().substring(subLength),
AttributeType.GetByName(e.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
<K, V> Collector<? super Map.Entry<K, V>, ?, Map<K, V>> toMap() {
return Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue);
}
private Map<String, String> mapConfig(Map<String, Integer> input, String prefix) {
int subLength = prefix.length();
return input.entrySet().stream()
.collect(Collectors.toMap(
entry -> entry.getKey().substring(subLength),
entry -> AttributeType.GetByName(entry.getValue())));
}
Accelerate Your Automation Test Cycles With LambdaTest
Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.