/*
 * Copyright (C) 2016 AXON IVY AG
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ch.ivyteam.ivy.maven;

import static org.fest.assertions.api.Assertions.assertThat;
import static org.fest.assertions.api.Assertions.failBecauseExceptionWasNotThrown;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.junit.Rule;
import org.junit.Test;

import ch.ivyteam.ivy.maven.engine.deploy.DeploymentMarkerFiles;

public class TestIarDeployMojo
{
  @Test
  public void deployPackedIar() throws Exception
  {
    IarDeployMojo mojo = rule.getMojo();
    mojo.deployEngineDirectory = createEngineDir();
    File iar = mojo.deployIarFile;
    assertThat(iar).isNotNull();

    iar.createNewFile();
    File deployedIar = getTarget(iar, mojo);
    File deployMarkerFile = new DeploymentMarkerFiles(deployedIar).doDeploy();
    assertThat(deployedIar).doesNotExist();
    assertThat(deployMarkerFile).doesNotExist();
    
    DelayedOperation mockEngineDeployThread = new DelayedOperation(500, TimeUnit.MILLISECONDS);
    Callable<Void> engineOperation = () -> {
      assertThat(deployMarkerFile).as("deployment must be initialized").exists();
      deployMarkerFile.delete(); //deployment finished
      return null;
    };
    mockEngineDeployThread.execute(engineOperation);
    mojo.execute();
    mockEngineDeployThread.failOnExecption();
    
    assertThat(deployedIar)
      .as("IAR must exist in engine deploy directory")
      .exists();
  }
  
  @Test
  public void failOnEngineDeployError() throws Exception
  {
    IarDeployMojo mojo = rule.getMojo();
    mojo.deployEngineDirectory = createEngineDir();
    mojo.deployIarFile.createNewFile();
    DeploymentMarkerFiles markers = new DeploymentMarkerFiles(getTarget(mojo.deployIarFile, mojo));
    
    DelayedOperation mockEngineDeployThread = new DelayedOperation(500, TimeUnit.MILLISECONDS);
    Callable<Void> engineOperation = () -> {
      assertThat(markers.doDeploy()).as("deployment must be initialized").exists();
      FileUtils.write(markers.errorLog(), "validation errors");
      markers.doDeploy().delete(); //deployment finished
      return null;
    };
    
    mockEngineDeployThread.execute(engineOperation);
    try
    {
      mojo.execute();
      failBecauseExceptionWasNotThrown(MojoExecutionException.class);
    }
    catch (MojoExecutionException ex)
    {
      assertThat(ex).hasMessageContaining("failed!");
    }
    finally
    {
      mockEngineDeployThread.failOnExecption();
    }
  }

  private static File getTarget(File iar, IarDeployMojo mojo)
  {
    File deploy = new File(mojo.deployEngineDirectory, mojo.deployDirectory);
    File app = new File(deploy, mojo.deployToEngineApplication);
    File deployedIar = new File(app, iar.getName());
    return deployedIar;
  }
  
  private static File createEngineDir() throws IOException
  {
    File engine = Files.createTempDirectory("myIvyEngine").toFile();
    File deploy = new File(engine, "deploy");
    deploy.mkdir();
    return engine;
  }

  @Rule
  public ProjectMojoRule<IarDeployMojo> rule = new ProjectMojoRule<IarDeployMojo>(
          new File("src/test/resources/base"), IarDeployMojo.GOAL);

  private static class DelayedOperation
  {
    private final long delayMillis;
    private Exception ex;
    private Thread thread;
  
    public DelayedOperation(long delay, TimeUnit unit)
    {
      delayMillis = unit.toMillis(delay);
    }
    
    public void execute(Callable<Void> delayedFunction)
    {
      thread = new Thread(){
        @Override
        public void run()
        {
          try
          {
            Thread.sleep(delayMillis);
            delayedFunction.call();
          }
          catch (Exception functionEx)
          {
            DelayedOperation.this.ex = functionEx;
          }
        }
      };
      thread.start();
    }
  
    public void failOnExecption() throws Exception
    {
      assertThat(thread).as("Delayed operation thread has never been started.").isNotNull();
      while(thread.isAlive())
      {
        Thread.sleep(10); // wait for result
      }
      if (ex != null)
      {
        throw ex;
      }
    }
  }

}

@@ -790,64 +790,8 @@
 le;%0A
-import java.io.IOException;%0Aimport java.nio.file.Files;%0A
 impo
@@ -1210,60 +1210,8 @@
 ();%0A
-    mojo.deployEngineDirectory = createEngineDir();%0A
     
@@ -2171,60 +2171,8 @@
 ();%0A
-    mojo.deployEngineDirectory = createEngineDir();%0A
     
@@ -3329,74 +3329,372 @@
   %7D%0A
+%0A
   
-%0A  private static File createEngineDir() throws IOException%0A
+@Rule%0A  public ProjectMojoRule%3CIarDeployMojo%3E rule = new ProjectMojoRule%3CIarDeployMojo%3E(%0A          new File(%22src/test/resources/base%22), IarDeployMojo.GOAL)%0A  %7B%0A    @Override%0A    protected void before() throws Throwable %0A    %7B%0A      super.before();%0A      getMojo().deployEngineDirectory = createEngineDir();%0A    %7D%0A    %0A    private File createEngineDir()%0A  
   %7B%0A
+  
     
@@ -3710,60 +3710,47 @@
 ne =
+ new
  File
-s.createTempDirectory(%22myIvyEngine%22).toFile();%0A
+(%22target/myTestIvyEngine%22);%0A  
     
@@ -3791,24 +3791,26 @@
 ploy%22);%0A    
+  
 deploy.mkdir
@@ -3809,24 +3809,25 @@
 oy.mkdir
+s
 ();%0A    
 return e
@@ -3814,24 +3814,26 @@
 dirs();%0A    
+  
 return engin
@@ -3841,168 +3841,158 @@
 ;%0A  
+  
 %7D%0A
-%0A  @Rule%0A  public ProjectMojoRule%3CIarDeployMojo%3E rule = new ProjectMojoRule%3CIarDeployMojo%3E(
+    %0A    @Override%0A    protected void after()
 %0A    
+%7B%0A
       
-new File(%22src/test/resources/base%22), IarDeployMojo.GOAL)
+super.after();%0A      FileUtils.deleteQuietly(getMojo().deployEngineDirectory);%0A    %7D%0A  %7D
 ;%0A%0A 

fix failing tests