Beispiel #1
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();
  }
Beispiel #2
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"))));
  }
  @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");
  }
  @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());
  }
Beispiel #5
0
 public Date getDate(String key) {
   String value = getString(key);
   if (StringUtils.isNotEmpty(value)) {
     return DateUtils.parseDate(value);
   }
   return null;
 }
Beispiel #6
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);
 }
Beispiel #7
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 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);
 }
  @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);
  }
  @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");
  }
  @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));
  }
  @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));
  }
}
Beispiel #14
0
 public static PurgeableSnapshotDto createSnapshotWithDate(long snapshotId, String date) {
   PurgeableSnapshotDto snapshot = new PurgeableSnapshotDto();
   snapshot.setSnapshotId(snapshotId);
   snapshot.setDate(DateUtils.parseDate(date));
   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();
  }
}