|
| 1 | +/* |
| 2 | + * Modifications Copyright (c) 2019 BrowserUp, Inc. |
| 3 | + */ |
| 4 | + |
| 5 | +package com.browserup.bup |
| 6 | + |
| 7 | +/* |
| 8 | + * Modifications Copyright (c) 2019 BrowserUp, Inc. |
| 9 | + */ |
| 10 | + |
| 11 | +import com.browserup.bup.MitmProxyServer |
| 12 | +import com.browserup.bup.proxy.MitmProxyManager |
| 13 | +import com.browserup.bup.proxy.bricks.ProxyResource |
| 14 | +import com.browserup.bup.proxy.guice.ConfigModule |
| 15 | +import com.browserup.bup.proxy.guice.JettyModule |
| 16 | +import com.browserup.bup.util.BrowserUpProxyUtil |
| 17 | +import com.github.tomakehurst.wiremock.junit.WireMockRule |
| 18 | +import com.google.inject.Guice |
| 19 | +import com.google.inject.Injector |
| 20 | +import com.google.inject.servlet.GuiceServletContextListener |
| 21 | +import com.google.sitebricks.SitebricksModule |
| 22 | +import groovyx.net.http.HTTPBuilder |
| 23 | +import groovyx.net.http.Method |
| 24 | +import org.apache.http.entity.ContentType |
| 25 | +import org.awaitility.Awaitility |
| 26 | +import org.eclipse.jetty.server.Server |
| 27 | +import org.eclipse.jetty.servlet.ServletContextHandler |
| 28 | +import org.junit.After |
| 29 | +import org.junit.Before |
| 30 | +import org.junit.Rule |
| 31 | +import org.slf4j.Logger |
| 32 | +import org.slf4j.LoggerFactory |
| 33 | + |
| 34 | +import javax.servlet.ServletContextEvent |
| 35 | +import java.util.concurrent.TimeUnit |
| 36 | + |
| 37 | +import static com.github.tomakehurst.wiremock.client.WireMock.* |
| 38 | +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options |
| 39 | +import static org.junit.Assert.assertEquals |
| 40 | + |
| 41 | +abstract class WithRunningProxyRestTest { |
| 42 | + private static final Logger LOG = LoggerFactory.getLogger(MitmProxyManager) |
| 43 | + |
| 44 | + protected MitmProxyManager proxyManager |
| 45 | + protected MitmProxyServer proxy |
| 46 | + protected Server restServer |
| 47 | + |
| 48 | + protected String[] getArgs() { |
| 49 | + ['--port', '0'] as String[] |
| 50 | + } |
| 51 | + |
| 52 | + abstract String getUrlPath(); |
| 53 | + |
| 54 | + String getFullUrlPath() { |
| 55 | + return "/proxy/${proxy.port}/${urlPath}" |
| 56 | + } |
| 57 | + |
| 58 | + protected int mockServerPort |
| 59 | + protected int mockServerHttpsPort |
| 60 | + |
| 61 | + @Rule |
| 62 | + public WireMockRule wireMockRule = new WireMockRule(options().port(0).httpsPort(0)) |
| 63 | + |
| 64 | + @Before |
| 65 | + void setUp() throws Exception { |
| 66 | + Injector injector = Guice.createInjector(new ConfigModule(args), new JettyModule(), new SitebricksModule() { |
| 67 | + @Override |
| 68 | + protected void configureSitebricks() { |
| 69 | + scan(ProxyResource.class.getPackage()) |
| 70 | + } |
| 71 | + }) |
| 72 | + |
| 73 | + proxyManager = injector.getInstance(MitmProxyManager) |
| 74 | + |
| 75 | + LOG.debug("Starting BrowserUp Proxy version " + BrowserUpProxyUtil.versionString) |
| 76 | + |
| 77 | + new Thread(new Runnable() { |
| 78 | + @Override |
| 79 | + void run() { |
| 80 | + startRestServer(injector) |
| 81 | + } |
| 82 | + }).start() |
| 83 | + |
| 84 | + LOG.debug("Waiting till BrowserUp Rest server is started") |
| 85 | + |
| 86 | + Awaitility.await().atMost(10, TimeUnit.SECONDS).until({ -> restServer != null && restServer.isStarted() }) |
| 87 | + |
| 88 | + LOG.debug("BrowserUp Rest server is started successfully") |
| 89 | + |
| 90 | + LOG.debug("Waiting till BrowserUp Proxy server is started") |
| 91 | + |
| 92 | + proxy = proxyManager.create(0) |
| 93 | + |
| 94 | + Awaitility.await().atMost(5, TimeUnit.SECONDS).until({ -> proxyManager.get().size() > 0 }) |
| 95 | + |
| 96 | + LOG.debug("BrowserUp Proxy server is started successfully") |
| 97 | + |
| 98 | + mockServerPort = wireMockRule.port(); |
| 99 | + mockServerHttpsPort = wireMockRule.httpsPort(); |
| 100 | + |
| 101 | + waitForProxyServer() |
| 102 | + } |
| 103 | + |
| 104 | + def waitForProxyServer() { |
| 105 | + Awaitility.await().atMost(5, TimeUnit.SECONDS).until({ -> |
| 106 | + def successful = false |
| 107 | + proxyRestServerClient.request(Method.GET, ContentType.TEXT_PLAIN) { req -> |
| 108 | + uri.path = "/proxy" |
| 109 | + response.success = { _, reader -> |
| 110 | + successful = true |
| 111 | + } |
| 112 | + response.failure = { _, reader -> |
| 113 | + successful = false |
| 114 | + } |
| 115 | + } |
| 116 | + return successful |
| 117 | + }) |
| 118 | + } |
| 119 | + |
| 120 | + HTTPBuilder getTargetServerClient() { |
| 121 | + def http = new HTTPBuilder("http://localhost:${mockServerPort}") |
| 122 | + http.setProxy('localhost', proxy.port, 'http') |
| 123 | + http |
| 124 | + } |
| 125 | + |
| 126 | + HTTPBuilder getProxyRestServerClient() { |
| 127 | + new HTTPBuilder("http://localhost:${restServer.connectors[0].localPort}") |
| 128 | + } |
| 129 | + |
| 130 | + def sendGetToProxyServer(Closure configClosure) { |
| 131 | + proxyRestServerClient.request(Method.GET, ContentType.WILDCARD, configClosure) |
| 132 | + } |
| 133 | + |
| 134 | + void requestToTargetServer(url, expectedResponse) { |
| 135 | + targetServerClient.request(Method.GET, ContentType.TEXT_PLAIN) { req -> |
| 136 | + uri.path = "/${url}" |
| 137 | + response.success = { _, reader -> |
| 138 | + assertEquals(expectedResponse, reader.text) |
| 139 | + } |
| 140 | + response.failure = { _, reader -> |
| 141 | + assertEquals(expectedResponse, reader.text) |
| 142 | + } |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + @After |
| 147 | + void tearDown() throws Exception { |
| 148 | + LOG.debug('Stopping proxy servers') |
| 149 | + for (def proxyServer : proxyManager.get()) { |
| 150 | + try { |
| 151 | + proxyManager.delete(proxyServer.port) |
| 152 | + } catch (Exception ex) { |
| 153 | + LOG.error('Error while stopping proxy servers', ex) |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + if (restServer != null) { |
| 158 | + LOG.debug('Stopping rest proxy server') |
| 159 | + try { |
| 160 | + restServer.stop() |
| 161 | + } catch (Exception ex) { |
| 162 | + LOG.error('Error while stopping rest proxy server', ex) |
| 163 | + } |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + private void startRestServer(Injector injector) { |
| 168 | + restServer = injector.getInstance(Server.class) |
| 169 | + def contextListener = new GuiceServletContextListener() { |
| 170 | + @Override |
| 171 | + protected Injector getInjector() { |
| 172 | + return injector |
| 173 | + } |
| 174 | + } |
| 175 | + restServer.start() |
| 176 | + contextListener.contextInitialized( |
| 177 | + new ServletContextEvent((restServer.handler as ServletContextHandler).servletContext)) |
| 178 | + try { |
| 179 | + restServer.join() |
| 180 | + } catch (InterruptedException ignored) { |
| 181 | + Thread.currentThread().interrupt() |
| 182 | + } |
| 183 | + } |
| 184 | + |
| 185 | + protected void mockTargetServerResponse(String url, String responseBody, int delayMilliseconds=0) { |
| 186 | + def response = aResponse().withStatus(200) |
| 187 | + .withBody(responseBody) |
| 188 | + .withHeader('Content-Type', 'text/plain') |
| 189 | + .withFixedDelay(delayMilliseconds) |
| 190 | + stubFor(get(urlEqualTo("/${url}")).willReturn(response)) |
| 191 | + } |
| 192 | +} |
0 commit comments