Showing preview only (218K chars total). Download the full file or copy to clipboard to get everything.
Repository: seleniumkit/gridrouter
Branch: master
Commit: 13aec297eac9
Files: 135
Total size: 180.9 KB
Directory structure:
gitextract_k296bzti/
├── .gitignore
├── AUTHORS
├── LICENSE
├── README.md
├── ci/
│ └── jenkins.groovy
├── config/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── ru/
│ │ │ └── qatools/
│ │ │ └── gridrouter/
│ │ │ └── config/
│ │ │ ├── GridRouterException.java
│ │ │ ├── HostSelectionStrategy.java
│ │ │ ├── RandomHostSelectionStrategy.java
│ │ │ ├── RegionWithCount.java
│ │ │ ├── SequentialHostSelectionStrategy.java
│ │ │ ├── VersionWithCount.java
│ │ │ ├── WithBrowserVersionFind.java
│ │ │ ├── WithCopy.java
│ │ │ ├── WithCount.java
│ │ │ ├── WithRoute.java
│ │ │ ├── WithRoutesMap.java
│ │ │ ├── WithVersionFind.java
│ │ │ └── WithXmlView.java
│ │ └── resources/
│ │ └── xsd/
│ │ ├── bindings.xjb
│ │ └── config.xsd
│ └── test/
│ └── java/
│ └── ru/
│ └── qatools/
│ └── gridrouter/
│ └── config/
│ └── RandomHostSelectionStrategyTest.java
├── pom.xml
├── proxy/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── ru/
│ │ │ └── qatools/
│ │ │ └── gridrouter/
│ │ │ ├── ConfigRepository.java
│ │ │ ├── ConfigRepositoryXml.java
│ │ │ ├── JsonWireUtils.java
│ │ │ ├── PingServlet.java
│ │ │ ├── ProxyServlet.java
│ │ │ ├── QuotaServlet.java
│ │ │ ├── RequestUtils.java
│ │ │ ├── RouteServlet.java
│ │ │ ├── SessionStorageEvictionScheduler.java
│ │ │ ├── SpringHttpServlet.java
│ │ │ ├── StatsServlet.java
│ │ │ ├── caps/
│ │ │ │ ├── AppiumCapabilityProcessor.java
│ │ │ │ ├── CapabilityProcessor.java
│ │ │ │ ├── CapabilityProcessorFactory.java
│ │ │ │ ├── DummyCapabilityProcessor.java
│ │ │ │ └── IECapabilityProcessor.java
│ │ │ ├── json/
│ │ │ │ ├── Describable.java
│ │ │ │ ├── JsonFormatter.java
│ │ │ │ ├── JsonMessageFactory.java
│ │ │ │ ├── JsonWithAnyProperties.java
│ │ │ │ ├── WithErrorMessage.java
│ │ │ │ └── WithJsonView.java
│ │ │ └── sessions/
│ │ │ ├── AvailableBrowserCheckExeption.java
│ │ │ ├── AvailableBrowsersChecker.java
│ │ │ ├── BrowserVersion.java
│ │ │ ├── BrowsersCountMap.java
│ │ │ ├── GridRouterUserStats.java
│ │ │ ├── MemoryStatsCounter.java
│ │ │ ├── SkipAvailableBrowsersChecker.java
│ │ │ ├── StatsCounter.java
│ │ │ ├── WaitAvailableBrowserTimeoutException.java
│ │ │ └── WaitAvailableBrowsersChecker.java
│ │ ├── resources/
│ │ │ ├── META-INF/
│ │ │ │ └── spring/
│ │ │ │ └── application-context.xml
│ │ │ ├── application.properties
│ │ │ ├── log4j.properties
│ │ │ └── xsd/
│ │ │ ├── json.xjb
│ │ │ └── json.xsd
│ │ └── webapp/
│ │ └── WEB-INF/
│ │ └── web.xml
│ └── test/
│ ├── java/
│ │ └── ru/
│ │ └── qatools/
│ │ └── gridrouter/
│ │ ├── CommandDecodingTest.java
│ │ ├── JsonWireUtilsTest.java
│ │ ├── PingServletTest.java
│ │ ├── ProxyServletExceptionsWithHubTest.java
│ │ ├── ProxyServletExceptionsWithoutHubTest.java
│ │ ├── ProxyServletTest.java
│ │ ├── ProxyServletWithBrokenAndOkHubsTest.java
│ │ ├── ProxyServletWithBrokenHubTest.java
│ │ ├── ProxyServletWithOneHubTest.java
│ │ ├── ProxyServletWithTwoHubsTest.java
│ │ ├── ProxyServletWithoutHubTest.java
│ │ ├── QuotaReloadTest.java
│ │ ├── QuotaServletTest.java
│ │ ├── RegionsTest.java
│ │ ├── RouteServletTest.java
│ │ ├── StatsServletTest.java
│ │ ├── caps/
│ │ │ ├── AppiumCapabilityProcessorTest.java
│ │ │ ├── CapabilityProcessorFactoryTest.java
│ │ │ └── IECapabilityProcessorTest.java
│ │ ├── json/
│ │ │ └── JsonMessageTest.java
│ │ ├── sessions/
│ │ │ ├── MemoryStatsCounterTest.java
│ │ │ └── WaitAvailableBrowsersCheckerTest.java
│ │ └── utils/
│ │ ├── FindElementCallback.java
│ │ ├── GridRouterRule.java
│ │ ├── HttpUtils.java
│ │ ├── HubEmulator.java
│ │ ├── HubEmulatorRule.java
│ │ ├── JettyRule.java
│ │ ├── JsonUtils.java
│ │ ├── MatcherUtils.java
│ │ ├── QuotaUtils.java
│ │ ├── RememberUrlCallback.java
│ │ ├── SocketUtil.java
│ │ └── TestConfigRepository.java
│ └── resources/
│ ├── META-INF/
│ │ └── spring/
│ │ └── test-application-context.xml
│ ├── application.properties
│ ├── log4j.properties
│ └── quota/
│ ├── user1.xml
│ ├── user2.xml
│ └── user3.xml
└── testing/
├── group_vars/
│ └── all.yml
├── ping-local-gridrouter.sh
├── roles/
│ ├── start/
│ │ ├── files/
│ │ │ └── gridrouter/
│ │ │ ├── conf/
│ │ │ │ ├── application.properties
│ │ │ │ ├── quota/
│ │ │ │ │ └── selenium.xml
│ │ │ │ └── users.properties
│ │ │ └── webapps/
│ │ │ └── ROOT.xml
│ │ └── tasks/
│ │ ├── before.yml
│ │ ├── main.yml
│ │ ├── start-gridrouter.yml
│ │ └── start-selenium.yml
│ ├── stop/
│ │ └── tasks/
│ │ ├── before.yml
│ │ ├── main.yml
│ │ ├── stop-gridrouter.yml
│ │ └── stop-selenium.yml
│ └── test/
│ ├── files/
│ │ ├── java/
│ │ │ ├── pom.xml
│ │ │ ├── run.sh
│ │ │ └── src/
│ │ │ └── test/
│ │ │ └── java/
│ │ │ └── SeleniumTest.java
│ │ ├── js/
│ │ │ ├── config.json
│ │ │ ├── fixtures/
│ │ │ │ └── big-script.js
│ │ │ ├── package.json
│ │ │ ├── run.sh
│ │ │ └── test/
│ │ │ ├── selenium-test-sync.js
│ │ │ └── selenium-test-wd.js
│ │ └── python/
│ │ ├── requirements.txt
│ │ ├── run.sh
│ │ └── src/
│ │ └── test_selenium.py
│ └── tasks/
│ ├── after.yml
│ ├── before.yml
│ ├── main.yml
│ └── run-tests.yml
├── start.yml
├── stop.yml
└── test.yml
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# IDEA files
.idea
*.iml
# Maven files
target
# Docker compose files
compose/war
# Npm modules
node_modules
================================================
FILE: AUTHORS
================================================
The following authors have created the source code of "Selenium Grid Router"
published and distributed by YANDEX LLC as the owner:
* Alexander Andryashin <aandryashin@yandex-team.ru>
* Dmitry Baev <charlie@yandex-team.ru>
* Artem Eroshenko <eroshenkoam@yandex-team.ru>
* Innokenty Shuvalov <innokenty@yandex-team.ru>
* Ivan Krutov <vania-pooh@yandex-team.ru>
================================================
FILE: LICENSE
================================================
(C) YANDEX LLC, 2015
The Source Code called "Selenium Grid Router" available at https://github.com/seleniumkit/gridrouter is subject
to the terms of the Apache License 2.0 (hereinafter referred to as the "License").
The text of the License is the following:
Licensed 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.
================================================
FILE: README.md
================================================
# Selenium Grid Router
**Selenium Grid Router** is a lightweight server that routes and proxies [Selenium Wedriver](http://www.seleniumhq.org/projects/webdriver/) requests to multiple Selenium hubs.
## Golang Implementation
There is a smaller and faster Golang implementation of this server. See https://github.com/aerokube/ggr for more details.
## What is this for
If you're frequently using Selenium for running your tests in browsers you may notice that a standard [Selenium Grid](https://github.com/SeleniumHQ/selenium/wiki/Grid2) installation has some faults that can prevent you from using it on large scale:
* **Does not support high availability.** Selenium Grid consists of a single entry point **hub** server and multiple **node** processes. Users interact only with hub. That means that if for some reason hub goes down all nodes also become unavailable to user.
* **Does not scale well.** Our experience shows that even when running on high-end hardware Selenium hub is able to handle correctly no more than 20-30 nodes. When more nodes are connected hub very often stops responding.
* **Does not support authentication and authorization.** Standard Selenium grid hub makes all nodes available for everyone.
## How it works
The basic idea is very simple:
1. Define user names and their passwords in a plain text file
2. Distribute a set of running Selenium hubs (aka "hosts") with nodes connected to each one over multiple datacenters
3. For each defined user save hosts to a simple XML configuration file
4. Start multiple instances of Grid Router in different datacenters and load-balance them
5. Work with Grid Router like you do with a regular Selenium hub
## Installation
Currently we maintain only Debian packages. To install on Ubuntu ensure that you have Java 8 installed:
```
# add-apt-repository ppa:webupd8team/java
# apt-get update
# apt-get install oracle-java8-installer
```
Then install Gridrouter itself:
```
# add-apt-repository ppa:yandex-qatools/gridrouter
# apt-get update
# apt-get install yandex-grid-router
# service yandex-grid-router start
```
Configuration files are located in `/etc/grid-router/` directory, XML quota files - by default in `/etc/grid-router/quota/`, log files reside in `/var/log/grid-router/`, binaries are installed to `/usr/share/grid-router`.
## Configuration
Two types of configuration files exist:
* A plain text file with users and passwords (users.properties)
* An XML file with user quota definition (<username>.xml)
### Users list (users.properties)
A typical file looks like this:
```
alice:alicePassword, user
bob:bobPassword, user
```
As you can see passwords are **NOT** encrypted. This is because we consider quotas as a way to easily limit Selenium browsers consumption and not a restrictive tool.
### User quota definition (<username>.xml)
This file has the following format:
```xml
<qa:browsers xmlns:qa="urn:config.gridrouter.qatools.ru">
<browser name="firefox" defaultVersion="33.0">
<version number="33.0">
<region name="us-west">
<host name="my-firefox33-hub-1.example.com" port="4444" count="5"/>
</region>
<region name="us-east">
<host name="my-firefox33-hub-2.example.com" port="4444" count="5"/>
</region>
</version>
<version number="37.0">
<region name="us-west">
<host name="my-firefox37-hub-1.example.com" port="4444" count="3"/>
<host name="my-firefox37-hub-2.example.com" port="4444" count="4"/>
</region>
<region name="us-east">
<host name="my-firefox37-hub-3.example.com" port="4444" count="2"/>
</region>
</version>
</browser>
<browser name="chrome" defaultVersion="42.0">
<version number="42.0">
<region name="us-west">
<host name="my-chrome42-hub-1.example.com" port="4444" count="10"/>
</region>
<region name="us-east">
<host name="my-chrome42-hub-2.example.com" port="4444" count="10"/>
</region>
</version>
</browser>
</qa:browsers>
```
What we basically do in this file - we enumerate hub hosts, ports and counts of browsers available on each hub. We also distribute hosts across regions, i.e. we place hosts from different datacenters in different **<region>** tags. The most important thing is to make sure that browser name and browser version have **exactly** the same value as respective Selenium hub does.
### Authentication
Grid router is using [BASIC HTTP authentication](https://en.wikipedia.org/wiki/Basic_access_authentication). That means that for the majority of test frameworks connection URL would be:
```
http://username:password@grid-router-host.example.com:4444/wd/hub
```
However some Javascript test frameworks have their own ways to specify connection URL, user name and password.
### Hub selection logic
When you request a browser by specifying its name and version **Grid Router** does the following:
1. Searches for the browser in user quota XML and returns error if not found
2. Randomly selects a host from all hosts and tries to obtain browser on that host. Our algorithm also considers browser counts specified in XML for each host so that hosts with more browsers get more connections.
3. If browser was obtained - returns it to the user and proxies all requests in this session to the same host
4. If not - selects a new host **from another region** and tries again. This guarantees that when one datacenter goes down in most of cases we'll obtain browser at worst after the second attempt.
5. After trying all hosts returns error if no browser was obtained
### Hub configuration recommendations
Our experience shows that Grid Router works better with a big set of "small" hubs (having no more than 5 connected nodes) than with some "big" hubs. A good idea is to launch small virtual machines (with 1 or 2 virtual CPUs) containing one Selenium hub process 4-5 Selenium node processes that connect to **localhost**. This gives us the following profit:
* Because we have more hubs the probability to successfully obtain browser is greater
* If each virtual machine has only one browser version installed - it's simpler to increase overall count of available browsers
* Hubs with small count of connected nodes perform better
## Development
We're using [Docker](https://www.docker.com/) and [Ansible](http://www.ansible.com/) for integration tests so you need to install them on your Mac or Linux.
### Install Boot2docker (dog-nail for Mac users)
* Install Ansible: `brew install ansible`
* Create an empty inventory file: `touch /usr/local/etc/ansible/hosts`
* Adjust Python settings: `echo 'localhost ansible_python_interpreter=/usr/local/bin/python' >> /usr/local/etc/ansible/hosts`
* Instally Python from [official website](https://www.python.org/ftp/python/2.7.10/python-2.7.10-macosx10.6.pkg)
* Install requests with pip: `pip install requests[security]`
* Install docker-py: `pip install -Iv https://pypi.python.org/packages/source/d/docker-py/docker-py-1.1.0.tar.gz`
* Run boot2docker: `boot2docker up`
* Get Docker VM IP: `boot2docker ip`
* Modify `/etc/hosts`: `<boot2docker_ip> boot2docker`
* Add certificates information to console: `$(boot2docker shellinit)`
* Export correct host name: `export DOCKER_HOST=tcp://boot2docker:2376`
### Running service locally
#### Start
1. Build project: `mvn clean package`
2. Start app: `ansible-playbook testing/start.yml`
3. Check that container is running: `docker ps -a`
#### Run integration tests
```bash]
$ ansible-playbook testing/test.yml
```
#### Stop
```bash
$ ansible-playbook testing/stop.yml
```
================================================
FILE: ci/jenkins.groovy
================================================
def project = 'gridrouter';
def repo = 'seleniumkit/gridrouter'
def buildWarJob = mavenJob("${project}_build-war")
def e2eTestsJob = job("${project}_e2e-tests")
def sonarJob = mavenJob("${project}_sonar")
def sonarIncrJob = mavenJob("${project}_sonar-incr")
def deployJob = mavenJob("${project}_deploy")
def pullRequestJob = multiJob("${project}_pull-reqest_flow")
def snapshotJob = multiJob("${project}_snapshot_flow")
def releaseJob = mavenJob("${project}_release_flow")
buildWarJob.with {
label('maven')
scm {
git {
remote {
github(repo, 'https', 'github.com')
refspec('${GIT_REFSPEC}')
}
branch('${GIT_COMMIT}')
localBranch('master')
}
}
goals('clean package')
publishers {
archiveArtifacts('proxy/target/*.war')
}
}
e2eTestsJob.with {
label('e2e')
scm {
git {
remote {
github(repo, 'https', 'github.com')
refspec('${GIT_REFSPEC}')
}
branch('${GIT_COMMIT}')
localBranch('master')
}
}
steps {
copyArtifacts(buildWarJob.name) {
includePatterns('proxy/target/*.war')
buildSelector {
buildNumber('${WAR_BUILD_NUMBER}')
}
}
shell('ansible-playbook -e "workspace=/tmp/e2e/${JOB_NAME}/${BUILD_NUMBER}" testing/start.yml')
shell('ansible-playbook -e "workspace=/tmp/e2e/${JOB_NAME}/${BUILD_NUMBER}" testing/test.yml')
shell('ansible-playbook -e "workspace=/tmp/e2e/${JOB_NAME}/${BUILD_NUMBER}" testing/stop.yml')
}
publishers {
archiveJunit('testing/target/surefire-reports/*.xml')
}
}
sonarJob.with {
label('maven')
scm {
git {
remote {
github(repo, 'https', 'github.com')
refspec('${GIT_REFSPEC}')
}
branch('${GIT_COMMIT}')
localBranch('master')
}
}
publishers {
sonar()
}
}
sonarIncrJob.with {
label('maven')
scm {
git {
remote {
github(repo, 'https', 'github.com')
refspec('${GIT_REFSPEC}')
}
branch('${GIT_COMMIT}')
localBranch('master')
}
}
configure {
it / 'publishers' / 'hudson.plugins.sonar.SonarPublisher' {
jdk('(Inherit From Job)')
branch()
language()
jobAdditionalProperties('-Dsonar.analysis.mode=incremental -Dsonar.github.pullRequest=${ghprbPullId} -Dsonar.github.repository=' + repo)
settings(class: 'jenkins.mvn.DefaultSettingsProvider')
globalSettings(class: 'jenkins.mvn.DefaultGlobalSettingsProvider')
usePrivateRepository(false)
}
}
}
deployJob.with {
label('maven')
scm {
git {
remote {
github(repo, 'https', 'github.com')
refspec('${GIT_REFSPEC}')
}
branch('${GIT_COMMIT}')
localBranch('master')
}
}
goals('clean deploy')
}
pullRequestJob.with {
label('master')
displayName('Grid Router Pull Requests Flow')
scm {
git {
remote {
github(repo, 'https', 'github.com')
refspec('+refs/pull/*:refs/remotes/origin/pr/*')
}
branch('${sha1}')
}
}
triggers {
pullRequest {
orgWhitelist(['seleniumkit'])
permitAll()
useGitHubHooks()
}
}
steps {
phase('Build war file') {
job(sonarIncrJob.name) {
prop('GIT_REFSPEC', '+refs/pull/*:refs/remotes/origin/pr/*');
prop('GIT_COMMIT', '\${sha1}');
}
job(buildWarJob.name) {
prop('GIT_REFSPEC', '+refs/pull/*:refs/remotes/origin/pr/*');
prop('GIT_COMMIT', '\${sha1}');
}
}
phase('Run e2e tests', 'UNSTABLE') {
job(e2eTestsJob.name) {
prop('WAR_BUILD_NUMBER', '\${' + buildWarJob.name.toUpperCase().replace("-", "_") + '_BUILD_NUMBER}');
prop('GIT_REFSPEC', '+refs/pull/*:refs/remotes/origin/pr/*');
prop('GIT_COMMIT', '\${sha1}');
}
}
}
publishers {
aggregateDownstreamTestResults()
}
}
snapshotJob.with {
label('default')
displayName('Grid Router Snapshot Flow')
scm {
git {
remote {
github(repo, 'https', 'github.com')
}
localBranch('master')
branch('master')
}
}
triggers {
githubPush()
}
steps {
phase('Build war file') {
job(buildWarJob.name) {
prop('GIT_COMMIT', '\${GIT_COMMIT}');
prop('GIT_REFSPEC', '');
}
}
phase('Run e2e tests') {
job(e2eTestsJob.name) {
prop('WAR_BUILD_NUMBER', '\${' + buildWarJob.name.toUpperCase().replace("-", "_") + '_BUILD_NUMBER}');
prop('GIT_COMMIT', '\${GIT_COMMIT}');
prop('GIT_REFSPEC', '');
}
job(sonarJob.name) {
prop('GIT_COMMIT', '\${GIT_COMMIT}');
prop('GIT_REFSPEC', '');
}
}
phase('Deploy war') {
job(deployJob.name) {
prop('GIT_COMMIT', '\${GIT_COMMIT}');
prop('GIT_REFSPEC', '');
}
}
}
publishers {
aggregateDownstreamTestResults()
}
}
releaseJob.with {
label('maven')
displayName('Grid Router Release Flow')
scm {
git {
remote {
github(repo, 'https', 'github.com')
}
localBranch('master')
branch('master')
}
}
goals('clean deploy')
wrappers {
mavenRelease {
releaseGoals('release:clean release:prepare release:perform')
dryRunGoals('-DdryRun=true release:prepare')
numberOfReleaseBuildsToKeep(10)
}
}
}
listView(project) {
jobs {
regex("${project}_.*_flow")
}
columns {
status()
name()
lastSuccess()
lastFailure()
lastDuration()
buildButton()
}
}
================================================
FILE: config/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>ru.qatools.seleniumkit</groupId>
<artifactId>gridrouter</artifactId>
<version>1.32-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gridrouter-config</artifactId>
<name>Selenium Grid Router Config</name>
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<!-- Tests -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/GridRouterException.java
================================================
package ru.qatools.gridrouter.config;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class GridRouterException extends RuntimeException {
public GridRouterException(String message, Throwable cause) {
super(message, cause);
}
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/HostSelectionStrategy.java
================================================
package ru.qatools.gridrouter.config;
import java.util.List;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface HostSelectionStrategy {
Region selectRegion(List<Region> allRegions, List<Region> unvisitedRegions);
Host selectHost(List<Host> hosts);
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/RandomHostSelectionStrategy.java
================================================
package ru.qatools.gridrouter.config;
import java.util.ArrayList;
import java.util.List;
import static java.util.Collections.nCopies;
import static java.util.Collections.shuffle;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class RandomHostSelectionStrategy implements HostSelectionStrategy {
protected <T extends WithCount> T selectRandom(List<T> elements) {
List<T> copies = new ArrayList<>();
for (T element : elements) {
copies.addAll(nCopies(element.getCount(), element));
}
shuffle(copies);
return copies.get(0);
}
@Override
public Region selectRegion(List<Region> allRegions, List<Region> unvisitedRegions) {
return selectRandom(unvisitedRegions);
}
@Override
public Host selectHost(List<Host> hosts) {
return selectRandom(hosts);
}
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/RegionWithCount.java
================================================
package ru.qatools.gridrouter.config;
import java.util.List;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface RegionWithCount extends WithCount {
List<Host> getHosts();
@Override
default int getCount() {
return getHosts().stream().mapToInt(Host::getCount).sum();
}
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/SequentialHostSelectionStrategy.java
================================================
package ru.qatools.gridrouter.config;
import java.util.List;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class SequentialHostSelectionStrategy implements HostSelectionStrategy {
private int hostIndex;
@Override
public Region selectRegion(List<Region> allRegions, List<Region> unvisitedRegions) {
return unvisitedRegions.get(0);
}
@Override
public Host selectHost(List<Host> hosts) {
Host host = hosts.get(hostIndex++ % hosts.size());
hostIndex %= hosts.size();
return host;
}
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/VersionWithCount.java
================================================
package ru.qatools.gridrouter.config;
import java.util.List;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface VersionWithCount extends WithCount {
List<Region> getRegions();
@Override
default int getCount() {
return getRegions().stream().mapToInt(Region::getCount).sum();
}
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithBrowserVersionFind.java
================================================
package ru.qatools.gridrouter.config;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.isEmpty;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface WithBrowserVersionFind {
List<Browser> getBrowsers();
default Browser findBrowser(String name) {
return getBrowsers().stream()
.filter(b -> b.getName().equals(name))
.findFirst().orElse(null);
}
default Version find(String browserName, String browserVersion) {
Browser browser = findBrowser(browserName);
if (browser == null) {
return null;
}
return isEmpty(browserVersion) ?
browser.findDefaultVersion() :
browser.findVersion(browserVersion);
}
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithCopy.java
================================================
package ru.qatools.gridrouter.config;
import java.util.ArrayList;
import java.util.List;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface WithCopy {
List<Host> getHosts();
String getName();
/**
* Creates a copy for the {@link Region} object, which is almost deep:
* the hosts itself are not copied although the list is new.
*
* @return a copy of the object
*/
default Region copy() {
return new Region(new ArrayList<>(getHosts()), getName());
}
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithCount.java
================================================
package ru.qatools.gridrouter.config;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface WithCount {
int getCount();
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithRoute.java
================================================
package ru.qatools.gridrouter.config;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface WithRoute {
default String getAddress() {
return getName() + ":" + getPort();
}
default String getRoute() {
return "http://" + getAddress();
}
default String getRouteId() {
return DigestUtils.md5Hex(getRoute().getBytes(StandardCharsets.UTF_8));
}
String getName();
int getPort();
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithRoutesMap.java
================================================
package ru.qatools.gridrouter.config;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface WithRoutesMap {
List<Browser> getBrowsers();
default Map<String, String> getRoutesMap() {
HashMap<String, String> routes = new HashMap<>();
getBrowsers().stream()
.flatMap(b -> b.getVersions().stream())
.flatMap(v -> v.getRegions().stream())
.flatMap(r -> r.getHosts().stream())
.forEach(h -> routes.put(h.getRouteId(), h.getRoute()));
return routes;
}
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithVersionFind.java
================================================
package ru.qatools.gridrouter.config;
import java.util.List;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface WithVersionFind {
default Version findDefaultVersion() {
return findVersion(getDefaultVersion());
}
default Version findVersion(String versionPrefix) {
return getVersions().stream()
.filter(v -> v.getNumber().startsWith(versionPrefix))
.findFirst().orElse(null);
}
List<Version> getVersions();
String getDefaultVersion();
}
================================================
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithXmlView.java
================================================
package ru.qatools.gridrouter.config;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.StringWriter;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.xml.bind.Marshaller.JAXB_ENCODING;
import static javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT;
/**
* @author Dmitry Baev charlie@yandex-team.ru
*/
public interface WithXmlView {
default String toXml() {
try {
JAXBContext context = JAXBContext.newInstance(getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(JAXB_ENCODING, UTF_8.toString());
marshaller.setProperty(JAXB_FORMATTED_OUTPUT, true);
StringWriter writer = new StringWriter();
marshaller.marshal(this, writer);
return writer.toString();
} catch (JAXBException e) {
throw new GridRouterException("Unable to marshall bean", e);
}
}
}
================================================
FILE: config/src/main/resources/xsd/bindings.xjb
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_1.xsd"
xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
jaxb:extensionBindingPrefixes="xjc annox"
schemaLocation="config.xsd"
version="2.1">
<jaxb:bindings node="//xs:complexType[@name='Browsers']">
<inheritance:implements>ru.qatools.gridrouter.config.WithBrowserVersionFind</inheritance:implements>
<inheritance:implements>ru.qatools.gridrouter.config.WithXmlView</inheritance:implements>
<inheritance:implements>ru.qatools.gridrouter.config.WithRoutesMap</inheritance:implements>
</jaxb:bindings>
<jaxb:bindings node="//xs:complexType[@name='Browser']">
<inheritance:implements>ru.qatools.gridrouter.config.WithVersionFind</inheritance:implements>
</jaxb:bindings>
<jaxb:bindings node="//xs:complexType[@name='Version']">
<inheritance:implements>ru.qatools.gridrouter.config.VersionWithCount</inheritance:implements>
</jaxb:bindings>
<jaxb:bindings node="//xs:complexType[@name='Region']">
<inheritance:implements>ru.qatools.gridrouter.config.WithCopy</inheritance:implements>
<inheritance:implements>ru.qatools.gridrouter.config.RegionWithCount</inheritance:implements>
</jaxb:bindings>
<jaxb:bindings node="//xs:complexType[@name='Host']">
<inheritance:implements>ru.qatools.gridrouter.config.WithRoute</inheritance:implements>
<inheritance:implements>ru.qatools.gridrouter.config.WithCount</inheritance:implements>
</jaxb:bindings>
<jaxb:globalBindings>
<jaxb:serializable/>
<xjc:simple/>
</jaxb:globalBindings>
</jaxb:bindings>
================================================
FILE: config/src/main/resources/xsd/config.xsd
================================================
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:qa="urn:config.gridrouter.qatools.ru"
targetNamespace="urn:config.gridrouter.qatools.ru">
<xsd:element name="browsers" type="qa:Browsers"/>
<xsd:complexType name="Browsers">
<xsd:sequence>
<xsd:element name="browser" type="qa:Browser" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Browser">
<xsd:sequence>
<xsd:element name="version" type="qa:Version" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="defaultVersion" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="Version">
<xsd:sequence>
<xsd:element name="region" type="qa:Region" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="number" type="xsd:string" use="required"/>
<xsd:attribute name="permittedCount" type="xsd:int" use="optional"/>
</xsd:complexType>
<xsd:complexType name="Region">
<xsd:sequence>
<xsd:element name="host" type="qa:Host" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="Host">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="port" type="xsd:int" use="required"/>
<xsd:attribute name="count" type="xsd:int" use="required"/>
</xsd:complexType>
</xsd:schema>
================================================
FILE: config/src/test/java/ru/qatools/gridrouter/config/RandomHostSelectionStrategyTest.java
================================================
package ru.qatools.gridrouter.config;
import org.hamcrest.Matcher;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.both;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.lessThan;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class RandomHostSelectionStrategyTest {
private static final double ALLOWED_DEVIATION = 0.01;
@Test
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
public void testRandomness() {
int entriesCount = 5000000;
int keysCount = 10;
Host host1 = new Host("host_1", 4444, keysCount - 1);
List<Host> hosts = new ArrayList<>(keysCount);
hosts.add(host1);
int i = keysCount;
while (i --> 1) {
hosts.add(newHost());
}
HashMap<Host, Integer> appearances = new HashMap<>(keysCount, entriesCount / keysCount);
RandomHostSelectionStrategy strategy = new RandomHostSelectionStrategy();
i = entriesCount;
while (i-- > 0) {
Host host = strategy.selectRandom(hosts);
appearances.put(host, Optional.ofNullable(appearances.get(host)).orElse(0) + 1);
}
assertThat(appearances.remove(host1), isAround(entriesCount / 2));
for (int count : appearances.values()) {
assertThat(count, isAround(entriesCount / 2 / (keysCount - 1)));
}
}
private static Host newHost() {
return new Host(UUID.randomUUID().toString(), 4444, 1);
}
private static Matcher<Integer> isAround(int count) {
return both(greaterThan(
(int) (count * (1 - ALLOWED_DEVIATION))
)).and(lessThan(
(int) (count * (1 + ALLOWED_DEVIATION))
));
}
}
================================================
FILE: pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>9</version>
</parent>
<groupId>ru.qatools.seleniumkit</groupId>
<artifactId>gridrouter</artifactId>
<version>1.32-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>config</module>
<module>proxy</module>
</modules>
<name>Selenium Grid Router</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring.version>4.1.6.RELEASE</spring.version>
<jetty.version>9.3.6.v20151106</jetty.version>
<jackson.version>2.6.0-rc3</jackson.version>
<slf4j.version>1.7.7</slf4j.version>
</properties>
<organization>
<name>Yandex</name>
<url>http://yandex.ru/</url>
</organization>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<connection>scm:git:git@github.com:seleniumkit/gridrouter.git</connection>
<developerConnection>scm:git:git@github.com:seleniumkit/gridrouter.git</developerConnection>
<url>https://github.com/seleniumkit/gridrouter</url>
<tag>HEAD</tag>
</scm>
<issueManagement>
<system>GitHub Issues</system>
<url>https://github.com/seleniumkit/gridrouter/issues</url>
</issueManagement>
<ciManagement>
<system>Jenkins</system>
<url>http://ci.qatools.ru/</url>
</ciManagement>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
<configuration>
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<tagNameFormat>@{project.version}</tagNameFormat>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<bindingDirectory>src/main/resources/xsd</bindingDirectory>
<schemaDirectory>src/main/resources/xsd</schemaDirectory>
<removeOldOutput>true</removeOldOutput>
<readOnly>true</readOnly>
<verbose>true</verbose>
<args>
<arg>-Xinheritance</arg>
<arg>-Xvalue-constructor</arg>
</args>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-basics</artifactId>
<version>0.9.4</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-value-constructor</artifactId>
<version>3.0</version>
</plugin>
</plugins>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
================================================
FILE: proxy/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>ru.qatools.seleniumkit</groupId>
<artifactId>gridrouter</artifactId>
<version>1.32-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gridrouter-proxy</artifactId>
<name>Selenium Grid Router Proxy</name>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>ru.qatools.seleniumkit</groupId>
<artifactId>gridrouter-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.beanloader</groupId>
<artifactId>beanloader</artifactId>
<version>2.1</version>
</dependency>
<!-- Commons -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Jetty -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-proxy</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-annotations</artifactId>
<version>${jetty.version}</version>
<scope>test</scope>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- Http Client -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Tests -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>3.9.17</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20140107</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.53.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ru.yandex.qatools.matchers</groupId>
<artifactId>matcher-decorators</artifactId>
<version>1.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/ConfigRepository.java
================================================
package ru.qatools.gridrouter;
import ru.qatools.gridrouter.config.Browser;
import ru.qatools.gridrouter.config.Browsers;
import ru.qatools.gridrouter.config.Version;
import ru.qatools.gridrouter.json.JsonCapabilities;
import java.util.HashMap;
import java.util.Map;
/**
* @author Ilya Sadykov
*/
public interface ConfigRepository {
Map<String, Browsers> getQuotaMap();
String getRoute(String routeId);
default Version findVersion(String user, JsonCapabilities caps) {
final Browsers browsers = getQuotaMap().get(user);
return browsers != null ? browsers.find(caps.getBrowserName(), caps.getVersion()) : null;
}
default Map<String, Integer> getBrowsersCountMap(String user) {
HashMap<String, Integer> countMap = new HashMap<>();
for (Browser browser : getQuotaMap().get(user).getBrowsers()) {
for (Version version : browser.getVersions()) {
countMap.put(browser.getName() + ":" + version.getNumber(), version.getCount());
}
}
return countMap;
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/ConfigRepositoryXml.java
================================================
package ru.qatools.gridrouter;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import ru.qatools.beanloader.BeanChangeListener;
import ru.qatools.beanloader.BeanLoader;
import ru.qatools.beanloader.BeanWatcher;
import ru.qatools.gridrouter.config.Browsers;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
/**
* @author Alexander Andyashin aandryashin@yandex-team.ru
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class ConfigRepositoryXml implements ConfigRepository, BeanChangeListener<Browsers> {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigRepositoryXml.class);
private static final String XML_GLOB = "*.xml";
@Value("${grid.config.quota.directory}")
private File quotaDirectory;
@Value("${grid.config.quota.hotReload}")
private boolean quotaHotReload;
private Map<String, Browsers> userBrowsers = new HashMap<>();
private Map<String, String> routes = new HashMap<>();
@PostConstruct
public void init() {
try {
if (quotaHotReload) {
LOGGER.debug("Starting quota watcher");
BeanWatcher.watchFor(Browsers.class, quotaDirectory.toPath(), XML_GLOB, this);
} else {
LOGGER.debug("Loading quota configuration");
BeanLoader.loadAll(Browsers.class, quotaDirectory.toPath(), XML_GLOB, this);
}
} catch (IOException e) {
LOGGER.error("Quota configuration loading failed", e);
}
}
@Override
public void beanChanged(Path filename, Browsers browsers) {
if (browsers == null) {
LOGGER.info("Configuration file [{}] was deleted. "
+ "It is not purged from the running gridrouter process though.", filename);
} else {
LOGGER.info("Loading quota configuration file [{}]", filename);
String user = FilenameUtils.getBaseName(filename.toString());
userBrowsers.put(user, browsers);
routes.putAll(browsers.getRoutesMap());
LOGGER.info("Loaded quota configuration for [{}] from [{}]: \n\n{}",
user, filename, browsers.toXml());
}
}
@Override
public Map<String, Browsers> getQuotaMap() {
return userBrowsers;
}
@Override
public String getRoute(String routeId) {
return routes.get(routeId);
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/JsonWireUtils.java
================================================
package ru.qatools.gridrouter;
import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.http.HttpMethod.DELETE;
/**
* @author Alexander Andyashin aandryashin@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
* @author Dmitry Baev charlie@yandex-team.ru
* @author Artem Eroshenko eroshenkoam@yandex-team.ru
*/
public final class JsonWireUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(JsonWireUtils.class);
public static final String WD_HUB_SESSION = "/wd/hub/session/";
public static final int SESSION_HASH_LENGTH = 32;
private JsonWireUtils() {
}
public static boolean isUriValid(String uri) {
return uri.length() > getUriPrefixLength();
}
public static boolean isSessionDeleteRequest(HttpServletRequest request, String command) {
return DELETE.name().equalsIgnoreCase(request.getMethod()) && !command.contains("/");
}
public static String getSessionHash(String uri) {
return uri.substring(WD_HUB_SESSION.length(), getUriPrefixLength());
}
public static String getFullSessionId(String uri) {
String tail = uri.substring(WD_HUB_SESSION.length());
int end = tail.indexOf('/');
if (end < 0) {
return tail;
}
return tail.substring(0, end);
}
public static int getUriPrefixLength() {
return WD_HUB_SESSION.length() + SESSION_HASH_LENGTH;
}
public static String redirectionUrl(String host, String command) throws URISyntaxException {
return new URIBuilder(host).setPath(WD_HUB_SESSION + command).build().toString();
}
public static String getCommand(String uri) {
String encodedCommand = uri.substring(getUriPrefixLength());
try {
return URLDecoder.decode(encodedCommand, UTF_8.name());
} catch (UnsupportedEncodingException e) {
LOGGER.error("[UNABLE_TO_DECODE_COMMAND] - could not decode command: {}", encodedCommand, e);
return encodedCommand;
}
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/PingServlet.java
================================================
package ru.qatools.gridrouter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author Alexander Andyashin aandryashin@yandex-team.ru
* @author Artem Eroshenko eroshenkoam@yandex-team.ru
* @author Dmitry Baev charlie@yandex-team.ru
*/
@WebServlet(urlPatterns = {"/ping"}, asyncSupported = true)
public class PingServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try (PrintWriter writer = resp.getWriter()) {
writer.print("OK");
writer.flush();
}
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/ProxyServlet.java
================================================
package ru.qatools.gridrouter;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ru.qatools.gridrouter.json.JsonMessage;
import ru.qatools.gridrouter.json.JsonMessageFactory;
import ru.qatools.gridrouter.sessions.StatsCounter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.web.context.support.SpringBeanAutowiringSupport.processInjectionBasedOnServletContext;
import static ru.qatools.gridrouter.JsonWireUtils.*;
import static ru.qatools.gridrouter.RequestUtils.getRemoteHost;
/**
* @author Alexander Andyashin aandryashin@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
* @author Dmitry Baev charlie@yandex-team.ru
* @author Artem Eroshenko eroshenkoam@yandex-team.ru
*/
@WebServlet(
urlPatterns = {WD_HUB_SESSION + "*"},
asyncSupported = true,
initParams = {
@WebInitParam(name = "timeout", value = "300000"),
@WebInitParam(name = "idleTimeout", value = "300000")
}
)
public class ProxyServlet extends org.eclipse.jetty.proxy.ProxyServlet {
private static final Logger LOGGER = LoggerFactory.getLogger(ProxyServlet.class);
@Autowired
private transient ConfigRepository config;
@Autowired
private transient StatsCounter statsCounter;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
processInjectionBasedOnServletContext(this, config.getServletContext());
}
@Override
protected void sendProxyRequest(
HttpServletRequest clientRequest, HttpServletResponse proxyResponse, Request proxyRequest) {
try {
Request request = getRequestWithoutSessionId(clientRequest, proxyRequest);
super.sendProxyRequest(clientRequest, proxyResponse, request);
} catch (Exception exception) {
LOGGER.error("[REQUEST_READ_FAILURE] [{}] - could not read client request, proxying request as is",
clientRequest.getRemoteHost(), exception);
super.sendProxyRequest(clientRequest, proxyResponse, proxyRequest);
}
}
@Override
protected String rewriteTarget(HttpServletRequest request) {
String uri = request.getRequestURI();
String remoteHost = getRemoteHost(request);
if (!isUriValid(uri)) {
LOGGER.warn("[INVALID_SESSION_HASH] [{}] - request uri is {}", remoteHost, uri);
return null;
}
String route = config.getRoute(getSessionHash(uri));
String command = getCommand(uri);
if (route == null) {
LOGGER.error("[ROUTE_NOT_FOUND] [{}] - request uri is {}", remoteHost, uri);
return null;
}
if (isSessionDeleteRequest(request, command)) {
LOGGER.info("[SESSION_DELETED] [{}] [{}] [{}]", remoteHost, route, command);
statsCounter.deleteSession(getFullSessionId(uri), route);
} else {
statsCounter.updateSession(getFullSessionId(uri), route);
}
try {
return redirectionUrl(route, command);
} catch (Exception exception) {
LOGGER.error("[REDIRECTION_URL_ERROR] [{}] - error building redirection uri because of {}\n"
+ " request uri: {}\n"
+ " parsed route: {}\n"
+ " parsed command: {}",
remoteHost, exception.toString(), uri, route, command);
}
return null;
}
protected Request getRequestWithoutSessionId(HttpServletRequest clientRequest, Request proxyRequest) throws IOException {
String content = IOUtils.toString(clientRequest.getInputStream(), UTF_8);
if (!content.isEmpty()) {
String remoteHost = getRemoteHost(clientRequest);
content = removeSessionIdSafe(content, remoteHost);
}
return proxyRequest.content(
new StringContentProvider(clientRequest.getContentType(), content, UTF_8));
}
private String removeSessionIdSafe(String content, String remoteHost) {
try {
JsonMessage message = JsonMessageFactory.from(content);
message.setSessionId(null);
return message.toJson();
} catch (IOException exception) {
LOGGER.error("[UNABLE_TO_REMOVE_SESSION_ID] [{}] - could not create proxy request without session id, "
+ "proxying request as is. Request content is: {}",
remoteHost, content, exception);
}
return content;
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/QuotaServlet.java
================================================
package ru.qatools.gridrouter;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.ServletException;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static ru.qatools.gridrouter.json.JsonFormatter.toJson;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
@WebServlet(urlPatterns = {"/quota"}, asyncSupported = true)
@ServletSecurity(value = @HttpConstraint(rolesAllowed = {"user"}))
public class QuotaServlet extends SpringHttpServlet {
@Autowired
private transient ConfigRepository config;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(SC_OK);
resp.setContentType(APPLICATION_JSON_VALUE);
try (OutputStream output = resp.getOutputStream()) {
String jsonResponse = toJson(config.getBrowsersCountMap(req.getRemoteUser()));
IOUtils.write(jsonResponse, output, UTF_8);
}
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/RequestUtils.java
================================================
package ru.qatools.gridrouter;
import javax.servlet.http.HttpServletRequest;
public final class RequestUtils {
private static final String X_FORWARDED_FOR = "X-Forwarded-For";
public static String getRemoteHost(HttpServletRequest request) {
String remoteHost = request.getHeader(X_FORWARDED_FOR);
if (remoteHost == null) {
return request.getRemoteHost();
}
return remoteHost;
}
private RequestUtils(){}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/RouteServlet.java
================================================
package ru.qatools.gridrouter;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import ru.qatools.gridrouter.caps.CapabilityProcessorFactory;
import ru.qatools.gridrouter.config.Host;
import ru.qatools.gridrouter.config.HostSelectionStrategy;
import ru.qatools.gridrouter.config.Region;
import ru.qatools.gridrouter.config.Version;
import ru.qatools.gridrouter.json.JsonCapabilities;
import ru.qatools.gridrouter.json.JsonMessage;
import ru.qatools.gridrouter.json.JsonMessageFactory;
import ru.qatools.gridrouter.sessions.AvailableBrowserCheckExeption;
import ru.qatools.gridrouter.sessions.AvailableBrowsersChecker;
import ru.qatools.gridrouter.sessions.StatsCounter;
import javax.servlet.ServletException;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.stream.Collectors.toList;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.apache.http.HttpHeaders.ACCEPT;
import static org.apache.http.entity.ContentType.APPLICATION_JSON;
import static ru.qatools.gridrouter.RequestUtils.getRemoteHost;
/**
* @author Alexander Andyashin aandryashin@yandex-team.ru
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
* @author Artem Eroshenko eroshenkoam@yandex-team.ru
*/
@WebServlet(urlPatterns = {"/wd/hub/session"}, asyncSupported = true)
@ServletSecurity(value = @HttpConstraint(rolesAllowed = {"user"}))
public class RouteServlet extends SpringHttpServlet {
private static final Logger LOGGER = LoggerFactory.getLogger(RouteServlet.class);
private static final String ROUTE_TIMEOUT_CAPABILITY = "grid.router.route.timeout.seconds";
private static final int MAX_ROUTE_TIMEOUT_SECONDS = 300;
@Autowired
private transient ConfigRepository config;
@Autowired
private transient HostSelectionStrategy hostSelectionStrategy;
@Autowired
private transient StatsCounter statsCounter;
@Autowired
private transient CapabilityProcessorFactory capabilityProcessorFactory;
@Autowired
private transient AvailableBrowsersChecker avblBrowsersChecker;
@Value("${grid.router.route.timeout.seconds:120}")
private int routeTimeout;
private AtomicLong requestCounter = new AtomicLong();
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
JsonMessage message = JsonMessageFactory.from(request.getInputStream());
long requestId = requestCounter.getAndIncrement();
int routeTimeout = getRouteTimeout(request.getRemoteUser(), message);
AtomicBoolean terminated = new AtomicBoolean(false);
executor.submit(getRouteCallable(request, message, response, requestId, routeTimeout, terminated));
executor.shutdown();
try {
executor.awaitTermination(routeTimeout, TimeUnit.SECONDS);
terminated.set(true);
} catch (InterruptedException e) {
executor.shutdownNow();
}
replyWithError("Timed out when searching for valid host", response);
}
private Callable<Object> getRouteCallable(HttpServletRequest request, JsonMessage message, HttpServletResponse response,
long requestId, int routeTimeout, AtomicBoolean terminated) {
return () -> {
route(request, message, response, requestId, routeTimeout, terminated);
return null;
};
}
private int getRouteTimeout(String user, JsonMessage message) {
JsonCapabilities caps = message.getDesiredCapabilities();
try {
if (caps.any().containsKey(ROUTE_TIMEOUT_CAPABILITY)) {
Integer desiredRouteTimeout = Integer.valueOf(String.valueOf(caps.any().get(ROUTE_TIMEOUT_CAPABILITY)));
routeTimeout = (desiredRouteTimeout < MAX_ROUTE_TIMEOUT_SECONDS) ?
desiredRouteTimeout :
MAX_ROUTE_TIMEOUT_SECONDS;
LOGGER.warn("[{}] [INVALID_ROUTE_TIMEOUT] [{}]", user, desiredRouteTimeout);
}
} catch (NumberFormatException ignored) {
}
return routeTimeout;
}
private void route(HttpServletRequest request, JsonMessage message,
HttpServletResponse response,
long requestId, int routeTimeout, AtomicBoolean terminated) throws IOException {
long initialSeconds = Instant.now().getEpochSecond();
JsonCapabilities caps = message.getDesiredCapabilities();
String user = request.getRemoteUser();
String remoteHost = getRemoteHost(request);
String browser = caps.describe();
Version actualVersion = config.findVersion(user, caps);
if (actualVersion == null) {
LOGGER.warn("[{}] [UNSUPPORTED_BROWSER] [{}] [{}] [{}]", requestId, user, remoteHost, browser);
replyWithError(format("Cannot find %s capabilities on any available node",
caps.describe()), response);
return;
}
caps.setVersion(actualVersion.getNumber());
capabilityProcessorFactory.getProcessor(caps).process(caps);
List<Region> allRegions = actualVersion.getRegions()
.stream().map(Region::copy).collect(toList());
List<Region> unvisitedRegions = new ArrayList<>(allRegions);
int attempt = 0;
JsonMessage hubMessage = null;
try (CloseableHttpClient client = newHttpClient(routeTimeout * 1000)) {
if (actualVersion.getPermittedCount() != null) {
avblBrowsersChecker.ensureFreeBrowsersAvailable(user, remoteHost, browser, actualVersion);
}
while (!allRegions.isEmpty() && !terminated.get()) {
attempt++;
Region currentRegion = hostSelectionStrategy.selectRegion(allRegions, unvisitedRegions);
Host host = hostSelectionStrategy.selectHost(currentRegion.getHosts());
String route = host.getRoute();
try {
LOGGER.info("[{}] [SESSION_ATTEMPTED] [{}] [{}] [{}] [{}] [{}]", requestId, user, remoteHost, browser, route, attempt);
String target = route + request.getRequestURI();
HttpResponse hubResponse = client.execute(post(target, message));
hubMessage = JsonMessageFactory.from(hubResponse.getEntity().getContent());
if (hubResponse.getStatusLine().getStatusCode() == SC_OK) {
String sessionId = hubMessage.getSessionId();
hubMessage.setSessionId(host.getRouteId() + sessionId);
replyWithOk(hubMessage, response);
long createdDurationSeconds = Instant.now().getEpochSecond() - initialSeconds;
LOGGER.info("[{}] [{}] [SESSION_CREATED] [{}] [{}] [{}] [{}] [{}] [{}]",
requestId, createdDurationSeconds, user, remoteHost, browser, route, sessionId, attempt);
statsCounter.startSession(hubMessage.getSessionId(), user, caps.getBrowserName(), actualVersion.getNumber(), route);
return;
}
LOGGER.warn("[{}] [SESSION_FAILED] [{}] [{}] [{}] [{}] - {}",
requestId, user, remoteHost, browser, route, hubMessage.getErrorMessage());
} catch (JsonProcessingException exception) {
LOGGER.error("[{}] [BAD_HUB_JSON] [{}] [{}] [{}] [{}] - {}", "",
requestId, user, remoteHost, browser, route, exception.getMessage());
} catch (IOException exception) {
LOGGER.error("[{}] [HUB_COMMUNICATION_FAILURE] [{}] [{}] [{}] - {}",
requestId, user, remoteHost, browser, route, exception.getMessage());
}
currentRegion.getHosts().remove(host);
if (currentRegion.getHosts().isEmpty()) {
allRegions.remove(currentRegion);
}
unvisitedRegions.remove(currentRegion);
if (unvisitedRegions.isEmpty()) {
unvisitedRegions = new ArrayList<>(allRegions);
}
}
} catch (AvailableBrowserCheckExeption e) {
LOGGER.error("[{}] [AVAILABLE_BROWSER_CHECK_ERROR] [{}] [{}] [{}] - {}",
requestId, user, remoteHost, browser, e.getMessage());
}
LOGGER.error("[{}] [SESSION_NOT_CREATED] [{}] [{}] [{}]", requestId, user, remoteHost, browser);
if (hubMessage == null) {
replyWithError("Cannot create session on any available node", response);
} else {
replyWithError(hubMessage, response);
}
}
protected void replyWithOk(JsonMessage message, HttpServletResponse response) throws IOException {
reply(SC_OK, message, response);
}
protected void replyWithError(String errorMessage, HttpServletResponse response) throws IOException {
replyWithError(JsonMessageFactory.error(13, errorMessage), response);
}
protected void replyWithError(JsonMessage message, HttpServletResponse response) throws IOException {
reply(SC_INTERNAL_SERVER_ERROR, message, response);
}
protected void reply(int code, JsonMessage message, HttpServletResponse response) throws IOException {
response.setStatus(code);
response.setContentType(APPLICATION_JSON.toString());
String messageRaw = message.toJson();
response.setContentLength(messageRaw.getBytes(UTF_8).length);
try (OutputStream output = response.getOutputStream()) {
IOUtils.write(messageRaw, output, UTF_8);
}
}
protected HttpPost post(String target, JsonMessage message) throws IOException {
HttpPost method = new HttpPost(target);
StringEntity entity = new StringEntity(message.toJson(), APPLICATION_JSON);
method.setEntity(entity);
method.setHeader(ACCEPT, APPLICATION_JSON.getMimeType());
return method;
}
protected CloseableHttpClient newHttpClient(int maxTimeout) {
return HttpClientBuilder.create().setDefaultRequestConfig(
RequestConfig.custom()
.setConnectionRequestTimeout(10000)
.setConnectTimeout(10000)
.setSocketTimeout(maxTimeout)
.build()
).setRedirectStrategy(new LaxRedirectStrategy()).disableAutomaticRetries().build();
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/SessionStorageEvictionScheduler.java
================================================
package ru.qatools.gridrouter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import ru.qatools.gridrouter.sessions.StatsCounter;
import java.time.Duration;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
@Configuration
@EnableScheduling
public class SessionStorageEvictionScheduler {
@Value("${grid.router.evict.sessions.timeout.seconds}")
private int timeout;
@Autowired
private StatsCounter statsCounter;
@Scheduled(cron = "${grid.router.evict.sessions.cron}")
public void expireOldSessions() {
statsCounter.expireSessionsOlderThan(Duration.ofSeconds(timeout));
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/SpringHttpServlet.java
================================================
package ru.qatools.gridrouter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import static org.springframework.web.context.support.SpringBeanAutowiringSupport.processInjectionBasedOnServletContext;
/**
* @author Ilya Sadykov
*/
public abstract class SpringHttpServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
processInjectionBasedOnServletContext(this, config.getServletContext());
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/StatsServlet.java
================================================
package ru.qatools.gridrouter;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import ru.qatools.gridrouter.json.JsonFormatter;
import ru.qatools.gridrouter.sessions.StatsCounter;
import javax.servlet.ServletException;
import javax.servlet.annotation.HttpConstraint;
import javax.servlet.annotation.ServletSecurity;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
/**
* @author Dmitry Baev charlie@yandex-team.ru
*/
@WebServlet(urlPatterns = {"/stats"}, asyncSupported = true)
@ServletSecurity(value = @HttpConstraint(rolesAllowed = {"user"}))
public class StatsServlet extends SpringHttpServlet {
@Autowired
private transient StatsCounter statsCounter;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setStatus(SC_OK);
response.setContentType(APPLICATION_JSON_VALUE);
try (OutputStream output = response.getOutputStream()) {
IOUtils.write(JsonFormatter.toJson(
statsCounter.getStats(request.getRemoteUser())
), output, UTF_8);
}
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/AppiumCapabilityProcessor.java
================================================
package ru.qatools.gridrouter.caps;
import org.springframework.stereotype.Service;
import ru.qatools.gridrouter.json.JsonCapabilities;
import java.util.Map;
/**
* <p>
* Sets "keepKeyChains" capability for Mac sessions.
* </p>
*
* @author Ivan Krutov vania-pooh@yandex-team.ru
*
*/
@SuppressWarnings("JavadocReference")
@Service
public class AppiumCapabilityProcessor implements CapabilityProcessor {
private static final String PLATFORM_NAME = "platformName";
private static final String IOS = "iOS";
@Override
public boolean accept(JsonCapabilities caps) {
return caps.getBrowserName().isEmpty() && isMac(caps);
}
@Override
public void process(JsonCapabilities caps) {
caps.any().put("keepKeyChains", true);
}
private boolean isMac(JsonCapabilities jsonCapabilities) {
Map<String, Object> capsMap = jsonCapabilities.any();
return
capsMap.containsKey(PLATFORM_NAME) &&
String.valueOf(capsMap.get(PLATFORM_NAME)).contains(IOS);
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/CapabilityProcessor.java
================================================
package ru.qatools.gridrouter.caps;
import ru.qatools.gridrouter.json.JsonCapabilities;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface CapabilityProcessor {
boolean accept(JsonCapabilities caps);
void process(JsonCapabilities caps);
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/CapabilityProcessorFactory.java
================================================
package ru.qatools.gridrouter.caps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ru.qatools.gridrouter.json.JsonCapabilities;
import java.util.List;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
@Component
public class CapabilityProcessorFactory {
@Autowired
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private List<CapabilityProcessor> processors;
public CapabilityProcessor getProcessor(JsonCapabilities caps) {
return processors.stream()
.filter(p -> p.accept(caps))
.findFirst()
.orElse(new DummyCapabilityProcessor());
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/DummyCapabilityProcessor.java
================================================
package ru.qatools.gridrouter.caps;
import ru.qatools.gridrouter.json.JsonCapabilities;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class DummyCapabilityProcessor implements CapabilityProcessor {
@Override
public boolean accept(JsonCapabilities caps) {
throw new UnsupportedOperationException("Method DummyCapabilityProcessor::accept should never be called");
}
@Override
public void process(JsonCapabilities caps) {
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/IECapabilityProcessor.java
================================================
package ru.qatools.gridrouter.caps;
import org.springframework.stereotype.Service;
import ru.qatools.gridrouter.json.JsonCapabilities;
import ru.qatools.gridrouter.json.Proxy;
/**
* <p>
* Sets "ie.ensureCleanSession" and "ie.usePerProcessProxy" for all new
* internet explorer sessions to ensure clean browser state.
* </p>
* <p>
* Apart from that it sets the "proxy" capability to
* {@link org.openqa.selenium.Proxy.ProxyType#DIRECT ProxyType.DIRECT}
* because explorers tend to reuse the proxy from the previous sessions.
* </p>
*
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
@SuppressWarnings("JavadocReference")
@Service
public class IECapabilityProcessor implements CapabilityProcessor {
private static final String IE_BROWSER_NAME = "internet explorer";
@Override
public boolean accept(JsonCapabilities caps) {
return caps.getBrowserName().equals(IE_BROWSER_NAME);
}
@Override
public void process(JsonCapabilities caps) {
caps.any().put("ie.ensureCleanSession", true);
caps.any().put("ie.usePerProcessProxy", true);
if (!caps.any().containsKey("proxy")) {
Proxy proxy = new Proxy();
proxy.setProxyType("DIRECT");
caps.any().put("proxy", proxy);
}
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/Describable.java
================================================
package ru.qatools.gridrouter.json;
import static org.apache.commons.lang3.StringUtils.isEmpty;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
* @author Dmitry Baev charlie@yandex-team.ru
*/
public interface Describable {
String getBrowserName();
String getVersion();
default String describe() {
return getBrowserName() + (isEmpty(getVersion()) ? "" : "-" + getVersion());
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/JsonFormatter.java
================================================
package ru.qatools.gridrouter.json;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class JsonFormatter {
public static String toJson(Object o) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return mapper.writeValueAsString(o);
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/JsonMessageFactory.java
================================================
package ru.qatools.gridrouter.json;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public final class JsonMessageFactory {
JsonMessageFactory() {
}
public static JsonMessage from(String content) throws IOException {
return new ObjectMapper().readValue(content, JsonMessage.class);
}
public static JsonMessage from(InputStream stream) throws IOException {
return new ObjectMapper().readValue(stream, JsonMessage.class);
}
public static JsonMessage error(int status, String errorMessage) {
JsonMessage message = new JsonMessage();
message.setStatus(status);
message.setErrorMessage(errorMessage);
return message;
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/JsonWithAnyProperties.java
================================================
package ru.qatools.gridrouter.json;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import java.util.HashMap;
import java.util.Map;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public abstract class JsonWithAnyProperties {
private Map<String, Object> otherProperties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> any() {
return otherProperties;
}
@JsonAnySetter
public void set(String name, Object value) {
otherProperties.put(name, value);
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/WithErrorMessage.java
================================================
package ru.qatools.gridrouter.json;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.IOException;
import java.util.Map;
import static java.util.Collections.emptyMap;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface WithErrorMessage {
String VALUE_KEY = "value";
String MESSAGE_KEY = "message";
String DEFAULT_ERROR_MESSAGE = "no error message was provided from hub";
Map<String, Object> any();
void set(String name, Object value);
@JsonIgnore
@SuppressWarnings("unchecked")
default String getErrorMessage() throws IOException {
try {
return (String) ((Map<String, Object>)
any().getOrDefault(VALUE_KEY, emptyMap()))
.getOrDefault(MESSAGE_KEY, DEFAULT_ERROR_MESSAGE);
} catch (ClassCastException ignored) {
return DEFAULT_ERROR_MESSAGE;
}
}
@JsonIgnore
default void setErrorMessage(String message) {
JsonValue value = new JsonValue();
value.setMessage(message);
set(VALUE_KEY, value);
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/WithJsonView.java
================================================
package ru.qatools.gridrouter.json;
import com.fasterxml.jackson.core.JsonProcessingException;
/**
* @author Dmitry Baev charlie@yandex-team.ru
*/
public interface WithJsonView {
default String toJson() throws JsonProcessingException {
return JsonFormatter.toJson(this);
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/AvailableBrowserCheckExeption.java
================================================
package ru.qatools.gridrouter.sessions;
/**
* @author Ilya Sadykov
*/
public class AvailableBrowserCheckExeption extends RuntimeException {
public AvailableBrowserCheckExeption(String message) {
super(message);
}
public AvailableBrowserCheckExeption(String message, Throwable cause) {
super(message, cause);
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/AvailableBrowsersChecker.java
================================================
package ru.qatools.gridrouter.sessions;
import ru.qatools.gridrouter.config.Version;
/**
* @author Ilya Sadykov
*/
public interface AvailableBrowsersChecker {
/**
* Blocks or throws an exception if there is no browsers available for user
*/
void ensureFreeBrowsersAvailable(String user, String remoteHost, String browser, Version actualVersion);
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/BrowserVersion.java
================================================
package ru.qatools.gridrouter.sessions;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class BrowserVersion {
private final String browser;
private final String version;
public BrowserVersion(String browser, String version) {
this.browser = browser;
this.version = version;
}
public String getBrowser() {
return browser;
}
public String getVersion() {
return version;
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/BrowsersCountMap.java
================================================
package ru.qatools.gridrouter.sessions;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class BrowsersCountMap extends HashMap<String, Map<String, Integer>> implements GridRouterUserStats {
public void increment(String browser, String version) {
putIfAbsent(browser, new HashMap<>());
get(browser).compute(version, (v, count) -> Optional.ofNullable(count).orElse(0) + 1);
}
public void decrement(BrowserVersion browser) {
decrement(browser.getBrowser(), browser.getVersion());
}
public void decrement(String browser, String version) {
if (!containsKey(browser)) {
return;
}
Map<String, Integer> versions = get(browser);
if (!versions.containsKey(version)) {
return;
}
int count = versions.get(version) - 1;
if (count > 0) {
versions.put(version, count);
} else {
versions.remove(version);
}
if (versions.isEmpty()) {
remove(browser);
}
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/GridRouterUserStats.java
================================================
package ru.qatools.gridrouter.sessions;
import java.io.Serializable;
/**
* @author Ilya Sadykov
*/
public interface GridRouterUserStats extends Serializable {
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/MemoryStatsCounter.java
================================================
package ru.qatools.gridrouter.sessions;
import java.time.Duration;
import java.time.temporal.Temporal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static java.time.ZonedDateTime.now;
import static java.util.stream.Collectors.toList;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class MemoryStatsCounter implements StatsCounter {
private final Map<String, Temporal> session2instant = new HashMap<>();
private final Map<String, String> session2user = new HashMap<>();
private final Map<String, BrowserVersion> session2browserVersion = new HashMap<>();
private final Map<String, BrowsersCountMap> user2browserCount = new HashMap<>();
@Override
public synchronized void startSession(String sessionId, String user, String browser, String version, String route) {
if (session2instant.put(sessionId, now()) == null) {
session2user.put(sessionId, user);
session2browserVersion.put(sessionId, new BrowserVersion(browser, version));
user2browserCount.putIfAbsent(user, new BrowsersCountMap());
user2browserCount.get(user).increment(browser, version);
}
}
@Override
public void updateSession(String sessionId, String route) {
session2instant.replace(sessionId, now());
}
@Override
public synchronized void deleteSession(String sessionId, String route) {
if (session2instant.remove(sessionId) != null) {
String user = session2user.remove(sessionId);
BrowserVersion browser = session2browserVersion.remove(sessionId);
user2browserCount.get(user).decrement(browser);
}
}
@Override
public void expireSessionsOlderThan(Duration duration) {
List<String> sessions2delete = session2instant.entrySet().stream()
.filter(e -> duration.compareTo(Duration.between(e.getValue(), now())) < 0)
.map(Map.Entry::getKey)
.collect(toList());
sessions2delete.stream().forEach(this::deleteSession);
}
@Override
public Set<String> getActiveSessions() {
return session2instant.keySet();
}
@Override
public synchronized BrowsersCountMap getStats(String user) {
return user2browserCount.getOrDefault(user, new BrowsersCountMap());
}
@Override
public int getSessionsCountForUser(String user) {
return user2browserCount.getOrDefault(user, new BrowsersCountMap()).values()
.parallelStream().flatMapToInt(version -> version.values().stream().mapToInt(Integer::intValue))
.sum();
}
@Override
public int getSessionsCountForUserAndBrowser(String user, String browser, String version) {
return user2browserCount.getOrDefault(user, new BrowsersCountMap()).entrySet()
.parallelStream().filter(entry -> entry.getKey().equals(browser))
.flatMapToInt(entry -> entry.getValue().entrySet().parallelStream()
.filter(ver -> ver.getKey().equals(version)).mapToInt(Map.Entry::getValue)
).sum();
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/SkipAvailableBrowsersChecker.java
================================================
package ru.qatools.gridrouter.sessions;
import ru.qatools.gridrouter.config.Version;
/**
* @author Ilya Sadykov
*/
public class SkipAvailableBrowsersChecker implements AvailableBrowsersChecker {
@Override
public void ensureFreeBrowsersAvailable(String user, String remoteHost, String browser, Version actualVersion) {
// do nothing
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/StatsCounter.java
================================================
package ru.qatools.gridrouter.sessions;
import java.time.Duration;
import java.util.Set;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public interface StatsCounter {
default void startSession(String sessionId, String user, String browser, String version) {
startSession(sessionId, user, browser, version, null);
}
default void updateSession(String sessionId) {
updateSession(sessionId, null);
}
default void deleteSession(String sessionId) {
deleteSession(sessionId, null);
}
void startSession(String sessionId, String user, String browser, String version, String route);
default void updateSession(String sessionId, String route) {
}
void deleteSession(String sessionId, String route);
void expireSessionsOlderThan(Duration duration);
Set<String> getActiveSessions();
GridRouterUserStats getStats(String user);
int getSessionsCountForUser(String user);
int getSessionsCountForUserAndBrowser(String user, String browser, String version);
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowserTimeoutException.java
================================================
package ru.qatools.gridrouter.sessions;
/**
* @author Ilya Sadykov
*/
public class WaitAvailableBrowserTimeoutException extends AvailableBrowserCheckExeption {
public WaitAvailableBrowserTimeoutException(String message) {
super(message);
}
public WaitAvailableBrowserTimeoutException(String message, Throwable cause) {
super(message, cause);
}
}
================================================
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowsersChecker.java
================================================
package ru.qatools.gridrouter.sessions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import ru.qatools.gridrouter.config.Version;
import java.time.Duration;
import java.time.temporal.Temporal;
import static java.lang.String.format;
import static java.time.ZonedDateTime.now;
import static java.util.UUID.randomUUID;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* @author Ilya Sadykov
*/
public class WaitAvailableBrowsersChecker implements AvailableBrowsersChecker {
private static final Logger LOGGER = LoggerFactory.getLogger(WaitAvailableBrowsersChecker.class);
@Value("${grid.router.queue.interval.seconds}")
protected int queueWaitInterval;
@Autowired
protected StatsCounter statsCounter;
@Value("${grid.router.queue.timeout.seconds}")
protected int queueTimeout;
public WaitAvailableBrowsersChecker() {
}
public WaitAvailableBrowsersChecker(int queueTimeout, int queueWaitInterval, StatsCounter statsCounter) {
this.queueTimeout = queueTimeout;
this.queueWaitInterval = queueWaitInterval;
this.statsCounter = statsCounter;
}
@Override
public void ensureFreeBrowsersAvailable(String user, String remoteHost, String browser, Version version) {
int waitAttempt = 0;
final String requestId = randomUUID().toString();
final Temporal waitingStarted = now();
final Duration maxWait = Duration.ofSeconds(queueTimeout);
while (maxWait.compareTo(Duration.between(waitingStarted, now())) > 0 &&
(countSessions(user, browser, version)) >= version.getPermittedCount()) {
try {
onWait(user, browser, version, requestId, waitAttempt);
Thread.sleep(SECONDS.toMillis(queueWaitInterval));
} catch (InterruptedException e) {
LOGGER.error("Failed to sleep thread", e);
}
if (maxWait.compareTo(Duration.between(waitingStarted, now())) < 0) {
onWaitTimeout(user, browser, version, requestId, waitAttempt);
}
}
onWaitFinished(user, browser, version, requestId, waitAttempt);
}
protected void onWaitTimeout(String user, String browser, Version version, String requestId, int waitAttempt) {
throw new WaitAvailableBrowserTimeoutException(
format("Waiting for available browser of %s %s timed out for %s after %s attempts",
browser, version.getNumber(), user, waitAttempt));
}
protected void onWait(String user, String browser, Version version, String requestId, int waitAttempt) {
LOGGER.info("[SESSION_WAIT_AVAILABLE_BROWSER] [{}] [{}] [{}] [{}] [{}]",
user, browser, version.getNumber(), version.getPermittedCount(), ++waitAttempt);
}
protected void onWaitFinished(String user, String browser, Version version, String requestId, int waitAttempt) {
LOGGER.info("[SESSION_WAIT_FINISHED] [{}] [{}] [{}] [{}] [{}]",
user, browser, version.getNumber(), version.getPermittedCount(), ++waitAttempt);
}
protected int countSessions(String user, String browser, Version actualVersion) {
return statsCounter.getSessionsCountForUserAndBrowser(user, browser, actualVersion.getNumber());
}
}
================================================
FILE: proxy/src/main/resources/META-INF/spring/application-context.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="ru.qatools.gridrouter"/>
<bean id="configurationProperties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
<bean id="configRepository" class="${grid.router.quota.repository}"/>
<bean id="hostSelectionStrategy" class="${grid.router.host.selection.strategy}"/>
<bean class="${grid.router.stats.counter}"/>
<bean class="${grid.router.available.browsers.checker}"/>
</beans>
================================================
FILE: proxy/src/main/resources/application.properties
================================================
grid.config.quota.directory=classpath:quota
grid.router.quota.repository=ru.qatools.gridrouter.ConfigRepositoryXml
grid.config.quota.hotReload=true
grid.router.evict.sessions.cron=0 * * * * *
grid.router.evict.sessions.timeout.seconds=120
grid.router.route.timeout.seconds=120
grid.router.queue.timeout.seconds=120
grid.router.queue.interval.seconds=5
grid.router.host.selection.strategy=ru.qatools.gridrouter.config.RandomHostSelectionStrategy
grid.router.stats.counter=ru.qatools.gridrouter.sessions.MemoryStatsCounter
grid.router.available.browsers.checker=ru.qatools.gridrouter.sessions.SkipAvailableBrowsersChecker
================================================
FILE: proxy/src/main/resources/log4j.properties
================================================
# suppress inspection "UnusedProperty" for whole file
log4j.rootLogger=INFO, out
# CONSOLE appender not used by default
log4j.appender.out=org.apache.log4j.ConsoleAppender
log4j.appender.out.layout=org.apache.log4j.PatternLayout
log4j.appender.out.layout.ConversionPattern=%d [%-10.10t] %-5p %-20.20c{1} - %m%n
log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
================================================
FILE: proxy/src/main/resources/xsd/json.xjb
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_1.xsd"
xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance"
jaxb:extensionBindingPrefixes="xjc annox"
schemaLocation="json.xsd"
version="2.1">
<jaxb:bindings node="//xs:complexType[starts-with(@name, 'Json')]" multiple="true">
<inheritance:extends>ru.qatools.gridrouter.json.JsonWithAnyProperties</inheritance:extends>
</jaxb:bindings>
<jaxb:bindings node="//xs:complexType[@name='JsonMessage']">
<inheritance:implements>ru.qatools.gridrouter.json.WithJsonView</inheritance:implements>
<inheritance:implements>ru.qatools.gridrouter.json.WithErrorMessage</inheritance:implements>
</jaxb:bindings>
<jaxb:bindings node="//xs:complexType[@name='JsonCapabilities']">
<inheritance:implements>ru.qatools.gridrouter.json.Describable</inheritance:implements>
</jaxb:bindings>
<jaxb:globalBindings>
<jaxb:serializable/>
<xjc:simple/>
</jaxb:globalBindings>
</jaxb:bindings>
================================================
FILE: proxy/src/main/resources/xsd/json.xsd
================================================
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema attributeFormDefault="unqualified" elementFormDefault="unqualified"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:json="urn:json.gridrouter.qatools.ru"
targetNamespace="urn:json.gridrouter.qatools.ru">
<xsd:element name="jsonMessage" type="json:JsonMessage"/>
<xsd:complexType name="JsonMessage">
<xsd:sequence>
<xsd:element name="desiredCapabilities" type="json:JsonCapabilities"/>
</xsd:sequence>
<xsd:attribute name="status" type="xsd:int"/>
<xsd:attribute name="sessionId" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="JsonCapabilities">
<xsd:attribute name="browserName" type="xsd:string"/>
<xsd:attribute name="version" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="JsonValue">
<xsd:attribute name="message" type="xsd:string"/>
</xsd:complexType>
<xsd:complexType name="Proxy">
<xsd:attribute name="proxyType" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
================================================
FILE: proxy/src/main/webapp/WEB-INF/web.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
metadata-complete="false"
version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:META-INF/spring/*application-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
<init-param>
<param-name>dirAllowed</param-name>
<param-value>false</param-value>
</init-param>
</servlet>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Selenium Grid Router</realm-name>
</login-config>
</web-app>
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/CommandDecodingTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Collection;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.hamcrest.Matchers.endsWith;
import static org.junit.Assert.assertThat;
/**
* @author Artem Eroshenko eroshenkoam@yandex-team.ru
*/
@RunWith(Parameterized.class)
public class CommandDecodingTest {
public static final String SUFFIX = "http://host.com/wd/hub/session/8dec71ede39ad9ff3";
public static final String POSTFIX = "b3fbc03311bdc45282358f1-f09c-4c44-8057-4b82f4a53002/element/id/";
public String requestUri;
public String elementId;
public CommandDecodingTest(String elementId) throws Exception {
this.requestUri = String.format("%s%s%s", SUFFIX, POSTFIX, URLEncoder.encode(elementId, UTF_8.name()));
this.elementId = elementId;
}
@Parameterized.Parameters
public static Collection<Object[]> getData() {
return Arrays.asList(
new Object[]{"text_???"},
new Object[]{"text_&_not_text"}
);
}
@Test
public void testOutput() throws Exception {
assertThat(JsonWireUtils.getCommand(requestUri), endsWith(elementId));
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/JsonWireUtilsTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
import static java.util.UUID.randomUUID;
import static org.apache.commons.codec.digest.DigestUtils.md5Hex;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static ru.qatools.gridrouter.JsonWireUtils.WD_HUB_SESSION;
import static ru.qatools.gridrouter.JsonWireUtils.getFullSessionId;
import static ru.qatools.gridrouter.JsonWireUtils.getSessionHash;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class JsonWireUtilsTest {
@Test
public void testGetSessionHash() {
String routeHash = md5Hex("hubAddress".getBytes(StandardCharsets.UTF_8));
assertThat(getSessionHash(sessionRequest(routeHash, randomUUID().toString(), "")), is(equalTo(routeHash)));
assertThat(getSessionHash(sessionRequest(routeHash, randomUUID().toString(), "dhgdhg")), is(equalTo(routeHash)));
assertThat(getSessionHash(sessionRequest(routeHash, randomUUID().toString(), "dh/gdh/")), is(equalTo(routeHash)));
assertThat(getSessionHash(sessionRequest(routeHash, randomUUID().toString(), "dh/gdh/g")), is(equalTo(routeHash)));
}
@Test
public void testGetFullSessionId() {
String routeHash = md5Hex("hubAddress".getBytes(StandardCharsets.UTF_8));
String sessionId = randomUUID().toString();
String expected = routeHash + sessionId;
assertThat(getFullSessionId(sessionRequest(routeHash, sessionId, "")), is(equalTo(expected)));
assertThat(getFullSessionId(sessionRequest(routeHash, sessionId, "sfgsds")), is(equalTo(expected)));
assertThat(getFullSessionId(sessionRequest(routeHash, sessionId, "sfg/sds/")), is(equalTo(expected)));
assertThat(getFullSessionId(sessionRequest(routeHash, sessionId, "sfg/sds/adfad")), is(equalTo(expected)));
}
public String sessionRequest(String routeHash, String sessionId, String sessionCommand) {
if (!sessionCommand.isEmpty()) {
sessionCommand = "/".concat(sessionCommand);
}
return WD_HUB_SESSION + routeHash + sessionId + sessionCommand;
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/PingServletTest.java
================================================
package ru.qatools.gridrouter;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.junit.Rule;
import org.junit.Test;
import ru.qatools.gridrouter.utils.GridRouterRule;
import java.io.IOException;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class PingServletTest {
@Rule
public GridRouterRule gridRouter = new GridRouterRule();
@Test
public void testPingWithAuth() throws IOException {
assertThat(executeSimpleGet(gridRouter.baseUrlWithAuth + "/ping"), equalTo(SC_OK));
}
public static int executeSimpleGet(String url) throws IOException {
return HttpClientBuilder
.create().build()
.execute(new HttpGet(url))
.getStatusLine()
.getStatusCode();
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletExceptionsWithHubTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.After;
import org.junit.Rule;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class ProxyServletExceptionsWithHubTest extends ProxyServletExceptionsWithoutHubTest {
@Rule
public HubEmulatorRule hub = new HubEmulatorRule( 8081);
@After
public void tearDown() {
hub.verify().totalRequestsCountIs(0);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletExceptionsWithoutHubTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.UnsupportedCommandException;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.utils.GridRouterRule;
import static org.openqa.selenium.remote.DesiredCapabilities.chrome;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static ru.qatools.gridrouter.utils.GridRouterRule.hubUrl;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class ProxyServletExceptionsWithoutHubTest {
@Rule
public GridRouterRule gridRouter = new GridRouterRule();
@Test(expected = UnsupportedCommandException.class)
public void testProxyWithWrongAuth() {
new RemoteWebDriver(hubUrl(gridRouter.baseUrlWrongPassword), firefox());
}
@Test(expected = UnsupportedCommandException.class)
public void testProxyWithoutAuth() {
new RemoteWebDriver(hubUrl(gridRouter.baseUrl), firefox());
}
@Test(expected = WebDriverException.class)
public void testProxyWithNotSupportedBrowser() {
new RemoteWebDriver(hubUrl(gridRouter.baseUrlWithAuth), chrome());
}
@Test(expected = WebDriverException.class)
public void testProxyWithNotSupportedVersion() {
DesiredCapabilities caps = firefox();
caps.setVersion("1");
new RemoteWebDriver(hubUrl(gridRouter.baseUrlWithAuth), caps);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.RemoteWebElement;
import ru.qatools.gridrouter.utils.GridRouterRule;
import java.net.URL;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.openqa.selenium.Platform.ANY;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public abstract class ProxyServletTest {
@Rule
public GridRouterRule gridRouter = new GridRouterRule();
private final URL url;
public ProxyServletTest(String user) {
url = GridRouterRule.hubUrl(gridRouter.baseUrl(user));
}
protected final URL getUrl() {
return url;
}
@Test
public void testSpecifyingBrowserVersion() {
DesiredCapabilities caps = firefox();
caps.setVersion("32");
new RemoteWebDriver(getUrl(), caps);
}
@Test
public void testSessionIdDoesNotChange() {
RemoteWebDriver driver = new RemoteWebDriver(getUrl(), firefox());
String sessionId = driver.getSessionId().toString();
driver.getCurrentUrl();
driver.get("some url");
assertThat(driver.getSessionId().toString(), is(equalTo(sessionId)));
driver.getCurrentUrl();
assertThat(driver.getSessionId().toString(), is(equalTo(sessionId)));
}
@Test
public void testSessionIdChangesForANewBrowser() {
RemoteWebDriver driver1 = new RemoteWebDriver(getUrl(), firefox());
String sessionId1 = driver1.getSessionId().toString();
RemoteWebDriver driver2 = new RemoteWebDriver(getUrl(), firefox());
String sessionId2 = driver2.getSessionId().toString();
assertThat(sessionId1, is(not(equalTo(sessionId2))));
}
@Test
public void testQuit() {
RemoteWebDriver driver = new RemoteWebDriver(getUrl(), firefox());
driver.quit();
}
@Test
public void testSendRequestParams() {
RemoteWebDriver driver = new RemoteWebDriver(getUrl(), firefox());
String url = "some url";
driver.getCurrentUrl();
driver.get(url);
assertThat(driver.getCurrentUrl(), is(url));
}
@Test
public void testFindElement() {
RemoteWebDriver driver = new RemoteWebDriver(getUrl(), firefox());
driver.getCurrentUrl();
String selector = "//lol[foo='bar']";
WebElement element = driver.findElement(By.xpath(selector));
assertThat(
((RemoteWebElement) element).getId(),
is(String.valueOf(selector.hashCode()))
);
}
@Test
public void testNullVersion() throws Exception {
String browserName = "other";
try {
new RemoteWebDriver(getUrl(), new DesiredCapabilities(browserName, null, ANY));
} catch (WebDriverException e) {
assertThat(e.getMessage(),
startsWith("Cannot find " + browserName + " capabilities on any available node"));
}
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithBrokenAndOkHubsTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.utils.GridRouterRule;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static ru.qatools.gridrouter.utils.GridRouterRule.USER_2;
import static ru.qatools.gridrouter.utils.GridRouterRule.hubUrl;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class ProxyServletWithBrokenAndOkHubsTest {
@Rule
public GridRouterRule gridRouter = new GridRouterRule();
@Rule
public HubEmulatorRule hub1 = new HubEmulatorRule(8081, hub -> hub.emulate().newSessionFailures(1));
@Rule
public HubEmulatorRule hub2 = new HubEmulatorRule(8082, hub -> hub.emulate().newSessions(1));
@Test
public void testFailingHubIsSkipped() {
new RemoteWebDriver(hubUrl(gridRouter.baseUrl(USER_2)), firefox());
hub1.verify().totalRequestsCountIs(1);
hub1.verify().totalRequestsCountIs(1);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithBrokenHubTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.utils.GridRouterRule;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class ProxyServletWithBrokenHubTest {
@ClassRule
public static GridRouterRule gridRouter = new GridRouterRule();
@Rule
public HubEmulatorRule hub = new HubEmulatorRule( 8081, hub -> hub.emulate().newSessionFailures(1));
@Test(expected = WebDriverException.class)
public void testFailingHubIsSkipped() {
new RemoteWebDriver(GridRouterRule.hubUrl(gridRouter.baseUrlWithAuth), firefox());
hub.verify().totalRequestsCountIs(1);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithOneHubTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static ru.qatools.gridrouter.utils.GridRouterRule.USER_1;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class ProxyServletWithOneHubTest extends ProxyServletTest {
@Rule
public HubEmulatorRule hub = new HubEmulatorRule( 8081,
hub -> hub.emulate().newSessions(1)
);
public ProxyServletWithOneHubTest() throws Exception {
super(USER_1);
}
@Test
public void testSessionIdsHaveACommonPrefix() {
hub.emulate().newSessions(1);
RemoteWebDriver driver1 = new RemoteWebDriver(getUrl(), firefox());
String sessionId1 = driver1.getSessionId().toString();
RemoteWebDriver driver2 = new RemoteWebDriver(getUrl(), firefox());
String sessionId2 = driver2.getSessionId().toString();
assertThat("sessionIds should have the same prefix",
sessionId1.regionMatches(0, sessionId2, 0, 30));
hub.verify().totalRequestsCountIs(2);
}
@Test
@Override
public void testSpecifyingBrowserVersion() {
super.testSpecifyingBrowserVersion();
hub.verify().totalRequestsCountIs(1);
}
@Test
@Override
public void testSessionIdDoesNotChange() {
hub.emulate().navigation();
super.testSessionIdDoesNotChange();
hub.verify().totalRequestsCountIs(4);
}
@Test
@Override
public void testSessionIdChangesForANewBrowser() {
hub.emulate().newSessions(1);
super.testSessionIdChangesForANewBrowser();
hub.verify().totalRequestsCountIs(2);
}
@Test
@Override
public void testQuit() {
hub.emulate().quit();
super.testQuit();
hub.verify().newSessionRequestsCountIs(1)
.quitRequestsCountIs(1);
}
@Override
public void testSendRequestParams() {
hub.emulate().navigation();
super.testSendRequestParams();
hub.verify().totalRequestsCountIs(4);
}
@Override
public void testFindElement() {
hub.emulate().navigation().findElement();
super.testFindElement();
hub.verify().totalRequestsCountIs(3);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithTwoHubsTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static ru.qatools.gridrouter.utils.GridRouterRule.USER_2;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class ProxyServletWithTwoHubsTest extends ProxyServletTest {
@Rule
public HubEmulatorRule hub1 = new HubEmulatorRule( 8081, hub -> hub.emulate().newSessions(1));
@Rule
public HubEmulatorRule hub2 = new HubEmulatorRule( 8082, hub -> hub.emulate().newSessions(1));
public ProxyServletWithTwoHubsTest() throws Exception {
super(USER_2);
}
@Test
public void testSessionIdsHaveNoCommonPrefix() {
RemoteWebDriver driver1 = new RemoteWebDriver(getUrl(), firefox());
String sessionId1 = driver1.getSessionId().toString();
RemoteWebDriver driver2 = new RemoteWebDriver(getUrl(), firefox());
String sessionId2 = driver2.getSessionId().toString();
assertThat("sessionIds should not have the same prefix",
!sessionId1.regionMatches(0, sessionId2, 0, 30));
hub1.verify().totalRequestsCountIs(1);
hub2.verify().totalRequestsCountIs(1);
}
@Override
public void testSpecifyingBrowserVersion() {
super.testSpecifyingBrowserVersion();
}
@Override
public void testSessionIdDoesNotChange() {
hub1.emulate().navigation();
hub2.emulate().navigation();
super.testSessionIdDoesNotChange();
}
@Test
@Override
public void testSessionIdChangesForANewBrowser() {
super.testSessionIdChangesForANewBrowser();
hub1.verify().totalRequestsCountIs(1);
hub2.verify().totalRequestsCountIs(1);
}
@Override
public void testQuit() {
hub1.emulate().quit();
hub2.emulate().quit();
super.testQuit();
}
@Override
public void testSendRequestParams() {
hub1.emulate().navigation();
hub2.emulate().navigation();
super.testSendRequestParams();
}
@Test
@Override
public void testFindElement() {
hub1.emulate().navigation().findElement();
hub2.emulate().navigation().findElement();
super.testFindElement();
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithoutHubTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.ClassRule;
import org.junit.Test;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.utils.GridRouterRule;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class ProxyServletWithoutHubTest {
@ClassRule
public static GridRouterRule gridRouterRule = new GridRouterRule();
@Test(expected = WebDriverException.class)
public void testProxyWithProperAuth() {
new RemoteWebDriver(GridRouterRule.hubUrl(gridRouterRule.baseUrlWithAuth), firefox());
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/QuotaReloadTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.*;
import ru.qatools.gridrouter.utils.GridRouterRule;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static ru.qatools.gridrouter.utils.GridRouterRule.USER_1;
import static ru.qatools.gridrouter.utils.GridRouterRule.USER_4;
import static ru.qatools.gridrouter.utils.MatcherUtils.canObtain;
import static ru.qatools.gridrouter.utils.QuotaUtils.*;
import static ru.yandex.qatools.matchers.decorators.MatcherDecorators.should;
import static ru.yandex.qatools.matchers.decorators.MatcherDecorators.timeoutHasExpired;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
@Ignore
public class QuotaReloadTest {
public static final int HUB_PORT_2 = 8082;
@Rule
public GridRouterRule gridRouter = new GridRouterRule();
@Rule
public HubEmulatorRule hub2 = new HubEmulatorRule( HUB_PORT_2, hub -> hub.emulate().newSessions(1));
@Test
public void testQuotaIsReloadedOnFileChange() throws Exception {
replacePortInQuotaFile(USER_1, hub2.getPort());
assertThat(USER_1, should(canObtain(gridRouter, firefox()))
.whileWaitingUntil(timeoutHasExpired(SECONDS.toMillis(60))
.withPollingInterval(SECONDS.toMillis(3))));
}
@Test
public void testNewQuotaFileIsLoaded() throws Exception {
copyQuotaFile(USER_1, USER_4, 0, 0, hub2.getPort());
assertThat(USER_4, should(canObtain(gridRouter, firefox()))
.whileWaitingUntil(timeoutHasExpired(SECONDS.toMillis(60))
.withPollingInterval(SECONDS.toMillis(3))));
}
@After
public void tearDown() {
hub2.verify().newSessionRequestsCountIs(1);
hub2.verify().totalRequestsCountIs(1);
}
@AfterClass
public static void restoreQuotaFiles() throws Exception {
replacePortInQuotaFile(USER_1, 8081);
deleteQuotaFile(USER_4);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/QuotaServletTest.java
================================================
package ru.qatools.gridrouter;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import ru.qatools.gridrouter.utils.GridRouterRule;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static ru.qatools.gridrouter.utils.GridRouterRule.*;
/**
* TODO add test for user with different browsers and different versions
* @author Dmitry Baev charlie@yandex-team.ru
*/
@RunWith(Parameterized.class)
public class QuotaServletTest {
@ClassRule
public static GridRouterRule gridRouter = new GridRouterRule();
@Parameters(name = "{0}")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{USER_1, 1}, {USER_2, 4}, {USER_3, 8},
});
}
private final String user;
private final int browsersCount;
public QuotaServletTest(String user, int browsersCount) {
this.user = user;
this.browsersCount = browsersCount;
}
@Test
public void testQuota() throws IOException {
Map<String, Integer> quota = executeSimpleGet(gridRouter.baseUrl(user) + "/quota");
assertThat(quota.size(), is(1));
assertThat(quota.get("firefox:32.0"), is(browsersCount));
}
public static Map<String, Integer> executeSimpleGet(String url) throws IOException {
CloseableHttpResponse execute = HttpClientBuilder
.create().build()
.execute(new HttpGet(url));
InputStream content = execute.getEntity().getContent();
//noinspection unchecked
return new ObjectMapper().readValue(content, HashMap.class);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/RegionsTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.utils.GridRouterRule;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static ru.qatools.gridrouter.utils.GridRouterRule.*;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class RegionsTest {
@ClassRule
public static GridRouterRule gridRouter = new GridRouterRule();
@Rule
public HubEmulatorRule hub1 = new HubEmulatorRule( 8081);
@Rule
public HubEmulatorRule hub2 = new HubEmulatorRule( 8082);
@Rule
public HubEmulatorRule hub3 = new HubEmulatorRule( 8083);
@Test
public void testRegionIsChangedAfterFailedTry() {
hub3.emulate().newSessions(1);
new RemoteWebDriver(hubUrl(gridRouter.baseUrl(USER_3)), firefox());
hub1.verify().newSessionRequestsCountIs(1);
hub2.verify().newSessionRequestsCountIs(0);
hub3.verify().newSessionRequestsCountIs(1);
}
@Test
public void testAllHostsAreTriedExactlyOnceInTheEnd() {
getWebDriverSafe(USER_3);
hub1.verify().newSessionRequestsCountIs(1);
hub2.verify().newSessionRequestsCountIs(1);
hub3.verify().newSessionRequestsCountIs(1);
}
@Test
public void testConfigIsImmutableBetweenRequests() {
// note here user1 is used for simplicity
getWebDriverSafe(USER_1);
hub1.verify().newSessionRequestsCountIs(1);
getWebDriverSafe(USER_1);
hub1.verify().newSessionRequestsCountIs(2);
}
private static void getWebDriverSafe(String user) {
try {
new RemoteWebDriver(hubUrl(gridRouter.baseUrl(user)), firefox());
} catch (WebDriverException ignored) {
}
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/RouteServletTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.utils.GridRouterRule;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static ru.qatools.gridrouter.utils.GridRouterRule.USER_3;
import static ru.qatools.gridrouter.utils.GridRouterRule.hubUrl;
public class RouteServletTest {
@ClassRule
public static GridRouterRule gridRouter = new GridRouterRule();
@Rule
public HubEmulatorRule hub = new HubEmulatorRule( 8081);
@Test(expected = WebDriverException.class, timeout = 10 * 1000)
public void testRouteTimeout() {
hub.emulate().newSessionFreeze(30);
new RemoteWebDriver(hubUrl(gridRouter.baseUrl(USER_3)), firefox());
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/StatsServletTest.java
================================================
package ru.qatools.gridrouter;
import org.junit.Rule;
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.RemoteWebDriver;
import ru.qatools.gridrouter.sessions.BrowsersCountMap;
import ru.qatools.gridrouter.utils.GridRouterRule;
import ru.qatools.gridrouter.utils.HubEmulatorRule;
import java.io.IOException;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static ru.qatools.gridrouter.utils.GridRouterRule.*;
import static ru.qatools.gridrouter.utils.HttpUtils.executeSimpleGet;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class StatsServletTest {
@Rule
public GridRouterRule gridRouter = new GridRouterRule();
@Rule
public HubEmulatorRule hub = new HubEmulatorRule(8081);
@Test
public void testStats() throws IOException {
assertThat(getActual(USER_1), is(empty()));
hub.emulate().newSessions(1);
hub.emulate().quit();
WebDriver driver = new RemoteWebDriver(hubUrl(gridRouter.baseUrlWithAuth), firefox());
assertThat(getActual(USER_1), is(newCountMap("firefox", "32.0")));
driver.quit();
assertThat(getActual(USER_1), is(empty()));
}
@Test
public void testStatsForDifferentUsers() throws IOException {
hub.emulate().newSessions(1);
new RemoteWebDriver(hubUrl(gridRouter.baseUrlWithAuth), firefox());
assertThat(getActual(USER_1), is(newCountMap("firefox", "32.0")));
assertThat(getActual(USER_2), is(empty()));
}
@Test
public void testEvictionOfOldSession() throws Exception {
hub.emulate().newSessions(1);
new RemoteWebDriver(hubUrl(gridRouter.baseUrlWithAuth), firefox());
Thread.sleep(1000);
assertThat(getActual(USER_1), is(newCountMap("firefox", "32.0")));
Thread.sleep(6000);
assertThat(getActual(USER_1), is(empty()));
}
@Test
public void testActiveSessionIsNotEvicted() throws Exception {
hub.emulate().newSessions(1).navigation();
WebDriver driver = new RemoteWebDriver(hubUrl(gridRouter.baseUrlWithAuth), firefox());
for (int i = 0; i < 3; i++) {
Thread.sleep(2000);
driver.getCurrentUrl();
driver.get("http://yandex.ru");
}
assertThat(getActual(USER_1), is(newCountMap("firefox", "32.0")));
}
private BrowsersCountMap getActual(String user) throws IOException {
return executeSimpleGet(gridRouter.baseUrl(user) + "/stats", BrowsersCountMap.class);
}
private BrowsersCountMap newCountMap(String browser, String version) {
BrowsersCountMap expected = new BrowsersCountMap();
expected.increment(browser, version);
return expected;
}
private BrowsersCountMap empty() {
return new BrowsersCountMap();
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/caps/AppiumCapabilityProcessorTest.java
================================================
package ru.qatools.gridrouter.caps;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.Platform;
import org.openqa.selenium.remote.DesiredCapabilities;
import ru.qatools.gridrouter.json.JsonCapabilities;
import ru.qatools.gridrouter.utils.JsonUtils;
import java.io.IOException;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
public class AppiumCapabilityProcessorTest {
private CapabilityProcessor processor;
@Before
public void setUp() throws Exception {
processor = new AppiumCapabilityProcessor();
}
@Test
public void accept() throws Exception {
assertThat(processor.accept(createCapabilities("", "iOS")), is(true));
assertThat(processor.accept(createCapabilities("blabla", "iOS")), is(false));
assertThat(processor.accept(createCapabilities("", "bla")), is(false));
assertThat(processor.accept(createCapabilities("bla", "iOS")), is(false));
}
private JsonCapabilities createCapabilities(String browserName, String platformName) throws IOException {
DesiredCapabilities desiredCapabilities = new DesiredCapabilities(browserName, "test", Platform.ANY);
desiredCapabilities.setCapability("platformName", platformName);
return JsonUtils.buildJsonCapabilities(desiredCapabilities);
}
@Test
public void process() throws Exception {
JsonCapabilities jsonCapabilities = new JsonCapabilities();
processor.process(jsonCapabilities);
assertThat(jsonCapabilities.any().keySet(), contains("keepKeyChains"));
assertThat(jsonCapabilities.any().get("keepKeyChains"), equalTo(true));
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/caps/CapabilityProcessorFactoryTest.java
================================================
package ru.qatools.gridrouter.caps;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import ru.qatools.gridrouter.json.JsonCapabilities;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static org.openqa.selenium.remote.DesiredCapabilities.internetExplorer;
import static ru.qatools.gridrouter.utils.JsonUtils.buildJsonCapabilities;
import static org.hamcrest.Matchers.*;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:META-INF/spring/application-context.xml")
public class CapabilityProcessorFactoryTest {
@Autowired
private CapabilityProcessorFactory factory;
@Test
public void testGetIEProcessor() throws Exception {
JsonCapabilities ieCaps = buildJsonCapabilities(internetExplorer());
assertThat(factory.getProcessor(ieCaps), is(instanceOf(IECapabilityProcessor.class)));
}
@Test
public void testGetDummyProcessor() throws Exception {
JsonCapabilities firefoxCaps = buildJsonCapabilities(firefox());
assertThat(factory.getProcessor(firefoxCaps), is(instanceOf(DummyCapabilityProcessor.class)));
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/caps/IECapabilityProcessorTest.java
================================================
package ru.qatools.gridrouter.caps;
import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.remote.DesiredCapabilities;
import ru.qatools.gridrouter.json.JsonCapabilities;
import ru.qatools.gridrouter.json.JsonMessage;
import ru.qatools.gridrouter.json.Proxy;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.openqa.selenium.Proxy.ProxyType.DIRECT;
import static org.openqa.selenium.remote.BrowserType.IE;
import static org.openqa.selenium.remote.CapabilityType.PROXY;
import static org.openqa.selenium.remote.DesiredCapabilities.firefox;
import static org.openqa.selenium.remote.DesiredCapabilities.internetExplorer;
import static ru.qatools.gridrouter.utils.JsonUtils.buildJsonCapabilities;
import static ru.qatools.gridrouter.utils.JsonUtils.buildJsonMessage;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class IECapabilityProcessorTest {
private IECapabilityProcessor processor;
@Before
public void setUp() throws Exception {
processor = new IECapabilityProcessor();
}
@Test
public void testAccept() throws Exception {
assertThat(processor.accept(buildJsonCapabilities(internetExplorer())), is(true));
assertThat(processor.accept(buildJsonCapabilities(firefox())), is(false));
}
@Test
public void testAddProxy() throws Exception {
String version = "11";
JsonCapabilities capabilities = buildJsonCapabilities(internetExplorer(), version);
processor.process(capabilities);
assertThat(capabilities.getBrowserName(), is(equalTo(IE)));
assertThat(capabilities.getVersion(), is(equalTo(version)));
assertThat(capabilities.any().get(PROXY), is(notNullValue()));
assertThat(((Proxy) capabilities.any().get(PROXY)).getProxyType(), is(equalTo(DIRECT.name())));
}
@Test
public void testJsonMarshalling() throws Exception {
JsonMessage message = buildJsonMessage(internetExplorer());
processor.process(message.getDesiredCapabilities());
String proxyType = (String) new JSONObject(message.toJson())
.getJSONObject("desiredCapabilities")
.getJSONObject("proxy")
.get("proxyType");
assertThat(proxyType, is(equalTo(DIRECT.name())));
}
@Test
public void testExistingProxyIsNotOverridden() throws Exception {
DesiredCapabilities caps = internetExplorer();
org.openqa.selenium.Proxy proxy = new org.openqa.selenium.Proxy();
proxy.setHttpProxy(PROXY);
caps.setCapability(PROXY, proxy);
JsonCapabilities capabilities = buildJsonCapabilities(caps);
processor.process(capabilities);
assertThat(capabilities.any().get(PROXY), not(instanceOf(Proxy.class)));
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/json/JsonMessageTest.java
================================================
package ru.qatools.gridrouter.json;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.json.JSONObject;
import org.junit.Test;
import java.io.IOException;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static ru.qatools.gridrouter.json.WithErrorMessage.DEFAULT_ERROR_MESSAGE;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class JsonMessageTest {
@Test
public void testProperJson() throws IOException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("status", 69);
jsonObject.put("sessionId", "session id");
jsonObject.put("some other key", "some other value");
JSONObject capabilitiesObject = new JSONObject();
capabilitiesObject.put("browserName", "firefox");
capabilitiesObject.put("version", "32.0");
capabilitiesObject.put("some capability key", "some capability value");
jsonObject.put("desiredCapabilities", capabilitiesObject);
JSONObject valueObject = new JSONObject();
valueObject.put("message", "some error message");
valueObject.put("some value key", "some value value");
jsonObject.put("value", valueObject);
JsonMessage jsonMessage = JsonMessageFactory.from(jsonObject.toString());
assertThat(jsonMessage.getStatus(), is(69));
assertThat(jsonMessage.getSessionId(), is("session id"));
assertThat(jsonMessage.any().get("some other key"), is("some other value"));
JsonCapabilities jsonCapabilities = jsonMessage.getDesiredCapabilities();
assertThat(jsonCapabilities.getBrowserName(), is("firefox"));
assertThat(jsonCapabilities.getVersion(), is("32.0"));
assertThat(jsonCapabilities.any().get("some capability key"), is("some capability value"));
assertThat(jsonMessage.getErrorMessage(), is("some error message"));
}
@Test
public void testJsonWithKeysMissing() throws IOException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("status", 69);
JsonMessage jsonMessage = JsonMessageFactory.from(jsonObject.toString());
assertThat(jsonMessage.getStatus(), is(69));
assertThat(jsonMessage.getSessionId(), is(nullValue()));
assertThat(jsonMessage.getDesiredCapabilities(), is(nullValue()));
}
@Test
public void testErrorMessageForNullValue() throws IOException {
JSONObject jsonObject = new JSONObject();
JsonMessage jsonMessage = JsonMessageFactory.from(jsonObject.toString());
assertThat(jsonMessage.getErrorMessage(), is(DEFAULT_ERROR_MESSAGE));
}
@Test
public void testNullErrorMessageForPresentValue() throws IOException {
JSONObject jsonObject = new JSONObject();
jsonObject.put("value", new JSONObject());
JsonMessage jsonMessage = JsonMessageFactory.from(jsonObject.toString());
assertThat(jsonMessage.getErrorMessage(), is(DEFAULT_ERROR_MESSAGE));
}
@Test
public void testValueOfSimpleType() throws IOException {
String jsonRaw =
"{"
+ "\"using\":\"xpath\","
+ "\"value\":\"//lol[foo='bar']\""
+ "}";
JsonMessage jsonMessage = JsonMessageFactory.from(jsonRaw);
assertThat(jsonMessage.getSessionId(), is(nullValue()));
assertThat(jsonMessage.any().get("value"), is("//lol[foo='bar']"));
}
@Test
public void testJsonView() throws JsonProcessingException {
JsonMessage jsonMessage = new JsonMessage();
jsonMessage.setSessionId("session id");
jsonMessage.setStatus(69);
JsonCapabilities jsonCapabilities = new JsonCapabilities();
jsonCapabilities.setBrowserName("browser name");
jsonCapabilities.setVersion("browser version");
jsonMessage.setDesiredCapabilities(jsonCapabilities);
jsonMessage.set("some key", "some value");
JSONObject jsonObject = new JSONObject(jsonMessage.toJson());
assertThat(jsonObject.getString("sessionId"), is("session id"));
assertThat(jsonObject.getInt("status"), is(69));
JSONObject capabilitiesObject = jsonObject.getJSONObject("desiredCapabilities");
assertThat(capabilitiesObject.get("browserName"), is("browser name"));
assertThat(capabilitiesObject.get("version"), is("browser version"));
assertThat(jsonObject.isNull("value"), is(true));
assertThat(jsonObject.isNull("message"), is(true));
assertThat(jsonObject.isNull("errorMessage"), is(true));
}
@Test
public void testSettingErrorMessage() throws JsonProcessingException {
JsonMessage jsonMessage = JsonMessageFactory.error(69, "some error message");
JSONObject jsonObject = new JSONObject(jsonMessage.toJson());
assertThat(jsonObject.getInt("status"), is(69));
assertThat(jsonObject.getJSONObject("value").getString("message"), is("some error message"));
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/sessions/MemoryStatsCounterTest.java
================================================
package ru.qatools.gridrouter.sessions;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.Before;
import org.junit.Test;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import static java.time.Duration.ZERO;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static ru.qatools.gridrouter.json.JsonFormatter.toJson;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class MemoryStatsCounterTest {
private MemoryStatsCounter storage;
@Before
public void setUp() throws Exception {
storage = new MemoryStatsCounter();
}
@Test
public void testEmptyStorage() throws Exception {
assertThat(countJsonFor("user"), is("{}"));
assertThat(expiredSessions(ZERO), is(empty()));
assertThat(expiredSessions(Duration.ofDays(1)), is(empty()));
}
@Test
public void testAddSession() throws Exception {
storage.startSession("session1", "user", "firefox", "33");
storage.startSession("session2", "user", "firefox", "33");
storage.startSession("session3", "user", "firefox", "33");
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":3}}"));
assertThat(storage.getSessionsCountForUser("user"), is(3));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "33"), is(3));
storage.startSession("session1", "user", "firefox", "33");
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":3}}"));
assertThat(storage.getSessionsCountForUser("user"), is(3));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "33"), is(3));
}
@Test
public void testDifferentBrowsers() throws Exception {
storage.startSession("session1", "user", "chrome", "33");
storage.startSession("session2", "user", "firefox", "33");
storage.startSession("session3", "user", "firefox", "33");
assertThat(countJsonFor("user"), is("{\"chrome\":{\"33\":1},\"firefox\":{\"33\":2}}"));
assertThat(storage.getSessionsCountForUser("user"), is(3));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "33"), is(2));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "chrome", "33"), is(1));
}
@Test
public void testDifferentVersions() throws Exception {
storage.startSession("session1", "user", "firefox", "33");
storage.startSession("session2", "user", "firefox", "34");
storage.startSession("session3", "user", "firefox", "34");
storage.startSession("session4", "user", "firefox", "firefox");
storage.startSession("session5", "user", "firefox", "firefox");
storage.startSession("session6", "user", "firefox", "firefox");
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":1,\"34\":2,\"firefox\":3}}"));
assertThat(storage.getSessionsCountForUser("user"), is(6));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "33"), is(1));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "34"), is(2));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "firefox"), is(3));
}
@Test
public void testRemoveExistingSession() throws Exception {
storage.startSession("session1", "user", "firefox", "33");
storage.startSession("session2", "user", "firefox", "33");
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":2}}"));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "33"), is(2));
storage.deleteSession("session1");
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":1}}"));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "33"), is(1));
storage.deleteSession("session1");
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":1}}"));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "33"), is(1));
storage.deleteSession("session2");
assertThat(countJsonFor("user"), is("{}"));
assertThat(storage.getSessionsCountForUserAndBrowser("user", "firefox", "33"), is(0));
}
@Test
public void testRemoveNotExistingSession() throws Exception {
storage.deleteSession("session1");
storage.startSession("session1", "user", "firefox", "33");
storage.startSession("session2", "user", "firefox", "33");
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":2}}"));
storage.deleteSession("session4");
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":2}}"));
}
@Test
public void testMultipleUsers() throws Exception {
storage.startSession("session1", "user1", "firefox", "33");
storage.startSession("session2", "user2", "firefox", "33");
storage.startSession("session3", "user2", "firefox", "33");
assertThat(countJsonFor("user1"), is("{\"firefox\":{\"33\":1}}"));
assertThat(countJsonFor("user2"), is("{\"firefox\":{\"33\":2}}"));
storage.deleteSession("session1");
storage.deleteSession("session2");
assertThat(countJsonFor("user1"), is("{}"));
assertThat(countJsonFor("user2"), is("{\"firefox\":{\"33\":1}}"));
}
@Test
public void testNewSessionsAreNotExpired() throws Exception {
storage.startSession("session1", "user", "firefox", "33");
storage.startSession("session2", "user", "firefox", "33");
assertThat(expiredSessions(1000), is(empty()));
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":2}}"));
}
@Test
public void testOldSessionsAreExpired() throws Exception {
storage.startSession("session1", "user", "firefox", "33");
storage.startSession("session2", "user", "firefox", "33");
Thread.sleep(500);
storage.startSession("session3", "user", "firefox", "33");
assertThat(expiredSessions(250), containsInAnyOrder("session1", "session2"));
assertThat(countJsonFor("user"), is("{\"firefox\":{\"33\":1}}"));
Thread.sleep(500);
assertThat(expiredSessions(250), contains("session3"));
assertThat(countJsonFor("user"), is("{}"));
}
@Test
public void testUpdateExistingSession() throws Exception {
storage.startSession("session1", "user", "firefox", "33");
Thread.sleep(500);
storage.updateSession("session1");
assertThat(expiredSessions(250), is(empty()));
}
@Test
public void testMultipleUsersExpiration() throws Exception {
storage.startSession("session1", "user1", "firefox", "33");
Thread.sleep(500);
storage.startSession("session2", "user2", "firefox", "33");
assertThat(expiredSessions(250), contains("session1"));
assertThat(countJsonFor("user1"), is("{}"));
assertThat(countJsonFor("user2"), is("{\"firefox\":{\"33\":1}}"));
}
private String countJsonFor(String user) throws JsonProcessingException {
return toJson(storage.getStats(user));
}
public Set<String> expiredSessions(int millis) {
return expiredSessions(Duration.ofMillis(millis));
}
public Set<String> expiredSessions(Duration duration) {
final Set<String> removedSessionIds = new HashSet<>(storage.getActiveSessions());
storage.expireSessionsOlderThan(duration);
removedSessionIds.removeAll(storage.getActiveSessions());
return removedSessionIds;
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowsersCheckerTest.java
================================================
package ru.qatools.gridrouter.sessions;
import org.junit.Before;
import org.junit.Test;
import ru.qatools.gridrouter.config.Version;
import java.time.Duration;
import java.time.temporal.Temporal;
import static java.time.ZonedDateTime.now;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.lessThan;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
/**
* @author Ilya Sadykov
*/
public class WaitAvailableBrowsersCheckerTest {
WaitAvailableBrowsersChecker checker;
Version version;
StatsCounter counter;
@Before
public void setUp() throws Exception {
counter = mock(StatsCounter.class);
checker = new WaitAvailableBrowsersChecker(3, 1, counter);
version = new Version();
version.setPermittedCount(10);
version.setNumber("33");
when(counter.getSessionsCountForUserAndBrowser(eq("user"), eq("firefox"), eq("33"))).thenReturn(10);
}
@Test
public void testWaitAvailableBrowsersChecker() throws Exception {
Temporal started = now();
try {
checker.ensureFreeBrowsersAvailable("user", "host", "firefox", version);
} catch (WaitAvailableBrowserTimeoutException e) {
// do nothing
}
verify(counter, times(3)).getSessionsCountForUserAndBrowser(eq("user"), eq("firefox"), eq("33"));
assertThat(Duration.between(started, now()).toMillis(), greaterThanOrEqualTo(3000L));
}
@Test(expected = WaitAvailableBrowserTimeoutException.class)
public void testWaitAvailableBrowsersTimeout() throws Exception {
checker.ensureFreeBrowsersAvailable("user", "host", "firefox", version);
}
@Test
public void testNoWaitAvailableBrowser() throws Exception {
when(counter.getSessionsCountForUserAndBrowser(eq("user"), eq("firefox"), eq("33"))).thenReturn(5);
Temporal started = now();
checker.ensureFreeBrowsersAvailable("user", "host", "firefox", version);
verify(counter, times(1)).getSessionsCountForUserAndBrowser(eq("user"), eq("firefox"), eq("33"));
assertThat(Duration.between(started, now()).toMillis(), lessThan(1000L));
verifyNoMoreInteractions(counter);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/FindElementCallback.java
================================================
package ru.qatools.gridrouter.utils;
import org.json.JSONObject;
import org.mockserver.mock.action.ExpectationCallback;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;
import static org.mockserver.model.HttpResponse.response;
/**
* Sets the element id (according to protocol specification)
* to the hashcode of the selector. This way we can check that
* the selector was passed through proxy correctly.
*
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class FindElementCallback implements ExpectationCallback {
@Override
public HttpResponse handle(HttpRequest httpRequest) {
JSONObject jsonObject = new JSONObject(httpRequest.getBodyAsString());
String selector = jsonObject.get("value").toString();
JSONObject responce = new JSONObject();
responce.put("status", 0);
JSONObject value = new JSONObject();
value.put("ELEMENT", selector.hashCode());
responce.put("value", value);
return response(responce.toString()).withStatusCode(500);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/GridRouterRule.java
================================================
package ru.qatools.gridrouter.utils;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.util.security.Password;
import java.net.MalformedURLException;
import java.net.URL;
import static java.util.UUID.randomUUID;
import static ru.qatools.gridrouter.utils.SocketUtil.findFreePort;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class GridRouterRule extends JettyRule {
public static final String USER_1 = "user1";
public static final String USER_2 = "user2";
public static final String USER_3 = "user3";
public static final String USER_4 = "user4";
public static final String PASSWORD = "password";
public static final String ROLE = "user";
public final String baseUrl;
public final String baseUrlWithAuth;
public final String baseUrlWrongPassword;
public GridRouterRule() {
super(
"/",
"src/main/webapp",
"target/classes",
findFreePort(),
new HashLoginService() {{
setName("Selenium Grid Router");
putUser(USER_1, new Password(PASSWORD), new String[]{ROLE});
putUser(USER_2, new Password(PASSWORD), new String[]{ROLE});
putUser(USER_3, new Password(PASSWORD), new String[]{ROLE});
putUser(USER_4, new Password(PASSWORD), new String[]{ROLE});
}}
);
baseUrl = "http://localhost:" + getPort();
baseUrlWithAuth = baseUrl(USER_1);
baseUrlWrongPassword = baseUrl(USER_1, randomUUID().toString());
}
public static URL hubUrl(String baseUrl) {
try {
return new URL(baseUrl + "/wd/hub");
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
public String baseUrl(String user) {
return baseUrl(user, PASSWORD);
}
public String baseUrl(String user, String password) {
return String.format("http://%s:%s@localhost:%d",
user, password, getPort());
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/HttpUtils.java
================================================
package ru.qatools.gridrouter.utils;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* @author Dmitry Baev charlie@yandex-team.ru
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public final class HttpUtils {
private HttpUtils() {
}
public static <T> T executeSimpleGet(String url, Class<T> clazz) throws IOException {
CloseableHttpResponse execute = HttpClientBuilder
.create().build()
.execute(new HttpGet(url));
InputStream content = execute.getEntity().getContent();
return new ObjectMapper().readValue(content, clazz);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/HubEmulator.java
================================================
package ru.qatools.gridrouter.utils;
import org.json.JSONObject;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.matchers.Times;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;
import java.util.concurrent.TimeUnit;
import static java.util.UUID.randomUUID;
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
import static org.mockserver.matchers.Times.once;
import static org.mockserver.model.HttpCallback.callback;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
import static org.mockserver.verify.VerificationTimes.exactly;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class HubEmulator {
private static final String WD_HUB_SESSION = "/wd/hub/session";
private static final String SESSION_ID_REGEX = "[-a-zA-Z0-9]{36}";
private ClientAndServer hub;
public HubEmulator(int hubPort) {
hub = startClientAndServer(hubPort);
}
public HubEmulations emulate() {
return new HubEmulations();
}
public HubVerifications verify() {
return new HubVerifications();
}
public void stop() {
hub.stop();
}
public class HubEmulations {
public HubEmulations newSessions(int sessionsCount) {
for (int i = 0; i < sessionsCount; i++) {
hub.when(newSessionRequest(), once()).respond(newSessionSuccessful());
}
return this;
}
public HubEmulations newSessionFailures(int times) {
return newSessionFailures(Times.exactly(times));
}
public HubEmulations newSessionFailures(Times times) {
hub.when(newSessionRequest(), times).respond(newSessionFailed());
return this;
}
public HubEmulations newSessionFreeze(int seconds) {
hub.when(newSessionRequest(), once()).respond(
response()
.withDelay(TimeUnit.SECONDS, seconds)
.withStatusCode(500)
);
return this;
}
public HubEmulations navigation() {
hub.when(sessionRequest("url"))
.callback(callback().withCallbackClass(
RememberUrlCallback.class.getCanonicalName()));
return this;
}
public HubEmulations findElement() {
hub.when(sessionRequest("element").withMethod("POST"))
.callback(callback().withCallbackClass(
FindElementCallback.class.getCanonicalName()));
return this;
}
public HubEmulations quit() {
hub.when(sessionQuitRequest()).respond(emptyResponse());
return this;
}
}
public class HubVerifications {
public HubVerifications newSessionRequestsCountIs(int sessionsCount) {
hub.verify(newSessionRequest(), exactly(sessionsCount));
return this;
}
public HubVerifications quitRequestsCountIs(int times) {
hub.verify(sessionQuitRequest(), exactly(times));
return this;
}
public HubVerifications totalRequestsCountIs(int times) {
hub.verify(request(".*"), exactly(times));
return this;
}
}
private static HttpRequest newSessionRequest() {
return request(WD_HUB_SESSION).withMethod("POST");
}
private static HttpRequest sessionRequest(String handler) {
return request(WD_HUB_SESSION + "/" + SESSION_ID_REGEX + "/" + handler);
}
private static HttpRequest sessionQuitRequest() {
return request(WD_HUB_SESSION +"/.*").withMethod("DELETE");
}
private HttpResponse emptyResponse() {
JSONObject json = new JSONObject();
json.put("value", new JSONObject());
return response(json.toString());
}
private static HttpResponse newSessionSuccessful() {
JSONObject json = new JSONObject();
json.put("value", new JSONObject());
json.put("sessionId", randomUUID());
return response(json.toString());
}
private static HttpResponse newSessionFailed() {
JSONObject json = new JSONObject();
json.put("status", 6);
JSONObject value = new JSONObject();
value.put("message", "unable to start browser");
json.put("value", value);
return response(json.toString()).withStatusCode(500);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/HubEmulatorRule.java
================================================
package ru.qatools.gridrouter.utils;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.Consumer;
import static ru.qatools.gridrouter.utils.SocketUtil.findFreePort;
import static ru.qatools.gridrouter.utils.TestConfigRepository.changePort;
import static ru.qatools.gridrouter.utils.TestConfigRepository.resetConfig;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public class HubEmulatorRule extends TestWatcher {
static final Logger LOGGER = LoggerFactory.getLogger(HubEmulatorRule.class);
private int fromPort;
private int port;
private HubEmulator hub;
public HubEmulatorRule(int fromPort) {
this(fromPort, hub -> {
});
}
public HubEmulatorRule(int fromPort, Consumer<HubEmulator> initializer) {
this.fromPort = fromPort;
port = findFreePort();
LOGGER.info("Selected new free port {}, starting emulator...", port);
hub = new HubEmulator(port);
if (initializer != null) {
LOGGER.info("Running initializer...");
try {
initializer.accept(hub);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
LOGGER.info("Waiting for config initialization...");
changePort(fromPort, port);
}
@Override
protected void finished(Description description) {
resetConfig();
hub.stop();
}
public HubEmulator.HubEmulations emulate() {
return hub.emulate();
}
public HubEmulator.HubVerifications verify() {
return hub.verify();
}
public int getPort() {
return port;
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/JettyRule.java
================================================
package ru.qatools.gridrouter.utils;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;
import org.eclipse.jetty.webapp.WebXmlConfiguration;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class JettyRule implements TestRule {
private final String contextPath;
private final String classPath;
private final String warPath;
private final int port;
private Server server;
private Object[] beans;
public JettyRule(String contextPath, String warPath, String classPath, int port, Object... beans) {
this.contextPath = contextPath;
this.classPath = classPath;
this.warPath = warPath;
this.port = port;
this.beans = beans;
}
@Override
public Statement apply(final Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
before();
try {
base.evaluate();
} finally {
after();
}
}
};
}
protected void before() throws Exception {
WebAppContext context = new WebAppContext();
context.setResourceBase(warPath);
context.setExtraClasspath(classPath);
context.setContextPath(contextPath);
context.setParentLoaderPriority(true);
context.setConfigurations(new Configuration[]{
new AnnotationConfiguration(),
new WebXmlConfiguration(),
new WebInfConfiguration()
});
server = new Server(port);
server.setHandler(context);
for (Object bean : beans) {
server.addBean(bean);
}
server.start();
}
protected void after() throws Exception {
server.stop();
}
public int getPort() {
return port;
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/JsonUtils.java
================================================
package ru.qatools.gridrouter.utils;
import org.json.JSONObject;
import org.openqa.selenium.remote.DesiredCapabilities;
import ru.qatools.gridrouter.json.JsonCapabilities;
import ru.qatools.gridrouter.json.JsonMessage;
import ru.qatools.gridrouter.json.JsonMessageFactory;
import java.io.IOException;
import java.util.Map;
import static org.openqa.selenium.remote.CapabilityType.BROWSER_NAME;
import static org.openqa.selenium.remote.CapabilityType.PLATFORM;
import static org.openqa.selenium.remote.CapabilityType.PROXY;
import static org.openqa.selenium.remote.CapabilityType.VERSION;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public final class JsonUtils {
private JsonUtils() {
}
public static JsonCapabilities buildJsonCapabilities(DesiredCapabilities capabilities)
throws IOException {
return buildJsonMessage(capabilities).getDesiredCapabilities();
}
public static JsonCapabilities buildJsonCapabilities(DesiredCapabilities capabilities, String version)
throws IOException {
capabilities.setVersion(version);
return buildJsonMessage(capabilities).getDesiredCapabilities();
}
public static JsonMessage buildJsonMessage(DesiredCapabilities capabilities) throws IOException {
JSONObject capabilitiesObject = new JSONObject();
Map<String, ?> capabilitiesMap = capabilities.asMap();
capabilitiesMap.keySet().forEach(k -> capabilitiesObject.put(k, capabilitiesMap.get(k)));
JSONObject jsonObject = new JSONObject();
jsonObject.put("desiredCapabilities", capabilitiesObject);
return JsonMessageFactory.from(jsonObject.toString());
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/MatcherUtils.java
================================================
package ru.qatools.gridrouter.utils;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import static ru.qatools.gridrouter.utils.GridRouterRule.hubUrl;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public final class MatcherUtils {
private MatcherUtils() {
}
/**
* Creates a matcher that tries to obtain a browser
* for a user that it is matched against.
*
* @return A matcher instance that creates a new webdriver
* on {@link Matcher#matches(Object) matches()} method invocation.
*
* @param browser capabilities for the browser to obtain
*/
public static Matcher<String> canObtain(final GridRouterRule gridRouter, final DesiredCapabilities browser) {
return new TypeSafeMatcher<String>() {
private Exception exception;
@Override
protected boolean matchesSafely(String user) {
try {
new RemoteWebDriver(hubUrl(gridRouter.baseUrl(user)), browser);
return true;
} catch (Exception e) {
exception = e;
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("not able to obtain browser because of ")
.appendValue(exception.toString());
}
};
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/QuotaUtils.java
================================================
package ru.qatools.gridrouter.utils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.SerializationUtils;
import ru.qatools.gridrouter.config.Browsers;
import javax.xml.bind.JAXB;
import java.io.File;
import java.io.StringWriter;
import static java.lang.ClassLoader.getSystemResource;
import static ru.qatools.gridrouter.utils.GridRouterRule.USER_1;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
*/
public final class QuotaUtils {
public static final String QUOTA_FILE_PATTERN
= getSystemResource("quota/" + USER_1 + ".xml").getPath().replace(USER_1, "%s");
private QuotaUtils() {
}
public static void replacePortInQuotaFile(String user, int port) {
replacePortInQuotaFile(user, 0, 0, port);
}
public static void replacePortInQuotaFile(String user, int regionNum, int hostNum, int port) {
copyQuotaFile(user, user, regionNum, hostNum, port);
}
public static void copyQuotaFile(String srcUser, String dstUser, int regionNum, int hostNum, int withHubPort) {
Browsers browsers = getQuotaFor(srcUser);
setPort(browsers, regionNum, hostNum, withHubPort);
writeQuotaFor(dstUser, browsers);
}
public static Browsers getQuotaFor(String user) {
File quotaFile = getQuotaFile(user);
Browsers browsersOriginal = JAXB.unmarshal(quotaFile, Browsers.class);
return SerializationUtils.clone(browsersOriginal);
}
public static synchronized void writeQuotaFor(String user, Browsers browsers) {
try {
//workaround to write the whole file at once
StringWriter xml = new StringWriter();
JAXB.marshal(browsers, xml);
final File fileToWrite = getQuotaFile(user);
final File tmpFile = File.createTempFile(user, "xml");
FileUtils.write(tmpFile, xml.toString());
FileUtils.copyFile(tmpFile, fileToWrite);
FileUtils.deleteQuietly(tmpFile);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static File getQuotaFile(String user) {
return new File(String.format(QUOTA_FILE_PATTERN, user));
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public static void deleteQuotaFile(String user) {
getQuotaFile(user).delete();
}
public static void setPort(Browsers browsers, int regionNum, int hostNumber, int port) {
browsers.getBrowsers().get(0)
.getVersions().get(0)
.getRegions().get(regionNum)
.getHosts().get(hostNumber)
.setPort(port);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/RememberUrlCallback.java
================================================
package ru.qatools.gridrouter.utils;
import org.json.JSONObject;
import org.mockserver.mock.action.ExpectationCallback;
import org.mockserver.model.HttpRequest;
import org.mockserver.model.HttpResponse;
import static org.mockserver.model.HttpResponse.response;
/**
* @author Innokenty Shuvalov innokenty@yandex-team.ru
* @author Dmitry Baev charlie@yandex-team.ru
*/
public class RememberUrlCallback implements ExpectationCallback {
private static String currentUrl = "{\"value\":\"\"}";
@Override
public HttpResponse handle(HttpRequest httpRequest) {
if (httpRequest.getMethod().toString().contains("POST")) {
JSONObject jsonObject = new JSONObject(httpRequest.getBodyAsString());
currentUrl = jsonObject.get("url").toString();
return response();
} else if (httpRequest.getMethod().toString().contains("GET")) {
return response(currentUrl);
}
return response("invalid request!").withStatusCode(400);
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/SocketUtil.java
================================================
package ru.qatools.gridrouter.utils;
import java.io.IOException;
import java.net.ServerSocket;
public enum SocketUtil {
;
/**
* Returns a free port number on localhost.
* Heavily inspired from org.eclipse.jdt.launching.SocketUtil (to avoid a dependency to JDT just because of this).
* Slightly improved with close() missing in JDT. And throws exception instead of returning -1.
*
* @return a free port number on localhost
* @throws IllegalStateException if unable to find a free port
*/
public static int findFreePort() {
ServerSocket socket = null;
try {
socket = new ServerSocket(0);
socket.setReuseAddress(true);
int port = socket.getLocalPort();
try {
socket.close();
} catch (IOException ignored) {
// Ignore IOException on close()
}
return port;
} catch (IOException ignored) {
// Ignore IOException on open
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException ignored) {
// Ignore IOException on close()
}
}
}
throw new IllegalStateException("Could not find a free TCP/IP port to start embedded Jetty HTTP Server on");
}
}
================================================
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/TestConfigRepository.java
================================================
package ru.qatools.gridrouter.utils;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.qatools.beanloader.BeanLoader;
import ru.qatools.gridrouter.ConfigRepository;
import ru.qatools.gridrouter.config.Browsers;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import static java.util.Collections.unmodifiableMap;
import static javax.xml.bind.JAXB.marshal;
import static javax.xml.bind.JAXB.unmarshal;
/**
* @author Ilya Sadykov
*/
public class TestConfigRepository implements ConfigRepository {
protected static final String XML_GLOB = "*.xml";
private static final Logger LOGGER = LoggerFactory.getLogger(TestConfigRepository.class);
private static Map<String, Browsers> initialBrowsers = new HashMap<>();
private static Map<String, String> initialRoutes = new HashMap<>();
private static Map<String, Browsers> userBrowsers = new HashMap<>();
private static Map<String, String> routes = new HashMap<>();
static {
try {
final Path quotaDir = Paths.get(TestConfigRepository.class.getClassLoader().getResource("quota").toURI());
LOGGER.debug("Loading quota configuration");
initialBrowsers = new HashMap<>();
initialRoutes = new HashMap<>();
BeanLoader.loadAll(Browsers.class, quotaDir, XML_GLOB, (path, quota) -> {
String user = FilenameUtils.getBaseName(path.toString());
initialBrowsers.put(user, quota);
initialRoutes.putAll(quota.getRoutesMap());
});
initialBrowsers = unmodifiableMap(initialBrowsers);
initialRoutes = unmodifiableMap(initialRoutes);
resetConfig();
} catch (IOException | URISyntaxException e) {
LOGGER.error("Quota configuration loading failed", e);
}
}
private static Browsers copy(Browsers quota) {
StringWriter writer = new StringWriter();
marshal(quota, writer);
return unmarshal(new StringReader(writer.toString()), Browsers.class);
}
public static synchronized void resetConfig() {
userBrowsers.clear();
initialBrowsers.entrySet().forEach(e -> {
userBrowsers.put(e.getKey(), copy(e.getValue()));
});
routes.clear();
routes.putAll(initialRoutes);
}
public static synchronized void changePort(int from, int to) {
userBrowsers.keySet().forEach(quotaName ->
userBrowsers.get(quotaName).getBrowsers().forEach(browser ->
browser.getVersions().forEach(version ->
version.getRegions().forEach(region ->
region.getHosts().forEach(host -> {
if (host.getPort() == from) {
LOGGER.info("Changing port of {} from {} to {} for user {}",
host, from, to, quotaName);
host.setPort(to);
routes.putAll(userBrowsers.get(quotaName).getRoutesMap());
}
})))));
}
@Override
public Map<String, Browsers> getQuotaMap() {
return userBrowsers;
}
@Override
public String getRoute(String routeId) {
return routes.get(routeId);
}
}
================================================
FILE: proxy/src/test/resources/META-INF/spring/test-application-context.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<import resource="classpath:META-INF/spring/application-context.xml"/>
<bean id="hostSelectionStrategy" class="ru.qatools.gridrouter.config.SequentialHostSelectionStrategy"/>
</beans>
================================================
FILE: proxy/src/test/resources/application.properties
================================================
grid.config.quota.directory=classpath:quota
grid.router.quota.repository=ru.qatools.gridrouter.utils.TestConfigRepository
grid.config.quota.hotReload=true
grid.router.evict.sessions.cron=* * * * * *
grid.router.evict.sessions.timeout.seconds=5
grid.router.route.timeout.seconds=5
grid.router.host.selection.strategy=ru.qatools.gridrouter.config.RandomHostSelectionStrategy
grid.router.stats.counter=ru.qatools.gridrouter.sessions.MemoryStatsCounter
grid.router.available.browsers.checker=ru.qatools.gridrouter.sessions.SkipAvailableBrowsersChecker
================================================
FILE: proxy/src/test/resources/log4j.properties
================================================
# suppress inspection "UnusedProperty" for whole file
log4j.rootLogger=INFO, out
# CONSOLE appender not used by default
log4j.appender.out=org.apache.log4j.ConsoleAppender
log4j.appender.out.layout=org.apache.log4j.PatternLayout
log4j.appender.out.layout.ConversionPattern=%d %-5p %c - %m%n
log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
log4j.logger.org.mockserver.mockserver.MockServerHandler=WARN
log4j.logger.ru.qatools.gridrouter=DEBUG
================================================
FILE: proxy/src/test/resources/quota/user1.xml
================================================
<qa:browsers xmlns:qa="urn:config.gridrouter.qatools.ru">
<browser name="firefox" defaultVersion="32.0">
<version number="32.0">
<region name="first">
<host name="localhost" port="8081" count="1"/>
</region>
</version>
</browser>
</qa:browsers>
================================================
FILE: proxy/src/test/resources/quota/user2.xml
================================================
<qa:browsers xmlns:qa="urn:config.gridrouter.qatools.ru">
<browser name="firefox" defaultVersion="32.0">
<version number="32.0">
<region name="first">
<host name="localhost" port="8081" count="1"/>
<host name="localhost" port="8082" count="3"/>
</region>
</version>
</browser>
</qa:browsers>
================================================
FILE: proxy/src/test/resources/quota/user3.xml
================================================
<qa:browsers xmlns:qa="urn:config.gridrouter.qatools.ru">
<browser name="firefox" defaultVersion="32.0">
<version number="32.0">
<region name="first">
<host name="localhost" port="8081" count="1"/>
<host name="localhost" port="8082" count="2"/>
</region>
<region name="second">
<host name="localhost" port="8083" count="5"/>
</region>
</version>
</browser>
</qa:browsers>
================================================
FILE: testing/group_vars/all.yml
================================================
workspace: "{{ ansible_env.PWD }}/target"
================================================
FILE: testing/ping-local-gridrouter.sh
================================================
#!/usr/bin/env bash
curl http://boot2docker:$(docker ps | grep jetty | sed 's/.*0.0.0.0://' | sed 's/->.*//')/ping && echo
================================================
FILE: testing/roles/start/files/gridrouter/conf/application.properties
================================================
# suppress inspection "UnusedProperty" for whole file
grid.config.quota.directory=classpath:quota
grid.config.quota.hotReload=true
grid.router.evict.sessions.cron=0 * * * * *
grid.router.evict.sessions.timeout.seconds=120
================================================
FILE: testing/roles/start/files/gridrouter/conf/quota/selenium.xml
================================================
<browsers>
<browser name="firefox" defaultVersion="38.0">
<version number="38.0">
<region name="first">
<host name="firefox" port="4444" count="5"/>
</region>
</version>
</browser>
<browser name="chrome" defaultVersion="43.0">
<version number="43.0">
<region name="first">
<host name="chrome" port="4444" count="5"/>
</region>
</version>
</browser>
</browsers>
================================================
FILE: testing/roles/start/files/gridrouter/conf/users.properties
================================================
selenium:selenium, user
================================================
FILE: testing/roles/start/files/gridrouter/webapps/ROOT.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC
"-//Mort Bay Consulting//DTD Configure//EN"
"http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/</Set>
<Set name="war">/etc/gridrouter/war/ROOT.war</Set>
<Set name="extraClasspath">/etc/gridrouter/conf/</Set>
<Get name="securityHandler">
<Set name="loginService">
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Selenium Grid Router</Set>
<Set name="config">/etc/gridrouter/conf/users.properties</Set>
<Call name="start"/>
</New>
</Set>
</Get>
</Configure>
================================================
FILE: testing/roles/start/tasks/before.yml
================================================
- debug: msg="workspace {{ workspace }}"
================================================
FILE: testing/roles/start/tasks/main.yml
================================================
---
- include: before.yml
- include: start-selenium.yml version="2.46.0" browser="firefox"
- include: start-selenium.yml version="2.46.0" browser="chrome"
- include: start-gridrouter.yml
================================================
FILE: testing/roles/start/tasks/start-gridrouter.yml
================================================
- name: copy configuration files
copy: src=gridrouter dest={{ workspace }}
- shell: "ls -d {{ ansible_env.PWD }}/../proxy/target/*.war"
register: war_path
- file: path={{ war_path.stdout }} state=file
- file: path={{ workspace }}/gridrouter/war/ state=directory
- copy: src={{ war_path.stdout }} dest={{ workspace }}/gridrouter/war/ROOT.war
- name: start jetty with gridrouter
docker:
name: gridrouter
image: jetty:9.3.2
expose:
- "8080"
ports:
- "8080"
links:
- "chrome"
- "firefox"
volumes:
- "{{ workspace }}/gridrouter/webapps:/var/lib/jetty/webapps"
- "{{ workspace }}/gridrouter/conf:/etc/gridrouter/conf"
- "{{ workspace }}/gridrouter/war:/etc/gridrouter/war"
state: started
================================================
FILE: testing/roles/start/tasks/start-selenium.yml
================================================
- name: start selenium standalone with {{ browser }}
docker:
name: "{{ browser }}"
image: selenium/standalone-{{ browser }}:{{ version }}
expose:
- "4444"
state: started
================================================
FILE: testing/roles/stop/tasks/before.yml
================================================
- debug: msg="workspace {{ workspace }}"
================================================
FILE: testing/roles/stop/tasks/main.yml
================================================
---
- include: before.yml
- include: stop-selenium.yml version="2.46.0" browser="firefox"
- include: stop-selenium.yml version="2.46.0" browser="chrome"
- include: stop-gridrouter.yml
================================================
FILE: testing/roles/stop/tasks/stop-gridrouter.yml
================================================
- name: stop jetty with gridrouter
docker:
name: gridrouter
image: jetty:9.3.0-jre8
state: absent
- name: delete workspace
file: path={{ workspace }} state=absent
ignore_errors: yes
================================================
FILE: testing/roles/stop/tasks/stop-selenium.yml
================================================
- name: stop selenium standalone with {{ browser }}
docker:
name: "{{ browser }}"
image: selenium/standalone-{{ browser }}:{{ version }}
expose:
- "4444"
state: absent
================================================
FILE: testing/roles/test/files/java/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.qatools.seleniumkit</groupId>
<artifactId>gridrouter-e2e-java</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.46.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
================================================
FILE: testing/roles/test/files/java/run.sh
================================================
#! /bin/sh
mvn -f /code/pom.xml test
================================================
FILE: testing/roles/test/files/java/src/test/java/SeleniumTest.java
================================================
import org.junit.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.net.URL;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
public class SeleniumTest {
@Test
public void testConnection() throws Exception {
URL url = new URL("http://selenium:selenium@gridrouter:8080/wd/hub");
DesiredCapabilities capabilities = DesiredCapabilities.firefox();
capabilities.setVersion("38.0");
WebDriver driver = new RemoteWebDriver(url, capabilities);
driver.get("http://www.yandex.ru");
assertThat(driver.getTitle(), equalTo("Яндекс"));
}
}
================================================
FILE: testing/roles/test/files/js/config.json
================================================
{
"baseUrl": "http://selenium:selenium@gridrouter:8080/wd/hub"
}
================================================
FILE: testing/roles/test/files/js/fixtures/big-script.js
================================================
function prepareScreenshotUnsafe(selectors, opts) {
var rect = getCaptureRect(selectors);
if (rect.error) {
return rect;
}
var viewportHeight = window.innerHeight || document.documentElement.clientHeight,
viewportWidth = window.innerWidth || document.documentElement.clientWidth,
documentHeight = document.documentElement.scrollHeight,
documentWidth = document.documentElement.scrollWidth,
coverage,
viewPort = new Rect({
left: util.getScrollLeft(),
top: util.getScrollTop(),
width: viewportWidth,
height: viewportHeight
});
if (!viewPort.rectInside(rect)) {
window.scrollTo(rect.left, rect.top);
}
if (opts.coverage) {
coverage = require('./gemini.coverage').collectCoverage(rect);
}
return {
viewportOffset: {
top: util.getScrollTop(),
left: util.getScrollLeft()
},
captureArea: rect.serialize(),
ignoreAreas: findIgnoreAreas(opts.ignoreSelectors),
viewportHeight: Math.round(viewportHeight),
documentHeight: Math.round(documentHeight),
documentWidth: Math.round(documentWidth),
coverage: coverage,
canHaveCaret: isEditable(document.activeElement)
};
}
function getElementCaptureRect(element) {
var pseudo = [':before', ':after'],
css = window.getComputedStyle(element),
clientRect = rect.getAbsoluteClientRect(element);
if (isHidden(css, clientRect)) {
return null;
}
var elementRect = getExtRect(css, clientRect);
util.each(pseudo, function(pseudoEl) {
css = window.getComputedStyle(element, pseudoEl);
elementRect = elementRect.merge(getExtRect(css, clientRect));
});
return elementRect;
}
function getExtRect(css, clientRect) {
var shadows = parseBoxShadow(css.boxShadow),
outline = parseInt(css.outlineWidth, 10);
if (isNaN(outline)) {
outline = 0;
}
return adjustRect(clientRect, shadows, outline);
}
function parseBoxShadow(value) {
value = value || '';
var regex = /[-+]?\d*\.?\d+px/g,
values = value.split(','),
results = [],
match;
util.each(values, function(value) {
if ((match = value.match(regex))) {
results.push({
offsetX: parseFloat(match[0]),
offsetY: parseFloat(match[1]) || 0,
blurRadius: parseFloat(match[2]) || 0,
spreadRadius: parseFloat(match[3]) || 0,
inset: value.indexOf('inset') !== -1
});
}
});
return results;
}
function adjustRect(rect, shadows, outline) {
var shadowRect = calculateShadowRect(rect, shadows),
outlineRect = calculateOutlineRect(rect, outline);
return shadowRect.merge(outlineRect);
}
function calculateOutlineRect(rect, outline) {
return new Rect({
top: Math.max(0, rect.top - outline),
left: Math.max(0, rect.left - outline),
bottom: rect.bottom + outline,
right: rect.right + outline
});
}
function calc
gitextract_k296bzti/
├── .gitignore
├── AUTHORS
├── LICENSE
├── README.md
├── ci/
│ └── jenkins.groovy
├── config/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── ru/
│ │ │ └── qatools/
│ │ │ └── gridrouter/
│ │ │ └── config/
│ │ │ ├── GridRouterException.java
│ │ │ ├── HostSelectionStrategy.java
│ │ │ ├── RandomHostSelectionStrategy.java
│ │ │ ├── RegionWithCount.java
│ │ │ ├── SequentialHostSelectionStrategy.java
│ │ │ ├── VersionWithCount.java
│ │ │ ├── WithBrowserVersionFind.java
│ │ │ ├── WithCopy.java
│ │ │ ├── WithCount.java
│ │ │ ├── WithRoute.java
│ │ │ ├── WithRoutesMap.java
│ │ │ ├── WithVersionFind.java
│ │ │ └── WithXmlView.java
│ │ └── resources/
│ │ └── xsd/
│ │ ├── bindings.xjb
│ │ └── config.xsd
│ └── test/
│ └── java/
│ └── ru/
│ └── qatools/
│ └── gridrouter/
│ └── config/
│ └── RandomHostSelectionStrategyTest.java
├── pom.xml
├── proxy/
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── ru/
│ │ │ └── qatools/
│ │ │ └── gridrouter/
│ │ │ ├── ConfigRepository.java
│ │ │ ├── ConfigRepositoryXml.java
│ │ │ ├── JsonWireUtils.java
│ │ │ ├── PingServlet.java
│ │ │ ├── ProxyServlet.java
│ │ │ ├── QuotaServlet.java
│ │ │ ├── RequestUtils.java
│ │ │ ├── RouteServlet.java
│ │ │ ├── SessionStorageEvictionScheduler.java
│ │ │ ├── SpringHttpServlet.java
│ │ │ ├── StatsServlet.java
│ │ │ ├── caps/
│ │ │ │ ├── AppiumCapabilityProcessor.java
│ │ │ │ ├── CapabilityProcessor.java
│ │ │ │ ├── CapabilityProcessorFactory.java
│ │ │ │ ├── DummyCapabilityProcessor.java
│ │ │ │ └── IECapabilityProcessor.java
│ │ │ ├── json/
│ │ │ │ ├── Describable.java
│ │ │ │ ├── JsonFormatter.java
│ │ │ │ ├── JsonMessageFactory.java
│ │ │ │ ├── JsonWithAnyProperties.java
│ │ │ │ ├── WithErrorMessage.java
│ │ │ │ └── WithJsonView.java
│ │ │ └── sessions/
│ │ │ ├── AvailableBrowserCheckExeption.java
│ │ │ ├── AvailableBrowsersChecker.java
│ │ │ ├── BrowserVersion.java
│ │ │ ├── BrowsersCountMap.java
│ │ │ ├── GridRouterUserStats.java
│ │ │ ├── MemoryStatsCounter.java
│ │ │ ├── SkipAvailableBrowsersChecker.java
│ │ │ ├── StatsCounter.java
│ │ │ ├── WaitAvailableBrowserTimeoutException.java
│ │ │ └── WaitAvailableBrowsersChecker.java
│ │ ├── resources/
│ │ │ ├── META-INF/
│ │ │ │ └── spring/
│ │ │ │ └── application-context.xml
│ │ │ ├── application.properties
│ │ │ ├── log4j.properties
│ │ │ └── xsd/
│ │ │ ├── json.xjb
│ │ │ └── json.xsd
│ │ └── webapp/
│ │ └── WEB-INF/
│ │ └── web.xml
│ └── test/
│ ├── java/
│ │ └── ru/
│ │ └── qatools/
│ │ └── gridrouter/
│ │ ├── CommandDecodingTest.java
│ │ ├── JsonWireUtilsTest.java
│ │ ├── PingServletTest.java
│ │ ├── ProxyServletExceptionsWithHubTest.java
│ │ ├── ProxyServletExceptionsWithoutHubTest.java
│ │ ├── ProxyServletTest.java
│ │ ├── ProxyServletWithBrokenAndOkHubsTest.java
│ │ ├── ProxyServletWithBrokenHubTest.java
│ │ ├── ProxyServletWithOneHubTest.java
│ │ ├── ProxyServletWithTwoHubsTest.java
│ │ ├── ProxyServletWithoutHubTest.java
│ │ ├── QuotaReloadTest.java
│ │ ├── QuotaServletTest.java
│ │ ├── RegionsTest.java
│ │ ├── RouteServletTest.java
│ │ ├── StatsServletTest.java
│ │ ├── caps/
│ │ │ ├── AppiumCapabilityProcessorTest.java
│ │ │ ├── CapabilityProcessorFactoryTest.java
│ │ │ └── IECapabilityProcessorTest.java
│ │ ├── json/
│ │ │ └── JsonMessageTest.java
│ │ ├── sessions/
│ │ │ ├── MemoryStatsCounterTest.java
│ │ │ └── WaitAvailableBrowsersCheckerTest.java
│ │ └── utils/
│ │ ├── FindElementCallback.java
│ │ ├── GridRouterRule.java
│ │ ├── HttpUtils.java
│ │ ├── HubEmulator.java
│ │ ├── HubEmulatorRule.java
│ │ ├── JettyRule.java
│ │ ├── JsonUtils.java
│ │ ├── MatcherUtils.java
│ │ ├── QuotaUtils.java
│ │ ├── RememberUrlCallback.java
│ │ ├── SocketUtil.java
│ │ └── TestConfigRepository.java
│ └── resources/
│ ├── META-INF/
│ │ └── spring/
│ │ └── test-application-context.xml
│ ├── application.properties
│ ├── log4j.properties
│ └── quota/
│ ├── user1.xml
│ ├── user2.xml
│ └── user3.xml
└── testing/
├── group_vars/
│ └── all.yml
├── ping-local-gridrouter.sh
├── roles/
│ ├── start/
│ │ ├── files/
│ │ │ └── gridrouter/
│ │ │ ├── conf/
│ │ │ │ ├── application.properties
│ │ │ │ ├── quota/
│ │ │ │ │ └── selenium.xml
│ │ │ │ └── users.properties
│ │ │ └── webapps/
│ │ │ └── ROOT.xml
│ │ └── tasks/
│ │ ├── before.yml
│ │ ├── main.yml
│ │ ├── start-gridrouter.yml
│ │ └── start-selenium.yml
│ ├── stop/
│ │ └── tasks/
│ │ ├── before.yml
│ │ ├── main.yml
│ │ ├── stop-gridrouter.yml
│ │ └── stop-selenium.yml
│ └── test/
│ ├── files/
│ │ ├── java/
│ │ │ ├── pom.xml
│ │ │ ├── run.sh
│ │ │ └── src/
│ │ │ └── test/
│ │ │ └── java/
│ │ │ └── SeleniumTest.java
│ │ ├── js/
│ │ │ ├── config.json
│ │ │ ├── fixtures/
│ │ │ │ └── big-script.js
│ │ │ ├── package.json
│ │ │ ├── run.sh
│ │ │ └── test/
│ │ │ ├── selenium-test-sync.js
│ │ │ └── selenium-test-wd.js
│ │ └── python/
│ │ ├── requirements.txt
│ │ ├── run.sh
│ │ └── src/
│ │ └── test_selenium.py
│ └── tasks/
│ ├── after.yml
│ ├── before.yml
│ ├── main.yml
│ └── run-tests.yml
├── start.yml
├── stop.yml
└── test.yml
SYMBOL INDEX (388 symbols across 83 files)
FILE: config/src/main/java/ru/qatools/gridrouter/config/GridRouterException.java
class GridRouterException (line 7) | public class GridRouterException extends RuntimeException {
method GridRouterException (line 9) | public GridRouterException(String message, Throwable cause) {
FILE: config/src/main/java/ru/qatools/gridrouter/config/HostSelectionStrategy.java
type HostSelectionStrategy (line 8) | public interface HostSelectionStrategy {
method selectRegion (line 10) | Region selectRegion(List<Region> allRegions, List<Region> unvisitedReg...
method selectHost (line 12) | Host selectHost(List<Host> hosts);
FILE: config/src/main/java/ru/qatools/gridrouter/config/RandomHostSelectionStrategy.java
class RandomHostSelectionStrategy (line 12) | public class RandomHostSelectionStrategy implements HostSelectionStrategy {
method selectRandom (line 14) | protected <T extends WithCount> T selectRandom(List<T> elements) {
method selectRegion (line 23) | @Override
method selectHost (line 28) | @Override
FILE: config/src/main/java/ru/qatools/gridrouter/config/RegionWithCount.java
type RegionWithCount (line 8) | public interface RegionWithCount extends WithCount {
method getHosts (line 10) | List<Host> getHosts();
method getCount (line 12) | @Override
FILE: config/src/main/java/ru/qatools/gridrouter/config/SequentialHostSelectionStrategy.java
class SequentialHostSelectionStrategy (line 8) | public class SequentialHostSelectionStrategy implements HostSelectionStr...
method selectRegion (line 12) | @Override
method selectHost (line 17) | @Override
FILE: config/src/main/java/ru/qatools/gridrouter/config/VersionWithCount.java
type VersionWithCount (line 8) | public interface VersionWithCount extends WithCount {
method getRegions (line 10) | List<Region> getRegions();
method getCount (line 12) | @Override
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithBrowserVersionFind.java
type WithBrowserVersionFind (line 11) | public interface WithBrowserVersionFind {
method getBrowsers (line 13) | List<Browser> getBrowsers();
method findBrowser (line 15) | default Browser findBrowser(String name) {
method find (line 21) | default Version find(String browserName, String browserVersion) {
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithCopy.java
type WithCopy (line 10) | public interface WithCopy {
method getHosts (line 12) | List<Host> getHosts();
method getName (line 14) | String getName();
method copy (line 22) | default Region copy() {
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithCount.java
type WithCount (line 6) | public interface WithCount {
method getCount (line 8) | int getCount();
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithRoute.java
type WithRoute (line 11) | public interface WithRoute {
method getAddress (line 13) | default String getAddress() {
method getRoute (line 17) | default String getRoute() {
method getRouteId (line 21) | default String getRouteId() {
method getName (line 25) | String getName();
method getPort (line 27) | int getPort();
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithRoutesMap.java
type WithRoutesMap (line 11) | public interface WithRoutesMap {
method getBrowsers (line 13) | List<Browser> getBrowsers();
method getRoutesMap (line 15) | default Map<String, String> getRoutesMap() {
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithVersionFind.java
type WithVersionFind (line 9) | public interface WithVersionFind {
method findDefaultVersion (line 11) | default Version findDefaultVersion() {
method findVersion (line 15) | default Version findVersion(String versionPrefix) {
method getVersions (line 21) | List<Version> getVersions();
method getDefaultVersion (line 23) | String getDefaultVersion();
FILE: config/src/main/java/ru/qatools/gridrouter/config/WithXmlView.java
type WithXmlView (line 15) | public interface WithXmlView {
method toXml (line 17) | default String toXml() {
FILE: config/src/test/java/ru/qatools/gridrouter/config/RandomHostSelectionStrategyTest.java
class RandomHostSelectionStrategyTest (line 20) | public class RandomHostSelectionStrategyTest {
method testRandomness (line 24) | @Test
method newHost (line 56) | private static Host newHost() {
method isAround (line 60) | private static Matcher<Integer> isAround(int count) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/ConfigRepository.java
type ConfigRepository (line 14) | public interface ConfigRepository {
method getQuotaMap (line 15) | Map<String, Browsers> getQuotaMap();
method getRoute (line 17) | String getRoute(String routeId);
method findVersion (line 19) | default Version findVersion(String user, JsonCapabilities caps) {
method getBrowsersCountMap (line 24) | default Map<String, Integer> getBrowsersCountMap(String user) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/ConfigRepositoryXml.java
class ConfigRepositoryXml (line 24) | public class ConfigRepositoryXml implements ConfigRepository, BeanChange...
method init (line 40) | @PostConstruct
method beanChanged (line 55) | @Override
method getQuotaMap (line 70) | @Override
method getRoute (line 75) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/JsonWireUtils.java
class JsonWireUtils (line 21) | public final class JsonWireUtils {
method JsonWireUtils (line 29) | private JsonWireUtils() {
method isUriValid (line 32) | public static boolean isUriValid(String uri) {
method isSessionDeleteRequest (line 36) | public static boolean isSessionDeleteRequest(HttpServletRequest reques...
method getSessionHash (line 40) | public static String getSessionHash(String uri) {
method getFullSessionId (line 44) | public static String getFullSessionId(String uri) {
method getUriPrefixLength (line 53) | public static int getUriPrefixLength() {
method redirectionUrl (line 57) | public static String redirectionUrl(String host, String command) throw...
method getCommand (line 61) | public static String getCommand(String uri) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/PingServlet.java
class PingServlet (line 16) | @WebServlet(urlPatterns = {"/ping"}, asyncSupported = true)
method doGet (line 19) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/ProxyServlet.java
class ProxyServlet (line 32) | @WebServlet(
method init (line 50) | @Override
method sendProxyRequest (line 56) | @Override
method rewriteTarget (line 69) | @Override
method getRequestWithoutSessionId (line 107) | protected Request getRequestWithoutSessionId(HttpServletRequest client...
method removeSessionIdSafe (line 117) | private String removeSessionIdSafe(String content, String remoteHost) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/QuotaServlet.java
class QuotaServlet (line 23) | @WebServlet(urlPatterns = {"/quota"}, asyncSupported = true)
method doGet (line 30) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/RequestUtils.java
class RequestUtils (line 5) | public final class RequestUtils {
method getRemoteHost (line 9) | public static String getRemoteHost(HttpServletRequest request) {
method RequestUtils (line 17) | private RequestUtils(){}
FILE: proxy/src/main/java/ru/qatools/gridrouter/RouteServlet.java
class RouteServlet (line 61) | @WebServlet(urlPatterns = {"/wd/hub/session"}, asyncSupported = true)
method doPost (line 87) | @Override
method getRouteCallable (line 107) | private Callable<Object> getRouteCallable(HttpServletRequest request, ...
method getRouteTimeout (line 115) | private int getRouteTimeout(String user, JsonMessage message) {
method route (line 130) | private void route(HttpServletRequest request, JsonMessage message,
method replyWithOk (line 224) | protected void replyWithOk(JsonMessage message, HttpServletResponse re...
method replyWithError (line 228) | protected void replyWithError(String errorMessage, HttpServletResponse...
method replyWithError (line 232) | protected void replyWithError(JsonMessage message, HttpServletResponse...
method reply (line 236) | protected void reply(int code, JsonMessage message, HttpServletRespons...
method post (line 246) | protected HttpPost post(String target, JsonMessage message) throws IOE...
method newHttpClient (line 254) | protected CloseableHttpClient newHttpClient(int maxTimeout) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/SessionStorageEvictionScheduler.java
class SessionStorageEvictionScheduler (line 15) | @Configuration
method expireOldSessions (line 25) | @Scheduled(cron = "${grid.router.evict.sessions.cron}")
FILE: proxy/src/main/java/ru/qatools/gridrouter/SpringHttpServlet.java
class SpringHttpServlet (line 12) | public abstract class SpringHttpServlet extends HttpServlet {
method init (line 13) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/StatsServlet.java
class StatsServlet (line 24) | @WebServlet(urlPatterns = {"/stats"}, asyncSupported = true)
method doGet (line 31) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/AppiumCapabilityProcessor.java
class AppiumCapabilityProcessor (line 16) | @SuppressWarnings("JavadocReference")
method accept (line 23) | @Override
method process (line 28) | @Override
method isMac (line 33) | private boolean isMac(JsonCapabilities jsonCapabilities) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/CapabilityProcessor.java
type CapabilityProcessor (line 8) | public interface CapabilityProcessor {
method accept (line 10) | boolean accept(JsonCapabilities caps);
method process (line 12) | void process(JsonCapabilities caps);
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/CapabilityProcessorFactory.java
class CapabilityProcessorFactory (line 12) | @Component
method getProcessor (line 19) | public CapabilityProcessor getProcessor(JsonCapabilities caps) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/DummyCapabilityProcessor.java
class DummyCapabilityProcessor (line 8) | public class DummyCapabilityProcessor implements CapabilityProcessor {
method accept (line 10) | @Override
method process (line 15) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/caps/IECapabilityProcessor.java
class IECapabilityProcessor (line 20) | @SuppressWarnings("JavadocReference")
method accept (line 26) | @Override
method process (line 31) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/Describable.java
type Describable (line 9) | public interface Describable {
method getBrowserName (line 11) | String getBrowserName();
method getVersion (line 12) | String getVersion();
method describe (line 14) | default String describe() {
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/JsonFormatter.java
class JsonFormatter (line 10) | public class JsonFormatter {
method toJson (line 12) | public static String toJson(Object o) throws JsonProcessingException {
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/JsonMessageFactory.java
class JsonMessageFactory (line 12) | public final class JsonMessageFactory {
method JsonMessageFactory (line 14) | JsonMessageFactory() {
method from (line 17) | public static JsonMessage from(String content) throws IOException {
method from (line 21) | public static JsonMessage from(InputStream stream) throws IOException {
method error (line 25) | public static JsonMessage error(int status, String errorMessage) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/JsonWithAnyProperties.java
class JsonWithAnyProperties (line 12) | public abstract class JsonWithAnyProperties {
method any (line 16) | @JsonAnyGetter
method set (line 21) | @JsonAnySetter
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/WithErrorMessage.java
type WithErrorMessage (line 13) | public interface WithErrorMessage {
method any (line 20) | Map<String, Object> any();
method set (line 22) | void set(String name, Object value);
method getErrorMessage (line 24) | @JsonIgnore
method setErrorMessage (line 36) | @JsonIgnore
FILE: proxy/src/main/java/ru/qatools/gridrouter/json/WithJsonView.java
type WithJsonView (line 8) | public interface WithJsonView {
method toJson (line 10) | default String toJson() throws JsonProcessingException {
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/AvailableBrowserCheckExeption.java
class AvailableBrowserCheckExeption (line 6) | public class AvailableBrowserCheckExeption extends RuntimeException {
method AvailableBrowserCheckExeption (line 7) | public AvailableBrowserCheckExeption(String message) {
method AvailableBrowserCheckExeption (line 11) | public AvailableBrowserCheckExeption(String message, Throwable cause) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/AvailableBrowsersChecker.java
type AvailableBrowsersChecker (line 8) | public interface AvailableBrowsersChecker {
method ensureFreeBrowsersAvailable (line 12) | void ensureFreeBrowsersAvailable(String user, String remoteHost, Strin...
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/BrowserVersion.java
class BrowserVersion (line 6) | public class BrowserVersion {
method BrowserVersion (line 11) | public BrowserVersion(String browser, String version) {
method getBrowser (line 16) | public String getBrowser() {
method getVersion (line 20) | public String getVersion() {
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/BrowsersCountMap.java
class BrowsersCountMap (line 10) | public class BrowsersCountMap extends HashMap<String, Map<String, Intege...
method increment (line 12) | public void increment(String browser, String version) {
method decrement (line 17) | public void decrement(BrowserVersion browser) {
method decrement (line 21) | public void decrement(String browser, String version) {
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/GridRouterUserStats.java
type GridRouterUserStats (line 8) | public interface GridRouterUserStats extends Serializable {
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/MemoryStatsCounter.java
class MemoryStatsCounter (line 16) | public class MemoryStatsCounter implements StatsCounter {
method startSession (line 23) | @Override
method updateSession (line 33) | @Override
method deleteSession (line 38) | @Override
method expireSessionsOlderThan (line 47) | @Override
method getActiveSessions (line 56) | @Override
method getStats (line 61) | @Override
method getSessionsCountForUser (line 66) | @Override
method getSessionsCountForUserAndBrowser (line 73) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/SkipAvailableBrowsersChecker.java
class SkipAvailableBrowsersChecker (line 8) | public class SkipAvailableBrowsersChecker implements AvailableBrowsersCh...
method ensureFreeBrowsersAvailable (line 9) | @Override
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/StatsCounter.java
type StatsCounter (line 9) | public interface StatsCounter {
method startSession (line 11) | default void startSession(String sessionId, String user, String browse...
method updateSession (line 15) | default void updateSession(String sessionId) {
method deleteSession (line 19) | default void deleteSession(String sessionId) {
method startSession (line 23) | void startSession(String sessionId, String user, String browser, Strin...
method updateSession (line 25) | default void updateSession(String sessionId, String route) {
method deleteSession (line 29) | void deleteSession(String sessionId, String route);
method expireSessionsOlderThan (line 31) | void expireSessionsOlderThan(Duration duration);
method getActiveSessions (line 33) | Set<String> getActiveSessions();
method getStats (line 35) | GridRouterUserStats getStats(String user);
method getSessionsCountForUser (line 37) | int getSessionsCountForUser(String user);
method getSessionsCountForUserAndBrowser (line 39) | int getSessionsCountForUserAndBrowser(String user, String browser, Str...
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowserTimeoutException.java
class WaitAvailableBrowserTimeoutException (line 6) | public class WaitAvailableBrowserTimeoutException extends AvailableBrows...
method WaitAvailableBrowserTimeoutException (line 7) | public WaitAvailableBrowserTimeoutException(String message) {
method WaitAvailableBrowserTimeoutException (line 11) | public WaitAvailableBrowserTimeoutException(String message, Throwable ...
FILE: proxy/src/main/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowsersChecker.java
class WaitAvailableBrowsersChecker (line 20) | public class WaitAvailableBrowsersChecker implements AvailableBrowsersCh...
method WaitAvailableBrowsersChecker (line 32) | public WaitAvailableBrowsersChecker() {
method WaitAvailableBrowsersChecker (line 35) | public WaitAvailableBrowsersChecker(int queueTimeout, int queueWaitInt...
method ensureFreeBrowsersAvailable (line 41) | @Override
method onWaitTimeout (line 62) | protected void onWaitTimeout(String user, String browser, Version vers...
method onWait (line 68) | protected void onWait(String user, String browser, Version version, St...
method onWaitFinished (line 73) | protected void onWaitFinished(String user, String browser, Version ver...
method countSessions (line 78) | protected int countSessions(String user, String browser, Version actua...
FILE: proxy/src/test/java/ru/qatools/gridrouter/CommandDecodingTest.java
class CommandDecodingTest (line 18) | @RunWith(Parameterized.class)
method CommandDecodingTest (line 29) | public CommandDecodingTest(String elementId) throws Exception {
method getData (line 34) | @Parameterized.Parameters
method testOutput (line 42) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/JsonWireUtilsTest.java
class JsonWireUtilsTest (line 19) | public class JsonWireUtilsTest {
method testGetSessionHash (line 21) | @Test
method testGetFullSessionId (line 30) | @Test
method sessionRequest (line 41) | public String sessionRequest(String routeHash, String sessionId, Strin...
FILE: proxy/src/test/java/ru/qatools/gridrouter/PingServletTest.java
class PingServletTest (line 18) | public class PingServletTest {
method testPingWithAuth (line 23) | @Test
method executeSimpleGet (line 28) | public static int executeSimpleGet(String url) throws IOException {
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletExceptionsWithHubTest.java
class ProxyServletExceptionsWithHubTest (line 10) | public class ProxyServletExceptionsWithHubTest extends ProxyServletExcep...
method tearDown (line 15) | @After
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletExceptionsWithoutHubTest.java
class ProxyServletExceptionsWithoutHubTest (line 18) | public class ProxyServletExceptionsWithoutHubTest {
method testProxyWithWrongAuth (line 23) | @Test(expected = UnsupportedCommandException.class)
method testProxyWithoutAuth (line 28) | @Test(expected = UnsupportedCommandException.class)
method testProxyWithNotSupportedBrowser (line 33) | @Test(expected = WebDriverException.class)
method testProxyWithNotSupportedVersion (line 38) | @Test(expected = WebDriverException.class)
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletTest.java
class ProxyServletTest (line 23) | public abstract class ProxyServletTest {
method ProxyServletTest (line 30) | public ProxyServletTest(String user) {
method getUrl (line 34) | protected final URL getUrl() {
method testSpecifyingBrowserVersion (line 38) | @Test
method testSessionIdDoesNotChange (line 45) | @Test
method testSessionIdChangesForANewBrowser (line 56) | @Test
method testQuit (line 65) | @Test
method testSendRequestParams (line 71) | @Test
method testFindElement (line 80) | @Test
method testNullVersion (line 92) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithBrokenAndOkHubsTest.java
class ProxyServletWithBrokenAndOkHubsTest (line 16) | public class ProxyServletWithBrokenAndOkHubsTest {
method testFailingHubIsSkipped (line 27) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithBrokenHubTest.java
class ProxyServletWithBrokenHubTest (line 16) | public class ProxyServletWithBrokenHubTest {
method testFailingHubIsSkipped (line 24) | @Test(expected = WebDriverException.class)
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithOneHubTest.java
class ProxyServletWithOneHubTest (line 15) | public class ProxyServletWithOneHubTest extends ProxyServletTest {
method ProxyServletWithOneHubTest (line 22) | public ProxyServletWithOneHubTest() throws Exception {
method testSessionIdsHaveACommonPrefix (line 26) | @Test
method testSpecifyingBrowserVersion (line 40) | @Test
method testSessionIdDoesNotChange (line 47) | @Test
method testSessionIdChangesForANewBrowser (line 55) | @Test
method testQuit (line 63) | @Test
method testSendRequestParams (line 72) | @Override
method testFindElement (line 79) | @Override
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithTwoHubsTest.java
class ProxyServletWithTwoHubsTest (line 15) | public class ProxyServletWithTwoHubsTest extends ProxyServletTest {
method ProxyServletWithTwoHubsTest (line 23) | public ProxyServletWithTwoHubsTest() throws Exception {
method testSessionIdsHaveNoCommonPrefix (line 27) | @Test
method testSpecifyingBrowserVersion (line 40) | @Override
method testSessionIdDoesNotChange (line 45) | @Override
method testSessionIdChangesForANewBrowser (line 52) | @Test
method testQuit (line 60) | @Override
method testSendRequestParams (line 67) | @Override
method testFindElement (line 74) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithoutHubTest.java
class ProxyServletWithoutHubTest (line 14) | public class ProxyServletWithoutHubTest {
method testProxyWithProperAuth (line 19) | @Test(expected = WebDriverException.class)
FILE: proxy/src/test/java/ru/qatools/gridrouter/QuotaReloadTest.java
class QuotaReloadTest (line 20) | @Ignore
method testQuotaIsReloadedOnFileChange (line 30) | @Test
method testNewQuotaFileIsLoaded (line 38) | @Test
method tearDown (line 46) | @After
method restoreQuotaFiles (line 52) | @AfterClass
FILE: proxy/src/test/java/ru/qatools/gridrouter/QuotaServletTest.java
class QuotaServletTest (line 29) | @RunWith(Parameterized.class)
method data (line 35) | @Parameters(name = "{0}")
method QuotaServletTest (line 45) | public QuotaServletTest(String user, int browsersCount) {
method testQuota (line 50) | @Test
method executeSimpleGet (line 57) | public static Map<String, Integer> executeSimpleGet(String url) throws...
FILE: proxy/src/test/java/ru/qatools/gridrouter/RegionsTest.java
class RegionsTest (line 18) | public class RegionsTest {
method testRegionIsChangedAfterFailedTry (line 32) | @Test
method testAllHostsAreTriedExactlyOnceInTheEnd (line 41) | @Test
method testConfigIsImmutableBetweenRequests (line 49) | @Test
method getWebDriverSafe (line 58) | private static void getWebDriverSafe(String user) {
FILE: proxy/src/test/java/ru/qatools/gridrouter/RouteServletTest.java
class RouteServletTest (line 15) | public class RouteServletTest {
method testRouteTimeout (line 23) | @Test(expected = WebDriverException.class, timeout = 10 * 1000)
FILE: proxy/src/test/java/ru/qatools/gridrouter/StatsServletTest.java
class StatsServletTest (line 23) | public class StatsServletTest {
method testStats (line 31) | @Test
method testStatsForDifferentUsers (line 45) | @Test
method testEvictionOfOldSession (line 53) | @Test
method testActiveSessionIsNotEvicted (line 63) | @Test
method getActual (line 75) | private BrowsersCountMap getActual(String user) throws IOException {
method newCountMap (line 79) | private BrowsersCountMap newCountMap(String browser, String version) {
method empty (line 85) | private BrowsersCountMap empty() {
FILE: proxy/src/test/java/ru/qatools/gridrouter/caps/AppiumCapabilityProcessorTest.java
class AppiumCapabilityProcessorTest (line 17) | public class AppiumCapabilityProcessorTest {
method setUp (line 21) | @Before
method accept (line 26) | @Test
method createCapabilities (line 34) | private JsonCapabilities createCapabilities(String browserName, String...
method process (line 40) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/caps/CapabilityProcessorFactoryTest.java
class CapabilityProcessorFactoryTest (line 19) | @RunWith(SpringJUnit4ClassRunner.class)
method testGetIEProcessor (line 26) | @Test
method testGetDummyProcessor (line 32) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/caps/IECapabilityProcessorTest.java
class IECapabilityProcessorTest (line 24) | public class IECapabilityProcessorTest {
method setUp (line 28) | @Before
method testAccept (line 33) | @Test
method testAddProxy (line 39) | @Test
method testJsonMarshalling (line 52) | @Test
method testExistingProxyIsNotOverridden (line 63) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/json/JsonMessageTest.java
class JsonMessageTest (line 17) | public class JsonMessageTest {
method testProperJson (line 19) | @Test
method testJsonWithKeysMissing (line 52) | @Test
method testErrorMessageForNullValue (line 64) | @Test
method testNullErrorMessageForPresentValue (line 71) | @Test
method testValueOfSimpleType (line 79) | @Test
method testJsonView (line 92) | @Test
method testSettingErrorMessage (line 119) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/sessions/MemoryStatsCounterTest.java
class MemoryStatsCounterTest (line 19) | public class MemoryStatsCounterTest {
method setUp (line 23) | @Before
method testEmptyStorage (line 28) | @Test
method testAddSession (line 35) | @Test
method testDifferentBrowsers (line 49) | @Test
method testDifferentVersions (line 60) | @Test
method testRemoveExistingSession (line 75) | @Test
method testRemoveNotExistingSession (line 92) | @Test
method testMultipleUsers (line 102) | @Test
method testNewSessionsAreNotExpired (line 115) | @Test
method testOldSessionsAreExpired (line 123) | @Test
method testUpdateExistingSession (line 136) | @Test
method testMultipleUsersExpiration (line 144) | @Test
method countJsonFor (line 154) | private String countJsonFor(String user) throws JsonProcessingException {
method expiredSessions (line 158) | public Set<String> expiredSessions(int millis) {
method expiredSessions (line 162) | public Set<String> expiredSessions(Duration duration) {
FILE: proxy/src/test/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowsersCheckerTest.java
class WaitAvailableBrowsersCheckerTest (line 20) | public class WaitAvailableBrowsersCheckerTest {
method setUp (line 25) | @Before
method testWaitAvailableBrowsersChecker (line 35) | @Test
method testWaitAvailableBrowsersTimeout (line 47) | @Test(expected = WaitAvailableBrowserTimeoutException.class)
method testNoWaitAvailableBrowser (line 52) | @Test
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/FindElementCallback.java
class FindElementCallback (line 17) | public class FindElementCallback implements ExpectationCallback {
method handle (line 19) | @Override
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/GridRouterRule.java
class GridRouterRule (line 15) | public class GridRouterRule extends JettyRule {
method GridRouterRule (line 29) | public GridRouterRule() {
method hubUrl (line 48) | public static URL hubUrl(String baseUrl) {
method baseUrl (line 56) | public String baseUrl(String user) {
method baseUrl (line 60) | public String baseUrl(String user, String password) {
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/HttpUtils.java
class HttpUtils (line 15) | public final class HttpUtils {
method HttpUtils (line 17) | private HttpUtils() {
method executeSimpleGet (line 20) | public static <T> T executeSimpleGet(String url, Class<T> clazz) throw...
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/HubEmulator.java
class HubEmulator (line 22) | public class HubEmulator {
method HubEmulator (line 30) | public HubEmulator(int hubPort) {
method emulate (line 34) | public HubEmulations emulate() {
method verify (line 38) | public HubVerifications verify() {
method stop (line 42) | public void stop() {
class HubEmulations (line 46) | public class HubEmulations {
method newSessions (line 48) | public HubEmulations newSessions(int sessionsCount) {
method newSessionFailures (line 55) | public HubEmulations newSessionFailures(int times) {
method newSessionFailures (line 59) | public HubEmulations newSessionFailures(Times times) {
method newSessionFreeze (line 64) | public HubEmulations newSessionFreeze(int seconds) {
method navigation (line 73) | public HubEmulations navigation() {
method findElement (line 80) | public HubEmulations findElement() {
method quit (line 87) | public HubEmulations quit() {
class HubVerifications (line 93) | public class HubVerifications {
method newSessionRequestsCountIs (line 95) | public HubVerifications newSessionRequestsCountIs(int sessionsCount) {
method quitRequestsCountIs (line 100) | public HubVerifications quitRequestsCountIs(int times) {
method totalRequestsCountIs (line 105) | public HubVerifications totalRequestsCountIs(int times) {
method newSessionRequest (line 111) | private static HttpRequest newSessionRequest() {
method sessionRequest (line 115) | private static HttpRequest sessionRequest(String handler) {
method sessionQuitRequest (line 119) | private static HttpRequest sessionQuitRequest() {
method emptyResponse (line 123) | private HttpResponse emptyResponse() {
method newSessionSuccessful (line 130) | private static HttpResponse newSessionSuccessful() {
method newSessionFailed (line 137) | private static HttpResponse newSessionFailed() {
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/HubEmulatorRule.java
class HubEmulatorRule (line 17) | public class HubEmulatorRule extends TestWatcher {
method HubEmulatorRule (line 23) | public HubEmulatorRule(int fromPort) {
method HubEmulatorRule (line 28) | public HubEmulatorRule(int fromPort, Consumer<HubEmulator> initializer) {
method finished (line 45) | @Override
method emulate (line 51) | public HubEmulator.HubEmulations emulate() {
method verify (line 55) | public HubEmulator.HubVerifications verify() {
method getPort (line 59) | public int getPort() {
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/JettyRule.java
class JettyRule (line 13) | public class JettyRule implements TestRule {
method JettyRule (line 23) | public JettyRule(String contextPath, String warPath, String classPath,...
method apply (line 31) | @Override
method before (line 46) | protected void before() throws Exception {
method after (line 67) | protected void after() throws Exception {
method getPort (line 71) | public int getPort() {
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/JsonUtils.java
class JsonUtils (line 20) | public final class JsonUtils {
method JsonUtils (line 22) | private JsonUtils() {
method buildJsonCapabilities (line 25) | public static JsonCapabilities buildJsonCapabilities(DesiredCapabiliti...
method buildJsonCapabilities (line 30) | public static JsonCapabilities buildJsonCapabilities(DesiredCapabiliti...
method buildJsonMessage (line 36) | public static JsonMessage buildJsonMessage(DesiredCapabilities capabil...
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/MatcherUtils.java
class MatcherUtils (line 14) | public final class MatcherUtils {
method MatcherUtils (line 16) | private MatcherUtils() {
method canObtain (line 28) | public static Matcher<String> canObtain(final GridRouterRule gridRoute...
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/QuotaUtils.java
class QuotaUtils (line 17) | public final class QuotaUtils {
method QuotaUtils (line 22) | private QuotaUtils() {
method replacePortInQuotaFile (line 25) | public static void replacePortInQuotaFile(String user, int port) {
method replacePortInQuotaFile (line 29) | public static void replacePortInQuotaFile(String user, int regionNum, ...
method copyQuotaFile (line 33) | public static void copyQuotaFile(String srcUser, String dstUser, int r...
method getQuotaFor (line 39) | public static Browsers getQuotaFor(String user) {
method writeQuotaFor (line 45) | public static synchronized void writeQuotaFor(String user, Browsers br...
method getQuotaFile (line 60) | public static File getQuotaFile(String user) {
method deleteQuotaFile (line 64) | @SuppressWarnings("ResultOfMethodCallIgnored")
method setPort (line 69) | public static void setPort(Browsers browsers, int regionNum, int hostN...
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/RememberUrlCallback.java
class RememberUrlCallback (line 14) | public class RememberUrlCallback implements ExpectationCallback {
method handle (line 18) | @Override
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/SocketUtil.java
type SocketUtil (line 6) | public enum SocketUtil {
method findFreePort (line 17) | public static int findFreePort() {
FILE: proxy/src/test/java/ru/qatools/gridrouter/utils/TestConfigRepository.java
class TestConfigRepository (line 26) | public class TestConfigRepository implements ConfigRepository {
method copy (line 53) | private static Browsers copy(Browsers quota) {
method resetConfig (line 60) | public static synchronized void resetConfig() {
method changePort (line 69) | public static synchronized void changePort(int from, int to) {
method getQuotaMap (line 84) | @Override
method getRoute (line 89) | @Override
FILE: testing/roles/test/files/java/src/test/java/SeleniumTest.java
class SeleniumTest (line 11) | public class SeleniumTest {
method testConnection (line 13) | @Test
FILE: testing/roles/test/files/js/fixtures/big-script.js
function prepareScreenshotUnsafe (line 1) | function prepareScreenshotUnsafe(selectors, opts) {
function getElementCaptureRect (line 43) | function getElementCaptureRect(element) {
function getExtRect (line 62) | function getExtRect(css, clientRect) {
function parseBoxShadow (line 73) | function parseBoxShadow(value) {
function adjustRect (line 94) | function adjustRect(rect, shadows, outline) {
function calculateOutlineRect (line 100) | function calculateOutlineRect(rect, outline) {
function calculateShadowRect (line 109) | function calculateShadowRect(rect, shadows) {
function calculateShadowExtent (line 119) | function calculateShadowExtent(shadows) {
function isEditable (line 137) | function isEditable(element) {
FILE: testing/roles/test/files/python/src/test_selenium.py
class TestSelenium (line 4) | class TestSelenium:
method test_selenium (line 5) | def test_selenium(self):
Condensed preview — 135 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (204K chars).
[
{
"path": ".gitignore",
"chars": 111,
"preview": "# IDEA files\n.idea\n*.iml\n\n# Maven files\ntarget\n\n# Docker compose files\ncompose/war\n\n# Npm modules\nnode_modules\n"
},
{
"path": "AUTHORS",
"chars": 390,
"preview": "The following authors have created the source code of \"Selenium Grid Router\"\npublished and distributed by YANDEX LLC as "
},
{
"path": "LICENSE",
"chars": 784,
"preview": "(C) YANDEX LLC, 2015\n\nThe Source Code called \"Selenium Grid Router\" available at https://github.com/seleniumkit/gridrout"
},
{
"path": "README.md",
"chars": 7744,
"preview": "# Selenium Grid Router\n\n**Selenium Grid Router** is a lightweight server that routes and proxies [Selenium Wedriver](htt"
},
{
"path": "ci/jenkins.groovy",
"chars": 6445,
"preview": "def project = 'gridrouter';\ndef repo = 'seleniumkit/gridrouter'\n\ndef buildWarJob = mavenJob(\"${project}_build-war\")\ndef "
},
{
"path": "config/pom.xml",
"chars": 1614,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/GridRouterException.java",
"chars": 314,
"preview": "package ru.qatools.gridrouter.config;\n\n/**\n * @author Dmitry Baev charlie@yandex-team.ru\n * @author Innokenty Shuvalov i"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/HostSelectionStrategy.java",
"chars": 292,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.List;\n\n/**\n * @author Innokenty Shuvalov innokenty@yandex-team.r"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/RandomHostSelectionStrategy.java",
"chars": 873,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static java.util.Colle"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/RegionWithCount.java",
"chars": 326,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.List;\n\n/**\n * @author Innokenty Shuvalov innokenty@yandex-team.r"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/SequentialHostSelectionStrategy.java",
"chars": 569,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.List;\n\n/**\n * @author Innokenty Shuvalov innokenty@yandex-team.r"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/VersionWithCount.java",
"chars": 335,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.List;\n\n/**\n * @author Innokenty Shuvalov innokenty@yandex-team.r"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/WithBrowserVersionFind.java",
"chars": 837,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.List;\n\nimport static org.apache.commons.lang3.StringUtils.isEmpt"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/WithCopy.java",
"chars": 582,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author Dmitry Baev ch"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/WithCount.java",
"chars": 154,
"preview": "package ru.qatools.gridrouter.config;\n\n/**\n * @author Innokenty Shuvalov innokenty@yandex-team.ru\n */\npublic interface W"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/WithRoute.java",
"chars": 604,
"preview": "package ru.qatools.gridrouter.config;\n\nimport org.apache.commons.codec.digest.DigestUtils;\n\nimport java.nio.charset.Stan"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/WithRoutesMap.java",
"chars": 694,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * @a"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/WithVersionFind.java",
"chars": 589,
"preview": "package ru.qatools.gridrouter.config;\n\nimport java.util.List;\n\n/**\n * @author Dmitry Baev charlie@yandex-team.ru\n * @aut"
},
{
"path": "config/src/main/java/ru/qatools/gridrouter/config/WithXmlView.java",
"chars": 1012,
"preview": "package ru.qatools.gridrouter.config;\n\nimport javax.xml.bind.JAXBContext;\nimport javax.xml.bind.JAXBException;\nimport ja"
},
{
"path": "config/src/main/resources/xsd/bindings.xjb",
"chars": 2034,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<jaxb:bindings\n xmlns:jaxb=\"http://java.sun.com/xml/ns/ja"
},
{
"path": "config/src/main/resources/xsd/config.xsd",
"chars": 1805,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xsd:schema attributeFormDefault=\"unqualified\" elementFormDefault=\"unqualified\"\n "
},
{
"path": "config/src/test/java/ru/qatools/gridrouter/config/RandomHostSelectionStrategyTest.java",
"chars": 1957,
"preview": "package ru.qatools.gridrouter.config;\n\nimport org.hamcrest.Matcher;\nimport org.junit.Test;\n\nimport java.util.ArrayList;\n"
},
{
"path": "pom.xml",
"chars": 6221,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "proxy/pom.xml",
"chars": 5930,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/ConfigRepository.java",
"chars": 1067,
"preview": "package ru.qatools.gridrouter;\n\nimport ru.qatools.gridrouter.config.Browser;\nimport ru.qatools.gridrouter.config.Browser"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/ConfigRepositoryXml.java",
"chars": 2671,
"preview": "package ru.qatools.gridrouter;\n\nimport org.apache.commons.io.FilenameUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.Lo"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/JsonWireUtils.java",
"chars": 2336,
"preview": "package ru.qatools.gridrouter;\n\nimport org.apache.http.client.utils.URIBuilder;\nimport org.slf4j.Logger;\nimport org.slf4"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/PingServlet.java",
"chars": 838,
"preview": "package ru.qatools.gridrouter;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimpor"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/ProxyServlet.java",
"chars": 5133,
"preview": "package ru.qatools.gridrouter;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.jetty.client.api.Request;\nimpor"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/QuotaServlet.java",
"chars": 1464,
"preview": "package ru.qatools.gridrouter;\n\nimport org.apache.commons.io.IOUtils;\nimport org.springframework.beans.factory.annotatio"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/RequestUtils.java",
"chars": 474,
"preview": "package ru.qatools.gridrouter;\n\nimport javax.servlet.http.HttpServletRequest;\n\npublic final class RequestUtils {\n\n pr"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/RouteServlet.java",
"chars": 12091,
"preview": "package ru.qatools.gridrouter;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport org.apache.commons.io."
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/SessionStorageEvictionScheduler.java",
"chars": 889,
"preview": "package ru.qatools.gridrouter;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframewor"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/SpringHttpServlet.java",
"chars": 563,
"preview": "package ru.qatools.gridrouter;\n\nimport javax.servlet.ServletConfig;\nimport javax.servlet.ServletException;\nimport javax."
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/StatsServlet.java",
"chars": 1526,
"preview": "package ru.qatools.gridrouter;\n\nimport org.apache.commons.io.IOUtils;\nimport org.springframework.beans.factory.annotatio"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/caps/AppiumCapabilityProcessor.java",
"chars": 1076,
"preview": "package ru.qatools.gridrouter.caps;\n\nimport org.springframework.stereotype.Service;\nimport ru.qatools.gridrouter.json.Js"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/caps/CapabilityProcessor.java",
"chars": 280,
"preview": "package ru.qatools.gridrouter.caps;\n\nimport ru.qatools.gridrouter.json.JsonCapabilities;\n\n/**\n * @author Innokenty Shuva"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/caps/CapabilityProcessorFactory.java",
"chars": 714,
"preview": "package ru.qatools.gridrouter.caps;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springfra"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/caps/DummyCapabilityProcessor.java",
"chars": 483,
"preview": "package ru.qatools.gridrouter.caps;\n\nimport ru.qatools.gridrouter.json.JsonCapabilities;\n\n/**\n * @author Innokenty Shuva"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/caps/IECapabilityProcessor.java",
"chars": 1290,
"preview": "package ru.qatools.gridrouter.caps;\n\nimport org.springframework.stereotype.Service;\nimport ru.qatools.gridrouter.json.Js"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/json/Describable.java",
"chars": 419,
"preview": "package ru.qatools.gridrouter.json;\n\nimport static org.apache.commons.lang3.StringUtils.isEmpty;\n\n/**\n * @author Innoken"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/json/JsonFormatter.java",
"chars": 545,
"preview": "package ru.qatools.gridrouter.json;\n\nimport com.fasterxml.jackson.annotation.JsonInclude;\nimport com.fasterxml.jackson.c"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/json/JsonMessageFactory.java",
"chars": 872,
"preview": "package ru.qatools.gridrouter.json;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\n\nimport java.io.IOException;\nim"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/json/JsonWithAnyProperties.java",
"chars": 590,
"preview": "package ru.qatools.gridrouter.json;\n\nimport com.fasterxml.jackson.annotation.JsonAnyGetter;\nimport com.fasterxml.jackson"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/json/WithErrorMessage.java",
"chars": 1112,
"preview": "package ru.qatools.gridrouter.json;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\n\nimport java.io.IOException;\nim"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/json/WithJsonView.java",
"chars": 296,
"preview": "package ru.qatools.gridrouter.json;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\n\n/**\n * @author Dmitry B"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/AvailableBrowserCheckExeption.java",
"chars": 348,
"preview": "package ru.qatools.gridrouter.sessions;\n\n/**\n * @author Ilya Sadykov\n */\npublic class AvailableBrowserCheckExeption exte"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/AvailableBrowsersChecker.java",
"chars": 370,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport ru.qatools.gridrouter.config.Version;\n\n/**\n * @author Ilya Sadykov\n */\np"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/BrowserVersion.java",
"chars": 464,
"preview": "package ru.qatools.gridrouter.sessions;\n\n/**\n * @author Innokenty Shuvalov innokenty@yandex-team.ru\n */\npublic class Bro"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/BrowsersCountMap.java",
"chars": 1141,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\n/**"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/GridRouterUserStats.java",
"chars": 165,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport java.io.Serializable;\n\n/**\n * @author Ilya Sadykov\n */\npublic interface "
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/MemoryStatsCounter.java",
"chars": 3172,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport java.time.Duration;\nimport java.time.temporal.Temporal;\nimport java.util"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/SkipAvailableBrowsersChecker.java",
"chars": 360,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport ru.qatools.gridrouter.config.Version;\n\n/**\n * @author Ilya Sadykov\n */\np"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/StatsCounter.java",
"chars": 1056,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport java.time.Duration;\nimport java.util.Set;\n\n/**\n * @author Innokenty Shuv"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowserTimeoutException.java",
"chars": 382,
"preview": "package ru.qatools.gridrouter.sessions;\n\n/**\n * @author Ilya Sadykov\n */\npublic class WaitAvailableBrowserTimeoutExcepti"
},
{
"path": "proxy/src/main/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowsersChecker.java",
"chars": 3435,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframe"
},
{
"path": "proxy/src/main/resources/META-INF/spring/application-context.xml",
"chars": 1157,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n xmlns:xsi=\"http"
},
{
"path": "proxy/src/main/resources/application.properties",
"chars": 621,
"preview": "grid.config.quota.directory=classpath:quota\ngrid.router.quota.repository=ru.qatools.gridrouter.ConfigRepositoryXml\ngrid."
},
{
"path": "proxy/src/main/resources/log4j.properties",
"chars": 379,
"preview": "# suppress inspection \"UnusedProperty\" for whole file\nlog4j.rootLogger=INFO, out\n\n# CONSOLE appender not used by default"
},
{
"path": "proxy/src/main/resources/xsd/json.xjb",
"chars": 1402,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<jaxb:bindings\n xmlns:jaxb=\"http://java.sun.com/xml/ns/ja"
},
{
"path": "proxy/src/main/resources/xsd/json.xsd",
"chars": 1109,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xsd:schema attributeFormDefault=\"unqualified\" elementFormDefault=\"unqualified\"\n "
},
{
"path": "proxy/src/main/webapp/WEB-INF/web.xml",
"chars": 1078,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<web-app\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xm"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/CommandDecodingTest.java",
"chars": 1335,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Paramet"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/JsonWireUtilsTest.java",
"chars": 2227,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.Test;\n\nimport java.nio.charset.StandardCharsets;\n\nimport static java.ut"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/PingServletTest.java",
"chars": 1008,
"preview": "package ru.qatools.gridrouter;\n\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.HttpCl"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/ProxyServletExceptionsWithHubTest.java",
"chars": 456,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.After;\nimport org.junit.Rule;\nimport ru.qatools.gridrouter.utils.HubEmu"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/ProxyServletExceptionsWithoutHubTest.java",
"chars": 1528,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.openqa.selenium.UnsupportedComm"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/ProxyServletTest.java",
"chars": 3315,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.openqa.selenium.By;\nimport org."
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithBrokenAndOkHubsTest.java",
"chars": 1078,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.openqa.selenium.remote.RemoteWe"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithBrokenHubTest.java",
"chars": 924,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.ClassRule;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.ope"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithOneHubTest.java",
"chars": 2452,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.openqa.selenium.remote.RemoteWe"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithTwoHubsTest.java",
"chars": 2438,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.openqa.selenium.remote.RemoteWe"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/ProxyServletWithoutHubTest.java",
"chars": 692,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.ClassRule;\nimport org.junit.Test;\nimport org.openqa.selenium.WebDriverE"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/QuotaReloadTest.java",
"chars": 2107,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.*;\nimport ru.qatools.gridrouter.utils.GridRouterRule;\nimport ru.qatools"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/QuotaServletTest.java",
"chars": 2130,
"preview": "package ru.qatools.gridrouter;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.apache.http.client.method"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/RegionsTest.java",
"chars": 1997,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.ClassRule;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.ope"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/RouteServletTest.java",
"chars": 939,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.ClassRule;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.ope"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/StatsServletTest.java",
"chars": 3007,
"preview": "package ru.qatools.gridrouter;\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.openqa.selenium.WebDriver;\nimpo"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/caps/AppiumCapabilityProcessorTest.java",
"chars": 1783,
"preview": "package ru.qatools.gridrouter.caps;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.openqa.selenium.Platform"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/caps/CapabilityProcessorFactoryTest.java",
"chars": 1447,
"preview": "package ru.qatools.gridrouter.caps;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework."
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/caps/IECapabilityProcessorTest.java",
"chars": 2868,
"preview": "package ru.qatools.gridrouter.caps;\n\nimport org.json.JSONObject;\nimport org.junit.Before;\nimport org.junit.Test;\nimport "
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/json/JsonMessageTest.java",
"chars": 5087,
"preview": "package ru.qatools.gridrouter.json;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport org.json.JSONObje"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/sessions/MemoryStatsCounterTest.java",
"chars": 7621,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport com.fasterxml.jackson.core.JsonProcessingException;\nimport org.junit.Bef"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/sessions/WaitAvailableBrowsersCheckerTest.java",
"chars": 2307,
"preview": "package ru.qatools.gridrouter.sessions;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport ru.qatools.gridrouter.co"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/FindElementCallback.java",
"chars": 1078,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.json.JSONObject;\nimport org.mockserver.mock.action.ExpectationCallback;"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/GridRouterRule.java",
"chars": 2101,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.eclipse.jetty.security.HashLoginService;\nimport org.eclipse.jetty.util."
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/HttpUtils.java",
"chars": 843,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport com.fasterxml.jackson.databind.ObjectMapper;\nimport org.apache.http.client."
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/HubEmulator.java",
"chars": 4555,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.json.JSONObject;\nimport org.mockserver.integration.ClientAndServer;\nimp"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/HubEmulatorRule.java",
"chars": 1754,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.junit.rules.TestWatcher;\nimport org.junit.runner.Description;\nimport or"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/JettyRule.java",
"chars": 2151,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.eclipse.jetty.annotations.AnnotationConfiguration;\nimport org.eclipse.j"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/JsonUtils.java",
"chars": 1692,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.json.JSONObject;\nimport org.openqa.selenium.remote.DesiredCapabilities;"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/MatcherUtils.java",
"chars": 1594,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.hamcrest.Description;\nimport org.hamcrest.Matcher;\nimport org.hamcrest."
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/QuotaUtils.java",
"chars": 2653,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.lang3.Serializat"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/RememberUrlCallback.java",
"chars": 1009,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.json.JSONObject;\nimport org.mockserver.mock.action.ExpectationCallback;"
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/SocketUtil.java",
"chars": 1396,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\n\npublic enum SocketUtil "
},
{
"path": "proxy/src/test/java/ru/qatools/gridrouter/utils/TestConfigRepository.java",
"chars": 3690,
"preview": "package ru.qatools.gridrouter.utils;\n\nimport org.apache.commons.io.FilenameUtils;\nimport org.slf4j.Logger;\nimport org.sl"
},
{
"path": "proxy/src/test/resources/META-INF/spring/test-application-context.xml",
"chars": 498,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n xmlns:xsi=\"http"
},
{
"path": "proxy/src/test/resources/application.properties",
"chars": 549,
"preview": "grid.config.quota.directory=classpath:quota\ngrid.router.quota.repository=ru.qatools.gridrouter.utils.TestConfigRepositor"
},
{
"path": "proxy/src/test/resources/log4j.properties",
"chars": 463,
"preview": "# suppress inspection \"UnusedProperty\" for whole file\nlog4j.rootLogger=INFO, out\n\n# CONSOLE appender not used by default"
},
{
"path": "proxy/src/test/resources/quota/user1.xml",
"chars": 309,
"preview": "<qa:browsers xmlns:qa=\"urn:config.gridrouter.qatools.ru\">\n <browser name=\"firefox\" defaultVersion=\"32.0\">\n <ve"
},
{
"path": "proxy/src/test/resources/quota/user2.xml",
"chars": 372,
"preview": "<qa:browsers xmlns:qa=\"urn:config.gridrouter.qatools.ru\">\n <browser name=\"firefox\" defaultVersion=\"32.0\">\n <ve"
},
{
"path": "proxy/src/test/resources/quota/user3.xml",
"chars": 492,
"preview": "<qa:browsers xmlns:qa=\"urn:config.gridrouter.qatools.ru\">\n <browser name=\"firefox\" defaultVersion=\"32.0\">\n <ve"
},
{
"path": "testing/group_vars/all.yml",
"chars": 41,
"preview": "workspace: \"{{ ansible_env.PWD }}/target\""
},
{
"path": "testing/ping-local-gridrouter.sh",
"chars": 123,
"preview": "#!/usr/bin/env bash\ncurl http://boot2docker:$(docker ps | grep jetty | sed 's/.*0.0.0.0://' | sed 's/->.*//')/ping && ec"
},
{
"path": "testing/roles/start/files/gridrouter/conf/application.properties",
"chars": 222,
"preview": "# suppress inspection \"UnusedProperty\" for whole file\ngrid.config.quota.directory=classpath:quota\ngrid.config.quota.hotR"
},
{
"path": "testing/roles/start/files/gridrouter/conf/quota/selenium.xml",
"chars": 489,
"preview": "<browsers>\n <browser name=\"firefox\" defaultVersion=\"38.0\">\n <version number=\"38.0\">\n <region name=\""
},
{
"path": "testing/roles/start/files/gridrouter/conf/users.properties",
"chars": 23,
"preview": "selenium:selenium, user"
},
{
"path": "testing/roles/start/files/gridrouter/webapps/ROOT.xml",
"chars": 759,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE Configure PUBLIC\n \"-//Mort Bay Consulting//DTD Configure//EN\"\n "
},
{
"path": "testing/roles/start/tasks/before.yml",
"chars": 40,
"preview": "- debug: msg=\"workspace {{ workspace }}\""
},
{
"path": "testing/roles/start/tasks/main.yml",
"chars": 196,
"preview": "---\n - include: before.yml\n - include: start-selenium.yml version=\"2.46.0\" browser=\"firefox\"\n - include: start-seleni"
},
{
"path": "testing/roles/start/tasks/start-gridrouter.yml",
"chars": 760,
"preview": "- name: copy configuration files\n copy: src=gridrouter dest={{ workspace }}\n\n- shell: \"ls -d {{ ansible_env.PWD }}/../p"
},
{
"path": "testing/roles/start/tasks/start-selenium.yml",
"chars": 193,
"preview": "- name: start selenium standalone with {{ browser }}\n docker:\n name: \"{{ browser }}\"\n image: selenium/standalone-"
},
{
"path": "testing/roles/stop/tasks/before.yml",
"chars": 40,
"preview": "- debug: msg=\"workspace {{ workspace }}\""
},
{
"path": "testing/roles/stop/tasks/main.yml",
"chars": 191,
"preview": "---\n - include: before.yml\n - include: stop-selenium.yml version=\"2.46.0\" browser=\"firefox\"\n - include: stop-selenium"
},
{
"path": "testing/roles/stop/tasks/stop-gridrouter.yml",
"chars": 200,
"preview": "- name: stop jetty with gridrouter\n docker:\n name: gridrouter\n image: jetty:9.3.0-jre8\n state: absent\n\n- name:"
},
{
"path": "testing/roles/stop/tasks/stop-selenium.yml",
"chars": 191,
"preview": "- name: stop selenium standalone with {{ browser }}\n docker:\n name: \"{{ browser }}\"\n image: selenium/standalone-{"
},
{
"path": "testing/roles/test/files/java/pom.xml",
"chars": 894,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n xmlns:xsi=\"http://www"
},
{
"path": "testing/roles/test/files/java/run.sh",
"chars": 36,
"preview": "#! /bin/sh\nmvn -f /code/pom.xml test"
},
{
"path": "testing/roles/test/files/java/src/test/java/SeleniumTest.java",
"chars": 744,
"preview": "import org.junit.Test;\nimport org.openqa.selenium.WebDriver;\nimport org.openqa.selenium.remote.DesiredCapabilities;\nimpo"
},
{
"path": "testing/roles/test/files/js/config.json",
"chars": 66,
"preview": "{\n\t\"baseUrl\": \"http://selenium:selenium@gridrouter:8080/wd/hub\"\n}\n"
},
{
"path": "testing/roles/test/files/js/fixtures/big-script.js",
"chars": 4309,
"preview": "function prepareScreenshotUnsafe(selectors, opts) {\n var rect = getCaptureRect(selectors);\n if (rect.error) {\n "
},
{
"path": "testing/roles/test/files/js/package.json",
"chars": 418,
"preview": "{\n \"name\": \"wd-test\",\n \"version\": \"1.0.0\",\n \"description\": \"webdriver test\",\n \"main\": \"index.js\",\n \"directories\": {"
},
{
"path": "testing/roles/test/files/js/run.sh",
"chars": 41,
"preview": "#! /bin/sh\ncd /code\nnpm install\nnpm test\n"
},
{
"path": "testing/roles/test/files/js/test/selenium-test-sync.js",
"chars": 551,
"preview": "var assert = require('assert'),\n config = require('../config.json'),\n WebDriver = require('webdriver-http-sync');\n"
},
{
"path": "testing/roles/test/files/js/test/selenium-test-wd.js",
"chars": 1028,
"preview": "'use strict';\nvar fs = require('fs'),\n assert = require('assert'),\n config = require('../config.json'),\n wd = r"
},
{
"path": "testing/roles/test/files/python/requirements.txt",
"chars": 30,
"preview": "selenium==2.46.0\npytest==2.7.1"
},
{
"path": "testing/roles/test/files/python/run.sh",
"chars": 145,
"preview": "#! /bin/sh\npip install -r /code/requirements.txt\npy.test --junitxml=/code/target/surefire-reports/test_selenium.xml -q /"
},
{
"path": "testing/roles/test/files/python/src/test_selenium.py",
"chars": 437,
"preview": "from selenium import webdriver\nfrom selenium.webdriver.common.desired_capabilities import DesiredCapabilities\n\nclass Tes"
},
{
"path": "testing/roles/test/tasks/after.yml",
"chars": 115,
"preview": "- name: \"copy report files\"\n copy: src={{ workspace }}/report/ dest={{ ansible_env.PWD }}/target/surefire-reports\n"
},
{
"path": "testing/roles/test/tasks/before.yml",
"chars": 40,
"preview": "- debug: msg=\"workspace {{ workspace }}\""
},
{
"path": "testing/roles/test/tasks/main.yml",
"chars": 182,
"preview": "---\n - include: before.yml\n - include: run-tests.yml language=\"python\" image=\"python:2.7\"\n - include: run-tests.yml l"
},
{
"path": "testing/roles/test/tasks/run-tests.yml",
"chars": 972,
"preview": "- name: \"{{ language }} gathering facts\"\n set_fact:\n name: \"{{ language }}_tests\"\n project: \"{{ workspace }}/{{ l"
},
{
"path": "testing/start.yml",
"chars": 65,
"preview": "---\n\n- hosts: 127.0.0.1\n connection: local\n\n roles:\n - start"
},
{
"path": "testing/stop.yml",
"chars": 64,
"preview": "---\n\n- hosts: 127.0.0.1\n connection: local\n\n roles:\n - stop"
},
{
"path": "testing/test.yml",
"chars": 64,
"preview": "---\n\n- hosts: 127.0.0.1\n connection: local\n\n roles:\n - test"
}
]
About this extraction
This page contains the full source code of the seleniumkit/gridrouter GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 135 files (180.9 KB), approximately 46.2k tokens, and a symbol index with 388 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.