/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.sqoop.validation; import org.apache.sqoop.model.ConfigurationClass; import org.apache.sqoop.model.Config; import org.apache.sqoop.model.ConfigClass; import org.apache.sqoop.model.Input; import org.apache.sqoop.model.Validator; import org.apache.sqoop.validation.validators.Contains; import org.apache.sqoop.validation.validators.NotEmpty; import org.apache.sqoop.validation.validators.NotNull; import org.apache.sqoop.validation.validators.AbstractValidator; import org.testng.annotations.Test; import static org.testng.AssertJUnit.assertEquals; import static org.testng.Assert.assertTrue; /** */ public class TestValidationRunner { @ConfigClass(validators = {@Validator(ConfigA.ConfigValidator.class)}) public static class ConfigA { @Input(validators = {@Validator(NotNull.class)}) String notNull; public static class ConfigValidator extends AbstractValidator<ConfigA> { @Override public void validate(ConfigA config) { if(config.notNull == null) { addMessage(Status.ERROR, "null"); } if("error".equals(config.notNull)) { addMessage(Status.ERROR, "error"); } } } } @Test public void testValidateConfig() { ConfigA config = new ConfigA(); ConfigValidationRunner runner = new ConfigValidationRunner(); ConfigValidationResult result; // Null string should fail on Input level and should not call config level validators config.notNull = null; result = runner.validateConfig("configName", config); assertEquals(Status.ERROR, result.getStatus()); assertEquals(1, result.getMessages().size()); assertTrue(result.getMessages().containsKey("configName.notNull")); // String "error" should trigger config level error, but not Input level config.notNull = "error"; result = runner.validateConfig("configName", config); assertEquals(Status.ERROR, result.getStatus()); assertEquals(1, result.getMessages().size()); assertTrue(result.getMessages().containsKey("configName")); // Acceptable state config.notNull = "This is truly random string"; result = runner.validateConfig("configName", config); assertEquals(Status.OK, result.getStatus()); assertEquals(0, result.getMessages().size()); } @ConfigClass public static class ConfigB { @Input(validators = {@Validator(NotNull.class), @Validator(NotEmpty.class)}) String str; } @ConfigClass public static class ConfigC { @Input(validators = {@Validator(value = Contains.class, strArg = "findme")}) String str; } @Test public void testMultipleValidatorsOnSingleInput() { ConfigB config = new ConfigB(); ConfigValidationRunner runner = new ConfigValidationRunner(); ConfigValidationResult result; config.str = null; result = runner.validateConfig("configName", config); assertEquals(Status.ERROR, result.getStatus()); assertEquals(1, result.getMessages().size()); assertTrue(result.getMessages().containsKey("configName.str")); assertEquals(2, result.getMessages().get("configName.str").size()); } @Test public void testValidatorWithParameters() { ConfigC config = new ConfigC(); ConfigValidationRunner runner = new ConfigValidationRunner(); ConfigValidationResult result; // Sub string not found config.str = "Mordor"; result = runner.validateConfig("configName", config); assertEquals(Status.ERROR, result.getStatus()); assertEquals(1, result.getMessages().size()); assertTrue(result.getMessages().containsKey("configName.str")); // Sub string found config.str = "Morfindmedor"; result = runner.validateConfig("configName", config); assertEquals(Status.OK, result.getStatus()); assertEquals(0, result.getMessages().size()); } @ConfigurationClass(validators = {@Validator(ConfigurationA.ClassValidator.class)}) public static class ConfigurationA { @Config ConfigA formA; public ConfigurationA() { formA = new ConfigA(); } public static class ClassValidator extends AbstractValidator<ConfigurationA> { @Override public void validate(ConfigurationA conf) { if("error".equals(conf.formA.notNull)) { addMessage(Status.ERROR, "error"); } if("conf-error".equals(conf.formA.notNull)) { addMessage(Status.ERROR, "conf-error"); } } } } @Test public void testValidate() { ConfigurationA conf = new ConfigurationA(); ConfigValidationRunner runner = new ConfigValidationRunner(); ConfigValidationResult result; // Null string should fail on Input level and should not call config nor class level validators conf.formA.notNull = null; result = runner.validate(conf); assertEquals(Status.ERROR, result.getStatus()); assertEquals(1, result.getMessages().size()); assertTrue(result.getMessages().containsKey("formA.notNull")); // String "error" should trigger config level error, but not Input nor class level conf.formA.notNull = "error"; result = runner.validate(conf); assertEquals(Status.ERROR, result.getStatus()); assertEquals(1, result.getMessages().size()); assertTrue(result.getMessages().containsKey("formA")); // String "conf-error" should trigger class level error, but not Input nor Config level conf.formA.notNull = "conf-error"; result = runner.validate(conf); assertEquals(Status.ERROR, result.getStatus()); assertEquals(1, result.getMessages().size()); assertTrue(result.getMessages().containsKey("")); // Valid string conf.formA.notNull = "Valid string"; result = runner.validate(conf); assertEquals(Status.OK, result.getStatus()); assertEquals(0, result.getMessages().size()); } }