001 /** 002 * Copyright 2013 The Kuali Foundation Licensed under the 003 * Educational Community License, Version 2.0 (the "License"); you may 004 * not use this file except in compliance with the License. You may 005 * obtain a copy of the License at 006 * 007 * http://www.osedu.org/licenses/ECL-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, 010 * software distributed under the License is distributed on an "AS IS" 011 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 012 * or implied. See the License for the specific language governing 013 * permissions and limitations under the License. 014 * 015 * Created by Mezba Mahtab (mezba.mahtab@utoronto.ca) on 3/8/13 016 */ 017 package org.kuali.student.mock.mojo; 018 019 import org.kuali.student.contract.model.MessageStructure; 020 import org.kuali.student.contract.model.Service; 021 import org.kuali.student.contract.model.ServiceContractModel; 022 import org.kuali.student.contract.model.ServiceMethod; 023 import org.kuali.student.contract.model.ServiceMethodError; 024 import org.kuali.student.contract.model.ServiceMethodParameter; 025 import org.kuali.student.contract.model.util.ServicesFilter; 026 import org.kuali.student.contract.writer.service.GetterSetterNameCalculator; 027 import org.slf4j.Logger; 028 import org.slf4j.LoggerFactory; 029 030 import javax.management.OperationsException; 031 032 import java.util.ArrayList; 033 import java.util.List; 034 035 /** 036 * This class will generate the base class that does CRUD tests as 037 * part of the Conformance Tests for services. The generated class will 038 * need to be extended (and abstract methods filled in) to be complete. 039 * This class is meant to be generated again and again, and developers 040 * should customize tests in the extended class by extending or overwriting 041 * methods of this class as needed. 042 * 043 * @author Mezba Mahtab (mezba.mahtab@utoronto.ca) 044 */ 045 public class ConformanceTestBaseCrudClassServiceWriter extends MockImplServiceWriter { 046 047 private static final Logger log = LoggerFactory.getLogger(ConformanceTestExtendedCrudClassServiceWriter.class); 048 049 ///////////////////////// 050 // CONSTANTS 051 ///////////////////////// 052 053 public static final String ROOT_PACKAGE = "org.kuali.student"; 054 protected static final String H1_COMMENT_CHAR = "="; 055 protected static final int H1_COMMENT_MARK_LENGTH = 20; 056 057 //////////////////////////// 058 // Data Variables 059 //////////////////////////// 060 061 private ServicesFilter filter; 062 063 List<String> dtoObjectNamesWithCrud = null; // a list of all the DTOs managed by this class that has CRUDs 064 065 protected List<String> getDtoObjectNamesWithCrud() { 066 return dtoObjectNamesWithCrud; 067 } 068 069 //////////////////////////// 070 // CONSTRUCTOR 071 //////////////////////////// 072 073 public ConformanceTestBaseCrudClassServiceWriter(ServiceContractModel model, 074 String directory, 075 String rootPackage, 076 String servKey, 077 List<ServiceMethod> methods, 078 boolean isR1) { 079 super(model, directory, rootPackage, servKey, methods, isR1, calcPackage(servKey, rootPackage), calcClassName(servKey)); 080 dtoObjectNamesWithCrud = calcNamesOfDTOsWithCrudManagedByService(); 081 } 082 083 public ConformanceTestBaseCrudClassServiceWriter(ServiceContractModel model, 084 String directory, 085 String rootPackage, 086 String servKey, 087 List<ServiceMethod> methods, 088 boolean isR1, 089 String packageName, 090 String className) { 091 super(model, directory, rootPackage, servKey, methods, isR1, packageName, className); 092 dtoObjectNamesWithCrud = calcNamesOfDTOsWithCrudManagedByService(); 093 } 094 095 ////////////////////////// 096 // FUNCTIONALS 097 ////////////////////////// 098 099 public static String calcPackage(String servKey, String rootPackage) { 100 String pack = rootPackage + "."; 101 pack = pack + "service.test"; 102 return pack; 103 } 104 105 /** 106 * Given the service key (name), returns a calculated class name for the conformance tester. 107 */ 108 public static String calcClassName(String servKey) { 109 return "Test" + GetterSetterNameCalculator.calcInitUpper(fixServKey(servKey) + "ServiceImplConformanceBaseCrud"); 110 } 111 112 public static List<Service> filterServices(ServiceContractModel model, ServicesFilter filter) { 113 if (filter == null) { 114 return model.getServices(); 115 } 116 return filter.filter(model.getServices()); 117 } 118 119 120 /** 121 * Write out the entire file 122 */ 123 public void write() { 124 // begin file 125 indentPrintln("@RunWith(SpringJUnit4ClassRunner.class)"); 126 indentPrintln("@ContextConfiguration(locations = {\"classpath:" + servKey + "-test-with-mock-context.xml\"})"); 127 indentPrint("public abstract class " + calcClassName(servKey) + " "); 128 // println(" implements " + calcServiceInterfaceClassName(servKey)); 129 Service serv = finder.findService(servKey); 130 setPackageName(serv.getImplProject() + ".impl"); // change the package name 131 importsAdd(serv.getImplProject() + "." + serv.getName()); // import for the service 132 133 doTestImportsAdd(); 134 135 // begin main class 136 openBrace(); 137 138 indentPrintln(""); 139 indentPrintDecoratedComment("SETUP", H1_COMMENT_CHAR, H1_COMMENT_MARK_LENGTH); 140 indentPrintln(""); 141 142 // test service setup 143 indentPrintln("@Resource"); 144 indentPrintln("public " + calcServiceInterfaceClassName(servKey) + " testService;"); 145 indentPrintln("public " + calcServiceInterfaceClassName(servKey) + " get" + calcServiceInterfaceClassName(servKey) + "() { return testService; }"); 146 indentPrintln("public void set" + calcServiceInterfaceClassName(servKey) + "(" + calcServiceInterfaceClassName(servKey) + " service) { testService = service; }"); 147 indentPrintln(""); 148 149 // context info setup 150 indentPrintln("public ContextInfo contextInfo = null;"); 151 indentPrintln("public static String principalId = \"123\";"); 152 indentPrintln(""); 153 indentPrintln("@Before"); 154 indentPrintln("public void setUp()"); 155 openBrace(); 156 indentPrintln("principalId = \"123\";"); 157 indentPrintln("contextInfo = new ContextInfo();"); 158 indentPrintln("contextInfo.setPrincipalId(principalId);"); 159 closeBrace(); 160 indentPrintln(""); 161 162 // testing starts 163 indentPrintDecoratedComment("TESTING", H1_COMMENT_CHAR, H1_COMMENT_MARK_LENGTH); 164 indentPrintln(""); 165 /* 166 new ArrayList<String>(); 167 for (ServiceMethod method: methods) { 168 // I am assuming all the DTOs will have a createXXX method. 169 if (MethodType.CREATE.equals (calcMethodType(method))) { 170 String objectName = calcObjectName(method); 171 dtoObjectNames.add(objectName); 172 } 173 } 174 */ 175 // for each DTO, write the testCRUD 176 for (String dtoObjectName : dtoObjectNamesWithCrud) { 177 writeTestCrud(dtoObjectName); 178 indentPrintln(""); 179 } 180 181 // print out list of service operations that were tested 182 indentPrintDecoratedComment("SERVICE OPS TESTED IN BASE TEST CLASS", H1_COMMENT_CHAR, H1_COMMENT_MARK_LENGTH*2); 183 indentPrintln(""); 184 185 // separate out crud and non-crud methods 186 List<ServiceMethod> methodsTestedAsCrud = new ArrayList<ServiceMethod>(); 187 List<ServiceMethod> methodsNotTested = new ArrayList<ServiceMethod>(); 188 189 for (ServiceMethod method : methods) { 190 if (isServiceMethodTestedAsPartofCrudInBaseConformanceTest (method)) { 191 methodsTestedAsCrud.add(method); 192 } else { 193 methodsNotTested.add(method); 194 } 195 } 196 197 // print out crud methods 198 indentPrintln("/*"); 199 incrementIndent(); 200 indentPrintln("The following methods are tested as part of CRUD operations for this service's DTOs:"); 201 incrementIndent(); 202 for (ServiceMethod method: methodsTestedAsCrud) { 203 indentPrintln(method.getName()); 204 } 205 decrementIndent(); 206 decrementIndent(); 207 indentPrintln("*/"); 208 indentPrintln(""); 209 210 // print out list of service operations that are not tested as abstract test methods 211 indentPrintDecoratedComment("SERVICE OPS NOT TESTED IN BASE TEST CLASS", H1_COMMENT_CHAR, H1_COMMENT_MARK_LENGTH*2); 212 indentPrintln(""); 213 214 // for each method, create an abstract method to test that and print it out 215 for (ServiceMethod method: methodsNotTested) { 216 indentPrintln("/* Method Name: " + method.getName() + " */"); 217 indentPrintln("@Test"); 218 indentPrintln("public abstract void test_" + method.getName() + "() "); 219 if (method.getErrors().size()>0) { 220 indentPrint("throws "); 221 String comma = ""; 222 for (ServiceMethodError error: method.getErrors()) { 223 indentPrint(comma + error.getClassName().trim()); 224 comma = ","; 225 } 226 } 227 indentPrintln(";"); 228 indentPrintln(""); 229 } 230 231 // end file print out 232 closeBrace (); 233 println (""); 234 235 // close and print file 236 this.writeJavaClassAndImportsOutToFile(); 237 this.getOut().close(); 238 } 239 240 /** 241 * Write the CRUD test methods 242 */ 243 public void writeTestCrud (String dtoObjectName) { 244 245 // get the message structures of the dto 246 List<MessageStructure> messageStructures = finder.findMessageStructures(dtoObjectName + "Info"); 247 248 // start method open signature 249 indentPrintln("// ****************************************************"); 250 indentPrintln("// " + dtoObjectName + "Info"); 251 indentPrintln("// ****************************************************"); 252 indentPrintln("@Test"); 253 indentPrintln("public void testCrud" + dtoObjectName + "() "); 254 incrementIndent(); 255 indentPrintln("throws DataValidationErrorException,"); 256 incrementIndent(); 257 indentPrintln("DoesNotExistException,"); 258 indentPrintln("InvalidParameterException,"); 259 indentPrintln("MissingParameterException,"); 260 indentPrintln("OperationFailedException,"); 261 indentPrintln("PermissionDeniedException,"); 262 indentPrintln("ReadOnlyException,"); 263 indentPrintln("VersionMismatchException,"); 264 indentPrintln("DependentObjectsExistException"); 265 decrementIndent(); 266 decrementIndent(); 267 openBrace(); 268 // end method open signature 269 270 // write the test portions 271 incrementIndent(); 272 writeTestCreate(dtoObjectName, messageStructures); 273 writeTestUpdate(dtoObjectName, messageStructures); 274 writeTestReadAfterUpdate(dtoObjectName, messageStructures); 275 writeTestDelete(dtoObjectName, messageStructures); 276 decrementIndent(); 277 278 // end method 279 closeBrace(); 280 indentPrintln(""); 281 282 // methods that will be overwritten 283 writetestCrudXXX_setDTOFieldsForTestCreate(dtoObjectName, messageStructures); 284 writetestCrudXXX_testDTOFieldsForTestCreateUpdate(dtoObjectName, messageStructures); 285 writetestCrudXXX_setDTOFieldsForTestUpdate(dtoObjectName, messageStructures); 286 writetestCrudXXX_testDTOFieldsForTestReadAfterUpdate(dtoObjectName, messageStructures); 287 writetestCrudXXX_setDTOFieldsForTestReadAfterUpdate(dtoObjectName, messageStructures); 288 } 289 290 /** 291 * Write the 'test create' portion. 292 */ 293 public void writeTestCreate (String dtoObjectName, List<MessageStructure> messageStructures) { 294 indentPrintDecoratedComment("test create"); 295 indentPrintln(dtoObjectName + "Info expected = new " + dtoObjectName + "Info ();"); 296 // indentPrintln("expected.setName(\"Name01\");"); 297 // indentPrintln("expected.setDescr(new RichTextHelper().fromPlain(\"Description01\"));"); 298 indentPrintln(""); 299 indentPrintln("// METHOD TO SET DTO FIELDS HERE FOR TEST CREATE"); 300 indentPrintln("testCrud" + dtoObjectName + "_setDTOFieldsForTestCreate (expected);"); 301 indentPrintln(""); 302 303 /* 304 indentPrintln("if (expected.getClass().isAssignableFrom(TypeStateEntityInfo.class))"); 305 openBrace(); 306 incrementIndent(); 307 // indentPrintln("TypeStateEntityInfo expectedTS = (TypeStateEntityInfo) expected;"); 308 indentPrintln("expected.setTypeKey(\"typeKey01\");"); 309 indentPrintln("expected.setStateKey(\"stateKey01\");"); 310 decrementIndent(); 311 closeBrace(); 312 */ 313 indentPrintln("new AttributeTester().add2ForCreate(expected.getAttributes());"); 314 315 indentPrintln(""); 316 indentPrintln("// code to create actual"); 317 indentPrintln(dtoObjectName + "Info actual = " + getMethodCallAsString ("create" + dtoObjectName, "= null; // TODO INSERT CODE TO CREATE actual HERE", MethodType.CREATE, dtoObjectName, "expected")); 318 indentPrintln(""); 319 320 // indentPrintln("if (actual.getClass().isAssignableFrom(IdEntityInfo.class))"); 321 if (finder.findMessageStructure(dtoObjectName + "Info", "id")!=null) { 322 // openBrace(); 323 // incrementIndent(); 324 indentPrintln("assertNotNull(actual.getId());"); 325 indentPrintln("new IdEntityTester().check(expected, actual);"); 326 // decrementIndent(); 327 // closeBrace(); 328 } 329 else if (finder.findMessageStructure(dtoObjectName + "Info", "key")!=null) { 330 indentPrintln("assertNotNull(actual.getKey());"); 331 indentPrintln("new KeyEntityTester().check(expected, actual);"); 332 } 333 334 indentPrintln(""); 335 indentPrintln("// METHOD TO TEST DTO FIELDS HERE FOR TEST CREATE"); 336 indentPrintln("testCrud" + dtoObjectName + "_testDTOFieldsForTestCreateUpdate (expected, actual);"); 337 indentPrintln(""); 338 339 indentPrintln("new AttributeTester().check(expected.getAttributes(), actual.getAttributes());"); 340 indentPrintln("new MetaTester().checkAfterCreate(actual.getMeta());"); 341 indentPrintln(""); 342 343 indentPrintDecoratedComment("test read"); 344 indentPrintln("expected = actual;"); 345 indentPrintln("actual = " + getMethodCallAsString ("get" + dtoObjectName, "null; // TODO INSERT CODE TO GET actual HERE BY CALLING SERVICE OP", MethodType.GET_BY_ID, dtoObjectName, "actual")); 346 if (finder.findMessageStructure(dtoObjectName + "Info", "id")!=null) { 347 indentPrintln("assertEquals(expected.getId(), actual.getId());"); 348 indentPrintln("new IdEntityTester().check(expected, actual);"); 349 } 350 else if (finder.findMessageStructure(dtoObjectName + "Info", "key")!=null) { 351 indentPrintln("assertEquals(expected.getKey(), actual.getKey());"); 352 indentPrintln("new KeyEntityTester().check(expected, actual);"); 353 } 354 355 356 indentPrintln(""); 357 358 indentPrintln("// INSERT CODE FOR TESTING MORE DTO FIELDS HERE"); 359 indentPrintln("testCrud" + dtoObjectName + "_testDTOFieldsForTestCreateUpdate (expected, actual);"); 360 indentPrintln(""); 361 362 indentPrintln("new AttributeTester().check(expected.getAttributes(), actual.getAttributes());"); 363 indentPrintln("new MetaTester().checkAfterGet(expected.getMeta(), actual.getMeta());"); 364 indentPrintln(""); 365 } 366 367 /** 368 * Write the 'test update' portion. 369 */ 370 public void writeTestUpdate (String dtoObjectName, List<MessageStructure> messageStructures) { 371 indentPrintDecoratedComment("test update"); 372 indentPrintln(dtoObjectName + "Info original = new " + dtoObjectName + "Info (actual);"); 373 indentPrintln("expected = new " + dtoObjectName + "Info (actual);"); 374 375 // indentPrintln("expected.setName(expected.getName() + \" updated\");"); 376 // indentPrintln("expected.setDescr(new RichTextHelper().fromPlain(expected.getDescr().getPlain() + \"_Updated\"));"); 377 indentPrintln(""); 378 // indentPrintln("if (expected.getClass().isAssignableFrom(TypeStateEntityInfo.class))"); 379 if (finder.findMessageStructure(dtoObjectName + "Info", "stateKey")!=null) { 380 // openBrace(); 381 // incrementIndent(); 382 // indentPrintln("TypeStateEntityInfo expectedTS = (TypeStateEntityInfo) expected;"); 383 indentPrintln("expected.setStateKey(expected.getState() + \"_Updated\");"); 384 // decrementIndent(); 385 // closeBrace(); 386 } 387 indentPrintln(""); 388 indentPrintln("// METHOD TO INSERT CODE TO UPDATE DTO FIELDS HERE"); 389 indentPrintln("testCrud" + dtoObjectName + "_setDTOFieldsForTestUpdate (expected);"); 390 indentPrintln(""); 391 indentPrintln("new AttributeTester().delete1Update1Add1ForUpdate(expected.getAttributes());"); 392 393 indentPrintln("// code to update"); 394 indentPrintln("actual = " + getMethodCallAsString ("update" + dtoObjectName, "= null; // TODO INSERT CODE TO CALL UPDATE SERVICE OP HERE", MethodType.UPDATE, dtoObjectName, "expected")); 395 indentPrintln(""); 396 397 if (finder.findMessageStructure(dtoObjectName + "Info", "id")!=null) { 398 indentPrintln("assertEquals(expected.getId(), actual.getId());"); 399 indentPrintln("new IdEntityTester().check(expected, actual);"); 400 } 401 else if (finder.findMessageStructure(dtoObjectName + "Info", "key")!=null) { 402 indentPrintln("assertEquals(expected.getKey(), actual.getKey());"); 403 indentPrintln("new KeyEntityTester().check(expected, actual);"); 404 } 405 indentPrintln(""); 406 indentPrintln("// METHOD TO INSERT CODE FOR TESTING DTO FIELDS HERE"); 407 indentPrintln("testCrud" + dtoObjectName + "_testDTOFieldsForTestCreateUpdate (expected, actual);"); 408 indentPrintln(""); 409 indentPrintln("new AttributeTester().check(expected.getAttributes(), actual.getAttributes());"); 410 indentPrintln("new MetaTester().checkAfterUpdate(expected.getMeta(), actual.getMeta());"); 411 indentPrintln(""); 412 413 indentPrintln("// Test that VersionMissmatchException's are being detected"); 414 indentPrintln("boolean exception = false;"); 415 indentPrintln("try {"); 416 indent(getOut(), ' '); 417 418 indentPrintln(getMethodCallAsString ("update" + dtoObjectName, "= null; // TODO INSERT CODE TO CALL UPDATE SERVICE OP HERE", MethodType.UPDATE, dtoObjectName, "original")); 419 indentPrintln("}"); 420 indentPrintln("catch (VersionMismatchException e) { "); 421 indent(getOut(), ' '); 422 indentPrint("exception = true;"); 423 indentPrintln("}"); 424 indentPrintln(""); 425 426 indentPrintln("Assert.assertTrue(\"VersionMissmatchException was not detected!\", exception);"); 427 indentPrintln(""); 428 429 } 430 431 /** 432 * Write the 'read after update' portion. 433 */ 434 public void writeTestReadAfterUpdate (String dtoObjectName, List<MessageStructure> messageStructures) { 435 indentPrintDecoratedComment("test read after update"); 436 indentPrintln(""); 437 indentPrintln("expected = actual;"); 438 439 indentPrintln("// code to get actual"); 440 indentPrintln("actual = " + getMethodCallAsString ("get" + dtoObjectName, "null; // TODO INSERT CODE TO GET actual HERE BY CALLING SERVICE OP", MethodType.GET_BY_ID, dtoObjectName, "actual")); 441 indentPrintln(""); 442 if (finder.findMessageStructure(dtoObjectName + "Info", "id")!=null) { 443 indentPrintln("assertEquals(expected.getId(), actual.getId());"); 444 indentPrintln("new IdEntityTester().check(expected, actual);"); 445 } 446 else if (finder.findMessageStructure(dtoObjectName + "Info", "key")!=null) { 447 indentPrintln("assertEquals(expected.getKey(), actual.getKey());"); 448 indentPrintln("new KeyEntityTester().check(expected, actual);"); 449 } 450 indentPrintln(""); 451 indentPrintln("// INSERT METHOD CODE FOR TESTING DTO FIELDS HERE"); 452 indentPrintln("testCrud" + dtoObjectName + "_testDTOFieldsForTestReadAfterUpdate (expected, actual);"); 453 indentPrintln(""); 454 indentPrintln("new AttributeTester().check(expected.getAttributes(), actual.getAttributes());"); 455 indentPrintln("new MetaTester().checkAfterGet(expected.getMeta(), actual.getMeta());"); 456 indentPrintln(""); 457 indentPrintln(dtoObjectName + "Info alphaDTO = actual;"); 458 indentPrintln(""); 459 indentPrintln("// create a 2nd DTO"); 460 indentPrintln(dtoObjectName + "Info betaDTO = new " + dtoObjectName + "Info ();"); 461 // indentPrintln("betaDTO.setName(\"Beta entity name\");"); 462 // indentPrintln("betaDTO.setDescr(new RichTextHelper().fromPlain(\"Beta entity description\"));"); 463 indentPrintln(""); 464 indentPrintln("// METHOD TO INSERT CODE TO SET MORE DTO FIELDS HERE"); 465 indentPrintln("testCrud" + dtoObjectName + "_setDTOFieldsForTestReadAfterUpdate (betaDTO);"); 466 indentPrintln(""); 467 // indentPrintln("if (betaDTO.getClass().isAssignableFrom(TypeStateEntityInfo.class))"); 468 if (finder.findMessageStructure(dtoObjectName + "Info", "typeKey")!=null) { 469 // openBrace(); 470 // incrementIndent(); 471 //indentPrintln("TypeStateEntityInfo betaDTOTS = (TypeStateEntityInfo) betaDTO;"); 472 indentPrintln("betaDTO.setTypeKey(\"typeKeyBeta\");"); 473 // decrementIndent(); 474 // closeBrace(); 475 } 476 if (finder.findMessageStructure(dtoObjectName + "Info", "stateKey")!=null) { 477 indentPrintln("betaDTO.setStateKey(\"stateKeyBeta\");"); 478 } 479 indentPrintln("betaDTO = " + getMethodCallAsString("create" + dtoObjectName, "null; // TODO INSERT CODE TO CREATE betaDTO", MethodType.CREATE, dtoObjectName, "betaDTO")); 480 481 indentPrintln(""); 482 indentPrintDecoratedComment("test bulk get with no ids supplied"); 483 indentPrintln(""); 484 indentPrintln("List<String> " + initLower(dtoObjectName) + "Ids = new ArrayList<String>();"); 485 486 indentPrintln("// code to get DTO by Ids"); 487 indentPrintln("List<" + dtoObjectName + "Info> records = " + getMethodCallAsString ("get" + dtoObjectName + "sByIds", "null; // TODO INSERT CODE TO GET DTO BY IDS", MethodType.GET_BY_IDS, dtoObjectName)); 488 indentPrintln(""); 489 490 indentPrintln("assertEquals(" + initLower(dtoObjectName) + "Ids.size(), records.size());"); 491 indentPrintln("assertEquals(0, " + initLower(dtoObjectName) + "Ids.size());"); 492 indentPrintln(""); 493 indentPrintDecoratedComment("test bulk get"); 494 indentPrintln(initLower(dtoObjectName) + "Ids = new ArrayList<String>();"); 495 indentPrintln(initLower(dtoObjectName) + "Ids.add(alphaDTO.getId());"); 496 indentPrintln(initLower(dtoObjectName) + "Ids.add(betaDTO.getId());"); 497 498 indentPrintln("// code to get DTO by Ids"); 499 indentPrintln("records = " + getMethodCallAsString ("get" + dtoObjectName + "sByIds", "null; // TODO INSERT CODE TO GET DTO BY IDS", MethodType.GET_BY_IDS, dtoObjectName)); 500 indentPrintln(""); 501 502 indentPrintln("assertEquals(" + initLower(dtoObjectName) + "Ids.size(), records.size());"); 503 indentPrintln("for (" + dtoObjectName + "Info record : records)"); 504 openBrace(); 505 incrementIndent(); 506 indentPrintln("if (!" + initLower(dtoObjectName) + "Ids.remove(record.getId()))"); 507 openBrace(); 508 incrementIndent(); 509 indentPrintln("fail(record.getId());"); 510 decrementIndent(); 511 closeBrace(); 512 decrementIndent(); 513 closeBrace(); 514 indentPrintln("assertEquals(0, " + initLower(dtoObjectName) + "Ids.size());"); 515 indentPrintln(""); 516 indentPrintDecoratedComment("test get by type"); 517 518 indentPrintln("// code to get by specific type \"typeKey01\" "); 519 indentPrintln(initLower(dtoObjectName) + "Ids = testService.get" + dtoObjectName + "IdsByType (\"typeKey_Updated\", contextInfo);"); 520 // indentPrintln(initLower(dtoObjectName) + "Ids = " + getMethodCallAsString ("get" + dtoObjectName + "IdsByType", "// INSERT CODE TO GET BY SPECIFIC TYPE \"typeKey01\" HERE", MethodType.GET_IDS_BY_TYPE)); 521 indentPrintln(""); 522 523 indentPrintln("assertEquals(1, " + initLower(dtoObjectName) + "Ids.size());"); 524 indentPrintln("assertEquals(alphaDTO.getId(), " + initLower(dtoObjectName) + "Ids.get(0));"); 525 indentPrintln(""); 526 indentPrintln("// test get by other type"); 527 528 indentPrintln("// code to get by specific type \"typeKeyBeta\" "); 529 indentPrintln(initLower(dtoObjectName) + "Ids = testService.get" + dtoObjectName + "IdsByType (\"typeKeyBeta\", contextInfo);"); 530 // indentPrintln(initLower(dtoObjectName) + "Ids = " + getMethodCallAsString ("get" + dtoObjectName + "IdsByType", "// INSERT CODE TO GET BY SPECIFIC TYPE \"typeKeyBeta\" HERE", MethodType.GET_IDS_BY_TYPE)); 531 indentPrintln(""); 532 533 indentPrintln("assertEquals(1, " + initLower(dtoObjectName) + "Ids.size());"); 534 indentPrintln("assertEquals(betaDTO.getId(), " + initLower(dtoObjectName) + "Ids.get(0));"); 535 indentPrintln(""); 536 } 537 538 /** 539 * Write the 'delete' portion. 540 */ 541 public void writeTestDelete (String dtoObjectName, List<MessageStructure> messageStructures) { 542 indentPrintDecoratedComment("test delete"); 543 indentPrintln(""); 544 545 indentPrintln("StatusInfo status = " + getMethodCallAsString ("delete" + dtoObjectName, "null; // TODO INSERT CODE TO DELETE RECORD", MethodType.DELETE, dtoObjectName, "actual")); 546 indentPrintln(""); 547 548 indentPrintln("assertNotNull(status);"); 549 indentPrintln("assertTrue(status.getIsSuccess());"); 550 indentPrintln("try"); 551 openBrace(); 552 incrementIndent(); 553 indentPrintln(dtoObjectName + "Info record = " + getMethodCallAsString ("get" + dtoObjectName, "null; // TODO INSERT CODE TO RETRIEVE RECENTLY DELETED RECORD", MethodType.GET_BY_ID, dtoObjectName, "actual")); 554 indentPrintln("fail(\"Did not receive DoesNotExistException when attempting to get already-deleted entity\");"); 555 decrementIndent(); 556 closeBrace(); 557 indentPrintln("catch (DoesNotExistException dnee)"); 558 openBrace(); 559 incrementIndent(); 560 indentPrintln("// expected"); 561 decrementIndent(); 562 closeBrace(); 563 indentPrintln(""); 564 } 565 566 /** 567 * Writes out a decorated comment. 568 */ 569 public void indentPrintDecoratedComment (String label) { 570 indentPrintDecoratedComment(label, "-", 37); 571 /* 572 indentPrintln("// -------------------------------------"); 573 indentPrintln("// " + label); 574 indentPrintln("// -------------------------------------"); 575 */ 576 } 577 578 /** 579 * Writes out a decorated comment, with the decoration string passed in. 580 */ 581 public void indentPrintDecoratedComment (String label, String decorChar, int decorLength) { 582 String decorPattern = ""; 583 for (int i=0; i<decorLength; i++) { decorPattern += decorChar; } 584 indentPrintln("// " + decorPattern); 585 indentPrintln("// " + label); 586 indentPrintln("// " + decorPattern); 587 } 588 589 /** 590 * Gets the method with the name. 591 */ 592 private ServiceMethod getServiceMethod (String methodName) throws OperationsException { 593 for (ServiceMethod method : methods) { 594 if (method.getName().equals(methodName)) return method; 595 } 596 throw new OperationsException("Method " + methodName + " not found!"); 597 } 598 599 /** 600 * Gets the string to print to call a method with the given name. 601 * @param dtoObjectName 602 */ 603 private String getMethodCallAsString (String builtUpMethodName, String errorCode, MethodType methodType, String dtoObjectName) { 604 return getMethodCallAsString (builtUpMethodName, errorCode, methodType, dtoObjectName, null); 605 } 606 607 /** 608 * Gets the string to print to call a method with the given name. 609 */ 610 private String getMethodCallAsString (String builtUpMethodName, String errorCode, MethodType methodType, String dtoName, String dtoNameReplacement) { 611 try { 612 ServiceMethod method = getServiceMethod(builtUpMethodName); 613 String methodCallStr = ""; 614 methodCallStr += method.getName() + " ("; 615 String comma = " "; 616 for (ServiceMethodParameter param : method.getParameters()) { 617 methodCallStr += comma; 618 if (dtoName!=null && dtoNameReplacement!=null) { 619 if ((dtoName + "Info").toLowerCase().equals(param.getName().toLowerCase())) { 620 methodCallStr += dtoNameReplacement; 621 } 622 else if (param.getName().endsWith("TypeKey")) { 623 methodCallStr += dtoNameReplacement + ".getTypeKey()"; 624 } 625 else if (param.getName().endsWith("Id")) { 626 methodCallStr += dtoNameReplacement + ".getId()"; 627 } 628 else { 629 methodCallStr += param.getName(); 630 } 631 } else { 632 methodCallStr += param.getName(); 633 } 634 comma = ", "; 635 } 636 methodCallStr += ");"; 637 return "testService." + methodCallStr; 638 } catch (Exception e) { 639 640 if (dtoName != null) 641 log.error("dtoName = " + dtoName + ", methodName = " + builtUpMethodName + ", errorCode = " + errorCode); 642 else 643 log.error("dtoName = unknown, methodName = " + builtUpMethodName + ", errorCode = " + errorCode); 644 645 return errorCode; 646 } 647 648 } 649 650 /** 651 * Writes the section to set fields specific to this dto for testCreate section. 652 */ 653 public void writetestCrudXXX_setDTOFieldsForTestCreate(String dtoObjectName, List<MessageStructure> messageStructures) { 654 indentPrintln("/*"); 655 incrementIndent(); 656 indentPrintln("A method to set the fields for a " + dtoObjectName + " in a 'test create' section prior to calling the 'create' operation."); 657 decrementIndent(); 658 indentPrintln("*/"); 659 indentPrintln("public abstract void testCrud" + dtoObjectName + "_setDTOFieldsForTestCreate(" + dtoObjectName + "Info expected);"); 660 indentPrintln(""); 661 } 662 663 /** 664 * Writes the section to test fields specific to this dto for testCreate and testUpdate sections. 665 */ 666 public void writetestCrudXXX_testDTOFieldsForTestCreateUpdate(String dtoObjectName, List<MessageStructure> messageStructures) { 667 indentPrintln("/*"); 668 incrementIndent(); 669 indentPrintln("A method to test the fields for a " + dtoObjectName + ". This is called after:"); 670 indentPrintln("- creating a DTO, where actual is the DTO returned by the create operation, and expected is the dto passed in to the create operation"); 671 indentPrintln("- reading a DTO after creating it, and actual is the read DTO, and expected is the dto that was created"); 672 indentPrintln("- updating a DTO, where actual is DTO returned by the update operation, and expected is the dto that was passed in to the update operation"); 673 decrementIndent(); 674 indentPrintln("*/"); 675 indentPrintln("public abstract void testCrud" + dtoObjectName + "_testDTOFieldsForTestCreateUpdate(" + dtoObjectName + "Info expected, " + dtoObjectName + "Info actual);"); 676 indentPrintln(""); 677 } 678 679 680 /** 681 * Writes the section to set fields specific to this dto for testUpdate sections. 682 */ 683 public void writetestCrudXXX_setDTOFieldsForTestUpdate(String dtoObjectName, List<MessageStructure> messageStructures) { 684 indentPrintln("/*"); 685 incrementIndent(); 686 indentPrintln("A method to set the fields for a " + dtoObjectName + " in a 'test update' section prior to calling the 'update' operation."); 687 decrementIndent(); 688 indentPrintln("*/"); 689 indentPrintln("public abstract void testCrud" + dtoObjectName + "_setDTOFieldsForTestUpdate(" + dtoObjectName + "Info expected);"); 690 indentPrintln(""); 691 } 692 693 /** 694 * Writes the section to test fields specific to this dto for testReadAfterUpdate sections. 695 */ 696 public void writetestCrudXXX_testDTOFieldsForTestReadAfterUpdate(String dtoObjectName, List<MessageStructure> messageStructures) { 697 indentPrintln("/*"); 698 incrementIndent(); 699 indentPrintln("A method to test the fields for a " + dtoObjectName + " after an update operation, followed by a read operation,"); 700 indentPrintln("where actual is the DTO returned by the read operation, and expected is the dto returned by the update operation."); 701 decrementIndent(); 702 indentPrintln("*/"); 703 indentPrintln("public abstract void testCrud" + dtoObjectName + "_testDTOFieldsForTestReadAfterUpdate(" + dtoObjectName + "Info expected, " + dtoObjectName + "Info actual);"); 704 indentPrintln(""); 705 } 706 707 /** 708 * Writes the section to set fields specific to this dto for testReadAfterUpdate sections. 709 */ 710 public void writetestCrudXXX_setDTOFieldsForTestReadAfterUpdate(String dtoObjectName, List<MessageStructure> messageStructures) { 711 indentPrintln("/*"); 712 incrementIndent(); 713 indentPrintln("A method to set the fields for a " + dtoObjectName + " in the 'test read after update' section."); 714 indentPrintln("This dto is another (second) dto object being created for other tests."); 715 decrementIndent(); 716 indentPrintln("*/"); 717 indentPrintln("public abstract void testCrud" + dtoObjectName + "_setDTOFieldsForTestReadAfterUpdate(" + dtoObjectName + "Info expected);"); 718 indentPrintln(""); 719 } 720 721 /** 722 * Given a method type, returns true if this method is tested as part of CRUD operations 723 * tested by the base test conformance class. 724 */ 725 protected boolean isServiceMethodTestedAsPartofCrudInBaseConformanceTest (ServiceMethod method) { 726 MethodType methodType = calcMethodType(method); 727 if ((MethodType.CREATE.equals(methodType)) 728 || (MethodType.UPDATE.equals(methodType)) 729 || (MethodType.DELETE.equals(methodType)) 730 || (MethodType.GET_BY_ID.equals(methodType)) 731 || (MethodType.GET_BY_IDS.equals(methodType)) 732 || (MethodType.GET_IDS_BY_TYPE.equals(methodType)) 733 || (MethodType.GET_TYPE.equals(methodType)) 734 || (MethodType.GET_TYPES.equals(methodType)) 735 || (MethodType.GET_IDS_BY_TYPE.equals(methodType)) 736 ) { 737 return true; 738 } else { 739 return false; 740 } 741 742 } 743 744 /** 745 * Gets a list of all the DTO names that are part of this service. 746 */ 747 protected List<String> calcNamesOfDTOsWithCrudManagedByService() { 748 List<String> dtoObjectNames = new ArrayList<String>(); 749 for (ServiceMethod method: methods) { 750 // I am assuming all the DTOs will have a createXXX method. 751 if (MethodType.CREATE.equals (calcMethodType(method))) { 752 String objectName = calcObjectName(method); 753 // check if this is a valid info object 754 if (finder.findXmlType(objectName + "Info")!=null) { 755 dtoObjectNames.add(objectName); 756 } 757 /* 758 for (XmlType xmlType: model.getXmlTypes()) { 759 if (xmlType.getName().equals(objectName + "Info")) { 760 dtoObjectNames.add(objectName); 761 break; 762 } 763 } 764 */ 765 } 766 } 767 return dtoObjectNames; 768 } 769 770 /** 771 * Does the importsAdd for all files required for testing 772 */ 773 protected void doTestImportsAdd() { 774 // kuali imports 775 importsAdd("org.kuali.student.common.test.util.IdEntityTester"); 776 importsAdd("org.kuali.student.common.test.util.KeyEntityTester"); 777 importsAdd("org.kuali.student.r2.common.dto.ContextInfo"); 778 importsAdd("org.kuali.student.r2.common.dto.IdEntityInfo"); 779 importsAdd("org.kuali.student.r2.common.dto.StatusInfo"); 780 importsAdd("org.kuali.student.r2.common.dto.TypeStateEntityInfo"); 781 importsAdd("org.kuali.student.r2.common.util.RichTextHelper"); 782 importsAdd("org.kuali.student.r2.core.organization.service.impl.lib.AttributeTester"); 783 importsAdd("org.kuali.student.r2.core.organization.service.impl.lib.MetaTester"); 784 785 // import all the dto 786 // for each DTO, write the testCRUD 787 for (String dtoObjectName : dtoObjectNamesWithCrud) { 788 try { importsAdd(finder.findXmlType(dtoObjectName + "Info").getJavaPackage() + "." + dtoObjectName + "Info"); } 789 catch (Exception ignored) {} 790 } 791 792 // exceptions 793 importsAdd("org.kuali.student.r2.common.exceptions.DataValidationErrorException"); 794 importsAdd("org.kuali.student.r2.common.exceptions.DependentObjectsExistException"); 795 importsAdd("org.kuali.student.r2.common.exceptions.DoesNotExistException"); 796 importsAdd("org.kuali.student.r2.common.exceptions.InvalidParameterException"); 797 importsAdd("org.kuali.student.r2.common.exceptions.MissingParameterException"); 798 importsAdd("org.kuali.student.r2.common.exceptions.OperationFailedException"); 799 importsAdd("org.kuali.student.r2.common.exceptions.PermissionDeniedException"); 800 importsAdd("org.kuali.student.r2.common.exceptions.ReadOnlyException"); 801 importsAdd("org.kuali.student.r2.common.exceptions.VersionMismatchException"); 802 803 // java imports 804 importsAdd("org.springframework.test.context.ContextConfiguration"); 805 importsAdd("org.springframework.test.context.junit4.SpringJUnit4ClassRunner"); 806 importsAdd("org.junit.Assert"); 807 importsAdd("org.junit.Before"); 808 importsAdd("org.junit.Test"); 809 importsAdd("org.junit.runner.RunWith"); 810 importsAdd("static org.junit.Assert.assertEquals"); 811 importsAdd("static org.junit.Assert.assertFalse"); 812 importsAdd("static org.junit.Assert.assertNotNull"); 813 importsAdd("static org.junit.Assert.assertNull"); 814 importsAdd("static org.junit.Assert.assertTrue"); 815 importsAdd("static org.junit.Assert.fail"); 816 importsAdd("javax.annotation.Resource"); 817 importsAdd("java.util.ArrayList"); 818 importsAdd("java.util.List"); 819 } 820 }