diff options
author | Jon Bratseth <bratseth@oath.com> | 2018-07-05 09:53:09 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-05 09:53:09 +0200 |
commit | 2ca4a89b20a5e629b21ac5970b1963b784096e7f (patch) | |
tree | e4bf178a7461b9fadff5f993c1cdca853af2cfc3 /container-search | |
parent | d701496a9175df1c1c74de24458735395112f20b (diff) | |
parent | 118c4706121fae7ae315081e08727ebdea431b5d (diff) |
Merge pull request #6271 from vespa-engine/henrhoi/json-query-api
Henrhoi/json query api
Diffstat (limited to 'container-search')
4 files changed, 560 insertions, 20 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/Query.java b/container-search/src/main/java/com/yahoo/search/Query.java index ab6976e29d9..dd3cc853742 100644 --- a/container-search/src/main/java/com/yahoo/search/Query.java +++ b/container-search/src/main/java/com/yahoo/search/Query.java @@ -46,7 +46,6 @@ import com.yahoo.search.yql.VespaSerializer; import com.yahoo.search.yql.YqlParser; import com.yahoo.yolean.Exceptions; import edu.umd.cs.findbugs.annotations.Nullable; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -270,6 +269,7 @@ public class Query extends com.yahoo.processing.Request implements Cloneable { this(""); } + /** * Construct a query from a string formatted in the http style, e.g <code>?query=test&offset=10&hits=13</code> * The query must be uri encoded. @@ -278,6 +278,16 @@ public class Query extends com.yahoo.processing.Request implements Cloneable { this(query, null); } + + /** + * Creates a query from a request + * + * @param request the HTTP request from which this is created + */ + public Query(HttpRequest request) { + this(request, null); + } + /** * Construct a query from a string formatted in the http style, e.g <code>?query=test&offset=10&hits=13</code> * The query must be uri encoded. @@ -293,20 +303,24 @@ public class Query extends com.yahoo.processing.Request implements Cloneable { * @param queryProfile the query profile to use for this query, or null if none. */ public Query(HttpRequest request, CompiledQueryProfile queryProfile) { - super(new QueryPropertyAliases(propertyAliases)); - this.httpRequest = request; - init(request.propertyMap(), queryProfile); + this(request, request.propertyMap(), queryProfile); } /** * Creates a query from a request * - * @param request the HTTP request from which this is created + * @param request the HTTP request from which this is created. + * @param requestMap the property map of the query. + * @param queryProfile the query profile to use for this query, or null if none. */ - public Query(HttpRequest request) { - this(request, null); + public Query(HttpRequest request, Map<String, String> requestMap, CompiledQueryProfile queryProfile) { + super(new QueryPropertyAliases(propertyAliases)); + this.httpRequest = request; + init(requestMap, queryProfile); } + + private void init(Map<String, String> requestMap, CompiledQueryProfile queryProfile) { startTime = System.currentTimeMillis(); if (queryProfile != null) { diff --git a/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java b/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java index e9e4e34727c..7406d492bc8 100644 --- a/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java +++ b/container-search/src/main/java/com/yahoo/search/handler/SearchHandler.java @@ -20,8 +20,8 @@ import com.yahoo.container.jdisc.LoggingRequestHandler; import com.yahoo.container.jdisc.VespaHeaders; import com.yahoo.container.logging.AccessLog; import com.yahoo.container.protect.FreezeDetector; +import com.yahoo.io.IOUtils; import com.yahoo.jdisc.Metric; -import com.yahoo.jdisc.Response; import com.yahoo.language.Linguistics; import com.yahoo.log.LogLevel; import com.yahoo.net.HostName; @@ -33,6 +33,9 @@ import com.yahoo.prelude.query.parser.ParseException; import com.yahoo.prelude.query.parser.SpecialTokenRegistry; import com.yahoo.processing.rendering.Renderer; import com.yahoo.processing.request.CompoundName; +import com.yahoo.slime.Inspector; +import com.yahoo.slime.ObjectTraverser; +import com.yahoo.vespa.config.SlimeUtils; import com.yahoo.yolean.Exceptions; import com.yahoo.search.Query; import com.yahoo.search.Result; @@ -55,9 +58,10 @@ import com.yahoo.statistics.Statistics; import com.yahoo.statistics.Value; import com.yahoo.vespa.configdefinition.SpecialtokensConfig; import edu.umd.cs.findbugs.annotations.NonNull; - -import java.util.ArrayList; -import java.util.Iterator; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; @@ -82,6 +86,8 @@ public class SearchHandler extends LoggingRequestHandler { /** Event name for number of connections to the search subsystem */ private static final String SEARCH_CONNECTIONS = "search_connections"; + private static final String JSON_CONTENT_TYPE = "application/json"; + private static Logger log = Logger.getLogger(SearchHandler.class.getName()); private Value searchConnections; @@ -275,14 +281,14 @@ public class SearchHandler extends LoggingRequestHandler { return errorResponse(request, ErrorMessage.createInternalServerError(Exceptions.toMessageString(e))); } - private HttpSearchResponse handleBody(HttpRequest request) { + + private HttpSearchResponse handleBody(HttpRequest request){ // Find query profile String queryProfileName = request.getProperty("queryProfile"); CompiledQueryProfile queryProfile = queryProfileRegistry.findQueryProfile(queryProfileName); boolean benchmarkOutput = VespaHeaders.benchmarkOutput(request); - // Create query - Query query = new Query(request, queryProfile); + Query query = queryFromRequest(request, queryProfile); boolean benchmarkCoverage = VespaHeaders.benchmarkCoverage(benchmarkOutput, request.getJDiscRequest().headers()); @@ -552,4 +558,62 @@ public class SearchHandler extends LoggingRequestHandler { return searchChainRegistry; } + + private Query queryFromRequest(HttpRequest request, CompiledQueryProfile queryProfile){ + if (request.getMethod() == com.yahoo.jdisc.http.HttpRequest.Method.POST && request.getHeader(com.yahoo.jdisc.http.HttpHeaders.Names.CONTENT_TYPE).equals(JSON_CONTENT_TYPE)) { + Inspector inspector; + try { + byte[] byteArray = IOUtils.readBytes(request.getData(), 1 << 20); + inspector = SlimeUtils.jsonToSlime(byteArray).get(); + if (inspector.field("error_message").valid()){ + throw new QueryException("Illegal query: "+inspector.field("error_message").asString() + ", at: "+ new String(inspector.field("offending_input").asData(), StandardCharsets.UTF_8)); + } + + } catch (IOException e) { + throw new RuntimeException("Problem with reading from input-stream", e); + } + + // Create request-mapping + Map<String, String> requestMap = new HashMap<>(); + createRequestMapping(inspector, requestMap, ""); + return new Query(request, requestMap, queryProfile); + + + } else { + return new Query(request, queryProfile); + + } + } + + public void createRequestMapping(Inspector inspector, Map<String, String> map, String parent){ + inspector.traverse((ObjectTraverser) (key, value) -> { + String qualifiedKey = parent + key; + switch (value.type()) { + case BOOL: + map.put(qualifiedKey, Boolean.toString(value.asBool())); + break; + case DOUBLE: + map.put(qualifiedKey, Double.toString(value.asDouble())); + break; + case LONG: + map.put(qualifiedKey, Long.toString(value.asLong())); + break; + case STRING: + map.put(qualifiedKey , value.asString()); + break; + case ARRAY: + map.put(qualifiedKey, value.asString()); + break; + case OBJECT: + createRequestMapping(value, map, qualifiedKey+"."); + break; + } + + }); + } + + + } + + diff --git a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java new file mode 100644 index 00000000000..eea58d5444e --- /dev/null +++ b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java @@ -0,0 +1,466 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.handler.test; + +import com.yahoo.container.Container; +import com.yahoo.container.core.config.testutil.HandlersConfigurerTestWrapper; +import com.yahoo.container.jdisc.HttpRequest; + +import com.yahoo.container.jdisc.RequestHandlerTestDriver; +import com.yahoo.container.protect.Error; +import com.yahoo.io.IOUtils; +import com.yahoo.net.HostName; +import com.yahoo.search.handler.SearchHandler; +import com.yahoo.search.searchchain.config.test.SearchChainConfigurerTestCase; +import com.yahoo.slime.Inspector; +import com.yahoo.vespa.config.SlimeUtils; +import org.json.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.HashMap; + +import static com.yahoo.jdisc.http.HttpRequest.Method.GET; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + + +public class JSONSearchHandlerTestCase { + + private static final String testDir = "src/test/java/com/yahoo/search/handler/test/config"; + private static final String myHostnameHeader = "my-hostname-header"; + private static final String selfHostname = HostName.getLocalhost(); + + private static String tempDir = ""; + private static String configId = null; + private static final String uri = "http://localhost?"; + private static final String JSON_CONTENT_TYPE = "application/json"; + + @Rule + public TemporaryFolder tempfolder = new TemporaryFolder(); + + private RequestHandlerTestDriver driver = null; + private HandlersConfigurerTestWrapper configurer = null; + private SearchHandler searchHandler; + + @Before + public void startUp() throws IOException { + File cfgDir = tempfolder.newFolder("SearchHandlerTestCase"); + tempDir = cfgDir.getAbsolutePath(); + configId = "dir:" + tempDir; + + IOUtils.copyDirectory(new File(testDir), cfgDir, 1); // make configs active + generateComponentsConfigForActive(); + + configurer = new HandlersConfigurerTestWrapper(new Container(), configId); + searchHandler = (SearchHandler)configurer.getRequestHandlerRegistry().getComponent(SearchHandler.class.getName()); + driver = new RequestHandlerTestDriver(searchHandler); + } + + @After + public void shutDown() { + if (configurer != null) configurer.shutdown(); + if (driver != null) driver.close(); + } + + private void generateComponentsConfigForActive() throws IOException { + File activeConfig = new File(tempDir); + SearchChainConfigurerTestCase. + createComponentsConfig(new File(activeConfig, "chains.cfg").getPath(), + new File(activeConfig, "handlers.cfg").getPath(), + new File(activeConfig, "components.cfg").getPath()); + } + + private SearchHandler fetchSearchHandler(HandlersConfigurerTestWrapper configurer) { + return (SearchHandler) configurer.getRequestHandlerRegistry().getComponent(SearchHandler.class.getName()); + } + + @Test + public void testBadJSON() throws Exception{ + String json = "Not a valid JSON-string"; + RequestHandlerTestDriver.MockResponseHandler responseHandler = driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json, JSON_CONTENT_TYPE); + String response = responseHandler.readAll(); + assertThat(responseHandler.getStatus(), is(400)); + assertThat(response, containsString("errors")); + assertThat(response, containsString("\"code\":" + Error.ILLEGAL_QUERY.code)); + } + + @Test + public void testFailing() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "test"); + json.put("searchChain", "classLoadingError"); + assertTrue(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE).readAll().contains("NoClassDefFoundError")); + } + + + @Test + public synchronized void testPluginError() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "test"); + json.put("searchChain", "exceptionInPlugin"); + assertTrue(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE).readAll().contains("NullPointerException")); + } + + @Test + public synchronized void testWorkingReconfiguration() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "abc"); + assertJsonResult(json, driver); + + // reconfiguration + IOUtils.copyDirectory(new File(testDir, "handlers2"), new File(tempDir), 1); + generateComponentsConfigForActive(); + configurer.reloadConfig(); + + // ...and check the resulting config + SearchHandler newSearchHandler = fetchSearchHandler(configurer); + assertNotSame("Have a new instance of the search handler", searchHandler, newSearchHandler); + assertNotNull("Have the new search chain", fetchSearchHandler(configurer).getSearchChainRegistry().getChain("hello")); + assertNull("Don't have the new search chain", fetchSearchHandler(configurer).getSearchChainRegistry().getChain("classLoadingError")); + try (RequestHandlerTestDriver newDriver = new RequestHandlerTestDriver(searchHandler)) { + assertJsonResult(json, newDriver); + } + } + + @Test + public void testInvalidYqlQuery() throws Exception { + IOUtils.copyDirectory(new File(testDir, "config_yql"), new File(tempDir), 1); + generateComponentsConfigForActive(); + configurer.reloadConfig(); + + SearchHandler newSearchHandler = fetchSearchHandler(configurer); + assertTrue("Do I have a new instance of the search handler?", searchHandler != newSearchHandler); + try (RequestHandlerTestDriver newDriver = new RequestHandlerTestDriver(newSearchHandler)) { + JSONObject json = new JSONObject(); + json.put("yql", "select * from foo where bar > 1453501295"); + RequestHandlerTestDriver.MockResponseHandler responseHandler = newDriver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE); + responseHandler.readAll(); + assertThat(responseHandler.getStatus(), is(400)); + } + } + + // Query handling takes a different code path when a query profile is active, so we test both paths. + @Test + public void testInvalidQueryParamWithQueryProfile() throws Exception { + try (RequestHandlerTestDriver newDriver = driverWithConfig("config_invalid_param")) { + testInvalidQueryParam(newDriver); + } + } + + private void testInvalidQueryParam(final RequestHandlerTestDriver testDriver) throws Exception{ + JSONObject json = new JSONObject(); + json.put("query", "status_code:0"); + json.put("hits", 20); + json.put("offset", -20); + RequestHandlerTestDriver.MockResponseHandler responseHandler = + testDriver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE); + String response = responseHandler.readAll(); + assertThat(responseHandler.getStatus(), is(400)); + assertThat(response, containsString("offset")); + assertThat(response, containsString("\"code\":" + com.yahoo.container.protect.Error.INVALID_QUERY_PARAMETER.code)); + } + + + + + @Test + public void testNormalResultJsonAliasRendering() throws Exception { + JSONObject json = new JSONObject(); + json.put("format", "json"); + json.put("query", "abc"); + assertJsonResult(json, driver); + } + + + + @Test + public void testNullQuery() throws Exception { + JSONObject json = new JSONObject(); + json.put("format", "xml"); + + assertEquals("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + + "<result total-hit-count=\"0\">\n" + + " <hit relevancy=\"1.0\">\n" + + " <field name=\"relevancy\">1.0</field>\n" + + " <field name=\"uri\">testHit</field>\n" + + " </hit>\n" + + "</result>\n", driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE).readAll()); + } + + + + @Test + public void testWebServiceStatus() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "web_service_status_code"); + RequestHandlerTestDriver.MockResponseHandler responseHandler = + driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE); + String response = responseHandler.readAll(); + assertThat(responseHandler.getStatus(), is(406)); + assertThat(response, containsString("\"code\":" + 406)); + } + + @Test + public void testNormalResultImplicitDefaultRendering() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "abc"); + assertJsonResult(json, driver); + } + + @Test + public void testNormalResultExplicitDefaultRendering() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "abc"); + json.put("format", "default"); + assertJsonResult(json, driver); + } + + @Test + public void testNormalResultXmlAliasRendering() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "abc"); + json.put("format", "xml"); + assertXmlResult(json, driver); + } + + + @Test + public void testNormalResultExplicitDefaultRenderingFullRendererName1() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "abc"); + json.put("format", "DefaultRenderer"); + assertXmlResult(json, driver); + } + + @Test + public void testNormalResultExplicitDefaultRenderingFullRendererName2() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "abc"); + json.put("format", "JsonRenderer"); + assertJsonResult(json, driver); + } + + @Test + public void testResultLegacyTiledFormat() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "abc"); + json.put("format", "tiled"); + assertTiledResult(json, driver); + } + + @Test + public void testResultLegacyPageFormat() throws Exception { + JSONObject json = new JSONObject(); + json.put("query", "abc"); + json.put("format", "page"); + assertPageResult(json, driver); + } + + + private static final String xmlResult = + "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + + "<result total-hit-count=\"0\">\n" + + " <hit relevancy=\"1.0\">\n" + + " <field name=\"relevancy\">1.0</field>\n" + + " <field name=\"uri\">testHit</field>\n" + + " </hit>\n" + + "</result>\n"; + + private void assertXmlResult(JSONObject json, RequestHandlerTestDriver driver) throws Exception { + assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE), xmlResult); + } + + + private static final String jsonResult = "{\"root\":{" + + "\"id\":\"toplevel\",\"relevance\":1.0,\"fields\":{\"totalCount\":0}," + + "\"children\":[" + + "{\"id\":\"testHit\",\"relevance\":1.0,\"fields\":{\"uri\":\"testHit\"}}" + + "]}}"; + + private void assertJsonResult(JSONObject json, RequestHandlerTestDriver driver) throws Exception { + assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE), jsonResult); + + } + + private static final String tiledResult = + "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + + "<result version=\"1.0\">\n" + + "\n" + + " <hit relevance=\"1.0\">\n" + + " <id>testHit</id>\n" + + " <uri>testHit</uri>\n" + + " </hit>\n" + + "\n" + + "</result>\n"; + + private void assertTiledResult(JSONObject json, RequestHandlerTestDriver driver) throws Exception { + assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE), tiledResult); + } + + private static final String pageResult = + "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + + "<page version=\"1.0\">\n" + + "\n" + + " <content>\n" + + " <hit relevance=\"1.0\">\n" + + " <id>testHit</id>\n" + + " <uri>testHit</uri>\n" + + " </hit>\n" + + " </content>\n" + + "\n" + + "</page>\n"; + + private void assertPageResult(JSONObject json, RequestHandlerTestDriver driver) throws Exception { + assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE), pageResult); + } + + private void assertOkResult(RequestHandlerTestDriver.MockResponseHandler response, String expected) { + assertEquals(expected, response.readAll()); + assertEquals(200, response.getStatus()); + assertEquals(selfHostname, response.getResponse().headers().get(myHostnameHeader).get(0)); + } + + + private RequestHandlerTestDriver driverWithConfig(String configDirectory) throws Exception { + IOUtils.copyDirectory(new File(testDir, configDirectory), new File(tempDir), 1); + generateComponentsConfigForActive(); + configurer.reloadConfig(); + + SearchHandler newSearchHandler = fetchSearchHandler(configurer); + assertTrue("Do I have a new instance of the search handler?", searchHandler != newSearchHandler); + return new RequestHandlerTestDriver(newSearchHandler); + } + + + + @Test + public void testRequestMapping() throws Exception { + JSONObject json = new JSONObject(); + json.put("yql", "select * from sources * where sddocname contains \"blog_post\" limit 0 | all(group(date) max(3) order(-count())each(output(count())));"); + json.put("hits", 10.0); + json.put("offset", 5); + json.put("queryProfile", "foo"); + json.put("nocache", false); + json.put("groupingSessionCache", false); + json.put("searchChain", "exceptionInPlugin"); + json.put("timeout", 0); + json.put("select", "_all"); + + + JSONObject model = new JSONObject(); + model.put("defaultIndex", 1); + model.put("encoding", "json"); + model.put("filter", "default"); + model.put("language", "en"); + model.put("queryString", "abc"); + model.put("restrict", "_doc,json,xml"); + model.put("searchPath", "node1"); + model.put("sources", "source1,source2"); + model.put("type", "yql"); + json.put("model", model); + + JSONObject ranking = new JSONObject(); + ranking.put("location", "123789.89123N;128123W"); + ranking.put("features", "none"); + ranking.put("listFeatures", false); + ranking.put("profile", "1"); + ranking.put("properties", "default"); + ranking.put("sorting", "desc"); + ranking.put("freshness", "0.05"); + ranking.put("queryCache", false); + + JSONObject matchPhase = new JSONObject(); + matchPhase.put("maxHits", "100"); + matchPhase.put("attribute", "title"); + matchPhase.put("ascending", true); + + JSONObject diversity = new JSONObject(); + diversity.put("attribute", "title"); + diversity.put("minGroups", 1); + matchPhase.put("diversity", diversity); + ranking.put("matchPhase", matchPhase); + json.put("ranking", ranking); + + JSONObject presentation = new JSONObject(); + presentation.put("bolding", true); + presentation.put("format", "json"); + presentation.put("summary", "none"); + presentation.put("template", "json"); + presentation.put("timing", false); + json.put("presentation", presentation); + + JSONObject collapse = new JSONObject(); + collapse.put("field", "none"); + collapse.put("size", 2); + collapse.put("summary", "default"); + json.put("collapse", collapse); + + JSONObject trace = new JSONObject(); + trace.put("level", 1); + trace.put("timestamps", false); + trace.put("rules", "none"); + json.put("trace", trace); + + JSONObject pos = new JSONObject(); + pos.put("ll", "1263123N;1231.9W"); + pos.put("radius", "71234m"); + pos.put("bb", "1237123W;123218N"); + pos.put("attribute", "default"); + json.put("pos", pos); + + JSONObject streaming = new JSONObject(); + streaming.put("userid", 123); + streaming.put("groupname", "abc"); + streaming.put("selection", "none"); + streaming.put("priority", 10); + streaming.put("maxbucketspervisitor", 5); + json.put("streaming", streaming); + + JSONObject rules = new JSONObject(); + rules.put("off", false); + rules.put("rulebase", "default"); + json.put("rules", rules); + + JSONObject metrics = new JSONObject(); + metrics.put("ignore", "_all"); + json.put("metrics", metrics); + + json.put("recall", "none"); + json.put("user", 123); + json.put("nocachewrite", false); + json.put("hitcountestimate", true); + + + + // Create mapping + Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes("utf-8")).get(); + Map<String, String> map = new HashMap<>(); + searchHandler.createRequestMapping(inspector, map, ""); + + // Create GET-request with same query + String url = uri + "&model.sources=source1%2Csource2&select=_all&model.language=en&presentation.timing=false&pos.attribute=default&pos.radius=71234m&model.searchPath=node1&nocachewrite=false&ranking.matchPhase.maxHits=100&presentation.summary=none" + + "&nocache=false&model.type=yql&collapse.summary=default&ranking.matchPhase.diversity.minGroups=1&ranking.location=123789.89123N%3B128123W&ranking.queryCache=false&offset=5&streaming.groupname=abc&groupingSessionCache=false" + + "&presentation.template=json&trace.rules=none&rules.off=false&ranking.properties=default&searchChain=exceptionInPlugin&pos.ll=1263123N%3B1231.9W&ranking.sorting=desc&ranking.matchPhase.ascending=true&ranking.features=none&hitcountestimate=true" + + "&model.filter=default&metrics.ignore=_all&collapse.field=none&ranking.profile=1&rules.rulebase=default&model.defaultIndex=1&trace.level=1&ranking.listFeatures=false&timeout=0&presentation.format=json" + + "&yql=select+%2A+from+sources+%2A+where+sddocname+contains+%22blog_post%22+limit+0+%7C+all%28group%28date%29+max%283%29+order%28-count%28%29%29each%28output%28count%28%29%29%29%29%3B&recall=none&streaming.maxbucketspervisitor=5" + + "&queryProfile=foo&presentation.bolding=true&model.encoding=json&model.queryString=abc&streaming.selection=none&trace.timestamps=false&collapse.size=2&streaming.priority=10&ranking.matchPhase.diversity.attribute=title" + + "&ranking.matchPhase.attribute=title&hits=10&streaming.userid=123&pos.bb=1237123W%3B123218N&model.restrict=_doc%2Cjson%2Cxml&ranking.freshness=0.05&user=123"; + + + + final HttpRequest request = HttpRequest.createTestRequest(url, GET); + + // Get mapping + Map<String, String> propertyMap = request.propertyMap(); + assertEquals("Should have same mapping for properties", map, propertyMap); + } + + + +} diff --git a/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java b/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java index ce40bd1f06b..6dcb34ec3e9 100644 --- a/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/handler/test/SearchHandlerTestCase.java @@ -3,16 +3,13 @@ package com.yahoo.search.handler.test; import com.yahoo.container.Container; import com.yahoo.container.core.config.testutil.HandlersConfigurerTestWrapper; -import com.yahoo.container.jdisc.AsyncHttpResponse; import com.yahoo.container.jdisc.HttpRequest; - import com.yahoo.container.jdisc.HttpResponse; import com.yahoo.container.jdisc.RequestHandlerTestDriver; import com.yahoo.container.jdisc.ThreadedHttpRequestHandler; import com.yahoo.io.IOUtils; import com.yahoo.jdisc.handler.RequestHandler; import com.yahoo.net.HostName; -import com.yahoo.processing.handler.ResponseStatus; import com.yahoo.search.Query; import com.yahoo.search.Result; import com.yahoo.search.Searcher; @@ -30,12 +27,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.URI; -import java.util.List; -import java.util.Map; import java.util.concurrent.Executors; import static org.hamcrest.CoreMatchers.containsString; @@ -187,6 +181,8 @@ public class SearchHandlerTestCase { } } + + // Query handling takes a different code path when a query profile is active, so we test both paths. @Test public void testInvalidQueryParamWithQueryProfile() throws Exception { |