Skip to content

Commit a251d26

Browse files
author
Hendrik Muhs
authored
[7.10][Transform] fix transform failure for configs with no field parameter… (#67380)
avoid illegal argument exception when fields is empty, which is a valid case fixes #67333
1 parent 0d3a486 commit a251d26

File tree

2 files changed

+132
-6
lines changed
  • x-pack/plugin/transform/src

2 files changed

+132
-6
lines changed

x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/transforms/pivot/SchemaUtil.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.xpack.core.transform.transforms.pivot.PivotConfig;
2525

2626
import java.math.BigDecimal;
27+
import java.util.Collections;
2728
import java.util.HashMap;
2829
import java.util.Map;
2930
import java.util.Objects;
@@ -249,12 +250,11 @@ private static Map<String, String> resolveMappings(
249250
/*
250251
* Very "magic" helper method to extract the source mappings
251252
*/
252-
private static void getSourceFieldMappings(
253-
Client client,
254-
String[] index,
255-
String[] fields,
256-
ActionListener<Map<String, String>> listener
257-
) {
253+
static void getSourceFieldMappings(Client client, String[] index, String[] fields, ActionListener<Map<String, String>> listener) {
254+
if (index == null || index.length == 0 || fields == null || fields.length == 0) {
255+
listener.onResponse(Collections.emptyMap());
256+
return;
257+
}
258258
FieldCapabilitiesRequest fieldCapabilitiesRequest = new FieldCapabilitiesRequest().indices(index)
259259
.fields(fields)
260260
.indicesOptions(IndicesOptions.LENIENT_EXPAND_OPEN);

x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/SchemaUtilTests.java

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,27 @@
66

77
package org.elasticsearch.xpack.transform.transforms.pivot;
88

9+
import org.elasticsearch.action.ActionListener;
10+
import org.elasticsearch.action.ActionRequest;
11+
import org.elasticsearch.action.ActionResponse;
12+
import org.elasticsearch.action.ActionType;
13+
import org.elasticsearch.action.LatchedActionListener;
14+
import org.elasticsearch.action.fieldcaps.FieldCapabilities;
15+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesRequest;
16+
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse;
17+
import org.elasticsearch.client.Client;
18+
import org.elasticsearch.common.Strings;
919
import org.elasticsearch.test.ESTestCase;
20+
import org.elasticsearch.test.client.NoOpClient;
1021

1122
import java.math.BigInteger;
23+
import java.util.Collections;
1224
import java.util.HashMap;
1325
import java.util.Map;
26+
import java.util.concurrent.CountDownLatch;
27+
import java.util.concurrent.TimeUnit;
28+
import java.util.concurrent.atomic.AtomicBoolean;
29+
import java.util.function.Consumer;
1430

1531
import static org.hamcrest.CoreMatchers.instanceOf;
1632

@@ -69,4 +85,114 @@ public void testConvertToIntegerTypeIfNeeded() {
6985
assertEquals(new BigInteger("18446744073709551615").doubleValue(), ((BigInteger) value).doubleValue(), 0.0);
7086
}
7187

88+
public void testGetSourceFieldMappings() throws InterruptedException {
89+
try (Client client = new FieldCapsMockClient(getTestName())) {
90+
// fields is null
91+
this.<Map<String, String>>assertAsync(
92+
listener -> SchemaUtil.getSourceFieldMappings(client, new String[] { "index-1", "index-2" }, null, listener),
93+
mappings -> {
94+
assertNotNull(mappings);
95+
assertTrue(mappings.isEmpty());
96+
}
97+
);
98+
99+
// fields is empty
100+
this.<Map<String, String>>assertAsync(
101+
listener -> SchemaUtil.getSourceFieldMappings(client, new String[] { "index-1", "index-2" }, new String[] {}, listener),
102+
mappings -> {
103+
assertNotNull(mappings);
104+
assertTrue(mappings.isEmpty());
105+
}
106+
);
107+
108+
// indices is null
109+
this.<Map<String, String>>assertAsync(
110+
listener -> SchemaUtil.getSourceFieldMappings(client, null, new String[] { "field-1", "field-2" }, listener),
111+
mappings -> {
112+
assertNotNull(mappings);
113+
assertTrue(mappings.isEmpty());
114+
}
115+
);
116+
117+
// indices is empty
118+
this.<Map<String, String>>assertAsync(
119+
listener -> SchemaUtil.getSourceFieldMappings(client, new String[] {}, new String[] { "field-1", "field-2" }, listener),
120+
mappings -> {
121+
assertNotNull(mappings);
122+
assertTrue(mappings.isEmpty());
123+
}
124+
);
125+
126+
// good use
127+
this.<Map<String, String>>assertAsync(
128+
listener -> SchemaUtil.getSourceFieldMappings(
129+
client,
130+
new String[] { "index-1", "index-2" },
131+
new String[] { "field-1", "field-2" },
132+
listener
133+
),
134+
mappings -> {
135+
assertNotNull(mappings);
136+
assertEquals(2, mappings.size());
137+
assertEquals("long", mappings.get("field-1"));
138+
assertEquals("long", mappings.get("field-2"));
139+
}
140+
);
141+
}
142+
}
143+
144+
private static class FieldCapsMockClient extends NoOpClient {
145+
FieldCapsMockClient(String testName) {
146+
super(testName);
147+
}
148+
149+
@SuppressWarnings("unchecked")
150+
@Override
151+
protected <Request extends ActionRequest, Response extends ActionResponse> void doExecute(
152+
ActionType<Response> action,
153+
Request request,
154+
ActionListener<Response> listener
155+
) {
156+
if (request instanceof FieldCapabilitiesRequest) {
157+
FieldCapabilitiesRequest fieldCapsRequest = (FieldCapabilitiesRequest) request;
158+
Map<String, Map<String, FieldCapabilities>> responseMap = new HashMap<>();
159+
for (String field : fieldCapsRequest.fields()) {
160+
responseMap.put(field, Collections.singletonMap(field, createFieldCapabilities(field, "long")));
161+
}
162+
163+
final FieldCapabilitiesResponse response = new FieldCapabilitiesResponse(fieldCapsRequest.indices(), responseMap);
164+
listener.onResponse((Response) response);
165+
return;
166+
}
167+
168+
super.doExecute(action, request, listener);
169+
}
170+
}
171+
172+
private static FieldCapabilities createFieldCapabilities(String name, String type) {
173+
return new FieldCapabilities(
174+
name,
175+
type,
176+
true,
177+
true,
178+
Strings.EMPTY_ARRAY,
179+
Strings.EMPTY_ARRAY,
180+
Strings.EMPTY_ARRAY,
181+
Collections.emptyMap()
182+
);
183+
}
184+
185+
private <T> void assertAsync(Consumer<ActionListener<T>> function, Consumer<T> furtherTests) throws InterruptedException {
186+
CountDownLatch latch = new CountDownLatch(1);
187+
AtomicBoolean listenerCalled = new AtomicBoolean(false);
188+
189+
LatchedActionListener<T> listener = new LatchedActionListener<>(ActionListener.wrap(r -> {
190+
assertTrue("listener called more than once", listenerCalled.compareAndSet(false, true));
191+
furtherTests.accept(r);
192+
}, e -> { fail("got unexpected exception: " + e); }), latch);
193+
194+
function.accept(listener);
195+
assertTrue("timed out after 20s", latch.await(20, TimeUnit.SECONDS));
196+
}
197+
72198
}

0 commit comments

Comments
 (0)