package de.spinscale.elasticsearch.module.suggest.test;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.Response;
import de.spinscale.elasticsearch.action.suggest.statistics.FstStats;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
import static org.hamcrest.Matchers.*;
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE, transportClientRatio = 0.0)
public class RestSuggestActionTest extends AbstractSuggestTest {
private final AsyncHttpClient httpClient = new AsyncHttpClient();
private int port;
@Before
public void setPort() {
NodesInfoResponse response = client().admin().cluster().prepareNodesInfo().setHttp(true).execute().actionGet();
port = ((InetSocketTransportAddress) response.getNodes()[0].getHttp().address().boundAddress()).address().getPort();
}
@After
public void closeHttpClient() {
httpClient.close();
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
return settingsBuilder().put(super.nodeSettings(nodeOrdinal))
.put("http.jsonp.enable", true)
.build();
}
@Test
public void testThatSuggestionsShouldWorkWithCallbackAndGetRequestParameter() throws Exception {
List<Map<String, Object>> products = createProducts(4);
products.get(0).put("ProductName", "foo");
products.get(1).put("ProductName", "foob");
products.get(2).put("ProductName", "foobar");
indexProducts(products);
refreshAllSuggesters();
String json = String.format(Locale.ROOT, "{ \"field\": \"%s\", \"term\": \"%s\" }", "ProductName.suggest", "foobar");
String query = URLEncoder.encode(json, "UTF8");
String queryString = "callback=mycallback&source=" + query;
String response = httpClient.prepareGet("http://localhost:" + port + "/"+ index +"/product/__suggest?" + queryString).
execute().get().getResponseBody();
assertThat(response, startsWith("mycallback({\"_shards\":{\"total\""));
assertThat(response, endsWith("\"suggestions\":[\"foobar\"]});"));
}
@Override
public List<String> getSuggestions(SuggestionQuery suggestionQuery) throws Exception {
String json = createJSONQuery(suggestionQuery);
String url = "http://localhost:" + port + "/" + suggestionQuery.index + "/" + suggestionQuery.type + "/__suggest";
Response r = httpClient.preparePost(url).setBody(json).execute().get();
assertThat(r.getStatusCode(), is(200));
assertThatResponseHasNoShardFailures(r);
// System.out.println("REQ : " + json);
// System.out.println("RESP: " + r.getResponseBody());
return getSuggestionsFromResponse(r.getResponseBody());
}
private void assertThatResponseHasNoShardFailures(Response r) throws IOException {
XContentParser parser = JsonXContent.jsonXContent.createParser(r.getResponseBody());
Map<String, Object> jsonResponse = parser.mapAndClose();
assertThat(jsonResponse, hasKey("_shards"));
Map<String, Object> shardResponse = (Map<String, Object>) jsonResponse.get("_shards");
assertThat(shardResponse, not(hasKey("failures")));
}
@Override
public void refreshAllSuggesters() throws Exception {
Response r = httpClient.preparePost("http://localhost:" + port + "/__suggestRefresh").execute().get();
assertThat(r.getStatusCode(), is(200));
}
@Override
public void refreshIndexSuggesters(String index) throws Exception {
Response r = httpClient.preparePost("http://localhost:" + port + "/"+ index + "/product/__suggestRefresh").execute().get();
assertThat(r.getStatusCode(), is(200));
}
@Override
public void refreshFieldSuggesters(String index, String field) throws Exception {
String jsonBody = String.format(Locale.ROOT, "{ \"field\": \"%s\" } ", field);
Response r = httpClient.preparePost("http://localhost:"+ port +"/" + index + "/product/__suggestRefresh").setBody(jsonBody).execute().get();
assertThat(r.getStatusCode(), is(200));
}
@Override
public FstStats getStatistics() throws Exception {
List<FstStats.FstIndexShardStats> stats = Lists.newArrayList();
Response r = httpClient.prepareGet("http://localhost:" + port + "/__suggestStatistics").execute().get();
assertThat(r.getStatusCode(), is(200));
System.out.println(r.getResponseBody());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootObj = objectMapper.readTree(r.getResponseBody());
FstStats fstStats = new FstStats();
ArrayNode jsonFstStats = (ArrayNode) rootObj.get("fstStats");
Iterator<JsonNode> nodesIterator = jsonFstStats.iterator();
while (nodesIterator.hasNext()) {
JsonNode fstStatsNodeEntry = nodesIterator.next();
if (fstStatsNodeEntry.isObject()) {
ShardId shardId = new ShardId(fstStatsNodeEntry.get("index").asText(), fstStatsNodeEntry.get("id").asInt());
FstStats.FstIndexShardStats fstIndexShardStats = new FstStats.FstIndexShardStats(shardId, null, null, fstStatsNodeEntry.get("sizeInBytes").getLongValue());
stats.add(fstIndexShardStats);
}
fstStats.getStats().addAll(stats);
}
return fstStats;
}
private String createJSONQuery(SuggestionQuery suggestionQuery) {
StringBuilder query = new StringBuilder("{");
query.append(String.format(Locale.ROOT, "\"field\": \"%s\", ", suggestionQuery.field));
query.append(String.format(Locale.ROOT, "\"term\": \"%s\"", suggestionQuery.term));
if (suggestionQuery.size != null) {
query.append(String.format(Locale.ROOT, ", \"size\": \"%s\"", suggestionQuery.size));
}
if (suggestionQuery.suggestType != null) {
query.append(String.format(Locale.ROOT, ", \"type\": \"%s\"", suggestionQuery.suggestType));
}
if (suggestionQuery.similarity != null && suggestionQuery.similarity > 0.0 && suggestionQuery.similarity < 1.0) {
query.append(String.format(Locale.ROOT, ", \"similarity\": \"%s\"", suggestionQuery.similarity));
}
if (Strings.hasLength(suggestionQuery.indexAnalyzer)) {
query.append(String.format(Locale.ROOT, ", \"indexAnalyzer\": \"%s\"", suggestionQuery.indexAnalyzer));
}
if (Strings.hasLength(suggestionQuery.queryAnalyzer)) {
query.append(String.format(Locale.ROOT, ", \"queryAnalyzer\": \"%s\"", suggestionQuery.queryAnalyzer));
}
if (Strings.hasLength(suggestionQuery.analyzer)) {
query.append(String.format(Locale.ROOT, ", \"analyzer\": \"%s\"", suggestionQuery.analyzer));
}
query.append(String.format(Locale.ROOT, ", \"preserve_position_increments\": \"%s\"", suggestionQuery.preservePositionIncrements));
query.append("}");
return query.toString();
}
@SuppressWarnings("unchecked")
private List<String> getSuggestionsFromResponse(String response) throws IOException {
XContentParser parser = JsonXContent.jsonXContent.createParser(response);
Map<String, Object> jsonResponse = parser.map();
assertThat(jsonResponse, hasKey("suggestions"));
return (List<String>) jsonResponse.get("suggestions");
}
}