Added: release/sling/src/test/java/org/apache/sling/testing/DelayRequestInterceptorTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/DelayRequestInterceptorTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/DelayRequestInterceptorTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing; + +import org.apache.sling.testing.clients.interceptors.DelayRequestInterceptor; +import org.junit.Assert; +import org.junit.Test; + +public class DelayRequestInterceptorTest { + + @Test + public void testDelay() throws Exception { + DelayRequestInterceptor interceptor = new DelayRequestInterceptor(700); + long before = System.currentTimeMillis(); + interceptor.process(null, null); + long after = System.currentTimeMillis(); + Assert.assertTrue(after - before >= 700); + } + +}
Added: release/sling/src/test/java/org/apache/sling/testing/clients/HttpServerRule.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/HttpServerRule.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/HttpServerRule.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,84 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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. + ******************************************************************************/ +package org.apache.sling.testing.clients; + +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.TimeUnit; + +import org.apache.http.HttpHost; +import org.apache.http.client.utils.URIUtils; +import org.apache.http.config.SocketConfig; +import org.apache.http.impl.bootstrap.HttpServer; +import org.apache.http.impl.bootstrap.ServerBootstrap; +import org.apache.http.localserver.SSLTestContexts; +import org.junit.rules.ExternalResource; + +/** JUnit Rule that starts an HTTP server */ +public class HttpServerRule extends ExternalResource { + public static final String ORIGIN = "TEST/1.1"; + private HttpServer server; + private HttpHost host; + private URI uri; + + protected ServerBootstrap serverBootstrap; + + public static enum ProtocolScheme { + http, + https; + private ProtocolScheme() { + } + } + + protected final ProtocolScheme protocolScheme; + + public HttpServerRule() { + this(ProtocolScheme.http); + } + + public HttpServerRule(ProtocolScheme protocolScheme) { + this.protocolScheme = protocolScheme; + } + + @Override + protected void after() { + server.shutdown(-1, TimeUnit.SECONDS); + } + + @Override + protected void before() throws Throwable { + final SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(5000).build(); + serverBootstrap = ServerBootstrap.bootstrap().setSocketConfig(socketConfig).setServerInfo(ORIGIN); + if(ProtocolScheme.https.equals(protocolScheme)) { + serverBootstrap.setSslContext(SSLTestContexts.createServerSSLContext()); + } + registerHandlers(); + server = serverBootstrap.create(); + server.start(); + host = new HttpHost("127.0.0.1", server.getLocalPort(), protocolScheme.name()); + uri = URIUtils.rewriteURI(new URI("/"), host); + } + + protected void registerHandlers() throws IOException { + } + + public URI getURI() { + return uri; + } +} \ No newline at end of file Added: release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientConfigTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientConfigTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientConfigTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients; + +import org.junit.Test; + +import java.net.URISyntaxException; + +public class SlingClientConfigTest { + + @Test(expected = ClientException.class) + public void testUrlNoProtocolUnauthenticated() throws URISyntaxException, ClientException { + // Should fail because URL doesn't start with http or https + SlingClientConfig.Builder + .create() + .setUrl("example.com") + .build(); + } + + @Test(expected = ClientException.class) + public void testUrlNoProtocolAuthenticated() throws URISyntaxException, ClientException { + // Should fail because URL doesn't start with http or https + SlingClientConfig.Builder + .create() + .setUser("username") + .setPassword("pass") + .setUrl("example.com") + .build(); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientConstructorTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientConstructorTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientConstructorTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.entity.StringEntity; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.codehaus.jackson.JsonNode; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; +import java.net.URI; + +import static org.junit.Assert.assertEquals; + +public class SlingClientConstructorTest { + + @Test + public void testConstructorUrlHttp() throws Exception { + URI url = URI.create("http://example.com"); + URI expected = URI.create("http://example.com/"); + SlingClient c = new SlingClient(url, "user", "pass"); + assertEquals(expected, c.getUrl()); + } + + @Test + public void testConstructorUrlHttpTrailingSlash() throws Exception { + URI url = URI.create("http://example.com/"); + URI expected = URI.create("http://example.com/"); + SlingClient c = new SlingClient(url, "user", "pass"); + assertEquals(expected, c.getUrl()); + } + + @Test + public void testConstructorUrlHttps() throws Exception { + URI url = URI.create("https://example.com"); + URI expected = URI.create("https://example.com/"); + SlingClient c = new SlingClient(url, "user", "pass"); + assertEquals(expected, c.getUrl()); + } + + @Test + public void testConstructorUrlHttpsTrailingSlash() throws Exception { + URI url = URI.create("https://example.com/"); + SlingClient c = new SlingClient(url, "user", "pass"); + assertEquals(url, c.getUrl()); + } + + @Test + public void testConstructorUrlBasePath() throws Exception { + URI url = URI.create("https://example.com/mypath"); + URI expected = URI.create("https://example.com/mypath/"); + SlingClient c = new SlingClient(url, "user", "pass"); + assertEquals(expected, c.getUrl()); + } + + @Test + public void testConstructorUrlBasePathTrailingSlash() throws Exception { + URI url = URI.create("https://example.com/mypath/"); + SlingClient c = new SlingClient(url, "user", "pass"); + assertEquals(url, c.getUrl()); + } + + @Test + public void testConstructorAnonymous() throws Exception { + URI url = URI.create("https://example.com/"); + SlingClient c = new SlingClient(url, null, null); + assertEquals(url, c.getUrl()); + } + + @Test(expected = ClientException.class) + public void testConstructorUrlNoProtocol() throws Exception { + URI url = URI.create("example.com/"); + SlingClient c = new SlingClient(url, "user", "pass"); + assertEquals(url, c.getUrl()); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientDoGetJsonTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientDoGetJsonTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientDoGetJsonTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.entity.StringEntity; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.codehaus.jackson.JsonNode; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class SlingClientDoGetJsonTest { + private static final String GET_JSON_PATH = "/test/json/resource"; + private static final String JSON_RESPONSE = "{\"jcr:primaryType\":\"cq:Page\",\"jcr:createdBy\":\"admin-json\"}"; + private static final String JSON_INF_RESPONSE = "{\"jcr:primaryType\":\"cq:Page\",\"jcr:createdBy\":\"admin-infinity\"}"; + + @ClassRule + public static HttpServerRule httpServer = new HttpServerRule() { + @Override + protected void registerHandlers() throws IOException { + serverBootstrap.registerHandler(GET_JSON_PATH + ".1.json", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + response.setEntity(new StringEntity(JSON_RESPONSE)); + } + }); + + serverBootstrap.registerHandler(GET_JSON_PATH + ".infinity.json", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + response.setEntity(new StringEntity(JSON_INF_RESPONSE)); + } + }); + } + }; + + @Test + public void testDoGetJson() throws Exception { + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + JsonNode res = c.doGetJson(GET_JSON_PATH, 1, 200); + assertEquals("admin-json", res.get("jcr:createdBy").getTextValue()); + } + + @Test + public void testDoGetJsonInfinity() throws Exception { + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + JsonNode res = c.doGetJson(GET_JSON_PATH, -1, 200); + assertEquals("admin-infinity", res.get("jcr:createdBy").getTextValue()); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientImportContentTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientImportContentTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientImportContentTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients; + +import org.apache.commons.io.IOUtils; +import org.apache.http.*; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.entity.StringEntity; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.codehaus.jackson.node.JsonNodeFactory; +import org.codehaus.jackson.node.ObjectNode; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.http.HttpStatus.SC_BAD_REQUEST; +import static org.apache.http.HttpStatus.SC_CREATED; + +public class SlingClientImportContentTest { + private static final Logger LOG = LoggerFactory.getLogger(SlingClientImportContentTest.class); + + private static final String IMPORT_PATH = "/test/import/parent"; + private static final String IMPORT_FILE_PATH = "/content/importfile"; + + private static final String IMPORT_FILE_CONTENT = "{\"nodefromfile\":{\"prop1\":\"val1\"}}"; + + @ClassRule + public static HttpServerRule httpServer = new HttpServerRule() { + @Override + protected void registerHandlers() throws IOException { + serverBootstrap.registerHandler(IMPORT_PATH, new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + List<NameValuePair> params = extractParameters(request); + String operation = getParameter(":operation", params); + String content = getParameter(":content", params); + + if (!"import".equals(operation)) { + response.setStatusCode(SC_BAD_REQUEST); + response.setEntity(new StringEntity("Unexpected operation: " + operation)); + return; + } + + if (!"{\"something\":{\"prop1\":\"val1\"}}".equals(content)) { + response.setStatusCode(SC_BAD_REQUEST); + response.setEntity(new StringEntity("Unexpected content: " + content)); + return; + } + + response.setStatusCode(SC_CREATED); + } + }); + + serverBootstrap.registerHandler(IMPORT_FILE_PATH, new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + LOG.debug("received: {}", request); + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + String content = IOUtils.toString(entity.getContent(), UTF_8); + LOG.debug("content: {}", content); + + if (!content.contains(":operation") || !content.contains("import")) { + response.setStatusCode(SC_BAD_REQUEST); + response.setEntity(new StringEntity("Operation not found")); + return; + } else if (!content.contains(IMPORT_FILE_CONTENT)) { + response.setStatusCode(SC_BAD_REQUEST); + response.setEntity(new StringEntity("File content not found")); + return; + } + + response.setStatusCode(SC_CREATED); + } else { + response.setStatusCode(SC_BAD_REQUEST); + response.setEntity(new StringEntity("Request doesn't contain an entity")); + } + } + }); + } + + private List<NameValuePair> extractParameters(HttpRequest request) { + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + try { + return URLEncodedUtils.parse(entity); + } catch (IOException e) { + LOG.error("Failed to parse entity", e); + } + } + + return new ArrayList<>(); + } + + private String getParameter(String parameterName, List<NameValuePair> parameters) { + for (NameValuePair parameter : parameters) { + if (parameter.getName().equals(parameterName)) { + return parameter.getValue(); + } + } + + return null; + } + }; + + + + private SlingClient client; + + public SlingClientImportContentTest() throws ClientException { + client = new SlingClient(httpServer.getURI(), "user", "pass"); + // to use with an already running instance + // client = new SlingClient(java.net.URI.create("http://localhost:8080"), "admin", "admin"); + } + + @Test + public void testImportContent() throws Exception { + client.importContent(IMPORT_PATH, "json", "{\"something\":{\"prop1\":\"val1\"}}"); + } + + @Test + public void testImportJson() throws Exception { + ObjectNode node = JsonNodeFactory.instance.objectNode(); + ObjectNode props = JsonNodeFactory.instance.objectNode(); + props.put("prop1", "val1"); + + node.put("something", props); + client.importJson(IMPORT_PATH, node); + } + @Test + public void testImportContentFile() throws Exception { + File tmp = File.createTempFile("import-json", null); + LOG.debug("created: " + tmp); + PrintWriter pw = new PrintWriter(tmp); + pw.write(IMPORT_FILE_CONTENT); + pw.close(); + + client.importContent(IMPORT_FILE_PATH, "json", tmp); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientRetryStrategyTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientRetryStrategyTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientRetryStrategyTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients; + +import org.apache.http.entity.StringEntity; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; + +import static org.apache.sling.testing.clients.SystemPropertiesConfig.CONFIG_PROP_PREFIX; +import static org.apache.sling.testing.clients.SystemPropertiesConfig.HTTP_RETRIES_ERROR_CODES_PROP; +import static org.junit.Assert.assertEquals; + +public class SlingClientRetryStrategyTest { + private static final String GET_UNAVAILABLE_PATH = "/test/unavailable/resource"; + private static final String GET_INEXISTENT_PATH = "/test/inexistent/resource"; + private static final String GET_INTERNAL_ERROR_PATH = "/test/internalerror/resource"; + private static final String GET_505_PATH = "/test/unsupportedversion/resource"; + private static final String NOK_RESPONSE = "TEST_NOK"; + private static final String OK_RESPONSE = "TEST_OK"; + + private static final int MAX_RETRIES = 4; + + private static int requestCount = 0; + private static int availableAtRequestCount = Integer.MAX_VALUE; + + static { + System.setProperty(CONFIG_PROP_PREFIX + SystemPropertiesConfig.HTTP_LOG_RETRIES_PROP, "true"); + System.setProperty(CONFIG_PROP_PREFIX + SystemPropertiesConfig.HTTP_DELAY_PROP, "50"); + System.setProperty(CONFIG_PROP_PREFIX + SystemPropertiesConfig.HTTP_RETRIES_PROP, "4"); + System.setProperty(CONFIG_PROP_PREFIX + HTTP_RETRIES_ERROR_CODES_PROP, "500,503"); + } + + @ClassRule + public static HttpServerRule httpServer = new HttpServerRule() { + @Override + protected void registerHandlers() throws IOException { + serverBootstrap.registerHandler(GET_UNAVAILABLE_PATH, (request, response, context) -> { + requestCount++; + if (requestCount == availableAtRequestCount) { + response.setEntity(new StringEntity(OK_RESPONSE)); + response.setStatusCode(200); + } else { + response.setEntity(new StringEntity(NOK_RESPONSE)); + response.setStatusCode(503); + } + }); + + serverBootstrap.registerHandler(GET_INTERNAL_ERROR_PATH, (request, response, context) -> { + requestCount++; + if (requestCount == availableAtRequestCount) { + response.setEntity(new StringEntity(OK_RESPONSE)); + response.setStatusCode(200); + } else { + response.setEntity(new StringEntity(NOK_RESPONSE)); + response.setStatusCode(500); + } + }); + + serverBootstrap.registerHandler(GET_INEXISTENT_PATH, (request, response, context) -> { + requestCount++; + response.setEntity(new StringEntity(NOK_RESPONSE)); + response.setStatusCode(404); + }); + + serverBootstrap.registerHandler(GET_505_PATH, (request, response, context) -> { + requestCount++; + if (requestCount == availableAtRequestCount) { + response.setEntity(new StringEntity(OK_RESPONSE)); + response.setStatusCode(200); + } else { + response.setEntity(new StringEntity(NOK_RESPONSE)); + response.setStatusCode(505); + } + }); + } + }; + + @Test + public void testRetryReallyUnavailable() throws Exception { + requestCount = 0; + availableAtRequestCount = Integer.MAX_VALUE; // never available + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + SlingHttpResponse slingHttpResponse = c.doGet(GET_UNAVAILABLE_PATH, 503); + assertEquals(MAX_RETRIES + 1, requestCount); + assertEquals(NOK_RESPONSE, slingHttpResponse.getContent()); + } + + @Test + public void testRetryReallyInternalError() throws Exception { + requestCount = 0; + availableAtRequestCount = Integer.MAX_VALUE; // never available + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + SlingHttpResponse slingHttpResponse = c.doGet(GET_INTERNAL_ERROR_PATH, 500); + assertEquals(MAX_RETRIES + 1, requestCount); + assertEquals(NOK_RESPONSE, slingHttpResponse.getContent()); + } + + @Test + public void test505ShouldNotRetry() throws Exception { + System.setProperty(CONFIG_PROP_PREFIX + HTTP_RETRIES_ERROR_CODES_PROP, "500,503"); + requestCount = 0; + availableAtRequestCount = Integer.MAX_VALUE; // never 200 + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + SlingHttpResponse slingHttpResponse = c.doGet(GET_505_PATH, 505); + assertEquals(1, requestCount); + assertEquals(NOK_RESPONSE, slingHttpResponse.getContent()); + } + + @Test + public void test505ShouldRetry() throws Exception { + System.setProperty(CONFIG_PROP_PREFIX + HTTP_RETRIES_ERROR_CODES_PROP, "500,503,505"); + requestCount = 0; + availableAtRequestCount = 3; + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + SlingHttpResponse slingHttpResponse = c.doGet(GET_505_PATH, 200); + assertEquals(availableAtRequestCount, requestCount); + assertEquals(OK_RESPONSE, slingHttpResponse.getContent()); + } + + @Test + public void testRetryInexistent() throws Exception { + requestCount = 0; + availableAtRequestCount = Integer.MAX_VALUE; // never available + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + SlingHttpResponse slingHttpResponse = c.doGet(GET_INEXISTENT_PATH, 404); + // should not retry at all + assertEquals(1, requestCount); + assertEquals(NOK_RESPONSE, slingHttpResponse.getContent()); + } + + @Test + public void testRetryEventuallyAvailable() throws Exception { + requestCount = 0; + availableAtRequestCount = 3; + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + SlingHttpResponse slingHttpResponse = c.doGet(GET_UNAVAILABLE_PATH, 200); + assertEquals(availableAtRequestCount, requestCount); + assertEquals(OK_RESPONSE, slingHttpResponse.getContent()); + + } + + @Test + public void testRetryEventuallyNoError() throws Exception { + requestCount = 0; + availableAtRequestCount = 3; + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + SlingHttpResponse slingHttpResponse = c.doGet(GET_INTERNAL_ERROR_PATH, 200); + assertEquals(availableAtRequestCount, requestCount); + assertEquals(OK_RESPONSE, slingHttpResponse.getContent()); + + } + +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.entity.StringEntity; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +import static org.junit.Assert.*; + +public class SlingClientWaitExistsTest { + private static final String GET_WAIT_PATH = "/test/wait/resource"; + private static final String OK_RESPONSE = "TEST_OK"; + private static final String NOK_RESPONSE = "TEST_OK"; + + private static int waitCount = 4; // truly randomly chosen by typing with the eyes closed + private static int callCount = 0; + + @ClassRule + public static HttpServerRule httpServer = new HttpServerRule() { + @Override + protected void registerHandlers() throws IOException { + serverBootstrap.registerHandler(GET_WAIT_PATH + ".json", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + callCount++; + if (callCount == waitCount) { + response.setEntity(new StringEntity(OK_RESPONSE)); + } else { + response.setEntity(new StringEntity(NOK_RESPONSE)); + response.setStatusCode(404); + } + } + }); + } + }; + + @Test + public void testWaitExists() throws Exception { + callCount = 0; // reset counter + waitCount = 3; // less than timeout + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + c.waitExists(GET_WAIT_PATH, 500, 10); + assertEquals(waitCount, callCount); + } + + @Test + public void testWaitExistsTimeout() throws Exception { + callCount = 0; // reset counter + waitCount = 40; // to be sure we reach timeout + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + try { + c.waitExists(GET_WAIT_PATH, 1000, 10); + } catch (TimeoutException e ) { + assertTrue("call was executed only " + callCount + " times", callCount > 3); + return; + } + + fail("waitExists did not timeout"); + } + + @Test + public void testWaitExistsOnce() throws Exception { + callCount = 0; // reset counter + waitCount = 1; // less than timeout + SlingClient c = new SlingClient(httpServer.getURI(), "user", "pass"); + c.waitExists(GET_WAIT_PATH, -1, 10); + assertEquals(1, callCount); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/indexing/IndexingClientTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/indexing/IndexingClientTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/indexing/IndexingClientTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,245 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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. + ******************************************************************************/ +package org.apache.sling.testing.clients.indexing; + +import org.apache.http.*; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.entity.StringEntity; +import org.apache.http.message.BasicHttpEntityEnclosingRequest; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.sling.testing.clients.ClientException; +import org.apache.sling.testing.clients.HttpServerRule; +import org.apache.sling.testing.clients.query.servlet.QueryServlet; +import org.hamcrest.CoreMatchers; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +public class IndexingClientTest { + private static final Logger LOG = LoggerFactory.getLogger(IndexingClientTest.class); + + private static final String EXPLAIN_RESPONSE = "{\"plan\": \"random plan with testIndexingLane-async and testIndexingLane-fulltext-async\",\"time\": 1}"; + private static final String QUERY_RESPONSE = "{\"total\": 1234,\"time\": 1}"; + + private static final String [] PRE_DEFINED_INDEXING_LANES = new String[]{"async", "fulltext-async"}; + + private static final AtomicInteger NUM_INDEXING_LANE_CONSOLE_CALLS = new AtomicInteger(); + + @ClassRule + public static HttpServerRule httpServer = new HttpServerRule() { + HttpRequestHandler okHandler = new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + response.setStatusCode(200); + response.setEntity(new StringEntity("Everything's fine")); + } + }; + + HttpRequestHandler createdHandler = new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + response.setStatusCode(201); + response.setEntity(new StringEntity("Created")); + } + }; + + @Override + protected void registerHandlers() throws IOException { + // Normal query request + serverBootstrap.registerHandler(QueryServlet.SERVLET_PATH, new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + List<NameValuePair> parameters = URLEncodedUtils.parse( + request.getRequestLine().getUri(), Charset.defaultCharset()); + + for (NameValuePair parameter : parameters) { + if (parameter.getName().equals("explain") && !parameter.getValue().equals("false")) { + response.setEntity(new StringEntity(EXPLAIN_RESPONSE)); + return; + } + } + + response.setEntity(new StringEntity(QUERY_RESPONSE)); + } + }); + + // Install servlet + serverBootstrap.registerHandler("/system/console/bundles", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + // is install (post) or checking status (get) + if (request instanceof BasicHttpEntityEnclosingRequest) { + response.setStatusCode(302); + } else { + response.setStatusCode(200); + } + } + }); + + // Check bundle status + serverBootstrap.registerHandler("BUNDLE_PATH" + ".json", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + response.setEntity(new StringEntity("JSON_BUNDLE")); + } + }); + + // Uninstall bundle + serverBootstrap.registerHandler("BUNDLE_PATH", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + response.setStatusCode(200); + } + }); + + // Uninstall bundle + serverBootstrap.registerHandler( + "/system/console/configMgr/org.apache.jackrabbit.oak.plugins.index.AsyncIndexerService", + new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + NUM_INDEXING_LANE_CONSOLE_CALLS.incrementAndGet(); + response.setStatusCode(200); + response.setEntity(new StringEntity("{\"properties\":{" + + "\"asyncConfigs\":{\"values\":[\"async:5\",\"fulltext-async:5\"]}}}")); + } + } + ); + + serverBootstrap.registerHandler("/tmp/testing/waitForAsyncIndexing/content/*", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + List<NameValuePair> params = extractParameters(request); + + for (NameValuePair param : params) { + if (param.getName().equals(":operation") && (param.getValue().equals("delete"))) { + response.setStatusCode(200); + return; + } + } + + response.setStatusCode(201); + response.setEntity(new StringEntity("Created!")); + } + }); + + serverBootstrap.registerHandler("/tmp/testing/waitForAsyncIndexing/oak:index/*", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws HttpException, IOException { + List<NameValuePair> params = extractParameters(request); + + for (NameValuePair param : params) { + if (param.getName().equals(":operation") && (param.getValue().equals("delete"))) { + response.setStatusCode(200); + return; + } + } + + response.setStatusCode(200); + response.setEntity(new StringEntity("Created!")); + } + }); + + // unimportant requests + serverBootstrap.registerHandler("/tmp.json", okHandler); + serverBootstrap.registerHandler("/tmp/testing.json", okHandler); + serverBootstrap.registerHandler("/tmp/testing/waitForAsyncIndexing", okHandler); + serverBootstrap.registerHandler("/tmp/testing", okHandler); + serverBootstrap.registerHandler("/tmp/testing/waitForAsyncIndexing/oak:index", createdHandler); + serverBootstrap.registerHandler("/tmp/testing/waitForAsyncIndexing/content", createdHandler); + } + }; + + private IndexingClient client; + + public IndexingClientTest() throws ClientException { + NUM_INDEXING_LANE_CONSOLE_CALLS.set(0); + client = new IndexingClient(httpServer.getURI(), "admin", "admin"); + //client = new IndexingClient(java.net.URI.create("http://localhost:4502"), "admin", "admin"); + } + + @Test + public void testInstall() throws ClientException { + client.install(); + } + + @Test + public void testUninstall() throws ClientException { + client.uninstall(); + } + + @Test + public void testWaitForAsyncIndexing() throws ClientException, TimeoutException, InterruptedException { + client.waitForAsyncIndexing(); + } + + @Test + public void testWaitForAsyncIndexingConfiguredLanes() throws ClientException, TimeoutException, InterruptedException { + client.setLaneNames(PRE_DEFINED_INDEXING_LANES); + + List<String> retrievedLaneNames = client.getLaneNames(); + Assert.assertEquals("Mismatched number of lanes", PRE_DEFINED_INDEXING_LANES.length, retrievedLaneNames.size()); + Assert.assertThat(retrievedLaneNames, CoreMatchers.hasItems(PRE_DEFINED_INDEXING_LANES)); + + client.waitForAsyncIndexing(); + + IndexingClient otherClient = client.adaptTo(IndexingClient.class); + + retrievedLaneNames = otherClient.getLaneNames(); + Assert.assertEquals("Mismatched number of lanes", PRE_DEFINED_INDEXING_LANES.length, retrievedLaneNames.size()); + Assert.assertThat(retrievedLaneNames, CoreMatchers.hasItems(PRE_DEFINED_INDEXING_LANES)); + + otherClient.waitForAsyncIndexing(); + + Assert.assertEquals("Must not get indexing lanes from /system/console", + 0, NUM_INDEXING_LANE_CONSOLE_CALLS.get()); + } + + private static List<NameValuePair> extractParameters(HttpRequest request) { + if (request instanceof HttpEntityEnclosingRequest) { + HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity(); + try { + return URLEncodedUtils.parse(entity); + } catch (IOException e) { + LOG.error("Failed to parse entity", e); + } + } + + return new ArrayList<>(); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/osgi/ServicesInfoTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/osgi/ServicesInfoTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/osgi/ServicesInfoTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients.osgi; + +import org.hamcrest.Matchers; +import org.junit.Assert; +import org.junit.Test; + +public class ServicesInfoTest { + + @Test + public void testSplitPseudoJsonValueArray() { + Assert.assertThat(ServicesInfo.splitPseudoJsonValueArray("test"), Matchers.contains("test")); + Assert.assertThat(ServicesInfo.splitPseudoJsonValueArray("[]"), Matchers.contains("")); + Assert.assertThat(ServicesInfo.splitPseudoJsonValueArray("[one, two]"), Matchers.contains("one", "two")); + Assert.assertThat(ServicesInfo.splitPseudoJsonValueArray("[one,two]"), Matchers.contains("one", "two")); + Assert.assertThat(ServicesInfo.splitPseudoJsonValueArray("[java.lang.Runnable, org.apache.sling.event.impl.jobs.queues.QueueManager, org.osgi.service.event.EventHandler]"), + Matchers.contains("java.lang.Runnable", "org.apache.sling.event.impl.jobs.queues.QueueManager", "org.osgi.service.event.EventHandler")); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/query/QueryClientTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/query/QueryClientTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/query/QueryClientTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients.query; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.entity.StringEntity; +import org.apache.http.message.BasicHttpEntityEnclosingRequest; +import org.apache.http.protocol.HttpContext; +import org.apache.http.protocol.HttpRequestHandler; +import org.apache.sling.testing.clients.ClientException; +import org.apache.sling.testing.clients.HttpServerRule; +import org.codehaus.jackson.JsonNode; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; + +public class QueryClientTest { + private static final Logger LOG = LoggerFactory.getLogger(QueryClientTest.class); + + private static final String QUERY_PATH = "/system/testing/query"; // same as in QueryServlet + private static final String BUNDLE_PATH = "/system/console/bundles/org.apache.sling.testing.clients.query"; + private static final String QUERY_RESPONSE = "{\"total\": 1234,\"time\": 1}"; + private static final String EXPLAIN_RESPONSE = "{\"plan\": \"some plan\",\"time\": 1}"; + private static final String JSON_BUNDLE = "{\n" + + " \"status\": \"Bundle information: 546 bundles in total, 537 bundles active, 8 bundles active fragments, 1 bundle resolved.\",\n" + + " \"s\": [\n" + + " 546,\n" + + " 537,\n" + + " 8,\n" + + " 1,\n" + + " 0\n" + + " ],\n" + + " \"data\": [\n" + + " {\n" + + " \"id\": 560,\n" + + " \"name\": \"Query servlet for testing\",\n" + + " \"fragment\": false,\n" + + " \"stateRaw\": 32,\n" + + " \"state\": \"Active\",\n" + + " \"version\": \"1.0.0\",\n" + + " \"symbolicName\": \"org.apache.sling.testing.clients.query\",\n" + + " \"category\": \"\"\n" + + " }\n" + + " ]\n" + + "}"; + + @ClassRule + public static HttpServerRule httpServer = new HttpServerRule() { + @Override + protected void registerHandlers() throws IOException { + + // Normal query request + serverBootstrap.registerHandler(QUERY_PATH, new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + List<NameValuePair> parameters = URLEncodedUtils.parse( + request.getRequestLine().getUri(), Charset.defaultCharset()); + + for (NameValuePair parameter : parameters) { + if (parameter.getName().equals("explain") && !parameter.getValue().equals("false")) { + response.setEntity(new StringEntity(EXPLAIN_RESPONSE)); + return; + } + } + + response.setEntity(new StringEntity(QUERY_RESPONSE)); + } + }); + + // Install servlet + serverBootstrap.registerHandler("/system/console/bundles", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + // is install (post) or checking status (get) + if (request instanceof BasicHttpEntityEnclosingRequest) { + response.setStatusCode(302); + } else { + response.setStatusCode(200); + } + } + }); + + // Check bundle status + serverBootstrap.registerHandler(BUNDLE_PATH + ".json", new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + response.setEntity(new StringEntity(JSON_BUNDLE)); + } + }); + + // Uninstall bundle + serverBootstrap.registerHandler(BUNDLE_PATH, new HttpRequestHandler() { + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + response.setStatusCode(200); + } + }); + } + }; + + private static QueryClient client; + + public QueryClientTest() throws ClientException { + client = new QueryClient(httpServer.getURI(), "admin", "admin"); + // for testing an already running instance + // client = new QueryClient(java.net.URI.create("http://localhost:8080"), "admin", "admin"); + } + + @Test + public void testInstallServlet() throws ClientException, InterruptedException { + client.installServlet(); + } + + @Test + public void testDoQuery() throws ClientException, InterruptedException { + JsonNode response = client.doQuery("SELECT * FROM [nt:file] WHERE ISDESCENDANTNODE([/etc/])", +// JsonNode response = client.doQuery("SELECT * FROM [cq:Tag] WHERE ISDESCENDANTNODE([/etc/])", + QueryClient.QueryType.SQL2); + LOG.info(response.toString()); + Assert.assertNotEquals(0, response.get("total").getLongValue()); + } + + @Test + public void testDoCount() throws ClientException, InterruptedException { + long results = client.doCount("SELECT * FROM [nt:file] WHERE ISDESCENDANTNODE([/etc/])", + QueryClient.QueryType.SQL2); + LOG.info("results={}", results); + Assert.assertNotEquals(0, results); + } + + @Test + public void testGetPlan() throws ClientException, InterruptedException { + String plan = client.getPlan("SELECT * FROM [nt:file] WHERE ISDESCENDANTNODE([/etc/])", + QueryClient.QueryType.SQL2); + LOG.info("plan={}", plan); + Assert.assertNotEquals("", plan); + } + + @Test + public void testUninstallServlet() throws ClientException { + client.uninstallServlet(); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/clients/util/poller/PollingTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/clients/util/poller/PollingTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/clients/util/poller/PollingTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.clients.util.poller; + +import org.apache.commons.lang3.mutable.MutableBoolean; +import org.apache.commons.lang3.mutable.MutableInt; +import org.junit.Assert; +import org.junit.Test; +import java.util.concurrent.TimeoutException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class PollingTest { + @Test + public void testCallOnce() throws Exception { + final MutableInt callCount = new MutableInt(0); + Polling p = new Polling() { + @Override + public Boolean call() throws Exception { + callCount.increment(); + return true; + } + }; + p.poll(500, 10); + + assertEquals(1, callCount.intValue()); + } + + @Test + public void testCallTwice() throws Exception { + final MutableInt callCount = new MutableInt(0); + final MutableBoolean called = new MutableBoolean(false); + Polling p = new Polling() { + @Override + public Boolean call() throws Exception { + callCount.increment(); + boolean b = called.booleanValue(); + called.setTrue(); + return b; + } + }; + p.poll(500, 10); + + assertEquals(2, callCount.intValue()); + } + + @Test + public void testCallTimeout() throws Exception { + final MutableInt callCount = new MutableInt(0); + Polling p = new Polling() { + @Override + public Boolean call() throws Exception { + callCount.increment(); + return false; + } + }; + + try { + p.poll(100, 10); + } catch (TimeoutException e ) { + assertTrue("Expected to execute call() at least 4 times, got instead only " + callCount.intValue() + " calls", + callCount.intValue() > 5); + return; + } + + fail("Did not reach timeout"); + } + + @Test + public void testNegativeTimeout() throws Exception { + final MutableInt callCount = new MutableInt(0); + Polling p = new Polling() { + @Override + public Boolean call() throws Exception { + callCount.increment(); + return true; + } + }; + p.poll(-1, 10); + + assertEquals(1, callCount.intValue()); + } + + // + // Tests with Callable + // + + @Test + public void testCallableOnce() throws Exception { + final MutableInt callCount = new MutableInt(0); + final MutableBoolean called = new MutableBoolean(false); + Polling p = new Polling(() -> { + callCount.increment(); + return true; + }); + p.poll(500, 10); + + assertEquals(1, callCount.intValue()); + } + + @Test + public void testCallableTwice() throws Exception { + final MutableInt callCount = new MutableInt(0); + final MutableBoolean called = new MutableBoolean(false); + Polling p = new Polling(() -> { + callCount.increment(); + boolean b = called.booleanValue(); + called.setTrue(); + return b; + }); + p.poll(500, 10); + + assertEquals(2, callCount.intValue()); + } + + @Test + public void testCallableTimeout() throws Exception { + final MutableInt callCount = new MutableInt(0); + Polling p = new Polling(() -> { + callCount.increment(); + return false; + }); + + try { + p.poll(100, 10); + } catch (TimeoutException e ) { + assertTrue("Expected to execute call() at least 4 times, got instead only " + callCount.intValue() + " calls", + callCount.intValue() > 5); + return; + } + + fail("Did not reach timeout"); + } + + + @Test + public void testCallPriority() throws Exception { + Polling p = new Polling(() -> false) { + @Override + public Boolean call() throws Exception { + return true; + } + }; + + // Should not reach timeout since overridden call() has priority over Callable param + p.poll(100, 10); + } + + @Test + public void testCallThrowException() throws Exception { + Polling p = new Polling(() -> { + throw new RuntimeException("%Failure"); + }); + try { + p.poll(100, 10); + } catch (TimeoutException e) { + Assert.assertTrue("Timeout message should contain original message", e.getMessage().contains("%Failure")); + } + + } + + +} \ No newline at end of file Added: release/sling/src/test/java/org/apache/sling/testing/util/ResourceUtilTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/util/ResourceUtilTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/util/ResourceUtilTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,41 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * 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. + ******************************************************************************/ +package org.apache.sling.testing.util; + +import org.apache.sling.testing.clients.util.ResourceUtil; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class ResourceUtilTest { + + private static final long EXPECTED_NB_CARRIAGE_RETURNS = 6; + + @Test + public void testReadResourceAsStringNoExtraLineBreak() throws IOException { + String input = ResourceUtil.readResourceAsString("/resource-util-test-file.txt"); + assertNotNull(input); + long count = input.chars().filter(ch -> ch == '\n').count(); + assertEquals("Expecting to have 6 line break in the given text file.", EXPECTED_NB_CARRIAGE_RETURNS, count); + } + +} Added: release/sling/src/test/java/org/apache/sling/testing/util/UniquePathsTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/util/UniquePathsTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/util/UniquePathsTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.util; + +import org.apache.sling.testing.clients.util.UniquePaths; +import org.junit.Before; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.util.concurrent.atomic.AtomicLong; + +import static org.junit.Assert.assertEquals; + +public class UniquePathsTest { + + @Before + public void setup() throws Exception { + // Set known startTime and counter values for tests + { + final Field f = UniquePaths.class.getDeclaredField("startTime"); + f.setAccessible(true); + f.set(UniquePaths.class, 1234L); + } + { + final Field f = UniquePaths.class.getDeclaredField("counter"); + f.setAccessible(true); + f.set(UniquePaths.class, new AtomicLong(9362L)); + } + } + + @Test + public void testNoUPattern() { + assertEquals("/tmp/UniquePathsTest_1234_9363", UniquePaths.get(this, "/tmp/")); + assertEquals("/bar/UniquePathsTest_1234_9364", UniquePaths.get(this, "/bar/")); + } + + @Test + public void testSingleUPattern() { + assertEquals("/tmp/UniquePathsTest_1234_9363/foo", UniquePaths.get(this, "/tmp/_UNIQ_/foo")); + } + + @Test + public void testMultipleUPattern() { + assertEquals( + "/tmp/UniquePathsTest_1234_9363/foo/UniquePathsTest_1234_9363.html", + UniquePaths.get(this, "/tmp/_UNIQ_/foo/_UNIQ_.html")); + } + + @Test + public void testNullPattern() { + assertEquals( + "UniquePathsTest_1234_9363", + UniquePaths.get(this, null)); + } + + @Test + public void testNoPattern() { + assertEquals( + "UniquePathsTest_1234_9363", + UniquePaths.get(this)); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/util/poller/AbstractPollerTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/util/poller/AbstractPollerTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/util/poller/AbstractPollerTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You 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. + */ +package org.apache.sling.testing.util.poller; + +import org.apache.sling.testing.clients.util.poller.AbstractPoller; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AbstractPollerTest { + private static final Logger LOG = LoggerFactory.getLogger(AbstractPollerTest.class); + + @Test + public void testCallAndWaitSuccess() throws InterruptedException { + AbstractPoller poller = new AbstractPoller(100, 5) { + int callNumber = 0; + + @Override + public boolean call() { + return true; + } + + @Override + public boolean condition() { + callNumber += 1; + LOG.debug("Call nr " + callNumber); + if (callNumber == 4) { + return true; + } + return false; + } + }; + Assert.assertTrue(poller.callAndWait()); + } + + @Test + public void testCallAndWaitFailure() throws InterruptedException { + AbstractPoller poller = new AbstractPoller(100, 5) { + @Override + public boolean call() { + return true; + } + + @Override + public boolean condition() { + return false; + } + }; + Assert.assertFalse(poller.callAndWait()); + } + + @Test + public void testCallUntilSuccess() throws InterruptedException { + AbstractPoller poller = new AbstractPoller(100, 5) { + int callNumber = 0; + + @Override + public boolean call() { + callNumber += 1; + LOG.debug("Call nr " + callNumber); + return true; + } + + @Override + public boolean condition() { + if (callNumber == 4) { + return true; + } + return false; + } + }; + Assert.assertTrue(poller.callUntilCondition()); + } + + @Test + public void testCallUntilFailure() throws InterruptedException { + AbstractPoller poller = new AbstractPoller(100, 5) { + @Override + public boolean call() { + return true; + } + + @Override + public boolean condition() { + return false; + } + }; + Assert.assertFalse(poller.callUntilCondition()); + } + + +} Added: release/sling/src/test/resources/resource-util-test-file.txt ============================================================================== --- release/sling/src/test/resources/resource-util-test-file.txt (added) +++ release/sling/src/test/resources/resource-util-test-file.txt Thu Apr 9 13:50:42 2020 @@ -0,0 +1,7 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +Odio facilisis mauris sit amet massa vitae. Ipsum a arcu cursus vitae congue mauris rhoncus. +Sit amet consectetur adipiscing elit ut aliquam purus sit. Non pulvinar neque laoreet suspendisse interdum consectetur. +Quisque id diam vel quam elementum pulvinar. Cras pulvinar mattis nunc sed blandit libero volutpat sed. +Accumsan lacus vel facilisis volutpat est velit egestas dui id. Vivamus at augue eget arcu dictum. +Turpis egestas integer eget aliquet nibh. Lobortis feugiat vivamus at augue eget arcu dictum. +Lorem ipsum dolor sit amet consectetur adipiscing elit pellentesque. \ No newline at end of file
