From 7bc01ee54790a3e38f35f98a6a0bc1a9b50107ae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 10 Oct 2024 08:49:30 +0000 Subject: [PATCH 1/2] Add IT for LogPatternTool (#421) * Add IT for LogPatternTool Signed-off-by: Heng Qian * spotlessApply Signed-off-by: Heng Qian --------- Signed-off-by: Heng Qian (cherry picked from commit a45af948805c0541e5773c00561c9df9789d1374) Signed-off-by: github-actions[bot] --- .../agent/tools/LogPatternTool.java | 32 +- .../agent/tools/LogPatternToolTests.java | 322 +++++++++++++++++- .../integTest/LogPatternToolIT.java | 193 +++++++++++ ...ent_of_log_pattern_tool_response_body.json | 45 +++ ...gent_of_log_pattern_tool_request_body.json | 12 + 5 files changed, 597 insertions(+), 7 deletions(-) create mode 100644 src/test/java/org/opensearch/integTest/LogPatternToolIT.java create mode 100644 src/test/resources/org/opensearch/agent/tools/expected_flow_agent_of_log_pattern_tool_response_body.json create mode 100644 src/test/resources/org/opensearch/agent/tools/register_flow_agent_of_log_pattern_tool_request_body.json diff --git a/src/main/java/org/opensearch/agent/tools/LogPatternTool.java b/src/main/java/org/opensearch/agent/tools/LogPatternTool.java index 99ca6446..a4ad832e 100644 --- a/src/main/java/org/opensearch/agent/tools/LogPatternTool.java +++ b/src/main/java/org/opensearch/agent/tools/LogPatternTool.java @@ -115,12 +115,32 @@ public void run(Map parameters, ActionListener listener) SearchHit[] hits = r.getHits().getHits(); if (hits != null && hits.length > 0) { + Map firstLogSource = hits[0].getSourceAsMap(); String patternField = parameters.containsKey(PATTERN_FIELD) ? parameters.get(PATTERN_FIELD) - : findLongestField(hits[0].getSourceAsMap()); + : findLongestField(firstLogSource); if (patternField == null) { - listener.onResponse((T) "Pattern field is not set and this index doesn't contain any string field"); - return; + throw new IllegalArgumentException("Pattern field is not set and this index doesn't contain any string field"); + } else if (!firstLogSource.containsKey(patternField)) { + throw new IllegalArgumentException( + LoggerMessageFormat + .format( + null, + "Invalid parameter pattern_field: index {} does not have a field named {}", + parameters.getOrDefault(INDEX_FIELD, index), + patternField + ) + ); + } else if (!(firstLogSource.get(patternField) instanceof String)) { + throw new IllegalArgumentException( + LoggerMessageFormat + .format( + null, + "Invalid parameter pattern_field: pattern field {} in index {} is not type of String", + patternField, + parameters.getOrDefault(INDEX_FIELD, index) + ) + ); } Map>> patternGroups = new HashMap<>(); for (SearchHit hit : hits) { @@ -262,9 +282,9 @@ public static LogPatternTool.Factory getInstance() { @Override public LogPatternTool create(Map params) { - int docSize = params.containsKey(DOC_SIZE_FIELD) ? getInteger(params, DOC_SIZE_FIELD) : LOG_PATTERN_DEFAULT_DOC_SIZE; - int topNPattern = params.containsKey(TOP_N_PATTERN) ? getInteger(params, TOP_N_PATTERN) : DEFAULT_TOP_N_PATTERN; - int sampleLogSize = params.containsKey(SAMPLE_LOG_SIZE) ? getInteger(params, SAMPLE_LOG_SIZE) : DEFAULT_SAMPLE_LOG_SIZE; + int docSize = params.containsKey(DOC_SIZE_FIELD) ? getPositiveInteger(params, DOC_SIZE_FIELD) : LOG_PATTERN_DEFAULT_DOC_SIZE; + int topNPattern = params.containsKey(TOP_N_PATTERN) ? getPositiveInteger(params, TOP_N_PATTERN) : DEFAULT_TOP_N_PATTERN; + int sampleLogSize = params.containsKey(SAMPLE_LOG_SIZE) ? getPositiveInteger(params, SAMPLE_LOG_SIZE) : DEFAULT_SAMPLE_LOG_SIZE; String patternStr = params.containsKey(PATTERN) ? (String) params.get(PATTERN) : null; return LogPatternTool .builder() diff --git a/src/test/java/org/opensearch/agent/tools/LogPatternToolTests.java b/src/test/java/org/opensearch/agent/tools/LogPatternToolTests.java index 21731005..1f469b43 100644 --- a/src/test/java/org/opensearch/agent/tools/LogPatternToolTests.java +++ b/src/test/java/org/opensearch/agent/tools/LogPatternToolTests.java @@ -5,25 +5,94 @@ package org.opensearch.agent.tools; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.opensearch.agent.tools.AbstractRetrieverTool.DOC_SIZE_FIELD; +import static org.opensearch.agent.tools.LogPatternTool.PATTERN; +import static org.opensearch.agent.tools.LogPatternTool.SAMPLE_LOG_SIZE; +import static org.opensearch.agent.tools.LogPatternTool.TOP_N_PATTERN; +import static org.opensearch.integTest.BaseAgentToolsIT.gson; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Pattern; +import org.hamcrest.MatcherAssert; import org.junit.Before; import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opensearch.action.search.SearchResponse; +import org.opensearch.client.Client; +import org.opensearch.common.xcontent.XContentFactory; +import org.opensearch.core.action.ActionListener; +import org.opensearch.core.common.bytes.BytesReference; +import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.search.SearchHit; +import org.opensearch.search.SearchHits; + +import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonElement; import lombok.SneakyThrows; public class LogPatternToolTests { + public static String responseBodyResourceFile = "org/opensearch/agent/tools/expected_flow_agent_of_log_pattern_tool_response_body.json"; public static final String TEST_QUERY_TEXT = "123fsd23134sdfouh"; private Map params = new HashMap<>(); + private final Client client = mock(Client.class); + @Mock + private SearchResponse searchResponse; + @Mock + private SearchHits searchHits; + @SneakyThrows @Before - public void setup() {} + public void setup() { + MockitoAnnotations.openMocks(this); + LogPatternTool.Factory.getInstance().init(client, null); + List fields = List.of("field1", "field2", "field3"); + SearchHit[] hits = new SearchHit[] { + createHit(0, null, fields, List.of("123", "123.abc-AB * De /", 12345)), + createHit(1, null, fields, List.of("123", "45.abc-AB * De /", 12345)), + createHit(2, null, fields, List.of("123", "12.abc_AB * De /", 12345)), + createHit(3, null, fields, List.of("123", "45.ab_AB * De /", 12345)), + createHit(4, null, fields, List.of("123", ".abAB * De /", 12345)), }; + doAnswer(invocation -> { + ActionListener listener = (ActionListener) invocation.getArguments()[1]; + listener.onResponse(searchResponse); + return null; + }).when(client).search(any(), any()); + when(searchResponse.getHits()).thenReturn(searchHits); + when(searchHits.getHits()).thenReturn(hits); + } + + private SearchHit createHit(int docId, String id, List fieldNames, List fieldContents) throws IOException { + return new SearchHit(docId, id, null, null).sourceRef(createSource(fieldNames, fieldContents)); + } + + private BytesReference createSource(List fieldNames, List fieldContents) throws IOException { + XContentBuilder builder = XContentFactory.jsonBuilder().startObject(); + for (int i = 0; i < fieldNames.size(); i++) { + builder.field(fieldNames.get(i), fieldContents.get(i)); + } + builder.endObject(); + return (BytesReference.bytes(builder)); + } @Test @SneakyThrows @@ -36,6 +105,56 @@ public void testCreateTool() { assertEquals("LogPatternTool", tool.getType()); assertEquals("LogPatternTool", tool.getName()); assertEquals(LogPatternTool.DEFAULT_DESCRIPTION, LogPatternTool.Factory.getInstance().getDefaultDescription()); + assertEquals(LogPatternTool.TYPE, LogPatternTool.Factory.getInstance().getDefaultType()); + assertNull(LogPatternTool.Factory.getInstance().getDefaultVersion()); + } + + @Test + @SneakyThrows + public void testCreateToolWithNonIntegerSize() { + Exception exception = assertThrows( + IllegalArgumentException.class, + () -> LogPatternTool.Factory.getInstance().create(Map.of(DOC_SIZE_FIELD, "1.5")) + ); + MatcherAssert.assertThat(exception.getMessage(), containsString("Invalid value 1.5 for parameter doc_size, it should be a number")); + + Exception exception2 = assertThrows( + IllegalArgumentException.class, + () -> LogPatternTool.Factory.getInstance().create(Map.of(TOP_N_PATTERN, "1.5")) + ); + MatcherAssert + .assertThat(exception2.getMessage(), containsString("Invalid value 1.5 for parameter top_n_pattern, it should be a number")); + + Exception exception3 = assertThrows( + IllegalArgumentException.class, + () -> LogPatternTool.Factory.getInstance().create(Map.of(SAMPLE_LOG_SIZE, "1.5")) + ); + MatcherAssert + .assertThat(exception3.getMessage(), containsString("Invalid value 1.5 for parameter sample_log_size, it should be a number")); + } + + @Test + @SneakyThrows + public void testCreateToolWithNonPositiveSize() { + Exception exception = assertThrows( + IllegalArgumentException.class, + () -> LogPatternTool.Factory.getInstance().create(Map.of(DOC_SIZE_FIELD, "-1")) + ); + MatcherAssert.assertThat(exception.getMessage(), containsString("Invalid value -1 for parameter doc_size, it should be positive")); + + Exception exception2 = assertThrows( + IllegalArgumentException.class, + () -> LogPatternTool.Factory.getInstance().create(Map.of(TOP_N_PATTERN, "-1")) + ); + MatcherAssert + .assertThat(exception2.getMessage(), containsString("Invalid value -1 for parameter top_n_pattern, it should be positive")); + + Exception exception3 = assertThrows( + IllegalArgumentException.class, + () -> LogPatternTool.Factory.getInstance().create(Map.of(SAMPLE_LOG_SIZE, "-1")) + ); + MatcherAssert + .assertThat(exception3.getMessage(), containsString("Invalid value -1 for parameter sample_log_size, it should be positive")); } @Test @@ -44,6 +163,18 @@ public void testGetQueryBody() { assertEquals(TEST_QUERY_TEXT, tool.getQueryBody(TEST_QUERY_TEXT)); } + @Test + public void testValidate() { + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + assertTrue(tool.validate(Map.of("index", "test1", "input", "input_value"))); + + // validate failure if no index + assertFalse(tool.validate(Map.of("input", "input_value"))); + + // validate failure if no + assertFalse(tool.validate(Map.of("index", "test1"))); + } + @Test public void testFindLongestField() { assertEquals("field2", LogPatternTool.findLongestField(Map.of("field1", "123", "field2", "1234", "filed3", 1234))); @@ -55,4 +186,193 @@ public void testExtractPattern() { assertEquals("123.c/.AB/", LogPatternTool.extractPattern("123.abc/.AB/", Pattern.compile("ab"))); assertEquals(".abc/.AB/", LogPatternTool.extractPattern("123.abc/.AB/", Pattern.compile("[0-9]"))); } + + @SneakyThrows + @Test + public void testExecutionDefault() { + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + JsonElement expected = gson + .fromJson( + Files.readString(Path.of(this.getClass().getClassLoader().getResource(responseBodyResourceFile).toURI())), + JsonElement.class + ); + tool + .run( + ImmutableMap.of("index", "index_name", "input", "{}"), + ActionListener + .wrap( + response -> assertEquals(expected, gson.fromJson(response, JsonElement.class)), + e -> fail("Tool runs failed: " + e.getMessage()) + ) + ); + } + + @SneakyThrows + @Test + public void testExecutionWithSpecifiedPatternField() { + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + JsonElement expected = gson + .fromJson( + "[{\"total count\":5,\"sample logs\":[{\"field1\":\"123\",\"field3\":12345,\"field2\":\"123.abc-AB * De /\"},{\"field1\":\"123\",\"field3\":12345,\"field2\":\"45.abc-AB * De /\"}],\"pattern\":\"\"}]", + JsonElement.class + ); + tool + .run( + ImmutableMap.of("index", "index_name", "input", "{}", "pattern_field", "field1", "sample_log_size", "2"), + ActionListener + .wrap( + response -> assertEquals(expected, gson.fromJson(response, JsonElement.class)), + e -> fail("Tool runs failed: " + e.getMessage()) + ) + ); + } + + @SneakyThrows + @Test + public void testExecutionWithSpecifiedPattern() { + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(Map.of(PATTERN, "[a-zA-Z]")); + JsonElement expected = gson + .fromJson( + "[{\"pattern\":\"45.- * /\",\"sample logs\":[{\"field1\":\"123\",\"field3\":12345,\"field2\":\"45.abc-AB * De /\"}],\"total count\":1},{\"pattern\":\". * /\",\"sample logs\":[{\"field1\":\"123\",\"field3\":12345,\"field2\":\".abAB * De /\"}],\"total count\":1},{\"pattern\":\"123.- * /\",\"sample logs\":[{\"field1\":\"123\",\"field3\":12345,\"field2\":\"123.abc-AB * De /\"}],\"total count\":1}]", + JsonElement.class + ); + tool + .run( + ImmutableMap.of("index", "index_name", "input", "{}"), + ActionListener + .wrap( + response -> assertEquals(expected, gson.fromJson(response, JsonElement.class)), + e -> fail("Tool runs failed: " + e.getMessage()) + ) + ); + } + + @SneakyThrows + @Test + public void testExecutionWithBlankInput() { + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + tool + .run( + ImmutableMap.of("index", "index_name", "input", ""), + ActionListener + .wrap( + response -> fail(), + e -> MatcherAssert.assertThat(e.getMessage(), containsString("[input] is null or empty, can not process it.")) + ) + ); + } + + @SneakyThrows + @Test + public void testExecutionFailedWithNonStringPatternFieldSpecified() { + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + tool + .run( + ImmutableMap.of("index", "index_name", "input", "{}", "pattern_field", "field3", "sample_log_size", "2"), + ActionListener + .wrap( + response -> fail(), + e -> MatcherAssert + .assertThat( + e.getMessage(), + containsString( + "Invalid parameter pattern_field: pattern field field3 in index index_name is not type of String" + ) + ) + ) + ); + } + + @SneakyThrows + @Test + public void testExecutionFailedWithNoStringPatternField() { + List fields = List.of("field1", "field2", "field3"); + SearchHit[] hits = new SearchHit[] { createHit(0, null, fields, List.of(1, 123, 12345)), }; + SearchResponse searchResponse = mock(SearchResponse.class); + SearchHits searchHits = mock(SearchHits.class); + doAnswer(invocation -> { + ActionListener listener = (ActionListener) invocation.getArguments()[1]; + listener.onResponse(searchResponse); + return null; + }).when(client).search(any(), any()); + when(searchResponse.getHits()).thenReturn(searchHits); + when(searchHits.getHits()).thenReturn(hits); + + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + tool + .run( + ImmutableMap.of("index", "index_name", "input", "{}"), + ActionListener + .wrap( + response -> fail(), + e -> MatcherAssert + .assertThat( + e.getMessage(), + containsString("Pattern field is not set and this index doesn't contain any string field") + ) + ) + ); + } + + @SneakyThrows + @Test + public void testExecutionFailedWithNonExistPatternFieldSpecified() { + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + tool + .run( + ImmutableMap.of("index", "index_name", "input", "{}", "pattern_field", "field4", "sample_log_size", "2"), + ActionListener + .wrap( + response -> fail(), + e -> MatcherAssert + .assertThat( + e.getMessage(), + containsString("Invalid parameter pattern_field: index index_name does not have a field named field4") + ) + ) + ); + } + + @SneakyThrows + @Test + public void testExecutionWithNoHits() { + SearchHit[] hits = new SearchHit[] {}; + SearchResponse searchResponse = mock(SearchResponse.class); + SearchHits searchHits = mock(SearchHits.class); + doAnswer(invocation -> { + ActionListener listener = (ActionListener) invocation.getArguments()[1]; + listener.onResponse(searchResponse); + return null; + }).when(client).search(any(), any()); + when(searchResponse.getHits()).thenReturn(searchHits); + when(searchHits.getHits()).thenReturn(hits); + + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + tool + .run( + ImmutableMap.of("index", "index_name", "input", "{}"), + ActionListener + .wrap( + response -> assertEquals("Can not get any match from search result.", response), + e -> fail("Tool runs failed: " + e.getMessage()) + ) + ); + } + + @SneakyThrows + @Test + public void testExecutionFailedInSearch() { + doAnswer(invocation -> { + ActionListener listener = (ActionListener) invocation.getArguments()[1]; + listener.onFailure(new Exception("Failed in Search")); + return null; + }).when(client).search(any(), any()); + + LogPatternTool tool = LogPatternTool.Factory.getInstance().create(params); + tool + .run( + ImmutableMap.of("index", "index_name", "input", "{}"), + ActionListener.wrap(response -> fail(), e -> assertEquals("Failed in Search", e.getMessage())) + ); + } } diff --git a/src/test/java/org/opensearch/integTest/LogPatternToolIT.java b/src/test/java/org/opensearch/integTest/LogPatternToolIT.java new file mode 100644 index 00000000..39ce1e98 --- /dev/null +++ b/src/test/java/org/opensearch/integTest/LogPatternToolIT.java @@ -0,0 +1,193 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.opensearch.integTest; + +import static org.hamcrest.Matchers.containsString; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.hamcrest.MatcherAssert; +import org.junit.After; +import org.junit.Before; +import org.opensearch.client.ResponseException; + +import com.google.gson.JsonElement; + +import lombok.SneakyThrows; + +public class LogPatternToolIT extends BaseAgentToolsIT { + + public static String requestBodyResourceFile = "org/opensearch/agent/tools/register_flow_agent_of_log_pattern_tool_request_body.json"; + public static String responseBodyResourceFile = "org/opensearch/agent/tools/expected_flow_agent_of_log_pattern_tool_response_body.json"; + public String registerAgentRequestBody; + public static String TEST_PATTERN_INDEX_NAME = "test_pattern_index"; + + public LogPatternToolIT() {} + + @SneakyThrows + private void prepareIndex() { + // prepare index for neural sparse query type + createIndexWithConfiguration( + TEST_PATTERN_INDEX_NAME, + "{\n" + + " \"mappings\": {\n" + + " \"properties\": {\n" + + " \"field1\": {\n" + + " \"type\": \"text\"\n" + + " },\n" + + " \"field2\": {\n" + + " \"type\": \"text\"\n" + + " },\n" + + " \"field3\": {\n" + + " \"type\": \"integer\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}" + ); + addDocToIndex(TEST_PATTERN_INDEX_NAME, "0", List.of("field1", "field2", "field3"), List.of("123", "123.abc-AB * De /", 12345)); + addDocToIndex(TEST_PATTERN_INDEX_NAME, "1", List.of("field1", "field2", "field3"), List.of("123", "45.abc-AB * De /", 12345)); + addDocToIndex(TEST_PATTERN_INDEX_NAME, "2", List.of("field1", "field2", "field3"), List.of("123", "12.abc_AB * De /", 12345)); + addDocToIndex(TEST_PATTERN_INDEX_NAME, "3", List.of("field1", "field2", "field3"), List.of("123", "45.ab_AB * De /", 12345)); + addDocToIndex(TEST_PATTERN_INDEX_NAME, "4", List.of("field1", "field2", "field3"), List.of("123", ".abAB * De /", 12345)); + } + + private String agentId; + + @Before + @SneakyThrows + public void setUp() { + super.setUp(); + prepareIndex(); + registerAgentRequestBody = Files.readString(Path.of(this.getClass().getClassLoader().getResource(requestBodyResourceFile).toURI())); + agentId = createAgent(registerAgentRequestBody); + } + + @After + @SneakyThrows + public void tearDown() { + super.tearDown(); + deleteExternalIndices(); + } + + @SneakyThrows + public void testLogPatternToolDefault() { + JsonElement expected = gson + .fromJson( + Files.readString(Path.of(this.getClass().getClassLoader().getResource(responseBodyResourceFile).toURI())), + JsonElement.class + ); + JsonElement result = gson + .fromJson( + executeAgent( + agentId, + String.format("{\"parameters\": {\"index\": \"%s\", \"input\": \"%s\"}}", TEST_PATTERN_INDEX_NAME, "{}") + ), + JsonElement.class + ); + assertEquals(expected, result); + } + + @SneakyThrows + public void testLogPatternToolWithSpecifiedPatternField() { + JsonElement expected = gson + .fromJson( + "[{\"total count\":5,\"sample logs\":[{\"field1\":\"123\",\"field3\":12345,\"field2\":\"123.abc-AB * De /\"},{\"field1\":\"123\",\"field3\":12345,\"field2\":\"45.abc-AB * De /\"}],\"pattern\":\"\"}]", + JsonElement.class + ); + JsonElement result = gson + .fromJson( + executeAgent( + agentId, + String + .format( + "{\"parameters\": {\"index\": \"%s\", \"pattern_field\": \"field1\", \"sample_log_size\": 2, \"input\": \"%s\"}}", + TEST_PATTERN_INDEX_NAME, + "{}" + ) + ), + JsonElement.class + ); + assertEquals(expected, result); + } + + public void testLogPatternToolWithNonStringPatternField() { + Exception exception = assertThrows( + ResponseException.class, + () -> executeAgent( + agentId, + String + .format( + "{\"parameters\": {\"index\": \"%s\", \"pattern_field\": \"field3\", \"sample_log_size\": 2, \"input\": \"%s\"}}", + TEST_PATTERN_INDEX_NAME, + "{}" + ) + ) + ); + MatcherAssert + .assertThat( + exception.getMessage(), + containsString("Invalid parameter pattern_field: pattern field field3 in index test_pattern_index is not type of String") + ); + } + + public void testLogPatternToolWithNonExistField() { + Exception exception = assertThrows( + ResponseException.class, + () -> executeAgent( + agentId, + String + .format( + "{\"parameters\": {\"index\": \"%s\", \"pattern_field\": \"field4\", \"sample_log_size\": 2, \"input\": \"%s\"}}", + TEST_PATTERN_INDEX_NAME, + "{}" + ) + ) + ); + MatcherAssert + .assertThat( + exception.getMessage(), + containsString("Invalid parameter pattern_field: index test_pattern_index does not have a field named field4") + ); + } + + public void testLogPatternToolWithNonIntegerSampleLogSize() { + Exception exception = assertThrows( + ResponseException.class, + () -> executeAgent( + agentId, + String + .format( + "{\"parameters\": {\"index\": \"%s\", \"sample_log_size\": 1.5, \"input\": \"%s\"}}", + TEST_PATTERN_INDEX_NAME, + "{}" + ) + ) + ); + MatcherAssert + .assertThat(exception.getMessage(), containsString("\"Invalid value 1.5 for parameter sample_log_size, it should be a number")); + } + + public void testLogPatternToolWithNonPositiveSampleLogSize() { + Exception exception = assertThrows( + ResponseException.class, + () -> executeAgent( + agentId, + String + .format( + "{\"parameters\": {\"index\": \"%s\", \"sample_log_size\": -1, \"input\": \"%s\"}}", + TEST_PATTERN_INDEX_NAME, + "{}" + ) + ) + ); + MatcherAssert + .assertThat(exception.getMessage(), containsString("\"Invalid value -1 for parameter sample_log_size, it should be positive")); + } + +} diff --git a/src/test/resources/org/opensearch/agent/tools/expected_flow_agent_of_log_pattern_tool_response_body.json b/src/test/resources/org/opensearch/agent/tools/expected_flow_agent_of_log_pattern_tool_response_body.json new file mode 100644 index 00000000..7ba8659c --- /dev/null +++ b/src/test/resources/org/opensearch/agent/tools/expected_flow_agent_of_log_pattern_tool_response_body.json @@ -0,0 +1,45 @@ +[ + { + "pattern": "._ * /", + "sample logs": [ + { + "field1": "123", + "field3": 12345, + "field2": "12.abc_AB * De /" + }, + { + "field1": "123", + "field3": 12345, + "field2": "45.ab_AB * De /" + } + ], + "total count": 2 + }, + { + "pattern": ".- * /", + "sample logs": [ + { + "field1": "123", + "field3": 12345, + "field2": "123.abc-AB * De /" + }, + { + "field1": "123", + "field3": 12345, + "field2": "45.abc-AB * De /" + } + ], + "total count": 2 + }, + { + "pattern": ". * /", + "sample logs": [ + { + "field1": "123", + "field3": 12345, + "field2": ".abAB * De /" + } + ], + "total count": 1 + } +] diff --git a/src/test/resources/org/opensearch/agent/tools/register_flow_agent_of_log_pattern_tool_request_body.json b/src/test/resources/org/opensearch/agent/tools/register_flow_agent_of_log_pattern_tool_request_body.json new file mode 100644 index 00000000..c125629b --- /dev/null +++ b/src/test/resources/org/opensearch/agent/tools/register_flow_agent_of_log_pattern_tool_request_body.json @@ -0,0 +1,12 @@ +{ + "name": "Test_log_pattern_tool_flow_agent", + "type": "flow", + "tools": [ + { + "type": "LogPatternTool", + "parameters": { + "doc_size": 100 + } + } + ] +} From 2e6291e0a0b20f4a8a2929695fde47ff06f939b5 Mon Sep 17 00:00:00 2001 From: zane-neo Date: Fri, 11 Oct 2024 15:57:29 +0800 Subject: [PATCH 2/2] Backport/backport 421 to 2.x (#429) * Fix test failure due to external change (#427) Signed-off-by: gaobinlong * Add IT for LogPatternTool (#421) * Add IT for LogPatternTool Signed-off-by: Heng Qian * spotlessApply Signed-off-by: Heng Qian --------- Signed-off-by: Heng Qian (cherry picked from commit a45af948805c0541e5773c00561c9df9789d1374) Signed-off-by: github-actions[bot] --------- Signed-off-by: gaobinlong Signed-off-by: Heng Qian Signed-off-by: github-actions[bot] Co-authored-by: gaobinlong Co-authored-by: github-actions[bot] --- .../opensearch/agent/tools/SearchAnomalyDetectorsToolTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/org/opensearch/agent/tools/SearchAnomalyDetectorsToolTests.java b/src/test/java/org/opensearch/agent/tools/SearchAnomalyDetectorsToolTests.java index f7ab651e..63e64da3 100644 --- a/src/test/java/org/opensearch/agent/tools/SearchAnomalyDetectorsToolTests.java +++ b/src/test/java/org/opensearch/agent/tools/SearchAnomalyDetectorsToolTests.java @@ -94,6 +94,7 @@ public void setup() { null, null, null, + null, null ); }