PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/action/EqlSearchResponseTests.java

https://github.com/imotov/elasticsearch
Java | 277 lines | 245 code | 26 blank | 6 comment | 30 complexity | b5ff7bf712614266c309dd1a6a26e222 MD5 | raw file
  1. /*
  2. * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
  3. * or more contributor license agreements. Licensed under the Elastic License
  4. * 2.0; you may not use this file except in compliance with the Elastic License
  5. * 2.0.
  6. */
  7. package org.elasticsearch.xpack.eql.action;
  8. import org.apache.lucene.search.TotalHits;
  9. import org.elasticsearch.Version;
  10. import org.elasticsearch.common.bytes.BytesReference;
  11. import org.elasticsearch.common.document.DocumentField;
  12. import org.elasticsearch.common.io.stream.Writeable;
  13. import org.elasticsearch.core.Tuple;
  14. import org.elasticsearch.test.ESTestCase;
  15. import org.elasticsearch.test.RandomObjects;
  16. import org.elasticsearch.xcontent.ToXContent;
  17. import org.elasticsearch.xcontent.ToXContentObject;
  18. import org.elasticsearch.xcontent.XContentBuilder;
  19. import org.elasticsearch.xcontent.XContentParser;
  20. import org.elasticsearch.xcontent.XContentType;
  21. import org.elasticsearch.xpack.eql.AbstractBWCWireSerializingTestCase;
  22. import org.elasticsearch.xpack.eql.action.EqlSearchResponse.Event;
  23. import org.elasticsearch.xpack.eql.action.EqlSearchResponse.Sequence;
  24. import java.io.IOException;
  25. import java.util.ArrayList;
  26. import java.util.Arrays;
  27. import java.util.HashMap;
  28. import java.util.List;
  29. import java.util.Map;
  30. import java.util.Objects;
  31. import java.util.function.Supplier;
  32. import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
  33. import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
  34. public class EqlSearchResponseTests extends AbstractBWCWireSerializingTestCase<EqlSearchResponse> {
  35. public void testFromXContent() throws IOException {
  36. XContentType xContentType = randomFrom(XContentType.values()).canonical();
  37. EqlSearchResponse response = randomEqlSearchResponse(xContentType);
  38. boolean humanReadable = randomBoolean();
  39. BytesReference originalBytes = toShuffledXContent(response, xContentType, ToXContent.EMPTY_PARAMS, humanReadable);
  40. EqlSearchResponse parsed;
  41. try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
  42. parsed = EqlSearchResponse.fromXContent(parser);
  43. }
  44. assertToXContentEquivalent(originalBytes, toXContent(parsed, xContentType, humanReadable), xContentType);
  45. }
  46. private static class RandomSource implements ToXContentObject {
  47. private final String key;
  48. private final String value;
  49. RandomSource(Supplier<String> randomStringSupplier) {
  50. this.key = randomStringSupplier.get();
  51. this.value = randomStringSupplier.get();
  52. }
  53. @Override
  54. public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
  55. builder.startObject();
  56. builder.field(key, value);
  57. builder.endObject();
  58. return builder;
  59. }
  60. @Override
  61. public int hashCode() {
  62. return Objects.hash(key, value);
  63. }
  64. @Override
  65. public boolean equals(Object obj) {
  66. if (obj == null) {
  67. return false;
  68. }
  69. if (getClass() != obj.getClass()) {
  70. return false;
  71. }
  72. RandomSource other = (RandomSource) obj;
  73. return Objects.equals(key, other.key) && Objects.equals(value, other.value);
  74. }
  75. public BytesReference toBytes(XContentType type) {
  76. try (XContentBuilder builder = XContentBuilder.builder(type.xContent())) {
  77. toXContent(builder, ToXContent.EMPTY_PARAMS);
  78. return BytesReference.bytes(builder);
  79. } catch (IOException ex) {
  80. throw new RuntimeException(ex);
  81. }
  82. }
  83. }
  84. static List<Event> randomEvents(XContentType xType) {
  85. int size = randomIntBetween(1, 10);
  86. List<Event> hits = null;
  87. if (randomBoolean()) {
  88. hits = new ArrayList<>();
  89. for (int i = 0; i < size; i++) {
  90. BytesReference bytes = new RandomSource(() -> randomAlphaOfLength(10)).toBytes(xType);
  91. Map<String, DocumentField> fetchFields = new HashMap<>();
  92. int fieldsCount = randomIntBetween(0, 5);
  93. for (int j = 0; j < fieldsCount; j++) {
  94. fetchFields.put(randomAlphaOfLength(10), randomDocumentField(xType).v1());
  95. }
  96. if (fetchFields.isEmpty() && randomBoolean()) {
  97. fetchFields = null;
  98. }
  99. hits.add(new Event(String.valueOf(i), randomAlphaOfLength(10), bytes, fetchFields));
  100. }
  101. }
  102. if (randomBoolean()) {
  103. return hits;
  104. }
  105. return null;
  106. }
  107. private static Tuple<DocumentField, DocumentField> randomDocumentField(XContentType xType) {
  108. switch (randomIntBetween(0, 2)) {
  109. case 0:
  110. String fieldName = randomAlphaOfLengthBetween(3, 10);
  111. Tuple<List<Object>, List<Object>> tuple = RandomObjects.randomStoredFieldValues(random(), xType);
  112. DocumentField input = new DocumentField(fieldName, tuple.v1());
  113. DocumentField expected = new DocumentField(fieldName, tuple.v2());
  114. return Tuple.tuple(input, expected);
  115. case 1:
  116. List<Object> listValues = randomList(1, 5, () -> randomList(1, 5, ESTestCase::randomInt));
  117. DocumentField listField = new DocumentField(randomAlphaOfLength(5), listValues);
  118. return Tuple.tuple(listField, listField);
  119. case 2:
  120. List<Object> objectValues = randomList(
  121. 1,
  122. 5,
  123. () -> Map.of(
  124. randomAlphaOfLength(5),
  125. randomInt(),
  126. randomAlphaOfLength(5),
  127. randomBoolean(),
  128. randomAlphaOfLength(5),
  129. randomAlphaOfLength(10)
  130. )
  131. );
  132. DocumentField objectField = new DocumentField(randomAlphaOfLength(5), objectValues);
  133. return Tuple.tuple(objectField, objectField);
  134. default:
  135. throw new IllegalStateException();
  136. }
  137. }
  138. @Override
  139. protected EqlSearchResponse createTestInstance() {
  140. return randomEqlSearchResponse(XContentType.JSON);
  141. }
  142. @Override
  143. protected Writeable.Reader<EqlSearchResponse> instanceReader() {
  144. return EqlSearchResponse::new;
  145. }
  146. public static EqlSearchResponse randomEqlSearchResponse(XContentType xContentType) {
  147. TotalHits totalHits = null;
  148. if (randomBoolean()) {
  149. totalHits = new TotalHits(randomIntBetween(100, 1000), TotalHits.Relation.EQUAL_TO);
  150. }
  151. return createRandomInstance(totalHits, xContentType);
  152. }
  153. public static EqlSearchResponse createRandomEventsResponse(TotalHits totalHits, XContentType xType) {
  154. EqlSearchResponse.Hits hits = null;
  155. if (randomBoolean()) {
  156. hits = new EqlSearchResponse.Hits(randomEvents(xType), null, totalHits);
  157. }
  158. if (randomBoolean()) {
  159. return new EqlSearchResponse(hits, randomIntBetween(0, 1001), randomBoolean());
  160. } else {
  161. return new EqlSearchResponse(
  162. hits,
  163. randomIntBetween(0, 1001),
  164. randomBoolean(),
  165. randomAlphaOfLength(10),
  166. randomBoolean(),
  167. randomBoolean()
  168. );
  169. }
  170. }
  171. public static EqlSearchResponse createRandomSequencesResponse(TotalHits totalHits, XContentType xType) {
  172. int size = randomIntBetween(1, 10);
  173. List<EqlSearchResponse.Sequence> seq = null;
  174. if (randomBoolean()) {
  175. List<Supplier<Object[]>> randoms = getKeysGenerators();
  176. seq = new ArrayList<>();
  177. for (int i = 0; i < size; i++) {
  178. List<Object> joins = null;
  179. if (randomBoolean()) {
  180. joins = Arrays.asList(randomFrom(randoms).get());
  181. }
  182. seq.add(new EqlSearchResponse.Sequence(joins, randomEvents(xType)));
  183. }
  184. }
  185. EqlSearchResponse.Hits hits = null;
  186. if (randomBoolean()) {
  187. hits = new EqlSearchResponse.Hits(null, seq, totalHits);
  188. }
  189. if (randomBoolean()) {
  190. return new EqlSearchResponse(hits, randomIntBetween(0, 1001), randomBoolean());
  191. } else {
  192. return new EqlSearchResponse(
  193. hits,
  194. randomIntBetween(0, 1001),
  195. randomBoolean(),
  196. randomAlphaOfLength(10),
  197. randomBoolean(),
  198. randomBoolean()
  199. );
  200. }
  201. }
  202. private static List<Supplier<Object[]>> getKeysGenerators() {
  203. List<Supplier<Object[]>> randoms = new ArrayList<>();
  204. randoms.add(() -> generateRandomStringArray(6, 11, false));
  205. randoms.add(() -> randomArray(0, 6, Integer[]::new, () -> randomInt()));
  206. randoms.add(() -> randomArray(0, 6, Long[]::new, () -> randomLong()));
  207. randoms.add(() -> randomArray(0, 6, Boolean[]::new, () -> randomBoolean()));
  208. return randoms;
  209. }
  210. public static EqlSearchResponse createRandomInstance(TotalHits totalHits, XContentType xType) {
  211. int type = between(0, 1);
  212. switch (type) {
  213. case 0:
  214. return createRandomEventsResponse(totalHits, xType);
  215. case 1:
  216. return createRandomSequencesResponse(totalHits, xType);
  217. default:
  218. return null;
  219. }
  220. }
  221. @Override
  222. protected EqlSearchResponse mutateInstanceForVersion(EqlSearchResponse instance, Version version) {
  223. List<Event> mutatedEvents = mutateEvents(instance.hits().events(), version);
  224. List<Sequence> sequences = instance.hits().sequences();
  225. List<Sequence> mutatedSequences = null;
  226. if (sequences != null) {
  227. mutatedSequences = new ArrayList<>(sequences.size());
  228. for (Sequence s : sequences) {
  229. mutatedSequences.add(new Sequence(s.joinKeys(), mutateEvents(s.events(), version)));
  230. }
  231. }
  232. return new EqlSearchResponse(
  233. new EqlSearchResponse.Hits(mutatedEvents, mutatedSequences, instance.hits().totalHits()),
  234. instance.took(),
  235. instance.isTimeout(),
  236. instance.id(),
  237. instance.isRunning(),
  238. instance.isPartial()
  239. );
  240. }
  241. private List<Event> mutateEvents(List<Event> original, Version version) {
  242. if (original == null || original.isEmpty()) {
  243. return original;
  244. }
  245. List<Event> mutatedEvents = new ArrayList<>(original.size());
  246. for (Event e : original) {
  247. mutatedEvents.add(new Event(e.index(), e.id(), e.source(), version.onOrAfter(Version.V_7_13_0) ? e.fetchFields() : null));
  248. }
  249. return mutatedEvents;
  250. }
  251. }