Skip to content
This repository was archived by the owner on Nov 23, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@
*/
package com.cognifide.qa.bb.modules;

import org.openqa.selenium.Proxy;

import com.cognifide.qa.bb.proxy.ProxyController;
import com.cognifide.qa.bb.proxy.ProxyControllerProvider;
import com.cognifide.qa.bb.proxy.ProxyEventListener;
import com.cognifide.qa.bb.proxy.providers.DefaultProxyProvider;
import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;

Expand All @@ -31,5 +34,7 @@ public class ProxyModule extends AbstractModule {
protected void configure() {
bind(ProxyController.class).toProvider(ProxyControllerProvider.class);
Multibinder.newSetBinder(binder(), ProxyEventListener.class);

bind(Proxy.class).toProvider(DefaultProxyProvider.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,23 @@
*/
package com.cognifide.qa.bb.provider.selenium.webdriver.modifiers.capabilities;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;

import com.cognifide.qa.bb.constants.ConfigKeys;
import com.cognifide.qa.bb.proxy.ProxyController;
import com.google.inject.Inject;
import com.google.inject.name.Named;

import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.client.ClientUtil;

public class EnableProxy implements CapabilitiesModifier {

@Inject
@Named(ConfigKeys.PROXY_ENABLED)
private boolean proxyEnabled;

@Inject
@Named(ConfigKeys.PROXY_IP)
private String proxyIp;

@Inject
private ProxyController proxyController;
private Proxy proxy;

@Override
public boolean shouldModify() {
Expand All @@ -60,14 +49,7 @@ public Capabilities modify(Capabilities capabilities) {

private DesiredCapabilities enableProxy(Capabilities capabilities) {
DesiredCapabilities caps = new DesiredCapabilities(capabilities);
try {
InetAddress proxyInetAddress = InetAddress.getByName(proxyIp);
BrowserMobProxy browserMobProxy = proxyController.startProxyServer(proxyInetAddress);
Proxy seleniumProxy = ClientUtil.createSeleniumProxy(browserMobProxy, proxyInetAddress);
caps.setCapability(CapabilityType.PROXY, seleniumProxy);
} catch (UnknownHostException e) {
throw new IllegalStateException(e);
}
caps.setCapability(CapabilityType.PROXY, proxy);
return caps;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class ProxyController {
}

public BrowserMobProxy startProxyServer(InetAddress proxyAddress) {
LOG.info("Starting BrowserMobProxy...");
if (!browserMobProxy.isStarted()) {
try {
browserMobProxy.start(port, proxyAddress);
Expand All @@ -72,6 +73,7 @@ public BrowserMobProxy startProxyServer(InetAddress proxyAddress) {
}

public void stopProxyServer() {
LOG.info("Stopping BrowserMobProxy...");
if (browserMobProxy.isStarted()) {
try {
browserMobProxy.stop();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*-
* #%L
* Bobcat
* %%
* Copyright (C) 2019 Cognifide Ltd.
* %%
* 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.
* #L%
*/
package com.cognifide.qa.bb.proxy.providers;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.openqa.selenium.Proxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cognifide.qa.bb.constants.ConfigKeys;
import com.cognifide.qa.bb.proxy.ProxyController;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;

import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.client.ClientUtil;

public class DefaultProxyProvider implements Provider<Proxy> {
private static final Logger LOG = LoggerFactory.getLogger(DefaultProxyProvider.class);

@Inject
@Named(ConfigKeys.PROXY_IP)
private String proxyIp;

@Inject
private ProxyController proxyController;

private Proxy proxy;

@Override
public Proxy get() {
if (proxy == null) {
proxy = createProxy();
}
return proxy;
}

private Proxy createProxy() {
InetAddress proxyInetAddress = null;
try {
proxyInetAddress = InetAddress.getByName(proxyIp);
} catch (UnknownHostException e) {
LOG.error("Failed to parse by name the provided IP address: {}", proxyIp, e);
}
BrowserMobProxy browserMobProxy = proxyController.startProxyServer(proxyInetAddress);
return ClientUtil.createSeleniumProxy(browserMobProxy, proxyInetAddress);
}
}
6 changes: 6 additions & 0 deletions bb-integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@
<version>3.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.25.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*-
* #%L
* Bobcat
* %%
* Copyright (C) 2019 Cognifide Ltd.
* %%
* 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.
* #L%
*/
package com.cognifide.qa.bb.core.modules;

import com.cognifide.qa.bb.constants.ConfigKeys;
import com.cognifide.qa.bb.modules.CoreModule;
import com.google.inject.AbstractModule;

public class ProxyEnabledModule extends AbstractModule {
@Override
protected void configure() {
System.setProperty(ConfigKeys.PROXY_ENABLED, "true");
install(new CoreModule());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Bobcat
* %%
* Copyright (C) 2016 Cognifide Ltd.
* Copyright (C) 2019 Cognifide Ltd.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,65 +19,65 @@
*/
package com.cognifide.qa.bb.proxy;

import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.assertj.core.api.Assertions.assertThat;

import java.io.IOException;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.WebDriver;

import com.cognifide.qa.bb.core.modules.ProxyEnabledModule;
import com.cognifide.qa.bb.junit5.BobcatExtension;
import com.cognifide.qa.bb.junit5.guice.Modules;
import com.cognifide.qa.bb.modules.CoreModule;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.google.inject.Inject;

import io.netty.handler.codec.http.HttpRequest;
import net.lightbody.bmp.BrowserMobProxy;
import net.lightbody.bmp.BrowserMobProxyServer;
import net.lightbody.bmp.filters.RequestFilter;
import net.lightbody.bmp.util.HttpMessageContents;
import net.lightbody.bmp.util.HttpMessageInfo;

@ExtendWith(MockitoExtension.class)
@Modules({CoreModule.class})
public class RequestFilterRegistryTest extends AbstractProxyTest {
@BobcatExtension
@Modules({ProxyEnabledModule.class})
class RequestFilterRegistryTest {

@Inject
private RequestFilterRegistry requestFilterRegistry;
private WebDriver webDriver;

@Inject
private RequestFilterRegistry requestFilterRegistryAlias;
private RequestFilterRegistry filters;

@Mock
private RequestFilter requestFilter;
private WireMockServer wireMockServer;

@Test
public void requestFilterRegistryShouldBeSingleton() {
assertSame(requestFilterRegistry, requestFilterRegistryAlias,
"RequestFilterRegistry should be thread-scoped");
@BeforeEach
void setup() {
wireMockServer = new WireMockServer();
wireMockServer.start();
}

@Disabled("TODO - some problems with timing (works in debug mode)")
@Test
public void shouldCallFilterByRegistry() throws IOException {
// given
BrowserMobProxy browserMobProxy = new BrowserMobProxyServer();
startProxyServer(browserMobProxy);
requestFilterRegistry.add(requestFilter);
browserMobProxy.addRequestFilter(requestFilterRegistry);
// when
DesiredCapabilities capabilities = proxyCapabilities(browserMobProxy);
visitSamplePage(capabilities);
browserMobProxy.stop();
// then
verify(requestFilter, atLeastOnce()).filterRequest(any(HttpRequest.class),
any(HttpMessageContents.class), any(HttpMessageInfo.class));
void bobcatUserCanAddHeaderWhenUsingProxy() {
//given
stubFor(get(urlEqualTo("/proxy-test"))
.withHeader("Bobcat-Header", equalTo("present"))
.willReturn(aResponse()
.withStatus(200)
.withBody("works correctly")));

filters.add((request, contents, messageInfo) -> {
request.headers().add("Bobcat-Header", "present");
return null;
});

//when
String url = String.format("http://%s:%s/proxy-test", wireMockServer.getOptions().bindAddress(),
wireMockServer.getOptions().portNumber());
webDriver.get(url);

//then
assertThat(webDriver.getPageSource()).contains("works correctly");
}

@AfterEach
void teardown() {
if (wireMockServer != null) {
wireMockServer.stop();
}
}
}
2 changes: 2 additions & 0 deletions docs/_data/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ docs:
url: /docs/modules/core/actions/
- title: "Setting cookies"
url: /docs/modules/core/cookies/
- title: "Working with proxy"
url: /docs/modules/core/proxy/
- title: "AEM features"
children:
- title: "AEM modules"
Expand Down
43 changes: 43 additions & 0 deletions docs/_docs/modules/core/proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: "Working with proxy"
---

## Overview
Potentially, you might run into a case, when you want to modify HTTP requests during your test runs.
Selenium does not have an in-built solution for that, but provides an option to hook up a proxy to
the browser it drives.

Bobcat uses `BrowserMobProxy` as a proxy solution. It can be controlled programmatically from your tests.

### Enabling proxy
To enable proxy use dedicated properties in your config.

Default config:
```yaml
proxy.enabled: false
proxy.ip: 127.0.0.1
proxy.port: 9000
```

- `proxy.enabled` - enable the proxy
- `proxy.ip` - define the IP on which the proxy listens (useful for external proxy)
- `proxy.port` - define the port used by the proxy

### Modifying requests
Most common use case when working with proxy is modifying requests, to e.g. attach additional header.
This can be done by registering a `RequestFilter` in the `RequestFilterRegistry`.

Example:
```java
@Inject
private RequestFilterRegistry filters;

//...

void setHeader() {
filters.add((request, contents, messageInfo) -> {
request.headers().add("headerName", "headerValue");
return null;
});
}
```