99import com .carrotsearch .randomizedtesting .annotations .Name ;
1010import com .carrotsearch .randomizedtesting .annotations .ParametersFactory ;
1111
12+ import org .elasticsearch .common .xcontent .XContentLocation ;
1213import org .elasticsearch .index .mapper .IpFieldMapper ;
1314import org .elasticsearch .index .mapper .KeywordFieldMapper ;
1415import org .elasticsearch .index .mapper .NumberFieldMapper .NumberType ;
1516import org .elasticsearch .test .rest .yaml .ClientYamlTestCandidate ;
17+ import org .elasticsearch .test .rest .yaml .ClientYamlTestExecutionContext ;
18+ import org .elasticsearch .test .rest .yaml .ClientYamlTestResponse ;
1619import org .elasticsearch .test .rest .yaml .ESClientYamlSuiteTestCase ;
20+ import org .elasticsearch .test .rest .yaml .section .ClientYamlTestSection ;
21+ import org .elasticsearch .test .rest .yaml .section .ClientYamlTestSuite ;
1722import org .elasticsearch .test .rest .yaml .section .DoSection ;
1823import org .elasticsearch .test .rest .yaml .section .ExecutableSection ;
24+ import org .elasticsearch .test .rest .yaml .section .SetupSection ;
1925
26+ import java .io .IOException ;
2027import java .util .ArrayList ;
2128import java .util .HashMap ;
2229import java .util .List ;
2330import java .util .Map ;
2431import java .util .Objects ;
2532
33+ import static org .hamcrest .Matchers .equalTo ;
34+
2635public class CoreTestsWithRuntimeFieldsIT extends ESClientYamlSuiteTestCase {
2736 public CoreTestsWithRuntimeFieldsIT (@ Name ("yaml" ) ClientYamlTestCandidate testCandidate ) {
2837 super (testCandidate );
@@ -37,34 +46,49 @@ public CoreTestsWithRuntimeFieldsIT(@Name("yaml") ClientYamlTestCandidate testCa
3746 */
3847 @ ParametersFactory
3948 public static Iterable <Object []> parameters () throws Exception {
40- /*
41- * Map of "setup"s that we've seen - from path to whether or
42- * not we the setup was modified to include a runtime_script
43- */
44- Map <String , Boolean > seenSetups = new HashMap <>();
49+ Map <String , ClientYamlTestSuite > suites = new HashMap <>();
4550 List <Object []> result = new ArrayList <>();
4651 for (Object [] orig : ESClientYamlSuiteTestCase .createParameters ()) {
4752 assert orig .length == 1 ;
4853 ClientYamlTestCandidate candidate = (ClientYamlTestCandidate ) orig [0 ];
49- boolean modifiedSetup = seenSetups .computeIfAbsent (
50- candidate .getName (),
51- k -> modifySection (candidate .getSuitePath () + "/setup" , candidate .getSetupSection ().getExecutableSections ())
54+ ClientYamlTestSuite suite = suites .computeIfAbsent (candidate .getTestPath (), k -> modifiedSuite (candidate ));
55+ modifySection (candidate .getTestPath (), candidate .getTestSection ().getExecutableSections ());
56+ ClientYamlTestSection modified = new ClientYamlTestSection (
57+ candidate .getTestSection ().getLocation (),
58+ candidate .getTestSection ().getName (),
59+ candidate .getTestSection ().getSkipSection (),
60+ candidate .getTestSection ().getExecutableSections ()
5261 );
53- boolean modifiedTest = modifySection (candidate .getTestPath (), candidate .getTestSection ().getExecutableSections ());
54- if (modifiedSetup || modifiedTest ) {
55- result .add (new Object [] { candidate });
56- }
62+ result .add (new Object [] { new ClientYamlTestCandidate (suite , modified ) });
5763 }
5864 return result ;
5965 }
6066
6167 /**
62- * Replace property configuration in {@code indices.create} with scripts
68+ * Modify the setup section to setup a dynamic template that replaces
69+ * field configurations with scripts that load from source
70+ * <strong>and</strong> replaces field configurations in {@code incides.create}
71+ * with scripts that load from source.
72+ */
73+ private static ClientYamlTestSuite modifiedSuite (ClientYamlTestCandidate candidate ) {
74+ modifySection (candidate .getSuitePath () + "/setup" , candidate .getSetupSection ().getExecutableSections ());
75+ List <ExecutableSection > setup = new ArrayList <>(candidate .getSetupSection ().getExecutableSections ().size () + 1 );
76+ setup .add (ADD_TEMPLATE );
77+ setup .addAll (candidate .getSetupSection ().getExecutableSections ());
78+ return new ClientYamlTestSuite (
79+ candidate .getApi (),
80+ candidate .getName (),
81+ new SetupSection (candidate .getSetupSection ().getSkipSection (), setup ),
82+ candidate .getTeardownSection (),
83+ List .of ()
84+ );
85+ }
86+
87+ /**
88+ * Replace field configuration in {@code indices.create} with scripts
6389 * that load from the source.
64- * @return {@code true} if any fields were rewritten into runtime_scripts, {@code false} otherwise.
6590 */
66- private static boolean modifySection (String sectionName , List <ExecutableSection > executables ) {
67- boolean include = false ;
91+ private static void modifySection (String sectionName , List <ExecutableSection > executables ) {
6892 for (ExecutableSection section : executables ) {
6993 if (false == (section instanceof DoSection )) {
7094 continue ;
@@ -129,11 +153,9 @@ private static boolean modifySection(String sectionName, List<ExecutableSection>
129153 propertyMap .remove ("store" );
130154 propertyMap .remove ("index" );
131155 propertyMap .remove ("doc_values" );
132- include = true ;
133156 }
134157 }
135158 }
136- return include ;
137159 }
138160
139161 private static String painlessToLoadFromSource (String name , String type ) {
@@ -173,4 +195,54 @@ private static String painlessToLoadFromSource(String name, String type) {
173195 )
174196 );
175197
198+ private static final ExecutableSection ADD_TEMPLATE = new ExecutableSection () {
199+ @ Override
200+ public XContentLocation getLocation () {
201+ return new XContentLocation (-1 , -1 );
202+ }
203+
204+ @ Override
205+ public void execute (ClientYamlTestExecutionContext executionContext ) throws IOException {
206+ Map <String , String > params = Map .of ("name" , "convert_to_source_only" , "create" , "true" );
207+ List <Map <String , Object >> dynamicTemplates = new ArrayList <>();
208+ for (String type : PAINLESS_TO_EMIT .keySet ()) {
209+ if (type .equals ("ip" )) {
210+ // There isn't a dynamic template to pick up ips. They'll just look like strings.
211+ continue ;
212+ }
213+ Map <String , Object > mapping = Map .ofEntries (
214+ Map .entry ("type" , "runtime_script" ),
215+ Map .entry ("runtime_type" , type ),
216+ Map .entry ("script" , painlessToLoadFromSource ("{name}" , type ))
217+ );
218+ Map <String , Object > body = Map .ofEntries (
219+ Map .entry ("match_mapping_type" , type .equals ("keyword" ) ? "string" : type ),
220+ Map .entry ("mapping" , mapping )
221+ );
222+ if (type .contentEquals ("keyword" )) {
223+ /*
224+ * For "string"-type dynamic mappings emulate our default
225+ * behavior with a top level text field and a `.keyword`
226+ * multi-field. But instead of the default, use a runtime
227+ * field for the multi-field.
228+ */
229+ mapping = Map .of ("type" , "text" , "fields" , Map .of ("keyword" , mapping ));
230+ dynamicTemplates .add (Map .of (type , Map .of ("match_mapping_type" , "string" , "mapping" , mapping )));
231+ } else {
232+ dynamicTemplates .add (Map .of (type , Map .of ("match_mapping_type" , type , "mapping" , mapping )));
233+ }
234+ dynamicTemplates .add (Map .of (type , body ));
235+ }
236+ List <Map <String , Object >> bodies = List .of (
237+ Map .ofEntries (
238+ Map .entry ("index_patterns" , "*" ),
239+ Map .entry ("priority" , Integer .MAX_VALUE ),
240+ Map .entry ("template" , Map .of ("settings" , Map .of (), "mappings" , Map .of ("dynamic_templates" , dynamicTemplates )))
241+ )
242+ );
243+ ClientYamlTestResponse response = executionContext .callApi ("indices.put_index_template" , params , bodies , Map .of ());
244+ assertThat (response .getStatusCode (), equalTo (200 ));
245+ // There are probably some warning about overlapping templates. Ignore them.
246+ }
247+ };
176248}
0 commit comments