Package org.sonar.core.issue.workflow

Source Code of org.sonar.core.issue.workflow.IssueWorkflowTest

/*
* SonarQube, open source software quality management tool.
* Copyright (C) 2008-2014 SonarSource
* mailto:contact AT sonarsource DOT com
*
* SonarQube is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* SonarQube is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package org.sonar.core.issue.workflow;

import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import org.apache.commons.lang.time.DateUtils;
import org.junit.Test;
import org.sonar.api.issue.DefaultTransitions;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.IssueChangeContext;
import org.sonar.api.rule.RuleKey;
import org.sonar.core.issue.IssueUpdater;

import javax.annotation.Nullable;

import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
import static org.mockito.Mockito.mock;

public class IssueWorkflowTest {

  IssueUpdater updater = new IssueUpdater();
  IssueWorkflow workflow = new IssueWorkflow(new FunctionExecutor(updater), updater);

  @Test
  public void should_init_state_machine() throws Exception {
    assertThat(workflow.machine()).isNull();
    workflow.start();
    assertThat(workflow.machine()).isNotNull();
    assertThat(workflow.machine().state(Issue.STATUS_OPEN)).isNotNull();
    assertThat(workflow.machine().state(Issue.STATUS_CONFIRMED)).isNotNull();
    assertThat(workflow.machine().state(Issue.STATUS_CLOSED)).isNotNull();
    assertThat(workflow.machine().state(Issue.STATUS_REOPENED)).isNotNull();
    assertThat(workflow.machine().state(Issue.STATUS_RESOLVED)).isNotNull();
    workflow.stop();
  }

  @Test
  public void should_list_statuses() throws Exception {
    workflow.start();
    // order is important for UI
    assertThat(workflow.statusKeys()).containsSequence(Issue.STATUS_OPEN, Issue.STATUS_CONFIRMED, Issue.STATUS_REOPENED, Issue.STATUS_RESOLVED, Issue.STATUS_CLOSED);
  }

  @Test
  public void should_list_out_transitions_from_status_open() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_OPEN);
    List<Transition> transitions = workflow.outTransitions(issue);
    assertThat(transitions).hasSize(3);
    assertThat(keys(transitions)).containsOnly("confirm", "falsepositive", "resolve");
  }

  @Test
  public void should_list_out_transitions_from_status_confirmed() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_CONFIRMED);
    List<Transition> transitions = workflow.outTransitions(issue);
    assertThat(transitions).hasSize(3);
    assertThat(keys(transitions)).containsOnly("unconfirm", "falsepositive", "resolve");
  }

  @Test
  public void should_list_out_transitions_from_status_resolved() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_RESOLVED);
    List<Transition> transitions = workflow.outTransitions(issue);
    assertThat(transitions).hasSize(1);
    assertThat(keys(transitions)).containsOnly("reopen");
  }

  @Test
  public void should_list_out_transitions_from_status_reopen() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_REOPENED);
    List<Transition> transitions = workflow.outTransitions(issue);
    assertThat(transitions).hasSize(3);
    assertThat(keys(transitions)).containsOnly("confirm", "resolve", "falsepositive");
  }

  @Test
  public void should_list_no_out_transition_from_status_closed() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue().setStatus(Issue.STATUS_CLOSED);
    List<Transition> transitions = workflow.outTransitions(issue);
    assertThat(transitions).isEmpty();
  }

  @Test
  public void should_list_out_transitions_from_status_closed_on_manual_issue() throws Exception {
    workflow.start();

    // Manual issue because of reporter
    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setStatus(Issue.STATUS_CLOSED)
      .setRuleKey(RuleKey.of("manual", "Performance"))
      .setReporter("simon");

    List<Transition> transitions = workflow.outTransitions(issue);
    assertThat(transitions).hasSize(1);
    assertThat(keys(transitions)).containsOnly("reopen");
  }

  @Test
  public void should_fail_if_unknown_status_when_listing_transitions() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue().setStatus("xxx");
    try {
      workflow.outTransitions(issue);
      fail();
    } catch (IllegalArgumentException e) {
      assertThat(e).hasMessage("Unknown status: xxx");
    }
  }


  @Test
  public void should_do_automatic_transition() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setResolution(Issue.RESOLUTION_FIXED)
      .setStatus(Issue.STATUS_RESOLVED)
      .setNew(false)
      .setEndOfLife(true);
    Date now = new Date();
    workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
    assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
    assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
    assertThat(issue.closeDate()).isNotNull();
    assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND));
  }

  @Test
  public void should_close_open_dead_issue() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setResolution(null)
      .setStatus(Issue.STATUS_OPEN)
      .setNew(false)
      .setEndOfLife(true);
    Date now = new Date();
    workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
    assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
    assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
    assertThat(issue.closeDate()).isNotNull();
    assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND));
  }

  @Test
  public void should_close_reopened_dead_issue() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setResolution(null)
      .setStatus(Issue.STATUS_REOPENED)
      .setNew(false)
      .setEndOfLife(true);
    Date now = new Date();
    workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
    assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
    assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
    assertThat(issue.closeDate()).isNotNull();
    assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND));
  }

  @Test
  public void should_close_confirmed_dead_issue() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setResolution(null)
      .setStatus(Issue.STATUS_CONFIRMED)
      .setNew(false)
      .setEndOfLife(true);
    Date now = new Date();
    workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(now));
    assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FIXED);
    assertThat(issue.status()).isEqualTo(Issue.STATUS_CLOSED);
    assertThat(issue.closeDate()).isNotNull();
    assertThat(issue.updateDate()).isEqualTo(DateUtils.truncate(now, Calendar.SECOND));
  }


  @Test
  public void should_fail_if_unknown_status_on_automatic_trans() throws Exception {
    workflow.start();

    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setResolution(Issue.RESOLUTION_FIXED)
      .setStatus("xxx")
      .setNew(false)
      .setEndOfLife(true);
    try {
      workflow.doAutomaticTransition(issue, IssueChangeContext.createScan(new Date()));
      fail();
    } catch (IllegalStateException e) {
      assertThat(e).hasMessage("Unknown status: xxx [issue=ABCDE]");
    }
  }

  @Test
  public void should_flag_as_false_positive() throws Exception {
    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setStatus(Issue.STATUS_OPEN)
      .setRuleKey(RuleKey.of("squid", "AvoidCycle"))
      .setAssignee("morgan");

    workflow.start();
    workflow.doTransition(issue, DefaultTransitions.FALSE_POSITIVE, IssueChangeContext.createScan(new Date()));

    assertThat(issue.resolution()).isEqualTo(Issue.RESOLUTION_FALSE_POSITIVE);
    assertThat(issue.status()).isEqualTo(Issue.STATUS_RESOLVED);

    // should remove assignee
    assertThat(issue.assignee()).isNull();
  }

  @Test
  public void manual_issues_should_be_resolved_then_closed() throws Exception {
    // Manual issue because of reporter
    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setStatus(Issue.STATUS_OPEN)
      .setRuleKey(RuleKey.of("manual", "Performance"))
      .setReporter("simon");

    workflow.start();

    assertThat(workflow.outTransitions(issue)).containsOnly(
      Transition.create("confirm", "OPEN", "CONFIRMED"),
      Transition.create("resolve", "OPEN", "RESOLVED"),
      Transition.create("falsepositive", "OPEN", "RESOLVED")
    );

    workflow.doTransition(issue, "resolve", mock(IssueChangeContext.class));
    assertThat(issue.resolution()).isEqualTo("FIXED");
    assertThat(issue.status()).isEqualTo("RESOLVED");

    assertThat(workflow.outTransitions(issue)).containsOnly(
      Transition.create("reopen", "RESOLVED", "REOPENED")
    );

    workflow.doAutomaticTransition(issue, mock(IssueChangeContext.class));
    assertThat(issue.resolution()).isEqualTo("FIXED");
    assertThat(issue.status()).isEqualTo("CLOSED");
  }

  @Test
  public void manual_issues_should_be_confirmed_then_kept_open() throws Exception {
    // Manual issue because of reporter
    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setStatus(Issue.STATUS_OPEN)
      .setRuleKey(RuleKey.of("manual", "Performance"))
      .setReporter("simon");

    workflow.start();

    assertThat(workflow.outTransitions(issue)).containsOnly(
      Transition.create("confirm", "OPEN", "CONFIRMED"),
      Transition.create("resolve", "OPEN", "RESOLVED"),
      Transition.create("falsepositive", "OPEN", "RESOLVED")
    );

    workflow.doTransition(issue, "confirm", mock(IssueChangeContext.class));
    assertThat(issue.resolution()).isNull();
    assertThat(issue.status()).isEqualTo("CONFIRMED");

    assertThat(workflow.outTransitions(issue)).containsOnly(
      Transition.create("unconfirm", "CONFIRMED", "REOPENED"),
      Transition.create("resolve", "CONFIRMED", "RESOLVED"),
      Transition.create("falsepositive", "CONFIRMED", "RESOLVED")
    );

    // keep confirmed and unresolved
    workflow.doAutomaticTransition(issue, mock(IssueChangeContext.class));
    assertThat(issue.resolution()).isNull();
    assertThat(issue.status()).isEqualTo("CONFIRMED");

    // unconfirm
    workflow.doTransition(issue, "unconfirm", mock(IssueChangeContext.class));
    assertThat(issue.resolution()).isNull();
    assertThat(issue.status()).isEqualTo("REOPENED");
  }

  @Test
  public void manual_issue_on_removed_rule_should_be_closed() throws Exception {
    // Manual issue because of reporter
    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setStatus(Issue.STATUS_OPEN)
      .setRuleKey(RuleKey.of("manual", "Performance"))
      .setReporter("simon")
      .setEndOfLife(true)
      .setOnDisabledRule(true);

    workflow.start();

    workflow.doAutomaticTransition(issue, mock(IssueChangeContext.class));
    assertThat(issue.resolution()).isEqualTo("REMOVED");
    assertThat(issue.status()).isEqualTo("CLOSED");
  }

  @Test
  public void manual_issue_on_removed_component_should_be_closed() throws Exception {
    // Manual issue because of reporter
    DefaultIssue issue = new DefaultIssue()
      .setKey("ABCDE")
      .setStatus(Issue.STATUS_OPEN)
      .setRuleKey(RuleKey.of("manual", "Performance"))
      .setReporter("simon")
      .setEndOfLife(true)
      .setOnDisabledRule(false);

    workflow.start();

    workflow.doAutomaticTransition(issue, mock(IssueChangeContext.class));
    assertThat(issue.resolution()).isEqualTo("FIXED");
    assertThat(issue.status()).isEqualTo("CLOSED");
  }

  private Collection<String> keys(List<Transition> transitions) {
    return Collections2.transform(transitions, new Function<Transition, String>() {
      @Override
      public String apply(@Nullable Transition transition) {
        return transition.key();
      }
    });
  }
}
TOP

Related Classes of org.sonar.core.issue.workflow.IssueWorkflowTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.