@Override
  public ComputeEngineContainer start(Props props) {
    this.level1 = new ComponentContainer();
    this.level1
        .add(props.rawProperties())
        .add(LEVEL_1_COMPONENTS)
        .add(toArray(CorePropertyDefinitions.all()))
        .add(toArray(CePropertyDefinitions.all()));
    configureFromModules(this.level1);
    this.level1.startComponents();

    ComponentContainer level2 = this.level1.createChild();
    level2.add(LEVEL_2_COMPONENTS);
    configureFromModules(level2);
    level2.startComponents();

    ComponentContainer level3 = level2.createChild();
    level3.add(LEVEL_3_COMPONENTS);
    configureFromModules(level3);
    level3.startComponents();

    this.level4 = level3.createChild();
    this.level4.add(LEVEL_4_COMPONENTS);
    configureFromModules(this.level4);
    ServerExtensionInstaller extensionInstaller =
        this.level4.getComponentByType(ServerExtensionInstaller.class);
    extensionInstaller.installExtensions(this.level4);
    this.level4.startComponents();

    startupTasks();

    return this;
  }
public class ReportPublisherTest {

  @Rule public LogTester logTester = new LogTester();

  @Rule public TemporaryFolder temp = new TemporaryFolder();

  @Rule public ExpectedException exception = ExpectedException.none();

  DefaultAnalysisMode mode = mock(DefaultAnalysisMode.class);
  Settings settings = new Settings(new PropertyDefinitions(CorePropertyDefinitions.all()));
  BatchWsClient wsClient = mock(BatchWsClient.class, Mockito.RETURNS_DEEP_STUBS);
  Server server = mock(Server.class);
  ImmutableProjectReactor reactor = mock(ImmutableProjectReactor.class);
  ProjectDefinition root;
  AnalysisContextReportPublisher contextPublisher = mock(AnalysisContextReportPublisher.class);

  @Before
  public void setUp() {
    root = ProjectDefinition.create().setKey("struts").setWorkDir(temp.getRoot());
    when(reactor.getRoot()).thenReturn(root);
    when(server.getPublicRootUrl()).thenReturn("https://localhost");
  }

  @Test
  public void log_and_dump_information_about_report_uploading() throws IOException {
    ReportPublisher underTest =
        new ReportPublisher(
            settings,
            wsClient,
            server,
            contextPublisher,
            reactor,
            mode,
            mock(TempFolder.class),
            new ReportPublisherStep[0]);

    underTest.logSuccess("TASK-123");

    assertThat(logTester.logs(LoggerLevel.INFO))
        .contains("ANALYSIS SUCCESSFUL, you can browse https://localhost/dashboard/index/struts")
        .contains(
            "Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report")
        .contains("More about the report processing at https://localhost/api/ce/task?id=TASK-123");

    File detailsFile = new File(temp.getRoot(), "report-task.txt");
    assertThat(readFileToString(detailsFile))
        .isEqualTo(
            "projectKey=struts\n"
                + "serverUrl=https://localhost\n"
                + "dashboardUrl=https://localhost/dashboard/index/struts\n"
                + "ceTaskId=TASK-123\n"
                + "ceTaskUrl=https://localhost/api/ce/task?id=TASK-123\n");
  }

  @Test
  public void log_public_url_if_defined() throws IOException {
    when(server.getPublicRootUrl()).thenReturn("https://publicserver/sonarqube");
    ReportPublisher underTest =
        new ReportPublisher(
            settings,
            wsClient,
            server,
            contextPublisher,
            reactor,
            mode,
            mock(TempFolder.class),
            new ReportPublisherStep[0]);

    underTest.logSuccess("TASK-123");

    assertThat(logTester.logs(LoggerLevel.INFO))
        .contains(
            "ANALYSIS SUCCESSFUL, you can browse https://publicserver/sonarqube/dashboard/index/struts")
        .contains(
            "More about the report processing at https://publicserver/sonarqube/api/ce/task?id=TASK-123");

    File detailsFile = new File(temp.getRoot(), "report-task.txt");
    assertThat(readFileToString(detailsFile))
        .isEqualTo(
            "projectKey=struts\n"
                + "serverUrl=https://publicserver/sonarqube\n"
                + "dashboardUrl=https://publicserver/sonarqube/dashboard/index/struts\n"
                + "ceTaskId=TASK-123\n"
                + "ceTaskUrl=https://publicserver/sonarqube/api/ce/task?id=TASK-123\n");
  }

  @Test
  public void fail_if_public_url_malformed() throws IOException {
    when(server.getPublicRootUrl()).thenReturn("invalid");
    ReportPublisher underTest =
        new ReportPublisher(
            settings,
            wsClient,
            server,
            contextPublisher,
            reactor,
            mode,
            mock(TempFolder.class),
            new ReportPublisherStep[0]);

    exception.expect(MessageException.class);
    exception.expectMessage("Failed to parse public URL set in SonarQube server: invalid");
    underTest.start();
  }

  @Test
  public void log_but_not_dump_information_when_report_is_not_uploaded() {
    ReportPublisher underTest =
        new ReportPublisher(
            settings,
            wsClient,
            server,
            contextPublisher,
            reactor,
            mode,
            mock(TempFolder.class),
            new ReportPublisherStep[0]);

    underTest.logSuccess(/* report not uploaded, no server task */ null);

    assertThat(logTester.logs(LoggerLevel.INFO))
        .contains("ANALYSIS SUCCESSFUL")
        .doesNotContain("dashboard/index");

    File detailsFile = new File(temp.getRoot(), ReportPublisher.METADATA_DUMP_FILENAME);
    assertThat(detailsFile).doesNotExist();
  }

  @Test
  public void should_not_delete_report_if_property_is_set() throws IOException {
    settings.setProperty("sonar.batch.keepReport", true);
    Path reportDir = temp.getRoot().toPath().resolve("batch-report");
    Files.createDirectory(reportDir);
    ReportPublisher underTest =
        new ReportPublisher(
            settings,
            wsClient,
            server,
            contextPublisher,
            reactor,
            mode,
            mock(TempFolder.class),
            new ReportPublisherStep[0]);

    underTest.start();
    underTest.stop();
    assertThat(reportDir).isDirectory();
  }

  @Test
  public void should_delete_report_by_default() throws IOException {
    Path reportDir = temp.getRoot().toPath().resolve("batch-report");
    Files.createDirectory(reportDir);
    ReportPublisher job =
        new ReportPublisher(
            settings,
            wsClient,
            server,
            contextPublisher,
            reactor,
            mode,
            mock(TempFolder.class),
            new ReportPublisherStep[0]);

    job.start();
    job.stop();
    assertThat(reportDir).doesNotExist();
  }
}