View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.service.impl;
17  
18  import java.io.IOException;
19  import java.util.ArrayList;
20  import java.util.Date;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import org.junit.Assert;
25  import org.junit.Before;
26  import org.junit.Test;
27  import org.kuali.rice.core.api.util.RiceKeyConstants;
28  import org.kuali.rice.krad.datadictionary.DataDictionary;
29  import org.kuali.rice.krad.datadictionary.DataObjectEntry;
30  import org.kuali.rice.krad.datadictionary.validation.Address;
31  import org.kuali.rice.krad.datadictionary.validation.Company;
32  import org.kuali.rice.krad.datadictionary.validation.Employee;
33  import org.kuali.rice.krad.datadictionary.validation.ErrorLevel;
34  import org.kuali.rice.krad.datadictionary.validation.Person;
35  import org.kuali.rice.krad.datadictionary.validation.constraint.provider.CollectionDefinitionConstraintProvider;
36  import org.kuali.rice.krad.datadictionary.validation.processor.MustOccurConstraintProcessor;
37  import org.kuali.rice.krad.datadictionary.validation.result.ConstraintValidationResult;
38  import org.kuali.rice.krad.datadictionary.validation.result.DictionaryValidationResult;
39  import org.kuali.rice.krad.service.DataDictionaryService;
40  import org.kuali.test.KRADTestCase;
41  import org.springframework.context.support.ClassPathXmlApplicationContext;
42  
43  
44  /**
45   * 
46   * @author Kuali Rice Team (rice.collab@kuali.org)
47   */
48  public class DictionaryValidationServiceImplTest {
49  
50  	ClassPathXmlApplicationContext context;
51  	private DictionaryValidationServiceImpl service;
52  	DataDictionary dataDictionary = new DataDictionary();	
53  	
54  	protected DataObjectEntry addressEntry;
55  	
56  	private Address validLondonAddress = new Address("8129 Maiden Lane", "", "London", "", "SE1 0P3", "UK", null);
57  	private Address validUSAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "DC", "12031", "USA", null);
58  	private Address invalidUSAddress = new Address("893 Presidential Ave", "Suite 800", "Washington", "", "92342-123456", "USA", null);
59  	private Address noZipNoCityUSAddress = new Address("893 Presidential Ave", "Suite 800", null, "DC", null, "USA", null);
60  	private Address validNonDCUSAddress = new Address("89 11th Street", "Suite 800", "Seattle", "WA", "", "USA", null);
61  	private Address invalidDCUSAddress = new Address("89 Presidential Ave", "Suite 800", "Washington", "DC", "12031", "USA", null);
62  	private Address invalidHKAddress = new Address("182 Lin Pai Road", "", "Hong Kong", "N.T.", "", "CN", null);
63  	
64  	
65  	@Before
66  	public void setUp() throws Exception {
67  		//super.setUp();
68  		
69  		context = new ClassPathXmlApplicationContext("classpath:DictionaryValidationServiceSpringBeans.xml");
70  		
71  		service = (DictionaryValidationServiceImpl)context.getBean("dictionaryValidationService");
72  	
73  		dataDictionary.addConfigFileLocation("classpath:org/kuali/rice/krad/bo/datadictionary/DataDictionaryBaseTypes.xml");
74          dataDictionary.addConfigFileLocation("classpath:org/kuali/rice/kns/bo/datadictionary/DataDictionaryBaseTypes.xml");
75  		dataDictionary.addConfigFileLocation("classpath:org/kuali/rice/krad/test/datadictionary/validation/Company.xml");
76  		dataDictionary.addConfigFileLocation("classpath:org/kuali/rice/krad/test/datadictionary/validation/Address.xml");
77  		dataDictionary.addConfigFileLocation("classpath:org/kuali/rice/krad/test/datadictionary/validation/Employee.xml");
78  		dataDictionary.addConfigFileLocation("classpath:org/kuali/rice/krad/test/datadictionary/validation/Person.xml");		
79  
80  		dataDictionary.parseDataDictionaryConfigurationFiles(false);
81  		
82  		addressEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Address");
83  	}
84  	
85  	
86  	@Test
87  	public void testValidNonUSAddress() {
88  		DictionaryValidationResult dictionaryValidationResult = service.validate(validLondonAddress, "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
89  		
90  		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
91  		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
92  	}
93  	
94      @Test
95  	public void testValidUSAddress() {
96  		DictionaryValidationResult dictionaryValidationResult = service.validate(validUSAddress, "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
97  		
98  		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
99  		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
100 	}
101 	
102 	@Test
103 	public void testInvalidUSAddress() {
104 		DictionaryValidationResult dictionaryValidationResult = service.validate(invalidUSAddress, "org.kuali.rice.kns.datadictionary.validation.MockAddress", addressEntry, true);
105 		
106 		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
107 		Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
108 		
109 		Assert.assertTrue(hasError(dictionaryValidationResult, "country", RiceKeyConstants.ERROR_REQUIRES_FIELD));
110 		Assert.assertTrue(hasError(dictionaryValidationResult, "postalCode", RiceKeyConstants.ERROR_OUT_OF_RANGE));
111 	}
112 	
113 	@Test
114 	public void testValidNonDCAddress() {
115 		DictionaryValidationResult dictionaryValidationResult = service.validate(validNonDCUSAddress, "org.kuali.rice.krad.datadictionary.validation.Address", addressEntry, true);
116 		
117 		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
118 		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
119 	}
120 	
121 	@Test
122 	public void testInvalidDCAddress() {
123 		DictionaryValidationResult dictionaryValidationResult = service.validate(invalidDCUSAddress, "org.kuali.rice.krad.datadictionary.validation.Address", addressEntry, true);
124 		
125 		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
126 		Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
127 		
128 		Assert.assertTrue(hasError(dictionaryValidationResult, "street1", RiceKeyConstants.ERROR_INVALID_FORMAT));
129 	}
130 	
131 	@Test
132 	public void testNoStateNoZipUSAddress() {
133 		DictionaryValidationResult dictionaryValidationResult = service.validate(noZipNoCityUSAddress, "org.kuali.rice.krad.datadictionary.validation.Address", addressEntry, true);
134 		
135 		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
136 		Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
137 		
138 		if (dictionaryValidationResult.getNumberOfErrors() > 0) {
139 	    	for (Iterator<ConstraintValidationResult> iterator = dictionaryValidationResult.iterator() ; iterator.hasNext() ;) {
140 	    		ConstraintValidationResult constraintValidationResult = iterator.next();
141 	    		if (constraintValidationResult.getStatus().getLevel() >= ErrorLevel.WARN.getLevel()) {
142 	    			// The top level error should be an occurs error
143 	    			Assert.assertEquals(ErrorLevel.ERROR, constraintValidationResult.getStatus());
144 	    			Assert.assertEquals("error.occurs", constraintValidationResult.getErrorKey());
145 	    			// It should have two children
146 	    			List<ConstraintValidationResult> children = constraintValidationResult.getChildren();
147 	    			Assert.assertNotNull(children);
148 	    			Assert.assertEquals(2, children.size());
149 	    			// The first child should have it's own child 
150 	    			ConstraintValidationResult child1 = children.get(0);
151 	    			ConstraintValidationResult child2 = children.get(1);
152 	    			
153 	    			Assert.assertEquals("error.requiresField", child1.getErrorKey());
154 	    			Assert.assertArrayEquals(new String[] { "postalCode" }, child1.getErrorParameters());
155 	    			
156 	    			List<ConstraintValidationResult> grandchildren = child2.getChildren();
157 	    			Assert.assertNotNull(grandchildren);
158 	    			Assert.assertEquals(2, grandchildren.size());
159 	    			ConstraintValidationResult grandchild1 = grandchildren.get(0);
160 	    			Assert.assertEquals(ErrorLevel.ERROR, grandchild1.getStatus());
161 	    			Assert.assertEquals("error.requiresField", grandchild1.getErrorKey());
162 	    			Assert.assertArrayEquals(new String[] { "city" }, grandchild1.getErrorParameters());
163 	    			ConstraintValidationResult grandchild2 = grandchildren.get(1);
164 	    			Assert.assertEquals(ErrorLevel.OK, grandchild2.getStatus());
165 	    			Assert.assertEquals(new MustOccurConstraintProcessor().getName(), grandchild2.getConstraintName());
166 	    		}
167 	    	}
168     	}
169 	}
170 	
171 	
172     @Test
173     public void testSimpleCaseConstraints() throws IOException{
174         DictionaryValidationResult dictionaryValidationResult = service.validate(invalidHKAddress, "org.kuali.rice.krad.datadictionary.validation.Address", addressEntry, true);
175         
176         Assert.assertEquals(0, dictionaryValidationResult.getNumberOfWarnings());
177         Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
178         
179         Assert.assertTrue(hasError(dictionaryValidationResult, "street2", RiceKeyConstants.ERROR_REQUIRED));        
180     }
181 
182 	@Test
183 	public void testRequiredNestedAttribute() throws IOException{	
184 		DataDictionaryService dataDictionaryService = new DataDictionaryServiceImpl(dataDictionary);
185 		service.setDataDictionaryService(dataDictionaryService);
186 						
187 		//Get object entries from dictionary
188 		DataObjectEntry addressEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Address");
189         DataObjectEntry companyEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Company");
190 		
191 		//Validate object entries
192 		addressEntry.completeValidation();
193 		companyEntry.completeValidation();
194 		
195 		Company acmeCompany = new Company();
196 		
197 		//Validate empty Company object
198         DictionaryValidationResult dictionaryValidationResult;		
199 		dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
200 		
201 		//Main address is required this should result in error
202 		Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
203 		Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress", RiceKeyConstants.ERROR_REQUIRED));
204 		
205 		//Adding an invalid mainAddress for company 
206 		Address acmeMainAddress = new Address();
207 		acmeCompany.setMainAddress(acmeMainAddress);
208 		
209 		dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
210 		
211 		//This should result in missing country error
212 		Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
213 		Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress.country", RiceKeyConstants.ERROR_REQUIRED));
214 	    Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress", RiceKeyConstants.ERROR_OCCURS));
215 		
216 		//Set items to valid address
217 		acmeMainAddress.setCountry("US");
218 		acmeMainAddress.setPostalCode("11111");
219 		
220 		dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
221 		
222 		//This should result in no error
223 		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
224 		
225 		//Test Nested Attribute Within Nested Attribute, and nested property override
226 		Employee companyContact = new Employee();
227 		acmeCompany.setMainContact(companyContact);
228 		Person mainContactPerson = new Person();
229 		companyContact.setEmployeeDetails(mainContactPerson);
230 		companyContact.setEmployeeId("companyContact");
231 
232 		dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);		
233 
234 		Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
235 		Assert.assertTrue(hasError(dictionaryValidationResult, "mainContact.employeeDetails.gender", RiceKeyConstants.ERROR_REQUIRED));
236 	}
237 	
238 	@Test
239     public void testCollectionConstraints() throws IOException{
240         DataDictionaryService dataDictionaryService = new DataDictionaryServiceImpl(dataDictionary);
241         service.setDataDictionaryService(dataDictionaryService);
242 
243         DataObjectEntry companyEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Company");
244 
245         //Add collection constraint provider so constraints on collections get processed
246         service.getConstraintProviders().add(new CollectionDefinitionConstraintProvider());
247 	    
248         Company acmeCompany = new Company();
249         Address acmeMainAddress = new Address();
250         acmeMainAddress.setCountry("US");
251         acmeMainAddress.setPostalCode("11111");
252         acmeCompany.setMainAddress(acmeMainAddress);
253         
254         DictionaryValidationResult dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
255         
256         //Company requires at least two employees
257         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
258         Assert.assertTrue(hasError(dictionaryValidationResult, "employees", RiceKeyConstants.ERROR_QUANTITY_RANGE));
259         Assert.assertTrue(hasError(dictionaryValidationResult, "slogans", RiceKeyConstants.ERROR_MIN_OCCURS));        
260         
261         //Add required employes and revalidate
262         Employee employee1 = new Employee();
263         Person person = new Person();
264         person.setBirthDate(new Date());
265         person.setGender("M");        
266         employee1.setEmployeeDetails(person);
267         employee1.setEmployeeId("123456789");       
268         
269         
270         List<Employee> employees = new ArrayList<Employee>();
271         employees.add(employee1);        
272         acmeCompany.setEmployees(employees);
273         
274         List<String> slogans = new ArrayList<String>();
275         slogans.add("Slogan One");
276         acmeCompany.setSlogans(slogans);
277         
278         dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
279         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
280         Assert.assertTrue(hasError(dictionaryValidationResult, "employees", RiceKeyConstants.ERROR_QUANTITY_RANGE));
281         Assert.assertTrue(hasError(dictionaryValidationResult, "slogans", RiceKeyConstants.ERROR_MIN_OCCURS));
282         
283         //Add two invalid employees, this should result in size constraint, and invalid employee errors
284         employees.add(new Employee());
285         employees.add(new Employee());
286         slogans.add("Slogan Two");
287         
288         dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
289         Assert.assertEquals(5, dictionaryValidationResult.getNumberOfErrors());
290         
291         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[1].employeeId", RiceKeyConstants.ERROR_REQUIRED));        
292         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[1].employeeDetails", RiceKeyConstants.ERROR_REQUIRED));
293         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[2].employeeId", RiceKeyConstants.ERROR_REQUIRED));        
294         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[2].employeeDetails", RiceKeyConstants.ERROR_REQUIRED));
295 
296 	}
297 	
298 	protected boolean hasError(DictionaryValidationResult dvr, String attributeName, String errorKey){
299 	    Iterator<ConstraintValidationResult> dvrIterator = dvr.iterator();
300 	    
301 	    boolean containsError = false;
302 	    while (dvrIterator.hasNext() && !containsError){
303 	        ConstraintValidationResult cvr = dvrIterator.next();
304 	        if (attributeName.contains("[")){
305 	            containsError = attributeName.equals(cvr.getAttributePath()) && errorKey.equals(cvr.getErrorKey()) && ErrorLevel.ERROR==cvr.getStatus();
306 	        } else {
307 	            containsError = attributeName.equals(cvr.getAttributeName()) && errorKey.equals(cvr.getErrorKey()) && ErrorLevel.ERROR==cvr.getStatus();
308 	        }
309 	    }
310 	    
311 	    return containsError;
312 	}
313 	
314 }