/*
* 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.cat;
import org.elasticsearch.common.Table;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.AbstractRestChannel;
import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.rest.FakeRestRequest;
import org.junit.Before;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static org.elasticsearch.rest.action.cat.RestTable.buildDisplayHeaders;
import static org.elasticsearch.rest.action.cat.RestTable.buildResponse;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
public class RestTableTests extends ESTestCase {
private static final String APPLICATION_JSON = XContentType.JSON.mediaType();
private static final String APPLICATION_YAML = XContentType.YAML.mediaType();
private static final String APPLICATION_SMILE = XContentType.SMILE.mediaType();
private static final String APPLICATION_CBOR = XContentType.CBOR.mediaType();
private static final String CONTENT_TYPE = "Content-Type";
private static final String ACCEPT = "Accept";
private static final String TEXT_PLAIN = "text/plain; charset=UTF-8";
private static final String TEXT_TABLE_BODY = "foo foo foo foo foo foo foo foo\n";
private static final String JSON_TABLE_BODY = "[{\"bulk.foo\":\"foo\",\"bulk.bar\":\"foo\",\"aliasedBulk\":\"foo\"," +
"\"aliasedSecondBulk\":\"foo\",\"unmatched\":\"foo\"," +
"\"invalidAliasesBulk\":\"foo\",\"timestamp\":\"foo\",\"epoch\":\"foo\"}]";
private static final String YAML_TABLE_BODY = "---\n" +
"- bulk.foo: \"foo\"\n" +
" bulk.bar: \"foo\"\n" +
" aliasedBulk: \"foo\"\n" +
" aliasedSecondBulk: \"foo\"\n" +
" unmatched: \"foo\"\n" +
" invalidAliasesBulk: \"foo\"\n" +
" timestamp: \"foo\"\n" +
" epoch: \"foo\"\n";
private Table table;
private FakeRestRequest restRequest;
@Before
public void setup() {
restRequest = new FakeRestRequest();
table = new Table();
table.startHeaders();
table.addCell("bulk.foo", "alias:f;desc:foo");
table.addCell("bulk.bar", "alias:b;desc:bar");
// should be matched as well due to the aliases
table.addCell("aliasedBulk", "alias:bulkWhatever;desc:bar");
table.addCell("aliasedSecondBulk", "alias:foobar,bulkolicious,bulkotastic;desc:bar");
// no match
table.addCell("unmatched", "alias:un.matched;desc:bar");
// invalid alias
table.addCell("invalidAliasesBulk", "alias:,,,;desc:bar");
// timestamp
table.addCell("timestamp", "alias:ts");
table.addCell("epoch", "alias:t");
table.endHeaders();
}
public void testThatDisplayHeadersSupportWildcards() throws Exception {
restRequest.params().put("h", "bulk*");
List<RestTable.DisplayHeader> headers = buildDisplayHeaders(table, restRequest);
List<String> headerNames = getHeaderNames(headers);
assertThat(headerNames, contains("bulk.foo", "bulk.bar", "aliasedBulk", "aliasedSecondBulk"));
assertThat(headerNames, not(hasItem("unmatched")));
}
public void testThatDisplayHeadersAreNotAddedTwice() throws Exception {
restRequest.params().put("h", "nonexistent,bulk*,bul*");
List<RestTable.DisplayHeader> headers = buildDisplayHeaders(table, restRequest);
List<String> headerNames = getHeaderNames(headers);
assertThat(headerNames, contains("bulk.foo", "bulk.bar", "aliasedBulk", "aliasedSecondBulk"));
assertThat(headerNames, not(hasItem("unmatched")));
}
public void testThatWeUseTheAcceptHeaderJson() throws Exception {
assertResponse(Collections.singletonMap(ACCEPT, Collections.singletonList(APPLICATION_JSON)),
APPLICATION_JSON,
JSON_TABLE_BODY);
}
public void testThatWeUseTheAcceptHeaderYaml() throws Exception {
assertResponse(Collections.singletonMap(ACCEPT, Collections.singletonList(APPLICATION_YAML)),
APPLICATION_YAML,
YAML_TABLE_BODY);
}
public void testThatWeUseTheAcceptHeaderSmile() throws Exception {
assertResponseContentType(Collections.singletonMap(ACCEPT, Collections.singletonList(APPLICATION_SMILE)),
APPLICATION_SMILE);
}
public void testThatWeUseTheAcceptHeaderCbor() throws Exception {
assertResponseContentType(Collections.singletonMap(ACCEPT, Collections.singletonList(APPLICATION_CBOR)),
APPLICATION_CBOR);
}
public void testThatWeUseTheAcceptHeaderText() throws Exception {
assertResponse(Collections.singletonMap(ACCEPT, Collections.singletonList(TEXT_PLAIN)),
TEXT_PLAIN,
TEXT_TABLE_BODY);
}
public void testIgnoreContentType() throws Exception {
assertResponse(Collections.singletonMap(CONTENT_TYPE, Collections.singletonList(APPLICATION_JSON)),
TEXT_PLAIN,
TEXT_TABLE_BODY);
}
public void testThatDisplayHeadersWithoutTimestamp() throws Exception {
restRequest.params().put("h", "timestamp,epoch,bulk*");
restRequest.params().put("ts", "false");
List<RestTable.DisplayHeader> headers = buildDisplayHeaders(table, restRequest);
List<String> headerNames = getHeaderNames(headers);
assertThat(headerNames, contains("bulk.foo", "bulk.bar", "aliasedBulk", "aliasedSecondBulk"));
assertThat(headerNames, not(hasItem("timestamp")));
assertThat(headerNames, not(hasItem("epoch")));
}
public void testCompareRow() {
Table table = new Table();
table.startHeaders();
table.addCell("compare");
table.endHeaders();
for (Integer i : Arrays.asList(1,2,1)) {
table.startRow();
table.addCell(i);
table.endRow();
}
RestTable.TableIndexComparator comparator = new RestTable.TableIndexComparator(table,
Collections.singletonList(new RestTable.ColumnOrderElement("compare", false)));
assertTrue(comparator.compare(0,1) < 0);
assertTrue(comparator.compare(0,2) == 0);
assertTrue(comparator.compare(1,2) > 0);
RestTable.TableIndexComparator reverseComparator = new RestTable.TableIndexComparator(table,
Collections.singletonList(new RestTable.ColumnOrderElement("compare", true)));
assertTrue(reverseComparator.compare(0,1) > 0);
assertTrue(reverseComparator.compare(0,2) == 0);
assertTrue(reverseComparator.compare(1,2) < 0);
}
public void testRowOutOfBounds() {
Table table = new Table();
table.startHeaders();
table.addCell("compare");
table.endHeaders();
RestTable.TableIndexComparator comparator = new RestTable.TableIndexComparator(table,
Collections.singletonList(new RestTable.ColumnOrderElement("compare", false)));
Error e = expectThrows(AssertionError.class, () -> {
comparator.compare(0,1);
});
assertEquals("Invalid comparison of indices (0, 1): Table has 0 rows.", e.getMessage());
}
public void testUnknownHeader() {
Table table = new Table();
table.startHeaders();
table.addCell("compare");
table.endHeaders();
restRequest.params().put("s", "notaheader");
Exception e = expectThrows(UnsupportedOperationException.class, () -> RestTable.getRowOrder(table, restRequest));
assertEquals("Unable to sort by unknown sort key `notaheader`", e.getMessage());
}
public void testAliasSort() {
Table table = new Table();
table.startHeaders();
table.addCell("compare", "alias:c;");
table.endHeaders();
List<Integer> comparisonList = Arrays.asList(3,1,2);
for (int i = 0; i < comparisonList.size(); i++) {
table.startRow();
table.addCell(comparisonList.get(i));
table.endRow();
}
restRequest.params().put("s", "c");
List<Integer> rowOrder = RestTable.getRowOrder(table, restRequest);
assertEquals(Arrays.asList(1,2,0), rowOrder);
}
public void testReversedSort() {
Table table = new Table();
table.startHeaders();
table.addCell("reversed");
table.endHeaders();
List<Integer> comparisonList = Arrays.asList(0, 1, 2);
for (int i = 0; i < comparisonList.size(); i++) {
table.startRow();
table.addCell(comparisonList.get(i));
table.endRow();
}
restRequest.params().put("s", "reversed:desc");
List<Integer> rowOrder = RestTable.getRowOrder(table, restRequest);
assertEquals(Arrays.asList(2,1,0), rowOrder);
}
public void testMultiSort() {
Table table = new Table();
table.startHeaders();
table.addCell("compare");
table.addCell("second.compare");
table.endHeaders();
List<Integer> comparisonList = Arrays.asList(3, 3, 2);
List<Integer> secondComparisonList = Arrays.asList(2, 1, 3);
for (int i = 0; i < comparisonList.size(); i++) {
table.startRow();
table.addCell(comparisonList.get(i));
table.addCell(secondComparisonList.get(i));
table.endRow();
}
restRequest.params().put("s", "compare,second.compare");
List<Integer> rowOrder = RestTable.getRowOrder(table, restRequest);
assertEquals(Arrays.asList(2,1,0), rowOrder);
restRequest.params().put("s", "compare:desc,second.compare");
rowOrder = RestTable.getRowOrder(table, restRequest);
assertEquals(Arrays.asList(1,0,2), rowOrder);
}
private RestResponse assertResponseContentType(Map<String, List<String>> headers, String mediaType) throws Exception {
FakeRestRequest requestWithAcceptHeader = new FakeRestRequest.Builder(xContentRegistry()).withHeaders(headers).build();
table.startRow();
table.addCell("foo");
table.addCell("foo");
table.addCell("foo");
table.addCell("foo");
table.addCell("foo");
table.addCell("foo");
table.addCell("foo");
table.addCell("foo");
table.endRow();
RestResponse response = buildResponse(table, new AbstractRestChannel(requestWithAcceptHeader, true) {
@Override
public void sendResponse(RestResponse response) {
}
});
assertThat(response.contentType(), equalTo(mediaType));
return response;
}
private void assertResponse(Map<String, List<String>> headers, String mediaType, String body) throws Exception {
RestResponse response = assertResponseContentType(headers, mediaType);
assertThat(response.content().utf8ToString(), equalTo(body));
}
private List<String> getHeaderNames(List<RestTable.DisplayHeader> headers) {
List<String> headerNames = new ArrayList<>();
for (RestTable.DisplayHeader header : headers) {
headerNames.add(header.name);
}
return headerNames;
}
}