I am trying to connect to the AWS device farm for desktop browser testing with Selenium 4 through a cooperate proxy, with no luck.
Here is the code I am using:
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>My Selenium Tests</groupId>
<artifactId>Selenium</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.17.209</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- TestNG -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.6.0</version>
<scope>compile</scope>
</dependency>
<!-- AWS -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<version>2.17.209</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>devicefarm</artifactId>
<version>2.17.209</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>aws-sdk-java</artifactId>
<version>2.17.209</version>
</dependency>
<!-- Selenium -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
</project>
SeleniumTest.java
package Selenium;
import okhttp3.*;
import okhttp3.Authenticator;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.remote.http.ClientConfig;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpClient.Factory;
import org.testng.annotations.Test;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.http.apache.ProxyConfiguration;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.devicefarm.DeviceFarmClient;
import software.amazon.awssdk.services.devicefarm.model.CreateTestGridUrlRequest;
import software.amazon.awssdk.services.devicefarm.model.CreateTestGridUrlResponse;
import java.io.IOException;
import java.net.*;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
public class SeleniumTest {
@Test
public void search() throws MalformedURLException, URISyntaxException, UnknownHostException {
ProxyConfiguration.Builder proxyConfiguration = ProxyConfiguration.builder();
proxyConfiguration.endpoint(new URI("http://myProxyUrl:8080"));
proxyConfiguration.username("myProxyUsername");
proxyConfiguration.password("myProxyPassword");
ApacheHttpClient.Builder httpClientBuilder = ApacheHttpClient.builder().proxyConfiguration(proxyConfiguration.build());
String projectARN = "arn:aws:devicefarm:someString:testgrid-project:someUid";
DeviceFarmClient deviceFarmClient = DeviceFarmClient.builder()
.credentialsProvider(DefaultCredentialsProvider.create())
.httpClientBuilder(httpClientBuilder)
.overrideConfiguration(ClientOverrideConfiguration.builder().build())
.region(Region.US_WEST_2)
.build();
CreateTestGridUrlRequest testGridUrlrequest = CreateTestGridUrlRequest.builder()
.expiresInSeconds(300)
.projectArn(projectARN)
.build();
CreateTestGridUrlResponse response = deviceFarmClient.createTestGridUrl(testGridUrlrequest);
URL testGridUrl = new URL(response.url());
Authenticator proxyAuthenticator = new Authenticator() {
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic("myProxyUsername", "myProxyPassword");
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
}
};
Builder okHttpClientBuilder = new Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("myProxyUrl", 8080)))
.proxyAuthenticator(proxyAuthenticator);
FirefoxOptions browserOptions = new FirefoxOptions();
browserOptions.addPreference("network.proxy.type", 0);
Factory factory = new MyHttpClientFactory(new OkHttpClient(okHttpClientBuilder));
HttpCommandExecutor executor = new HttpCommandExecutor(new HashMap<>(), testGridUrl, factory);
RemoteWebDriver remoteWebDriver = new RemoteWebDriver(executor, browserOptions);
remoteWebDriver.navigate().to("https://www.google.de");
remoteWebDriver.quit();
}
public class MyHttpClientFactory implements HttpClient.Factory {
final OkHttpClient okHttpClient;
public MyHttpClientFactory(OkHttpClient okHttpClient) {
this.okHttpClient = okHttpClient;
}
@Override
public HttpClient createClient(URL url) {
return (HttpClient) okHttpClient;
}
@Override
public HttpClient createClient(ClientConfig config) {
return (HttpClient) okHttpClient;
}
@Override
public void cleanupIdleClients() {
}
}
}
As you can see, I used the ApacheHttpClient as HTTPClient for the AWS DeviceFarmClient, so I can authenticate with the cooperate proxy - which works like a charm. I get the testGridUrl, which I can use in the second step to send commands via the RemoteWebDriver to the AWS Desktop Browser.
This is where the problems start. I use the OkHttpClient (recommended by Selenium) as HTTPClient for the RemoteWebDriver - here also to enable proxy authentication (which I think is not possible with the built in HTTPClient).
But when the test is run, I get a class cast exception - it seems the okHttpCLient cannot be cast to HttpClient.
java.lang.ClassCastException: class okhttp3.OkHttpClient cannot be cast to class org.openqa.selenium.remote.http.HttpClient (okhttp3.OkHttpClient and org.openqa.selenium.remote.http.HttpClient are in unnamed module of loader 'app')
at Selenium.SeleniumTest$MyHttpClientFactory.createClient(SeleniumTest.java:103)
at org.openqa.selenium.remote.HttpCommandExecutor.<init>(HttpCommandExecutor.java:107)
at org.openqa.selenium.remote.HttpCommandExecutor.<init>(HttpCommandExecutor.java:94)
at Selenium.SeleniumTest.search(SeleniumTest.java:77)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.testng.internal.invokers.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:139)
at org.testng.internal.invokers.TestInvoker.invokeMethod(TestInvoker.java:677)
at org.testng.internal.invokers.TestInvoker.invokeTestMethod(TestInvoker.java:221)
at org.testng.internal.invokers.MethodRunner.runInSequence(MethodRunner.java:50)
at org.testng.internal.invokers.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:962)
at org.testng.internal.invokers.TestInvoker.invokeTestMethods(TestInvoker.java:194)
at org.testng.internal.invokers.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:148)
at org.testng.internal.invokers.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.testng.TestRunner.privateRun(TestRunner.java:806)
at org.testng.TestRunner.run(TestRunner.java:601)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:433)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:427)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:387)
at org.testng.SuiteRunner.run(SuiteRunner.java:330)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:95)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1256)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1176)
at org.testng.TestNG.runSuites(TestNG.java:1099)
at org.testng.TestNG.run(TestNG.java:1067)
Did anyone use a proxy for connection to the AWS DeviceFarm before with Selenium 4 and can give me some hints on how to procede (replace the HTTPClient? Cast possible?)
All the best, Pita.