Skip to content

Commit 68092d0

Browse files
authored
[7.17] [Transform] Adding null check to fix potential NPE (#96785) (#97109)
1 parent 4e3cc9b commit 68092d0

File tree

3 files changed

+113
-1
lines changed

3 files changed

+113
-1
lines changed

docs/changelog/96785.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 96785
2+
summary: Adding null check to fix potential NPE
3+
area: Transform
4+
type: enhancement
5+
issues:
6+
- 96781

x-pack/plugin/transform/src/main/java/org/elasticsearch/xpack/transform/transforms/common/AbstractCompositeAggFunction.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.elasticsearch.xpack.transform.transforms.Function;
3535
import org.elasticsearch.xpack.transform.transforms.pivot.AggregationResultUtils;
3636

37+
import java.util.Collections;
3738
import java.util.List;
3839
import java.util.Map;
3940
import java.util.stream.Collectors;
@@ -88,9 +89,13 @@ public void preview(
8889
return;
8990
}
9091
final CompositeAggregation agg = aggregations.get(COMPOSITE_AGGREGATION_NAME);
92+
if (agg == null || agg.getBuckets().isEmpty()) {
93+
listener.onResponse(Collections.emptyList());
94+
return;
95+
}
96+
9197
TransformIndexerStats stats = new TransformIndexerStats();
9298
TransformProgress progress = new TransformProgress();
93-
9499
List<Map<String, Object>> docs = extractResults(agg, fieldTypeMap, stats, progress).map(
95100
this::documentTransformationFunction
96101
).collect(Collectors.toList());

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

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import org.elasticsearch.search.SearchHit;
2727
import org.elasticsearch.search.SearchHits;
2828
import org.elasticsearch.search.SearchModule;
29+
import org.elasticsearch.search.aggregations.Aggregations;
30+
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregation;
2931
import org.elasticsearch.test.ESTestCase;
3032
import org.elasticsearch.test.client.NoOpClient;
3133
import org.elasticsearch.xcontent.DeprecationHandler;
@@ -35,12 +37,14 @@
3537
import org.elasticsearch.xcontent.json.JsonXContent;
3638
import org.elasticsearch.xpack.core.transform.TransformDeprecations;
3739
import org.elasticsearch.xpack.core.transform.transforms.SettingsConfig;
40+
import org.elasticsearch.xpack.core.transform.transforms.SettingsConfigTests;
3841
import org.elasticsearch.xpack.core.transform.transforms.SourceConfig;
3942
import org.elasticsearch.xpack.core.transform.transforms.pivot.AggregationConfig;
4043
import org.elasticsearch.xpack.core.transform.transforms.pivot.AggregationConfigTests;
4144
import org.elasticsearch.xpack.core.transform.transforms.pivot.GroupConfig;
4245
import org.elasticsearch.xpack.core.transform.transforms.pivot.GroupConfigTests;
4346
import org.elasticsearch.xpack.core.transform.transforms.pivot.PivotConfig;
47+
import org.elasticsearch.xpack.core.transform.transforms.pivot.PivotConfigTests;
4448
import org.elasticsearch.xpack.spatial.SpatialPlugin;
4549
import org.elasticsearch.xpack.transform.Transform;
4650
import org.elasticsearch.xpack.transform.transforms.Function;
@@ -51,7 +55,9 @@
5155
import java.io.IOException;
5256
import java.util.ArrayList;
5357
import java.util.Collections;
58+
import java.util.HashMap;
5459
import java.util.List;
60+
import java.util.Map;
5561
import java.util.Set;
5662
import java.util.concurrent.CountDownLatch;
5763
import java.util.concurrent.TimeUnit;
@@ -63,8 +69,11 @@
6369
import static org.hamcrest.CoreMatchers.is;
6470
import static org.hamcrest.Matchers.contains;
6571
import static org.hamcrest.Matchers.containsString;
72+
import static org.hamcrest.Matchers.empty;
6673
import static org.hamcrest.Matchers.equalTo;
6774
import static org.hamcrest.Matchers.nullValue;
75+
import static org.mockito.Mockito.mock;
76+
import static org.mockito.Mockito.when;
6877

6978
public class PivotTests extends ESTestCase {
7079

@@ -206,6 +215,60 @@ public void testGetPerformanceCriticalFields() throws IOException {
206215
assertThat(pivot.getPerformanceCriticalFields(), contains("field-A", "field-B", "field-C"));
207216
}
208217

218+
public void testPreviewForEmptyAggregation() throws Exception {
219+
Function pivot = new Pivot(
220+
PivotConfigTests.randomPivotConfig(),
221+
SettingsConfigTests.randomSettingsConfig(),
222+
Version.CURRENT,
223+
Collections.emptySet()
224+
);
225+
226+
CountDownLatch latch = new CountDownLatch(1);
227+
final AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
228+
final AtomicReference<List<Map<String, Object>>> responseHolder = new AtomicReference<>();
229+
230+
Client emptyAggregationClient = new MyMockClientWithEmptyAggregation("empty aggregation test for preview");
231+
pivot.preview(emptyAggregationClient, null, new HashMap<>(), new SourceConfig("test"), null, 1, ActionListener.wrap(r -> {
232+
responseHolder.set(r);
233+
latch.countDown();
234+
}, e -> {
235+
exceptionHolder.set(e);
236+
latch.countDown();
237+
}));
238+
assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
239+
emptyAggregationClient.close();
240+
241+
assertThat(exceptionHolder.get(), is(nullValue()));
242+
assertThat(responseHolder.get(), is(empty()));
243+
}
244+
245+
public void testPreviewForCompositeAggregation() throws Exception {
246+
Function pivot = new Pivot(
247+
PivotConfigTests.randomPivotConfig(),
248+
SettingsConfigTests.randomSettingsConfig(),
249+
Version.CURRENT,
250+
Collections.emptySet()
251+
);
252+
253+
CountDownLatch latch = new CountDownLatch(1);
254+
final AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
255+
final AtomicReference<List<Map<String, Object>>> responseHolder = new AtomicReference<>();
256+
257+
Client compositeAggregationClient = new MyMockClientWithCompositeAggregation("composite aggregation test for preview");
258+
pivot.preview(compositeAggregationClient, null, new HashMap<>(), new SourceConfig("test"), null, 1, ActionListener.wrap(r -> {
259+
responseHolder.set(r);
260+
latch.countDown();
261+
}, e -> {
262+
exceptionHolder.set(e);
263+
latch.countDown();
264+
}));
265+
assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
266+
compositeAggregationClient.close();
267+
268+
assertThat(exceptionHolder.get(), is(nullValue()));
269+
assertThat(responseHolder.get(), is(empty()));
270+
}
271+
209272
private class MyMockClient extends NoOpClient {
210273
MyMockClient(String testName) {
211274
super(testName);
@@ -262,6 +325,44 @@ protected <Request extends ActionRequest, Response extends ActionResponse> void
262325
}
263326
}
264327

328+
private class MyMockClientWithEmptyAggregation extends NoOpClient {
329+
MyMockClientWithEmptyAggregation(String testName) {
330+
super(testName);
331+
}
332+
333+
@SuppressWarnings("unchecked")
334+
@Override
335+
protected <Request extends ActionRequest, Response extends ActionResponse> void doExecute(
336+
ActionType<Response> action,
337+
Request request,
338+
ActionListener<Response> listener
339+
) {
340+
SearchResponse response = mock(SearchResponse.class);
341+
when(response.getAggregations()).thenReturn(new Aggregations(Collections.emptyList()));
342+
listener.onResponse((Response) response);
343+
}
344+
}
345+
346+
private class MyMockClientWithCompositeAggregation extends NoOpClient {
347+
MyMockClientWithCompositeAggregation(String testName) {
348+
super(testName);
349+
}
350+
351+
@SuppressWarnings("unchecked")
352+
@Override
353+
protected <Request extends ActionRequest, Response extends ActionResponse> void doExecute(
354+
ActionType<Response> action,
355+
Request request,
356+
ActionListener<Response> listener
357+
) {
358+
SearchResponse response = mock(SearchResponse.class);
359+
CompositeAggregation compositeAggregation = mock(CompositeAggregation.class);
360+
when(response.getAggregations()).thenReturn(new Aggregations(Collections.singletonList(compositeAggregation)));
361+
when(compositeAggregation.getBuckets()).thenReturn(new ArrayList<>());
362+
listener.onResponse((Response) response);
363+
}
364+
}
365+
265366
private PivotConfig getValidPivotConfig() throws IOException {
266367
return new PivotConfig(GroupConfigTests.randomGroupConfig(), getValidAggregationConfig(), null);
267368
}

0 commit comments

Comments
 (0)