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 Charles on 5/6/13 016 */ 017package org.kuali.student.enrollment.class2.courseoffering.service.impl; 018 019import org.kuali.rice.core.api.criteria.PredicateFactory; 020import org.kuali.rice.core.api.criteria.QueryByCriteria; 021import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader; 022import org.kuali.rice.krad.uif.service.impl.ViewHelperServiceImpl; 023import org.kuali.student.enrollment.class2.courseoffering.dto.RGStateWrapper; 024import org.kuali.student.enrollment.class2.courseoffering.dto.StatePropagationWrapper; 025import org.kuali.student.enrollment.class2.courseoffering.form.TestStatePropagationForm; 026import org.kuali.student.enrollment.class2.courseoffering.service.TestStatePropagationViewHelperService; 027import org.kuali.student.enrollment.class2.courseoffering.service.exception.AssertException; 028import org.kuali.student.enrollment.class2.courseoffering.service.exception.PseudoUnitTestException; 029import org.kuali.student.enrollment.class2.courseoffering.service.util.AFUTTypeEnum; 030import org.kuali.student.enrollment.class2.courseoffering.service.util.AoStateTransitionRefSolution; 031import org.kuali.student.enrollment.class2.courseoffering.service.util.PseudoUnitTestStateTransitionGrid; 032import org.kuali.student.enrollment.class2.courseoffering.service.util.RegGroupStateResult; 033import org.kuali.student.enrollment.class2.courseoffering.service.util.TransitionGridYesNoEnum; 034import org.kuali.student.enrollment.class2.courseoffering.util.CourseOfferingConstants; 035import org.kuali.student.enrollment.class2.courseoffering.util.CourseOfferingManagementUtil; 036import org.kuali.student.enrollment.class2.courseofferingset.service.facade.RolloverAssist; 037import org.kuali.student.enrollment.class2.courseofferingset.util.CourseOfferingSetUtil; 038import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingInfo; 039import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingInfo; 040import org.kuali.student.enrollment.courseoffering.dto.FormatOfferingInfo; 041import org.kuali.student.enrollment.courseoffering.dto.RegistrationGroupInfo; 042import org.kuali.student.enrollment.courseofferingset.dto.SocInfo; 043import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultInfo; 044import org.kuali.student.enrollment.courseofferingset.dto.SocRolloverResultItemInfo; 045import org.kuali.student.enrollment.lui.dto.LuiInfo; 046import org.kuali.student.enrollment.lui.dto.LuiLuiRelationInfo; 047import org.kuali.student.poc.eventproc.KSEventProcessorImpl; 048import org.kuali.student.poc.eventproc.event.KSEvent; 049import org.kuali.student.poc.eventproc.event.KSEventFactory; 050import org.kuali.student.r2.common.dto.ContextInfo; 051import org.kuali.student.r2.common.dto.RichTextInfo; 052import org.kuali.student.r2.common.dto.StatusInfo; 053import org.kuali.student.r2.common.exceptions.DataValidationErrorException; 054import org.kuali.student.r2.common.exceptions.DoesNotExistException; 055import org.kuali.student.r2.common.exceptions.InvalidParameterException; 056import org.kuali.student.r2.common.exceptions.MissingParameterException; 057import org.kuali.student.r2.common.exceptions.OperationFailedException; 058import org.kuali.student.r2.common.exceptions.PermissionDeniedException; 059import org.kuali.student.r2.common.exceptions.ReadOnlyException; 060import org.kuali.student.r2.common.exceptions.VersionMismatchException; 061import org.kuali.student.common.util.security.ContextUtils; 062import org.kuali.student.r2.common.util.constants.CourseOfferingServiceConstants; 063import org.kuali.student.r2.common.util.constants.CourseOfferingSetServiceConstants; 064import org.kuali.student.r2.common.util.constants.LuiServiceConstants; 065import org.kuali.student.r2.core.acal.dto.TermInfo; 066import org.kuali.student.r2.core.acal.service.facade.AcademicCalendarServiceFacade; 067import org.kuali.student.r2.core.atp.dto.AtpInfo; 068import org.kuali.student.r2.core.atp.service.AtpService; 069import org.kuali.student.r2.core.constants.AtpServiceConstants; 070import org.kuali.student.r2.core.scheduling.dto.ScheduleRequestSetInfo; 071 072import javax.xml.namespace.QName; 073import java.util.ArrayList; 074import java.util.Date; 075import java.util.HashMap; 076import java.util.HashSet; 077import java.util.List; 078import java.util.Map; 079import java.util.Random; 080import java.util.Set; 081 082/** 083 * View helper service impl for running AFUTs for state propagation. 084 * 085 * @author Kuali Student Team 086 */ 087public class TestStatePropagationViewHelperServiceImpl extends ViewHelperServiceImpl implements TestStatePropagationViewHelperService { 088 089 // List of objects used in test 090 private SocInfo socInfo; 091 private CourseOfferingInfo courseOfferingInfo; 092 private List<FormatOfferingInfo> foInfos; 093 private RegistrationGroupInfo rgInfo; 094 private List<RegistrationGroupInfo> rgInfos; 095 private List<ActivityOfferingInfo> aoInfos; // Only for a single RG in first FO 096 private String primaryAoId; 097 private String secondaryAoId; 098 private String secondAoState = LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY; 099 private TermInfo targetTerm; 100 private TermInfo subtermOne; 101 private TermInfo subtermTwo; 102 103 // Constants 104 public static final String SAMPLE_TERM = "200008"; 105 public static final String SAMPLE_ROLLOVER_TERM = "200108"; 106 public static final String COURSE_OFFERING_KEY = "courseOfferingKey"; 107 private ContextInfo CONTEXT; 108 109 // Soc states 110 public static final List<String> SOC_STATES_ORDERED; 111 static { 112 SOC_STATES_ORDERED = new ArrayList<String>(); 113 SOC_STATES_ORDERED.add(CourseOfferingSetServiceConstants.DRAFT_SOC_STATE_KEY); 114 SOC_STATES_ORDERED.add(CourseOfferingSetServiceConstants.OPEN_SOC_STATE_KEY); 115 SOC_STATES_ORDERED.add(CourseOfferingSetServiceConstants.LOCKED_SOC_STATE_KEY); 116 SOC_STATES_ORDERED.add(CourseOfferingSetServiceConstants.FINALEDITS_SOC_STATE_KEY); 117 SOC_STATES_ORDERED.add(CourseOfferingSetServiceConstants.PUBLISHING_SOC_STATE_KEY); 118 SOC_STATES_ORDERED.add(CourseOfferingSetServiceConstants.PUBLISHED_SOC_STATE_KEY); 119 } 120 121 public static final List<String> FO_STATES_ORDERED; 122 static { 123 FO_STATES_ORDERED = new ArrayList<String>(); 124 FO_STATES_ORDERED.add(LuiServiceConstants.LUI_FO_STATE_DRAFT_KEY); 125 FO_STATES_ORDERED.add(LuiServiceConstants.LUI_FO_STATE_PLANNED_KEY); 126 // can only get to this state if SOC state is publishing/published 127 FO_STATES_ORDERED.add(LuiServiceConstants.LUI_FO_STATE_OFFERED_KEY); 128 } 129 130 public static final List<String> CO_STATES_ORDERED; 131 static { 132 CO_STATES_ORDERED = new ArrayList<String>(); 133 CO_STATES_ORDERED.add(LuiServiceConstants.LUI_CO_STATE_DRAFT_KEY); 134 CO_STATES_ORDERED.add(LuiServiceConstants.LUI_CO_STATE_PLANNED_KEY); 135 // can only get to this state if SOC state is publishing/published 136 CO_STATES_ORDERED.add(LuiServiceConstants.LUI_CO_STATE_OFFERED_KEY); 137 } 138 139 /** 140 * What the FO state should be given two of the AO states are initially in draft and the "second" AO is in 141 * possibly a different state. 142 */ 143 public static final Map<String, String> SECOND_AO_STATE_TO_FO_STATE; 144 static { 145 SECOND_AO_STATE_TO_FO_STATE = new HashMap<String, String>(); 146 SECOND_AO_STATE_TO_FO_STATE.put(LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY, LuiServiceConstants.LUI_FO_STATE_DRAFT_KEY); 147 SECOND_AO_STATE_TO_FO_STATE.put(LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY, LuiServiceConstants.LUI_FO_STATE_PLANNED_KEY); 148 SECOND_AO_STATE_TO_FO_STATE.put(LuiServiceConstants.LUI_AO_STATE_OFFERED_KEY, LuiServiceConstants.LUI_FO_STATE_OFFERED_KEY); 149 } 150 151 /** 152 * What the CO state should be given two of the AO states are initially in draft and the "second" AO is in 153 * possibly a different state. 154 */ 155 public static final Map<String, String> SECOND_AO_STATE_TO_CO_STATE; 156 static { 157 SECOND_AO_STATE_TO_CO_STATE = new HashMap<String, String>(); 158 SECOND_AO_STATE_TO_CO_STATE.put(LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY, LuiServiceConstants.LUI_CO_STATE_DRAFT_KEY); 159 SECOND_AO_STATE_TO_CO_STATE.put(LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY, LuiServiceConstants.LUI_CO_STATE_PLANNED_KEY); 160 SECOND_AO_STATE_TO_CO_STATE.put(LuiServiceConstants.LUI_AO_STATE_OFFERED_KEY, LuiServiceConstants.LUI_CO_STATE_OFFERED_KEY); 161 } 162 /** 163 * Get a fresh copy from the DB 164 */ 165 private void _refetch() throws PermissionDeniedException, MissingParameterException, InvalidParameterException, OperationFailedException, DoesNotExistException { 166 courseOfferingInfo = CourseOfferingManagementUtil.getCourseOfferingService().getCourseOffering(courseOfferingInfo.getId(), CONTEXT); 167 for (int i = 0; i < foInfos.size(); i++) { 168 FormatOfferingInfo foInfo = foInfos.get(i); 169 foInfos.set(i, CourseOfferingManagementUtil.getCourseOfferingService().getFormatOffering(foInfo.getId(), CONTEXT)); 170 } 171 for (int i = 0; i < aoInfos.size(); i++) { 172 ActivityOfferingInfo aoInfo = aoInfos.get(i); 173 aoInfos.set(i, CourseOfferingManagementUtil.getCourseOfferingService().getActivityOffering(aoInfo.getId(), CONTEXT)); 174 } 175 } 176 177 public TestStatePropagationViewHelperServiceImpl() { 178 CONTEXT = ContextUtils.createDefaultContextInfo(); 179 CONTEXT.setPrincipalId("admin"); 180 CONTEXT.setCurrentDate(new Date()); 181 } 182 183 /** 184 * fromState The initial state to set 185 186 */ 187 private void _resetFoCoAndSecondaryAoState(String fromState, String secondaryState) throws Exception { 188 // First, reset the secondary AO state 189 LuiInfo aoLui = CourseOfferingManagementUtil.getLuiService().getLui(secondaryAoId, CONTEXT); 190 aoLui.setStateKey(secondaryState); 191 CourseOfferingManagementUtil.getLuiService().updateLui(aoLui.getId(), aoLui, CONTEXT); 192 // The AO state that has the biggest index is used to determine what the FO/CO state is. 193 int fromStateIndex = AoStateTransitionRefSolution.AO_STATES_ORDERED.indexOf(fromState); 194 int secondaryStateIndex = AoStateTransitionRefSolution.AO_STATES_ORDERED.indexOf(secondaryState); 195 String aoStateWinner = fromState; 196 if (secondaryStateIndex > fromStateIndex) { 197 aoStateWinner = secondaryState; 198 } 199 // Set the FO state 200 String foId = foInfos.get(0).getId(); // Grab first FO 201 LuiInfo foLui = CourseOfferingManagementUtil.getLuiService().getLui(foId, CONTEXT); 202 String foState = SECOND_AO_STATE_TO_FO_STATE.get(aoStateWinner); 203 foLui.setStateKey(foState); 204 LuiInfo updateFoLui = CourseOfferingManagementUtil.getLuiService().updateLui(foLui.getId(), foLui, CONTEXT); 205 206 // Set the CO state 207 String coId = courseOfferingInfo.getId(); // Grab first FO 208 LuiInfo coLui = CourseOfferingManagementUtil.getLuiService().getLui(coId, CONTEXT); 209 String coState = SECOND_AO_STATE_TO_CO_STATE.get(aoStateWinner); 210 coLui.setStateKey(coState); 211 LuiInfo updateCoLui = CourseOfferingManagementUtil.getLuiService().updateLui(coLui.getId(), coLui, CONTEXT); 212 } 213 214 private void _resetSocOnly() throws Exception { 215 socInfo = _getMainSocForTerm(SAMPLE_TERM); 216 if (socInfo != null) { 217 CourseOfferingManagementUtil.getSocService().deleteSoc(socInfo.getId(), CONTEXT); 218 } 219 socInfo = _createSocForTerm(SAMPLE_TERM); 220 } 221 222 private void _cleanSoc(String termCode) throws Exception { 223 SocInfo socInfoLocal = _getMainSocForTerm(termCode); 224 if (socInfoLocal != null) { 225 List<String> coIds = null; 226 try { 227 coIds = CourseOfferingManagementUtil.getSocService().getCourseOfferingIdsBySoc(socInfoLocal.getId(), CONTEXT); 228 if (coIds != null) { 229 if (coIds.size() > 2) { 230 throw new PseudoUnitTestException("Should only have at most 2 COs in this term"); 231 } else if (!coIds.isEmpty()) { // Has one CO 232 CourseOfferingManagementUtil.getCourseOfferingService().deleteCourseOfferingCascaded(coIds.get(0), CONTEXT); 233 if (coIds.size() > 1) { 234 CourseOfferingManagementUtil.getCourseOfferingService().deleteCourseOfferingCascaded(coIds.get(1), CONTEXT); 235 } 236 } 237 } 238 } catch (DoesNotExistException e) { 239 // Do nothing 240 } 241 List<String> itemIds = CourseOfferingManagementUtil.getSocService().getSocRolloverResultIdsBySourceSoc(socInfoLocal.getId(), CONTEXT); 242 // Fetch socRollover 243 for (String itemId: itemIds) { 244 SocRolloverResultInfo result = CourseOfferingManagementUtil.getSocService().getSocRolloverResult(itemId, CONTEXT); 245 List<SocRolloverResultItemInfo> items = 246 CourseOfferingManagementUtil.getSocService().getSocRolloverResultItemsByResultId(result.getId(), CONTEXT); 247 if (items != null) { 248 for (SocRolloverResultItemInfo item: items) { 249 CourseOfferingManagementUtil.getSocService().deleteSocRolloverResultItem(item.getId(), CONTEXT); 250 } 251 } 252 CourseOfferingManagementUtil.getSocService().deleteSocRolloverResult(result.getId(), CONTEXT); 253 } 254 CourseOfferingManagementUtil.getSocService().deleteSoc(socInfoLocal.getId(), CONTEXT); 255 } 256 } 257 258 private void _cleanSubterms(String parentTermCode) 259 throws MissingParameterException, InvalidParameterException, OperationFailedException, PermissionDeniedException, DoesNotExistException, ReadOnlyException, DataValidationErrorException, VersionMismatchException { 260 AtpService atpService = (AtpService) GlobalResourceLoader.getService(new QName(AtpServiceConstants.NAMESPACE, 261 AtpServiceConstants.SERVICE_NAME_LOCAL_PART)); 262 TermInfo term = getTermByTermCode(parentTermCode); 263 List<TermInfo> childTerms = CourseOfferingManagementUtil.getAcademicCalendarService().getIncludedTermsInTerm(term.getId(), CONTEXT); 264 for (TermInfo child: childTerms) { 265 // Force into draft state so it can be deleted 266 AtpInfo atpInfo = atpService.getAtp(child.getId(), CONTEXT); 267 atpInfo.setStateKey(AtpServiceConstants.ATP_DRAFT_STATE_KEY); 268 atpService.updateAtp(atpInfo.getId(), atpInfo, CONTEXT); 269 // Then delete 270 CourseOfferingManagementUtil.getAcademicCalendarService().deleteTerm(child.getId(), CONTEXT); 271 } 272 } 273 274 private void _reset(boolean createCourseOffering) throws Exception { 275 for (int i = 0; i <= 4; i++) { 276 _cleanSoc("200" + i + "08"); 277 } 278 // Fortunately, subterms are independent of SOCs 279 _cleanSubterms(SAMPLE_TERM); 280 _cleanSubterms(SAMPLE_ROLLOVER_TERM); 281 socInfo = _createSocForTerm(SAMPLE_TERM); 282 _createSocForTerm(SAMPLE_ROLLOVER_TERM); 283 if (createCourseOffering) { 284 Map<String, Object> keyToValues = 285 rolloverCourseOfferingFromSourceTermToTargetTerm("CHEM237", "201201", SAMPLE_TERM); 286 targetTerm = getTermByTermCode(SAMPLE_TERM); 287 courseOfferingInfo = (CourseOfferingInfo) keyToValues.get(COURSE_OFFERING_KEY); 288 // Get FOs (should only be 1) 289 foInfos = CourseOfferingManagementUtil.getCourseOfferingService().getFormatOfferingsByCourseOffering(courseOfferingInfo.getId(), CONTEXT); 290 // Save all RGs 291 rgInfos = CourseOfferingManagementUtil.getCourseOfferingService().getRegistrationGroupsByFormatOffering(foInfos.get(0).getId(), CONTEXT); 292 // Pick first RG 293 rgInfo = rgInfos.get(0); 294 // Get list of AOs but only for this RG 295 aoInfos = CourseOfferingManagementUtil.getCourseOfferingService().getActivityOfferingsByIds(rgInfo.getActivityOfferingIds(), CONTEXT); 296 // Set AO Scheduling state to scheduled since it is a constraint for AO state change (approved->offered) 297 aoInfos.get(0).setSchedulingStateKey(LuiServiceConstants.LUI_AO_SCHEDULING_STATE_SCHEDULED_KEY); 298 try { 299 CourseOfferingManagementUtil.getCourseOfferingService().updateActivityOffering(aoInfos.get(0).getId(), aoInfos.get(0), CONTEXT); 300 } catch (Exception e) { 301 throw new RuntimeException(e); 302 } 303 304 primaryAoId = aoInfos.get(0).getId(); 305 secondaryAoId = aoInfos.get(1).getId(); 306 } 307 } 308 309 private String _computeFoState(String primaryAoId, String desiredAoState) throws Exception { 310 // Use actual AOs to compute CO state 311 Set<String> aoStates = new HashSet<String>(); 312 List<ActivityOfferingInfo> aoInfos = CourseOfferingManagementUtil.getCourseOfferingService().getActivityOfferingsByFormatOffering(foInfos.get(0).getId(), CONTEXT); 313 boolean foundPrimaryAoId = false; 314 for (ActivityOfferingInfo ao: aoInfos) { 315 if (ao.getId().equals(primaryAoId)) { 316 aoStates.add(desiredAoState); 317 foundPrimaryAoId = true; 318 } else { 319 aoStates.add(ao.getStateKey()); 320 } 321 } 322 if (!foundPrimaryAoId) { 323 throw new PseudoUnitTestException("primary AO ID not found"); 324 } 325 String foStateComputed = LuiServiceConstants.LUI_FO_STATE_DRAFT_KEY; 326 if (aoStates.contains(LuiServiceConstants.LUI_AO_STATE_OFFERED_KEY)) { 327 foStateComputed = LuiServiceConstants.LUI_FO_STATE_OFFERED_KEY; 328 } else if (aoStates.contains(LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY)) { 329 foStateComputed = LuiServiceConstants.LUI_FO_STATE_PLANNED_KEY; 330 } 331 return foStateComputed; 332 } 333 334 private String _computeCoState(String primaryAoId, String desiredAoState) throws Exception { 335 // Use actual AOs to compute CO state 336 Set<String> aoStates = new HashSet<String>(); 337 List<ActivityOfferingInfo> aoInfos = CourseOfferingManagementUtil.getCourseOfferingService().getActivityOfferingsByCourseOffering(courseOfferingInfo.getId(), CONTEXT); 338 boolean foundPrimaryAoId = false; 339 for (ActivityOfferingInfo ao: aoInfos) { 340 if (ao.getId().equals(primaryAoId)) { 341 aoStates.add(desiredAoState); 342 foundPrimaryAoId = true; 343 } else { 344 aoStates.add(ao.getStateKey()); 345 } 346 } 347 if (!foundPrimaryAoId) { 348 throw new PseudoUnitTestException("primary AO ID not found"); 349 } 350 351 String coStateComputed = LuiServiceConstants.LUI_CO_STATE_DRAFT_KEY; 352 if (aoStates.contains(LuiServiceConstants.LUI_AO_STATE_OFFERED_KEY)) { 353 coStateComputed = LuiServiceConstants.LUI_CO_STATE_OFFERED_KEY; 354 } else if (aoStates.contains(LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY)) { 355 coStateComputed = LuiServiceConstants.LUI_CO_STATE_PLANNED_KEY; 356 } 357 return coStateComputed; 358 } 359 360 private void _testRollover() throws Exception { 361 _reset(true); 362 TermInfo halfFallOne = new TermInfo(); 363 halfFallOne.setStateKey(AtpServiceConstants.ATP_DRAFT_STATE_KEY); 364 halfFallOne.setTypeKey(AtpServiceConstants.ATP_HALF_FALL_1_TYPE_KEY); 365 halfFallOne.setStartDate(targetTerm.getStartDate()); 366 halfFallOne.setEndDate(targetTerm.getEndDate()); 367 RichTextInfo richTextInfo = new RichTextInfo(); 368 richTextInfo.setPlain("foo"); 369 richTextInfo.setFormatted("bar"); 370 halfFallOne.setDescr(richTextInfo); 371 subtermOne = CourseOfferingManagementUtil.getAcademicCalendarService().createTerm(halfFallOne.getTypeKey(), halfFallOne, CONTEXT); 372 // Attach subterm to term 373 CourseOfferingManagementUtil.getAcademicCalendarService().addTermToTerm(targetTerm.getId(), subtermOne.getId(), CONTEXT); 374 // Change primary AO to refer to this term 375 ActivityOfferingInfo aoInfo = CourseOfferingManagementUtil.getCourseOfferingService().getActivityOffering(primaryAoId, CONTEXT); 376 aoInfo.setTermId(subtermOne.getId()); 377 aoInfo.setTermCode(null); 378 CourseOfferingManagementUtil.getCourseOfferingService().updateActivityOffering(aoInfo.getId(), aoInfo, CONTEXT); 379 // Create SOC in another term to rollover 380 SocInfo socInfo2 = _createSocForTerm(SAMPLE_ROLLOVER_TERM); 381 TermInfo newTargetTerm = getTermByTermCode(SAMPLE_ROLLOVER_TERM); 382 // Create fall subterm in new target term 383 TermInfo halfFallTwo = new TermInfo(); 384 halfFallTwo.setStateKey(AtpServiceConstants.ATP_DRAFT_STATE_KEY); 385 halfFallTwo.setTypeKey(AtpServiceConstants.ATP_HALF_FALL_1_TYPE_KEY); 386 halfFallTwo.setStartDate(newTargetTerm.getStartDate()); 387 halfFallTwo.setEndDate(newTargetTerm.getEndDate()); 388 richTextInfo = new RichTextInfo(); 389 richTextInfo.setPlain("foo"); 390 richTextInfo.setFormatted("bar"); 391 halfFallTwo.setDescr(richTextInfo); 392 // 393 subtermTwo = CourseOfferingManagementUtil.getAcademicCalendarService().createTerm(halfFallTwo.getTypeKey(), halfFallTwo, CONTEXT); 394 // Attach subterm to term 395 CourseOfferingManagementUtil.getAcademicCalendarService().addTermToTerm(newTargetTerm.getId(), subtermTwo.getId(), CONTEXT); 396 AcademicCalendarServiceFacade acalServiceFacade 397 = (AcademicCalendarServiceFacade) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/acalServiceFacade", "AcademicCalendarServiceFacade")); 398 acalServiceFacade.makeTermOfficialCascaded(subtermTwo.getId(), CONTEXT); 399 // Rollover (should cause exception) 400 try { 401 Map<String, Object> keyToValues = 402 rolloverCourseOfferingFromSourceTermToTargetTerm("CHEM237", SAMPLE_TERM, SAMPLE_ROLLOVER_TERM); 403 } catch (Exception e) { 404 System.err.println(e.getMessage()); 405 } 406 407 List<String> coIds = CourseOfferingManagementUtil.getSocService().getCourseOfferingIdsBySoc(socInfo2.getId(), CONTEXT); 408 List<ActivityOfferingInfo> aoInfos = CourseOfferingManagementUtil.getCourseOfferingService().getActivityOfferingsByCourseOffering(coIds.get(0), CONTEXT); 409 System.err.println("Hi"); 410 } 411 412 private void _testColo(ContextInfo context) 413 throws PermissionDeniedException, MissingParameterException, InvalidParameterException, 414 OperationFailedException, DoesNotExistException, ReadOnlyException, DataValidationErrorException { 415 416 RolloverAssist rolloverAssist = 417 (RolloverAssist) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/rolloverAssist", "RolloverAssist")); 418 List<ScheduleRequestSetInfo> srsList1 = 419 CourseOfferingManagementUtil.getSchedulingService().getScheduleRequestSetsByRefObject(CourseOfferingServiceConstants.REF_OBJECT_URI_ACTIVITY_OFFERING, primaryAoId, context); 420 List<ScheduleRequestSetInfo> srsList2 = 421 CourseOfferingManagementUtil.getSchedulingService().getScheduleRequestSetsByRefObject(CourseOfferingServiceConstants.REF_OBJECT_URI_ACTIVITY_OFFERING, secondaryAoId, context); 422 ScheduleRequestSetInfo srs1 = srsList1.get(0); 423 ScheduleRequestSetInfo srs2 = srsList2.get(0); 424 CourseOfferingManagementUtil.getSchedulingService().deleteScheduleRequestSet(srs2.getId(), context); 425 srs1.getRefObjectIds().add(secondaryAoId); 426 ScheduleRequestSetInfo srs1Fetched = null; 427 try { 428 srs1Fetched = CourseOfferingManagementUtil.getSchedulingService().updateScheduleRequestSet(srs1.getId(), srs1, context); 429 } catch (VersionMismatchException e) { 430 throw new OperationFailedException(e.getMessage()); 431 } 432 try { 433 rolloverCourseOfferingFromSourceTermToTargetTerm("CHEM237", SAMPLE_TERM, SAMPLE_TERM); 434 } catch (Exception e) { 435 System.out.println("Woops"); 436 } 437 System.out.println("Hi"); 438 } 439 440 private void _testEventProcessor() throws Exception { 441 _reset(true); 442 KSEventProcessorImpl ksEventProcessor 443 = (KSEventProcessorImpl) GlobalResourceLoader.getService(new QName("http://student.kuali.org/wsdl/ksEventProcessor", "KSEventProcessor")); 444 // Get all the AOs for the initial RG 445 List<ActivityOfferingInfo> rgAos = CourseOfferingManagementUtil.getCourseOfferingService().getActivityOfferingsByIds(rgInfo.getActivityOfferingIds(), CONTEXT); 446 ActivityOfferingInfo sampleAO = null; 447 for (ActivityOfferingInfo ao: rgAos) { 448 // Find the one that's a lecture 449 if (ao.getTypeKey().equals(LuiServiceConstants.LECTURE_ACTIVITY_OFFERING_TYPE_KEY)) { 450 sampleAO = ao; 451 break; 452 } 453 } 454 // Find another RG that has the same AO as sampleAO and store it in secondRG 455 RegistrationGroupInfo secondRG = null; 456 for (int i = 1; i < rgInfos.size(); i++) { 457 // Skip the zeroth one 458 RegistrationGroupInfo rg = rgInfos.get(i); 459 rgAos = CourseOfferingManagementUtil.getCourseOfferingService().getActivityOfferingsByIds(rgInfo.getActivityOfferingIds(), CONTEXT); 460 for (ActivityOfferingInfo ao: rgAos) { 461 // Find the one that's a lecture 462 if (ao.getId().equals(sampleAO.getId())) { 463 secondRG = rg; 464 break; 465 } 466 } 467 if (secondRG != null) { 468 break; 469 } 470 } 471 ksEventProcessor.getCoService().scheduleActivityOffering(sampleAO.getId(), CONTEXT); 472 sampleAO = ksEventProcessor.getCoService().getActivityOffering(sampleAO.getId(), CONTEXT); 473 KSEvent changeAOState = KSEventFactory.createChangeActivityOfferingStateEvent(sampleAO.getId(), LuiServiceConstants.LUI_AO_STATE_CANCELED_KEY); 474 ksEventProcessor.fireEvent(changeAOState, CONTEXT); 475 } 476 477 private void _runTimings() throws Exception { 478 _reset(true); 479 List<LuiLuiRelationInfo> infos = null; 480 481 // Stopwatch watch = new Stopwatch(); 482 // watch.reset(); 483 // int iterations = 2000; 484 // for (int i = 0; i < iterations; i++) { 485 // infos = CourseOfferingManagementUtil.getLuiService().getLuiLuiRelationsByLui(rgInfo.getId(), CONTEXT); 486 // } 487 // String overall = watch.computeAndAccumulate(); 488 // LOGGER.info("Total time: " + overall); 489 // 490 // Stopwatch watch2 = new Stopwatch(); 491 // watch2.reset(); 492 // for (int i = 0; i < iterations; i++) { 493 // List<String> aoIds = CourseOfferingManagementUtil.getLuiService().getLuiIdsByLuiAndRelationType(rgInfo.getId(), 494 // LuiServiceConstants.LUI_LUI_RELATION_REGISTERED_FOR_VIA_RG_TO_AO_TYPE_KEY, CONTEXT); 495 // List<String> foIds = CourseOfferingManagementUtil.getLuiService().getLuiIdsByRelatedLuiAndRelationType(rgInfo.getId(), 496 // LuiServiceConstants.LUI_LUI_RELATION_DELIVERED_VIA_FO_TO_RG_TYPE_KEY, CONTEXT); 497 // } 498 // overall = watch2.computeAndAccumulate(); 499 // LOGGER.info("Total time 2: " + overall); 500 } 501 502 503 @Override 504 public void runTests(TestStatePropagationForm form) throws Exception { 505 // Now begin to test AO state transitions 506 System.err.println("<<<<<<<<<<<<<< Starting tests >>>>>>>>>>>>"); 507 _reset(true); 508 _testAoStateTransition(form); 509 System.err.println("<<<<<<<<<<<<<< Ending tests >>>>>>>>>>>>"); 510 System.err.println("<<<<<<<<<<<<<< Starting RG tests >>>>>>>>>>>>"); 511 _reset(true); 512 System.err.println("------------------------- Testing draft"); 513 RegGroupStateResult rgStateResult = testRegistrationGroupStatePropagation(LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY); 514 _printRegGroupResults(rgStateResult, form); 515 System.err.println("------------------------- Testing approved"); 516 rgStateResult = testRegistrationGroupStatePropagation(LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY); 517 _printRegGroupResults(rgStateResult, form); 518 System.err.println("<<<<<<<<<<<<<< Ending RG tests >>>>>>>>>>>>"); 519 520 System.err.println("<<<<<<<<<<<<<< Starting RG Invalid tests >>>>>>>>>>>>"); 521 _reset(true); 522 PseudoUnitTestStateTransitionGrid grid = testRegistrationGroupInvalid(true); 523 _printRegGroupInvalid(grid, true, form); 524 grid = testRegistrationGroupInvalid(false); 525 _printRegGroupInvalid(grid, false, form); 526 System.err.println("<<<<<<<<<<<<<< END RG Invalid tests >>>>>>>>>>>>"); 527 } 528 529 private void _printRegGroupInvalid(PseudoUnitTestStateTransitionGrid grid, boolean isRgOffered, TestStatePropagationForm form) { 530 for (int i = 0; i < grid.size(); i++) { 531 for (int j = 0; j < grid.size(); j++) { 532 String expected = grid.getTransition(AFUTTypeEnum.EXPECTED, i, j); 533 if (!expected.equals(TransitionGridYesNoEnum.INVALID.getName())) { 534 String actual = grid.getTransition(AFUTTypeEnum.ACTUAL, i, j); 535 String offered = "[RG offered] "; 536 if (!isRgOffered) { 537 offered = "[RG pending] "; 538 } 539 String message = offered + " expected/actual = " + _getAfterDot(expected) 540 + "/" + _getAfterDot(actual); 541 System.err.println(message); 542 RGStateWrapper rgStateWrapper = new RGStateWrapper(grid.getStateKeyAt(i), grid.getStateKeyAt(j), _getAfterDot(expected) ,_getAfterDot(actual)); 543 if(rgStateWrapper.getStatus().equals("pass")){ 544 form.setPassCount(form.getPassCount()+1); 545 } else if(rgStateWrapper.getStatus().equals("fail")){ 546 form.setFailCount(form.getFailCount()+1); 547 } 548 form.addRGFromTransitionStatePropagationWrapper(rgStateWrapper); 549 } 550 } 551 } 552 } 553 554 private void _setAosInRgToAoState(String aoState) throws Exception { 555 for (ActivityOfferingInfo aoInfo: aoInfos) { 556 _forceChangeLuiState(aoInfo.getId(), aoState); 557 } 558 } 559 public static final List<String> RG_STATES; 560 static { 561 RG_STATES = new ArrayList<String>(); 562 RG_STATES.add(LuiServiceConstants.REGISTRATION_GROUP_PENDING_STATE_KEY); 563 RG_STATES.add(LuiServiceConstants.REGISTRATION_GROUP_OFFERED_STATE_KEY); 564 RG_STATES.add(LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY); 565 } 566 567 // Only testing three transitions 568 private PseudoUnitTestStateTransitionGrid _createRgStateGrid(boolean aosAllOffered) { 569 PseudoUnitTestStateTransitionGrid rgStateGrid = 570 new PseudoUnitTestStateTransitionGrid(RG_STATES, TransitionGridYesNoEnum.ALLOWED_VALUES, "rg"); 571 if (aosAllOffered) { 572 rgStateGrid.setTransition(AFUTTypeEnum.EXPECTED, 573 LuiServiceConstants.REGISTRATION_GROUP_OFFERED_STATE_KEY, 574 LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, 575 TransitionGridYesNoEnum.YES.getName()); 576 rgStateGrid.setTransition(AFUTTypeEnum.EXPECTED, 577 LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, 578 LuiServiceConstants.REGISTRATION_GROUP_OFFERED_STATE_KEY, 579 TransitionGridYesNoEnum.YES.getName()); 580 rgStateGrid.setTransition(AFUTTypeEnum.EXPECTED, 581 LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, 582 LuiServiceConstants.REGISTRATION_GROUP_PENDING_STATE_KEY, 583 TransitionGridYesNoEnum.NO.getName()); 584 } else { 585 rgStateGrid.setTransition(AFUTTypeEnum.EXPECTED, 586 LuiServiceConstants.REGISTRATION_GROUP_PENDING_STATE_KEY, 587 LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, 588 TransitionGridYesNoEnum.YES.getName()); 589 rgStateGrid.setTransition(AFUTTypeEnum.EXPECTED, 590 LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, 591 LuiServiceConstants.REGISTRATION_GROUP_OFFERED_STATE_KEY, 592 TransitionGridYesNoEnum.NO.getName()); 593 rgStateGrid.setTransition(AFUTTypeEnum.EXPECTED, 594 LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, 595 LuiServiceConstants.REGISTRATION_GROUP_PENDING_STATE_KEY, 596 TransitionGridYesNoEnum.YES.getName()); 597 } 598 return rgStateGrid; 599 } 600 601 // Just test in SOC state of publishing 602 public PseudoUnitTestStateTransitionGrid testRegistrationGroupInvalid(boolean aosAllOffered) throws Exception { 603 String initRgState = LuiServiceConstants.REGISTRATION_GROUP_OFFERED_STATE_KEY; 604 String otherRgState = LuiServiceConstants.REGISTRATION_GROUP_PENDING_STATE_KEY; 605 if (aosAllOffered) { 606 _setAosInRgToAoState(LuiServiceConstants.LUI_AO_STATE_OFFERED_KEY); 607 _forceChangeLuiState(rgInfo.getId(), LuiServiceConstants.REGISTRATION_GROUP_OFFERED_STATE_KEY); 608 } else { 609 initRgState = LuiServiceConstants.REGISTRATION_GROUP_PENDING_STATE_KEY; 610 otherRgState = LuiServiceConstants.REGISTRATION_GROUP_OFFERED_STATE_KEY; 611 _setAosInRgToAoState(LuiServiceConstants.LUI_AO_STATE_DRAFT_KEY); 612 _forceChangeLuiState(rgInfo.getId(), LuiServiceConstants.REGISTRATION_GROUP_PENDING_STATE_KEY); 613 } 614 615 StatusInfo status = CourseOfferingManagementUtil.getCourseOfferingService().changeRegistrationGroupState(rgInfo.getId(), LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, CONTEXT); 616 PseudoUnitTestStateTransitionGrid rgStateGrid = _createRgStateGrid(aosAllOffered); 617 String result = TransitionGridYesNoEnum.YES.getName(); 618 if (!status.getIsSuccess()) { 619 result = TransitionGridYesNoEnum.NO.getName(); 620 } 621 rgStateGrid.setTransition(AFUTTypeEnum.ACTUAL, 622 initRgState, LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, result); 623 // RG should be in invalid state now 624 rgInfo = CourseOfferingManagementUtil.getCourseOfferingService().getRegistrationGroup(rgInfo.getId(), CONTEXT); 625 if (!rgInfo.getStateKey().equals(LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY)) { 626 throw new PseudoUnitTestException("RG should be in invalid state"); 627 } 628 // Attempt to change it to state it shouldn't go to 629 status = CourseOfferingManagementUtil.getCourseOfferingService().changeRegistrationGroupState(rgInfo.getId(), otherRgState, CONTEXT); 630 result = TransitionGridYesNoEnum.YES.getName(); 631 if (!status.getIsSuccess()) { 632 result = TransitionGridYesNoEnum.NO.getName(); 633 } 634 rgStateGrid.setTransition(AFUTTypeEnum.ACTUAL, 635 LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, otherRgState, result); 636 // Change back to invalid for now 637 _forceChangeLuiState(rgInfo.getId(), LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY); 638 // Attempt to change it to state it SHOULD go to 639 status = CourseOfferingManagementUtil.getCourseOfferingService().changeRegistrationGroupState(rgInfo.getId(), initRgState, CONTEXT); 640 result = TransitionGridYesNoEnum.YES.getName(); 641 if (!status.getIsSuccess()) { 642 result = TransitionGridYesNoEnum.NO.getName(); 643 } 644 rgStateGrid.setTransition(AFUTTypeEnum.ACTUAL, 645 LuiServiceConstants.REGISTRATION_GROUP_INVALID_STATE_KEY, initRgState, result); 646 return rgStateGrid; 647 } 648 649 private void _testAoStateTransition(TestStatePropagationForm form) throws Exception { 650 String aoId = aoInfos.get(0).getId(); 651 for (String secondaryAoState: AoStateTransitionRefSolution.AO_STATES_ORDERED) { 652 secondAoState = secondaryAoState; // Save to instance variable 653 654 for (int i = 0; i < SOC_STATES_ORDERED.size(); i++) { 655 String socState = SOC_STATES_ORDERED.get(i); 656 if (secondAoState.equals(LuiServiceConstants.LUI_AO_STATE_OFFERED_KEY)) { 657 if (! (socState.equals(CourseOfferingSetServiceConstants.PUBLISHED_SOC_STATE_KEY) || 658 socState.equals(CourseOfferingSetServiceConstants.PUBLISHING_SOC_STATE_KEY))) { 659 // Can only have AO offered in SOC published/publishing, so skip if need be 660 continue; 661 } 662 } 663 System.err.println("======================= SOC state = " + socState + " (Second AO state: " + secondAoState + ")"); 664 Map<String, PseudoUnitTestStateTransitionGrid> gridTypeToGrid = 665 testAoStateTransitionsInSocState(aoId, socInfo.getId(), socState, secondaryAoState); 666 _compareGrids(gridTypeToGrid, socState, secondaryAoState, form); 667 _resetSocOnly(); // Make sure to reset the SOC 668 } 669 } 670 } 671 672 private String _computeAoStateString(int index, int size) { 673 // "O" stands for offered state and "X" stands for not offered 674 String binString = Integer.toString(index, 2); 675 binString = binString.replaceAll("1", "O"); 676 binString = binString.replaceAll("0", "X"); 677 while (binString.length() < size) { 678 binString = "X" + binString; 679 } 680 return binString; 681 } 682 683 private String _getAfterDot(String s) { 684 int index = s.lastIndexOf('.'); 685 if (index == -1) { 686 return s; 687 } 688 s = s.substring(index + 1); 689 return s; 690 } 691 692 private void _printRegGroupResults(RegGroupStateResult rgStateResult, TestStatePropagationForm form) { 693 for (int i = 0; i < rgStateResult.size(); i++) { 694 String aoStatesString = _computeAoStateString(i, rgStateResult.numAos()); 695 String expected = _getAfterDot(rgStateResult.getExpected(i)); 696 String actual = _getAfterDot(rgStateResult.getActual(i)); 697 System.err.println(aoStatesString + " expected/actual = " + expected + "/" + actual); 698 RGStateWrapper rgStateWrapper = new RGStateWrapper(aoStatesString, expected, actual); 699 if(rgStateWrapper.getStatus().equals("pass")){ 700 form.setPassCount(form.getPassCount()+1); 701 } else if(rgStateWrapper.getStatus().equals("fail")){ 702 form.setFailCount(form.getFailCount()+1); 703 } 704 form.addRGFromAOStatePropagationWrapper(rgStateWrapper); 705 706 } 707 } 708 709 private int _intPower(int base, int exponent) { 710 return (int) Math.pow(base, exponent); 711 } 712 713 public RegGroupStateResult testRegistrationGroupStatePropagation(String otherAoState) throws Exception { 714 RegGroupStateResult result = new RegGroupStateResult(rgInfo.getActivityOfferingIds().size()); 715 _resetSocOnly(); 716 _advanceSocState(socInfo.getId(), CourseOfferingSetServiceConstants.PUBLISHED_SOC_STATE_KEY); 717 List<Integer> ints = new ArrayList<Integer>(); 718 int numPermutations = result.size(); 719 for (int i = 0; i < numPermutations; i++) { 720 ints.add(i); 721 } 722 Random rn = new Random(); 723 // Randomly select values from 0 to power - 1 to test RG states 724 for (int i = 0; i < numPermutations; i++) { 725 int index = rn.nextInt(ints.size()); 726 int val = ints.get(index); // Pick a random int from the list of ints 727 String resultRgState = testRegGroupPermutation(val, otherAoState); 728 result.setActual(val, resultRgState); 729 ints.remove(index); // Remove it so it doesn't get picked again 730 731 _reset(true); 732 _resetSocOnly(); 733 _advanceSocState(socInfo.getId(), CourseOfferingSetServiceConstants.PUBLISHED_SOC_STATE_KEY); 734 } 735 736 return result; 737 } 738 739 private String testRegGroupPermutation(int index, String otherAoState) throws PermissionDeniedException, MissingParameterException, InvalidParameterException, OperationFailedException, DoesNotExistException { 740 List<String> aoIds = rgInfo.getActivityOfferingIds(); 741 int pow = _intPower(2, aoIds.size()); 742 if (index >= pow) { 743 throw new IndexOutOfBoundsException(index + " too big for: " + pow); 744 } 745 746 String aoStateString = _computeAoStateString(index, aoIds.size()); 747 for (int i = 0; i < aoStateString.length(); i++) { 748 char ch = aoStateString.charAt(i); 749 if (ch == 'X') { 750 CourseOfferingManagementUtil.getCourseOfferingService().changeActivityOfferingState(aoIds.get(i), otherAoState, CONTEXT); 751 } else { 752 CourseOfferingManagementUtil.getCourseOfferingService().changeActivityOfferingState(aoIds.get(i), LuiServiceConstants.LUI_AO_STATE_OFFERED_KEY, CONTEXT); 753 } 754 } 755 LuiInfo lui = CourseOfferingManagementUtil.getLuiService().getLui(rgInfo.getId(), CONTEXT); 756 return lui.getStateKey(); 757 } 758 759 private String _computeDisplayString(String aoFromState, String aoToState, int size) { 760 StringBuilder transition = new StringBuilder("[AO "); 761 transition.append(aoFromState).append(" => AO ").append(aoToState).append("]"); 762 while (transition.length() < size) { 763 transition.append(" "); 764 } 765 return transition.toString(); 766 } 767 768 private String _computeExpectedActual(String expected, String actual, int size) { 769 StringBuilder result = new StringBuilder(expected); 770 result.append("/").append(actual); 771 while (result.length() < size) { 772 result.append(" "); 773 } 774 return result.toString(); 775 } 776 777 private void _compareGrids(Map<String, PseudoUnitTestStateTransitionGrid> gridTypeToGrid, 778 String socState, String secondAoState, TestStatePropagationForm form) { 779 List<Map<String, String>> aoResults = gridTypeToGrid.get("ao").compare(); 780 System.err.println("---------------------- AO state results (SOC: " + socState + ")"); 781 for (int i = 0; i < aoResults.size(); i++) { 782 // Put socState in front 783 Map<String, String> resultMap = aoResults.get(i); 784 String aoFromState = resultMap.get(PseudoUnitTestStateTransitionGrid.AO_STATE_FROM); 785 int indexOfLastDot = aoFromState.lastIndexOf("."); 786 aoFromState = aoFromState.substring(indexOfLastDot + 1); 787 String aoToState = resultMap.get(PseudoUnitTestStateTransitionGrid.AO_STATE_TO); 788 indexOfLastDot = aoToState.lastIndexOf("."); 789 aoToState = aoToState.substring(indexOfLastDot + 1); 790 String expectedVal = resultMap.get(PseudoUnitTestStateTransitionGrid.EXPECTED); 791 String actualVal = resultMap.get(PseudoUnitTestStateTransitionGrid.ACTUAL); 792 String passFail = resultMap.get(PseudoUnitTestStateTransitionGrid.PASS_FAIL); 793 String color = passFail.equals(PseudoUnitTestStateTransitionGrid.PASS_VAL) ? "((( GREEN )))" : 794 (passFail.equals(PseudoUnitTestStateTransitionGrid.FAIL_VAL) ? 795 "*** red ***" : "... White ..."); 796 String transition = _computeDisplayString(aoFromState, aoToState, 30); 797 String message = "(AO) " + transition + 798 " expected/actual = " + _computeExpectedActual(expectedVal, actualVal, 15) + " " + color; 799 System.err.println(message); 800 StatePropagationWrapper statePropagationWrapper = new StatePropagationWrapper(socState, aoFromState, aoToState, secondAoState, expectedVal, actualVal, passFail); 801 if(statePropagationWrapper.getStatus().equals("pass")){ 802 form.setPassCount(form.getPassCount()+1); 803 } else if(statePropagationWrapper.getStatus().equals("fail")){ 804 form.setFailCount(form.getFailCount()+1); 805 } 806 form.addAoStatePropagationWrapper(statePropagationWrapper); 807 808 } 809 System.err.println("---------------------- FO state results (SOC: " + socState + ")"); 810 List<Map<String, String>> foResults = gridTypeToGrid.get("fo").compare(); 811 for (int i = 0; i < foResults.size(); i++) { 812 // Put socState in front 813 Map<String, String> resultMap = foResults.get(i); 814 String aoFromState = resultMap.get(PseudoUnitTestStateTransitionGrid.AO_STATE_FROM); 815 int indexOfLastDot = aoFromState.lastIndexOf("."); 816 aoFromState = aoFromState.substring(indexOfLastDot + 1); 817 818 String aoToState = resultMap.get(PseudoUnitTestStateTransitionGrid.AO_STATE_TO); 819 indexOfLastDot = aoToState.lastIndexOf("."); 820 aoToState = aoToState.substring(indexOfLastDot + 1); 821 822 String expectedVal = resultMap.get(PseudoUnitTestStateTransitionGrid.EXPECTED); 823 indexOfLastDot = expectedVal.lastIndexOf("."); 824 expectedVal = expectedVal.substring(indexOfLastDot + 1); 825 826 String actualVal = resultMap.get(PseudoUnitTestStateTransitionGrid.ACTUAL); 827 indexOfLastDot = actualVal.lastIndexOf("."); 828 actualVal = actualVal.substring(indexOfLastDot + 1); 829 String passFail = resultMap.get(PseudoUnitTestStateTransitionGrid.PASS_FAIL); 830 String color = passFail.equals(PseudoUnitTestStateTransitionGrid.PASS_VAL) ? "((( GREEN )))" : 831 (passFail.equals(PseudoUnitTestStateTransitionGrid.FAIL_VAL) ? 832 "*** red ***" : "... White ..."); 833 String transition = _computeDisplayString(aoFromState, aoToState, 30); 834 String message = "(FO) " + transition + 835 " expected/actual = " + _computeExpectedActual(expectedVal, actualVal, 15) + " " + color; 836 StatePropagationWrapper statePropagationWrapper = new StatePropagationWrapper(socState, aoFromState, aoToState, secondAoState, expectedVal, actualVal, passFail); 837 if(statePropagationWrapper.getStatus().equals("pass")){ 838 form.setPassCount(form.getPassCount()+1); 839 } else if(statePropagationWrapper.getStatus().equals("fail")){ 840 form.setFailCount(form.getFailCount()+1); 841 } 842 form.addFoStatePropagationWrapper(statePropagationWrapper); 843 System.err.println(message); 844 } 845 System.err.println("---------------------- CO state results (SOC: " + socState + ")"); 846 List<Map<String, String>> coResults = gridTypeToGrid.get("co").compare(); 847 for (int i = 0; i < foResults.size(); i++) { 848 // Put socState in front 849 Map<String, String> resultMap = coResults.get(i); 850 String aoFromState = resultMap.get(PseudoUnitTestStateTransitionGrid.AO_STATE_FROM); 851 int indexOfLastDot = aoFromState.lastIndexOf("."); 852 aoFromState = aoFromState.substring(indexOfLastDot + 1); 853 854 String aoToState = resultMap.get(PseudoUnitTestStateTransitionGrid.AO_STATE_TO); 855 indexOfLastDot = aoToState.lastIndexOf("."); 856 aoToState = aoToState.substring(indexOfLastDot + 1); 857 858 String expectedVal = resultMap.get(PseudoUnitTestStateTransitionGrid.EXPECTED); 859 indexOfLastDot = expectedVal.lastIndexOf("."); 860 expectedVal = expectedVal.substring(indexOfLastDot + 1); 861 String actualVal = resultMap.get(PseudoUnitTestStateTransitionGrid.ACTUAL); 862 indexOfLastDot = actualVal.lastIndexOf("."); 863 actualVal = actualVal.substring(indexOfLastDot + 1); 864 String passFail = resultMap.get(PseudoUnitTestStateTransitionGrid.PASS_FAIL); 865 String color = passFail.equals(PseudoUnitTestStateTransitionGrid.PASS_VAL) ? "((( GREEN )))" : 866 (passFail.equals(PseudoUnitTestStateTransitionGrid.FAIL_VAL) ? 867 "*** red ***" : "... White ..."); 868 String transition = _computeDisplayString(aoFromState, aoToState, 30); 869 String message = "(CO) " + transition + 870 " expected/actual = " + _computeExpectedActual(expectedVal, actualVal, 15) + " " + color; 871 System.err.println(message); 872 StatePropagationWrapper statePropagationWrapper = new StatePropagationWrapper(socState, aoFromState, aoToState, secondAoState, expectedVal, actualVal, passFail); 873 if(statePropagationWrapper.getStatus().equals("pass")){ 874 form.setPassCount(form.getPassCount()+1); 875 } else if(statePropagationWrapper.getStatus().equals("fail")){ 876 form.setFailCount(form.getFailCount()+1); 877 } 878 form.addCoStatePropagationWrapper(statePropagationWrapper); 879 } 880 System.err.println("---------------------- end"); 881 } 882 883 public void testSocStateHappy() throws Exception { 884 assertEquals(socInfo.getStateKey(), CourseOfferingSetServiceConstants.DRAFT_SOC_STATE_KEY, "SocHappy 1"); 885 // Draft to Open 886 _changeSocState(socInfo.getId(), CourseOfferingSetServiceConstants.OPEN_SOC_STATE_KEY, "SocHappy 2"); 887 // Open to Locked 888 _changeSocState(socInfo.getId(), CourseOfferingSetServiceConstants.LOCKED_SOC_STATE_KEY, "SocHappy 3"); 889 // Locked to Final Edits 890 _changeSocState(socInfo.getId(), CourseOfferingSetServiceConstants.FINALEDITS_SOC_STATE_KEY, "SocHappy 4"); 891 // Final Edits to Publishing 892 _changeSocState(socInfo.getId(), CourseOfferingSetServiceConstants.PUBLISHING_SOC_STATE_KEY, "SocHappy 5"); 893 // Publishing to Published 894 _changeSocState(socInfo.getId(), CourseOfferingSetServiceConstants.PUBLISHED_SOC_STATE_KEY, "SocHappy 6"); 895 } 896 897 public void testSocStateUnhappy(String socState, int index) throws Exception { 898 _advanceSocState(socInfo.getId(), socState); // Move us to the desired SOC state 899 int i = SOC_STATES_ORDERED.indexOf(socState); 900 for (int j = 0; j < SOC_STATES_ORDERED.size(); j++) { 901 if (j == i || j == i + 1) { 902 // Skip over transitioning to yourself or to the next state 903 continue; 904 } 905 _changeSocStateInvalid(socInfo.getId(), SOC_STATES_ORDERED.get(j), socState, "Unhappy Soc " + index + "-" + j); 906 } 907 } 908 909 910 public Map<String, PseudoUnitTestStateTransitionGrid> 911 testAoStateTransitionsInSocState(String aoId, String socId, String socState, String secondaryAoState) throws Exception { 912 SocInfo fetched = CourseOfferingManagementUtil.getSocService().getSoc(socId, CONTEXT); 913 if (!fetched.getStateKey().equals(CourseOfferingSetServiceConstants.DRAFT_SOC_STATE_KEY)) { 914 throw new PseudoUnitTestException("Initial soc state not in DRAFT state"); 915 } 916 if (!socState.equals(CourseOfferingSetServiceConstants.DRAFT_SOC_STATE_KEY)) { 917 _advanceSocState(socId, socState); 918 } 919 List<String> allowedAoValues = new ArrayList<String>(); 920 allowedAoValues.add(TransitionGridYesNoEnum.YES.getName()); 921 allowedAoValues.add(TransitionGridYesNoEnum.NO.getName()); 922 allowedAoValues.add(TransitionGridYesNoEnum.YES.getName()); 923 PseudoUnitTestStateTransitionGrid foGrid = 924 new PseudoUnitTestStateTransitionGrid(AoStateTransitionRefSolution.AO_STATES_ORDERED, FO_STATES_ORDERED, "fo"); 925 PseudoUnitTestStateTransitionGrid coGrid = 926 new PseudoUnitTestStateTransitionGrid(AoStateTransitionRefSolution.AO_STATES_ORDERED, CO_STATES_ORDERED, "co"); 927 foGrid.setSocStateKey(socState); 928 coGrid.setSocStateKey(socState); 929 PseudoUnitTestStateTransitionGrid aoGrid = AoStateTransitionRefSolution.getReferenceGridForState(socState); 930 for (int i = 0; i < aoGrid.size(); i++) { 931 String fromState = aoGrid.getStateKeyAt(i); 932 for (int j = 0; j < aoGrid.size(); j++) { 933 String toState = aoGrid.getStateKeyAt(j); 934 boolean invalidTransition = aoGrid.getTransition(AFUTTypeEnum.EXPECTED, fromState, toState).equals(TransitionGridYesNoEnum.INVALID.getName()); 935 if (invalidTransition) { 936 aoGrid.setTransition(AFUTTypeEnum.ACTUAL, fromState, toState, TransitionGridYesNoEnum.INVALID.getName()); 937 continue; 938 } 939 940 // Force the original AO to be in fromState 941 _forceChangeLuiState(aoId, fromState); 942 // Adjust FO/CO states 943 _resetFoCoAndSecondaryAoState(fromState, secondaryAoState); 944 _refetch(); // Need to get latest CO/FO/AOs 945 946 // Attempt to change toState using normal services call 947 boolean change = _tryChangingAoState(aoId, toState); 948 aoGrid.setTransition(AFUTTypeEnum.ACTUAL, fromState, toState, 949 change ? TransitionGridYesNoEnum.YES.getName() : TransitionGridYesNoEnum.NO.getName()); 950 // Now to test FO/CO states 951 _refetch(); 952 String localCoState = courseOfferingInfo.getStateKey(); 953 String localFoState = foInfos.get(0).getStateKey(); 954 // In order to test CO/FO state propagation, we need to pretend valid AO state transitions occurred. 955 String desiredAoState = fromState; // Initialize to fromState 956 if (aoGrid.getTransition(AFUTTypeEnum.EXPECTED, fromState, toState).equals(TransitionGridYesNoEnum.YES.getName())) { 957 desiredAoState = toState; // Transition valid so this is the desired AO state 958 } 959 if (fromState.equals(LuiServiceConstants.LUI_AO_STATE_APPROVED_KEY) && 960 toState.equals(LuiServiceConstants.LUI_AO_STATE_OFFERED_KEY) && 961 socState.equals(CourseOfferingSetServiceConstants.PUBLISHED_SOC_STATE_KEY)) { 962 System.err.print(""); 963 } 964 String foStateComputed = _computeFoState(primaryAoId, desiredAoState); 965 String coStateComputed = _computeCoState(primaryAoId, desiredAoState); 966 foGrid.setTransition(AFUTTypeEnum.EXPECTED, fromState, toState, foStateComputed); 967 foGrid.setTransition(AFUTTypeEnum.ACTUAL, fromState, toState, localFoState); 968 coGrid.setTransition(AFUTTypeEnum.EXPECTED, fromState, toState, coStateComputed); 969 coGrid.setTransition(AFUTTypeEnum.ACTUAL, fromState, toState, localCoState); 970 } 971 } 972 Map<String, PseudoUnitTestStateTransitionGrid> gridTypeToGrid = new HashMap<String, PseudoUnitTestStateTransitionGrid>(); 973 gridTypeToGrid.put("ao", aoGrid); 974 gridTypeToGrid.put("fo", foGrid); 975 gridTypeToGrid.put("co", coGrid); 976 return gridTypeToGrid; 977 } 978 979 private void _advanceSocState(String socId, String socState) throws Exception { 980 if (socState.equals(CourseOfferingSetServiceConstants.DRAFT_SOC_STATE_KEY)) { 981 return; 982 } 983 int index = 1; 984 String nextSocState = SOC_STATES_ORDERED.get(index); 985 while (!nextSocState.equals(socState)) { 986 _changeSocState(socId, nextSocState, "Unhappy Soc " + index); 987 index++; 988 if (index == 6) { 989 System.out.println(); 990 } 991 nextSocState = SOC_STATES_ORDERED.get(index); 992 } 993 if (!nextSocState.equals(SOC_STATES_ORDERED.get(0))) { 994 _changeSocState(socId, socState, "Unhappy Soc " + index); 995 } 996 } 997 998 private void _changeSocState(String socId, String nextState, String message) throws Exception { 999 CourseOfferingManagementUtil.getSocService().changeSocState(socId, nextState, ContextUtils.createDefaultContextInfo()); 1000 SocInfo fetched = _getMainSocForTerm(SAMPLE_TERM); 1001 assertEquals(fetched.getStateKey(), nextState, message); 1002 } 1003 1004 private void _changeSocStateInvalid(String socId, String nextState, String origState, String message) throws Exception { 1005 boolean exceptionThrown = false; 1006 try { 1007 CourseOfferingManagementUtil.getSocService().changeSocState(socId, nextState, ContextUtils.createDefaultContextInfo()); 1008 } catch (OperationFailedException e) { 1009 exceptionThrown = true; 1010 } 1011 assertTrue(exceptionThrown, "Exception not thrown for invalid Soc state change"); 1012 SocInfo fetched = _getMainSocForTerm(SAMPLE_TERM); 1013 assertEquals(fetched.getStateKey(), origState, message); 1014 } 1015 1016 private boolean _forceChangeLuiState(String aoId, String nextState) throws PseudoUnitTestException { 1017 // DanEp suggested this sneaky way to circumvent state changes 1018 try { 1019 LuiInfo lui = CourseOfferingManagementUtil.getLuiService().getLui(aoId, CONTEXT); 1020 lui.setStateKey(nextState); 1021 CourseOfferingManagementUtil.getLuiService().updateLui(lui.getId(), lui, CONTEXT); 1022 return true; 1023 } catch (Exception e) { 1024 throw new PseudoUnitTestException("Unexpected exception in _forceChangeAoState: " + e.getMessage()); 1025 } 1026 } 1027 1028 private boolean _tryChangingAoState(String aoId, String nextState) throws PseudoUnitTestException { 1029 try { 1030 if (nextState.equals(LuiServiceConstants.LUI_AO_STATE_SUSPENDED_KEY)) { 1031 System.out.println("Hi"); 1032 } 1033 if (CourseOfferingManagementUtil.getCourseOfferingService().changeActivityOfferingState(aoId, nextState, CONTEXT).getIsSuccess()) { 1034 return true; 1035 } else { 1036 return false; 1037 } 1038 1039 } catch (OperationFailedException e) { 1040 return false; 1041 } catch (Exception e) { 1042 throw new PseudoUnitTestException("Unexpected exception: " + e.getMessage()); 1043 } 1044 } 1045 1046 private void assertTrue(boolean actual, String message) throws AssertException { 1047 if (!actual) { 1048 throw new AssertException("assertTrue failed", message); 1049 } 1050 } 1051 1052 private void assertEquals(String expected, String actual, String testType) throws AssertException { 1053 if (!expected.equals(actual)) { 1054 throw new AssertException(expected + " != " + actual, testType); 1055 } 1056 } 1057 1058 private SocInfo _createSocForTerm(String termCode) throws Exception { 1059 SocInfo soc = null; 1060 if (_getMainSocForTerm(termCode) != null) { 1061 return null; // Already exists, so return null 1062 } else { 1063 TermInfo mainTerm = getTermByTermCode(termCode); 1064 SocInfo socInfo = new SocInfo(); 1065 socInfo.setTypeKey(CourseOfferingSetServiceConstants.MAIN_SOC_TYPE_KEY); 1066 socInfo.setStateKey(CourseOfferingSetServiceConstants.DRAFT_SOC_STATE_KEY); 1067 socInfo.setTermId(mainTerm.getId()); 1068 socInfo.setSchedulingStateKey(CourseOfferingSetServiceConstants.SOC_SCHEDULING_STATE_NOT_STARTED); 1069 soc = CourseOfferingManagementUtil.getSocService().createSoc(mainTerm.getId(), socInfo.getTypeKey(), socInfo, new ContextInfo()); 1070 } 1071 return soc; 1072 } 1073 1074 private SocInfo _getMainSocForTerm(String termCode) throws Exception { 1075 TermInfo mainTerm = getTermByTermCode(termCode); 1076 ContextInfo contextInfo = new ContextInfo(); 1077 1078 SocInfo socInfo = CourseOfferingSetUtil.getMainSocForTermId(mainTerm.getId(), contextInfo); 1079 if (socInfo != null) { 1080 return socInfo; 1081 } 1082 return null; 1083 } 1084 1085 public TermInfo getTermByTermCode(String termCode) throws InvalidParameterException, MissingParameterException, PermissionDeniedException, OperationFailedException { 1086 // TODO: Find sensible way to rewrap exception that acal service may throw 1087 // Find the term (alas, I think it does approximate search) 1088 QueryByCriteria.Builder qbcBuilder = QueryByCriteria.Builder.create(); 1089 qbcBuilder.setPredicates(PredicateFactory.equal(CourseOfferingConstants.ATP_CODE, termCode)); 1090 QueryByCriteria criteria = qbcBuilder.build(); 1091 1092 // Do search. In ideal case, terms returns one element, which is the desired term. 1093 List<TermInfo> terms = null; 1094 terms = CourseOfferingManagementUtil.getAcademicCalendarService().searchForTerms(criteria, new ContextInfo()); 1095 TermInfo mainTerm = null; 1096 if (terms == null || terms.isEmpty()) { 1097 throw new InvalidParameterException("Unable to find term for: " + termCode); 1098 } else { 1099 mainTerm = terms.get(0); 1100 } 1101 return mainTerm; 1102 } 1103 1104 @Override 1105 public Map<String, Object> rolloverCourseOfferingFromSourceTermToTargetTerm(String courseOfferingCode, String sourceTermCode, String targetTermCode) throws Exception { 1106 TermInfo sourceTerm = getTermByTermCode(sourceTermCode); 1107 TermInfo targetTerm = getTermByTermCode(targetTermCode); 1108 List<CourseOfferingInfo> coInfos = _searchCourseOfferingByCOCodeAndTerm(courseOfferingCode, sourceTerm.getId()); 1109 if (coInfos == null || coInfos.isEmpty()) { 1110 return null; 1111 } 1112 ContextInfo contextInfo = ContextUtils.createDefaultContextInfo(); 1113 CourseOfferingInfo coInfo = coInfos.get(0); // Just get the first one 1114 Date start = new Date(); 1115 List<String> optionKeys = CourseOfferingManagementUtil.getDefaultOptionKeysService().getDefaultOptionKeysForCopySingleCourseOffering(); 1116 SocRolloverResultItemInfo rolloverResultInfo = 1117 CourseOfferingManagementUtil.getCourseOfferingService().rolloverCourseOffering(coInfo.getId(), targetTerm.getId(), optionKeys, contextInfo); 1118 Date end = new Date(); 1119 String targetId = rolloverResultInfo.getTargetCourseOfferingId(); 1120 CourseOfferingInfo targetCo = CourseOfferingManagementUtil.getCourseOfferingService().getCourseOffering(targetId, contextInfo); 1121 1122 Map<String, Object> keyToValues = new HashMap<String, Object>(); 1123 keyToValues.put(COURSE_OFFERING_KEY, targetCo); 1124 return keyToValues; 1125 } 1126 1127 private List<CourseOfferingInfo> _searchCourseOfferingByCOCodeAndTerm(String courseOfferingCode, String termId) throws Exception { 1128 QueryByCriteria.Builder qbcBuilder = QueryByCriteria.Builder.create(); 1129 qbcBuilder.setPredicates( 1130 PredicateFactory.and( 1131 PredicateFactory.equal(CourseOfferingConstants.COURSEOFFERING_COURSE_OFFERING_CODE, courseOfferingCode), 1132 PredicateFactory.equal(CourseOfferingConstants.ATP_ID, termId) 1133 )); 1134 QueryByCriteria criteria = qbcBuilder.build(); 1135 List<CourseOfferingInfo> coList = CourseOfferingManagementUtil.getCourseOfferingService().searchForCourseOfferings(criteria, new ContextInfo()); 1136 return coList; 1137 } 1138}