@@ -189,6 +189,90 @@ private void doWithRandomAccessPattern(Consumer<IngestDocument> action) throws E
189
189
doWithAccessPattern (randomFrom (IngestPipelineFieldAccessPattern .values ()), action );
190
190
}
191
191
192
+ private void assertPathValid (IngestDocument doc , String path ) {
193
+ // The fields being checked do not exist, so they all return false when running hasField
194
+ assertFalse (doc .hasField (path ));
195
+ }
196
+
197
+ private void assertPathInvalid (IngestDocument doc , String path , String errorMessage ) {
198
+ IllegalArgumentException expected = expectThrows (IllegalArgumentException .class , () -> doc .hasField (path ));
199
+ assertThat (expected .getMessage (), equalTo (errorMessage ));
200
+ }
201
+
202
+ public void testPathParsingLogic () throws Exception {
203
+ // Force a blank document for this test
204
+ document = new IngestDocument ("index" , "id" , 1 , null , null , new HashMap <>());
205
+
206
+ doWithRandomAccessPattern ((doc ) -> {
207
+ assertPathInvalid (doc , null , "path cannot be null nor empty" );
208
+ assertPathInvalid (doc , "" , "path cannot be null nor empty" );
209
+ assertPathValid (doc , "a" );
210
+ assertPathValid (doc , "ab" );
211
+ assertPathValid (doc , "abc" );
212
+ assertPathValid (doc , "a.b" );
213
+ assertPathValid (doc , "a.b.c" );
214
+ // Trailing empty strings are trimmed by field path parsing logic
215
+ assertPathValid (doc , "a." );
216
+ assertPathValid (doc , "a.." );
217
+ assertPathValid (doc , "a..." );
218
+ // Empty field names are not allowed in the beginning or middle of the path though
219
+ assertPathInvalid (doc , ".a.b" , "path [.a.b] is not valid" );
220
+ assertPathInvalid (doc , "a..b" , "path [a..b] is not valid" );
221
+ });
222
+
223
+ doWithAccessPattern (CLASSIC , (doc ) -> {
224
+ // Classic allows number fields because they are treated as either field names or array indices depending on context
225
+ assertPathValid (doc , "a.0" );
226
+ // Classic allows square brackets because it is not part of it's syntax
227
+ assertPathValid (doc , "a[0]" );
228
+ assertPathValid (doc , "a[]" );
229
+ assertPathValid (doc , "a][" );
230
+ assertPathValid (doc , "[" );
231
+ assertPathValid (doc , "a[" );
232
+ assertPathValid (doc , "[a" );
233
+ assertPathValid (doc , "]" );
234
+ assertPathValid (doc , "a]" );
235
+ assertPathValid (doc , "]a" );
236
+ assertPathValid (doc , "[]" );
237
+ assertPathValid (doc , "][" );
238
+ assertPathValid (doc , "[a]" );
239
+ assertPathValid (doc , "]a[" );
240
+ assertPathValid (doc , "[]a" );
241
+ assertPathValid (doc , "][a" );
242
+ });
243
+
244
+ doWithAccessPattern (FLEXIBLE , (doc ) -> {
245
+ // Flexible has specific handling of square brackets
246
+ assertPathInvalid (doc , "a[0]" , "path [a[0]] is not valid" );
247
+ assertPathInvalid (doc , "a[]" , "path [a[]] is not valid" );
248
+ assertPathInvalid (doc , "a][" , "path [a][] is not valid" );
249
+ assertPathInvalid (doc , "[" , "path [[] is not valid" );
250
+ assertPathInvalid (doc , "a[" , "path [a[] is not valid" );
251
+ assertPathInvalid (doc , "[a" , "path [[a] is not valid" );
252
+ assertPathInvalid (doc , "]" , "path []] is not valid" );
253
+ assertPathInvalid (doc , "a]" , "path [a]] is not valid" );
254
+ assertPathInvalid (doc , "]a" , "path []a] is not valid" );
255
+ assertPathInvalid (doc , "[]" , "path [[]] is not valid" );
256
+ assertPathInvalid (doc , "][" , "path [][] is not valid" );
257
+ assertPathInvalid (doc , "[a]" , "path [[a]] is not valid" );
258
+ assertPathInvalid (doc , "]a[" , "path []a[] is not valid" );
259
+ assertPathInvalid (doc , "[]a" , "path [[]a] is not valid" );
260
+ assertPathInvalid (doc , "][a" , "path [][a] is not valid" );
261
+
262
+ assertPathInvalid (doc , "a[0].b" , "path [a[0].b] is not valid" );
263
+ assertPathInvalid (doc , "a[0].b[1]" , "path [a[0].b[1]] is not valid" );
264
+ assertPathInvalid (doc , "a[0].b[1].c" , "path [a[0].b[1].c] is not valid" );
265
+ assertPathInvalid (doc , "a[0].b[1].c[2]" , "path [a[0].b[1].c[2]] is not valid" );
266
+ assertPathInvalid (doc , "a[0][1].c[2]" , "path [a[0][1].c[2]] is not valid" );
267
+ assertPathInvalid (doc , "a[0].b[1][2]" , "path [a[0].b[1][2]] is not valid" );
268
+ assertPathInvalid (doc , "a[0][1][2]" , "path [a[0][1][2]] is not valid" );
269
+
270
+ assertPathInvalid (doc , "a[0][" , "path [a[0][] is not valid" );
271
+ assertPathInvalid (doc , "a[0]]" , "path [a[0]]] is not valid" );
272
+ assertPathInvalid (doc , "a[0]blahblah" , "path [a[0]blahblah] is not valid" );
273
+ });
274
+ }
275
+
192
276
public void testSimpleGetFieldValue () throws Exception {
193
277
doWithRandomAccessPattern ((doc ) -> {
194
278
assertThat (doc .getFieldValue ("foo" , String .class ), equalTo ("bar" ));
@@ -2034,7 +2118,7 @@ public void testNestedAccessPatternPropagation() {
2034
2118
2035
2119
// At the end of the test, there should be neither pipeline ids nor access patterns left in the stack.
2036
2120
assertThat (document .getPipelineStack (), is (empty ()));
2037
- assertThat (document .getCurrentAccessPattern (), is (nullValue () ));
2121
+ assertThat (document .getCurrentAccessPattern (). isEmpty () , is (true ));
2038
2122
}
2039
2123
2040
2124
/**
@@ -2082,7 +2166,8 @@ void doTestNestedAccessPatternPropagation(int level, int maxCallDepth, IngestDoc
2082
2166
2083
2167
// Assert expected state
2084
2168
assertThat (document .getPipelineStack ().getFirst (), is (expectedPipelineId ));
2085
- assertThat (document .getCurrentAccessPattern (), is (expectedAccessPattern ));
2169
+ assertThat (document .getCurrentAccessPattern ().isPresent (), is (true ));
2170
+ assertThat (document .getCurrentAccessPattern ().get (), is (expectedAccessPattern ));
2086
2171
2087
2172
// Randomly recurse: We recurse only one time per level to avoid hogging test time, but we randomize which
2088
2173
// pipeline to recurse on, eventually requiring a recursion on the last pipeline run if one hasn't happened yet.
@@ -2099,11 +2184,11 @@ void doTestNestedAccessPatternPropagation(int level, int maxCallDepth, IngestDoc
2099
2184
assertThat (document .getPipelineStack ().size (), is (equalTo (level )));
2100
2185
if (level == 0 ) {
2101
2186
// Top level means access pattern should be empty
2102
- assertThat (document .getCurrentAccessPattern (), is (nullValue () ));
2187
+ assertThat (document .getCurrentAccessPattern (). isEmpty () , is (true ));
2103
2188
} else {
2104
2189
// If we're nested below the top level we should still have an access
2105
2190
// pattern on the document for the pipeline above us
2106
- assertThat (document .getCurrentAccessPattern (), is (not ( nullValue ()) ));
2191
+ assertThat (document .getCurrentAccessPattern (). isPresent () , is (true ));
2107
2192
}
2108
2193
}
2109
2194
logger .debug ("LEVEL {}/{}: COMPLETE" , level , maxCallDepth );
0 commit comments