Skip to content

Commit 04c58f4

Browse files
committed
ShardFailure response should not require a 'primary' property
Signed-off-by: Jan Høydahl <jan.git@cominvent.com>
1 parent fc4d9b2 commit 04c58f4

2 files changed

Lines changed: 110 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
2929
### Removed
3030

3131
### Fixed
32+
- Fixed deserialization failure when OpenSearch returns shard failures without the `primary` field in error responses by upgrading version of `opensearch-api-specification`
3233

3334
### Security
3435

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*/
8+
9+
package org.opensearch.client.opensearch._types;
10+
11+
import static org.junit.Assert.assertEquals;
12+
import static org.junit.Assert.assertNotNull;
13+
import static org.junit.Assert.assertNull;
14+
import static org.junit.Assert.assertTrue;
15+
16+
import jakarta.json.stream.JsonParser;
17+
import java.io.StringReader;
18+
import org.junit.Test;
19+
import org.opensearch.client.json.JsonpMapper;
20+
import org.opensearch.client.json.jackson.JacksonJsonpMapper;
21+
22+
public class ShardFailureTest {
23+
24+
private final JsonpMapper mapper = new JacksonJsonpMapper();
25+
26+
@Test
27+
public void testShardFailureWithPrimaryField() {
28+
String json = "{"
29+
+ "\"shard\": 0,"
30+
+ "\"index\": \"test-index\","
31+
+ "\"node\": \"node-123\","
32+
+ "\"primary\": true,"
33+
+ "\"reason\": {"
34+
+ " \"type\": \"query_shard_exception\","
35+
+ " \"reason\": \"Failed to parse query\""
36+
+ "}"
37+
+ "}";
38+
39+
JsonParser parser = mapper.jsonProvider().createParser(new StringReader(json));
40+
ShardFailure shardFailure = ShardFailure._DESERIALIZER.deserialize(parser, mapper);
41+
42+
assertNotNull(shardFailure);
43+
assertEquals(0, shardFailure.shard());
44+
assertEquals("test-index", shardFailure.index());
45+
assertEquals("node-123", shardFailure.node());
46+
assertNotNull(shardFailure.primary());
47+
assertTrue(shardFailure.primary());
48+
assertNotNull(shardFailure.reason());
49+
assertEquals("query_shard_exception", shardFailure.reason().type());
50+
}
51+
52+
@Test
53+
public void testShardFailureWithoutPrimaryField() {
54+
// This is the real-world case that fails - OpenSearch often omits the "primary" field
55+
String json = "{"
56+
+ "\"shard\": 0,"
57+
+ "\"index\": \"cases-p360\","
58+
+ "\"node\": \"h88XL3ygSy2OxP0Ak-YIdA\","
59+
+ "\"reason\": {"
60+
+ " \"type\": \"query_shard_exception\","
61+
+ " \"reason\": \"Failed to execute query\""
62+
+ "}"
63+
+ "}";
64+
65+
JsonParser parser = mapper.jsonProvider().createParser(new StringReader(json));
66+
ShardFailure shardFailure = ShardFailure._DESERIALIZER.deserialize(parser, mapper);
67+
68+
assertNotNull(shardFailure);
69+
assertEquals(0, shardFailure.shard());
70+
assertEquals("cases-p360", shardFailure.index());
71+
assertEquals("h88XL3ygSy2OxP0Ak-YIdA", shardFailure.node());
72+
// Primary field should be null when not present in JSON
73+
assertNull(shardFailure.primary());
74+
assertNotNull(shardFailure.reason());
75+
assertEquals("query_shard_exception", shardFailure.reason().type());
76+
}
77+
78+
@Test
79+
public void testErrorCauseWithFailedShards() {
80+
// Test a more complete error response with failed_shards array
81+
// This verifies that ErrorCause can be deserialized when it contains
82+
// a failed_shards array with ShardFailure objects missing the primary field
83+
String json = "{"
84+
+ "\"type\": \"search_phase_execution_exception\","
85+
+ "\"reason\": \"all shards failed\","
86+
+ "\"metadata\": {"
87+
+ " \"failed_shards\": ["
88+
+ " {"
89+
+ " \"shard\": 0,"
90+
+ " \"index\": \"test-index\","
91+
+ " \"node\": \"node-1\","
92+
+ " \"reason\": {"
93+
+ " \"type\": \"query_shard_exception\","
94+
+ " \"reason\": \"Parse error\""
95+
+ " }"
96+
+ " }"
97+
+ " ]"
98+
+ "}"
99+
+ "}";
100+
101+
JsonParser parser = mapper.jsonProvider().createParser(new StringReader(json));
102+
ErrorCause errorCause = ErrorCause._DESERIALIZER.deserialize(parser, mapper);
103+
104+
// The main goal is to verify deserialization succeeds without throwing
105+
assertNotNull(errorCause);
106+
assertEquals("search_phase_execution_exception", errorCause.type());
107+
assertEquals("all shards failed", errorCause.reason());
108+
}
109+
}

0 commit comments

Comments
 (0)