public CourseOfferingInfo testCRUDCourseOffering()
      throws DoesNotExistException, DataValidationErrorException, InvalidParameterException,
          MissingParameterException, OperationFailedException, PermissionDeniedException,
          ReadOnlyException, VersionMismatchException {
    // get course
    CourseInfo course;
    course = courseService.getCourse("COURSE1", ContextUtils.getContextInfo());
    // create co from course
    List<String> optionKeys = new ArrayList<String>();
    CourseOfferingInfo orig = new CourseOfferingInfo();
    orig.setCourseId(course.getId());
    orig.setTermId("testAtpId1");
    orig.setTypeKey(LuiServiceConstants.COURSE_OFFERING_TYPE_KEY);
    orig.setStateKey(LuiServiceConstants.LUI_CO_STATE_DRAFT_KEY);
    orig.setCourseOfferingTitle("my name");
    orig.setWaitlistLevelTypeKey("waitlist key");
    orig.setHasWaitlist(true);
    orig.setFinalExamType(FinalExam.STANDARD.toString());
    orig.setIsEvaluated(true);
    orig.setIsFeeAtActivityOffering(false);
    orig.setFundingSource("funding source");
    orig.setCourseOfferingCode("CODE");
    orig.setCourseNumberSuffix("");
    orig.setCourseOfferingTitle("Title");
    orig.getStudentRegistrationGradingOptions()
        .add(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_AUDIT);
    orig.getStudentRegistrationGradingOptions()
        .add(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_PASSFAIL);
    orig.setGradingOptionId(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_LETTER);

    CourseOfferingInfo info =
        courseOfferingService.createCourseOffering(
            orig.getCourseId(), orig.getTermId(), orig.getTypeKey(), orig, optionKeys, callContext);
    assertNotNull(info);
    assertNotNull(info.getId());
    assertEquals(orig.getCourseId(), info.getCourseId());
    assertEquals(orig.getTermId(), info.getTermId());
    assertEquals(orig.getStateKey(), info.getStateKey());
    assertEquals(orig.getTypeKey(), info.getTypeKey());
    assertEquals(orig.getWaitlistLevelTypeKey(), info.getWaitlistLevelTypeKey());
    assertEquals(orig.getHasWaitlist(), info.getHasWaitlist());
    assertEquals(orig.getFinalExamType(), info.getFinalExamType());
    assertEquals(orig.getIsFeeAtActivityOffering(), info.getIsFeeAtActivityOffering());
    assertEquals(orig.getFundingSource(), info.getFundingSource());
    assertEquals(course.getCode() + info.getCourseNumberSuffix(), info.getCourseOfferingCode());
    assertEquals(orig.getCourseNumberSuffix(), info.getCourseNumberSuffix());
    assertEquals(course.getSubjectArea(), info.getSubjectArea());
    if (course.getDescr() != null) {
      assertEquals(course.getDescr().getPlain(), info.getDescr().getPlain());
      assertEquals(course.getDescr().getFormatted(), info.getDescr().getFormatted());
    }
    //        assertEquals(2,info.getStudentRegistrationOptionIds().size());
    //
    // assertTrue(info.getStudentRegistrationOptionIds().contains(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_AUDIT));
    //
    // assertTrue(info.getStudentRegistrationOptionIds().contains(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_PASSFAIL));
    //
    //        assertEquals(2,info.getGradingOptionIds().size());
    //
    // assertTrue(info.getGradingOptionIds().contains(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_LETTER));
    //
    // assertTrue(info.getGradingOptionIds().contains(LrcServiceConstants.RESULT_GROUP_KEY_GRADE_PERCENTAGE));

    // TODO: test for these things
    //        assertEquals(course.getUnitsContentOwnerOrgIds(), info.getUnitsContentOwnerOrgIds());
    //        assertEquals(course.getUnitsDeploymentOrgIds(), info.getUnitsDeploymentOrgIds());
    //        assertEquals(course.getGradingOptions(), info.getGradingOptionIds());
    //        assertEquals(course.getCreditOptionIds(), info.getCreditOptionIds());

    // refetch co
    orig = info;
    info = courseOfferingService.getCourseOffering(orig.getId(), callContext);
    assertNotNull(info);
    assertEquals(orig.getId(), info.getId());
    assertEquals(orig.getCourseId(), info.getCourseId());
    assertEquals(orig.getTermId(), info.getTermId());
    assertEquals(orig.getStateKey(), info.getStateKey());
    assertEquals(orig.getTypeKey(), info.getTypeKey());

    // update co
    orig = info;
    orig.setIsHonorsOffering(true);
    orig.setMaximumEnrollment(40);
    orig.setMinimumEnrollment(10);
    List<OfferingInstructorInfo> instructors = new ArrayList<OfferingInstructorInfo>();
    //        OfferingInstructorInfo instructor = new OfferingInstructorInfo();
    //        instructor.setPersonId("Pers-1");
    //        instructor.setPercentageEffort(Float.valueOf("60"));
    //        instructor.setTypeKey(LprServiceConstants.INSTRUCTOR_MAIN_TYPE_KEY);
    //        instructor.setStateKey(LprServiceConstants.ASSIGNED_STATE_KEY);
    // TODO: add this back in and test for it
    //        instructors.add(instructor);
    orig.setInstructors(instructors);
    info = courseOfferingService.updateCourseOffering(orig.getId(), orig, callContext);
    assertNotNull(info);
    assertEquals(orig.getId(), info.getId());
    assertEquals(orig.getCourseId(), info.getCourseId());
    assertEquals(orig.getTermId(), info.getTermId());
    assertEquals(orig.getStateKey(), info.getStateKey());
    assertEquals(orig.getTypeKey(), info.getTypeKey());
    assertEquals(orig.getIsHonorsOffering(), info.getIsHonorsOffering());
    assertEquals(orig.getMaximumEnrollment(), info.getMaximumEnrollment());
    assertEquals(orig.getMinimumEnrollment(), info.getMinimumEnrollment());
    assertEquals(orig.getInstructors().size(), info.getInstructors().size());
    //        OfferingInstructorInfo origInst1 = orig.getInstructors().get(0);
    //        OfferingInstructorInfo infoInst1 = info.getInstructors().get(0);
    //        assertEquals(origInst1.getPersonId(), infoInst1.getPersonId());
    //        assertEquals(origInst1.getPercentageEffort(), infoInst1.getPercentageEffort());
    //        assertEquals(origInst1.getTypeKey(), infoInst1.getTypeKey());
    //        assertEquals(origInst1.getStateKey(), infoInst1.getStateKey());
    return info;
  }
  protected static void continueFromCreateCopyCourseOfferingInfo(
      CourseOfferingCreateWrapper coWrapper, CourseInfo course, TermInfo term) {

    ContextInfo contextInfo = ContextUtils.createDefaultContextInfo();
    int firstValue = 0;

    try {
      List<CourseOfferingInfo> courseOfferingInfos =
          CourseOfferingManagementUtil.getCourseOfferingService()
              .getCourseOfferingsByCourseAndTerm(course.getId(), term.getId(), contextInfo);

      coWrapper.setCourse(course);
      coWrapper.setCreditCount(
          CourseOfferingViewHelperUtil.trimTrailing0(
              CourseOfferingManagementUtil.getLrcService()
                  .getResultValue(
                      course
                          .getCreditOptions()
                          .get(firstValue)
                          .getResultValueKeys()
                          .get(firstValue),
                      contextInfo)
                  .getValue()));
      coWrapper.setShowAllSections(true);
      coWrapper.setShowCopyCourseOffering(false);
      coWrapper.setShowTermOfferingLink(true);

      coWrapper.setContextBar(
          CourseOfferingContextBar.NEW_INSTANCE(
              coWrapper.getTerm(),
              coWrapper.getSocInfo(),
              CourseOfferingManagementUtil.getStateService(),
              CourseOfferingManagementUtil.getAcademicCalendarService(),
              contextInfo));

      coWrapper.getExistingTermOfferings().clear();
      coWrapper.getExistingOfferingsInCurrentTerm().clear();

      for (CourseOfferingInfo courseOfferingInfo : courseOfferingInfos) {
        if (StringUtils.equals(
            courseOfferingInfo.getStateKey(), LuiServiceConstants.LUI_CO_STATE_OFFERED_KEY)) {
          CourseOfferingEditWrapper co = new CourseOfferingEditWrapper(courseOfferingInfo);
          co.setGradingOption(
              CourseOfferingManagementUtil.getGradingOption(
                  courseOfferingInfo.getGradingOptionId()));
          coWrapper.getExistingOfferingsInCurrentTerm().add(co);
        }
      }

      // Get past 5 years CO
      Calendar termStart = Calendar.getInstance();
      termStart.setTime(term.getStartDate());
      String termYear = Integer.toString(termStart.get(Calendar.YEAR));
      String termMonth = Integer.toString((termStart.get(Calendar.MONTH) + 1));
      String termDayOfMonth = Integer.toString((termStart.getActualMaximum(Calendar.DAY_OF_MONTH)));

      org.kuali.student.r2.core.search.dto.SearchRequestInfo searchRequest =
          new org.kuali.student.r2.core.search.dto.SearchRequestInfo(
              CourseOfferingHistorySearchImpl.PAST_CO_SEARCH.getKey());
      searchRequest.addParam(
          CourseOfferingHistorySearchImpl.COURSE_ID, coWrapper.getCourse().getId());

      searchRequest.addParam(
          CourseOfferingHistorySearchImpl.TARGET_DAY_OF_MONTH_PARAM, termDayOfMonth);
      searchRequest.addParam(CourseOfferingHistorySearchImpl.TARGET_MONTH_PARAM, termMonth);
      searchRequest.addParam(CourseOfferingHistorySearchImpl.TARGET_YEAR_PARAM, termYear);
      searchRequest.addParam(
          CourseOfferingHistorySearchImpl.SearchParameters.CROSS_LIST_SEARCH_ENABLED,
          BooleanUtils.toStringTrueFalse(true));
      org.kuali.student.r2.core.search.dto.SearchResultInfo searchResult =
          CourseOfferingManagementUtil.getSearchService().search(searchRequest, null);

      List<String> courseOfferingIds = new ArrayList<String>(searchResult.getTotalResults());

      /* Checks whether the course is cross-listed and Set the codes that are cross listed to the cross-listed list */

      for (org.kuali.student.r2.core.search.dto.SearchResultRowInfo row : searchResult.getRows()) {
        for (SearchResultCellInfo cellInfo : row.getCells()) {
          String value = StringUtils.EMPTY;
          if (cellInfo.getValue() != null) {
            value = cellInfo.getValue();
          }
          if (CourseOfferingHistorySearchImpl.SearchResultColumns.CO_ID.equals(cellInfo.getKey())) {
            courseOfferingIds.add(value);
          } else if (CourseOfferingHistorySearchImpl.SearchResultColumns.IS_CROSS_LISTED.equals(
              cellInfo.getValue())) {
            coWrapper.setCrossListedCo(BooleanUtils.toBoolean(value));
          } else if (CourseOfferingHistorySearchImpl.SearchResultColumns.CROSS_LISTED_COURSES
              .equals(cellInfo.getKey())) {
            coWrapper.setAlternateCOCodes(Arrays.asList(StringUtils.split(value, ",")));
          }
        }
      }

      /*
       * Avoid duplicates in case there is a cross Listed
       */
      HashSet hs = new HashSet();
      hs.addAll(courseOfferingIds);
      courseOfferingIds.clear();
      courseOfferingIds.addAll(hs);

      courseOfferingInfos =
          CourseOfferingManagementUtil.getCourseOfferingService()
              .getCourseOfferingsByIds(courseOfferingIds, contextInfo);

      for (CourseOfferingInfo courseOfferingInfo : courseOfferingInfos) {
        CourseOfferingEditWrapper co = new CourseOfferingEditWrapper(courseOfferingInfo);
        TermInfo termInfo =
            CourseOfferingManagementUtil.getAcademicCalendarService()
                .getTerm(courseOfferingInfo.getTermId(), contextInfo);
        co.setTerm(termInfo);
        co.setGradingOption(
            CourseOfferingManagementUtil.getGradingOption(courseOfferingInfo.getGradingOptionId()));
        co.setAlternateCOCodes(coWrapper.getAlternateCOCodes());
        coWrapper.getExistingTermOfferings().add(co);
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }