diff --git a/src/test/java/org/codelibs/fesen/client/action/HttpActionTest.java b/src/test/java/org/codelibs/fesen/client/action/HttpActionTest.java new file mode 100644 index 0000000..bf25635 --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/action/HttpActionTest.java @@ -0,0 +1,166 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; +import org.opensearch.OpenSearchException; +import org.opensearch.action.support.ActiveShardCount; +import org.opensearch.common.xcontent.XContentType; +import org.opensearch.core.xcontent.MediaType; + +class HttpActionTest { + + private final HttpAction action = new HttpAction(null); + + @Test + void test_fromMediaTypeOrFormat_json() { + final MediaType result = HttpAction.fromMediaTypeOrFormat("application/json"); + assertEquals(XContentType.JSON, result); + } + + @Test + void test_fromMediaTypeOrFormat_jsonWithCharset() { + final MediaType result = HttpAction.fromMediaTypeOrFormat("application/json; charset=UTF-8"); + assertEquals(XContentType.JSON, result); + } + + @Test + void test_fromMediaTypeOrFormat_yaml() { + final MediaType result = HttpAction.fromMediaTypeOrFormat("application/yaml"); + assertEquals(XContentType.YAML, result); + } + + @Test + void test_fromMediaTypeOrFormat_cbor() { + final MediaType result = HttpAction.fromMediaTypeOrFormat("application/cbor"); + assertEquals(XContentType.CBOR, result); + } + + @Test + void test_fromMediaTypeOrFormat_smile() { + final MediaType result = HttpAction.fromMediaTypeOrFormat("application/smile"); + assertEquals(XContentType.SMILE, result); + } + + @Test + void test_fromMediaTypeOrFormat_null_defaultsToJson() { + final MediaType result = HttpAction.fromMediaTypeOrFormat(null); + assertEquals(XContentType.JSON, result); + } + + @Test + void test_fromMediaTypeOrFormat_unknown_defaultsToJson() { + final MediaType result = HttpAction.fromMediaTypeOrFormat("text/plain"); + assertEquals(XContentType.JSON, result); + } + + @Test + void test_fromMediaTypeOrFormat_subtypeOnly() { + final MediaType result = HttpAction.fromMediaTypeOrFormat("json"); + assertEquals(XContentType.JSON, result); + } + + @Test + void test_getActiveShardsCountValue_all() throws IOException { + final int value = action.getActiveShardsCountValue(ActiveShardCount.ALL); + assertEquals(-1, value); + } + + @Test + void test_getActiveShardsCountValue_default() throws IOException { + final int value = action.getActiveShardsCountValue(ActiveShardCount.DEFAULT); + assertEquals(-2, value); + } + + @Test + void test_getActiveShardsCountValue_one() throws IOException { + final int value = action.getActiveShardsCountValue(ActiveShardCount.ONE); + assertEquals(1, value); + } + + @Test + void test_getActiveShardsCountValue_none() throws IOException { + final int value = action.getActiveShardsCountValue(ActiveShardCount.NONE); + assertEquals(0, value); + } + + @Test + void test_getActiveShardsCountValue_customValue() throws IOException { + final int value = action.getActiveShardsCountValue(ActiveShardCount.from(3)); + assertEquals(3, value); + } + + @Test + void test_unwrapOpenSearchException_withOpenSearchCause() { + final OpenSearchException cause = new OpenSearchException("inner error"); + final Exception wrapper = new RuntimeException("outer", cause); + final boolean[] called = { false }; + action.unwrapOpenSearchException(new org.opensearch.core.action.ActionListener<>() { + @Override + public void onResponse(final Object o) { + } + + @Override + public void onFailure(final Exception e) { + called[0] = true; + assertEquals(cause, e); + } + }, wrapper); + assertEquals(true, called[0]); + } + + @Test + void test_unwrapOpenSearchException_withoutOpenSearchCause() { + final RuntimeException original = new RuntimeException("direct error"); + final boolean[] called = { false }; + action.unwrapOpenSearchException(new org.opensearch.core.action.ActionListener<>() { + @Override + public void onResponse(final Object o) { + } + + @Override + public void onFailure(final Exception e) { + called[0] = true; + assertEquals(original, e); + } + }, original); + assertEquals(true, called[0]); + } + + @Test + void test_parseFields_areNotNull() { + assertNotNull(HttpAction.SHARD_FIELD); + assertNotNull(HttpAction.INDEX_FIELD); + assertNotNull(HttpAction.QUERY_FIELD); + assertNotNull(HttpAction.REASON_FIELD); + assertNotNull(HttpAction.ALIASES_FIELD); + assertNotNull(HttpAction.MAPPINGS_FIELD); + assertNotNull(HttpAction.TYPE_FIELD); + assertNotNull(HttpAction.DETAILS_FIELD); + assertNotNull(HttpAction._SHARDS_FIELD); + assertNotNull(HttpAction.TASKS_FIELD); + assertNotNull(HttpAction.TOTAL_FIELD); + assertNotNull(HttpAction.SUCCESSFUL_FIELD); + assertNotNull(HttpAction.FAILED_FIELD); + assertNotNull(HttpAction.FAILURES_FIELD); + } +} diff --git a/src/test/java/org/codelibs/fesen/client/action/HttpBulkActionTest.java b/src/test/java/org/codelibs/fesen/client/action/HttpBulkActionTest.java new file mode 100644 index 0000000..03c3e9f --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/action/HttpBulkActionTest.java @@ -0,0 +1,152 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; +import org.opensearch.action.bulk.BulkAction; +import org.opensearch.action.bulk.BulkResponse; +import org.opensearch.action.delete.DeleteRequest; +import org.opensearch.action.index.IndexRequest; +import org.opensearch.common.xcontent.XContentType; +import org.opensearch.common.xcontent.json.JsonXContent; +import org.opensearch.core.xcontent.DeprecationHandler; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.core.xcontent.XContentParser; + +class HttpBulkActionTest { + + private final HttpBulkAction action = new HttpBulkAction(null, BulkAction.INSTANCE); + + @Test + void test_getStringfromDocWriteRequest_indexWithId() { + final IndexRequest request = new IndexRequest("test-index").id("doc1").source("{\"field\":\"value\"}", XContentType.JSON); + final String result = action.getStringfromDocWriteRequest(request); + assertTrue(result.contains("\"index\"")); + assertTrue(result.contains("\"_index\":\"test-index\"")); + assertTrue(result.contains("\"_id\":\"doc1\"")); + } + + @Test + void test_getStringfromDocWriteRequest_indexWithoutId() { + final IndexRequest request = new IndexRequest("test-index").source("{\"field\":\"value\"}", XContentType.JSON); + request.id(null); + final String result = action.getStringfromDocWriteRequest(request); + assertTrue(result.contains("\"index\"") || result.contains("\"create\"")); + assertTrue(result.contains("\"_index\":\"test-index\"")); + assertFalse(result.contains("\"_id\"")); + } + + @Test + void test_getStringfromDocWriteRequest_delete() { + final DeleteRequest request = new DeleteRequest("test-index", "doc1"); + final String result = action.getStringfromDocWriteRequest(request); + assertTrue(result.contains("\"delete\"")); + assertTrue(result.contains("\"_index\":\"test-index\"")); + assertTrue(result.contains("\"_id\":\"doc1\"")); + } + + @Test + void test_getStringfromDocWriteRequest_withRouting() { + final IndexRequest request = + new IndexRequest("test-index").id("doc1").routing("r1").source("{\"field\":\"value\"}", XContentType.JSON); + final String result = action.getStringfromDocWriteRequest(request); + assertTrue(result.contains("\"routing\":\"r1\"")); + } + + @Test + void test_getStringfromDocWriteRequest_withPipeline() { + final IndexRequest request = + new IndexRequest("test-index").id("doc1").setPipeline("my-pipeline").source("{\"field\":\"value\"}", XContentType.JSON); + final String result = action.getStringfromDocWriteRequest(request); + assertTrue(result.contains("\"pipeline\":\"my-pipeline\"")); + } + + @Test + void test_fromXContent_emptyBulkResponse() throws IOException { + final String json = "{\"took\":10,\"errors\":false,\"items\":[]}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final BulkResponse response = action.fromXContent(parser); + assertNotNull(response); + assertEquals(10, response.getTook().millis()); + assertFalse(response.hasFailures()); + assertEquals(0, response.getItems().length); + } + } + + @Test + void test_fromXContent_withIngestTook() throws IOException { + final String json = "{\"took\":5,\"ingest_took\":3,\"errors\":false,\"items\":[]}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final BulkResponse response = action.fromXContent(parser); + assertNotNull(response); + assertEquals(5, response.getTook().millis()); + assertEquals(3, response.getIngestTookInMillis()); + } + } + + @Test + void test_fromXContent_withIndexItem() throws IOException { + final String json = "{\"took\":1,\"errors\":false,\"items\":[{\"index\":{\"_index\":\"test\",\"_id\":\"1\"," + + "\"_version\":1,\"result\":\"created\",\"_shards\":{\"total\":2,\"successful\":1,\"failed\":0}," + + "\"_seq_no\":0,\"_primary_term\":1,\"status\":201}}]}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final BulkResponse response = action.fromXContent(parser); + assertNotNull(response); + assertEquals(1, response.getItems().length); + assertEquals("test", response.getItems()[0].getIndex()); + assertEquals("1", response.getItems()[0].getId()); + assertFalse(response.getItems()[0].isFailed()); + } + } + + @Test + void test_fromXContent_withDeleteItem() throws IOException { + final String json = "{\"took\":1,\"errors\":false,\"items\":[{\"delete\":{\"_index\":\"test\",\"_id\":\"1\"," + + "\"_version\":2,\"result\":\"deleted\",\"_shards\":{\"total\":2,\"successful\":1,\"failed\":0}," + + "\"_seq_no\":1,\"_primary_term\":1,\"status\":200}}]}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final BulkResponse response = action.fromXContent(parser); + assertNotNull(response); + assertEquals(1, response.getItems().length); + assertFalse(response.getItems()[0].isFailed()); + } + } + + @Test + void test_fromXContent_withFailedItem() throws IOException { + final String json = "{\"took\":1,\"errors\":true,\"items\":[{\"index\":{\"_index\":\"test\",\"_id\":\"1\"," + + "\"status\":400,\"error\":{\"type\":\"mapper_parsing_exception\"," + "\"reason\":\"failed to parse\"}}}]}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final BulkResponse response = action.fromXContent(parser); + assertNotNull(response); + assertTrue(response.hasFailures()); + assertEquals(1, response.getItems().length); + assertTrue(response.getItems()[0].isFailed()); + } + } +} diff --git a/src/test/java/org/codelibs/fesen/client/action/HttpDeleteActionTest.java b/src/test/java/org/codelibs/fesen/client/action/HttpDeleteActionTest.java new file mode 100644 index 0000000..df9e8ac --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/action/HttpDeleteActionTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; +import org.opensearch.action.delete.DeleteAction; +import org.opensearch.action.delete.DeleteResponse; +import org.opensearch.common.xcontent.json.JsonXContent; +import org.opensearch.core.xcontent.DeprecationHandler; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.core.xcontent.XContentParser; + +class HttpDeleteActionTest { + + private final HttpDeleteAction action = new HttpDeleteAction(null, DeleteAction.INSTANCE); + + @Test + void test_fromXContent_deleted() throws IOException { + final String json = "{\"_index\":\"test\",\"_id\":\"1\",\"_version\":2,\"result\":\"deleted\"," + + "\"_shards\":{\"total\":2,\"successful\":1,\"failed\":0}," + "\"_seq_no\":1,\"_primary_term\":1}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final DeleteResponse response = action.fromXContent(parser); + assertNotNull(response); + assertEquals("test", response.getIndex()); + assertEquals("1", response.getId()); + assertEquals(2, response.getVersion()); + assertEquals("deleted", response.getResult().getLowercase()); + } + } + + @Test + void test_fromXContent_notFound() throws IOException { + final String json = "{\"_index\":\"test\",\"_id\":\"1\",\"_version\":1,\"result\":\"not_found\"," + + "\"_shards\":{\"total\":2,\"successful\":1,\"failed\":0}," + "\"_seq_no\":2,\"_primary_term\":1}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final DeleteResponse response = action.fromXContent(parser); + assertNotNull(response); + assertEquals("not_found", response.getResult().getLowercase()); + } + } +} diff --git a/src/test/java/org/codelibs/fesen/client/action/HttpGetActionTest.java b/src/test/java/org/codelibs/fesen/client/action/HttpGetActionTest.java new file mode 100644 index 0000000..2a9c09f --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/action/HttpGetActionTest.java @@ -0,0 +1,30 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.action; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; +import org.opensearch.action.get.GetAction; + +class HttpGetActionTest { + + @Test + void test_construction() { + final HttpGetAction action = new HttpGetAction(null, GetAction.INSTANCE); + assertNotNull(action); + } +} diff --git a/src/test/java/org/codelibs/fesen/client/action/HttpIndexActionTest.java b/src/test/java/org/codelibs/fesen/client/action/HttpIndexActionTest.java new file mode 100644 index 0000000..63cbe6b --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/action/HttpIndexActionTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; +import org.opensearch.action.index.IndexAction; +import org.opensearch.action.index.IndexResponse; +import org.opensearch.common.xcontent.json.JsonXContent; +import org.opensearch.core.xcontent.DeprecationHandler; +import org.opensearch.core.xcontent.NamedXContentRegistry; +import org.opensearch.core.xcontent.XContentParser; + +class HttpIndexActionTest { + + private final HttpIndexAction action = new HttpIndexAction(null, IndexAction.INSTANCE); + + @Test + void test_fromXContent_created() throws IOException { + final String json = "{\"_index\":\"test\",\"_id\":\"1\",\"_version\":1,\"result\":\"created\"," + + "\"_shards\":{\"total\":2,\"successful\":1,\"failed\":0}," + "\"_seq_no\":0,\"_primary_term\":1}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final IndexResponse response = action.fromXContent(parser); + assertNotNull(response); + assertEquals("test", response.getIndex()); + assertEquals("1", response.getId()); + assertEquals(1, response.getVersion()); + assertEquals("created", response.getResult().getLowercase()); + } + } + + @Test + void test_fromXContent_updated() throws IOException { + final String json = "{\"_index\":\"test\",\"_id\":\"1\",\"_version\":2,\"result\":\"updated\"," + + "\"_shards\":{\"total\":2,\"successful\":1,\"failed\":0}," + "\"_seq_no\":1,\"_primary_term\":1}"; + try (final XContentParser parser = + JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, json)) { + final IndexResponse response = action.fromXContent(parser); + assertNotNull(response); + assertEquals(2, response.getVersion()); + assertEquals("updated", response.getResult().getLowercase()); + } + } +} diff --git a/src/test/java/org/codelibs/fesen/client/action/HttpSearchActionTest.java b/src/test/java/org/codelibs/fesen/client/action/HttpSearchActionTest.java new file mode 100644 index 0000000..ad0bb8f --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/action/HttpSearchActionTest.java @@ -0,0 +1,111 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.action; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.opensearch.action.search.SearchAction; +import org.opensearch.action.search.SearchRequest; +import org.opensearch.index.query.QueryBuilders; +import org.opensearch.search.builder.SearchSourceBuilder; + +class HttpSearchActionTest { + + private final HttpSearchAction action = new HttpSearchAction(null, SearchAction.INSTANCE); + + @Test + void test_getQuerySource_withDefaultSource() { + final SearchRequest request = new SearchRequest("test-index"); + final String result = action.getQuerySource(request); + // SearchRequest initializes with a default SearchSourceBuilder, so result is not null + assertNotNull(result); + assertEquals("{}", result); + } + + @Test + void test_getQuerySource_withMatchAllQuery() { + final SearchRequest request = new SearchRequest("test-index"); + request.source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())); + final String result = action.getQuerySource(request); + assertNotNull(result); + assertTrue(result.contains("match_all")); + } + + @Test + void test_getQuerySource_withTermQuery() { + final SearchRequest request = new SearchRequest("test-index"); + request.source(new SearchSourceBuilder().query(QueryBuilders.termQuery("field1", "value1"))); + final String result = action.getQuerySource(request); + assertNotNull(result); + assertTrue(result.contains("term")); + assertTrue(result.contains("field1")); + assertTrue(result.contains("value1")); + } + + @Test + void test_getQuerySource_withSizeAndFrom() { + final SearchRequest request = new SearchRequest("test-index"); + request.source(new SearchSourceBuilder().size(10).from(20)); + final String result = action.getQuerySource(request); + assertNotNull(result); + assertTrue(result.contains("\"size\":10")); + assertTrue(result.contains("\"from\":20")); + } + + @Test + void test_getQuerySource_withBoolQuery() { + final SearchRequest request = new SearchRequest("test-index"); + request.source(new SearchSourceBuilder().query(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("status", "active")) + .mustNot(QueryBuilders.termQuery("deleted", true)))); + final String result = action.getQuerySource(request); + assertNotNull(result); + assertTrue(result.contains("bool")); + assertTrue(result.contains("must")); + assertTrue(result.contains("must_not")); + } + + @Test + void test_getQuerySource_withEmptySource() { + final SearchRequest request = new SearchRequest("test-index"); + request.source(new SearchSourceBuilder()); + final String result = action.getQuerySource(request); + assertNotNull(result); + } + + @Test + void test_getQuerySource_withSourceFiltering() { + final SearchRequest request = new SearchRequest("test-index"); + request.source(new SearchSourceBuilder().fetchSource(new String[] { "field1", "field2" }, new String[] { "excluded" })); + final String result = action.getQuerySource(request); + assertNotNull(result); + assertTrue(result.contains("_source")); + assertTrue(result.contains("field1")); + } + + @Test + void test_getQuerySource_withAggregation() { + final SearchRequest request = new SearchRequest("test-index"); + request.source(new SearchSourceBuilder().size(0) + .aggregation(org.opensearch.search.aggregations.AggregationBuilders.terms("by_status").field("status"))); + final String result = action.getQuerySource(request); + assertNotNull(result); + assertTrue(result.contains("aggs") || result.contains("aggregations")); + assertTrue(result.contains("by_status")); + } +} diff --git a/src/test/java/org/codelibs/fesen/client/action/indices/create/HttpCreateIndexRequestTest.java b/src/test/java/org/codelibs/fesen/client/action/indices/create/HttpCreateIndexRequestTest.java new file mode 100644 index 0000000..69de84c --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/action/indices/create/HttpCreateIndexRequestTest.java @@ -0,0 +1,111 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.action.indices.create; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.opensearch.action.admin.indices.create.CreateIndexRequest; + +class HttpCreateIndexRequestTest { + + @Test + void test_prepareMappings_withoutMappings() { + final Map source = new HashMap<>(); + source.put("settings", Map.of("number_of_shards", 1)); + final Map result = HttpCreateIndexRequest.prepareMappings(source); + assertEquals(source, result); + } + + @Test + void test_prepareMappings_withMappings() { + final Map mappings = new HashMap<>(); + mappings.put("properties", Map.of("field1", Map.of("type", "text"))); + + final Map source = new HashMap<>(); + source.put("mappings", mappings); + + final Map result = HttpCreateIndexRequest.prepareMappings(source); + assertNotNull(result.get("mappings")); + @SuppressWarnings("unchecked") + final Map resultMappings = (Map) result.get("mappings"); + assertTrue(resultMappings.containsKey("_doc")); + } + + @Test + void test_prepareMappings_withNonMapMappings() { + final Map source = new HashMap<>(); + source.put("mappings", "not a map"); + final Map result = HttpCreateIndexRequest.prepareMappings(source); + assertEquals(source, result); + } + + @Test + void test_prepareMappings_withTypedMappings_throwsException() { + final Map typedMappings = new HashMap<>(); + typedMappings.put("_doc", Map.of("properties", Map.of("field1", Map.of("type", "text")))); + + final Map source = new HashMap<>(); + source.put("mappings", typedMappings); + + assertThrows(IllegalArgumentException.class, () -> HttpCreateIndexRequest.prepareMappings(source)); + } + + @Test + void test_delegation_index() { + final CreateIndexRequest inner = new CreateIndexRequest("test-index"); + final HttpCreateIndexRequest request = new HttpCreateIndexRequest(inner); + assertEquals("test-index", request.index()); + } + + @Test + void test_delegation_settings() { + final CreateIndexRequest inner = new CreateIndexRequest("test-index"); + final HttpCreateIndexRequest request = new HttpCreateIndexRequest(inner); + assertNotNull(request.settings()); + } + + @Test + void test_delegation_aliases() { + final CreateIndexRequest inner = new CreateIndexRequest("test-index"); + final HttpCreateIndexRequest request = new HttpCreateIndexRequest(inner); + assertNotNull(request.aliases()); + assertTrue(request.aliases().isEmpty()); + } + + @Test + void test_delegation_mappings() { + final CreateIndexRequest inner = new CreateIndexRequest("test-index"); + inner.mapping("{\"properties\":{\"f1\":{\"type\":\"text\"}}}"); + final HttpCreateIndexRequest request = new HttpCreateIndexRequest(inner); + assertNotNull(request.mappings()); + assertTrue(request.mappings().contains("properties")); + } + + @Test + void test_delegation_cause() { + final CreateIndexRequest inner = new CreateIndexRequest("test-index"); + inner.cause("test-cause"); + final HttpCreateIndexRequest request = new HttpCreateIndexRequest(inner); + assertEquals("test-cause", request.cause()); + } +} diff --git a/src/test/java/org/codelibs/fesen/client/node/NodeIteratorTest.java b/src/test/java/org/codelibs/fesen/client/node/NodeIteratorTest.java new file mode 100644 index 0000000..3f7ffa5 --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/node/NodeIteratorTest.java @@ -0,0 +1,96 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.node; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashSet; +import java.util.NoSuchElementException; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +class NodeIteratorTest { + + @Test + void test_singleNode() { + final Node[] nodes = { new Node("http://server1:9200") }; + final NodeIterator iter = new NodeIterator(nodes); + assertTrue(iter.hasNext()); + final Node node = iter.next(); + assertEquals("[http://server1:9200][green]", node.toString()); + assertFalse(iter.hasNext()); + } + + @Test + void test_multipleNodes_iteratesAll() { + final Node[] nodes = { new Node("http://s1:9200"), new Node("http://s2:9200"), new Node("http://s3:9200") }; + final NodeIterator iter = new NodeIterator(nodes); + final Set visited = new HashSet<>(); + while (iter.hasNext()) { + visited.add(iter.next().toString()); + } + assertEquals(3, visited.size()); + } + + @Test + void test_next_throwsNoSuchElementException() { + final Node[] nodes = { new Node("http://server1:9200") }; + final NodeIterator iter = new NodeIterator(nodes); + iter.next(); + assertThrows(NoSuchElementException.class, iter::next); + } + + @Test + void test_roundRobin_distributesStartPosition() { + final Node[] nodes = { new Node("http://s1:9200"), new Node("http://s2:9200"), new Node("http://s3:9200") }; + final Set firstNodes = new HashSet<>(); + for (int i = 0; i < 10; i++) { + final NodeIterator iter = new NodeIterator(nodes); + firstNodes.add(iter.next().toString()); + } + // Over 10 iterations with 3 nodes, we should see more than 1 different starting node + assertTrue(firstNodes.size() > 1); + } + + @Test + void test_hasNext_doesNotAdvance() { + final Node[] nodes = { new Node("http://server1:9200") }; + final NodeIterator iter = new NodeIterator(nodes); + assertTrue(iter.hasNext()); + assertTrue(iter.hasNext()); + assertTrue(iter.hasNext()); + iter.next(); + assertFalse(iter.hasNext()); + } + + @Test + void test_wrapsAroundArrayBoundary() { + final Node[] nodes = { new Node("http://s1:9200"), new Node("http://s2:9200") }; + // Create multiple iterators to hit different starting positions + final Set allVisited = new HashSet<>(); + for (int i = 0; i < 5; i++) { + final NodeIterator iter = new NodeIterator(nodes); + while (iter.hasNext()) { + allVisited.add(iter.next().toString()); + } + } + assertEquals(2, allVisited.size()); + } +} diff --git a/src/test/java/org/codelibs/fesen/client/node/NodeTest.java b/src/test/java/org/codelibs/fesen/client/node/NodeTest.java new file mode 100644 index 0000000..4e37015 --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/node/NodeTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.node; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class NodeTest { + + @Test + void test_constructor() { + final Node node = new Node("http://localhost:9200"); + assertTrue(node.isAvailable()); + assertEquals("[http://localhost:9200][green]", node.toString()); + } + + @Test + void test_getUrl() { + final Node node = new Node("http://localhost:9200"); + assertEquals("http://localhost:9200/_search", node.getUrl("/_search")); + assertEquals("http://localhost:9200/", node.getUrl("/")); + assertEquals("http://localhost:9200", node.getUrl("")); + } + + @Test + void test_isAvailable_defaultTrue() { + final Node node = new Node("http://localhost:9200"); + assertTrue(node.isAvailable()); + } + + @Test + void test_setAvailable() { + final Node node = new Node("http://localhost:9200"); + assertTrue(node.isAvailable()); + + node.setAvailable(false); + assertFalse(node.isAvailable()); + + node.setAvailable(true); + assertTrue(node.isAvailable()); + } + + @Test + void test_toString_available() { + final Node node = new Node("http://server1:9200"); + assertEquals("[http://server1:9200][green]", node.toString()); + } + + @Test + void test_toString_unavailable() { + final Node node = new Node("http://server1:9200"); + node.setAvailable(false); + assertEquals("[http://server1:9200][red]", node.toString()); + } + + @Test + void test_concurrentAvailability() throws InterruptedException { + final Node node = new Node("http://localhost:9200"); + final Thread t1 = new Thread(() -> { + for (int i = 0; i < 1000; i++) { + node.setAvailable(false); + node.setAvailable(true); + } + }); + final Thread t2 = new Thread(() -> { + for (int i = 0; i < 1000; i++) { + node.isAvailable(); + } + }); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + // No exception means thread safety works + assertTrue(true); + } +} diff --git a/src/test/java/org/codelibs/fesen/client/util/UrlUtilsTest.java b/src/test/java/org/codelibs/fesen/client/util/UrlUtilsTest.java new file mode 100644 index 0000000..8274de9 --- /dev/null +++ b/src/test/java/org/codelibs/fesen/client/util/UrlUtilsTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012-2025 CodeLibs Project and the Others. + * + * Licensed 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.codelibs.fesen.client.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +class UrlUtilsTest { + + @Test + void test_encode_withSimpleString() { + assertEquals("hello", UrlUtils.encode("hello")); + } + + @Test + void test_encode_withNull() { + assertNull(UrlUtils.encode(null)); + } + + @Test + void test_encode_withSpecialCharacters() { + assertEquals("hello+world", UrlUtils.encode("hello world")); + assertEquals("%2F", UrlUtils.encode("/")); + assertEquals("%3A", UrlUtils.encode(":")); + assertEquals("%23", UrlUtils.encode("#")); + assertEquals("%3F", UrlUtils.encode("?")); + assertEquals("%26", UrlUtils.encode("&")); + assertEquals("%3D", UrlUtils.encode("=")); + } + + @Test + void test_encode_withUnicodeCharacters() { + final String encoded = UrlUtils.encode("\u65E5\u672C\u8A9E"); + assertEquals("%E6%97%A5%E6%9C%AC%E8%AA%9E", encoded); + } + + @Test + void test_encode_withEmptyString() { + assertEquals("", UrlUtils.encode("")); + } + + @Test + void test_joinAndEncode_withNull() { + assertNull(UrlUtils.joinAndEncode(",", (CharSequence[]) null)); + } + + @Test + void test_joinAndEncode_withSingleElement() { + assertEquals("index1", UrlUtils.joinAndEncode(",", "index1")); + } + + @Test + void test_joinAndEncode_withMultipleElements() { + assertEquals("index1,index2,index3", UrlUtils.joinAndEncode(",", "index1", "index2", "index3")); + } + + @Test + void test_joinAndEncode_withSpecialCharactersInElements() { + assertEquals("my+index,your+index", UrlUtils.joinAndEncode(",", "my index", "your index")); + } + + @Test + void test_joinAndEncode_withNullElement() { + final String result = UrlUtils.joinAndEncode(",", "index1", null, "index3"); + assertEquals("index1,null,index3", result); + } + + @Test + void test_joinAndEncode_withEmptyArray() { + assertEquals("", UrlUtils.joinAndEncode(",", new CharSequence[0])); + } + + @Test + void test_joinAndEncode_withDifferentDelimiter() { + assertEquals("a/b/c", UrlUtils.joinAndEncode("/", "a", "b", "c")); + } +}