Example #1
0
  @Test
  public void testBlame() throws IOException {
    File source = new File(baseDir, "src/foo.xoo");
    FileUtils.write(source, "sample content");
    File scm = new File(baseDir, "src/foo.xoo.scm");
    FileUtils.write(scm, "123,julien,2014-12-12\n234,julien,2014-12-24");
    DefaultInputFile inputFile = new DefaultInputFile("foo", "src/foo.xoo").setLanguage(Xoo.KEY);
    fs.add(inputFile);

    BlameOutput result = mock(BlameOutput.class);
    when(input.filesToBlame()).thenReturn(Arrays.<InputFile>asList(inputFile));
    new XooBlameCommand().blame(input, result);
    verify(result)
        .blameResult(
            inputFile,
            Arrays.asList(
                new BlameLine()
                    .revision("123")
                    .author("julien")
                    .date(DateUtils.parseDate("2014-12-12")),
                new BlameLine()
                    .revision("234")
                    .author("julien")
                    .date(DateUtils.parseDate("2014-12-24"))));
  }
Example #2
0
 public Settings setProperty(String key, @Nullable Date date, boolean includeTime) {
   if (date == null) {
     return removeProperty(key);
   }
   return setProperty(
       key, includeTime ? DateUtils.formatDateTime(date) : DateUtils.formatDate(date));
 }
Example #3
0
  @Test
  public void get_last_snapshot_by_component_uuid() {
    setupData("get_last_snapshot_by_component_uuid");

    SnapshotDto snapshotDto = dao.getLastSnapshotByResourceUuid("ABCD", session);
    assertThat(snapshotDto.getId()).isEqualTo(1);

    assertThat(snapshotDto.getPeriodMode(1)).isEqualTo("previous_analysis");
    assertThat(snapshotDto.getPeriodModeParameter(1)).isNull();
    assertThat(snapshotDto.getPeriodDate(1)).isNull();

    assertThat(snapshotDto.getPeriodMode(2)).isEqualTo("days");
    assertThat(snapshotDto.getPeriodModeParameter(2)).isEqualTo("30");
    assertThat(snapshotDto.getPeriodDate(2)).isEqualTo(DateUtils.parseDate("2011-09-24").getTime());

    assertThat(snapshotDto.getPeriodMode(3)).isEqualTo("days");
    assertThat(snapshotDto.getPeriodModeParameter(3)).isEqualTo("90");
    assertThat(snapshotDto.getPeriodDate(3)).isEqualTo(DateUtils.parseDate("2011-07-26").getTime());

    assertThat(snapshotDto.getPeriodMode(4)).isEqualTo("previous_analysis");
    assertThat(snapshotDto.getPeriodModeParameter(4)).isNull();
    assertThat(snapshotDto.getPeriodDate(4)).isNull();

    assertThat(snapshotDto.getPeriodMode(5)).isEqualTo("previous_version");
    assertThat(snapshotDto.getPeriodModeParameter(5)).isNull();
    assertThat(snapshotDto.getPeriodDate(5)).isNull();

    snapshotDto = dao.getLastSnapshotByResourceUuid("EFGH", session);
    assertThat(snapshotDto.getId()).isEqualTo(2L);

    snapshotDto = dao.getLastSnapshotByResourceUuid("GHIJ", session);
    assertThat(snapshotDto.getId()).isEqualTo(3L);

    assertThat(dao.getLastSnapshotByResourceUuid("UNKNOWN", session)).isNull();
  }
Example #4
0
  private void writeChangelog(Issue issue, JsonWriter json) {
    json.name("changelog")
        .beginArray()
        .beginObject()
        .prop("creationDate", DateUtils.formatDateTime(issue.creationDate()))
        .prop("fCreationDate", formatDate(issue.creationDate()))
        .name("diffs")
        .beginArray()
        .value(i18n.message(UserSession.get().locale(), "created", null))
        .endArray()
        .endObject();

    IssueChangelog changelog = issueChangelogService.changelog(issue);
    for (FieldDiffs diffs : changelog.changes()) {
      String userLogin = diffs.userLogin();
      json.beginObject()
          .prop("userName", userLogin != null ? changelog.user(diffs).name() : null)
          .prop("creationDate", DateUtils.formatDateTime(diffs.creationDate()))
          .prop("fCreationDate", formatDate(diffs.creationDate()));
      json.name("diffs").beginArray();
      List<String> diffsFormatted = issueChangelogService.formatDiffs(diffs);
      for (String diff : diffsFormatted) {
        json.value(diff);
      }
      json.endArray();
      json.endObject();
    }
    json.endArray();
  }
  @Test
  public void should_keep_changes_made_by_user() throws Exception {
    DefaultIssue issue =
        new DefaultIssue()
            .setKey("ABCDE")
            .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
            .setComponentKey("struts:org.apache.struts.Action")
            .setNew(false);

    // Before starting scan
    issue.setAssignee(null);
    issue.setActionPlanKey("PLAN-1");
    issue.setCreationDate(DateUtils.parseDate("2012-01-01"));
    issue.setUpdateDate(DateUtils.parseDate("2012-02-02"));

    // Changed by scan
    issue.setLine(200);
    issue.setSeverity(Severity.BLOCKER);
    issue.setManualSeverity(false);
    issue.setAuthorLogin("simon");
    issue.setChecksum("CHECKSUM-ABCDE");
    issue.setResolution(null);
    issue.setStatus(Issue.STATUS_REOPENED);

    // Issue as seen and changed by end-user
    IssueDto dbIssue =
        new IssueDto()
            .setKee("ABCDE")
            .setRuleId(10)
            .setRuleKey("squid", "AvoidCycles")
            .setComponentUuid("100")
            .setComponentKey("struts:org.apache.struts.Action")
            .setLine(10)
            .setResolution(Issue.RESOLUTION_FALSE_POSITIVE)
            .setStatus(Issue.STATUS_RESOLVED)
            .setAssignee("arthur")
            .setActionPlanKey("PLAN-2")
            .setSeverity(Severity.MAJOR)
            .setManualSeverity(false);

    new UpdateConflictResolver().mergeFields(dbIssue, issue);

    assertThat(issue.key()).isEqualTo("ABCDE");
    assertThat(issue.componentKey()).isEqualTo("struts:org.apache.struts.Action");

    // Scan wins on :
    assertThat(issue.line()).isEqualTo(200);
    assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
    assertThat(issue.manualSeverity()).isFalse();

    // User wins on :
    assertThat(issue.assignee()).isEqualTo("arthur");
    assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FALSE_POSITIVE);
    assertThat(issue.status()).isEqualTo(Issue.STATUS_RESOLVED);
    assertThat(issue.actionPlanKey()).isEqualTo("PLAN-2");
  }
 protected void appendFooter(StringBuilder message, Notification notification) {
   String projectKey = notification.getFieldValue(FIELD_PROJECT_KEY);
   String dateString = notification.getFieldValue(FIELD_PROJECT_DATE);
   if (projectKey != null && dateString != null) {
     Date date = DateUtils.parseDateTime(dateString);
     String url =
         String.format(
             "%s/component_issues?id=%s#createdAt=%s",
             settings.getServerBaseURL(),
             encode(projectKey),
             encode(DateUtils.formatDateTime(date)));
     message.append("See it in SonarQube: ").append(url).append(NEW_LINE);
   }
 }
Example #7
0
 public Date getDateTime(String key) {
   String value = getString(key);
   if (StringUtils.isNotEmpty(value)) {
     return DateUtils.parseDateTime(value);
   }
   return null;
 }
Example #8
0
 @Before
 public void createDao() {
   session = getMyBatis().openSession(false);
   system2 = mock(System2.class);
   when(system2.now()).thenReturn(DateUtils.parseDate("2014-09-03").getTime());
   dao = new ResourceDao(getMyBatis(), system2);
 }
  @Test
  public void should_send_notification_if_issue_change() throws Exception {
    when(project.getAnalysisDate()).thenReturn(DateUtils.parseDate("2013-05-18"));
    RuleKey ruleKey = RuleKey.of("squid", "AvoidCycles");
    Rule rule = new Rule("squid", "AvoidCycles");
    DefaultIssue issue =
        new DefaultIssue()
            .setNew(false)
            .setChanged(true)
            .setFieldChange(mock(IssueChangeContext.class), "severity", "MINOR", "BLOCKER")
            .setRuleKey(ruleKey);
    when(issueCache.all()).thenReturn(Arrays.asList(issue));
    when(ruleFinder.findByKey(ruleKey)).thenReturn(rule);

    SendIssueNotificationsPostJob job =
        new SendIssueNotificationsPostJob(issueCache, notifications, ruleFinder);
    job.executeOn(project, sensorContext);

    verify(notifications)
        .sendChanges(
            eq(issue),
            any(IssueChangeContext.class),
            eq(rule),
            any(Component.class),
            (Component) isNull());
  }
Example #10
0
  @Test
  public void search_json_example() {
    ComponentDto jdk7 = insertJdk7();
    ComponentDto cLang = insertClang();
    dbClient
        .componentLinkDao()
        .insert(
            dbSession,
            new ComponentLinkDto()
                .setComponentUuid(jdk7.uuid())
                .setHref("http://www.oracle.com")
                .setType(ComponentLinkDto.TYPE_HOME_PAGE)
                .setName("Home"));
    dbClient
        .componentLinkDao()
        .insert(
            dbSession,
            new ComponentLinkDto()
                .setComponentUuid(jdk7.uuid())
                .setHref("http://download.java.net/openjdk/jdk8/")
                .setType(ComponentLinkDto.TYPE_SOURCES)
                .setName("Sources"));
    long oneTime = DateUtils.parseDateTime("2016-06-10T13:17:53+0000").getTime();
    long anotherTime = DateUtils.parseDateTime("2016-06-11T14:25:53+0000").getTime();
    SnapshotDto jdk7Snapshot =
        dbClient.snapshotDao().insert(dbSession, newAnalysis(jdk7).setCreatedAt(oneTime));
    SnapshotDto cLangSnapshot =
        dbClient.snapshotDao().insert(dbSession, newAnalysis(cLang).setCreatedAt(anotherTime));
    dbClient
        .measureDao()
        .insert(
            dbSession,
            newMeasureDto(alertStatusMetric, jdk7, jdk7Snapshot).setData(Level.ERROR.name()));
    dbClient
        .measureDao()
        .insert(
            dbSession,
            newMeasureDto(alertStatusMetric, cLang, cLangSnapshot).setData(Level.OK.name()));
    insertUserPermission(UserRole.ADMIN, user.getId(), jdk7.getId());
    insertUserPermission(UserRole.ADMIN, user.getId(), cLang.getId());
    db.commit();
    System.setProperty("user.timezone", "UTC");

    String result = ws.newRequest().execute().getInput();

    assertJson(result).isSimilarTo(getClass().getResource("search_my_projects-example.json"));
  }
 public void add(String language, String name) {
   qualityProfiles.add(
       QualityProfile.newBuilder()
           .setLanguage(language)
           .setKey(name)
           .setName(name)
           .setRulesUpdatedAt(DateUtils.formatDateTime(new Date(1234567891212L)))
           .build());
 }
 @Test
 public void toDate() throws Exception {
   assertThat(RubyUtils.toDate(null)).isNull();
   assertThat(RubyUtils.toDate("")).isNull();
   assertThat(RubyUtils.toDate("   ")).isNull();
   assertThat(RubyUtils.toDate("2013-01-18").getDate()).isEqualTo(18);
   assertThat(RubyUtils.toDate("2013-01-18T15:38:19+0200").getDate()).isEqualTo(18);
   assertThat(RubyUtils.toDate("2013-01-18T15:38:19+0200").getMinutes()).isEqualTo(38);
   assertThat(RubyUtils.toDate(DateUtils.parseDate("2013-01-18")).getDate()).isEqualTo(18);
 }
Example #13
0
 @Before
 public void before() {
   System2 system2 = mock(System2.class);
   when(system2.now()).thenReturn(DateUtils.parseDate("2011-09-29").getTime());
   underTest =
       new SwitchSnapshotStep(
           new DbClient(db.database(), db.myBatis(), new SnapshotDao()),
           treeRootHolder,
           dbIdsRepository);
 }
  @Test
  public void should_not_send_notif_if_no_new_issues() throws Exception {
    when(project.getAnalysisDate()).thenReturn(DateUtils.parseDate("2013-05-18"));
    when(issueCache.all()).thenReturn(Arrays.asList(new DefaultIssue().setNew(false)));

    SendIssueNotificationsPostJob job =
        new SendIssueNotificationsPostJob(issueCache, notifications, ruleFinder);
    job.executeOn(project, sensorContext);

    verifyZeroInteractions(notifications);
  }
 private void delete(List<PurgeableSnapshotDto> snapshots, DbSession session) {
   for (PurgeableSnapshotDto snapshot : snapshots) {
     LOG.debug(
         "<- Delete snapshot: {} [{}]",
         DateUtils.formatDateTime(snapshot.getDate()),
         snapshot.getSnapshotId());
     purgeDao.deleteSnapshots(
         PurgeSnapshotQuery.create().setRootSnapshotId(snapshot.getSnapshotId()), session);
     purgeDao.deleteSnapshots(
         PurgeSnapshotQuery.create().setId(snapshot.getSnapshotId()), session);
   }
 }
Example #16
0
  private void writeIssue(IssueQueryResult result, DefaultIssue issue, JsonWriter json) {
    Component component = result.component(issue);
    Component project = result.project(issue);
    String actionPlanKey = issue.actionPlanKey();
    WorkDayDuration technicalDebt = issue.technicalDebt();
    Date updateDate = issue.updateDate();
    Date closeDate = issue.closeDate();

    json.prop("key", issue.key())
        .prop("component", issue.componentKey())
        .prop("componentLongName", component != null ? component.longName() : null)
        .prop("componentQualifier", component != null ? component.qualifier() : null)
        .prop("project", issue.projectKey())
        .prop("projectLongName", project != null ? project.longName() : null)
        .prop("rule", issue.ruleKey().toString())
        .prop("ruleName", result.rule(issue).getName())
        .prop("line", issue.line())
        .prop("message", issue.message())
        .prop("resolution", issue.resolution())
        .prop("status", issue.status())
        .prop("severity", issue.severity())
        .prop("author", issue.authorLogin())
        .prop("actionPlan", actionPlanKey)
        .prop(
            "debt",
            technicalDebt != null
                ? technicalDebtFormatter.format(UserSession.get().locale(), technicalDebt)
                : null)
        .prop("actionPlanName", actionPlanKey != null ? result.actionPlan(issue).name() : null)
        .prop("creationDate", DateUtils.formatDateTime(issue.creationDate()))
        .prop("fCreationDate", formatDate(issue.creationDate()))
        .prop("updateDate", updateDate != null ? DateUtils.formatDateTime(updateDate) : null)
        .prop("fUpdateDate", formatDate(updateDate))
        .prop("fUpdateAge", formatAgeDate(updateDate))
        .prop("closeDate", closeDate != null ? DateUtils.formatDateTime(closeDate) : null)
        .prop("fCloseDate", formatDate(issue.closeDate()));

    addUserWithLabel(result, issue.assignee(), "assignee", json);
    addUserWithLabel(result, issue.reporter(), "reporter", json);
  }
  @Test
  public void should_update_issues() throws Exception {
    setupData("should_update_issues");

    IssueChangeContext context = IssueChangeContext.createUser(new Date(), "emmerik");

    DefaultIssueComment comment = DefaultIssueComment.create("ABCDE", "emmerik", "the comment");
    // override generated key
    comment.setKey("FGHIJ");

    Date date = DateUtils.parseDate("2013-05-18");
    DefaultIssue issue =
        new DefaultIssue()
            .setKey("ABCDE")
            .setNew(false)
            .setChanged(true)

            // updated fields
            .setLine(5000)
            .setProjectUuid("CDEF")
            .setDebt(Duration.create(10L))
            .setChecksum("FFFFF")
            .setAuthorLogin("simon")
            .setAssignee("loic")
            .setFieldChange(context, "severity", "INFO", "BLOCKER")
            .setReporter("emmerik")
            .setResolution("FIXED")
            .setStatus("RESOLVED")
            .setSeverity("BLOCKER")
            .setAttribute("foo", "bar")
            .addComment(comment)
            .setCreationDate(date)
            .setUpdateDate(date)
            .setCloseDate(date)

            // unmodifiable fields
            .setRuleKey(RuleKey.of("xxx", "unknown"))
            .setComponentKey("struts:Action")
            .setProjectKey("struts");

    storage.save(issue);

    checkTables(
        "should_update_issues",
        new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"},
        "issues",
        "issue_changes");
  }
Example #18
0
  @CheckForNull
  private static Long parseDateTimeAsLong(@Nullable String dateAsString) {
    if (dateAsString == null) {
      return null;
    }

    Date date = parseDateTimeQuietly(dateAsString);
    if (date == null) {
      date = parseDateQuietly(dateAsString);
      checkRequest(
          date != null, "Date '%s' cannot be parsed as either a date or date+time", dateAsString);
      date = DateUtils.addDays(date, 1);
    }

    return date.getTime();
  }
  @Test
  public void shouldCopyDateWhenNotNew() {
    Violation newViolation = newViolation("message", 1, 50, "checksum");
    RuleFailureModel referenceViolation = newReferenceViolation("", 1, 50, "checksum");
    Date referenceDate = DateUtils.parseDate("2009-05-18");
    referenceViolation.setCreatedAt(referenceDate);
    assertThat(newViolation.getCreatedAt(), nullValue());

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation),
            Lists.<RuleFailureModel>newArrayList(referenceViolation));
    assertThat(mapping.size(), is(1));
    assertThat(newViolation.getCreatedAt(), is(referenceDate));
    assertThat(newViolation.isNew(), is(false));
  }
Example #20
0
 private void writeComments(IssueQueryResult queryResult, Issue issue, JsonWriter json) {
   json.name("comments").beginArray();
   for (IssueComment comment : issue.comments()) {
     String userLogin = comment.userLogin();
     json.beginObject()
         .prop("key", comment.key())
         .prop("userName", userLogin != null ? queryResult.user(userLogin).name() : null)
         .prop("raw", comment.markdownText())
         .prop("html", Markdown.convertToHtml(comment.markdownText()))
         .prop("createdAt", DateUtils.formatDateTime(comment.createdAt()))
         .prop("fCreatedAge", formatAgeDate(comment.createdAt()))
         .prop(
             "updatable",
             UserSession.get().isLoggedIn()
                 && UserSession.get().login().equals(comment.userLogin()))
         .endObject();
   }
   json.endArray();
 }
 private void writeResponse(JsonWriter json, Result<QProfileActivity> result, Paging paging) {
   json.beginObject();
   json.prop("total", result.getTotal());
   json.prop(Param.PAGE, paging.pageIndex());
   json.prop(Param.PAGE_SIZE, paging.pageSize());
   json.name("events").beginArray();
   for (QProfileActivity event : result.getHits()) {
     json.beginObject()
         .prop("date", DateUtils.formatDateTime(event.getCreatedAt()))
         .prop("authorLogin", event.getLogin())
         .prop("authorName", event.authorName())
         .prop("action", event.getAction())
         .prop("ruleKey", event.ruleKey().toString())
         .prop("ruleName", event.ruleName());
     writeParameters(json, event);
     json.endObject();
   }
   json.endArray();
   json.endObject().close();
 }
  @Test
  public void should_insert_new_issues() throws Exception {
    setupData("should_insert_new_issues");

    DefaultIssueComment comment = DefaultIssueComment.create("ABCDE", "emmerik", "the comment");
    // override generated key
    comment.setKey("FGHIJ");

    Date date = DateUtils.parseDate("2013-05-18");
    DefaultIssue issue =
        new DefaultIssue()
            .setKey("ABCDE")
            .setNew(true)
            .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
            .setProjectKey("struts")
            .setLine(5000)
            .setDebt(Duration.create(10L))
            .setReporter("emmerik")
            .setResolution("OPEN")
            .setStatus("OPEN")
            .setSeverity("BLOCKER")
            .setAttribute("foo", "bar")
            .addComment(comment)
            .setCreationDate(date)
            .setUpdateDate(date)
            .setCloseDate(date)
            .setComponentKey("struts:Action");

    storage.save(issue);

    checkTables(
        "should_insert_new_issues",
        new String[] {"id", "created_at", "updated_at", "issue_change_creation_date"},
        "issues",
        "issue_changes");
  }
/** TODO this class should use ServerTester instead of mocking db */
@RunWith(MockitoJUnitRunner.class)
public class DebtModelOperationsTest {

  @Rule public UserSessionRule userSessionRule = UserSessionRule.standalone();

  @Mock CharacteristicDao dao;

  @Mock RuleDao ruleDao;

  @Mock DbClient dbClient;

  @Mock DbSession session;

  @Mock System2 system2;

  @Captor ArgumentCaptor<CharacteristicDto> characteristicCaptor;

  @Captor ArgumentCaptor<RuleDto> ruleCaptor;

  Date now = DateUtils.parseDate("2014-03-19");

  CharacteristicDto characteristicDto =
      new CharacteristicDto()
          .setId(1)
          .setKey("MEMORY_EFFICIENCY")
          .setName("Memory use")
          .setOrder(2)
          .setEnabled(true);

  CharacteristicDto subCharacteristicDto =
      new CharacteristicDto()
          .setId(2)
          .setKey("EFFICIENCY")
          .setName("Efficiency")
          .setParentId(1)
          .setEnabled(true);

  int currentId;

  DebtModelOperations service;

  @Before
  public void setUp() {
    when(system2.now()).thenReturn(now.getTime());

    userSessionRule.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);

    currentId = 10;
    // Associate an id when inserting an object to simulate the db id generator
    doAnswer(
            new Answer() {
              public Object answer(InvocationOnMock invocation) {
                Object[] args = invocation.getArguments();
                CharacteristicDto dto = (CharacteristicDto) args[0];
                dto.setId(++currentId);
                return null;
              }
            })
        .when(dao)
        .insert(any(CharacteristicDto.class), any(SqlSession.class));

    when(dbClient.openSession(false)).thenReturn(session);
    when(dbClient.ruleDao()).thenReturn(ruleDao);
    when(dbClient.debtCharacteristicDao()).thenReturn(dao);
    service = new DebtModelOperations(dbClient, system2, userSessionRule);
  }

  @Test
  public void create_sub_characteristic() {
    when(dao.selectById(1, session)).thenReturn(characteristicDto);

    DefaultDebtCharacteristic result =
        (DefaultDebtCharacteristic) service.create("Compilation name", 1);

    assertThat(result.id()).isEqualTo(currentId);
    assertThat(result.key()).isEqualTo("COMPILATION_NAME");
    assertThat(result.name()).isEqualTo("Compilation name");
    assertThat(result.parentId()).isEqualTo(1);
    assertThat(result.createdAt()).isEqualTo(now);
  }

  @Test
  public void fail_to_create_sub_characteristic_when_parent_id_is_not_a_root_characteristic() {
    when(dao.selectById(1, session)).thenReturn(subCharacteristicDto);

    try {
      service.create("Compilation", 1);
      fail();
    } catch (BadRequestException e) {
      assertThat(e.firstError().getKey())
          .isEqualTo("A sub characteristic can not have a sub characteristic as parent.");
    }
  }

  @Test
  public void fail_to_create_sub_characteristic_when_parent_does_not_exists() {
    when(dao.selectById(1, session)).thenReturn(null);

    try {
      service.create("Compilation", 1);
      fail();
    } catch (Exception e) {
      assertThat(e)
          .isInstanceOf(NotFoundException.class)
          .hasMessage("Characteristic with id 1 does not exists.");
    }
  }

  @Test
  public void fail_to_create_sub_characteristic_when_name_already_used() {
    when(dao.selectByName("Compilation", session)).thenReturn(new CharacteristicDto());
    when(dao.selectById(1, session)).thenReturn(characteristicDto);

    try {
      service.create("Compilation", 1);
      fail();
    } catch (BadRequestException e) {
      assertThat(e.firstError().getKey()).isEqualTo("errors.is_already_used");
      assertThat(e.firstError().getParams()[0]).isEqualTo("Compilation");
    }
  }

  @Test
  public void fail_to_create_sub_characteristic_when_wrong_permission() {
    userSessionRule.setGlobalPermissions(GlobalPermissions.DASHBOARD_SHARING);

    try {
      service.create("Compilation", 1);
      fail();
    } catch (Exception e) {
      assertThat(e).isInstanceOf(ForbiddenException.class);
    }
  }

  @Test
  public void create_characteristic() {
    when(dao.selectMaxCharacteristicOrder(session)).thenReturn(2);

    DefaultDebtCharacteristic result =
        (DefaultDebtCharacteristic) service.create("Portability", null);

    assertThat(result.id()).isEqualTo(currentId);
    assertThat(result.key()).isEqualTo("PORTABILITY");
    assertThat(result.name()).isEqualTo("Portability");
    assertThat(result.order()).isEqualTo(3);
    assertThat(result.createdAt()).isEqualTo(now);
  }

  @Test
  public void create_first_characteristic() {
    when(dao.selectMaxCharacteristicOrder(session)).thenReturn(0);

    DefaultDebtCharacteristic result =
        (DefaultDebtCharacteristic) service.create("Portability", null);

    assertThat(result.id()).isEqualTo(currentId);
    assertThat(result.key()).isEqualTo("PORTABILITY");
    assertThat(result.name()).isEqualTo("Portability");
    assertThat(result.order()).isEqualTo(1);
    assertThat(result.createdAt()).isEqualTo(now);
  }

  @Test
  public void rename_characteristic() {
    when(dao.selectById(10, session)).thenReturn(subCharacteristicDto);

    DefaultDebtCharacteristic result =
        (DefaultDebtCharacteristic) service.rename(10, "New Efficiency");

    assertThat(result.key()).isEqualTo("EFFICIENCY");
    assertThat(result.name()).isEqualTo("New Efficiency");
    assertThat(result.updatedAt()).isEqualTo(now);
  }

  @Test
  public void not_rename_characteristic_when_renaming_with_same_name() {
    when(dao.selectById(10, session)).thenReturn(subCharacteristicDto);

    service.rename(10, "Efficiency");

    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }

  @Test
  public void fail_to_rename_unknown_characteristic() {
    when(dao.selectById(10, session)).thenReturn(null);

    try {
      service.rename(10, "New Efficiency");
      fail();
    } catch (Exception e) {
      assertThat(e)
          .isInstanceOf(NotFoundException.class)
          .hasMessage("Characteristic with id 10 does not exists.");
    }
  }

  @Test
  public void move_up() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(1),
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2)));

    DebtCharacteristic result = service.moveUp(10);

    verify(dao, times(2)).update(characteristicCaptor.capture(), eq(session));

    assertThat(result.order()).isEqualTo(1);
    assertThat(characteristicCaptor.getAllValues().get(0).getOrder()).isEqualTo(2);
    assertThat(characteristicCaptor.getAllValues().get(0).getUpdatedAt()).isEqualTo(now);
    assertThat(characteristicCaptor.getAllValues().get(1).getOrder()).isEqualTo(1);
    assertThat(characteristicCaptor.getAllValues().get(1).getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void do_nothing_when_move_up_and_already_on_top() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(1));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(1),
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(2)));

    service.moveUp(10);

    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }

  @Test
  public void move_down() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2),
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(3)));

    DebtCharacteristic result = service.moveDown(10);

    verify(dao, times(2)).update(characteristicCaptor.capture(), eq(session));

    assertThat(result.order()).isEqualTo(3);
    assertThat(characteristicCaptor.getAllValues().get(0).getOrder()).isEqualTo(2);
    assertThat(characteristicCaptor.getAllValues().get(0).getUpdatedAt()).isEqualTo(now);
    assertThat(characteristicCaptor.getAllValues().get(1).getOrder()).isEqualTo(3);
    assertThat(characteristicCaptor.getAllValues().get(1).getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void do_nothing_when_move_down_and_already_on_bottom() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(1),
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2)));

    service.moveDown(10);

    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }

  @Test
  public void fail_to_move_sub_characteristic() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setParentId(1));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2),
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(3)));

    try {
      service.moveDown(10);
      fail();
    } catch (BadRequestException e) {
      assertThat(e.firstError().getKey()).isEqualTo("Sub characteristics can not be moved.");
    }
    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }

  @Test
  public void fail_to_move_characteristic_with_no_order() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(null));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2),
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(3)));

    try {
      service.moveDown(10);
      fail();
    } catch (Exception e) {
      assertThat(e)
          .isInstanceOf(IllegalArgumentException.class)
          .hasMessage("The order of the characteristic 'MEMORY_EFFICIENCY' should not be null");
    }

    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }

  @Test
  public void delete_sub_characteristic() {
    DbSession batchSession = mock(DbSession.class);
    when(dbClient.openSession(true)).thenReturn(batchSession);

    when(ruleDao.findRulesByDebtSubCharacteristicId(batchSession, 2))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("5min")
                    .setDefaultSubCharacteristicId(10)
                    .setDefaultRemediationFunction(
                        DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setDefaultRemediationCoefficient("4h")
                    .setDefaultRemediationOffset("15min")));
    when(dao.selectById(2, batchSession)).thenReturn(subCharacteristicDto);

    service.delete(2);

    verify(ruleDao).update(eq(batchSession), ruleCaptor.capture());

    RuleDto ruleDto = ruleCaptor.getValue();
    assertThat(ruleDto.getUpdatedAt()).isEqualTo(now);

    // Overridden debt data are disabled
    assertThat(ruleDto.getSubCharacteristicId()).isEqualTo(-1);
    assertThat(ruleDto.getRemediationFunction()).isNull();
    assertThat(ruleDto.getRemediationCoefficient()).isNull();
    assertThat(ruleDto.getRemediationOffset()).isNull();

    // Default debt data should not be touched
    assertThat(ruleDto.getDefaultSubCharacteristicId()).isEqualTo(10);
    assertThat(ruleDto.getDefaultRemediationFunction()).isEqualTo("LINEAR_OFFSET");
    assertThat(ruleDto.getDefaultRemediationCoefficient()).isEqualTo("4h");
    assertThat(ruleDto.getDefaultRemediationOffset()).isEqualTo("15min");

    verify(dao).update(characteristicCaptor.capture(), eq(batchSession));
    CharacteristicDto characteristicDto = characteristicCaptor.getValue();

    // Sub characteristic is disable
    assertThat(characteristicDto.getId()).isEqualTo(2);
    assertThat(characteristicDto.isEnabled()).isFalse();
    assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void
      delete_sub_characteristic_disable_default_rules_debt_if_default_characteristic_is_deleted() {
    DbSession batchSession = mock(DbSession.class);
    when(dbClient.openSession(true)).thenReturn(batchSession);

    when(ruleDao.findRulesByDebtSubCharacteristicId(batchSession, 2))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setSubCharacteristicId(10)
                    .setRemediationFunction("LINEAR_OFFSET")
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("5min")
                    .setDefaultSubCharacteristicId(2)
                    .setDefaultRemediationFunction("LINEAR_OFFSET")
                    .setDefaultRemediationCoefficient("4h")
                    .setDefaultRemediationOffset("15min")));
    when(dao.selectById(2, batchSession)).thenReturn(subCharacteristicDto);

    service.delete(2);

    verify(ruleDao).update(eq(batchSession), ruleCaptor.capture());
    RuleDto ruleDto = ruleCaptor.getValue();

    // Default debt data are disabled
    assertThat(ruleDto.getDefaultSubCharacteristicId()).isNull();
    assertThat(ruleDto.getDefaultRemediationFunction()).isNull();
    assertThat(ruleDto.getDefaultRemediationCoefficient()).isNull();
    assertThat(ruleDto.getDefaultRemediationOffset()).isNull();

    // Overridden debt data should not be touched
    assertThat(ruleDto.getSubCharacteristicId()).isEqualTo(10);
    assertThat(ruleDto.getRemediationFunction()).isEqualTo("LINEAR_OFFSET");
    assertThat(ruleDto.getRemediationCoefficient()).isEqualTo("2h");
    assertThat(ruleDto.getRemediationOffset()).isEqualTo("5min");

    verify(dao).update(characteristicCaptor.capture(), eq(batchSession));
    CharacteristicDto characteristicDto = characteristicCaptor.getValue();

    // Sub characteristic is disable
    assertThat(characteristicDto.getId()).isEqualTo(2);
    assertThat(characteristicDto.isEnabled()).isFalse();
    assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void delete_characteristic() {
    DbSession batchSession = mock(DbSession.class);
    when(dbClient.openSession(true)).thenReturn(batchSession);

    when(ruleDao.findRulesByDebtSubCharacteristicId(batchSession, subCharacteristicDto.getId()))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setSubCharacteristicId(subCharacteristicDto.getId())
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("5min")));
    when(dao.selectCharacteristicsByParentId(1, batchSession))
        .thenReturn(newArrayList(subCharacteristicDto));
    when(dao.selectById(1, batchSession)).thenReturn(characteristicDto);

    service.delete(1);

    verify(ruleDao).update(eq(batchSession), ruleCaptor.capture());

    verify(dao, times(2)).update(characteristicCaptor.capture(), eq(batchSession));
    CharacteristicDto subCharacteristicDto = characteristicCaptor.getAllValues().get(0);
    CharacteristicDto characteristicDto = characteristicCaptor.getAllValues().get(1);

    // Sub characteristic is disable
    assertThat(subCharacteristicDto.getId()).isEqualTo(2);
    assertThat(subCharacteristicDto.isEnabled()).isFalse();
    assertThat(subCharacteristicDto.getUpdatedAt()).isEqualTo(now);

    // Characteristic is disable
    assertThat(characteristicDto.getId()).isEqualTo(1);
    assertThat(characteristicDto.isEnabled()).isFalse();
    assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void not_delete_already_disabled_characteristic() {
    DbSession batchSession = mock(DbSession.class);
    when(dbClient.openSession(true)).thenReturn(batchSession);

    when(dao.selectById(1, batchSession))
        .thenReturn(
            new CharacteristicDto()
                .setId(1)
                .setKey("MEMORY_EFFICIENCY")
                .setName("Memory use")
                .setOrder(2)
                .setEnabled(false));

    service.delete(1);

    verify(dao, never()).update(any(CharacteristicDto.class), eq(batchSession));
  }
}
Example #24
0
@Category(DbTests.class)
public class RegisterRulesTest {

  static final Date DATE1 = DateUtils.parseDateTime("2014-01-01T19:10:03+0100");
  static final Date DATE2 = DateUtils.parseDateTime("2014-02-01T12:10:03+0100");
  static final Date DATE3 = DateUtils.parseDateTime("2014-03-01T12:10:03+0100");

  System2 system;

  @org.junit.Rule public DbTester dbTester = DbTester.create(system);

  RuleActivator ruleActivator = mock(RuleActivator.class);

  DbClient dbClient;

  @Before
  public void before() {
    system = mock(System2.class);
    when(system.now()).thenReturn(DATE1.getTime());
    RuleDao ruleDao = new RuleDao(system);
    ActiveRuleDao activeRuleDao =
        new ActiveRuleDao(new QualityProfileDao(dbTester.myBatis(), system), ruleDao, system);
    dbClient =
        new DbClient(
            dbTester.database(),
            dbTester.myBatis(),
            ruleDao,
            activeRuleDao,
            new QualityProfileDao(dbTester.myBatis(), system),
            new CharacteristicDao(dbTester.myBatis()));
  }

  @Test
  public void insert_new_rules() {
    execute(new FakeRepositoryV1());

    // verify db
    assertThat(dbClient.ruleDao().selectAll(dbTester.getSession())).hasSize(2);
    RuleKey ruleKey1 = RuleKey.of("fake", "rule1");
    RuleDto rule1 = dbClient.ruleDao().getNullableByKey(dbTester.getSession(), ruleKey1);
    assertThat(rule1.getName()).isEqualTo("One");
    assertThat(rule1.getDescription()).isEqualTo("Description of One");
    assertThat(rule1.getSeverityString()).isEqualTo(Severity.BLOCKER);
    assertThat(rule1.getTags()).isEmpty();
    assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag2", "tag3");
    assertThat(rule1.getConfigKey()).isEqualTo("config1");
    assertThat(rule1.getStatus()).isEqualTo(RuleStatus.BETA);
    assertThat(rule1.getCreatedAt()).isEqualTo(DATE1);
    assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1);
    // TODO check characteristic and remediation function

    List<RuleParamDto> params =
        dbClient.ruleDao().selectRuleParamsByRuleKey(dbTester.getSession(), ruleKey1);
    assertThat(params).hasSize(2);
    RuleParamDto param = getParam(params, "param1");
    assertThat(param.getDescription()).isEqualTo("parameter one");
    assertThat(param.getDefaultValue()).isEqualTo("default1");
  }

  @Test
  public void do_not_update_rules_when_no_changes() {
    execute(new FakeRepositoryV1());
    assertThat(dbClient.ruleDao().selectAll(dbTester.getSession())).hasSize(2);

    when(system.now()).thenReturn(DATE2.getTime());
    execute(new FakeRepositoryV1());

    RuleKey ruleKey1 = RuleKey.of("fake", "rule1");
    RuleDto rule1 = dbClient.ruleDao().getNullableByKey(dbTester.getSession(), ruleKey1);
    assertThat(rule1.getCreatedAt()).isEqualTo(DATE1);
    assertThat(rule1.getUpdatedAt()).isEqualTo(DATE1);
  }

  @Test
  public void update_and_remove_rules_on_changes() {
    execute(new FakeRepositoryV1());
    assertThat(dbClient.ruleDao().selectAll(dbTester.getSession())).hasSize(2);

    // user adds tags and sets markdown note
    RuleKey ruleKey1 = RuleKey.of("fake", "rule1");
    RuleDto rule1 = dbClient.ruleDao().getNullableByKey(dbTester.getSession(), ruleKey1);
    rule1.setTags(Sets.newHashSet("usertag1", "usertag2"));
    rule1.setNoteData("user *note*");
    rule1.setNoteUserLogin("marius");
    dbClient.ruleDao().update(dbTester.getSession(), rule1);
    dbTester.getSession().commit();

    when(system.now()).thenReturn(DATE2.getTime());
    execute(new FakeRepositoryV2());

    // rule1 has been updated
    rule1 = dbClient.ruleDao().getNullableByKey(dbTester.getSession(), ruleKey1);
    assertThat(rule1.getName()).isEqualTo("One v2");
    assertThat(rule1.getDescription()).isEqualTo("Description of One v2");
    assertThat(rule1.getSeverityString()).isEqualTo(Severity.INFO);
    assertThat(rule1.getTags()).containsOnly("usertag1", "usertag2");
    assertThat(rule1.getSystemTags()).containsOnly("tag1", "tag4");
    assertThat(rule1.getConfigKey()).isEqualTo("config1 v2");
    assertThat(rule1.getNoteData()).isEqualTo("user *note*");
    assertThat(rule1.getNoteUserLogin()).isEqualTo("marius");
    assertThat(rule1.getStatus()).isEqualTo(RuleStatus.READY);
    assertThat(rule1.getCreatedAt()).isEqualTo(DATE1);
    assertThat(rule1.getUpdatedAt()).isEqualTo(DATE2);

    // TODO check characteristic and remediation function
    List<RuleParamDto> params =
        dbClient.ruleDao().selectRuleParamsByRuleKey(dbTester.getSession(), ruleKey1);
    assertThat(params).hasSize(2);
    RuleParamDto param = getParam(params, "param1");
    assertThat(param.getDescription()).isEqualTo("parameter one v2");
    assertThat(param.getDefaultValue()).isEqualTo("default1 v2");

    // rule2 has been removed -> status set to REMOVED but db row is not deleted
    RuleDto rule2 =
        dbClient.ruleDao().getNullableByKey(dbTester.getSession(), RuleKey.of("fake", "rule2"));
    assertThat(rule2.getStatus()).isEqualTo(RuleStatus.REMOVED);
    assertThat(rule2.getUpdatedAt()).isEqualTo(DATE2);

    // rule3 has been created
    RuleDto rule3 =
        dbClient.ruleDao().getNullableByKey(dbTester.getSession(), RuleKey.of("fake", "rule3"));
    assertThat(rule3).isNotNull();
    assertThat(rule3.getStatus()).isEqualTo(RuleStatus.READY);
  }

  @Test
  public void do_not_update_already_removed_rules() {
    execute(new FakeRepositoryV1());
    assertThat(dbClient.ruleDao().selectAll(dbTester.getSession())).hasSize(2);

    RuleDto rule2 = dbClient.ruleDao().getByKey(dbTester.getSession(), RuleKey.of("fake", "rule2"));
    assertThat(rule2.getStatus()).isEqualTo(RuleStatus.READY);

    when(system.now()).thenReturn(DATE2.getTime());
    execute(new FakeRepositoryV2());

    // On MySQL, need to update a rule otherwise rule2 will be seen as READY, but why ???
    dbClient
        .ruleDao()
        .update(
            dbTester.getSession(),
            dbClient.ruleDao().getByKey(dbTester.getSession(), RuleKey.of("fake", "rule1")));
    dbTester.getSession().commit();

    // rule2 is removed
    rule2 = dbClient.ruleDao().getNullableByKey(dbTester.getSession(), RuleKey.of("fake", "rule2"));
    assertThat(rule2.getStatus()).isEqualTo(RuleStatus.REMOVED);

    when(system.now()).thenReturn(DATE3.getTime());
    execute(new FakeRepositoryV2());
    dbTester.getSession().commit();

    // -> rule2 is still removed, but not update at DATE3
    rule2 = dbClient.ruleDao().getNullableByKey(dbTester.getSession(), RuleKey.of("fake", "rule2"));
    assertThat(rule2.getStatus()).isEqualTo(RuleStatus.REMOVED);
    assertThat(rule2.getUpdatedAt()).isEqualTo(DATE2);
  }

  @Test
  public void mass_insert() {
    execute(new BigRepository());
    assertThat(dbClient.ruleDao().selectAll(dbTester.getSession())).hasSize(BigRepository.SIZE);
    assertThat(dbClient.ruleDao().selectAllRuleParams(dbTester.getSession()))
        .hasSize(BigRepository.SIZE * 20);
  }

  @Test
  public void manage_repository_extensions() {
    execute(new FindbugsRepository(), new FbContribRepository());
    List<RuleDto> rules = dbClient.ruleDao().selectAll(dbTester.getSession());
    assertThat(rules).hasSize(2);
    for (RuleDto rule : rules) {
      assertThat(rule.getRepositoryKey()).isEqualTo("findbugs");
    }
  }

  private void execute(RulesDefinition... defs) {
    RuleDefinitionsLoader loader =
        new RuleDefinitionsLoader(
            mock(DeprecatedRulesDefinitionLoader.class),
            new RuleRepositories(),
            mock(CommonRuleDefinitionsImpl.class),
            defs);
    Languages languages = mock(Languages.class);
    when(languages.get("java")).thenReturn(mock(Language.class));

    RegisterRules task = new RegisterRules(loader, ruleActivator, dbClient, languages);
    task.start();
    // Execute a commit to refresh session state as the task is using its own session
    dbTester.getSession().commit();
  }

  private RuleParamDto getParam(List<RuleParamDto> params, String key) {
    for (RuleParamDto param : params) {
      if (param.getName().equals(key)) {
        return param;
      }
    }
    return null;
  }

  static class FakeRepositoryV1 implements RulesDefinition {
    @Override
    public void define(Context context) {
      NewRepository repo = context.createRepository("fake", "java");
      NewRule rule1 =
          repo.createRule("rule1")
              .setName("One")
              .setHtmlDescription("Description of One")
              .setSeverity(Severity.BLOCKER)
              .setInternalKey("config1")
              .setTags("tag1", "tag2", "tag3")
              .setStatus(RuleStatus.BETA)
              .setDebtSubCharacteristic("MEMORY_EFFICIENCY")
              .setEffortToFixDescription("squid.S115.effortToFix");
      rule1.setDebtRemediationFunction(
          rule1.debtRemediationFunctions().linearWithOffset("5d", "10h"));

      rule1.createParam("param1").setDescription("parameter one").setDefaultValue("default1");
      rule1.createParam("param2").setDescription("parameter two").setDefaultValue("default2");

      repo.createRule("rule2").setName("Two").setHtmlDescription("Minimal rule");
      repo.done();
    }
  }

  /** FakeRepositoryV1 with some changes */
  static class FakeRepositoryV2 implements RulesDefinition {
    @Override
    public void define(Context context) {
      NewRepository repo = context.createRepository("fake", "java");

      // almost all the attributes of rule1 are changed
      NewRule rule1 =
          repo.createRule("rule1")
              .setName("One v2")
              .setHtmlDescription("Description of One v2")
              .setSeverity(Severity.INFO)
              .setInternalKey("config1 v2")
              // tag2 and tag3 removed, tag4 added
              .setTags("tag1", "tag4")
              .setStatus(RuleStatus.READY)
              .setDebtSubCharacteristic("MEMORY_EFFICIENCY")
              .setEffortToFixDescription("squid.S115.effortToFix.v2");
      rule1.setDebtRemediationFunction(
          rule1.debtRemediationFunctions().linearWithOffset("6d", "2h"));
      rule1.createParam("param1").setDescription("parameter one v2").setDefaultValue("default1 v2");
      rule1.createParam("param2").setDescription("parameter two v2").setDefaultValue("default2 v2");

      // rule2 is dropped, rule3 is new
      repo.createRule("rule3").setName("Three").setHtmlDescription("Rule Three");
      repo.done();
    }
  }

  static class BigRepository implements RulesDefinition {
    static final int SIZE = 500;

    @Override
    public void define(Context context) {
      NewRepository repo = context.createRepository("big", "java");
      for (int i = 0; i < SIZE; i++) {
        NewRule rule =
            repo.createRule("rule" + i)
                .setName("name of " + i)
                .setHtmlDescription("description of " + i);
        for (int j = 0; j < 20; j++) {
          rule.createParam("param" + j);
        }
      }
      repo.done();
    }
  }

  static class FindbugsRepository implements RulesDefinition {
    @Override
    public void define(Context context) {
      NewRepository repo = context.createRepository("findbugs", "java");
      repo.createRule("rule1").setName("Rule One").setHtmlDescription("Description of Rule One");
      repo.done();
    }
  }

  static class FbContribRepository implements RulesDefinition {
    @Override
    public void define(Context context) {
      NewExtendedRepository repo = context.extendRepository("findbugs", "java");
      repo.createRule("rule2").setName("Rule Two").setHtmlDescription("Description of Rule Two");
      repo.done();
    }
  }
}
Example #25
0
  @Override
  public void define(WebService.NewController controller) {
    WebService.NewAction action =
        controller
            .createAction("activity")
            .setDescription(
                format(
                    "Search for tasks.<br> "
                        + "Requires the system administration permission, "
                        + "or project administration permission if %s is set.<br/>"
                        + "Since 5.5, it's no more possible to specify the page parameter",
                    PARAM_COMPONENT_ID))
            .setResponseExample(getClass().getResource("activity-example.json"))
            .setHandler(this)
            .setSince("5.2");

    action
        .createParam(PARAM_COMPONENT_ID)
        .setDescription("Id of the component (project) to filter on")
        .setExampleValue(Uuids.UUID_EXAMPLE_03);
    action
        .createParam(PARAM_COMPONENT_QUERY)
        .setDescription(
            format(
                "Limit search to: <ul>"
                    + "<li>component names that contain the supplied string</li>"
                    + "<li>component keys that are exactly the same as the supplied string</li>"
                    + "</ul>"
                    + "Must not be set together with %s.<br />"
                    + "Deprecated and replaced by '%s'",
                PARAM_COMPONENT_ID, Param.TEXT_QUERY))
        .setExampleValue("Apache")
        .setDeprecatedSince("5.5");
    action
        .createParam(Param.TEXT_QUERY)
        .setDescription(
            format(
                "Limit search to: <ul>"
                    + "<li>component names that contain the supplied string</li>"
                    + "<li>component keys that are exactly the same as the supplied string</li>"
                    + "<li>task ids that are exactly the same as the supplied string</li>"
                    + "</ul>"
                    + "Must not be set together with %s",
                PARAM_COMPONENT_ID))
        .setExampleValue("Apache")
        .setSince("5.5");
    action
        .createParam(PARAM_STATUS)
        .setDescription("Comma separated list of task statuses")
        .setPossibleValues(
            ImmutableList.builder()
                .add(CeActivityDto.Status.values())
                .add(CeQueueDto.Status.values())
                .build())
        .setExampleValue(
            Joiner.on(",").join(CeQueueDto.Status.IN_PROGRESS, CeActivityDto.Status.SUCCESS))
        // activity statuses by default to be backward compatible
        // queued tasks have been added in 5.5
        .setDefaultValue(Joiner.on(",").join(CeActivityDto.Status.values()));
    action
        .createParam(PARAM_ONLY_CURRENTS)
        .setDescription("Filter on the last tasks (only the most recent finished task by project)")
        .setBooleanPossibleValues()
        .setDefaultValue("false");
    action
        .createParam(PARAM_TYPE)
        .setDescription("Task type")
        .setExampleValue(CeTaskTypes.REPORT)
        .setPossibleValues(taskTypes);
    action
        .createParam(PARAM_MIN_SUBMITTED_AT)
        .setDescription("Minimum date of task submission (inclusive)")
        .setExampleValue(DateUtils.formatDateTime(new Date()));
    action
        .createParam(PARAM_MAX_EXECUTED_AT)
        .setDescription("Maximum date of end of task processing (inclusive)")
        .setExampleValue(DateUtils.formatDateTime(new Date()));
    action
        .createParam(Param.PAGE)
        .setDescription("Deprecated parameter")
        .setDeprecatedSince("5.5")
        .setDeprecatedKey("pageIndex");
    action.addPageSize(100, MAX_PAGE_SIZE);
  }
Example #26
0
 @Nullable
 public Date getExpirationDate() {
   return DateUtils.parseDateQuietly(expirationDate);
 }
 private void addDate(@Nullable Date date, String dateKey, JsonWriter json) {
   if (date != null) {
     json.prop(dateKey, DateUtils.formatDateTime(date));
   }
 }
Example #28
0
 public static PurgeableSnapshotDto createSnapshotWithDateTime(long snapshotId, String datetime) {
   PurgeableSnapshotDto snapshot = new PurgeableSnapshotDto();
   snapshot.setSnapshotId(snapshotId);
   snapshot.setDate(DateUtils.parseDateTime(datetime));
   return snapshot;
 }
public class ViolationTrackingDecoratorTest {

  private ViolationTrackingDecorator decorator;
  private Date analysisDate = DateUtils.parseDate("2010-12-25");

  @Before
  public void setUp() throws ParseException {
    Project project = mock(Project.class);
    when(project.getAnalysisDate()).thenReturn(analysisDate);
    decorator = new ViolationTrackingDecorator(project, null, null);
  }

  @Test
  public void permanentIdShouldBeThePrioritaryFieldToCheck() {
    RuleFailureModel referenceViolation1 =
        newReferenceViolation("message", 10, 1, "checksum1").setPermanentId(100);
    RuleFailureModel referenceViolation2 =
        newReferenceViolation("message", 18, 1, "checksum2").setPermanentId(200);
    Violation newViolation =
        newViolation("message", 10, 1, "checksum1"); // exactly the fields of referenceViolation1
    newViolation.setPermanentId(200);

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation),
            Lists.newArrayList(referenceViolation1, referenceViolation2));

    assertThat(mapping.get(newViolation), equalTo(referenceViolation2)); // same permanent id
    assertThat(newViolation.isNew(), is(false));
  }

  @Test
  public void checksumShouldHaveGreaterPriorityThanLine() {
    RuleFailureModel referenceViolation1 = newReferenceViolation("message", 1, 50, "checksum1");
    RuleFailureModel referenceViolation2 = newReferenceViolation("message", 3, 50, "checksum2");

    Violation newViolation1 = newViolation("message", 3, 50, "checksum1");
    Violation newViolation2 = newViolation("message", 5, 50, "checksum2");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation1, newViolation2),
            Lists.newArrayList(referenceViolation1, referenceViolation2));
    assertThat(mapping.get(newViolation1), equalTo(referenceViolation1));
    assertThat(newViolation1.isNew(), is(false));
    assertThat(mapping.get(newViolation2), equalTo(referenceViolation2));
    assertThat(newViolation2.isNew(), is(false));
  }

  /** See SONAR-2928 */
  @Test
  public void sameRuleAndNullLineAndChecksumButDifferentMessages() {
    Violation newViolation = newViolation("new message", null, 50, "checksum1");
    RuleFailureModel referenceViolation =
        newReferenceViolation("old message", null, 50, "checksum1");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation));
    assertThat(mapping.get(newViolation), equalTo(referenceViolation));
    assertThat(newViolation.isNew(), is(false));
  }

  @Test
  public void sameRuleAndLineAndChecksumButDifferentMessages() {
    Violation newViolation = newViolation("new message", 1, 50, "checksum1");
    RuleFailureModel referenceViolation = newReferenceViolation("old message", 1, 50, "checksum1");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation));
    assertThat(mapping.get(newViolation), equalTo(referenceViolation));
    assertThat(newViolation.isNew(), is(false));
  }

  @Test
  public void sameRuleAndLineMessage() {
    Violation newViolation = newViolation("message", 1, 50, "checksum1");
    RuleFailureModel refernceViolation = newReferenceViolation("message", 1, 50, "checksum2");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(refernceViolation));
    assertThat(mapping.get(newViolation), equalTo(refernceViolation));
    assertThat(newViolation.isNew(), is(false));
  }

  @Test
  public void shouldIgnoreReferenceMeasureWithoutChecksum() {
    Violation newViolation = newViolation("message", 1, 50, null);
    RuleFailureModel referenceViolation = newReferenceViolation("message", 1, 51, null);

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation));
    assertThat(mapping.get(newViolation), is(nullValue()));
    assertThat(newViolation.isNew(), is(true));
  }

  @Test
  public void sameRuleAndMessageAndChecksumButDifferentLine() {
    Violation newViolation = newViolation("message", 1, 50, "checksum1");
    RuleFailureModel referenceViolation = newReferenceViolation("message", 2, 50, "checksum1");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation));
    assertThat(mapping.get(newViolation), equalTo(referenceViolation));
    assertThat(newViolation.isNew(), is(false));
  }

  /** See https://jira.codehaus.org/browse/SONAR-2812 */
  @Test
  public void sameChecksumAndRuleButDifferentLineAndDifferentMessage() {
    Violation newViolation = newViolation("new message", 1, 50, "checksum1");
    RuleFailureModel referenceViolation = newReferenceViolation("old message", 2, 50, "checksum1");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation));
    assertThat(mapping.get(newViolation), equalTo(referenceViolation));
    assertThat(newViolation.isNew(), is(false));
  }

  @Test
  public void shouldCreateNewViolationWhenSameRuleSameMessageButDifferentLineAndChecksum() {
    Violation newViolation = newViolation("message", 1, 50, "checksum1");
    RuleFailureModel referenceViolation = newReferenceViolation("message", 2, 50, "checksum2");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation));
    assertThat(mapping.get(newViolation), is(nullValue()));
    assertThat(newViolation.isNew(), is(true));
  }

  @Test
  public void shouldNotTrackViolationIfDifferentRule() {
    Violation newViolation = newViolation("message", 1, 50, "checksum1");
    RuleFailureModel referenceViolation = newReferenceViolation("message", 1, 51, "checksum1");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation));
    assertThat(mapping.get(newViolation), is(nullValue()));
    assertThat(newViolation.isNew(), is(true));
  }

  @Test
  public void shouldCompareViolationsWithDatabaseFormat() {
    // violation messages are trimmed and can be abbreviated when persisted in database.
    // Comparing violation messages must use the same format.
    Violation newViolation = newViolation(" message ", 1, 50, "checksum1");
    RuleFailureModel referenceViolation =
        newReferenceViolation("       message       ", 1, 50, "checksum2");

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Lists.newArrayList(referenceViolation));
    assertThat(mapping.get(newViolation), equalTo(referenceViolation));
    assertThat(newViolation.isNew(), is(false));
  }

  @Test
  public void shouldSetDateOfNewViolations() {
    Violation newViolation = newViolation("message", 1, 50, "checksum");
    assertThat(newViolation.getCreatedAt(), nullValue());

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation), Collections.<RuleFailureModel>emptyList());
    assertThat(mapping.size(), is(0));
    assertThat(newViolation.getCreatedAt(), is(analysisDate));
    assertThat(newViolation.isNew(), is(true));
  }

  @Test
  public void shouldCopyDateWhenNotNew() {
    Violation newViolation = newViolation("message", 1, 50, "checksum");
    RuleFailureModel referenceViolation = newReferenceViolation("", 1, 50, "checksum");
    Date referenceDate = DateUtils.parseDate("2009-05-18");
    referenceViolation.setCreatedAt(referenceDate);
    assertThat(newViolation.getCreatedAt(), nullValue());

    Map<Violation, RuleFailureModel> mapping =
        decorator.mapViolations(
            Lists.newArrayList(newViolation),
            Lists.<RuleFailureModel>newArrayList(referenceViolation));
    assertThat(mapping.size(), is(1));
    assertThat(newViolation.getCreatedAt(), is(referenceDate));
    assertThat(newViolation.isNew(), is(false));
  }

  private Violation newViolation(String message, Integer lineId, int ruleId) {
    Rule rule = Rule.create().setKey("rule");
    rule.setId(ruleId);
    return Violation.create(rule, null).setLineId(lineId).setMessage(message);
  }

  private Violation newViolation(String message, Integer lineId, int ruleId, String lineChecksum) {
    return newViolation(message, lineId, ruleId).setChecksum(lineChecksum);
  }

  private RuleFailureModel newReferenceViolation(
      String message, Integer lineId, int ruleId, String lineChecksum) {
    RuleFailureModel referenceViolation = new RuleFailureModel();
    referenceViolation.setId(violationId++);
    referenceViolation.setLine(lineId);
    referenceViolation.setMessage(message);
    referenceViolation.setRuleId(ruleId);
    referenceViolation.setChecksum(lineChecksum);
    return referenceViolation;
  }

  private int violationId = 0;
}
@RunWith(MockitoJUnitRunner.class)
public class DebtModelBackupTest {

  @Rule public UserSessionRule userSessionRule = UserSessionRule.standalone();

  @Mock DbClient dbClient;
  @Mock DbSession session;
  @Mock DebtModelPluginRepository debtModelPluginRepository;
  @Mock CharacteristicDao dao;
  @Mock RuleDao ruleDao;
  @Mock DebtModelOperations debtModelOperations;
  @Mock RuleOperations ruleOperations;
  @Mock DebtCharacteristicsXMLImporter characteristicsXMLImporter;
  @Mock DebtRulesXMLImporter rulesXMLImporter;
  @Mock DebtModelXMLExporter debtModelXMLExporter;
  @Mock RuleDefinitionsLoader defLoader;
  @Mock System2 system2;

  @Captor ArgumentCaptor<CharacteristicDto> characteristicCaptor;
  @Captor ArgumentCaptor<RuleDto> ruleCaptor;
  @Captor ArgumentCaptor<ArrayList<RuleDebt>> ruleDebtListCaptor;

  Date oldDate = DateUtils.parseDate("2014-01-01");
  Date now = DateUtils.parseDate("2014-03-19");

  int currentId;

  DebtModelBackup debtModelBackup;

  @Before
  public void setUp() {
    userSessionRule.setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN);

    when(system2.now()).thenReturn(now.getTime());

    currentId = 10;
    // Associate an id when inserting an object to simulate the db id generator
    doAnswer(
            new Answer() {
              public Object answer(InvocationOnMock invocation) {
                Object[] args = invocation.getArguments();
                CharacteristicDto dto = (CharacteristicDto) args[0];
                dto.setId(currentId++);
                return null;
              }
            })
        .when(dao)
        .insert(any(CharacteristicDto.class), any(DbSession.class));

    when(dbClient.openSession(false)).thenReturn(session);
    when(dbClient.ruleDao()).thenReturn(ruleDao);
    when(dbClient.debtCharacteristicDao()).thenReturn(dao);

    Reader defaultModelReader = mock(Reader.class);
    when(debtModelPluginRepository.createReaderForXMLFile("technical-debt"))
        .thenReturn(defaultModelReader);

    debtModelBackup =
        new DebtModelBackup(
            dbClient,
            debtModelOperations,
            ruleOperations,
            debtModelPluginRepository,
            characteristicsXMLImporter,
            rulesXMLImporter,
            debtModelXMLExporter,
            defLoader,
            system2,
            userSessionRule);
  }

  @Test
  public void backup() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                // Rule with overridden debt values
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min"),

                // Rule with default debt values
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("AvoidNPE")
                    .setDefaultSubCharacteristicId(2)
                    .setDefaultRemediationFunction("LINEAR")
                    .setDefaultRemediationCoefficient("2h")));

    debtModelBackup.backup();

    ArgumentCaptor<DebtModel> debtModelArgument = ArgumentCaptor.forClass(DebtModel.class);
    verify(debtModelXMLExporter).export(debtModelArgument.capture(), ruleDebtListCaptor.capture());
    assertThat(debtModelArgument.getValue().rootCharacteristics()).hasSize(1);
    assertThat(debtModelArgument.getValue().subCharacteristics("PORTABILITY")).hasSize(1);

    List<RuleDebt> rules = ruleDebtListCaptor.getValue();
    assertThat(rules).hasSize(2);

    RuleDebt rule = rules.get(0);
    assertThat(rule.ruleKey().repository()).isEqualTo("squid");
    assertThat(rule.ruleKey().rule()).isEqualTo("UselessImportCheck");
    assertThat(rule.subCharacteristicKey()).isEqualTo("COMPILER");
    assertThat(rule.function()).isEqualTo("LINEAR_OFFSET");
    assertThat(rule.coefficient()).isEqualTo("2h");
    assertThat(rule.offset()).isEqualTo("15min");

    rule = rules.get(1);
    assertThat(rule.ruleKey().repository()).isEqualTo("squid");
    assertThat(rule.ruleKey().rule()).isEqualTo("AvoidNPE");
    assertThat(rule.subCharacteristicKey()).isEqualTo("COMPILER");
    assertThat(rule.function()).isEqualTo("LINEAR");
    assertThat(rule.coefficient()).isEqualTo("2h");
    assertThat(rule.offset()).isNull();
  }

  @Test
  public void backup_with_disabled_rules() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                // Debt disabled
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setSubCharacteristicId(RuleDto.DISABLED_CHARACTERISTIC_ID),

                // Not debt
                new RuleDto().setRepositoryKey("squid").setRuleKey("AvoidNPE")));

    debtModelBackup.backup();

    verify(debtModelXMLExporter).export(any(DebtModel.class), ruleDebtListCaptor.capture());

    assertThat(ruleDebtListCaptor.getValue()).isEmpty();
  }

  @Test
  public void backup_with_rule_having_default_linear_and_overridden_offset() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                // Rule with default debt values : default value is linear (only coefficient is set)
                // and overridden value is constant per issue (only offset is set)
                // -> Ony offset should be set
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("AvoidNPE")
                    .setDefaultSubCharacteristicId(2)
                    .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setDefaultRemediationCoefficient("2h")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.toString())
                    .setRemediationOffset("15min")));

    debtModelBackup.backup();

    ArgumentCaptor<DebtModel> debtModelArgument = ArgumentCaptor.forClass(DebtModel.class);
    verify(debtModelXMLExporter).export(debtModelArgument.capture(), ruleDebtListCaptor.capture());
    assertThat(debtModelArgument.getValue().rootCharacteristics()).hasSize(1);
    assertThat(debtModelArgument.getValue().subCharacteristics("PORTABILITY")).hasSize(1);

    List<RuleDebt> rules = ruleDebtListCaptor.getValue();
    assertThat(rules).hasSize(1);

    RuleDebt rule = rules.get(0);
    assertThat(rule.ruleKey().repository()).isEqualTo("squid");
    assertThat(rule.ruleKey().rule()).isEqualTo("AvoidNPE");
    assertThat(rule.subCharacteristicKey()).isEqualTo("COMPILER");
    assertThat(rule.function()).isEqualTo("CONSTANT_ISSUE");
    assertThat(rule.offset()).isEqualTo("15min");
    assertThat(rule.coefficient()).isNull();
  }

  @Test
  public void backup_from_language() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setLanguage("java")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.toString())
                    .setRemediationOffset("15min"),
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate),
                // Should be ignored
                new RuleDto()
                    .setId(2)
                    .setRepositoryKey("checkstyle")
                    .setLanguage("java2")
                    .setSubCharacteristicId(3)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setRemediationCoefficient("2h")
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate)
                ));

    debtModelBackup.backup("java");

    verify(debtModelXMLExporter).export(any(DebtModel.class), ruleDebtListCaptor.capture());

    List<RuleDebt> rules = ruleDebtListCaptor.getValue();
    assertThat(rules).hasSize(1);

    RuleDebt rule = rules.get(0);
    assertThat(rule.ruleKey().repository()).isEqualTo("squid");
    assertThat(rule.ruleKey().rule()).isEqualTo("UselessImportCheck");
    assertThat(rule.subCharacteristicKey()).isEqualTo("COMPILER");
    assertThat(rule.function()).isEqualTo("CONSTANT_ISSUE");
    assertThat(rule.coefficient()).isNull();
    assertThat(rule.offset()).isEqualTo("15min");
  }

  @Test
  public void create_characteristics_when_restoring_characteristics() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(Collections.<CharacteristicDto>emptyList());

    debtModelBackup.restoreCharacteristics(
        new DebtModel()
            .addRootCharacteristic(
                new DefaultDebtCharacteristic()
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1))
            .addSubCharacteristic(
                new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                "PORTABILITY"),
        now,
        session);

    verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));

    CharacteristicDto dto1 = characteristicCaptor.getAllValues().get(0);
    assertThat(dto1.getId()).isEqualTo(10);
    assertThat(dto1.getKey()).isEqualTo("PORTABILITY");
    assertThat(dto1.getName()).isEqualTo("Portability");
    assertThat(dto1.getParentId()).isNull();
    assertThat(dto1.getOrder()).isEqualTo(1);
    assertThat(dto1.getCreatedAt()).isEqualTo(now);
    assertThat(dto1.getUpdatedAt()).isNull();

    CharacteristicDto dto2 = characteristicCaptor.getAllValues().get(1);
    assertThat(dto2.getId()).isEqualTo(11);
    assertThat(dto2.getKey()).isEqualTo("COMPILER");
    assertThat(dto2.getName()).isEqualTo("Compiler");
    assertThat(dto2.getParentId()).isEqualTo(10);
    assertThat(dto2.getOrder()).isNull();
    assertThat(dto2.getCreatedAt()).isEqualTo(now);
    assertThat(dto2.getUpdatedAt()).isNull();
  }

  @Test
  public void update_characteristics_when_restoring_characteristics() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                // Order and name have changed
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate)
                    .setUpdatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)
                    .setUpdatedAt(oldDate)));

    debtModelBackup.restoreCharacteristics(
        new DebtModel()
            .addRootCharacteristic(
                new DefaultDebtCharacteristic()
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1))
            .addSubCharacteristic(
                new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                "PORTABILITY"),
        now,
        session);

    verify(dao, times(2)).update(characteristicCaptor.capture(), eq(session));

    CharacteristicDto dto1 = characteristicCaptor.getAllValues().get(0);
    assertThat(dto1.getId()).isEqualTo(1);
    assertThat(dto1.getKey()).isEqualTo("PORTABILITY");
    assertThat(dto1.getName()).isEqualTo("Portability");
    assertThat(dto1.getParentId()).isNull();
    assertThat(dto1.getOrder()).isEqualTo(1);
    assertThat(dto1.getCreatedAt()).isEqualTo(oldDate);
    assertThat(dto1.getUpdatedAt()).isEqualTo(now);

    CharacteristicDto dto2 = characteristicCaptor.getAllValues().get(1);
    assertThat(dto2.getId()).isEqualTo(2);
    assertThat(dto2.getKey()).isEqualTo("COMPILER");
    assertThat(dto2.getName()).isEqualTo("Compiler");
    assertThat(dto2.getParentId()).isEqualTo(1);
    assertThat(dto2.getOrder()).isNull();
    assertThat(dto2.getCreatedAt()).isEqualTo(oldDate);
    assertThat(dto2.getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void update_parent_when_restoring_characteristics() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                // Parent has changed
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setParentId(1)
                    .setOrder(1)
                    .setCreatedAt(oldDate)
                    .setUpdatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setCreatedAt(oldDate)
                    .setUpdatedAt(oldDate)));

    debtModelBackup.restoreCharacteristics(
        new DebtModel()
            .addRootCharacteristic(
                new DefaultDebtCharacteristic()
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1))
            .addSubCharacteristic(
                new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                "PORTABILITY"),
        now,
        session);

    verify(dao, times(2)).update(characteristicCaptor.capture(), eq(session));

    CharacteristicDto dto1 = characteristicCaptor.getAllValues().get(0);
    assertThat(dto1.getId()).isEqualTo(1);
    assertThat(dto1.getKey()).isEqualTo("PORTABILITY");
    assertThat(dto1.getParentId()).isNull();
    assertThat(dto1.getUpdatedAt()).isEqualTo(now);

    CharacteristicDto dto2 = characteristicCaptor.getAllValues().get(1);
    assertThat(dto2.getId()).isEqualTo(2);
    assertThat(dto2.getKey()).isEqualTo("COMPILER");
    assertThat(dto2.getParentId()).isEqualTo(1);
    assertThat(dto2.getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void disable_no_more_existing_characteristics_when_restoring_characteristics() {
    CharacteristicDto dto1 =
        new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1);
    CharacteristicDto dto2 =
        new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1);

    when(dao.selectEnabledCharacteristics(session)).thenReturn(newArrayList(dto1, dto2));

    debtModelBackup.restoreCharacteristics(new DebtModel(), now, session);

    verify(debtModelOperations).delete(dto1, now, session);
    verify(debtModelOperations).delete(dto2, now, session);
  }

  @Test
  public void reset_model() {
    when(characteristicsXMLImporter.importXML(any(Reader.class)))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2), // .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1) // .setCreatedAt(oldDate)
                ));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("NPE")
                    .setDefaultSubCharacteristicId(10)
                    .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setDefaultRemediationCoefficient("2h")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min")));

    RulesDefinition.Context context = new RulesDefinition.Context();
    RulesDefinition.NewRepository repo = context.createRepository("squid", "java").setName("Squid");
    RulesDefinition.NewRule newRule =
        repo.createRule("NPE")
            .setName("Detect NPE")
            .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
            .setSeverity(Severity.BLOCKER)
            .setStatus(RuleStatus.BETA)
            .setDebtSubCharacteristic("COMPILER");
    newRule.setDebtRemediationFunction(
        newRule.debtRemediationFunctions().linearWithOffset("4h", "20min"));
    repo.done();
    when(defLoader.load()).thenReturn(context);

    debtModelBackup.reset();

    verify(dao).selectEnabledCharacteristics(session);
    verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
    verifyNoMoreInteractions(dao);

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(ruleDao).update(eq(session), ruleCaptor.capture());
    verifyNoMoreInteractions(ruleDao);

    verify(session).commit();

    RuleDto rule = ruleCaptor.getValue();

    assertThat(rule.getDefaultSubCharacteristicId()).isEqualTo(2);
    assertThat(rule.getDefaultRemediationFunction()).isEqualTo("LINEAR_OFFSET");
    assertThat(rule.getDefaultRemediationCoefficient()).isEqualTo("4h");
    assertThat(rule.getDefaultRemediationOffset()).isEqualTo("20min");
    assertThat(rule.getUpdatedAt()).isEqualTo(now);

    assertThat(rule.getSubCharacteristicId()).isNull();
    assertThat(rule.getRemediationFunction()).isNull();
    assertThat(rule.getRemediationCoefficient()).isNull();
    assertThat(rule.getRemediationOffset()).isNull();
    assertThat(rule.getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void reset_model_when_no_default_value() {
    when(characteristicsXMLImporter.importXML(any(Reader.class)))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("NPE")
                    .setDefaultSubCharacteristicId(10)
                    .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setDefaultRemediationCoefficient("2h")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min")));

    RulesDefinition.Context context = new RulesDefinition.Context();
    RulesDefinition.NewRepository repo = context.createRepository("squid", "java").setName("Squid");
    repo.createRule("NPE")
        .setName("Detect NPE")
        .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
        .setSeverity(Severity.BLOCKER)
        .setStatus(RuleStatus.BETA);
    repo.done();
    when(defLoader.load()).thenReturn(context);

    debtModelBackup.reset();

    verify(dao).selectEnabledCharacteristics(session);
    verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
    verifyNoMoreInteractions(dao);

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(ruleDao).update(eq(session), ruleCaptor.capture());
    verifyNoMoreInteractions(ruleDao);

    verify(session).commit();

    RuleDto rule = ruleCaptor.getValue();
    assertThat(rule.getDefaultSubCharacteristicId()).isNull();
    assertThat(rule.getDefaultRemediationFunction()).isNull();
    assertThat(rule.getDefaultRemediationCoefficient()).isNull();
    assertThat(rule.getDefaultRemediationOffset()).isNull();
    assertThat(rule.getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void reset_model_on_custom_rules() {
    when(characteristicsXMLImporter.importXML(any(Reader.class)))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                // Template rule
                new RuleDto()
                    .setId(5)
                    .setRepositoryKey("squid")
                    .setRuleKey("XPath")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min"),
                // Custom rule
                new RuleDto()
                    .setId(6)
                    .setRepositoryKey("squid")
                    .setRuleKey("XPath_1369910135")
                    .setTemplateId(5)
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min")));

    RulesDefinition.Context context = new RulesDefinition.Context();
    // Template rule
    RulesDefinition.NewRepository repo = context.createRepository("squid", "java").setName("XPath");
    RulesDefinition.NewRule newRule =
        repo.createRule("XPath")
            .setName("XPath")
            .setHtmlDescription("XPath")
            .setSeverity(Severity.BLOCKER)
            .setStatus(RuleStatus.BETA)
            .setDebtSubCharacteristic("COMPILER");
    newRule.setDebtRemediationFunction(
        newRule.debtRemediationFunctions().linearWithOffset("4h", "20min"));
    repo.done();
    when(defLoader.load()).thenReturn(context);

    debtModelBackup.reset();

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(ruleDao, times(2)).update(eq(session), ruleCaptor.capture());
    verifyNoMoreInteractions(ruleDao);
    verify(session).commit();

    RuleDto rule = ruleCaptor.getAllValues().get(1);

    assertThat(rule.getId()).isEqualTo(6);
    assertThat(rule.getDefaultSubCharacteristicId()).isEqualTo(2);
    assertThat(rule.getDefaultRemediationFunction()).isEqualTo("LINEAR_OFFSET");
    assertThat(rule.getDefaultRemediationCoefficient()).isEqualTo("4h");
    assertThat(rule.getDefaultRemediationOffset()).isEqualTo("20min");
    assertThat(rule.getUpdatedAt()).isEqualTo(now);

    assertThat(rule.getSubCharacteristicId()).isNull();
    assertThat(rule.getRemediationFunction()).isNull();
    assertThat(rule.getRemediationCoefficient()).isNull();
    assertThat(rule.getRemediationOffset()).isNull();
    assertThat(rule.getUpdatedAt()).isEqualTo(now);
  }

  @Test
  public void reset_model_do_not_load_rule_definitions_if_no_rule() {
    when(characteristicsXMLImporter.importXML(any(Reader.class)))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(ruleDao.selectEnabledAndNonManual(session)).thenReturn(Collections.<RuleDto>emptyList());

    debtModelBackup.reset();

    verify(dao).selectEnabledCharacteristics(session);
    verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
    verifyNoMoreInteractions(dao);

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(ruleDao, never()).update(eq(session), any(RuleDto.class));
    verifyZeroInteractions(defLoader);

    verify(session).commit();
  }

  @Test
  public void restore_from_xml() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    CharacteristicDto compiler =
        new CharacteristicDto()
            .setId(2)
            .setKey("COMPILER")
            .setName("Compiler")
            .setParentId(1)
            .setCreatedAt(oldDate);
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(3)
                    .setKey("HARDWARE")
                    .setName("Hardware")
                    .setParentId(1)
                    .setCreatedAt(oldDate),
                compiler));

    when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class)))
        .thenReturn(
            newArrayList(
                new RuleDebt()
                    .setRuleKey(RuleKey.of("squid", "UselessImportCheck"))
                    .setSubCharacteristicKey("COMPILER")
                    .setFunction(DebtRemediationFunction.Type.LINEAR.name())
                    .setCoefficient("2h")));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setDefaultSubCharacteristicId(3)
                    .setDefaultRemediationFunction("LINEAR")
                    .setDefaultRemediationCoefficient("2h")
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate)
                ));

    debtModelBackup.restoreFromXml("<xml/>");

    verify(ruleOperations)
        .updateRule(
            ruleCaptor.capture(),
            eq(compiler),
            eq("LINEAR"),
            eq("2h"),
            isNull(String.class),
            eq(session));

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session).commit();
  }

  @Test
  public void
      restore_from_xml_disable_rule_debt_when_not_in_xml_and_rule_have_default_debt_values() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setDefaultSubCharacteristicId(2)
                    .setDefaultRemediationFunction("LINEAR_OFFSET")
                    .setDefaultRemediationCoefficient("2h")
                    .setDefaultRemediationOffset("15min")
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate)
                ));

    debtModelBackup.restoreFromXml("<xml/>");

    verify(ruleOperations)
        .updateRule(
            ruleCaptor.capture(),
            isNull(CharacteristicDto.class),
            isNull(String.class),
            isNull(String.class),
            isNull(String.class),
            eq(session));

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session).commit();
  }

  @Test
  public void restore_from_xml_and_language() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    CharacteristicDto compiler =
        new CharacteristicDto()
            .setId(2)
            .setKey("COMPILER")
            .setName("Compiler")
            .setParentId(1)
            .setCreatedAt(oldDate);
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1)
                    .setCreatedAt(oldDate),
                compiler));

    when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class)))
        .thenReturn(
            newArrayList(
                new RuleDebt()
                    .setRuleKey(RuleKey.of("squid", "UselessImportCheck"))
                    .setSubCharacteristicKey("COMPILER")
                    .setFunction(DebtRemediationFunction.Type.LINEAR.name())
                    .setCoefficient("2h")));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setLanguage("java")
                    .setDefaultSubCharacteristicId(10)
                    .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setDefaultRemediationCoefficient("2h"),
                // Should be ignored
                new RuleDto()
                    .setId(2)
                    .setRepositoryKey("checkstyle")
                    .setLanguage("java2")
                    .setSubCharacteristicId(3)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setRemediationCoefficient("2h")));

    debtModelBackup.restoreFromXml("<xml/>", "java");

    verify(ruleOperations)
        .updateRule(
            ruleCaptor.capture(),
            eq(compiler),
            eq("LINEAR"),
            eq("2h"),
            isNull(String.class),
            eq(session));

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session).commit();
  }

  @Test
  public void restore_from_xml_and_language_disable_no_more_existing_characteristics() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1)));

    CharacteristicDto dto1 =
        new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1);
    // No more existing characteristic
    CharacteristicDto dto2 =
        new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1);
    when(dao.selectEnabledCharacteristics(session)).thenReturn(newArrayList(dto1, dto2));

    debtModelBackup.restoreFromXml("<xml/>", "java");

    verify(debtModelOperations).delete(dto2, now, session);
    verify(session).commit();
  }

  @Test
  public void restore_from_xml_and_language_with_rule_not_in_xml() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class)))
        .thenReturn(Collections.<RuleDebt>emptyList());
    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                // Rule does not exits in XML -> debt will be disabled
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setLanguage("java")
                    .setDefaultSubCharacteristicId(2)
                    .setDefaultRemediationFunction("LINEAR")
                    .setDefaultRemediationCoefficient("2h")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min")));

    debtModelBackup.restoreFromXml("<xml/>", "java");

    verify(ruleOperations)
        .updateRule(
            ruleCaptor.capture(),
            isNull(CharacteristicDto.class),
            isNull(String.class),
            isNull(String.class),
            isNull(String.class),
            eq(session));

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session).commit();
  }

  @Test
  public void restore_from_xml_add_warning_message_when_rule_from_xml_is_not_found() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class)))
        .thenReturn(
            newArrayList(
                new RuleDebt()
                    .setRuleKey(RuleKey.of("squid", "UselessImportCheck"))
                    .setSubCharacteristicKey("COMPILER")
                    .setFunction(DebtRemediationFunction.Type.LINEAR.name())
                    .setCoefficient("2h")));

    when(ruleDao.selectEnabledAndNonManual(session)).thenReturn(Collections.<RuleDto>emptyList());

    assertThat(debtModelBackup.restoreFromXml("<xml/>").getWarnings()).hasSize(1);

    verifyZeroInteractions(ruleOperations);

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session).commit();
  }

  @Test
  public void restore_from_xml_add_error_message_when_illegal_argument_exception() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class)))
        .thenReturn(
            newArrayList(
                new RuleDebt()
                    .setRuleKey(RuleKey.of("squid", "UselessImportCheck"))
                    .setSubCharacteristicKey("COMPILER")
                    .setFunction(DebtRemediationFunction.Type.LINEAR.name())
                    .setCoefficient("2h")));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setDefaultSubCharacteristicId(3)
                    .setDefaultRemediationFunction("LINEAR")
                    .setDefaultRemediationCoefficient("2h")
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate)
                ));

    when(ruleOperations.updateRule(
            any(RuleDto.class),
            any(CharacteristicDto.class),
            anyString(),
            anyString(),
            anyString(),
            eq(session)))
        .thenThrow(IllegalArgumentException.class);

    assertThat(debtModelBackup.restoreFromXml("<xml/>").getErrors()).hasSize(1);

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session, never()).commit();
  }
}