Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/JsonUtils.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/JsonUtils.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/JsonUtils.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.util; + +import org.apache.sling.testing.clients.ClientException; +import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.JsonProcessingException; +import org.codehaus.jackson.map.ObjectMapper; + +import java.io.IOException; + +public class JsonUtils { + /** + * Get {@link JsonNode} from a a String containing JSON. + * + * @param jsonString A string containing JSON + * @return A {@link JsonNode} that is the root node of the JSON structure. + * @throws ClientException if error occurs while reading json string + */ + public static JsonNode getJsonNodeFromString(String jsonString) throws ClientException { + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.readTree(jsonString); + } catch (JsonProcessingException e) { + throw new ClientException("Could not read json file.", e); + } catch (IOException e) { + throw new ClientException("Could not read json node.", e); + } + } +} \ No newline at end of file
Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/PortAllocator.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/PortAllocator.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/PortAllocator.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,58 @@ +/* + * 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; + +import java.net.ServerSocket; +import java.util.HashSet; +import java.util.Set; + +public class PortAllocator { + + private static Set<Integer> allocatedPorts; + + static { + allocatedPorts = new HashSet<Integer>(); + } + + public Integer allocatePort() { + while (true) { + int port = tryAllocation(); + + boolean portAdded = checkAndAddPort(port); + + if (portAdded) { + return port; + } + } + } + + private int tryAllocation() { + try { + ServerSocket serverSocket = new ServerSocket(0); + int port = serverSocket.getLocalPort(); + serverSocket.close(); + return port; + } catch (Exception e) { + throw new RuntimeException("Can't allocate a port"); + } + } + + private synchronized boolean checkAndAddPort(int port) { + return allocatedPorts.add(port); + } + +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/ResourceUtil.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/ResourceUtil.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/ResourceUtil.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,72 @@ +/* + * 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; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class ResourceUtil { + + /** + * We must get the Resource as a stream from the ContextClassLoader and not from the normal classLoader + * acquired by using getClass.getClassLoader, since we must be able to load resources from different threads + * e.g. running in ant. + * + * @param resourcePath path to the resource + * @return resource as InputStream + */ + public static InputStream getResourceAsStream(final String resourcePath) { + final String path = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; + return Thread.currentThread().getContextClassLoader().getResourceAsStream(path); + } + + /** + * Helper method to read a resource from class using {@link Class#getResourceAsStream(String)} + * and convert into a String. + * + * @param resource The resource to read. + * @return The requested resource as String, resolved using + * {@link Class#getResourceAsStream(String)}, or {@code null} + * if the requested resource cannot be resolved for some reason + * @throws IOException if the Resource Stream cannot be read + */ + public static String readResourceAsString(final String resource) throws IOException { + InputStream resourceAsStream = ResourceUtil.getResourceAsStream(resource); + if (resourceAsStream != null) { + StringBuilder sb = new StringBuilder(); + String line; + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(resourceAsStream, UTF_8.name())); + while ((line = reader.readLine()) != null) { + if (sb.length() > 0) { + sb.append("\n"); + } + sb.append(line); + } + } finally { + resourceAsStream.close(); + } + return sb.toString(); + } + return null; + } + +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/ServerErrorRetryStrategy.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/ServerErrorRetryStrategy.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/ServerErrorRetryStrategy.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,77 @@ +/* + * 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; + +import org.apache.http.HttpResponse; +import org.apache.http.client.ServiceUnavailableRetryStrategy; +import org.apache.http.protocol.HttpContext; +import org.apache.http.util.EntityUtils; +import org.apache.sling.testing.clients.SystemPropertiesConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; + +import static org.apache.http.HttpStatus.*; + +/** + * {code ServiceUnavailableRetryStrategy} strategy for retrying request in case of a 5XX response code + */ +public class ServerErrorRetryStrategy implements ServiceUnavailableRetryStrategy { + + private static final Logger LOG = LoggerFactory.getLogger(ServerErrorRetryStrategy.class); + + public ServerErrorRetryStrategy() { + super(); + } + + @Override + public boolean retryRequest(final HttpResponse response, final int executionCount, final HttpContext context) { + boolean needsRetry = executionCount <= SystemPropertiesConfig.getHttpRetries() && responseRetryCondition(response); + + if (SystemPropertiesConfig.isHttpLogRetries() && needsRetry && LOG.isWarnEnabled()) { + LOG.warn("Request retry needed due to service unavailable response"); + LOG.warn("Response headers contained:"); + Arrays.stream(response.getAllHeaders()).forEach(h -> LOG.warn("Header {}:{}", h.getName(), h.getValue())); + try { + String content = EntityUtils.toString(response.getEntity()); + LOG.warn("Response content: {}", content); + } catch (IOException exc) { + LOG.warn("Response as no content"); + } + } + return needsRetry; + } + + @Override + public long getRetryInterval() { + return SystemPropertiesConfig.getHttpRetriesDelay(); + } + + private boolean responseRetryCondition(final HttpResponse response) { + final Integer statusCode = response.getStatusLine().getStatusCode(); + final Collection<Integer> errorCodes = SystemPropertiesConfig.getHttpRetriesErrorCodes(); + if (errorCodes != null && !errorCodes.isEmpty()) { + return errorCodes.contains(statusCode); + } else { + return statusCode >= SC_INTERNAL_SERVER_ERROR && + statusCode < SC_INTERNAL_SERVER_ERROR + 100; + } + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/SlingParameter.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/SlingParameter.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/SlingParameter.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,108 @@ +/* + * 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; + +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; + +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class SlingParameter { + + private String typeHint = null; + private boolean delete = false; + + String parameterName; + private String[] values = null; + private boolean multiple = false; + + public SlingParameter(String parameterName) { + if (parameterName == null || parameterName.length() == 0) { + throw new IllegalArgumentException("parameterName must not be null or empty"); + } + this.parameterName = parameterName; + } + + public SlingParameter value(String value) { + if (value != null) { + this.values(new String[]{value}); + } else { + this.values(new String[]{}); + } + return this; + } + + public SlingParameter values(String[] values) { + if (values == null) { + this.values = new String[]{}; + } else { + this.values = values; + } + return this; + } + + public SlingParameter typeHint(String typeHint) { + this.typeHint = typeHint; + return this; + } + + public SlingParameter delete() { + this.delete = true; + return this; + } + + public SlingParameter multiple() { + this.multiple = true; + return this; + } + + public List<NameValuePair> toNameValuePairs() { + List<NameValuePair> parameters = new ArrayList<NameValuePair>(); + + if (multiple) { + for (String value : values) { + parameters.add(new BasicNameValuePair(parameterName, value)); + } + } else if (values != null && values.length == 1) { + parameters.add(new BasicNameValuePair(parameterName, values[0])); + } else if (values != null && values.length > 1) { + // TODO not sure about the proper format of the values in this case? + // For now, only take the first one. + parameters.add(new BasicNameValuePair(parameterName, values[0])); + } else { + parameters.add(new BasicNameValuePair(parameterName, null)); + } + + // add @TypeHint suffix + if (typeHint != null) { + String parameter = parameterName + "@TypeHint"; + parameters.add(new BasicNameValuePair(parameter, typeHint)); + } + + // add @Delete suffix + if (delete) { + String parameter = parameterName + "@Delete"; + parameters.add(new BasicNameValuePair(parameter, "true")); + } + + return parameters; + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/TimeoutsProvider.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/TimeoutsProvider.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/TimeoutsProvider.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,86 @@ +/* + * 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; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Return timeout values that can be multiplied by a configurable + * factor. Useful to cope with slower integration testing systems: + * use timeout constants in your code that work for usual development + * systems, and set a multiplier when running on a slower system. + * + * @deprecated duplicate of {@link org.apache.sling.testing.timeouts.TimeoutsProvider}. This will be removed in the future, so switch to + * the other one instead + */ +@Deprecated +public class TimeoutsProvider { + private static final Logger log = LoggerFactory.getLogger(TimeoutsProvider.class); + public static final String PROP_TIMEOUT_MULTIPLIER = "sling.testing.timeout.multiplier"; + private static float timeoutFactor = -1; + private static TimeoutsProvider INSTANCE; + + private TimeoutsProvider() { + if(timeoutFactor < 0) { + timeoutFactor = 1; + final String str = System.getProperty(PROP_TIMEOUT_MULTIPLIER); + if(str != null) { + try { + timeoutFactor = Float.valueOf(str.trim()); + log.info("Timeout factor set to {} from system property {}", + timeoutFactor, PROP_TIMEOUT_MULTIPLIER); + } catch(NumberFormatException nfe) { + throw new IllegalStateException("Invalid timeout factor: " + PROP_TIMEOUT_MULTIPLIER + "=" + str); + } + } + } + } + + public static TimeoutsProvider getInstance() { + if(INSTANCE == null) { + synchronized (TimeoutsProvider.class) { + INSTANCE = new TimeoutsProvider(); + } + } + return INSTANCE; + } + + public long getTimeout(long nomimalValue) { + final long result = (long)(nomimalValue * timeoutFactor); + return result; + } + + public int getTimeout(int nomimalValue) { + final int result = (int)(nomimalValue * timeoutFactor); + return result; + } + + /** + * Get timeout from a system property, with default value + * @param systemPropertyName Name of the system property that holds the timeout multiplier + * @param defaultNominalValue The default timeout multiplier + * @return the total timeout value + */ + public int getTimeout(String systemPropertyName, int defaultNominalValue) { + int result = defaultNominalValue; + final String str = System.getProperty(systemPropertyName); + if(str != null) { + result = Integer.parseInt(str); + } + return getTimeout(result); + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/URLParameterBuilder.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/URLParameterBuilder.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/URLParameterBuilder.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,79 @@ +/* + * 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; + +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.message.BasicNameValuePair; + +import java.util.ArrayList; +import java.util.List; + +public class URLParameterBuilder { + + public final static String DEFAULT_ENCODING = "UTF-8"; + + private List<NameValuePair> params; + private String encoding; + + public static URLParameterBuilder create() { + return new URLParameterBuilder(); + } + + URLParameterBuilder() { + params = new ArrayList<NameValuePair>(); + encoding = DEFAULT_ENCODING; + } + + public URLParameterBuilder add(String name, String value) { + params.add(new BasicNameValuePair(name, value)); + return this; + } + + public URLParameterBuilder add(NameValuePair pair) { + params.add(pair); + return this; + } + + public URLParameterBuilder add(List<NameValuePair> list) { + params.addAll(list); + return this; + } + + public URLParameterBuilder add(String name, String[] values) { + for (String value : values) this.add(name, value); + return this; + } + + public URLParameterBuilder setEncoding(String encoding) { + this.encoding = encoding; + return this; + } + + /** + * Build the URL parameters + * + * @return The URL parameters string without the leading question mark. + */ + public String getURLParameters() { + return URLEncodedUtils.format(params, encoding); + } + + public List<NameValuePair> getList() { + return params; + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/UniquePaths.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/UniquePaths.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/UniquePaths.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,67 @@ +/* + * 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; + +import java.util.concurrent.atomic.AtomicLong; + +/** Generate unique paths, for tests isolation */ +public class UniquePaths { + + private static long startTime = System.currentTimeMillis(); + private static AtomicLong counter = new AtomicLong(); + public final static String SEP = "_"; + public final static String U_PATTERN = "_UNIQ_"; + + /** + * Return a unique path based on basePath + * @param nameReference The simple class name of that object is used as part of the + * generated unique ID + * @param basePath All occurrences of {@link UniquePaths#U_PATTERN} in basePath are replaced by the generated + * unique ID. If $U$ is not found in basePath, unique ID is added at its end. + * @return path with a unique value for each call. + */ + public static String get(Object nameReference, String basePath) { + if(basePath == null) { + basePath = ""; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(nameReference.getClass().getSimpleName()); + sb.append(SEP); + sb.append(startTime); + sb.append(SEP); + sb.append(counter.incrementAndGet()); + + if(basePath.contains(U_PATTERN)) { + return basePath.replaceAll(U_PATTERN, sb.toString()); + } else { + return basePath + sb.toString(); + } + } + + /** + * Get a unique ID with no base path + * + * @param nameReference The simple class name of that object is used as part of the + * generated unique ID + * @return path with a unique value for each call + */ + public static String get(Object nameReference) { + return get(nameReference, null); + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/XSSUtils.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/XSSUtils.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/XSSUtils.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,137 @@ +/* + * 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; + +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.sling.xss.XSSAPI; +import org.apache.sling.xss.impl.XSSAPIImpl; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +/** + * Basic class for XSS Testing + * The reliability of these methods are not critical + */ +public class XSSUtils { + + /** + * Use to ensure that HTTP query strings are in proper form, by escaping + * special characters such as spaces. + * + * @param urlString the string to be encoded + * @return the encoded string + */ + public static String encodeUrl(String urlString) { + try { + return URLEncoder.encode(urlString, "UTF-8"); + } catch (UnsupportedEncodingException ex) { + throw new RuntimeException("UTF-8 not supported", ex); + } + } + + /** + * Use to encapsulate old-style escaping of HTML (using StringEscapeUtils). + * NB: newer code uses XSSAPI (based on OWASP's ESAPI). + * + * @param htmlString the string to be escaped + * @return the escaped string + */ + public static String escapeHtml(String htmlString) { + return StringEscapeUtils.escapeHtml4(htmlString); + } + + /** + * Use to encapsulate old-style escaping of XML (with JSTL encoding rules). + * NB: newer code uses XSSAPI (based on OWASP's ESAPI). + * + * @param xmlString the string to be escaped + * @return the escaped string + */ + public static String escapeXml(String xmlString) { + String xssString = xmlString; + if (xmlString != null) { + xssString = xssString.replace(";", ";"); + xssString = xssString.replace(" ", " "); + xssString = xssString.replace("'", "'"); + xssString = xssString.replace("\"", """); + xssString = xssString.replace(">", ">"); + xssString = xssString.replace("<", "<"); + xssString = xssString.replace("/", "/"); + xssString = xssString.replace("(", "("); + xssString = xssString.replace(")", ")"); + xssString = xssString.replace(":", ":"); + } + return xssString; + } + + /** + * Use to encapsulate new-style (XSSAPI-based) encoding for HTML element content. + * + * @param source the string to be encoded + * @return the encoded string + */ + public static String encodeForHTML(String source) { + XSSAPI xssAPI = new XSSAPIImpl(); + return xssAPI.encodeForHTML(source); + } + + /** + * Use to encapsulate new-style (XSSAPI-based) encoding for HTML attribute values. + * + * @param source the string to be encoded + * @return the encoded string + */ + public static String encodeForHTMLAttr(String source) { + XSSAPI xssAPI = new XSSAPIImpl(); + return xssAPI.encodeForHTMLAttr(source); + } + + /** + * Use to encapsulate new-style (XSSAPI-based) encoding for XML element content. + * + * @param source the string to be encoded + * @return the encoded string + */ + public static String encodeForXML(String source) { + XSSAPI xssAPI = new XSSAPIImpl(); + return xssAPI.encodeForXML(source); + } + + /** + * Use to encapsulate new-style (XSSAPI-based) encoding for XML attribute values. + * + * @param source the string to be encoded + * @return the encoded string + */ + public static String encodeForXMLAttr(String source) { + XSSAPI xssAPI = new XSSAPIImpl(); + return xssAPI.encodeForXMLAttr(source); + } + + /** + * Use to encapsulate new-style (XSSAPI-based) encoding for JavaScript strings. + * + * @param source the string to be encoded + * @return the encoded string + */ + public static String encodeForJSString(String source) { + XSSAPI xssAPI = new XSSAPIImpl(); + return xssAPI.encodeForJSString(source); + } + +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfig.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfig.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfig.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,42 @@ +/* + * 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.config; + +/** + * Allows saving and restoring an instance configuration. + * Implementations define the behaviour of save() and restore() + */ +public interface InstanceConfig { + + /** + * Saves the current status of the configuration + * + * @return this + * @throws InstanceConfigException if saving the configuration fails + * @throws InterruptedException if interrupted + */ + public InstanceConfig save() throws InstanceConfigException, InterruptedException; + + /** + * Restores the saved status of the configuration + * + * @return this + * @throws InstanceConfigException if restoring the configuration fails + * @throws InterruptedException if interrupted + */ + public InstanceConfig restore() throws InstanceConfigException, InterruptedException; +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfigCache.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfigCache.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfigCache.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,25 @@ +/* + * 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.config; + +import java.util.Collection; + +/** + * A cache for different {@link InstanceConfig} objects + */ +public interface InstanceConfigCache extends InstanceConfig, Collection<InstanceConfig> { +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfigException.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfigException.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/config/InstanceConfigException.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,39 @@ +/* + * 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.config; + +public class InstanceConfigException extends Exception { + + public InstanceConfigException(Exception e) { + super(e); + } + + public InstanceConfigException() { + } + + public InstanceConfigException(String message) { + super(message); + } + + public InstanceConfigException(String message, Throwable cause) { + super(message, cause); + } + + public InstanceConfigException(Throwable cause) { + super(cause); + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/EmptyInstanceConfig.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/EmptyInstanceConfig.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/EmptyInstanceConfig.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,36 @@ +/* + * 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.config.impl; + +import org.apache.sling.testing.clients.util.config.InstanceConfig; +import org.apache.sling.testing.clients.util.config.InstanceConfigException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EmptyInstanceConfig implements InstanceConfig { + private static final Logger LOG = LoggerFactory.getLogger(EmptyInstanceConfig.class); + + public InstanceConfig save() throws InstanceConfigException { + LOG.debug("Saved nothing"); + return this; + } + + public InstanceConfig restore() throws InstanceConfigException { + LOG.debug("Restored nothing"); + return this; + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/InstanceConfigCacheImpl.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/InstanceConfigCacheImpl.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/InstanceConfigCacheImpl.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,120 @@ +/* + * 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.config.impl; + +import org.apache.sling.testing.clients.util.config.InstanceConfig; +import org.apache.sling.testing.clients.util.config.InstanceConfigCache; +import org.apache.sling.testing.clients.util.config.InstanceConfigException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +public class InstanceConfigCacheImpl implements InstanceConfigCache { + List<InstanceConfig> configs; + + public InstanceConfigCacheImpl(List<InstanceConfig> configs) { + this.configs = configs; + } + + public InstanceConfigCacheImpl() { + this.configs = new ArrayList<InstanceConfig>(); + } + + @Override + public int size() { + return configs.size(); + } + + @Override + public boolean isEmpty() { + return configs.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return configs.contains(o); + } + + @Override + public Iterator<InstanceConfig> iterator() { + return configs.iterator(); + } + + @Override + public Object[] toArray() { + return configs.toArray(); + } + + @Override + public <T> T[] toArray(T[] a) { + return configs.toArray(a); + } + + @Override + public boolean add(InstanceConfig instanceConfig) { + return configs.add(instanceConfig); + } + + @Override + public boolean remove(Object o) { + return configs.remove(o); + } + + @Override + public boolean containsAll(Collection<?> c) { + return configs.containsAll(c); + } + + @Override + public boolean addAll(Collection<? extends InstanceConfig> c) { + return configs.addAll(c); + } + + @Override + public boolean removeAll(Collection<?> c) { + return configs.removeAll(c); + } + + @Override + public boolean retainAll(Collection<?> c) { + return configs.retainAll(c); + } + + @Override + public void clear() { + configs.clear(); + } + + + @Override + public InstanceConfig save() throws InstanceConfigException, InterruptedException { + for (InstanceConfig ic : configs) { + ic.save(); + } + return this; + } + + @Override + public InstanceConfig restore() throws InstanceConfigException, InterruptedException { + for (InstanceConfig ic : configs) { + ic.restore(); + } + return this; + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/package-info.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/package-info.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/config/impl/package-info.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,23 @@ +/* + * 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. + */ + +@Version("1.0.0") +package org.apache.sling.testing.clients.util.config.impl; + +import org.osgi.annotation.versioning.Version; Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/config/package-info.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/config/package-info.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/config/package-info.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,23 @@ +/* + * 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. + */ + +@Version("1.0.0") +package org.apache.sling.testing.clients.util.config; + +import org.osgi.annotation.versioning.Version; Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/package-info.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/package-info.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/package-info.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,23 @@ +/* + * 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. + */ + +@Version("2.0.0") +package org.apache.sling.testing.clients.util; + +import org.osgi.annotation.versioning.Version; Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/AbstractPoller.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/AbstractPoller.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/AbstractPoller.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,74 @@ +/* + * 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; + +/** + * @deprecated use {@link Polling} instead. + * @see Polling for a better way to implement polling + */ +@Deprecated +public abstract class AbstractPoller implements Poller { + + private final long waitInterval; + private final long waitCount; + + /** + * Convenience method to execute a generic call and do polling until a condition is met + * The user must implement the {@link Poller#call()} and {@link Poller#condition()} methods + * @param waitInterval Number of milliseconds to wait between polls + * @param waitCount Number of wait intervals + */ + public AbstractPoller(long waitInterval, long waitCount) { + this.waitInterval = waitInterval; + this.waitCount = waitCount; + } + + /** + * Calls the {@link Poller#call()} once and then calls {@link Poller#condition()} until it returns true + * The method waits AbstractPoller#waitInterval milliseconds between calls to {@link Poller#condition()} + * A maximum of AbstractPoller#waitCount intervals are checked + * @return true if the condition is met after waiting a maximum of AbstractPoller#waitCount intervals, false otherwise + * @throws InterruptedException to mark this operation as "waiting" + */ + public boolean callAndWait() throws InterruptedException { + if (!call()) return false; + for (int i=0; i<waitCount; i++) { + if (condition()) return true; + Thread.sleep(waitInterval); + } + return false; + } + + /** + * Calls the @see: Poller#call() and then calls {@link Poller#condition()} until it returns true + * The Poller#call() method is called in each wait interval, before the Poller#condition(). + * The method waits AbstractPoller#waitInterval milliseconds between calls to {@link Poller#condition()} + * A maximum of AbstractPoller#waitCount intervals are checked + * @return true if the condition is met after waiting a maximum of AbstractPoller#waitCount intervals, false otherwise + * @throws InterruptedException to mark this operation as "waiting" + */ + public boolean callUntilCondition() throws InterruptedException { + if (!call()) return false; + if (condition()) return true; + for (int i = 0; i < waitCount; i++) { + Thread.sleep(waitInterval); + if (!call()) return false; + if (condition()) return true; + } + return false; + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/PathPoller.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/PathPoller.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/PathPoller.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,69 @@ +/******************************************************************************* + * 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.util.poller; + +import org.apache.sling.testing.clients.AbstractSlingClient; +import org.apache.sling.testing.clients.ClientException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Allows polling for a resource + */ +@Deprecated +public class PathPoller extends AbstractPoller { + private static final Logger LOG = LoggerFactory.getLogger(PathPoller.class); + private final AbstractSlingClient client; + private final String path; + private final int[] expectedStatus; + private Exception exception; + + public PathPoller(AbstractSlingClient client, String path, long waitInterval, long waitCount, int... expectedStatus) { + super(waitInterval, waitCount); + this.client = client; + this.path = path; + if (null == expectedStatus || expectedStatus.length == 0) { + this.expectedStatus = new int[]{200}; + } else { + this.expectedStatus = expectedStatus; + } + } + + + @Override + public boolean call() { + return true; + } + + @Override + public boolean condition() { + try { + client.doGet(path, expectedStatus); + } catch (ClientException e) { + LOG.warn("Get on {} failed: {}", path, e); + this.exception = e; + return false; + } + return true; + } + + public Exception getException() { + return exception; + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/Poller.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/Poller.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/Poller.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,32 @@ +/* + * 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; + +/** + * Abstract Poller interface. + * Provides simple methods to implement custom pollers + * + * @deprecated use {@link Polling} instead. + * @see Polling for a better way to implement polling + */ +@Deprecated +public interface Poller { + boolean call(); + boolean condition(); + boolean callAndWait() throws InterruptedException; + boolean callUntilCondition() throws InterruptedException; +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/Polling.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/Polling.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/Polling.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,153 @@ +/* + * 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; + + /** + * Counter for total waiting time + */ + protected long waited; + + /** + * 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; + this.waited = 0; + } + + /** + * 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; + this.waited = 0; + } + + /** + * <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) { + waited = System.currentTimeMillis() - start; + return; + } + } catch (InterruptedException e) { + throw e; // Never inhibit InterruptedException + } catch (Exception e) { + lastException = e; + } + Thread.sleep(delay); + } while (System.currentTimeMillis() < start + effectiveTimeout); + + waited = System.currentTimeMillis() - start; + throw new TimeoutException(String.format(message(), effectiveTimeout, delay) + + " Last exception was: " + lastException); + } + + public long getWaited() { + return waited; + } + + /** + * 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$d} and {@code %2$d}. 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."; + } + + /** + * Return the last exception while polling or {null} + * @return + */ + public Exception getLastException() { + return lastException; + } +} Added: release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/package-info.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/package-info.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/clients/util/poller/package-info.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,23 @@ +/* + * 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. + */ + +@Version("1.3.0") +package org.apache.sling.testing.clients.util.poller; + +import org.osgi.annotation.versioning.Version; Added: release/sling/src/main/java/org/apache/sling/testing/timeouts/TimeoutsProvider.java ============================================================================== --- release/sling/src/main/java/org/apache/sling/testing/timeouts/TimeoutsProvider.java (added) +++ release/sling/src/main/java/org/apache/sling/testing/timeouts/TimeoutsProvider.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,96 @@ +/* + * 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.timeouts; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Return timeout values that can be multiplied by a configurable + * factor. Useful to cope with slower integration testing systems: + * use timeout constants in your code that work for usual development + * systems, and set a multiplier when running on a slower system. + */ +public class TimeoutsProvider { + private static final Logger log = LoggerFactory.getLogger(TimeoutsProvider.class); + public static final String PROP_TIMEOUT_MULTIPLIER = "sling.testing.timeout.multiplier"; + private static float timeoutFactor = -1; + private static TimeoutsProvider INSTANCE; + + private TimeoutsProvider() { + if(timeoutFactor < 0) { + timeoutFactor = 1; + final String str = System.getProperty(PROP_TIMEOUT_MULTIPLIER); + if(str != null) { + try { + timeoutFactor = Float.valueOf(str.trim()); + log.info("Timeout factor set to {} from system property {}", + timeoutFactor, PROP_TIMEOUT_MULTIPLIER); + } catch(NumberFormatException nfe) { + throw new IllegalStateException("Invalid timeout factor: " + PROP_TIMEOUT_MULTIPLIER + "=" + str); + } + } + } + } + + /** + * + * @return the instance of the singleton + */ + public static TimeoutsProvider getInstance() { + if(INSTANCE == null) { + synchronized (TimeoutsProvider.class) { + INSTANCE = new TimeoutsProvider(); + } + } + return INSTANCE; + } + + /** + * + * @param nomimalValue base number to be multiplied internally with the factor + * @return the new timeout + */ + public long getTimeout(long nomimalValue) { + final long result = (long)(nomimalValue * timeoutFactor); + return result; + } + + /** + * + * @param nomimalValue base number to be multiplied internally with the factor + * @return the new timeout + */ + public int getTimeout(int nomimalValue) { + final int result = (int)(nomimalValue * timeoutFactor); + return result; + } + + /** + * Get timeout from a system property, with default value + * @param systemPropertyName the name of the system prop from which to get the timeout + * @param defaultNominalValue default value in case the property does not exist + * @return the timeout + */ + public int getTimeout(String systemPropertyName, int defaultNominalValue) { + int result = defaultNominalValue; + final String str = System.getProperty(systemPropertyName); + if(str != null) { + result = Integer.parseInt(str); + } + return getTimeout(result); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetPathTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetPathTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetPathTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,176 @@ +/* + * 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.ClientException; +import org.apache.sling.testing.clients.SlingClient; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +@RunWith(Parameterized.class) +public class AbstractSlingClientGetPathTest { + + @Parameterized.Parameters(name = "{index} - serverUrl: {0}, input: {1}, expected: {2}") + public static Collection<String[]> data() { + return Arrays.asList(new String[][] { + {"http://HOST", "http://HOST/page.html", "/page.html"}, + {"http://HOST", "http://HOST/my/page.html", "/my/page.html"}, + {"http://HOST", "http://HOST/my/", "/my/"}, + {"http://HOST", "http://HOST/my", "/my"}, + {"http://HOST", "http://HOST/", "/"}, + {"http://HOST", "http://HOST", "/"}, + {"http://HOST", "/page.html", "/page.html"}, + {"http://HOST", "/my/page.html", "/my/page.html"}, + {"http://HOST", "/my/", "/my/"}, + {"http://HOST", "/", "/"}, + {"http://HOST", "page.html", "/page.html"}, + {"http://HOST", "my/page.html", "/my/page.html"}, + {"http://HOST", "my", "/my"}, + {"http://HOST", "", "/"}, + + {"http://HOST:4502", "http://HOST:4502/page.html", "/page.html"}, + {"http://HOST:4502", "http://HOST:4502/my/page.html", "/my/page.html"}, + {"http://HOST:4502", "http://HOST:4502/my/", "/my/"}, + {"http://HOST:4502", "http://HOST:4502/my", "/my"}, + {"http://HOST:4502", "http://HOST:4502/", "/"}, + {"http://HOST:4502", "http://HOST:4502", "/"}, + {"http://HOST:4502", "/page.html", "/page.html"}, + {"http://HOST:4502", "/my/page.html", "/my/page.html"}, + {"http://HOST:4502", "/my/", "/my/"}, + {"http://HOST:4502", "/my", "/my"}, + {"http://HOST:4502", "/", "/"}, + {"http://HOST:4502", "page.html", "/page.html"}, + {"http://HOST:4502", "my/page.html", "/my/page.html"}, + {"http://HOST:4502", "my/", "/my/"}, + {"http://HOST:4502", "my", "/my"}, + {"http://HOST:4502", "", "/"}, + + {"http://HOST:4502/", "http://HOST:4502/page.html", "/page.html"}, + {"http://HOST:4502/", "http://HOST:4502/my/page.html", "/my/page.html"}, + {"http://HOST:4502/", "http://HOST:4502/my/", "/my/"}, + {"http://HOST:4502/", "http://HOST:4502/my", "/my"}, + {"http://HOST:4502/", "http://HOST:4502/", "/"}, + {"http://HOST:4502/", "http://HOST:4502", "/"}, + {"http://HOST:4502/", "/page.html", "/page.html"}, + {"http://HOST:4502/", "/my/page.html", "/my/page.html"}, + {"http://HOST:4502/", "/my/", "/my/"}, + {"http://HOST:4502/", "/my", "/my"}, + {"http://HOST:4502/", "/", "/"}, + {"http://HOST:4502/", "page.html", "/page.html"}, + {"http://HOST:4502/", "my/page.html", "/my/page.html"}, + {"http://HOST:4502/", "my/", "/my/"}, + {"http://HOST:4502/", "my", "/my"}, + {"http://HOST:4502/", "", "/"}, + + {"http://HOST:4502/CTX", "http://HOST:4502/CTX/page.html", "/page.html"}, + {"http://HOST:4502/CTX", "http://HOST:4502/CTX/my/page.html", "/my/page.html"}, + {"http://HOST:4502/CTX", "http://HOST:4502/CTX/my/", "/my/"}, + {"http://HOST:4502/CTX", "http://HOST:4502/CTX/my", "/my"}, + {"http://HOST:4502/CTX", "http://HOST:4502/CTX/", "/"}, + {"http://HOST:4502/CTX", "http://HOST:4502/CTX", "/"}, + {"http://HOST:4502/CTX", "/CTX", "/"}, + {"http://HOST:4502/CTX", "/CTX/", "/"}, + {"http://HOST:4502/CTX", "/CTX/page.html", "/page.html"}, + {"http://HOST:4502/CTX", "/page.html", "/page.html"}, + {"http://HOST:4502/CTX", "/my/page.html", "/my/page.html"}, + {"http://HOST:4502/CTX", "/my/", "/my/"}, + {"http://HOST:4502/CTX", "/my", "/my"}, + {"http://HOST:4502/CTX", "/", "/"}, + {"http://HOST:4502/CTX", "CTX", "/"}, + {"http://HOST:4502/CTX", "CTX/", "/"}, + {"http://HOST:4502/CTX", "CTX/page.html", "/page.html"}, + {"http://HOST:4502/CTX", "page.html", "/page.html"}, + {"http://HOST:4502/CTX", "my/page.html", "/my/page.html"}, + {"http://HOST:4502/CTX", "my/", "/my/"}, + {"http://HOST:4502/CTX", "my", "/my"}, + {"http://HOST:4502/CTX", "", "/"}, + + {"http://HOST:4502/CTX/", "http://HOST:4502/CTX/page.html", "/page.html"}, + {"http://HOST:4502/CTX/", "http://HOST:4502/CTX/my/page.html", "/my/page.html"}, + {"http://HOST:4502/CTX/", "http://HOST:4502/CTX/my/", "/my/"}, + {"http://HOST:4502/CTX/", "http://HOST:4502/CTX/my", "/my"}, + {"http://HOST:4502/CTX/", "http://HOST:4502/CTX/", "/"}, + {"http://HOST:4502/CTX/", "http://HOST:4502/CTX", "/"}, + + {"http://HOST:4502/CTX/", "/CTX", "/"}, + {"http://HOST:4502/CTX/", "/CTX/", "/"}, + {"http://HOST:4502/CTX/", "/CTX/page.html", "/page.html"}, + {"http://HOST:4502/CTX/", "/page.html", "/page.html"}, + {"http://HOST:4502/CTX/", "/my/page.html", "/my/page.html"}, + {"http://HOST:4502/CTX/", "/my/", "/my/"}, + {"http://HOST:4502/CTX/", "/my", "/my"}, + {"http://HOST:4502/CTX/", "/", "/"}, + {"http://HOST:4502/CTX/", "CTX", "/"}, + {"http://HOST:4502/CTX/", "CTX/", "/"}, + {"http://HOST:4502/CTX/", "CTX/page.html", "/page.html"}, + {"http://HOST:4502/CTX/", "page.html", "/page.html"}, + {"http://HOST:4502/CTX/", "my/page.html", "/my/page.html"}, + {"http://HOST:4502/CTX/", "my/", "/my/"}, + {"http://HOST:4502/CTX/", "my", "/my"}, + {"http://HOST:4502/CTX/", "", "/"}, + + {"http://HOST:4502/CTX/", "/CTX/?param=value", "/?param=value"}, + {"http://HOST:4502/CTX/", "/CTX/page.html?param=value", "/page.html?param=value"}, + {"http://HOST:4502/CTX/", "/page.html?param=value", "/page.html?param=value"}, + {"http://HOST:4502/CTX/", "/my/page.html?param=value", "/my/page.html?param=value"}, + {"http://HOST:4502/CTX/", "/my/?param=value", "/my/?param=value"}, + {"http://HOST:4502/CTX/", "/my?param=value", "/my?param=value"}, + {"http://HOST:4502/CTX/", "CTX/?param=value", "/?param=value"}, + {"http://HOST:4502/CTX/", "CTX/page.html?param=value", "/page.html?param=value"}, + {"http://HOST:4502/CTX/", "page.html?param=value", "/page.html?param=value"}, + {"http://HOST:4502/CTX/", "my/page.html?param=value", "/my/page.html?param=value"}, + {"http://HOST:4502/CTX/", "my/?param=value", "/my/?param=value"}, + {"http://HOST:4502/CTX/", "my?param=value", "/my?param=value"}, + + {"http://HOST:4502/CTX/", "http://www.google.com", "http://www.google.com"}, + }); + } + + @Parameterized.Parameter(value = 0) + public String serverUrl; + + @Parameterized.Parameter(value = 1) + public String inputUri; + + @Parameterized.Parameter(value = 2) + public String expectedPath; + + @Test + public void testGetPath() throws ClientException, URISyntaxException { + SlingClient c = new SlingClient(URI.create(serverUrl), "USER", "PWD"); + assertEquals(URI.create(expectedPath), c.getPath(inputUri)); + } +} + + + + + + + + + + + Added: release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetServerUrlTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetServerUrlTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetServerUrlTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,56 @@ +/* + * 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.ClientException; +import org.apache.sling.testing.clients.SlingClient; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.net.URI; +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +@RunWith(Parameterized.class) +public class AbstractSlingClientGetServerUrlTest { + + @Parameterized.Parameters(name = "{index} - serverUrl: {0}, path: {1}, expected: {2}") + public static Collection<String[]> data() { + return Arrays.asList(new String[][] { + {"http://HOST", "http://HOST/"}, + {"http://HOST:4502", "http://HOST:4502/"}, + {"http://HOST:4502/", "http://HOST:4502/"}, + {"http://HOST:4502/CTX", "http://HOST:4502/CTX/"}, + {"http://HOST:4502/CTX/", "http://HOST:4502/CTX/"}, + }); + } + + @Parameterized.Parameter(value = 0) + public String serverUrl; + + @Parameterized.Parameter(value = 1) + public String expectedUrl; + + @Test + public void testGetUrl() throws ClientException { + SlingClient c = new SlingClient(URI.create(serverUrl), "USER", "PWD"); + assertEquals("", URI.create(expectedUrl), c.getUrl()); + } +} Added: release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetUrlTest.java ============================================================================== --- release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetUrlTest.java (added) +++ release/sling/src/test/java/org/apache/sling/testing/AbstractSlingClientGetUrlTest.java Thu Apr 9 13:50:42 2020 @@ -0,0 +1,136 @@ +/* + * 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.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; +import org.apache.sling.testing.clients.ClientException; +import org.apache.sling.testing.clients.SlingClient; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +@RunWith(Parameterized.class) +public class AbstractSlingClientGetUrlTest { + + @Parameterized.Parameters(name = "{index} - serverUrl: {0}, path: {1}, expected: {2}") + public static Collection<String[]> data() { + return Arrays.asList(new String[][] { + // Server URL with no port + {"http://HOST", "/page.html", "http://HOST/page.html"}, + {"http://HOST", "/my/page.html", "http://HOST/my/page.html"}, + {"http://HOST", "/my/", "http://HOST/my/"}, + {"http://HOST", "/my", "http://HOST/my"}, + {"http://HOST", "/", "http://HOST/"}, + + {"http://HOST", "page.html", "http://HOST/page.html"}, + {"http://HOST", "my/page.html", "http://HOST/my/page.html"}, + {"http://HOST", "my/", "http://HOST/my/"}, + {"http://HOST", "my", "http://HOST/my"}, + {"http://HOST", "", "http://HOST/"}, + + // Server URL with with port + {"http://HOST:4502", "/page.html", "http://HOST:4502/page.html"}, + {"http://HOST:4502", "/my/page.html", "http://HOST:4502/my/page.html"}, + {"http://HOST:4502", "/my/", "http://HOST:4502/my/"}, + {"http://HOST:4502", "/my", "http://HOST:4502/my"}, + {"http://HOST:4502", "/", "http://HOST:4502/"}, + + {"http://HOST:4502", "page.html", "http://HOST:4502/page.html"}, + {"http://HOST:4502", "my/page.html", "http://HOST:4502/my/page.html"}, + {"http://HOST:4502", "my/", "http://HOST:4502/my/"}, + {"http://HOST:4502", "my", "http://HOST:4502/my"}, + {"http://HOST:4502", "", "http://HOST:4502/"}, + + // Server URL with with port and trailing slash + {"http://HOST:4502/", "/page.html", "http://HOST:4502/page.html"}, + {"http://HOST:4502/", "/my/page.html", "http://HOST:4502/my/page.html"}, + {"http://HOST:4502/", "/my/", "http://HOST:4502/my/"}, + {"http://HOST:4502/", "/my", "http://HOST:4502/my"}, + {"http://HOST:4502/", "/", "http://HOST:4502/"}, + + {"http://HOST:4502/", "page.html", "http://HOST:4502/page.html"}, + {"http://HOST:4502/", "my/page.html", "http://HOST:4502/my/page.html"}, + {"http://HOST:4502/", "my/", "http://HOST:4502/my/"}, + {"http://HOST:4502/", "my", "http://HOST:4502/my"}, + {"http://HOST:4502/", "", "http://HOST:4502/"}, + + // Server URL with with port and context path (no trailing slash) + {"http://HOST:4502/CTX", "/page.html", "http://HOST:4502/CTX/page.html"}, + {"http://HOST:4502/CTX", "/my/page.html", "http://HOST:4502/CTX/my/page.html"}, + {"http://HOST:4502/CTX", "/my/", "http://HOST:4502/CTX/my/"}, + {"http://HOST:4502/CTX", "/my", "http://HOST:4502/CTX/my"}, + {"http://HOST:4502/CTX", "/", "http://HOST:4502/CTX/"}, + + {"http://HOST:4502/CTX", "page.html", "http://HOST:4502/CTX/page.html"}, + {"http://HOST:4502/CTX", "my/page.html", "http://HOST:4502/CTX/my/page.html"}, + {"http://HOST:4502/CTX", "my/", "http://HOST:4502/CTX/my/"}, + {"http://HOST:4502/CTX", "my", "http://HOST:4502/CTX/my"}, + {"http://HOST:4502/CTX", "", "http://HOST:4502/CTX/"}, + + // Server URL with with port and context path and trailing slash + {"http://HOST:4502/CTX/", "/page.html", "http://HOST:4502/CTX/page.html"}, + {"http://HOST:4502/CTX/", "/my/page.html", "http://HOST:4502/CTX/my/page.html"}, + {"http://HOST:4502/CTX/", "/my/", "http://HOST:4502/CTX/my/"}, + {"http://HOST:4502/CTX/", "/my", "http://HOST:4502/CTX/my"}, + {"http://HOST:4502/CTX/", "/", "http://HOST:4502/CTX/"}, + + {"http://HOST:4502/CTX/", "page.html", "http://HOST:4502/CTX/page.html"}, + {"http://HOST:4502/CTX/", "my/page.html", "http://HOST:4502/CTX/my/page.html"}, + {"http://HOST:4502/CTX/", "my/", "http://HOST:4502/CTX/my/"}, + {"http://HOST:4502/CTX/", "my", "http://HOST:4502/CTX/my"}, + {"http://HOST:4502/CTX/", "", "http://HOST:4502/CTX/"}, + + // External URLs + {"http://HOST:4502/CTX/", "http://www.google.com", "http://www.google.com"}, + {"http://HOST:4502/CTX/", "http://HOST:4502/CTX/my/page.html", "http://HOST:4502/CTX/my/page.html"}, + + // URL encoding of the path + {"http://HOST:4502/CTX/", "!@*()'~ #$%^&{}[]|\\<>?\"`", "http://host:4502/CTX/!@*()'~%20%23$%25%5E&%7B%7D%5B%5D%7C%5C%3C%3E%3F%22%60"}, + }); + } + + + private static final List<NameValuePair> TEST_PARAMETERS = Arrays.<NameValuePair>asList(new BasicNameValuePair("key", "value")); + private static final String STRING_TEST_PARAMETERS = "key=value"; + + @Parameterized.Parameter(value = 0) + public String serverUrl; + + @Parameterized.Parameter(value = 1) + public String inputPath; + + @Parameterized.Parameter(value = 2) + public String expectedUrl; + + @Test + public void testGetUrlWithParam() throws ClientException { + SlingClient c = new SlingClient(URI.create(serverUrl), "USER", "PWD"); + assertEquals("", URI.create(expectedUrl), c.getUrl(inputPath)); + assertEquals(URI.create(expectedUrl), c.getUrl(inputPath, null)); + assertEquals(URI.create(expectedUrl + "?"), c.getUrl(inputPath, new ArrayList<NameValuePair>())); + assertEquals(URI.create(expectedUrl + "?" + STRING_TEST_PARAMETERS), c.getUrl(inputPath, TEST_PARAMETERS)); + } +}
