You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 10:17:26 UTC
[sling-org-apache-sling-testing-clients] 05/08: SLING-6853 Fixed
incomplete patch.
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.testing.clients-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-clients.git
commit a06ceb1265a678a3e7820441ff8152062c59cd53
Author: Andrei Dulvac <du...@apache.org>
AuthorDate: Tue May 16 15:03:12 2017 +0000
SLING-6853 Fixed incomplete patch.
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/testing/http/clients@1795326 13f79535-47bb-0310-9956-ffa450edef68
---
.../sling/testing/clients/util/poller/Polling.java | 131 +++++++++++++++
.../sling/testing/clients/HttpServerRule.java | 84 ++++++++++
.../testing/clients/SlingClientDoGetJsonTest.java | 71 ++++++++
.../testing/clients/SlingClientWaitExistsTest.java | 93 +++++++++++
.../testing/clients/util/poller/PollingTest.java | 179 +++++++++++++++++++++
5 files changed, 558 insertions(+)
diff --git a/src/main/java/org/apache/sling/testing/clients/util/poller/Polling.java b/src/main/java/org/apache/sling/testing/clients/util/poller/Polling.java
new file mode 100644
index 0000000..faef6b2
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/clients/util/poller/Polling.java
@@ -0,0 +1,131 @@
+/*
+ * 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.sling.testing.timeouts.TimeoutsProvider;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Helper for repeating a call until it returns true, with timeout capabilities.
+ * Subclasses should override the {@link #call()} method.
+ * Can be used with lambda expressions, using the constructor {@link #Polling(Callable c)}.
+ *
+ * @since 1.1.0
+ */
+public class Polling implements Callable<Boolean> {
+
+ /**
+ * Optional object to be used by the default implementation of call()
+ */
+ protected final Callable<Boolean> c;
+
+ /**
+ * Holder for the last exception thrown by call(), to be used for logging
+ */
+ protected Exception lastException;
+
+ /**
+ * Default constructor to be used in subclasses that override the {@link #call()} method.
+ * Should not be used directly on {@code Polling} instances, but only on extended classes.
+ * If used directly to get a {@code Polling} instance, executing {@link #poll(long timeout, long delay)}
+ * will be equivalent to {@code Thread.sleep(timeout)}
+ */
+ public Polling() {
+ this.c = null;
+ this.lastException = null;
+ }
+
+ /**
+ * Creates a new instance that uses the {@code Callable} parameter for polling
+ *
+ * @param c object whose {@code call()} method will be polled
+ */
+ public Polling(Callable<Boolean> c) {
+ this.c = c;
+ this.lastException = null;
+ }
+
+ /**
+ * <p>Method to be called by {@link #poll(long timeout, long delay)}, potentially multiple times,
+ * until it returns true or timeout is reached.<br/>
+ * Subclasses can override it to change the check accordingly. The method should return true
+ * only when the call was successful.<br/>
+ * It can return false or throw any {@code Exception} to make the poller try again later.</p>
+ *
+ * <p>The default implementation delegates the call to the {@code Callable c} instance.</p>
+ *
+ * @return {@code true} to end polling
+ * @throws Exception if unable to compute a result
+ */
+ @Override
+ public Boolean call() throws Exception {
+ if (c != null) {
+ return c.call();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * <p>Tries to execute {@link #call()} until it returns true or until {@code timeout} is reached.
+ * Between retries, it waits using {@code Thread.sleep(delay)}. It means the retry is not at a fixed pace,
+ * but depends on the execution time of the call itself.</p>
+ * <p>The method guarantees that the call() will be executed at least once. If the timeout is 0 or less, then
+ * call() will be executed exactly once.</p>
+ * <p>The timeout is adjusted using {@link TimeoutsProvider} so the final value can be changed using the
+ * system property: {@value org.apache.sling.testing.timeouts.TimeoutsProvider#PROP_TIMEOUT_MULTIPLIER}</p>
+ *
+ * @param timeout max total execution time, in milliseconds
+ * @param delay time to wait between calls, in milliseconds
+ *
+ * @throws TimeoutException if {@code timeout} was reached
+ * @throws InterruptedException if the thread was interrupted while sleeping; caller should throw it further
+ */
+ public void poll(long timeout, long delay) throws TimeoutException, InterruptedException {
+ long start = System.currentTimeMillis();
+ long effectiveTimeout = TimeoutsProvider.getInstance().getTimeout(timeout);
+
+ do {
+ try {
+ boolean success = call();
+ if (success) {
+ return;
+ }
+ Thread.sleep(delay);
+ } catch (InterruptedException e) {
+ throw e;
+ } catch (Exception e) {
+ lastException = e;
+ }
+ } while (System.currentTimeMillis() < start + effectiveTimeout);
+
+ throw new TimeoutException(String.format(message(), effectiveTimeout, delay));
+ }
+
+ /**
+ * Returns the string to be used in the {@code TimeoutException}, if needed.
+ * The string is passed to {@code String.format(message(), timeout, delay)}, so it can be a format
+ * including {@code %1$} and {@code %2$}. The field {@code lastException} is also available for logging
+ *
+ * @return the format string
+ */
+ protected String message() {
+ return "Call failed to return true in %1$d ms. Last exception was: " + lastException;
+ }
+}
diff --git a/src/test/java/org/apache/sling/testing/clients/HttpServerRule.java b/src/test/java/org/apache/sling/testing/clients/HttpServerRule.java
new file mode 100644
index 0000000..926f79b
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/clients/HttpServerRule.java
@@ -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
diff --git a/src/test/java/org/apache/sling/testing/clients/SlingClientDoGetJsonTest.java b/src/test/java/org/apache/sling/testing/clients/SlingClientDoGetJsonTest.java
new file mode 100644
index 0000000..6eeba23
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/clients/SlingClientDoGetJsonTest.java
@@ -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());
+ }
+}
diff --git a/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java b/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java
new file mode 100644
index 0000000..31b67bf
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/clients/SlingClientWaitExistsTest.java
@@ -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, 200, 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);
+ }
+}
diff --git a/src/test/java/org/apache/sling/testing/clients/util/poller/PollingTest.java b/src/test/java/org/apache/sling/testing/clients/util/poller/PollingTest.java
new file mode 100644
index 0000000..15994ed
--- /dev/null
+++ b/src/test/java/org/apache/sling/testing/clients/util/poller/PollingTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.Test;
+
+import java.util.concurrent.Callable;
+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(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ 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(new Callable<Boolean>() {
+ @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 testCallableTimeout() throws Exception {
+ final MutableInt callCount = new MutableInt(0);
+ Polling p = new Polling(new Callable<Boolean>() {
+ @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 testCallPriority() throws Exception {
+ Polling p = new Polling(new Callable<Boolean>() {
+ @Override
+ public Boolean call() throws Exception {
+ return 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);
+ }
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.