use of io.cdap.cdap.etl.proto.v2.validation.StageValidationRequest in project cdap by caskdata.
the class ValidationUtils method validate.
/**
* Validate plugin based on the {@link StageValidationRequest}
*
* @param validationRequest {@link StageValidationRequest} with plugin properties
* @param pluginConfigurer {@link PluginConfigurer} for using the plugin
* @param macroFn {@link Function} for evaluating macros
* @return {@link StageValidationResponse} in json format
*/
public static StageValidationResponse validate(String namespace, StageValidationRequest validationRequest, PluginConfigurer pluginConfigurer, Function<Map<String, String>, Map<String, String>> macroFn, FeatureFlagsProvider featureFlagsProvider) {
ETLStage stageConfig = validationRequest.getStage();
ValidatingConfigurer validatingConfigurer = new ValidatingConfigurer(pluginConfigurer, featureFlagsProvider);
// Batch or Streaming doesn't matter for a single stage.
PipelineSpecGenerator<ETLBatchConfig, BatchPipelineSpec> pipelineSpecGenerator = new BatchPipelineSpecGenerator(namespace, validatingConfigurer, null, Collections.emptySet(), Collections.emptySet(), Engine.SPARK, featureFlagsProvider);
DefaultStageConfigurer stageConfigurer = new DefaultStageConfigurer(stageConfig.getName());
for (StageSchema stageSchema : validationRequest.getInputSchemas()) {
stageConfigurer.addInputSchema(stageSchema.getStage(), stageSchema.getSchema());
stageConfigurer.addInputStage(stageSchema.getStage());
}
DefaultPipelineConfigurer pipelineConfigurer = new DefaultPipelineConfigurer(validatingConfigurer, stageConfig.getName(), Engine.SPARK, stageConfigurer, featureFlagsProvider);
// evaluate macros
Map<String, String> evaluatedProperties = macroFn.apply(stageConfig.getPlugin().getProperties());
ETLPlugin originalConfig = stageConfig.getPlugin();
ETLPlugin evaluatedConfig = new ETLPlugin(originalConfig.getName(), originalConfig.getType(), evaluatedProperties, originalConfig.getArtifactConfig());
try {
StageSpec spec = pipelineSpecGenerator.configureStage(stageConfig.getName(), evaluatedConfig, pipelineConfigurer).build();
return new StageValidationResponse(spec);
} catch (ValidationException e) {
return new StageValidationResponse(e.getFailures());
}
}
use of io.cdap.cdap.etl.proto.v2.validation.StageValidationRequest in project cdap by caskdata.
the class DataPipelineServiceTest method testValidateStageSingleInvalidConfigProperty.
@Test
public void testValidateStageSingleInvalidConfigProperty() throws Exception {
// StringValueFilterTransform will be configured to filter records where field x has value 'y'
// it will be invalid because the type of field x will be an int instead of the required string
String stageName = "tx";
Map<String, String> properties = new HashMap<>();
properties.put("field", "x");
properties.put("value", "y");
ETLStage stage = new ETLStage(stageName, new ETLPlugin(StringValueFilterTransform.NAME, Transform.PLUGIN_TYPE, properties));
Schema inputSchema = Schema.recordOf("x", Schema.Field.of("x", Schema.of(Schema.Type.INT)));
StageValidationRequest requestBody = new StageValidationRequest(stage, Collections.singletonList(new StageSchema("input", inputSchema)), false);
StageValidationResponse actual = sendRequest(requestBody);
Assert.assertNull(actual.getSpec());
Assert.assertEquals(1, actual.getFailures().size());
ValidationFailure failure = actual.getFailures().iterator().next();
// the stage will add 2 causes for invalid input field failure. One is related to input field and the other is
// related to config property.
Assert.assertEquals(2, failure.getCauses().size());
Assert.assertEquals("field", failure.getCauses().get(0).getAttribute(CauseAttributes.STAGE_CONFIG));
Assert.assertEquals(stageName, failure.getCauses().get(0).getAttribute(STAGE));
Assert.assertEquals("x", failure.getCauses().get(1).getAttribute(CauseAttributes.INPUT_SCHEMA_FIELD));
Assert.assertEquals("input", failure.getCauses().get(1).getAttribute(CauseAttributes.INPUT_STAGE));
Assert.assertEquals(stageName, failure.getCauses().get(1).getAttribute(STAGE));
}
use of io.cdap.cdap.etl.proto.v2.validation.StageValidationRequest in project cdap by caskdata.
the class DataPipelineServiceTest method testValidationFailureWithNPE.
@Test
public void testValidationFailureWithNPE() throws Exception {
String stageName = "npe";
ETLStage stage = new ETLStage(stageName, NullErrorTransform.getPlugin());
StageValidationResponse actual = sendRequest(new StageValidationRequest(stage, Collections.emptyList(), false));
Assert.assertNull(actual.getSpec());
Assert.assertEquals(1, actual.getFailures().size());
ValidationFailure failure = actual.getFailures().iterator().next();
Assert.assertEquals(stageName, failure.getCauses().get(0).getAttribute(STAGE));
Assert.assertNotNull(failure.getCauses().get(0).getAttribute(CauseAttributes.STACKTRACE));
}
use of io.cdap.cdap.etl.proto.v2.validation.StageValidationRequest in project cdap by caskdata.
the class DataPipelineServiceTest method testValidateStageMissingRequiredProperty.
// tests that plugins that cannot be instantiated due to missing required properties are captured
@Test
public void testValidateStageMissingRequiredProperty() throws Exception {
String stageName = "tx";
// string filter requires the field name and the value
ETLStage stage = new ETLStage(stageName, new ETLPlugin(StringValueFilterTransform.NAME, Transform.PLUGIN_TYPE, Collections.emptyMap()));
StageValidationResponse actual = sendRequest(new StageValidationRequest(stage, Collections.emptyList(), false));
Assert.assertNull(actual.getSpec());
Assert.assertEquals(2, actual.getFailures().size());
Set<String> properties = new HashSet<>();
properties.add(actual.getFailures().get(0).getCauses().get(0).getAttribute(CauseAttributes.STAGE_CONFIG));
properties.add(actual.getFailures().get(1).getCauses().get(0).getAttribute(CauseAttributes.STAGE_CONFIG));
Set<String> expected = new HashSet<>();
expected.add("field");
expected.add("value");
Assert.assertEquals(expected, properties);
}
use of io.cdap.cdap.etl.proto.v2.validation.StageValidationRequest in project cdap by caskdata.
the class DataPipelineServiceTest method testValidateMultiInputInvalidInputField.
@Test
public void testValidateMultiInputInvalidInputField() throws Exception {
// StringValueFilterTransform will be configured to filter records where field x has value 'y'
// it will be invalid because the type of field x will be an int instead of the required string
String stageName = "tx";
Map<String, String> properties = new HashMap<>();
properties.put("field", "x");
properties.put("value", "y");
ETLStage stage = new ETLStage(stageName, new ETLPlugin(StringValueFilterTransform.NAME, Transform.PLUGIN_TYPE, properties));
Schema inputSchema = Schema.recordOf("x", Schema.Field.of("x", Schema.of(Schema.Type.INT)));
StageValidationRequest requestBody = new StageValidationRequest(stage, ImmutableList.of(new StageSchema("input1", inputSchema), new StageSchema("input2", inputSchema)), false);
StageValidationResponse actual = sendRequest(requestBody);
List<String> expectedInputs = ImmutableList.of("input1", "input2");
Assert.assertNull(actual.getSpec());
Assert.assertEquals(1, actual.getFailures().size());
ValidationFailure failure = actual.getFailures().iterator().next();
// the stage will add 3 causes. Two are related to input field and one is related to config property.
Assert.assertEquals(3, failure.getCauses().size());
Assert.assertEquals("field", failure.getCauses().get(0).getAttribute(CauseAttributes.STAGE_CONFIG));
Assert.assertEquals(stageName, failure.getCauses().get(0).getAttribute(STAGE));
Assert.assertEquals(stageName, failure.getCauses().get(1).getAttribute(STAGE));
Assert.assertEquals(stageName, failure.getCauses().get(2).getAttribute(STAGE));
Assert.assertTrue(expectedInputs.contains(failure.getCauses().get(1).getAttribute(CauseAttributes.INPUT_STAGE)));
Assert.assertTrue(expectedInputs.contains(failure.getCauses().get(2).getAttribute(CauseAttributes.INPUT_STAGE)));
}
Aggregations