Skip to content

Commit b9028b5

Browse files
committed
WIP Support HttpClient based scenarios
When JPT detects a regression and the regression is on a backend side, then it's handy to test only the backend side, to avoid the browser's noise. I had this problem twice and two persons asked me about the feature. As there was no dedicated API, I've been creating a custom scenario, and translate web driver to HttpClient inside of a custom action. This approach has two disadvantages: - It requires expert-level knowledge about JPT - Each VU needs to run a real browser, even if it's not used. It limits the The goal of this change is to expose API for lightweight HttpClient based scenarios.
1 parent 1b847e2 commit b9028b5

6 files changed

Lines changed: 512 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Dropping a requirement of a major version of a dependency is a new contract.
2323
## [Unreleased]
2424
[Unreleased]: https://github.com/atlassian/virtual-users/compare/release-3.10.0...master
2525

26+
### Added
27+
- Support HttpClient based scenarios.
28+
2629
## [3.10.0] - 2019-08-02
2730
[3.10.0]: https://github.com/atlassian/virtual-users/compare/release-3.9.1...release-3.10.0
2831

Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
package com.atlassian.performance.tools.virtualusers
2+
3+
import com.google.common.util.concurrent.SettableFuture
4+
import net.jcip.annotations.GuardedBy
5+
import org.apache.http.auth.AuthScope
6+
import org.apache.http.auth.Credentials
7+
import org.apache.http.auth.UsernamePasswordCredentials
8+
import org.apache.http.client.CredentialsProvider
9+
import org.apache.http.impl.client.BasicCredentialsProvider
10+
import org.apache.http.impl.client.CloseableHttpClient
11+
import org.apache.http.impl.client.HttpClientBuilder
12+
import org.openqa.selenium.*
13+
import org.openqa.selenium.interactions.Keyboard
14+
import org.openqa.selenium.interactions.Mouse
15+
import org.openqa.selenium.remote.*
16+
import org.openqa.selenium.remote.internal.JsonToWebElementConverter
17+
import java.util.concurrent.Future
18+
import java.util.logging.Level
19+
20+
internal class HttpClientWebDriver : RemoteWebDriver() {
21+
private val lock = Object()
22+
@GuardedBy("lock")
23+
private val httpClient: SettableFuture<CloseableHttpClient> = SettableFuture.create()
24+
25+
internal fun getHttpClientFuture(): Future<CloseableHttpClient> {
26+
return httpClient
27+
}
28+
29+
fun initHttpClient(userName: String, password: String) {
30+
synchronized(lock) {
31+
if (httpClient.isDone.not()) {
32+
val provider: CredentialsProvider = BasicCredentialsProvider()
33+
val credentials: Credentials = UsernamePasswordCredentials(userName, password)
34+
provider.setCredentials(AuthScope.ANY, credentials)
35+
httpClient.set(
36+
HttpClientBuilder.create()
37+
.setDefaultCredentialsProvider(provider)
38+
.build()
39+
)
40+
}
41+
}
42+
}
43+
44+
override fun executeScript(script: String?, vararg args: Any?): Any {
45+
throw Exception("not implemented")
46+
}
47+
48+
override fun findElementById(using: String?): WebElement {
49+
throw Exception("not implemented")
50+
}
51+
52+
override fun setFileDetector(detector: FileDetector?) {
53+
throw Exception("not implemented")
54+
}
55+
56+
override fun getSessionId(): SessionId {
57+
throw Exception("not implemented")
58+
}
59+
60+
override fun log(sessionId: SessionId?, commandName: String?, toLog: Any?, `when`: When?) {
61+
throw Exception("not implemented")
62+
}
63+
64+
override fun findElementByTagName(using: String?): WebElement {
65+
throw Exception("not implemented")
66+
}
67+
68+
override fun findElementByXPath(using: String?): WebElement {
69+
throw Exception("not implemented")
70+
}
71+
72+
override fun findElementsByXPath(using: String?): MutableList<WebElement> {
73+
throw Exception("not implemented")
74+
}
75+
76+
override fun getTitle(): String {
77+
throw Exception("not implemented")
78+
}
79+
80+
override fun executeAsyncScript(script: String?, vararg args: Any?): Any {
81+
throw Exception("not implemented")
82+
}
83+
84+
override fun getMouse(): Mouse {
85+
throw Exception("not implemented")
86+
}
87+
88+
override fun close() {
89+
throw Exception("not implemented")
90+
}
91+
92+
override fun findElementByPartialLinkText(using: String?): WebElement {
93+
throw Exception("not implemented")
94+
}
95+
96+
override fun getWindowHandles(): MutableSet<String> {
97+
throw Exception("not implemented")
98+
}
99+
100+
override fun setElementConverter(converter: JsonToWebElementConverter?) {
101+
throw Exception("not implemented")
102+
}
103+
104+
override fun getExecuteMethod(): ExecuteMethod {
105+
throw Exception("not implemented")
106+
}
107+
108+
override fun setSessionId(opaqueKey: String?) {
109+
throw Exception("not implemented")
110+
}
111+
112+
override fun findElementsById(using: String?): MutableList<WebElement> {
113+
throw Exception("not implemented")
114+
}
115+
116+
override fun <X : Any?> getScreenshotAs(outputType: OutputType<X>?): X {
117+
return outputType!!.convertFromBase64Png("")
118+
}
119+
120+
override fun findElementsByPartialLinkText(using: String?): MutableList<WebElement> {
121+
throw Exception("not implemented")
122+
}
123+
124+
override fun toString(): String {
125+
throw Exception("not implemented")
126+
}
127+
128+
override fun getErrorHandler(): ErrorHandler {
129+
throw Exception("not implemented")
130+
}
131+
132+
override fun setFoundBy(context: SearchContext?, element: WebElement?, by: String?, using: String?) {
133+
throw Exception("not implemented")
134+
}
135+
136+
override fun getCommandExecutor(): CommandExecutor {
137+
throw Exception("not implemented")
138+
}
139+
140+
override fun findElementsByName(using: String?): MutableList<WebElement> {
141+
throw Exception("not implemented")
142+
}
143+
144+
override fun findElementsByCssSelector(using: String?): MutableList<WebElement> {
145+
throw Exception("not implemented")
146+
}
147+
148+
override fun findElements(by: By?): MutableList<WebElement> {
149+
throw Exception("not implemented")
150+
}
151+
152+
override fun findElements(by: String?, using: String?): MutableList<WebElement> {
153+
throw Exception("not implemented")
154+
}
155+
156+
override fun getElementConverter(): JsonToWebElementConverter {
157+
throw Exception("not implemented")
158+
}
159+
160+
override fun findElementByClassName(using: String?): WebElement {
161+
throw Exception("not implemented")
162+
}
163+
164+
override fun setLogLevel(level: Level?) {
165+
throw Exception("not implemented")
166+
}
167+
168+
override fun findElementsByLinkText(using: String?): MutableList<WebElement> {
169+
throw Exception("not implemented")
170+
}
171+
172+
override fun findElementsByClassName(using: String?): MutableList<WebElement> {
173+
throw Exception("not implemented")
174+
}
175+
176+
override fun getPageSource(): String {
177+
return "none"
178+
}
179+
180+
override fun setCommandExecutor(executor: CommandExecutor?) {
181+
throw Exception("not implemented")
182+
}
183+
184+
override fun findElementByName(using: String?): WebElement {
185+
throw Exception("not implemented")
186+
}
187+
188+
override fun resetInputState() {
189+
throw Exception("not implemented")
190+
}
191+
192+
override fun get(url: String?) {
193+
throw Exception("not implemented")
194+
}
195+
196+
override fun findElement(by: By?): WebElement {
197+
return HttpClientWebElement()
198+
}
199+
200+
override fun findElement(by: String?, using: String?): WebElement {
201+
throw Exception("not implemented")
202+
}
203+
204+
override fun getWindowHandle(): String {
205+
throw Exception("not implemented")
206+
}
207+
208+
override fun getFileDetector(): FileDetector {
209+
throw Exception("not implemented")
210+
}
211+
212+
override fun execute(driverCommand: String?, parameters: MutableMap<String, *>?): Response {
213+
throw Exception("not implemented")
214+
}
215+
216+
override fun execute(command: String?): Response {
217+
throw Exception("not implemented")
218+
}
219+
220+
override fun navigate(): WebDriver.Navigation {
221+
throw Exception("not implemented")
222+
}
223+
224+
override fun manage(): WebDriver.Options {
225+
throw Exception("not implemented")
226+
}
227+
228+
override fun findElementByLinkText(using: String?): WebElement {
229+
throw Exception("not implemented")
230+
}
231+
232+
override fun getKeyboard(): Keyboard {
233+
throw Exception("not implemented")
234+
}
235+
236+
override fun getCurrentUrl(): String {
237+
return "none"
238+
}
239+
240+
override fun getCapabilities(): Capabilities {
241+
throw Exception("not implemented")
242+
}
243+
244+
override fun findElementByCssSelector(using: String?): WebElement {
245+
throw Exception("not implemented")
246+
}
247+
248+
override fun setErrorHandler(handler: ErrorHandler?) {
249+
throw Exception("not implemented")
250+
}
251+
252+
override fun switchTo(): WebDriver.TargetLocator {
253+
throw Exception("not implemented")
254+
}
255+
256+
override fun quit() {
257+
httpClient.get().close()
258+
}
259+
260+
override fun findElementsByTagName(using: String?): MutableList<WebElement> {
261+
throw Exception("not implemented")
262+
}
263+
264+
override fun startSession(capabilities: Capabilities?) {
265+
throw Exception("not implemented")
266+
}
267+
268+
private class HttpClientWebElement : WebElement {
269+
override fun <X : Any?> getScreenshotAs(target: OutputType<X>?): X {
270+
throw Exception("not implemented")
271+
}
272+
273+
override fun isDisplayed(): Boolean {
274+
throw Exception("not implemented")
275+
}
276+
277+
override fun clear() {
278+
throw Exception("not implemented")
279+
}
280+
281+
override fun submit() {
282+
throw Exception("not implemented")
283+
}
284+
285+
override fun getLocation(): Point {
286+
throw Exception("not implemented")
287+
}
288+
289+
override fun findElement(by: By?): WebElement {
290+
throw Exception("not implemented")
291+
}
292+
293+
override fun click() {
294+
throw Exception("not implemented")
295+
}
296+
297+
override fun getTagName(): String {
298+
throw Exception("not implemented")
299+
}
300+
301+
override fun getSize(): Dimension {
302+
throw Exception("not implemented")
303+
}
304+
305+
override fun getText(): String {
306+
return "text"
307+
}
308+
309+
override fun isSelected(): Boolean {
310+
throw Exception("not implemented")
311+
}
312+
313+
override fun isEnabled(): Boolean {
314+
throw Exception("not implemented")
315+
}
316+
317+
override fun sendKeys(vararg keysToSend: CharSequence?) {
318+
throw Exception("not implemented")
319+
}
320+
321+
override fun getAttribute(name: String?): String {
322+
throw Exception("not implemented")
323+
}
324+
325+
override fun getRect(): Rectangle {
326+
throw Exception("not implemented")
327+
}
328+
329+
override fun getCssValue(propertyName: String?): String {
330+
throw Exception("not implemented")
331+
}
332+
333+
override fun findElements(by: By?): MutableList<WebElement> {
334+
throw Exception("not implemented")
335+
}
336+
}
337+
338+
}

0 commit comments

Comments
 (0)