diff options
author | Lukasz Jarocki <lukasz.jarocki@sonarsource.com> | 2022-01-24 10:01:00 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-02-18 15:48:03 +0000 |
commit | a9e3735302b847752a6abd60397f91fb9b91e4b7 (patch) | |
tree | 4ce1976e6eec8d77f5da6f3a7a17a700ee125d96 /server/sonar-webserver-ws | |
parent | dd5c24bc96a10a3b81bd1c94d40b936ba451cd90 (diff) | |
download | sonarqube-a9e3735302b847752a6abd60397f91fb9b91e4b7.tar.gz sonarqube-a9e3735302b847752a6abd60397f91fb9b91e4b7.zip |
SONAR-15918 making the new endpoint /api/push/sonarlint_events async
Diffstat (limited to 'server/sonar-webserver-ws')
12 files changed, 144 insertions, 96 deletions
diff --git a/server/sonar-webserver-ws/build.gradle b/server/sonar-webserver-ws/build.gradle index 33d0249b7f1..3fa8fed9bb6 100644 --- a/server/sonar-webserver-ws/build.gradle +++ b/server/sonar-webserver-ws/build.gradle @@ -20,6 +20,8 @@ dependencies { compileOnly 'javax.servlet:javax.servlet-api' compileOnly 'org.apache.tomcat.embed:tomcat-embed-core' + testCompile 'com.tngtech.java:junit-dataprovider' + testCompile 'junit:junit' testCompile 'com.google.code.findbugs:jsr305' testCompile 'javax.servlet:javax.servlet-api' testCompile 'org.apache.tomcat.embed:tomcat-embed-core' diff --git a/server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/ServletRequest.java b/server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/ServletRequest.java index 89226f6d9a9..cfc18bb2969 100644 --- a/server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/ServletRequest.java +++ b/server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/ServletRequest.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import javax.annotation.CheckForNull; +import javax.servlet.AsyncContext; import javax.servlet.http.HttpServletRequest; import org.sonar.api.impl.ws.PartImpl; import org.sonar.api.impl.ws.ValidatingRequest; @@ -122,6 +123,10 @@ public class ServletRequest extends ValidatingRequest { } } + public AsyncContext startAsync() { + return source.startAsync(); + } + private boolean isMultipartContent() { String contentType = source.getContentType(); return contentType != null && contentType.toLowerCase(ENGLISH).startsWith(MULTIPART); diff --git a/server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/ServletResponse.java b/server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/ServletResponse.java index f02e380142a..8d294b4552e 100644 --- a/server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/ServletResponse.java +++ b/server/sonar-webserver-ws/src/main/java/org/sonar/server/ws/ServletResponse.java @@ -80,6 +80,16 @@ public class ServletResponse implements Response { response.reset(); return this; } + + public ServletStream flushBuffer() throws IOException { + response.flushBuffer(); + return this; + } + + public ServletStream setCharacterEncoding(String charset) { + response.setCharacterEncoding(charset); + return this; + } } @Override diff --git a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/ServletRequestTest.java b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/ServletRequestTest.java index 79f57aed7b8..159be0e20eb 100644 --- a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/ServletRequestTest.java +++ b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/ServletRequestTest.java @@ -210,4 +210,11 @@ public class ServletRequestTest { assertThat(underTest.getReader()).isEqualTo(reader); } + @Test + public void startAsync() { + underTest.startAsync(); + + verify(source).startAsync(); + } + } diff --git a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/ServletResponseTest.java b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/ServletResponseTest.java index c5099cd677c..19cbc9f93f8 100644 --- a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/ServletResponseTest.java +++ b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/ServletResponseTest.java @@ -19,6 +19,8 @@ */ package org.sonar.server.ws; +import java.io.IOException; +import java.nio.charset.Charset; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; import org.junit.Before; @@ -84,6 +86,20 @@ public class ServletResponseTest { } @Test + public void setCharacterEncoding_encodingIsSet() { + underTest.stream().setCharacterEncoding("UTF-8"); + + verify(response).setCharacterEncoding("UTF-8"); + } + + @Test + public void flushBuffer_bufferIsFlushed() throws IOException { + underTest.stream().flushBuffer(); + + verify(response).flushBuffer(); + } + + @Test public void test_output() { assertThat(underTest.stream().output()).isEqualTo(output); } diff --git a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java index 6e4e694d67b..e138a6bc316 100644 --- a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java +++ b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WebServiceEngineTest.java @@ -19,11 +19,15 @@ */ package org.sonar.server.ws; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.util.function.Consumer; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.ClientAbortException; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mockito; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.RequestHandler; @@ -45,6 +49,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +@RunWith(DataProviderRunner.class) public class WebServiceEngineTest { @Rule @@ -68,37 +73,27 @@ public class WebServiceEngineTest { } } - @Test - public void ws_returns_successful_response() { - Request request = new TestRequest().setPath("/api/ping"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); + @DataProvider + public static Object[][] responseData() { + return new Object[][] { + {"/api/ping", "pong", 200}, + {"api/ping", "pong", 200}, + {"api/ping.json", "pong", 200}, + {"xxx/ping", "{\"errors\":[{\"msg\":\"Unknown url : xxx/ping\"}]}", 404}, + {"api/xxx", "{\"errors\":[{\"msg\":\"Unknown url : api/xxx\"}]}", 404} + }; } @Test - public void accept_path_that_does_not_start_with_slash() { - Request request = new TestRequest().setPath("api/ping"); + @UseDataProvider("responseData") + public void ws_returns_successful_response(String path, String output, int statusCode) { + Request request = new TestRequest().setPath(path); DumbResponse response = run(request, newPingWs(a -> { })); - assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); - } - - @Test - public void request_path_can_contain_valid_media_type() { - Request request = new TestRequest().setPath("api/ping.json"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); + assertThat(response.stream().outputAsString()).isEqualTo(output); + assertThat(response.status()).isEqualTo(statusCode); } @Test @@ -108,8 +103,8 @@ public class WebServiceEngineTest { DumbResponse response = run(request, newPingWs(a -> { })); - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); + assertThat(response.status()).isEqualTo(400); + assertThat(response.mediaType()).isEqualTo(MediaTypes.JSON); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown action extension: bat\"}]}"); } @@ -121,29 +116,7 @@ public class WebServiceEngineTest { DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler(handler))); assertThat(response.stream().outputAsString()).isEmpty(); - assertThat(response.stream().status()).isEqualTo(204); - } - - @Test - public void return_404_if_controller_does_not_exist() { - Request request = new TestRequest().setPath("xxx/ping"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown url : xxx/ping\"}]}"); - assertThat(response.stream().status()).isEqualTo(404); - } - - @Test - public void return_404_if_action_does_not_exist() { - Request request = new TestRequest().setPath("api/xxx"); - - DumbResponse response = run(request, newPingWs(a -> { - })); - - assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Unknown url : api/xxx\"}]}"); - assertThat(response.stream().status()).isEqualTo(404); + assertThat(response.status()).isEqualTo(204); } @Test @@ -153,7 +126,7 @@ public class WebServiceEngineTest { DumbResponse response = run(request, newWs("api/foo", a -> a.setPost(true))); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"HTTP method POST is required\"}]}"); - assertThat(response.stream().status()).isEqualTo(405); + assertThat(response.status()).isEqualTo(405); } @Test @@ -164,7 +137,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); + assertThat(response.status()).isEqualTo(200); } @Test @@ -175,7 +148,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"HTTP method PUT is not allowed\"}]}"); - assertThat(response.stream().status()).isEqualTo(405); + assertThat(response.status()).isEqualTo(405); } @Test @@ -186,7 +159,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"HTTP method DELETE is not allowed\"}]}"); - assertThat(response.stream().status()).isEqualTo(405); + assertThat(response.status()).isEqualTo(405); } @Test @@ -196,7 +169,7 @@ public class WebServiceEngineTest { DumbResponse response = run(request, newPingWs(a -> a.setPost(true))); assertThat(response.stream().outputAsString()).isEqualTo("pong"); - assertThat(response.stream().status()).isEqualTo(200); + assertThat(response.status()).isEqualTo(200); } @Test @@ -206,7 +179,7 @@ public class WebServiceEngineTest { DumbResponse response = run(request, newWs("api/foo", a -> a.setHandler((req, resp) -> request.param("unknown")))); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"BUG - parameter \\u0027unknown\\u0027 is undefined for action \\u0027foo\\u0027\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); + assertThat(response.status()).isEqualTo(400); } @Test @@ -219,7 +192,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"The \\u0027bar\\u0027 parameter is missing\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); + assertThat(response.status()).isEqualTo(400); } @Test @@ -233,7 +206,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"The \\u0027bar\\u0027 parameter is missing\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); + assertThat(response.status()).isEqualTo(400); } @Test @@ -246,7 +219,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("hello"); - assertThat(response.stream().status()).isEqualTo(200); + assertThat(response.status()).isEqualTo(200); } @Test @@ -259,7 +232,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("bar"); - assertThat(response.stream().status()).isEqualTo(200); + assertThat(response.status()).isEqualTo(200); } @Test @@ -272,7 +245,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("json"); - assertThat(response.stream().status()).isEqualTo(200); + assertThat(response.status()).isEqualTo(200); } @Test @@ -285,7 +258,7 @@ public class WebServiceEngineTest { })); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"Value of parameter \\u0027format\\u0027 (yml) must be one of: [json, xml]\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); + assertThat(response.status()).isEqualTo(400); } @Test @@ -295,8 +268,8 @@ public class WebServiceEngineTest { DumbResponse response = run(request, newFailWs()); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"An error has occurred. Please contact your administrator\"}]}"); - assertThat(response.stream().status()).isEqualTo(500); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); + assertThat(response.status()).isEqualTo(500); + assertThat(response.mediaType()).isEqualTo(MediaTypes.JSON); assertThat(logTester.logs(LoggerLevel.ERROR)).filteredOn(l -> l.contains("Fail to process request api/foo")).isNotEmpty(); } @@ -310,8 +283,8 @@ public class WebServiceEngineTest { assertThat(response.stream().outputAsString()).isEqualTo( "{\"errors\":[{\"msg\":\"Bad request !\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); + assertThat(response.status()).isEqualTo(400); + assertThat(response.mediaType()).isEqualTo(MediaTypes.JSON); assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); } @@ -328,8 +301,8 @@ public class WebServiceEngineTest { + "{\"msg\":\"two\"}," + "{\"msg\":\"three\"}" + "]}"); - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); + assertThat(response.status()).isEqualTo(400); + assertThat(response.mediaType()).isEqualTo(MediaTypes.JSON); assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); } @@ -343,8 +316,8 @@ public class WebServiceEngineTest { assertThat(response.stream().outputAsString()).isEqualTo( "{\"scope\":\"PROJECT\",\"errors\":[{\"msg\":\"Bad request !\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); + assertThat(response.status()).isEqualTo(400); + assertThat(response.mediaType()).isEqualTo(MediaTypes.JSON); assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty(); } @@ -357,8 +330,8 @@ public class WebServiceEngineTest { }))); assertThat(response.stream().outputAsString()).isEqualTo("{\"errors\":[{\"msg\":\"this should not fail %s\"}]}"); - assertThat(response.stream().status()).isEqualTo(400); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); + assertThat(response.status()).isEqualTo(400); + assertThat(response.mediaType()).isEqualTo(MediaTypes.JSON); } @Test diff --git a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WsUtilsTest.java b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WsUtilsTest.java index 71a4cbcc1c3..79bb015322c 100644 --- a/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WsUtilsTest.java +++ b/server/sonar-webserver-ws/src/test/java/org/sonar/server/ws/WsUtilsTest.java @@ -43,7 +43,7 @@ public class WsUtilsTest { Issues.Issue msg = Issues.Issue.newBuilder().setKey("I1").build(); WsUtils.writeProtobuf(msg, request, response); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.JSON); + assertThat(response.mediaType()).isEqualTo(MediaTypes.JSON); assertThat(response.outputAsString()) .startsWith("{") .contains("\"key\":\"I1\"") @@ -59,7 +59,7 @@ public class WsUtilsTest { Issues.Issue msg = Issues.Issue.newBuilder().setKey("I1").build(); WsUtils.writeProtobuf(msg, request, response); - assertThat(response.stream().mediaType()).isEqualTo(MediaTypes.PROTOBUF); + assertThat(response.mediaType()).isEqualTo(MediaTypes.PROTOBUF); assertThat(Issues.Issue.parseFrom(response.getFlushedOutput()).getKey()).isEqualTo("I1"); } diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/DumbResponse.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/DumbResponse.java index 9b91d24949b..adebb870aba 100644 --- a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/DumbResponse.java +++ b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/DumbResponse.java @@ -35,7 +35,7 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.utils.text.JsonWriter; import org.sonar.api.utils.text.XmlWriter; -public class DumbResponse implements Response { +public class DumbResponse implements Response, TestableResponse { private InMemoryStream stream; private final ByteArrayOutputStream output = new ByteArrayOutputStream(); @@ -47,15 +47,6 @@ public class DumbResponse implements Response { private int status = 200; - @CheckForNull - public String mediaType() { - return mediaType; - } - - public int status() { - return status; - } - @Override public Response.Stream setMediaType(String s) { this.mediaType = s; @@ -107,6 +98,15 @@ public class DumbResponse implements Response { return new String(output.toByteArray(), StandardCharsets.UTF_8); } + @CheckForNull + public String mediaType() { + return stream().mediaType; + } + + public int status() { + return stream().status; + } + @Override public Response setHeader(String name, String value) { headers.put(name, value); diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestRequest.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestRequest.java index dc083b685ad..d37f7a1e00f 100644 --- a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestRequest.java +++ b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestRequest.java @@ -73,17 +73,17 @@ public class TestRequest extends ValidatingRequest { } @Override - protected String readParam(String key) { + public String readParam(String key) { return params.get(key); } @Override - protected List<String> readMultiParam(String key) { + public List<String> readMultiParam(String key) { return multiParams.get(key); } @Override - protected InputStream readInputStreamParam(String key) { + public InputStream readInputStreamParam(String key) { String value = readParam(key); if (value == null) { return null; @@ -92,7 +92,7 @@ public class TestRequest extends ValidatingRequest { } @Override - protected Part readPart(String key) { + public Part readPart(String key) { return parts.get(key); } diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestResponse.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestResponse.java index c2511c22310..6fa82315e90 100644 --- a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestResponse.java +++ b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestResponse.java @@ -33,14 +33,14 @@ import static org.assertj.core.api.Assertions.assertThat; public class TestResponse { - private final DumbResponse dumbResponse; + private final TestableResponse testableResponse; - public TestResponse(DumbResponse dumbResponse) { - this.dumbResponse = dumbResponse; + public TestResponse(TestableResponse dumbResponse) { + this.testableResponse = dumbResponse; } public InputStream getInputStream() { - return new ByteArrayInputStream(dumbResponse.getFlushedOutput()); + return new ByteArrayInputStream(testableResponse.getFlushedOutput()); } public <T extends GeneratedMessageV3> T getInputObject(Class<T> protobufClass) { @@ -55,20 +55,20 @@ public class TestResponse { } public String getInput() { - return new String(dumbResponse.getFlushedOutput(), StandardCharsets.UTF_8); + return new String(testableResponse.getFlushedOutput(), StandardCharsets.UTF_8); } public String getMediaType() { - return dumbResponse.stream().mediaType(); + return testableResponse.mediaType(); } public int getStatus() { - return dumbResponse.stream().status(); + return testableResponse.status(); } @CheckForNull public String getHeader(String headerKey) { - return dumbResponse.getHeader(headerKey); + return testableResponse.getHeader(headerKey); } public void assertJson(String expectedJson) { diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestableResponse.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestableResponse.java new file mode 100644 index 00000000000..056c9e68019 --- /dev/null +++ b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/TestableResponse.java @@ -0,0 +1,35 @@ +/* + * SonarQube + * Copyright (C) 2009-2021 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.ws; + +import org.sonar.api.server.ws.Response; + +public interface TestableResponse { + + byte[] getFlushedOutput(); + + Response.Stream stream(); + + String getHeader(String headerKey); + + int status(); + + String mediaType(); +} diff --git a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/WsActionTester.java b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/WsActionTester.java index dbe31b268e4..863a5aaec1a 100644 --- a/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/WsActionTester.java +++ b/server/sonar-webserver-ws/src/testFixtures/java/org/sonar/server/ws/WsActionTester.java @@ -25,7 +25,7 @@ import org.sonar.api.server.ws.WebService; public class WsActionTester { public static final String CONTROLLER_KEY = "test"; - private final WebService.Action action; + protected final WebService.Action action; public WsActionTester(WsAction wsAction) { WebService.Context context = new WebService.Context(); |