Deprecate types in count and msearch. (#35421)
* Deprecate types in count requests. * Move RestCountAction to the 'search' package. * Deprecate types in multi search requests. * Add tests for types deprecation in the _search endpoint.
This commit is contained in:
parent
4fea6b6f9b
commit
c6a0904e0e
|
@ -90,7 +90,8 @@ public final class CountRequest extends ActionRequest implements IndicesRequest.
|
||||||
/**
|
/**
|
||||||
* The document types to execute the count against. Defaults to be executed against all types.
|
* The document types to execute the count against. Defaults to be executed against all types.
|
||||||
*
|
*
|
||||||
* @deprecated Types are going away, prefer filtering on a type.
|
* @deprecated Types are in the process of being removed. Instead of using a type, prefer to
|
||||||
|
* filter on a field on the document.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public CountRequest types(String... types) {
|
public CountRequest types(String... types) {
|
||||||
|
@ -172,6 +173,11 @@ public final class CountRequest extends ActionRequest implements IndicesRequest.
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Types are in the process of being removed. Instead of using a type, prefer to
|
||||||
|
* filter on a field on the document.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public String[] types() {
|
public String[] types() {
|
||||||
return Arrays.copyOf(this.types, this.types.length);
|
return Arrays.copyOf(this.types, this.types.length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,8 +174,8 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
sourceBuilder.fetchSource(false);
|
sourceBuilder.fetchSource(false);
|
||||||
// end::search-source-filtering-off
|
// end::search-source-filtering-off
|
||||||
// tag::search-source-filtering-includes
|
// tag::search-source-filtering-includes
|
||||||
String[] includeFields = new String[] {"title", "user", "innerObject.*"};
|
String[] includeFields = new String[] {"title", "innerObject.*"};
|
||||||
String[] excludeFields = new String[] {"_type"};
|
String[] excludeFields = new String[] {"user"};
|
||||||
sourceBuilder.fetchSource(includeFields, excludeFields);
|
sourceBuilder.fetchSource(includeFields, excludeFields);
|
||||||
// end::search-source-filtering-includes
|
// end::search-source-filtering-includes
|
||||||
sourceBuilder.fetchSource(true);
|
sourceBuilder.fetchSource(true);
|
||||||
|
@ -247,7 +247,6 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
for (SearchHit hit : searchHits) {
|
for (SearchHit hit : searchHits) {
|
||||||
// tag::search-hits-singleHit-properties
|
// tag::search-hits-singleHit-properties
|
||||||
String index = hit.getIndex();
|
String index = hit.getIndex();
|
||||||
String type = hit.getType();
|
|
||||||
String id = hit.getId();
|
String id = hit.getId();
|
||||||
float score = hit.getScore();
|
float score = hit.getScore();
|
||||||
// end::search-hits-singleHit-properties
|
// end::search-hits-singleHit-properties
|
||||||
|
@ -263,8 +262,8 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
assertEquals(3, totalHits);
|
assertEquals(3, totalHits);
|
||||||
assertNotNull(hits.getHits()[0].getSourceAsString());
|
assertNotNull(hits.getHits()[0].getSourceAsString());
|
||||||
assertNotNull(hits.getHits()[0].getSourceAsMap().get("title"));
|
assertNotNull(hits.getHits()[0].getSourceAsMap().get("title"));
|
||||||
assertNotNull(hits.getHits()[0].getSourceAsMap().get("user"));
|
|
||||||
assertNotNull(hits.getHits()[0].getSourceAsMap().get("innerObject"));
|
assertNotNull(hits.getHits()[0].getSourceAsMap().get("innerObject"));
|
||||||
|
assertNull(hits.getHits()[0].getSourceAsMap().get("user"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1242,18 +1241,6 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
|
|
||||||
assertTrue(latch.await(30L, TimeUnit.SECONDS));
|
assertTrue(latch.await(30L, TimeUnit.SECONDS));
|
||||||
}
|
}
|
||||||
{
|
|
||||||
// tag::multi-search-request-index
|
|
||||||
MultiSearchRequest request = new MultiSearchRequest();
|
|
||||||
request.add(new SearchRequest("posts") // <1>
|
|
||||||
.types("doc")); // <2>
|
|
||||||
// end::multi-search-request-index
|
|
||||||
MultiSearchResponse response = client.msearch(request, RequestOptions.DEFAULT);
|
|
||||||
MultiSearchResponse.Item firstResponse = response.getResponses()[0];
|
|
||||||
assertNull(firstResponse.getFailure());
|
|
||||||
SearchResponse searchResponse = firstResponse.getResponse();
|
|
||||||
assertEquals(3, searchResponse.getHits().getTotalHits());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void indexSearchTestData() throws IOException {
|
private void indexSearchTestData() throws IOException {
|
||||||
|
@ -1304,19 +1291,12 @@ public class SearchDocumentationIT extends ESRestHighLevelClientTestCase {
|
||||||
// end::count-request-basic
|
// end::count-request-basic
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// tag::count-request-indices-types
|
// tag::count-request-args
|
||||||
CountRequest countRequest = new CountRequest("blog"); // <1>
|
CountRequest countRequest = new CountRequest("blog") // <1>
|
||||||
countRequest.types("doc"); // <2>
|
.routing("routing") // <2>
|
||||||
// end::count-request-indices-types
|
.indicesOptions(IndicesOptions.lenientExpandOpen()) // <3>
|
||||||
// tag::count-request-routing
|
.preference("_local"); // <4>
|
||||||
countRequest.routing("routing"); // <1>
|
// end::count-request-args
|
||||||
// end::count-request-routing
|
|
||||||
// tag::count-request-indicesOptions
|
|
||||||
countRequest.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1>
|
|
||||||
// end::count-request-indicesOptions
|
|
||||||
// tag::count-request-preference
|
|
||||||
countRequest.preference("_local"); // <1>
|
|
||||||
// end::count-request-preference
|
|
||||||
assertNotNull(client.count(countRequest, RequestOptions.DEFAULT));
|
assertNotNull(client.count(countRequest, RequestOptions.DEFAULT));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,34 +29,16 @@ include-tagged::{doc-tests-file}[{api}-request-basic]
|
||||||
[[java-rest-high-count-request-optional]]
|
[[java-rest-high-count-request-optional]]
|
||||||
===== Count Request optional arguments
|
===== Count Request optional arguments
|
||||||
|
|
||||||
Let's first look at some of the optional arguments of a +{request}+:
|
A +{request}+ also takes the following optional arguments:
|
||||||
|
|
||||||
["source","java",subs="attributes,callouts,macros"]
|
["source","java",subs="attributes,callouts,macros"]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
include-tagged::{doc-tests-file}[{api}-request-indices-types]
|
include-tagged::{doc-tests-file}[{api}-request-args]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
<1> Restricts the request to an index
|
<1> Restricts the request to an index
|
||||||
<2> Limits the request to a type
|
<2> Set a routing parameter
|
||||||
|
<3> Setting `IndicesOptions` controls how unavailable indices are resolved and how wildcard expressions are expanded
|
||||||
There are a couple of other interesting optional parameters:
|
<4> Use the preference parameter e.g. to execute the search to prefer local shards. The default is to randomize across shards.
|
||||||
|
|
||||||
["source","java",subs="attributes,callouts,macros"]
|
|
||||||
--------------------------------------------------
|
|
||||||
include-tagged::{doc-tests-file}[{api}-request-routing]
|
|
||||||
--------------------------------------------------
|
|
||||||
<1> Set a routing parameter
|
|
||||||
|
|
||||||
["source","java",subs="attributes,callouts,macros"]
|
|
||||||
--------------------------------------------------
|
|
||||||
include-tagged::{doc-tests-file}[{api}-request-indicesOptions]
|
|
||||||
--------------------------------------------------
|
|
||||||
<1> Setting `IndicesOptions` controls how unavailable indices are resolved and how wildcard expressions are expanded
|
|
||||||
|
|
||||||
["source","java",subs="attributes,callouts,macros"]
|
|
||||||
--------------------------------------------------
|
|
||||||
include-tagged::{doc-tests-file}[{api}-request-preference]
|
|
||||||
--------------------------------------------------
|
|
||||||
<1> Use the preference parameter e.g. to execute the search to prefer local shards. The default is to randomize across shards.
|
|
||||||
|
|
||||||
===== Using the SearchSourceBuilder in CountRequest
|
===== Using the SearchSourceBuilder in CountRequest
|
||||||
|
|
||||||
|
|
|
@ -289,8 +289,8 @@ be iterated over:
|
||||||
include-tagged::{doc-tests-file}[{api}-hits-singleHit]
|
include-tagged::{doc-tests-file}[{api}-hits-singleHit]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
||||||
The `SearchHit` provides access to basic information like index, type, docId and
|
The `SearchHit` provides access to basic information like index, document ID
|
||||||
score of each search hit:
|
and score of each search hit:
|
||||||
|
|
||||||
["source","java",subs="attributes,callouts,macros"]
|
["source","java",subs="attributes,callouts,macros"]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
|
@ -14,9 +14,9 @@ PUT /twitter/_doc/1?refresh
|
||||||
"user": "kimchy"
|
"user": "kimchy"
|
||||||
}
|
}
|
||||||
|
|
||||||
GET /twitter/_doc/_count?q=user:kimchy
|
GET /twitter/_count?q=user:kimchy
|
||||||
|
|
||||||
GET /twitter/_doc/_count
|
GET /twitter/_count
|
||||||
{
|
{
|
||||||
"query" : {
|
"query" : {
|
||||||
"term" : { "user" : "kimchy" }
|
"term" : { "user" : "kimchy" }
|
||||||
|
|
|
@ -18,7 +18,6 @@ setup:
|
||||||
- do:
|
- do:
|
||||||
count:
|
count:
|
||||||
index: test
|
index: test
|
||||||
type: test
|
|
||||||
body:
|
body:
|
||||||
query:
|
query:
|
||||||
match:
|
match:
|
||||||
|
@ -29,7 +28,6 @@ setup:
|
||||||
- do:
|
- do:
|
||||||
count:
|
count:
|
||||||
index: test
|
index: test
|
||||||
type: test
|
|
||||||
body:
|
body:
|
||||||
query:
|
query:
|
||||||
match:
|
match:
|
||||||
|
@ -43,7 +41,6 @@ setup:
|
||||||
- do:
|
- do:
|
||||||
count:
|
count:
|
||||||
index: test
|
index: test
|
||||||
type: test
|
|
||||||
body: { }
|
body: { }
|
||||||
|
|
||||||
- match: {count : 1}
|
- match: {count : 1}
|
||||||
|
@ -51,7 +48,6 @@ setup:
|
||||||
- do:
|
- do:
|
||||||
count:
|
count:
|
||||||
index: test
|
index: test
|
||||||
type: test
|
|
||||||
|
|
||||||
- match: {count : 1}
|
- match: {count : 1}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
setup:
|
||||||
|
- do:
|
||||||
|
indices.create:
|
||||||
|
index: test
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: test
|
||||||
|
type: test
|
||||||
|
id: 1
|
||||||
|
body: { foo: bar }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
indices.refresh:
|
||||||
|
index: [test]
|
||||||
|
|
||||||
|
---
|
||||||
|
"count with body":
|
||||||
|
- do:
|
||||||
|
count:
|
||||||
|
index: test
|
||||||
|
type: test
|
||||||
|
body:
|
||||||
|
query:
|
||||||
|
match:
|
||||||
|
foo: bar
|
||||||
|
|
||||||
|
- match: {count : 1}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
count:
|
||||||
|
index: test
|
||||||
|
body:
|
||||||
|
query:
|
||||||
|
match:
|
||||||
|
foo: test
|
||||||
|
|
||||||
|
- match: {count : 0}
|
||||||
|
|
||||||
|
---
|
||||||
|
"count with empty body":
|
||||||
|
# empty body should default to match_all query
|
||||||
|
- do:
|
||||||
|
count:
|
||||||
|
index: test
|
||||||
|
type: test
|
||||||
|
body: { }
|
||||||
|
|
||||||
|
- match: {count : 1}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
count:
|
||||||
|
index: test
|
||||||
|
type: test
|
||||||
|
|
||||||
|
- match: {count : 1}
|
||||||
|
|
||||||
|
---
|
||||||
|
"count body without query element":
|
||||||
|
- do:
|
||||||
|
catch: bad_request
|
||||||
|
count:
|
||||||
|
index: test
|
||||||
|
type: test
|
||||||
|
body:
|
||||||
|
match:
|
||||||
|
foo: bar
|
|
@ -50,7 +50,7 @@ setup:
|
||||||
- index: index_3
|
- index: index_3
|
||||||
- query:
|
- query:
|
||||||
match_all: {}
|
match_all: {}
|
||||||
- type: test
|
- {}
|
||||||
- query:
|
- query:
|
||||||
match_all: {}
|
match_all: {}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ setup:
|
||||||
- index: index_3
|
- index: index_3
|
||||||
- query:
|
- query:
|
||||||
match_all: {}
|
match_all: {}
|
||||||
- type: test
|
- {}
|
||||||
- query:
|
- query:
|
||||||
match_all: {}
|
match_all: {}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
---
|
||||||
|
setup:
|
||||||
|
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: index_1
|
||||||
|
type: test
|
||||||
|
id: 1
|
||||||
|
body: { foo: bar }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: index_1
|
||||||
|
type: test
|
||||||
|
id: 2
|
||||||
|
body: { foo: baz }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: index_1
|
||||||
|
type: test
|
||||||
|
id: 3
|
||||||
|
body: { foo: foo }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
index:
|
||||||
|
index: index_2
|
||||||
|
type: test
|
||||||
|
id: 1
|
||||||
|
body: { foo: foo }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
indices.refresh: {}
|
||||||
|
|
||||||
|
---
|
||||||
|
"Basic multi-search":
|
||||||
|
|
||||||
|
- do:
|
||||||
|
msearch:
|
||||||
|
body:
|
||||||
|
- index: index_*
|
||||||
|
- query:
|
||||||
|
match: {foo: foo}
|
||||||
|
- index: index_2
|
||||||
|
- query:
|
||||||
|
match_all: {}
|
||||||
|
- index: index_1
|
||||||
|
- query:
|
||||||
|
match: {foo: foo}
|
||||||
|
- index: index_3
|
||||||
|
- query:
|
||||||
|
match_all: {}
|
||||||
|
- type: test
|
||||||
|
- query:
|
||||||
|
match_all: {}
|
||||||
|
|
||||||
|
- match: { responses.0.hits.total: 2 }
|
||||||
|
- match: { responses.1.hits.total: 1 }
|
||||||
|
- match: { responses.2.hits.total: 1 }
|
||||||
|
- match: { responses.3.error.root_cause.0.type: index_not_found_exception }
|
||||||
|
- match: { responses.3.error.root_cause.0.reason: "/no.such.index/" }
|
||||||
|
- match: { responses.3.error.root_cause.0.index: index_3 }
|
||||||
|
- match: { responses.4.hits.total: 4 }
|
||||||
|
|
||||||
|
---
|
||||||
|
"Least impact smoke test":
|
||||||
|
# only passing these parameters to make sure they are consumed
|
||||||
|
- do:
|
||||||
|
msearch:
|
||||||
|
max_concurrent_shard_requests: 1
|
||||||
|
max_concurrent_searches: 1
|
||||||
|
body:
|
||||||
|
- index: index_*
|
||||||
|
- query:
|
||||||
|
match: {foo: foo}
|
||||||
|
- index: index_2
|
||||||
|
- query:
|
||||||
|
match_all: {}
|
||||||
|
- index: index_1
|
||||||
|
- query:
|
||||||
|
match: {foo: foo}
|
||||||
|
- index: index_3
|
||||||
|
- query:
|
||||||
|
match_all: {}
|
||||||
|
- type: test
|
||||||
|
- query:
|
||||||
|
match_all: {}
|
||||||
|
|
||||||
|
- match: { responses.0.hits.total: 2 }
|
||||||
|
- match: { responses.1.hits.total: 1 }
|
||||||
|
- match: { responses.2.hits.total: 1 }
|
||||||
|
- match: { responses.3.error.root_cause.0.type: index_not_found_exception }
|
||||||
|
- match: { responses.3.error.root_cause.0.reason: "/no.such.index/" }
|
||||||
|
- match: { responses.3.error.root_cause.0.index: index_3 }
|
||||||
|
- match: { responses.4.hits.total: 4 }
|
|
@ -310,6 +310,7 @@ import org.elasticsearch.rest.action.ingest.RestGetPipelineAction;
|
||||||
import org.elasticsearch.rest.action.ingest.RestPutPipelineAction;
|
import org.elasticsearch.rest.action.ingest.RestPutPipelineAction;
|
||||||
import org.elasticsearch.rest.action.ingest.RestSimulatePipelineAction;
|
import org.elasticsearch.rest.action.ingest.RestSimulatePipelineAction;
|
||||||
import org.elasticsearch.rest.action.search.RestClearScrollAction;
|
import org.elasticsearch.rest.action.search.RestClearScrollAction;
|
||||||
|
import org.elasticsearch.rest.action.search.RestCountAction;
|
||||||
import org.elasticsearch.rest.action.search.RestExplainAction;
|
import org.elasticsearch.rest.action.search.RestExplainAction;
|
||||||
import org.elasticsearch.rest.action.search.RestMultiSearchAction;
|
import org.elasticsearch.rest.action.search.RestMultiSearchAction;
|
||||||
import org.elasticsearch.rest.action.search.RestSearchAction;
|
import org.elasticsearch.rest.action.search.RestSearchAction;
|
||||||
|
@ -595,7 +596,7 @@ public class ActionModule extends AbstractModule {
|
||||||
registerHandler.accept(new RestGetSourceAction(settings, restController));
|
registerHandler.accept(new RestGetSourceAction(settings, restController));
|
||||||
registerHandler.accept(new RestMultiGetAction(settings, restController));
|
registerHandler.accept(new RestMultiGetAction(settings, restController));
|
||||||
registerHandler.accept(new RestDeleteAction(settings, restController));
|
registerHandler.accept(new RestDeleteAction(settings, restController));
|
||||||
registerHandler.accept(new org.elasticsearch.rest.action.document.RestCountAction(settings, restController));
|
registerHandler.accept(new RestCountAction(settings, restController));
|
||||||
registerHandler.accept(new RestTermVectorsAction(settings, restController));
|
registerHandler.accept(new RestTermVectorsAction(settings, restController));
|
||||||
registerHandler.accept(new RestMultiTermVectorsAction(settings, restController));
|
registerHandler.accept(new RestMultiTermVectorsAction(settings, restController));
|
||||||
registerHandler.accept(new RestBulkAction(settings, restController));
|
registerHandler.accept(new RestBulkAction(settings, restController));
|
||||||
|
|
|
@ -217,7 +217,11 @@ public final class SearchRequest extends ActionRequest implements IndicesRequest
|
||||||
/**
|
/**
|
||||||
* The document types to execute the search against. Defaults to be executed against
|
* The document types to execute the search against. Defaults to be executed against
|
||||||
* all types.
|
* all types.
|
||||||
|
*
|
||||||
|
* @deprecated Types are in the process of being removed. Instead of using a type, prefer to
|
||||||
|
* filter on a field on the document.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String[] types() {
|
public String[] types() {
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
@ -225,7 +229,9 @@ public final class SearchRequest extends ActionRequest implements IndicesRequest
|
||||||
/**
|
/**
|
||||||
* The document types to execute the search against. Defaults to be executed against
|
* The document types to execute the search against. Defaults to be executed against
|
||||||
* all types.
|
* all types.
|
||||||
* @deprecated Types are going away, prefer filtering on a type.
|
*
|
||||||
|
* @deprecated Types are in the process of being removed. Instead of using a type, prefer to
|
||||||
|
* filter on a field on the document.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public SearchRequest types(String... types) {
|
public SearchRequest types(String... types) {
|
||||||
|
|
|
@ -17,13 +17,15 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.elasticsearch.rest.action.document;
|
package org.elasticsearch.rest.action.search;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.action.support.IndicesOptions;
|
import org.elasticsearch.action.support.IndicesOptions;
|
||||||
import org.elasticsearch.client.node.NodeClient;
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
|
@ -44,6 +46,11 @@ import static org.elasticsearch.rest.action.RestActions.buildBroadcastShardsHead
|
||||||
import static org.elasticsearch.search.internal.SearchContext.DEFAULT_TERMINATE_AFTER;
|
import static org.elasticsearch.search.internal.SearchContext.DEFAULT_TERMINATE_AFTER;
|
||||||
|
|
||||||
public class RestCountAction extends BaseRestHandler {
|
public class RestCountAction extends BaseRestHandler {
|
||||||
|
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(
|
||||||
|
LogManager.getLogger(RestCountAction.class));
|
||||||
|
static final String TYPES_DEPRECATION_MESSAGE = "[types removal]" +
|
||||||
|
" Specifying types in count requests is deprecated.";
|
||||||
|
|
||||||
public RestCountAction(Settings settings, RestController controller) {
|
public RestCountAction(Settings settings, RestController controller) {
|
||||||
super(settings);
|
super(settings);
|
||||||
controller.registerHandler(POST, "/_count", this);
|
controller.registerHandler(POST, "/_count", this);
|
||||||
|
@ -80,7 +87,12 @@ public class RestCountAction extends BaseRestHandler {
|
||||||
if (minScore != -1f) {
|
if (minScore != -1f) {
|
||||||
searchSourceBuilder.minScore(minScore);
|
searchSourceBuilder.minScore(minScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.hasParam("type")) {
|
||||||
|
deprecationLogger.deprecated(TYPES_DEPRECATION_MESSAGE);
|
||||||
countRequest.types(Strings.splitStringByCommaToArray(request.param("type")));
|
countRequest.types(Strings.splitStringByCommaToArray(request.param("type")));
|
||||||
|
}
|
||||||
|
|
||||||
countRequest.preference(request.param("preference"));
|
countRequest.preference(request.param("preference"));
|
||||||
|
|
||||||
final int terminateAfter = request.paramAsInt("terminate_after", DEFAULT_TERMINATE_AFTER);
|
final int terminateAfter = request.paramAsInt("terminate_after", DEFAULT_TERMINATE_AFTER);
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.rest.action.search;
|
package org.elasticsearch.rest.action.search;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.elasticsearch.action.search.MultiSearchRequest;
|
import org.elasticsearch.action.search.MultiSearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.support.IndicesOptions;
|
import org.elasticsearch.action.support.IndicesOptions;
|
||||||
|
@ -27,6 +28,7 @@ import org.elasticsearch.common.CheckedBiConsumer;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
|
import org.elasticsearch.common.logging.DeprecationLogger;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.XContent;
|
import org.elasticsearch.common.xcontent.XContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
@ -46,9 +48,13 @@ import static org.elasticsearch.rest.RestRequest.Method.GET;
|
||||||
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||||
|
|
||||||
public class RestMultiSearchAction extends BaseRestHandler {
|
public class RestMultiSearchAction extends BaseRestHandler {
|
||||||
|
|
||||||
private static final Set<String> RESPONSE_PARAMS = Collections.singleton(RestSearchAction.TYPED_KEYS_PARAM);
|
private static final Set<String> RESPONSE_PARAMS = Collections.singleton(RestSearchAction.TYPED_KEYS_PARAM);
|
||||||
|
|
||||||
|
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(
|
||||||
|
LogManager.getLogger(RestMultiSearchAction.class));
|
||||||
|
static final String TYPES_DEPRECATION_MESSAGE = "[types removal]" +
|
||||||
|
" Specifying types in multi search requests is deprecated.";
|
||||||
|
|
||||||
private final boolean allowExplicitIndex;
|
private final boolean allowExplicitIndex;
|
||||||
|
|
||||||
public RestMultiSearchAction(Settings settings, RestController controller) {
|
public RestMultiSearchAction(Settings settings, RestController controller) {
|
||||||
|
@ -96,6 +102,9 @@ public class RestMultiSearchAction extends BaseRestHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
parseMultiLineRequest(restRequest, multiRequest.indicesOptions(), allowExplicitIndex, (searchRequest, parser) -> {
|
parseMultiLineRequest(restRequest, multiRequest.indicesOptions(), allowExplicitIndex, (searchRequest, parser) -> {
|
||||||
|
if (searchRequest.types().length > 0) {
|
||||||
|
deprecationLogger.deprecated(TYPES_DEPRECATION_MESSAGE);
|
||||||
|
}
|
||||||
searchRequest.source(SearchSourceBuilder.fromXContent(parser, false));
|
searchRequest.source(SearchSourceBuilder.fromXContent(parser, false));
|
||||||
multiRequest.add(searchRequest);
|
multiRequest.add(searchRequest);
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,10 +54,12 @@ import static org.elasticsearch.rest.RestRequest.Method.POST;
|
||||||
import static org.elasticsearch.search.suggest.SuggestBuilders.termSuggestion;
|
import static org.elasticsearch.search.suggest.SuggestBuilders.termSuggestion;
|
||||||
|
|
||||||
public class RestSearchAction extends BaseRestHandler {
|
public class RestSearchAction extends BaseRestHandler {
|
||||||
|
|
||||||
public static final String TYPED_KEYS_PARAM = "typed_keys";
|
public static final String TYPED_KEYS_PARAM = "typed_keys";
|
||||||
private static final Set<String> RESPONSE_PARAMS = Collections.singleton(TYPED_KEYS_PARAM);
|
private static final Set<String> RESPONSE_PARAMS = Collections.singleton(TYPED_KEYS_PARAM);
|
||||||
|
|
||||||
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(LogManager.getLogger(RestSearchAction.class));
|
private static final DeprecationLogger deprecationLogger = new DeprecationLogger(LogManager.getLogger(RestSearchAction.class));
|
||||||
|
static final String TYPES_DEPRECATION_MESSAGE = "[types removal]" +
|
||||||
|
" Specifying types in search requests is deprecated.";
|
||||||
|
|
||||||
public RestSearchAction(Settings settings, RestController controller) {
|
public RestSearchAction(Settings settings, RestController controller) {
|
||||||
super(settings);
|
super(settings);
|
||||||
|
@ -150,11 +152,10 @@ public class RestSearchAction extends BaseRestHandler {
|
||||||
searchRequest.scroll(new Scroll(parseTimeValue(scroll, null, "scroll")));
|
searchRequest.scroll(new Scroll(parseTimeValue(scroll, null, "scroll")));
|
||||||
}
|
}
|
||||||
|
|
||||||
String types = request.param("type");
|
if (request.hasParam("type")) {
|
||||||
if (types != null) {
|
deprecationLogger.deprecated(TYPES_DEPRECATION_MESSAGE);
|
||||||
deprecationLogger.deprecated("The {index}/{type}/_search endpoint is deprecated, use {index}/_search instead");
|
searchRequest.types(Strings.splitStringByCommaToArray(request.param("type")));
|
||||||
}
|
}
|
||||||
searchRequest.types(Strings.splitStringByCommaToArray(types));
|
|
||||||
searchRequest.routing(request.param("routing"));
|
searchRequest.routing(request.param("routing"));
|
||||||
searchRequest.preference(request.param("preference"));
|
searchRequest.preference(request.param("preference"));
|
||||||
searchRequest.indicesOptions(IndicesOptions.fromRequest(request, searchRequest.indicesOptions()));
|
searchRequest.indicesOptions(IndicesOptions.fromRequest(request, searchRequest.indicesOptions()));
|
||||||
|
|
|
@ -183,7 +183,11 @@ public final class SearchHit implements Streamable, ToXContentObject, Iterable<D
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of the document.
|
* The type of the document.
|
||||||
|
*
|
||||||
|
* @deprecated Types are in the process of being removed. Instead of using a type, prefer to
|
||||||
|
* filter on a field on the document.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type != null ? type.string() : null;
|
return type != null ? type.string() : null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,7 +203,14 @@ public class MultiSearchRequestTests extends ESTestCase {
|
||||||
byte[] data = StreamsUtils.copyToBytesFromClasspath(sample);
|
byte[] data = StreamsUtils.copyToBytesFromClasspath(sample);
|
||||||
RestRequest restRequest = new FakeRestRequest.Builder(xContentRegistry())
|
RestRequest restRequest = new FakeRestRequest.Builder(xContentRegistry())
|
||||||
.withContent(new BytesArray(data), XContentType.JSON).build();
|
.withContent(new BytesArray(data), XContentType.JSON).build();
|
||||||
return RestMultiSearchAction.parseRequest(restRequest, true);
|
|
||||||
|
MultiSearchRequest request = new MultiSearchRequest();
|
||||||
|
RestMultiSearchAction.parseMultiLineRequest(restRequest, SearchRequest.DEFAULT_INDICES_OPTIONS, true,
|
||||||
|
(searchRequest, parser) -> {
|
||||||
|
searchRequest.source(SearchSourceBuilder.fromXContent(parser, false));
|
||||||
|
request.add(searchRequest);
|
||||||
|
});
|
||||||
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch 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.elasticsearch.rest.action.search;
|
||||||
|
|
||||||
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||||
|
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
|
||||||
|
import org.elasticsearch.rest.RestChannel;
|
||||||
|
import org.elasticsearch.rest.RestController;
|
||||||
|
import org.elasticsearch.rest.RestRequest;
|
||||||
|
import org.elasticsearch.rest.RestRequest.Method;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestChannel;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||||
|
import org.elasticsearch.usage.UsageService;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class RestCountActionTests extends ESTestCase {
|
||||||
|
private RestController controller;
|
||||||
|
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
controller = new RestController(Collections.emptySet(), null,
|
||||||
|
mock(NodeClient.class),
|
||||||
|
new NoneCircuitBreakerService(),
|
||||||
|
new UsageService());
|
||||||
|
new RestCountAction(Settings.EMPTY, controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTypeInPath() {
|
||||||
|
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
|
||||||
|
.withMethod(Method.POST)
|
||||||
|
.withPath("/some_index/some_type/_count")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
performRequest(request);
|
||||||
|
assertWarnings(RestCountAction.TYPES_DEPRECATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTypeParameter() {
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("type", "some_type");
|
||||||
|
|
||||||
|
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
|
||||||
|
.withMethod(Method.GET)
|
||||||
|
.withPath("/some_index/_count")
|
||||||
|
.withParams(params)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
performRequest(request);
|
||||||
|
assertWarnings(RestCountAction.TYPES_DEPRECATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performRequest(RestRequest request) {
|
||||||
|
RestChannel channel = new FakeRestChannel(request, false, 1);
|
||||||
|
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||||
|
controller.dispatchRequest(request, channel, threadContext);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch 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.elasticsearch.rest.action.search;
|
||||||
|
|
||||||
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
|
import org.elasticsearch.common.bytes.BytesArray;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
|
||||||
|
import org.elasticsearch.rest.RestChannel;
|
||||||
|
import org.elasticsearch.rest.RestController;
|
||||||
|
import org.elasticsearch.rest.RestRequest;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestChannel;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||||
|
import org.elasticsearch.usage.UsageService;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class RestMultiSearchActionTests extends ESTestCase {
|
||||||
|
private RestController controller;
|
||||||
|
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
controller = new RestController(Collections.emptySet(), null,
|
||||||
|
mock(NodeClient.class),
|
||||||
|
new NoneCircuitBreakerService(),
|
||||||
|
new UsageService());
|
||||||
|
new RestMultiSearchAction(Settings.EMPTY, controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTypeInPath() {
|
||||||
|
String content = "{ \"index\": \"some_index\" } \n {} \n";
|
||||||
|
BytesArray bytesContent = new BytesArray(content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
|
||||||
|
.withMethod(RestRequest.Method.GET)
|
||||||
|
.withPath("/some_index/some_type/_msearch")
|
||||||
|
.withContent(bytesContent, XContentType.JSON)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
performRequest(request);
|
||||||
|
assertWarnings(RestMultiSearchAction.TYPES_DEPRECATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTypeInBody() {
|
||||||
|
String content = "{ \"index\": \"some_index\", \"type\": \"some_type\" } \n {} \n";
|
||||||
|
BytesArray bytesContent = new BytesArray(content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
|
||||||
|
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
|
||||||
|
.withMethod(RestRequest.Method.POST)
|
||||||
|
.withPath("/some_index/_msearch")
|
||||||
|
.withContent(bytesContent, XContentType.JSON)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
performRequest(request);
|
||||||
|
assertWarnings(RestMultiSearchAction.TYPES_DEPRECATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performRequest(RestRequest request) {
|
||||||
|
RestChannel channel = new FakeRestChannel(request, false, 1);
|
||||||
|
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||||
|
controller.dispatchRequest(request, channel, threadContext);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch 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.elasticsearch.rest.action.search;
|
||||||
|
|
||||||
|
import org.elasticsearch.client.node.NodeClient;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||||
|
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
|
||||||
|
import org.elasticsearch.rest.RestChannel;
|
||||||
|
import org.elasticsearch.rest.RestController;
|
||||||
|
import org.elasticsearch.rest.RestRequest;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestChannel;
|
||||||
|
import org.elasticsearch.test.rest.FakeRestRequest;
|
||||||
|
import org.elasticsearch.usage.UsageService;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
public class RestSearchActionTests extends ESTestCase {
|
||||||
|
private RestController controller;
|
||||||
|
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
controller = new RestController(Collections.emptySet(), null,
|
||||||
|
mock(NodeClient.class),
|
||||||
|
new NoneCircuitBreakerService(),
|
||||||
|
new UsageService());
|
||||||
|
new RestSearchAction(Settings.EMPTY, controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTypeInPath() {
|
||||||
|
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
|
||||||
|
.withMethod(RestRequest.Method.GET)
|
||||||
|
.withPath("/some_index/some_type/_search")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
performRequest(request);
|
||||||
|
assertWarnings(RestSearchAction.TYPES_DEPRECATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTypeParameter() {
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("type", "some_type");
|
||||||
|
|
||||||
|
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
|
||||||
|
.withMethod(RestRequest.Method.GET)
|
||||||
|
.withPath("/some_index/_search")
|
||||||
|
.withParams(params)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
performRequest(request);
|
||||||
|
assertWarnings(RestSearchAction.TYPES_DEPRECATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void performRequest(RestRequest request) {
|
||||||
|
RestChannel channel = new FakeRestChannel(request, false, 1);
|
||||||
|
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
|
||||||
|
controller.dispatchRequest(request, channel, threadContext);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{"index":["test0", "test1"], "request_cache": true}
|
{"index":["test0", "test1"], "request_cache": true}
|
||||||
{"query" : {"match_all" : {}}}
|
{"query" : {"match_all" : {}}}
|
||||||
{"index" : "test2,test3", "type" : "type1", "preference": "_local"}
|
{"index" : "test2,test3", "preference": "_local"}
|
||||||
{"query" : {"match_all" : {}}}
|
{"query" : {"match_all" : {}}}
|
||||||
{"index" : ["test4", "test1"], "type" : [ "type2", "type1" ], "routing": "123"}
|
{"index" : ["test4", "test1"], "routing": "123"}
|
||||||
{"query" : {"match_all" : {}}}
|
{"query" : {"match_all" : {}}}
|
|
@ -49,7 +49,7 @@ public class IndexAuditUpgradeIT extends AbstractUpgradeTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertAuditDocsExist() throws Exception {
|
private void assertAuditDocsExist() throws Exception {
|
||||||
Response response = client().performRequest(new Request("GET", "/.security_audit_log*/doc/_count"));
|
Response response = client().performRequest(new Request("GET", "/.security_audit_log*/_count"));
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
Map<String, Object> responseMap = entityAsMap(response);
|
Map<String, Object> responseMap = entityAsMap(response);
|
||||||
assertNotNull(responseMap.get("count"));
|
assertNotNull(responseMap.get("count"));
|
||||||
|
|
Loading…
Reference in New Issue