@Test
  public void should_NOT_markAsChangedWhenMaterialIsReIntroducedWithSameRevisionsToPipeline()
      throws Exception {
    SvnMaterial svn1 = SvnMaterial.createSvnMaterialWithMock(repository);
    svn1.setFolder("another_repo");
    mingleConfig = configHelper.replaceMaterialForPipeline(MINGLE_PIPELINE_NAME, svn1.config());
    runAndPassWith(svn1, "foo.c", svnRepository);

    SvnTestRepo svn2Repository = new SvnTestRepo("testSvnRepo2");
    Subversion repository2 = new SvnCommand(null, svn2Repository.projectRepositoryUrl());
    SvnMaterial svn2 = SvnMaterial.createSvnMaterialWithMock(repository2);
    svn2.setFolder("boulder");

    checkinFile(svn2, "bar.c", svn2Repository);

    mingleConfig = configHelper.addMaterialToPipeline(MINGLE_PIPELINE_NAME, svn2.config());

    scheduleHelper.autoSchedulePipelinesWithRealMaterials(MINGLE_PIPELINE_NAME);

    assertThat(pipelineScheduleQueue.toBeScheduled().keySet(), hasItem(MINGLE_PIPELINE_NAME));
    BuildCause mingleBuildCause = pipelineScheduleQueue.toBeScheduled().get(MINGLE_PIPELINE_NAME);
    verifyChanged(svn2, mingleBuildCause, true);
    verifyChanged(
        svn1,
        mingleBuildCause,
        false); // this should not have changed, as foo.c was already built in the previous instance

    runAndPass(mingleBuildCause.getMaterialRevisions());

    mingleConfig = configHelper.replaceMaterialForPipeline(MINGLE_PIPELINE_NAME, svn1.config());
    scheduleHelper.autoSchedulePipelinesWithRealMaterials(MINGLE_PIPELINE_NAME);

    assertThat(pipelineScheduleQueue.toBeScheduled().keySet(), hasItem(MINGLE_PIPELINE_NAME));
    mingleBuildCause = pipelineScheduleQueue.toBeScheduled().get(MINGLE_PIPELINE_NAME);
    verifyChanged(
        svn1,
        mingleBuildCause,
        false); // this should not have changed, as foo.c was already built in the previous instance
    runAndPassWith(svn1, "baz.c", svnRepository);

    mingleConfig = configHelper.addMaterialToPipeline(MINGLE_PIPELINE_NAME, svn2.config());

    checkinFile(svn1, "quux.c", svnRepository);

    scheduleHelper.autoSchedulePipelinesWithRealMaterials(MINGLE_PIPELINE_NAME);

    assertThat(pipelineScheduleQueue.toBeScheduled().keySet(), hasItem(MINGLE_PIPELINE_NAME));
    mingleBuildCause = pipelineScheduleQueue.toBeScheduled().get(MINGLE_PIPELINE_NAME);
    verifyChanged(svn2, mingleBuildCause, false);
    verifyChanged(svn1, mingleBuildCause, true);
  }
 @Test
 public void shouldNotSchedulePipelineIfTheChangesAreIgnored() throws Exception {
   String ignoredFile = "a.doc";
   svnRepository.checkInOneFile(ignoredFile);
   scheduleHelper.autoSchedulePipelinesWithRealMaterials(MINGLE_PIPELINE_NAME);
   assertThat(pipelineScheduleQueue.toBeScheduled().keySet(), not(hasItem(MINGLE_PIPELINE_NAME)));
 }
 @Test
 public void shouldNotSchedulePipelineWithManualFirstStageForAutomaticBuild() throws Exception {
   configHelper.configureStageAsManualApproval(MINGLE_PIPELINE_NAME, STAGE_NAME);
   svnRepository.checkInOneFile("a.java");
   scheduleHelper.autoSchedulePipelinesWithRealMaterials(MINGLE_PIPELINE_NAME);
   assertThat(pipelineScheduleQueue.toBeScheduled().keySet(), not(hasItem(MINGLE_PIPELINE_NAME)));
 }
  // This is bug #2320 - Cruise doing full checkouts most times
  @Test
  public void shouldNotDeleteWorkingDirIfMaterialsAreCheckedOutToSubfoldersWithTheSameRootBug2320()
      throws Exception {
    SvnMaterial svnMaterial1 = repo.createMaterial("multiple-materials/trunk/part1", "root/part1");
    SvnMaterial svnMaterial2 = repo.createMaterial("multiple-materials/trunk/part2", "root/part2");
    Materials materials = new Materials(svnMaterial1, svnMaterial2);

    Revision revision =
        latestRevision(svnMaterial1, pipelineDir, new TestSubprocessExecutionContext());

    updateMaterials(materials, revision);

    assertThat(new File(pipelineDir, "root/part1").exists(), is(true));
    assertThat(new File(pipelineDir, "root/part2").exists(), is(true));

    File testFile = new File(pipelineDir, "root/part1/test-file");
    testFile.createNewFile();
    assertThat(testFile.exists(), is(true));
    // simulates what a build will do
    TestFileUtil.createTestFolder(pipelineDir, ArtifactLogUtil.CRUISE_OUTPUT_FOLDER);
    assertThat(pipelineDir.listFiles().length, is(2));

    updateMaterials(materials, revision);

    assertThat(new File(pipelineDir, "root/part1").exists(), is(true));
    assertThat(new File(pipelineDir, "root/part2").exists(), is(true));

    assertThat("Should not delete the part1 directory", testFile.exists(), is(true));
  }
  @Test
  public void shouldNotDeleteDirectoriesWhenThereIsACruiseOutputDirectory() throws Exception {
    SvnMaterial svnMaterial1 = repo.createMaterial("multiple-materials/trunk/part1", "part1");
    SvnMaterial svnMaterial2 = repo.createMaterial("multiple-materials/trunk/part2", "part2");
    Materials materials = new Materials(svnMaterial1, svnMaterial2);

    Revision revision =
        latestRevision(svnMaterial1, pipelineDir, new TestSubprocessExecutionContext());

    updateMaterials(materials, revision);

    assertThat(new File(pipelineDir, "part1").exists(), is(true));
    assertThat(new File(pipelineDir, "part2").exists(), is(true));

    File testFile = new File(pipelineDir, "part1/test-file");
    testFile.createNewFile();
    assertThat(testFile.exists(), is(true));
    // simulates what a build will do
    TestFileUtil.createTestFolder(pipelineDir, ArtifactLogUtil.CRUISE_OUTPUT_FOLDER);
    assertThat(pipelineDir.listFiles().length, is(3));

    updateMaterials(materials, revision);

    assertThat(new File(pipelineDir, "part1").exists(), is(true));
    assertThat(new File(pipelineDir, "part2").exists(), is(true));

    assertThat("Should not delete the part1 directory", testFile.exists(), is(true));
  }
  @Test
  public void shouldFindModificationForEachMaterial() throws Exception {
    SvnMaterial material1 = repo.createMaterial("multiple-materials/trunk/part1", "part1");
    SvnMaterial material2 = repo.createMaterial("multiple-materials/trunk/part2", "part2");

    Materials materials = new Materials(material1, material2);

    repo.checkInOneFile("filename.txt", material1);
    repo.checkInOneFile("filename2.txt", material2);

    MaterialRevisions materialRevisions =
        materials.latestModification(pipelineDir, new TestSubprocessExecutionContext());

    assertThat(materialRevisions.getRevisions().size(), is(2));
    assertThat(materialRevisions, containsModifiedFile("/trunk/part1/filename.txt"));
    assertThat(materialRevisions, containsModifiedFile("/trunk/part2/filename2.txt"));
  }
  @Before
  public void setup() throws Exception {
    diskSpaceSimulator = new DiskSpaceSimulator();
    new HgTestRepo("testHgRepo");

    svnRepository = new SvnTestRepo("testSvnRepo");

    dbHelper.onSetUp();
    configHelper.onSetUp();
    configHelper.usingCruiseConfigDao(goConfigDao).initializeConfigFile();

    repository = new SvnCommand(null, svnRepository.projectRepositoryUrl());

    goParentPipelineConfig =
        configHelper.addPipeline(
            GO_PIPELINE_UPSTREAM,
            STAGE_NAME,
            new MaterialConfigs(new GitMaterialConfig("foo-bar")),
            "unit");

    goPipelineConfig = configHelper.addPipeline(GO_PIPELINE_NAME, STAGE_NAME, repository, "unit");

    svnMaterialRevs = new MaterialRevisions();
    SvnMaterial svnMaterial = SvnMaterial.createSvnMaterialWithMock(repository);
    svnMaterialRevs.addRevision(
        svnMaterial,
        svnMaterial.latestModification(
            null, new ServerSubprocessExecutionContext(goConfigService, new SystemEnvironment())));

    final MaterialRevisions materialRevisions = new MaterialRevisions();
    SvnMaterial anotherSvnMaterial = SvnMaterial.createSvnMaterialWithMock(repository);
    materialRevisions.addRevision(
        anotherSvnMaterial,
        anotherSvnMaterial.latestModification(null, subprocessExecutionContext));

    transactionTemplate.execute(
        new TransactionCallbackWithoutResult() {
          @Override
          protected void doInTransactionWithoutResult(TransactionStatus status) {
            materialRepository.save(svnMaterialRevs);
          }
        });

    BuildCause buildCause = BuildCause.createWithModifications(svnMaterialRevs, "");

    mingleConfig =
        configHelper.addPipeline(
            MINGLE_PIPELINE_NAME,
            STAGE_NAME,
            repository,
            new Filter(new IgnoredFiles("**/*.doc")),
            "unit",
            "functional");
    latestPipeline = PipelineMother.schedule(this.mingleConfig, buildCause);
    latestPipeline = pipelineDao.saveWithStages(latestPipeline);
    dbHelper.passStage(latestPipeline.getStages().first());
    pipelineScheduleQueue.clear();
  }
  @Test
  public void shouldSchedulePipelineWithManualFirstStageWhenManuallyTriggered() throws Exception {
    configHelper.configureStageAsManualApproval(MINGLE_PIPELINE_NAME, STAGE_NAME);

    svnRepository.checkInOneFile("a.java");
    materialDatabaseUpdater.updateMaterial(svnRepository.material());

    final HashMap<String, String> revisions = new HashMap<String, String>();
    final HashMap<String, String> environmentVariables = new HashMap<String, String>();
    buildCauseProducer.manualProduceBuildCauseAndSave(
        MINGLE_PIPELINE_NAME,
        Username.ANONYMOUS,
        new ScheduleOptions(revisions, environmentVariables, new HashMap<String, String>()),
        new ServerHealthStateOperationResult());

    Map<String, BuildCause> afterLoad = scheduleHelper.waitForAnyScheduled(5);
    assertThat(afterLoad.keySet(), hasItem(MINGLE_PIPELINE_NAME));
    BuildCause cause = afterLoad.get(MINGLE_PIPELINE_NAME);
    assertThat(cause.getBuildCauseMessage(), containsString("Forced by anonymous"));
  }
  @Test
  public void shouldNotThrowNPEIfTheWorkingDirectoryIsEmpty() throws Exception {
    SvnMaterial svnMaterial1 = repo.createMaterial("multiple-materials/trunk/part1", "part1");
    SvnMaterial svnMaterial2 = repo.createMaterial("multiple-materials/trunk/part2", "part2");
    Materials materials = new Materials(svnMaterial1, svnMaterial2);

    Revision revision =
        latestRevision(svnMaterial1, pipelineDir, new TestSubprocessExecutionContext());
    updateMaterials(materials, revision);

    FileUtil.deleteFolder(pipelineDir);

    updateMaterials(materials, revision);
  }
  @Test
  public void shouldClearOutAllDirectoriesIfMaterialsChange() throws Exception {

    SvnMaterial part1 = repo.createMaterial("multiple-materials/trunk/part1", "part1");
    SvnMaterial part2 = repo.createMaterial("multiple-materials/trunk/part2", "part2");
    Materials materials = new Materials(part1, part2);

    Revision revision = latestRevision(part1, pipelineDir, new TestSubprocessExecutionContext());

    updateMaterials(materials, revision);

    assertThat(new File(pipelineDir, "part1").exists(), is(true));
    assertThat(new File(pipelineDir, "part2").exists(), is(true));

    SvnMaterial newFolder = repo.createMaterial("multiple-materials/trunk/part2", "newFolder");

    Materials changedMaterials = new Materials(part1, newFolder);

    updateMaterials(changedMaterials, revision);

    assertThat(new File(pipelineDir, "part1").exists(), is(true));
    assertThat(new File(pipelineDir, "newFolder").exists(), is(true));
  }
  @Test
  public void shouldUpdateMaterialToItsDestFolder() throws Exception {
    SvnMaterial material1 = repo.createMaterial("multiple-materials/trunk/part1", "part1");

    MaterialRevision materialRevision =
        new MaterialRevision(
            material1,
            material1.latestModification(pipelineDir, new TestSubprocessExecutionContext()));
    materialRevision.updateTo(
        pipelineDir,
        ProcessOutputStreamConsumer.inMemoryConsumer(),
        new TestSubprocessExecutionContext());

    assertThat(new File(pipelineDir, "part1").exists(), is(true));
  }
 @Test
 public void should_NOT_schedulePipeline_whenOneOfTheMaterialsHasNoModificationsPresent()
     throws Exception {
   Pipeline latestGoInstance =
       PipelineMother.schedule(
           goPipelineConfig,
           BuildCause.createManualForced(
               svnMaterialRevs, new Username(new CaseInsensitiveString("loser"))));
   latestGoInstance = pipelineDao.saveWithStages(latestGoInstance);
   dbHelper.passStage(latestGoInstance.getStages().first());
   configHelper.addMaterialToPipeline(
       GO_PIPELINE_NAME,
       new DependencyMaterialConfig(
           new CaseInsensitiveString(GO_PIPELINE_UPSTREAM),
           new CaseInsensitiveString(STAGE_NAME)));
   svnRepository.checkInOneFile("a.java");
   scheduleHelper.autoSchedulePipelinesWithRealMaterials(GO_PIPELINE_NAME);
   assertThat(pipelineScheduleQueue.toBeScheduled().keySet(), not(hasItem(GO_PIPELINE_NAME)));
 }
  @Test
  public void shouldNotDeleteWorkingDirIfThereAreNoRequiredFolders() throws Exception {
    SvnMaterial part = repo.createMaterial("multiple-materials/trunk/part1", null);

    Materials materials = new Materials(part);

    Revision revision = latestRevision(part, pipelineDir, new TestSubprocessExecutionContext());
    updateMaterials(materials, revision);

    File shouldNotCleanUp = new File(pipelineDir, "shouldNotDelete");
    shouldNotCleanUp.createNewFile();
    assertThat(shouldNotCleanUp.exists(), is(true));

    updateMaterials(materials, revision);
    assertThat(
        "should not clean up working dir for this pipeline if none of the materials specified a sub folder",
        shouldNotCleanUp.exists(),
        is(true));
  }
  @Test
  public void shouldDetectLatestModifications() throws Exception {

    SvnMaterial svnMaterial1 = repo.createMaterial("multiple-materials/trunk/part1", "part1");
    SvnMaterial svnMaterial2 = repo.createMaterial("multiple-materials/trunk/part2", "part2");
    Materials materials = new Materials(svnMaterial1, svnMaterial2);

    MaterialRevisions materialRevisions =
        materials.latestModification(pipelineDir, new TestSubprocessExecutionContext());

    MaterialRevision revision1 = materialRevisions.getMaterialRevision(0);
    assertThat(
        revision1.getRevision(),
        is(latestRevision(svnMaterial1, pipelineDir, new TestSubprocessExecutionContext())));

    MaterialRevision revision2 = materialRevisions.getMaterialRevision(1);
    assertThat(
        revision2.getRevision(),
        is(latestRevision(svnMaterial2, pipelineDir, new TestSubprocessExecutionContext())));
  }
  @Test
  public void
      shouldUnderstandChangedMaterial_forCompatibleRevisionsBeingSelectedForChangedMaterials_whenTriggeringTheFirstTime()
          throws Exception {
    DependencyMaterialConfig mingleMaterialConfig =
        new DependencyMaterialConfig(
            new CaseInsensitiveString(MINGLE_PIPELINE_NAME), new CaseInsensitiveString(STAGE_NAME));
    String mingleDownstreamPipelineName = "down_of_mingle";
    SvnMaterial svn = SvnMaterial.createSvnMaterialWithMock(repository);

    runAndPassWith(svn, "foo.c", svnRepository);

    svnRepository.checkInOneFile("bar.c");
    materialDatabaseUpdater.updateMaterial(svn);

    configHelper.addPipeline(
        mingleDownstreamPipelineName,
        STAGE_NAME,
        new MaterialConfigs(svn.config(), mingleMaterialConfig),
        "unit");

    pipelineTimeline.update();
    scheduleHelper.autoSchedulePipelinesWithRealMaterials(mingleDownstreamPipelineName);

    assertThat(
        pipelineScheduleQueue.toBeScheduled().keySet(), hasItem(mingleDownstreamPipelineName));
    BuildCause downstreamBuildCause =
        pipelineScheduleQueue.toBeScheduled().get(mingleDownstreamPipelineName);
    for (MaterialRevision materialRevision : downstreamBuildCause.getMaterialRevisions()) {
      assertThat(
          "material revision " + materialRevision + " was marked as not changed",
          materialRevision.isChanged(),
          is(true));
    }
    assertThat(downstreamBuildCause.getMaterialRevisions().getRevisions().size(), is(2));
  }
 private MaterialRevisions checkinFile(
     SvnMaterial svn, String checkinFile, final SvnTestRepo svnRepository) throws Exception {
   svnRepository.checkInOneFile(checkinFile);
   materialDatabaseUpdater.updateMaterial(svn);
   return materialRepository.findLatestModification(svn);
 }
 @After
 public void cleanupRepo() {
   repo.tearDown();
   FileUtil.deleteFolder(pipelineDir);
 }