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 extends KRADTestCase {
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         KualiModuleServiceImpl moduleService = new KualiModuleServiceImpl();
186 		service.setDataDictionaryService(dataDictionaryService);
187 						
188 		//Get object entries from dictionary
189 		DataObjectEntry addressEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Address");
190         DataObjectEntry companyEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Company");
191 		
192 		//Validate object entries
193 		addressEntry.completeValidation();
194 		companyEntry.completeValidation();
195 		
196 		Company acmeCompany = new Company();
197 		
198 		//Validate empty Company object
199         DictionaryValidationResult dictionaryValidationResult;		
200 		dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
201 		
202 		//Main address is required this should result in error
203 		Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
204 		Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress", RiceKeyConstants.ERROR_REQUIRED));
205 		
206 		//Adding an invalid mainAddress for company 
207 		Address acmeMainAddress = new Address();
208 		acmeCompany.setMainAddress(acmeMainAddress);
209 		
210 		dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
211 		
212 		//This should result in missing country error
213 		Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
214 		Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress.country", RiceKeyConstants.ERROR_REQUIRED));
215 	    Assert.assertTrue(hasError(dictionaryValidationResult, "mainAddress", RiceKeyConstants.ERROR_OCCURS));
216 		
217 		//Set items to valid address
218 		acmeMainAddress.setCountry("US");
219 		acmeMainAddress.setPostalCode("11111");
220 		
221 		dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
222 		
223 		//This should result in no error
224 		Assert.assertEquals(0, dictionaryValidationResult.getNumberOfErrors());
225 		
226 		//Test Nested Attribute Within Nested Attribute, and nested property override
227 		Employee companyContact = new Employee();
228 		acmeCompany.setMainContact(companyContact);
229 		Person mainContactPerson = new Person();
230 		companyContact.setEmployeeDetails(mainContactPerson);
231 		companyContact.setEmployeeId("companyContact");
232 
233 		dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);		
234 
235 		Assert.assertEquals(1, dictionaryValidationResult.getNumberOfErrors());
236 		Assert.assertTrue(hasError(dictionaryValidationResult, "mainContact.employeeDetails.gender", RiceKeyConstants.ERROR_REQUIRED));
237 	}
238 	
239 	@Test
240     public void testCollectionConstraints() throws IOException{
241         DataDictionaryService dataDictionaryService = new DataDictionaryServiceImpl(dataDictionary);
242         service.setDataDictionaryService(dataDictionaryService);
243 
244         DataObjectEntry companyEntry = dataDictionary.getDataObjectEntry("org.kuali.rice.krad.datadictionary.validation.Company");
245 
246         //Add collection constraint provider so constraints on collections get processed
247         service.getConstraintProviders().add(new CollectionDefinitionConstraintProvider());
248 	    
249         Company acmeCompany = new Company();
250         Address acmeMainAddress = new Address();
251         acmeMainAddress.setCountry("US");
252         acmeMainAddress.setPostalCode("11111");
253         acmeCompany.setMainAddress(acmeMainAddress);
254         
255         DictionaryValidationResult dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
256         
257         //Company requires at least two employees
258         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
259         Assert.assertTrue(hasError(dictionaryValidationResult, "employees", RiceKeyConstants.ERROR_QUANTITY_RANGE));
260         Assert.assertTrue(hasError(dictionaryValidationResult, "slogans", RiceKeyConstants.ERROR_MIN_OCCURS));        
261         
262         //Add required employes and revalidate
263         Employee employee1 = new Employee();
264         Person person = new Person();
265         person.setBirthDate(new Date());
266         person.setGender("M");        
267         employee1.setEmployeeDetails(person);
268         employee1.setEmployeeId("123456789");       
269         
270         
271         List<Employee> employees = new ArrayList<Employee>();
272         employees.add(employee1);        
273         acmeCompany.setEmployees(employees);
274         
275         List<String> slogans = new ArrayList<String>();
276         slogans.add("Slogan One");
277         acmeCompany.setSlogans(slogans);
278         
279         dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
280         Assert.assertEquals(2, dictionaryValidationResult.getNumberOfErrors());
281         Assert.assertTrue(hasError(dictionaryValidationResult, "employees", RiceKeyConstants.ERROR_QUANTITY_RANGE));
282         Assert.assertTrue(hasError(dictionaryValidationResult, "slogans", RiceKeyConstants.ERROR_MIN_OCCURS));
283         
284         //Add two invalid employees, this should result in size constraint, and invalid employee errors
285         employees.add(new Employee());
286         employees.add(new Employee());
287         slogans.add("Slogan Two");
288         
289         dictionaryValidationResult = service.validate(acmeCompany, "org.kuali.rice.krad.datadictionary.validation.Company",companyEntry, true);
290         Assert.assertEquals(5, dictionaryValidationResult.getNumberOfErrors());
291         
292         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[1].employeeId", RiceKeyConstants.ERROR_REQUIRED));
293         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[1].employeeDetails", RiceKeyConstants.ERROR_REQUIRED));
294         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[2].employeeId", RiceKeyConstants.ERROR_REQUIRED));
295         Assert.assertTrue(hasError(dictionaryValidationResult, "employees[2].employeeDetails", RiceKeyConstants.ERROR_REQUIRED));
296 
297 	}
298 	
299 	protected boolean hasError(DictionaryValidationResult dvr, String attributeName, String errorKey){
300 	    Iterator<ConstraintValidationResult> dvrIterator = dvr.iterator();
301 	    
302 	    boolean containsError = false;
303 	    while (dvrIterator.hasNext() && !containsError){
304 	        ConstraintValidationResult cvr = dvrIterator.next();
305 	        if (attributeName.contains("[")){
306 	            containsError = attributeName.equals(cvr.getAttributePath()) && errorKey.equals(cvr.getErrorKey()) && ErrorLevel.ERROR==cvr.getStatus();
307 	        } else {
308 	            containsError = attributeName.equals(cvr.getAttributeName()) && errorKey.equals(cvr.getErrorKey()) && ErrorLevel.ERROR==cvr.getStatus();
309 	        }
310 	    }
311 	    
312 	    return containsError;
313 	}
314 	
315 }