[ 
https://issues.apache.org/jira/browse/SLING-7509?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16380606#comment-16380606
 ] 

ASF GitHub Bot commented on SLING-7509:
---------------------------------------

volteanu commented on a change in pull request #5: SLING-7509 - Add QueryClient
URL: 
https://github.com/apache/sling-org-apache-sling-testing-clients/pull/5#discussion_r171301936
 
 

 ##########
 File path: 
src/main/java/org/apache/sling/testing/clients/query/QueryClient.java
 ##########
 @@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations 
under
+ * the License.
+ */
+package org.apache.sling.testing.clients.query;
+
+import org.apache.http.NameValuePair;
+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.SlingHttpResponse;
+import org.apache.sling.testing.clients.osgi.OsgiConsoleClient;
+import org.apache.sling.testing.clients.util.JsonUtils;
+import org.apache.sling.testing.clients.util.URLParameterBuilder;
+import org.codehaus.jackson.JsonNode;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.Files;
+import java.util.List;
+
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+import static org.apache.http.HttpStatus.SC_NOT_FOUND;
+import static org.apache.http.HttpStatus.SC_OK;
+import static 
org.apache.sling.testing.clients.util.ResourceUtil.getResourceAsStream;
+
+/**
+ * <p>Sling client for performing oak queries.</p>
+ *
+ * <p>Uses a custom query servlet {@code testQuery.json.jsp} to execute the 
query on the server
+ * and return the results as a json. If the servlet is not yet present, it 
automatically
+ * installs it and creates the corresponding nodes</p>
+ *
+ * <p>Paths created in jcr:<br>
+ * - {@value JSP_PATH}, created by the bundle<br>
+ * - {@value QUERY_NODE}, with {@code resourceType}={@value RESOURCE_TYPE}
+ * </p>
+ *
+ * <p>The servlet is not automatically uninstalled to avoid too much noise on 
the instance.
+ * The caller should take care of it, if needed, by calling {@link 
#uninstallServlet()}</p>
+ */
+public class QueryClient extends SlingClient {
+
+    /**
+     * Query types, as defined in {@code 
org.apache.jackrabbit.oak.query.QueryEngineImpl}
+     */
+    public enum QueryType {
+        SQL2("JCR-SQL2"),
+        SQL("sql"),
+        XPATH("xpath"),
+        JQOM("JCR-JQOM");
+
+        private final String name;
+
+        QueryType(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(QueryClient.class);
+
+    private static final String BUNDLE_BSN = 
"org.apache.sling.testing.clients.query";
+    private static final String BUNDLE_NAME = "Query servlet for testing";
+    private static final String BUNDLE_VERSION = "1.0.0";
+    private static final String BUNDLE_FILE = "testquery.bundle.";
+
+    private static final String JSP_FILE = 
"/org/apache/sling/testing/clients/query/testQuery.json.jsp";
+    private static final String RESOURCE_TYPE = "testQuery";
+    private static final String COMPONENT_PATH = "apps/" + RESOURCE_TYPE;
+    private static final String JSP_PATH = COMPONENT_PATH + "/" + 
RESOURCE_TYPE + ".json.jsp";
+    private static final String QUERY_NODE = "/content/testquery";
+    private static final String QUERY_PATH = QUERY_NODE + ".json";
+
+    /**
+     * Constructor used by adaptTo
+     * @param http underlying HttpClient
+     * @param config config state
+     * @throws ClientException if the client cannot be created
+     */
+    public QueryClient(CloseableHttpClient http, SlingClientConfig config) 
throws ClientException {
+        super(http, config);
+    }
+
+    /**
+     * Convenience constructor
+     * @param url host url
+     * @param user username
+     * @param password password
+     * @throws ClientException if the client cannot be constructed
+     */
+    public QueryClient(URI url, String user, String password) throws 
ClientException {
+        super(url, user, password);
+    }
+
+    /**
+     * Execute a query on the server and return the results as a json
+     *
+     * @param query query to be executed
+     * @param type type of the query
+     * @return the results in json as exported by {@code testQuery.json.jsp}
+     * @throws ClientException if the request failed to execute
+     */
+    public JsonNode doQuery(final String query, final QueryType type) throws 
ClientException {
+        return doQuery(query, type, true);
+    }
+
+    /**
+     * Execute a query on the server and return only the number of rows in the 
result
+     *
+     * @param query query to be executed
+     * @param type type of the query
+     * @return total results returned by the query
+     * @throws ClientException if the request failed to execute
+     */
+    public long doCount(final String query, final QueryType type) throws 
ClientException {
+        return doQuery(query, type, false).get("total").getLongValue();
+    }
+
+    protected JsonNode doQuery(final String query, final QueryType type, final 
boolean showResults)
+            throws ClientException {
+
+        List<NameValuePair> params = URLParameterBuilder.create()
+                .add("query", query)
+                .add("type", type.toString())
+                .add("showresults", Boolean.toString(showResults))
+                .getList();
+
+        try {
+            // try optimistically to execute the query
+            SlingHttpResponse response = this.doGet(QUERY_PATH, params, SC_OK);
+            return JsonUtils.getJsonNodeFromString(response.getContent());
+            // TODO check the json is a query result, not a default 
representation of the node
+        } catch (ClientException e) {
+            if (e.getHttpStatusCode() == SC_NOT_FOUND) {
+                LOG.info("Failed to execute the first search, maybe because 
the servlet was not yet installed");
+                installServlet();
+                // retry the same query
+                SlingHttpResponse response = this.doGet(QUERY_PATH, params, 
SC_OK);
+                return JsonUtils.getJsonNodeFromString(response.getContent());
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    /**
+     * <p>Install the servlet to be able to perform queries.</p>
+     *
+     * <p>By default, methods of this client automatically call this, so there 
is no
+     * need to explicitly call from outside</p>
+     *
+     * @throws ClientException if the installation failed
+     */
+    public void installServlet() throws ClientException {
+        InputStream jspStream = getResourceAsStream(JSP_FILE);
+
+        InputStream bundleStream = TinyBundles.bundle()
+                .set("Bundle-SymbolicName", BUNDLE_BSN)
+                .set("Bundle-Version", BUNDLE_VERSION)
+                .set("Bundle-Name", BUNDLE_NAME)
+                .set("Sling-Bundle-Resources", "/" + COMPONENT_PATH)
+                .add(JSP_PATH, jspStream)
+                .build();
+
+        File bundleFile;
+        try {
+            bundleFile = File.createTempFile(BUNDLE_FILE, null);
+            Files.copy(bundleStream, bundleFile.toPath(), REPLACE_EXISTING);
+        } catch (IOException e) {
+            throw new ClientException("Failed to install the query servlet 
bundle", e);
+        }
+
+        adaptTo(OsgiConsoleClient.class).installBundle(bundleFile, true);
+
+        createNode(QUERY_NODE, "nt:unstructured");
+        setPropertyString(QUERY_NODE, "sling:resourceType", RESOURCE_TYPE);
+
+        LOG.info("query servlet installed at {}", getUrl(QUERY_PATH));
+    }
+
+    /**
+     * Delete all the resources created by {@link #installServlet()}
+     *
+     * @throws ClientException if any of the resources failed to uninstall
+     */
+    public void uninstallServlet() throws ClientException {
 
 Review comment:
   Done

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


> Add QueryClient
> ---------------
>
>                 Key: SLING-7509
>                 URL: https://issues.apache.org/jira/browse/SLING-7509
>             Project: Sling
>          Issue Type: New Feature
>          Components: Apache Sling Testing Clients
>            Reporter: Valentin Olteanu
>            Priority: Major
>
> Currently, there is no way to run queries in sling using the clients. This is 
> needed in several tests to search content and assert the effects of a feature.
>  
> The solution proposed in 
> [https://github.com/apache/sling-org-apache-sling-testing-clients/pull/5] 
>  * installs a custom query servlet
>  * runs the query in any of the supported format
>  * returns results as json



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to