You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by jo...@apache.org on 2022/06/02 15:00:56 UTC

[sling-org-apache-sling-testing-clients] branch SLING-11364-more-precise-exceptions created (now da17429)

This is an automated email from the ASF dual-hosted git repository.

joerghoh pushed a change to branch SLING-11364-more-precise-exceptions
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-clients.git


      at da17429  SLING-11364 use specialized exceptions

This branch includes the following new commits:

     new da17429  SLING-11364 use specialized exceptions

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[sling-org-apache-sling-testing-clients] 01/01: SLING-11364 use specialized exceptions

Posted by jo...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

joerghoh pushed a commit to branch SLING-11364-more-precise-exceptions
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-testing-clients.git

commit da17429b23e580a5bfcbcb81142bc3d191b367d2
Author: Joerg Hoh <jh...@adobe.com>
AuthorDate: Thu Jun 2 16:58:55 2022 +0200

    SLING-11364 use specialized exceptions
---
 .../sling/testing/clients/AbstractSlingClient.java |  7 +--
 .../sling/testing/clients/ClientException.java     | 15 +++++-
 .../apache/sling/testing/clients/SlingClient.java  |  3 +-
 .../sling/testing/clients/SlingClientConfig.java   |  5 +-
 .../sling/testing/clients/SlingHttpResponse.java   |  9 ++--
 .../testing/clients/email/SlingEmailClient.java    |  6 ++-
 .../exceptions/TestValidationException.java        | 55 ++++++++++++++++++++++
 .../clients/exceptions/TestingIOException.java     | 48 +++++++++++++++++++
 .../testing/clients/indexing/IndexingClient.java   |  3 +-
 .../sling/testing/clients/osgi/BundleInfo.java     |  8 ++--
 .../sling/testing/clients/osgi/BundlesInfo.java    | 18 +++----
 .../testing/clients/osgi/BundlesInstaller.java     |  3 +-
 .../sling/testing/clients/osgi/ComponentInfo.java  |  8 ++--
 .../sling/testing/clients/osgi/ComponentsInfo.java | 14 +++---
 .../testing/clients/osgi/OsgiConsoleClient.java    | 20 ++++----
 .../sling/testing/clients/osgi/ServiceInfo.java    |  6 +--
 .../sling/testing/clients/osgi/ServicesInfo.java   | 12 ++---
 .../apache/sling/testing/clients/package-info.java |  2 +-
 .../sling/testing/clients/query/QueryClient.java   |  6 ++-
 .../sling/testing/clients/util/HttpUtils.java      | 19 ++++----
 .../clients/util/InputStreamBodyWithLength.java    | 10 ++--
 .../sling/testing/clients/util/JsonUtils.java      |  6 ++-
 22 files changed, 206 insertions(+), 77 deletions(-)

diff --git a/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java b/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java
index 59622c8..bc0ce7a 100644
--- a/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java
+++ b/src/main/java/org/apache/sling/testing/clients/AbstractSlingClient.java
@@ -25,6 +25,7 @@ import org.apache.http.client.utils.URIBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.protocol.HttpContext;
+import org.apache.sling.testing.clients.exceptions.TestingIOException;
 import org.apache.sling.testing.clients.util.HttpUtils;
 import org.slf4j.LoggerFactory;
 
@@ -227,7 +228,7 @@ public class AbstractSlingClient implements HttpClient, Closeable {
             Constructor cons = clientClass.getConstructor(CloseableHttpClient.class, SlingClientConfig.class);
             client = (T) cons.newInstance(this.http, this.config);
         } catch (Exception e) {
-            throw new ClientException("Could not initialize client: '" + clientClass.getCanonicalName() + "'.", e);
+            throw new TestingIOException("Could not initialize client: '" + clientClass.getCanonicalName() + "'.", e);
         }
         return client;
     }
@@ -334,7 +335,7 @@ public class AbstractSlingClient implements HttpClient, Closeable {
 
             return response;
         } catch (IOException e) {
-            throw new ClientException("Could not execute http request", e, request, response);
+            throw new TestingIOException("Could not execute http request", e, request, response);
         }
     }
 
@@ -386,7 +387,7 @@ public class AbstractSlingClient implements HttpClient, Closeable {
 
             return response;
         } catch (IOException e) {
-            throw new ClientException("Could not execute http request", e);
+            throw new TestingIOException("Could not execute http request", e);
         }
     }
 
diff --git a/src/main/java/org/apache/sling/testing/clients/ClientException.java b/src/main/java/org/apache/sling/testing/clients/ClientException.java
index e89dbc9..0579acd 100644
--- a/src/main/java/org/apache/sling/testing/clients/ClientException.java
+++ b/src/main/java/org/apache/sling/testing/clients/ClientException.java
@@ -19,7 +19,15 @@ package org.apache.sling.testing.clients;
 import org.apache.http.client.methods.HttpUriRequest;
 
 /**
- * An exception thrown when something went wrong with using the sling testing clients
+ * An exception thrown when something went wrong with using the sling testing clients;
+ * Do not instantiate this class directly, but rather use one of its sub-classes:
+ * <ul>
+ *   <li>TestingIOException for any type of network or IO related error</li>
+ *   <li>TestValidationException for any type of unmet expectation</li>
+ * </ul>
+ * 
+ * Note: This change is done in preparation to make this class abstract.
+ * 
  */
 public class ClientException extends Exception {
 
@@ -28,23 +36,28 @@ public class ClientException extends Exception {
     private HttpUriRequest request;
     private SlingHttpResponse response;
 
+    @Deprecated
     public ClientException(String message) {
         this(message, null);
     }
 
+    @Deprecated
     public ClientException(String message, Throwable throwable) {
         this(message, -1, throwable);
     }
 
+    @Deprecated
     public ClientException(String message, int httpStatusCode) {
         this(message, httpStatusCode, null);
     }
 
+    @Deprecated
     public ClientException(String message, int httpStatusCode, Throwable throwable) {
         super(message, throwable);
         this.httpStatusCode = httpStatusCode;
     }
 
+    @Deprecated
     public ClientException(String message, Throwable throwable, HttpUriRequest request, SlingHttpResponse response) {
         this(message, throwable);
         this.request = request;
diff --git a/src/main/java/org/apache/sling/testing/clients/SlingClient.java b/src/main/java/org/apache/sling/testing/clients/SlingClient.java
index baa3a0c..9156d90 100644
--- a/src/main/java/org/apache/sling/testing/clients/SlingClient.java
+++ b/src/main/java/org/apache/sling/testing/clients/SlingClient.java
@@ -41,6 +41,7 @@ import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.apache.sling.testing.clients.interceptors.DelayRequestInterceptor;
 import org.apache.sling.testing.clients.interceptors.HttpRequestResponseInterceptor;
 import org.apache.sling.testing.clients.interceptors.TestDescriptionInterceptor;
@@ -250,7 +251,7 @@ public class SlingClient extends AbstractSlingClient {
 
         boolean found = poller.callUntilCondition();
         if (!found) {
-            throw new ClientException("path " + path + " does not exist after " + retryCount + " retries");
+            throw new TestValidationException("path " + path + " does not exist after " + retryCount + " retries");
         }
     }
 
diff --git a/src/main/java/org/apache/sling/testing/clients/SlingClientConfig.java b/src/main/java/org/apache/sling/testing/clients/SlingClientConfig.java
index 825dfe8..126b315 100644
--- a/src/main/java/org/apache/sling/testing/clients/SlingClientConfig.java
+++ b/src/main/java/org/apache/sling/testing/clients/SlingClientConfig.java
@@ -30,6 +30,7 @@ import org.apache.http.impl.auth.BasicScheme;
 import org.apache.http.impl.client.BasicAuthCache;
 import org.apache.http.impl.client.BasicCookieStore;
 import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.sling.testing.clients.exceptions.TestingIOException;
 
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -209,12 +210,12 @@ public class SlingClientConfig {
 
         public SlingClientConfig build() throws ClientException {
             if (!this.url.isAbsolute()) {
-                throw new ClientException("Url must be absolute: " + url);
+                throw new TestingIOException("Url must be absolute: " + url);
             }
 
             HttpHost targetHost = URIUtils.extractHost(this.url);
             if (targetHost == null) {
-                throw new ClientException("Failed to extract hostname from url " + url);
+                throw new TestingIOException("Failed to extract hostname from url " + url);
             }
 
             // Create default CredentialsProvider if not set
diff --git a/src/main/java/org/apache/sling/testing/clients/SlingHttpResponse.java b/src/main/java/org/apache/sling/testing/clients/SlingHttpResponse.java
index 9f19f9e..596d4fc 100644
--- a/src/main/java/org/apache/sling/testing/clients/SlingHttpResponse.java
+++ b/src/main/java/org/apache/sling/testing/clients/SlingHttpResponse.java
@@ -31,6 +31,7 @@ import org.apache.http.ProtocolVersion;
 import org.apache.http.StatusLine;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.util.EntityUtils;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 
 public class SlingHttpResponse implements CloseableHttpResponse {
 
@@ -81,7 +82,7 @@ public class SlingHttpResponse implements CloseableHttpResponse {
      */
     public void checkStatus(int expected) throws ClientException {
         if (this.getStatusLine().getStatusCode() != expected) {
-            throw new ClientException(this + " has wrong response status ("
+            throw new TestValidationException(this + " has wrong response status ("
                     + this.getStatusLine().getStatusCode() + "). Expected " + expected);
         }
     }
@@ -101,7 +102,7 @@ public class SlingHttpResponse implements CloseableHttpResponse {
 
         // check for match
         if (!contentType.equals(expected)) {
-            throw new ClientException(this + " has wrong content type (" + contentType + "). Expected " + expected);
+            throw new TestValidationException(this + " has wrong content type (" + contentType + "). Expected " + expected);
         }
     }
 
@@ -127,7 +128,7 @@ public class SlingHttpResponse implements CloseableHttpResponse {
             }
 
             if (!matched) {
-                throw new ClientException("Pattern " + p + " didn't match any line in content. Content is: \n\n" + getContent());
+                throw new TestValidationException("Pattern " + p + " didn't match any line in content. Content is: \n\n" + getContent());
             }
         }
     }
@@ -141,7 +142,7 @@ public class SlingHttpResponse implements CloseableHttpResponse {
     public void checkContentContains(String... expected) throws ClientException {
         for (String s : expected) {
             if (!this.getContent().contains(s)) {
-                throw new ClientException("Content does not contain string " + s + ". Content is: \n\n" + getContent());
+                throw new TestValidationException("Content does not contain string " + s + ". Content is: \n\n" + getContent());
             }
         }
     }
diff --git a/src/main/java/org/apache/sling/testing/clients/email/SlingEmailClient.java b/src/main/java/org/apache/sling/testing/clients/email/SlingEmailClient.java
index a41c72f..10d2641 100644
--- a/src/main/java/org/apache/sling/testing/clients/email/SlingEmailClient.java
+++ b/src/main/java/org/apache/sling/testing/clients/email/SlingEmailClient.java
@@ -34,6 +34,8 @@ import org.apache.sling.testing.clients.ClientException;
 import org.apache.sling.testing.clients.SlingClient;
 import org.apache.sling.testing.clients.SlingClientConfig;
 import org.apache.sling.testing.clients.SlingHttpResponse;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
+import org.apache.sling.testing.clients.exceptions.TestingIOException;
 import org.codehaus.jackson.JsonNode;
 import org.codehaus.jackson.map.ObjectMapper;
 
@@ -74,7 +76,7 @@ public final class SlingEmailClient extends SlingClient {
 			JsonNode configNode = mapper.readTree(mockEmailConfig.getContent());
 			return configNode.get("bindPort").getIntValue();
 		} catch (IOException e) {
-			throw new ClientException("Failed retrieving configuration", e);
+			throw new TestingIOException("Failed retrieving configuration", e);
 		}
 	}
 	
@@ -104,7 +106,7 @@ public final class SlingEmailClient extends SlingClient {
 				emails.add(msg);
 			}
 		} catch (IOException e) {
-			throw new ClientException("Failed retrieving email messages", e);
+			throw new TestValidationException("Failed retrieving email messages", e);
 		}
         
         
diff --git a/src/main/java/org/apache/sling/testing/clients/exceptions/TestValidationException.java b/src/main/java/org/apache/sling/testing/clients/exceptions/TestValidationException.java
new file mode 100644
index 0000000..fddd3af
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/clients/exceptions/TestValidationException.java
@@ -0,0 +1,55 @@
+/*
+ * 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.exceptions;
+
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.SlingHttpResponse;
+
+/**
+ * indicates that an expected status is not given, this can include
+ * <ul>
+ *   <li>HTTP status codes</li>
+ *   <li>Content within the response</li>
+ *   <li>...
+ * </ul>
+ *
+ */
+
+public class TestValidationException extends ClientException {
+
+	public TestValidationException(String message) {
+		super(message);
+	}
+	
+    public TestValidationException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+
+    public TestValidationException(String message, int httpStatusCode) {
+        super(message,httpStatusCode);
+    }
+
+    public TestValidationException(String message, int httpStatusCode, Throwable throwable) {
+    	super(message,httpStatusCode, throwable);
+    }
+
+    public TestValidationException(String message, Throwable throwable, HttpUriRequest request, SlingHttpResponse response) {
+    	super(message,throwable,request,response);
+    }
+	
+}
diff --git a/src/main/java/org/apache/sling/testing/clients/exceptions/TestingIOException.java b/src/main/java/org/apache/sling/testing/clients/exceptions/TestingIOException.java
new file mode 100644
index 0000000..39e83c2
--- /dev/null
+++ b/src/main/java/org/apache/sling/testing/clients/exceptions/TestingIOException.java
@@ -0,0 +1,48 @@
+/*
+ * 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.exceptions;
+
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.SlingHttpResponse;
+
+/**
+ * Indicates any type of network and connection issue
+ *
+ */
+public class TestingIOException extends ClientException {
+
+	public TestingIOException(String message) {
+		super(message);
+	}
+
+    public TestingIOException(String message, Throwable throwable) {
+        super(message, throwable);
+    }
+
+    public TestingIOException(String message, int httpStatusCode) {
+        super(message,httpStatusCode);
+    }
+
+    public TestingIOException(String message, int httpStatusCode, Throwable throwable) {
+    	super(message,httpStatusCode, throwable);
+    }
+
+    public TestingIOException(String message, Throwable throwable, HttpUriRequest request, SlingHttpResponse response) {
+    	super(message,throwable,request,response);
+    }
+}
diff --git a/src/main/java/org/apache/sling/testing/clients/indexing/IndexingClient.java b/src/main/java/org/apache/sling/testing/clients/indexing/IndexingClient.java
index 1af1e4a..9a35ab8 100644
--- a/src/main/java/org/apache/sling/testing/clients/indexing/IndexingClient.java
+++ b/src/main/java/org/apache/sling/testing/clients/indexing/IndexingClient.java
@@ -23,6 +23,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.sling.testing.clients.ClientException;
 import org.apache.sling.testing.clients.SlingClient;
 import org.apache.sling.testing.clients.SlingClientConfig;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.apache.sling.testing.clients.osgi.OsgiConsoleClient;
 import org.apache.sling.testing.clients.query.QueryClient;
 import org.apache.sling.testing.clients.util.poller.Polling;
@@ -202,7 +203,7 @@ public class IndexingClient extends SlingClient {
         if (configs instanceof String[]) {
             return Stream.of((String[]) configs).map(e -> e.split(":")[0]).collect(Collectors.toList());
         } else {
-            throw new ClientException("Cannot retrieve config from AsyncIndexerService, asyncConfigs is not a String[]");
+            throw new TestValidationException("Cannot retrieve config from AsyncIndexerService, asyncConfigs is not a String[]");
         }
     }
 
diff --git a/src/main/java/org/apache/sling/testing/clients/osgi/BundleInfo.java b/src/main/java/org/apache/sling/testing/clients/osgi/BundleInfo.java
index 33cdd22..0d85737 100644
--- a/src/main/java/org/apache/sling/testing/clients/osgi/BundleInfo.java
+++ b/src/main/java/org/apache/sling/testing/clients/osgi/BundleInfo.java
@@ -17,7 +17,7 @@
 
 package org.apache.sling.testing.clients.osgi;
 
-import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.codehaus.jackson.JsonNode;
 
 import java.util.HashMap;
@@ -28,15 +28,15 @@ public class BundleInfo {
 
     private JsonNode bundle;
 
-    public BundleInfo(JsonNode root) throws ClientException {
+    public BundleInfo(JsonNode root) throws TestValidationException {
         if(root.get("id") != null) {
             if(root.get("id") == null) {
-                throw new ClientException("No Bundle Info returned");
+                throw new TestValidationException("No Bundle Info returned");
             }
             bundle = root;
         } else {
             if(root.get("data") == null && root.get("data").size() < 1) {
-                throw new ClientException("No Bundle Info returned");
+                throw new TestValidationException("No Bundle Info returned");
             }
             bundle = root.get("data").get(0);
         }
diff --git a/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInfo.java b/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInfo.java
index b99fbf5..239e0d1 100644
--- a/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInfo.java
+++ b/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInfo.java
@@ -17,7 +17,7 @@
 
 package org.apache.sling.testing.clients.osgi;
 
-import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.codehaus.jackson.JsonNode;
 
 import java.util.Iterator;
@@ -37,13 +37,13 @@ public class BundlesInfo {
      * @param root the root JSON node of the bundles info.
      * @throws ClientException if the json does not contain the proper info
      */
-    public BundlesInfo(JsonNode root) throws ClientException {
+    public BundlesInfo(JsonNode root) throws TestValidationException {
         this.root = root;
         // some simple sanity checks
         if(root.get("s") == null)
-            throw new ClientException("No Status Info returned!");
+            throw new TestValidationException("No Status Info returned!");
         if(root.get("s").size() != 5)
-            throw new ClientException("Wrong number of status numbers listed!");
+            throw new TestValidationException("Wrong number of status numbers listed!");
         status = root.get("s");
     }
 
@@ -51,9 +51,9 @@ public class BundlesInfo {
      * @return the status message of the bundle context
      * @throws ClientException if the request cannot be completed
      */
-    public String getStatusMessage() throws ClientException {
+    public String getStatusMessage() throws TestValidationException {
         if(root.get("status") == null)
-            throw new ClientException("No Status message returned!");
+            throw new TestValidationException("No Status message returned!");
         return root.get("status").getValueAsText();
     }
 
@@ -96,7 +96,7 @@ public class BundlesInfo {
      * @return the BundleInfo
      * @throws ClientException if the info could not be retrieved
      */
-    public BundleInfo forId(String id) throws ClientException {
+    public BundleInfo forId(String id) throws TestValidationException {
         JsonNode bundle = findBy("id", id);
         return (bundle != null) ? new BundleInfo(bundle) : null;
     }
@@ -108,7 +108,7 @@ public class BundlesInfo {
      * @return the info, or {@code null} if the bundle is not found
      * @throws ClientException if the info cannot be retrieved
      */
-    public BundleInfo forName(String name) throws ClientException {
+    public BundleInfo forName(String name) throws TestValidationException {
         JsonNode bundle = findBy("name", name);
         return (bundle != null) ? new BundleInfo(bundle) : null;
     }
@@ -120,7 +120,7 @@ public class BundlesInfo {
      * @return the info, or {@code null} if the bundle is not found
      * @throws ClientException if the info cannot be retrieved
      */
-    public BundleInfo forSymbolicName(String name) throws ClientException {
+    public BundleInfo forSymbolicName(String name) throws TestValidationException {
         JsonNode bundle = findBy("symbolicName", name);
         return (bundle != null) ? new BundleInfo(bundle) : null;
     }
diff --git a/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java b/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java
index bf342a6..d67e5e3 100644
--- a/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java
+++ b/src/main/java/org/apache/sling/testing/clients/osgi/BundlesInstaller.java
@@ -17,6 +17,7 @@
 package org.apache.sling.testing.clients.osgi;
 
 import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.apache.sling.testing.clients.util.poller.Polling;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,7 +60,7 @@ public class BundlesInstaller {
             return false;
         } catch (IOException e) {
             log.debug("Failed to retrieve bundle symbolic name from file. ", e);
-            throw new ClientException("Failed to retrieve bundle symbolic name from file. ", e);
+            throw new TestValidationException("Failed to retrieve bundle symbolic name from file. ", e);
         }
     }
 
diff --git a/src/main/java/org/apache/sling/testing/clients/osgi/ComponentInfo.java b/src/main/java/org/apache/sling/testing/clients/osgi/ComponentInfo.java
index 32ed94c..4e7a3af 100644
--- a/src/main/java/org/apache/sling/testing/clients/osgi/ComponentInfo.java
+++ b/src/main/java/org/apache/sling/testing/clients/osgi/ComponentInfo.java
@@ -17,22 +17,22 @@
 
 package org.apache.sling.testing.clients.osgi;
 
-import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.codehaus.jackson.JsonNode;
 
 public class ComponentInfo {
 
     private JsonNode component;
 
-    public ComponentInfo(JsonNode root) throws ClientException {
+    public ComponentInfo(JsonNode root) throws TestValidationException {
         if(root.get("id") != null) {
             if(root.get("id") == null) {
-                throw new ClientException("No Component Info returned");
+                throw new TestValidationException("No Component Info returned");
             }
             component = root;
         } else {
             if(root.get("data") == null && root.get("data").size() < 1) {
-                throw new ClientException("No Component Info returned");
+                throw new TestValidationException("No Component Info returned");
             }
             component = root.get("data").get(0);
         }
diff --git a/src/main/java/org/apache/sling/testing/clients/osgi/ComponentsInfo.java b/src/main/java/org/apache/sling/testing/clients/osgi/ComponentsInfo.java
index 49b7b14..91d0751 100644
--- a/src/main/java/org/apache/sling/testing/clients/osgi/ComponentsInfo.java
+++ b/src/main/java/org/apache/sling/testing/clients/osgi/ComponentsInfo.java
@@ -17,7 +17,7 @@
 
 package org.apache.sling.testing.clients.osgi;
 
-import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.codehaus.jackson.JsonNode;
 
 import java.util.Iterator;
@@ -35,7 +35,7 @@ public class ComponentsInfo {
      * @param rootNode the root JSON node of the components info.
      * @throws ClientException if the info cannot be retrieved
      */
-    public ComponentsInfo(JsonNode rootNode) throws ClientException {
+    public ComponentsInfo(JsonNode rootNode) {
         this.root = rootNode;
     }
 
@@ -43,9 +43,9 @@ public class ComponentsInfo {
      * @return the number of installed components
      * @throws ClientException if the info cannot be retrieved
      */
-    public int getNumberOfInstalledComponents() throws ClientException {
+    public int getNumberOfInstalledComponents() throws TestValidationException {
         if(root.get("status") == null)
-            throw new ClientException("Number of installed Components not defined!");
+            throw new TestValidationException("Number of installed Components not defined!");
         return Integer.parseInt(root.get("status").getValueAsText());
     }
 
@@ -54,7 +54,7 @@ public class ComponentsInfo {
      * @return the ComponentInfo for a component with the identifier {@code id}
      * @throws ClientException if the info cannot be retrieved
      */
-    public ComponentInfo forId(String id) throws ClientException {
+    public ComponentInfo forId(String id) throws TestValidationException {
         JsonNode component = findBy("id", id);
         return (component != null) ? new ComponentInfo(component) : null;
     }
@@ -64,7 +64,7 @@ public class ComponentsInfo {
      * @return the ComponentInfo for a component with the name {@code name}
      * @throws ClientException if the info cannot be retrieved
      */
-    public ComponentInfo forName(String name) throws ClientException {
+    public ComponentInfo forName(String name) throws TestValidationException {
         JsonNode component = findBy("name", name);
         return (component != null) ? new ComponentInfo(component) : null;
     }
@@ -74,7 +74,7 @@ public class ComponentsInfo {
      * @return the ComponentInfo for a component with the pid {@code pid}
      * @throws ClientException if the info cannot be retrieved
      */
-    public ComponentInfo forPid(String pid) throws ClientException {
+    public ComponentInfo forPid(String pid) throws TestValidationException {
         JsonNode component = findBy("pid", pid);
         return (component != null) ? new ComponentInfo(component) : null;
     }
diff --git a/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java b/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java
index 842015b..f60d1d6 100644
--- a/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java
+++ b/src/main/java/org/apache/sling/testing/clients/osgi/OsgiConsoleClient.java
@@ -41,6 +41,8 @@ import org.apache.sling.testing.clients.ClientException;
 import org.apache.sling.testing.clients.SlingClient;
 import org.apache.sling.testing.clients.SlingClientConfig;
 import org.apache.sling.testing.clients.SlingHttpResponse;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
+import org.apache.sling.testing.clients.exceptions.TestingIOException;
 import org.apache.sling.testing.clients.util.FormEntityBuilder;
 import org.apache.sling.testing.clients.util.HttpUtils;
 import org.apache.sling.testing.clients.util.JsonUtils;
@@ -393,7 +395,7 @@ public class OsgiConsoleClient extends SlingClient {
         try {
             poller.poll(500L * waitCount, 500);
         } catch (TimeoutException e) {
-            throw new ClientException("Cannot retrieve configuration.", e);
+            throw new TestValidationException("Cannot retrieve configuration.", e);
         }
         return poller.getConfig();
     }
@@ -623,7 +625,7 @@ public class OsgiConsoleClient extends SlingClient {
         try {
             return this.checkBundleInstalled(OsgiConsoleClient.getBundleSymbolicName(f), waitTime, retries);
         } catch (IOException e) {
-            throw new ClientException("Cannot get bundle symbolic name", e);
+            throw new TestingIOException("Cannot get bundle symbolic name", e);
         }
     }
 
@@ -645,7 +647,7 @@ public class OsgiConsoleClient extends SlingClient {
         try {
             waitBundleInstalled(getBundleSymbolicName(f), timeout, delay);
         } catch (IOException e) {
-            throw new ClientException("Cannot get bundle symbolic name", e);
+            throw new TestingIOException("Cannot get bundle symbolic name", e);
         }
     }
 
@@ -721,7 +723,7 @@ public class OsgiConsoleClient extends SlingClient {
         final JsonNode idNode = bundle.get(JSON_KEY_ID);
 
         if (idNode == null) {
-            throw new ClientException("Cannot get id from bundle json");
+            throw new TestValidationException("Cannot get id from bundle json");
         }
 
         return idNode.getLongValue();
@@ -738,7 +740,7 @@ public class OsgiConsoleClient extends SlingClient {
         final JsonNode versionNode = bundle.get(JSON_KEY_VERSION);
 
         if (versionNode == null) {
-            throw new ClientException("Cannot get version from bundle json");
+            throw new TestValidationException("Cannot get version from bundle json");
         }
 
         return versionNode.getTextValue();
@@ -755,7 +757,7 @@ public class OsgiConsoleClient extends SlingClient {
         final JsonNode stateNode = bundle.get(JSON_KEY_STATE);
 
         if (stateNode == null) {
-            throw new ClientException("Cannot get state from bundle json");
+            throw new TestValidationException("Cannot get state from bundle json");
         }
 
         return stateNode.getTextValue();
@@ -868,17 +870,17 @@ public class OsgiConsoleClient extends SlingClient {
         final JsonNode root = JsonUtils.getJsonNodeFromString(content);
 
         if (root.get(JSON_KEY_DATA) == null) {
-            throw new ClientException(path + " does not provide '" + JSON_KEY_DATA + "' element, JSON content=" + content);
+            throw new TestValidationException(path + " does not provide '" + JSON_KEY_DATA + "' element, JSON content=" + content);
         }
 
         Iterator<JsonNode> data = root.get(JSON_KEY_DATA).getElements();
         if (!data.hasNext()) {
-            throw new ClientException(path + "." + JSON_KEY_DATA + " is empty, JSON content=" + content);
+            throw new TestValidationException(path + "." + JSON_KEY_DATA + " is empty, JSON content=" + content);
         }
 
         final JsonNode bundle = data.next();
         if (bundle.get(JSON_KEY_STATE) == null) {
-            throw new ClientException(path + ".data[0].state missing, JSON content=" + content);
+            throw new TestValidationException(path + ".data[0].state missing, JSON content=" + content);
         }
 
         return bundle;
diff --git a/src/main/java/org/apache/sling/testing/clients/osgi/ServiceInfo.java b/src/main/java/org/apache/sling/testing/clients/osgi/ServiceInfo.java
index 2d703d8..3515e7f 100644
--- a/src/main/java/org/apache/sling/testing/clients/osgi/ServiceInfo.java
+++ b/src/main/java/org/apache/sling/testing/clients/osgi/ServiceInfo.java
@@ -19,19 +19,19 @@ package org.apache.sling.testing.clients.osgi;
 
 import java.util.List;
 
-import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.codehaus.jackson.JsonNode;
 
 public class ServiceInfo {
 
     private JsonNode service;
 
-    public ServiceInfo(JsonNode root) throws ClientException {
+    public ServiceInfo(JsonNode root) throws TestValidationException {
         if(root.get("id") != null) {
             service = root;
         } else {
             if(root.get("data") == null && root.get("data").size() < 1) {
-                throw new ClientException("No service info returned");
+                throw new TestValidationException("No service info returned");
             }
             service = root.get("data").get(0);
         }
diff --git a/src/main/java/org/apache/sling/testing/clients/osgi/ServicesInfo.java b/src/main/java/org/apache/sling/testing/clients/osgi/ServicesInfo.java
index 8ec3bbd..88b6fc6 100644
--- a/src/main/java/org/apache/sling/testing/clients/osgi/ServicesInfo.java
+++ b/src/main/java/org/apache/sling/testing/clients/osgi/ServicesInfo.java
@@ -17,7 +17,7 @@
 
 package org.apache.sling.testing.clients.osgi;
 
-import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 import org.codehaus.jackson.JsonNode;
 
 import java.util.Arrays;
@@ -40,13 +40,13 @@ public class ServicesInfo {
      * @param root the root JSON node of the bundles info.
      * @throws ClientException if the json does not contain the proper info
      */
-    public ServicesInfo(JsonNode root) throws ClientException {
+    public ServicesInfo(JsonNode root) throws TestValidationException {
         this.root = root;
         // some simple sanity checks
         if(root.get("status") == null)
-            throw new ClientException("No Status returned!");
+            throw new TestValidationException("No Status returned!");
         if(root.get("serviceCount") == null)
-            throw new ClientException("No serviceCount returned!");
+            throw new TestValidationException("No serviceCount returned!");
     }
 
     /**
@@ -63,7 +63,7 @@ public class ServicesInfo {
      * @return the BundleInfo
      * @throws ClientException if the info could not be retrieved
      */
-    public ServiceInfo forId(String id) throws ClientException {
+    public ServiceInfo forId(String id) throws TestValidationException {
         JsonNode serviceInfo = findBy("id", id);
         return (serviceInfo != null) ? new ServiceInfo(serviceInfo) : null;
     }
@@ -75,7 +75,7 @@ public class ServicesInfo {
      * @return a Collection of {@link ServiceInfo}s of all services with the given type. Might be empty, never {@code null}
      * @throws ClientException if the info cannot be retrieved
      */
-    public Collection<ServiceInfo> forType(String type) throws ClientException {
+    public Collection<ServiceInfo> forType(String type) throws TestValidationException {
         List<ServiceInfo> results = new LinkedList<>();
         List<JsonNode> serviceInfoNodes = findAllContainingValueInArray("types", type);
         for (JsonNode serviceInfoNode : serviceInfoNodes) {
diff --git a/src/main/java/org/apache/sling/testing/clients/package-info.java b/src/main/java/org/apache/sling/testing/clients/package-info.java
index 9e17199..8b3a108 100644
--- a/src/main/java/org/apache/sling/testing/clients/package-info.java
+++ b/src/main/java/org/apache/sling/testing/clients/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("2.3.0")
+@Version("2.4.0")
 package org.apache.sling.testing.clients;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/testing/clients/query/QueryClient.java b/src/main/java/org/apache/sling/testing/clients/query/QueryClient.java
index bfad020..e16768f 100644
--- a/src/main/java/org/apache/sling/testing/clients/query/QueryClient.java
+++ b/src/main/java/org/apache/sling/testing/clients/query/QueryClient.java
@@ -22,6 +22,8 @@ import org.apache.sling.testing.clients.ClientException;
 import org.apache.sling.testing.clients.SlingClient;
 import org.apache.sling.testing.clients.SlingClientConfig;
 import org.apache.sling.testing.clients.SlingHttpResponse;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
+import org.apache.sling.testing.clients.exceptions.TestingIOException;
 import org.apache.sling.testing.clients.osgi.OsgiConsoleClient;
 import org.apache.sling.testing.clients.query.servlet.QueryServlet;
 import org.apache.sling.testing.clients.util.JsonUtils;
@@ -203,9 +205,9 @@ public class QueryClient extends SlingClient {
 
             LOG.info("query servlet installed at {}", getUrl(QueryServlet.SERVLET_PATH));
         } catch (IOException e) {
-            throw new ClientException("Failed to create the query servlet bundle", e);
+            throw new TestingIOException("Failed to create the query servlet bundle", e);
         } catch (TimeoutException e) {
-            throw new ClientException("The query servlet bundle did not successfully start", e);
+            throw new TestValidationException("The query servlet bundle did not successfully start", e);
         }
 
         return this;
diff --git a/src/main/java/org/apache/sling/testing/clients/util/HttpUtils.java b/src/main/java/org/apache/sling/testing/clients/util/HttpUtils.java
index ba17460..9d3ce30 100644
--- a/src/main/java/org/apache/sling/testing/clients/util/HttpUtils.java
+++ b/src/main/java/org/apache/sling/testing/clients/util/HttpUtils.java
@@ -20,7 +20,7 @@ import org.apache.http.Header;
 import org.apache.http.HttpResponse;
 import org.apache.sling.testing.clients.ClientException;
 import org.apache.sling.testing.clients.SlingHttpResponse;
-
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
 
 import java.net.URI;
 
@@ -35,7 +35,7 @@ public class HttpUtils {
      * @param expectedStatus List of acceptable HTTP Statuses
      * @throws ClientException if status is not expected
      */
-    public static void verifyHttpStatus(SlingHttpResponse response, int... expectedStatus) throws ClientException {
+    public static void verifyHttpStatus(SlingHttpResponse response, int... expectedStatus) throws TestValidationException {
         if (!checkStatus(response, expectedStatus)) {
             throwError(response, buildDefaultErrorMessage(response), expectedStatus);
         }
@@ -56,8 +56,7 @@ public class HttpUtils {
         }
     }
 
-    private static boolean checkStatus(HttpResponse response, int... expectedStatus)
-            throws ClientException {
+    private static boolean checkStatus(HttpResponse response, int... expectedStatus) {
 
         // if no HttpResponse was given
         if (response == null) {
@@ -83,7 +82,7 @@ public class HttpUtils {
     }
 
     private static boolean throwError(HttpResponse response, String errorMessage, int... expectedStatus)
-            throws ClientException {
+            throws TestValidationException {
         // build error message
         String errorMsg = "Expected HTTP Status: ";
         for (int expected : expectedStatus) {
@@ -99,7 +98,7 @@ public class HttpUtils {
         }
 
         // throw the exception
-        throw new ClientException(errorMsg, givenStatus);
+        throw new TestValidationException(errorMsg, givenStatus);
     }
 
 
@@ -133,7 +132,7 @@ public class HttpUtils {
      * @return The HTTP Status of the response
      * @throws ClientException never (kept for uniformity)
      */
-    public static int getHttpStatus(HttpResponse response) throws ClientException {
+    public static int getHttpStatus(HttpResponse response) {
         return response.getStatusLine().getStatusCode();
     }
 
@@ -144,8 +143,8 @@ public class HttpUtils {
      * @return the location path
      * @throws ClientException never (kept for uniformity)
      */
-    public static String getLocationHeader(HttpResponse response) throws ClientException {
-        if (response == null) throw new ClientException("Response must not be null!");
+    public static String getLocationHeader(HttpResponse response) throws TestValidationException {
+        if (response == null) throw new TestValidationException("Response must not be null!");
 
         String locationPath = null;
         Header locationHeader = response.getFirstHeader("Location");
@@ -156,7 +155,7 @@ public class HttpUtils {
         }
 
         if (locationPath == null) {
-            throw new ClientException("not able to determine location path");
+            throw new TestValidationException("not able to determine location path");
         }
         return locationPath;
     }
diff --git a/src/main/java/org/apache/sling/testing/clients/util/InputStreamBodyWithLength.java b/src/main/java/org/apache/sling/testing/clients/util/InputStreamBodyWithLength.java
index 36361ef..2865c26 100644
--- a/src/main/java/org/apache/sling/testing/clients/util/InputStreamBodyWithLength.java
+++ b/src/main/java/org/apache/sling/testing/clients/util/InputStreamBodyWithLength.java
@@ -18,7 +18,7 @@ package org.apache.sling.testing.clients.util;
 
 import org.apache.http.entity.ContentType;
 import org.apache.http.entity.mime.content.InputStreamBody;
-import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestingIOException;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -29,7 +29,7 @@ import java.io.InputStream;
 public class InputStreamBodyWithLength extends InputStreamBody {
     private long streamLength;
 
-    public InputStreamBodyWithLength(String resourcePath, String contentType, String fileName) throws ClientException {
+    public InputStreamBodyWithLength(String resourcePath, String contentType, String fileName) throws TestingIOException {
         super(ResourceUtil.getResourceAsStream(resourcePath), ContentType.create(contentType), fileName);
         this.streamLength = getResourceStreamLength(resourcePath);
     }
@@ -47,7 +47,7 @@ public class InputStreamBodyWithLength extends InputStreamBody {
      * @param resourcePath path to the file
      * @return the size of the resource
      */
-    private static long getResourceStreamLength(String resourcePath) throws ClientException {
+    private static long getResourceStreamLength(String resourcePath) throws TestingIOException {
         int streamLength = 0;
         InputStream stream = ResourceUtil.getResourceAsStream(resourcePath);
         try {
@@ -56,12 +56,12 @@ public class InputStreamBodyWithLength extends InputStreamBody {
                 stream.skip(avail);
             }
         } catch (IOException e) {
-            throw new ClientException("Could not read " + resourcePath + "!", e);
+            throw new TestingIOException("Could not read " + resourcePath + "!", e);
         } finally {
             try {
                 stream.close();
             } catch (IOException e) {
-                throw new ClientException("Could not close Inputstream for " + resourcePath + "!", e);
+                throw new TestingIOException("Could not close Inputstream for " + resourcePath + "!", e);
             }
         }
         return streamLength;
diff --git a/src/main/java/org/apache/sling/testing/clients/util/JsonUtils.java b/src/main/java/org/apache/sling/testing/clients/util/JsonUtils.java
index e64ac8d..8d4b1d5 100644
--- a/src/main/java/org/apache/sling/testing/clients/util/JsonUtils.java
+++ b/src/main/java/org/apache/sling/testing/clients/util/JsonUtils.java
@@ -17,6 +17,8 @@
 package org.apache.sling.testing.clients.util;
 
 import org.apache.sling.testing.clients.ClientException;
+import org.apache.sling.testing.clients.exceptions.TestValidationException;
+import org.apache.sling.testing.clients.exceptions.TestingIOException;
 import org.codehaus.jackson.JsonNode;
 import org.codehaus.jackson.JsonProcessingException;
 import org.codehaus.jackson.map.ObjectMapper;
@@ -36,9 +38,9 @@ public class JsonUtils {
             ObjectMapper mapper = new ObjectMapper();
             return mapper.readTree(jsonString);
         } catch (JsonProcessingException e) {
-            throw new ClientException("Could not read json file.", e);
+            throw new TestValidationException("Could not read json file.", e);
         } catch (IOException e) {
-            throw new ClientException("Could not read json node.", e);
+            throw new TestingIOException("Could not read json node.", e);
         }
     }
 }
\ No newline at end of file