package net.raymanoz.migrate;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import net.raymanoz.config.ConditionDecoder;
import net.raymanoz.config.ConditionResult;
import net.raymanoz.config.ConfigurationImpl;
import net.raymanoz.config.ScriptStatus;
import net.raymanoz.io.File;
import net.raymanoz.ui.UserInteractionStrategy;
import net.raymanoz.util.FileUtil;
import net.raymanoz.util.InputStreamPrinter;
import net.raymanoz.util.Properties;
import net.raymanoz.util.ScriptExecuterCommandLineParser;
import org.junit.Test;
import org.junit.Before;
import org.mockito.InOrder;
public class ScriptImplTest {
private static final int EXIT_FAIL = 1;
private static final int EXIT_OK = 0;
private static final String COMMAND = "run this Command d";
private static final String ABSOLUTE_PATH = "this is an Absolute Path";
private static final String MOCK_CONDITION_STATUS = "mock condition Statuses";
final private ByteArrayInputStream errorStream = new ByteArrayInputStream("standard error".getBytes());
final private ByteArrayInputStream inputStream = new ByteArrayInputStream("standard out".getBytes());
final private Process mockProcess = mock(Process.class);
final private ScriptProcessBuilder mockProcessBuilder = mock(ScriptProcessBuilder.class);
final private InputStreamPrinter mockInputStreamPrinter = mock(InputStreamPrinter.class);
final private InputStreamPrinter mockErrorStreamPrinter = mock(InputStreamPrinter.class);
final private UserInteractionStrategy userInteractionStrategy = mock(UserInteractionStrategy.class);
final private ScriptExecuterCommandLineParser parser = mock(ScriptExecuterCommandLineParser.class);
final private Properties properties = mock(Properties.class);
final private ConditionDecoder mockConditionDecoder = mock(ConditionDecoder.class);
final private FileUtil mockFileUtil = mock(FileUtil.class);
final private ConfigurationImpl mockConfiguration = mock(ConfigurationImpl.class);
final private File mockScriptFile = mock(File.class);
final private File mockExecuteDir = mock(File.class);
final private File mockExecFile = mock(File.class);
private final ScriptAssembler mockScriptAssembler = mock(ScriptAssembler.class);
@Before
public void setup(){
when(mockScriptAssembler.newProcessBuilder()).thenReturn(mockProcessBuilder);
when(mockScriptAssembler.newInputStreamPrinter(inputStream, System.out, userInteractionStrategy)).thenReturn(mockInputStreamPrinter);
when(mockScriptAssembler.newInputStreamPrinter(errorStream, System.err, userInteractionStrategy)).thenReturn(mockErrorStreamPrinter);
when(mockScriptAssembler.getProperties()).thenReturn(properties);
when(mockScriptAssembler.getConfiguration()).thenReturn(mockConfiguration);
when(mockScriptAssembler.getConditionDecoder()).thenReturn(mockConditionDecoder);
when(mockScriptAssembler.getFileUtil()).thenReturn(mockFileUtil);
when(mockScriptAssembler.newFile(eq(mockExecuteDir), anyString())).thenReturn(mockExecFile);
when(mockScriptAssembler.getScriptExecuterCommandLineParser()).thenReturn(parser);
when(mockConfiguration.getExecuteDirectory()).thenReturn(mockExecuteDir);
when(mockConfiguration.getExecuteDirectory()).thenReturn(mockExecuteDir);
when(mockConfiguration.getExecutionCommand()).thenReturn(COMMAND + " ${script}");
when(mockExecFile.getAbsolutePath()).thenReturn(ABSOLUTE_PATH);
when(mockConditionDecoder.conditionStatuses()).thenReturn(MOCK_CONDITION_STATUS);
when(mockConditionDecoder.ShouldRunScript()).thenReturn(ConditionResult.RUN_SCRIPT);
when(mockProcess.getErrorStream()).thenReturn(errorStream);
when(mockProcess.getInputStream()).thenReturn(inputStream);
when(mockProcess.exitValue()).thenReturn(EXIT_OK);
when(mockProcessBuilder.start()).thenReturn(mockProcess);
when(mockProcessBuilder.start()).thenReturn(mockProcess);
}
private File mockFile(String fileName) {
final File mockFile = mock(File.class);
when(mockFile.getName()).thenReturn(fileName);
return mockFile;
}
private ScriptImpl scriptImpl(String fileName){
when(mockScriptFile.getName()).thenReturn(fileName);
ScriptImpl script = new ScriptImpl(mockScriptFile, mockScriptAssembler);
return script;
}
private void assertFileNumber(String fileName, long expectedNumber) {
ScriptImpl script = scriptImpl(fileName);
assertEquals("script file number should be " + expectedNumber, expectedNumber, script.getPatch());
}
@Test
public void scriptFileShouldReportCorrectNumber() {
assertFileNumber("4_test.sql", 4);
assertFileNumber("12_test.sql", 12);
assertFileNumber("00105_test.sql", 105);
}
@Test
public void scriptShouldReturnFileName() {
ScriptImpl script = scriptImpl("1_script.sql");
assertEquals("Script returned incorrect filename", "1_script.sql", script.getFileName());
}
@Test(expected=IllegalArgumentException.class)
public void scriptFileShouldThrowExceptionWhenCreatedWithInvalidFile() {
new ScriptImpl(mockFile("test.sql"), mock(ScriptAssembler.class));
}
@Test(expected=IllegalArgumentException.class)
public void scriptFileShouldThrowExceptionEvenWhenNumberInMiddleOfFileName() {
new ScriptImpl(mockFile("te_23_st.sql"), mock(ScriptAssembler.class));
}
@Test
public void isScriptFileShouldReturnTrue() {
assertTrue("should be true", ScriptImpl.isScriptFile(mockFile("3_test.sql")));
}
@Test
public void isScriptFileShouldReturnFalse() {
assertFalse("should be false", ScriptImpl.isScriptFile(mockFile("gar.sql")));
}
private void verifyCreateExecuteFile(String fileName){
InOrder inOrder = inOrder(mockScriptAssembler, mockFileUtil);
inOrder.verify(mockScriptAssembler).newFile(mockExecuteDir, fileName);
inOrder.verify(mockFileUtil).copyFile(mockScriptFile, mockExecFile, properties);
}
@Test
public void createExecuteFile(){
final String filename ="23_a_file.sql";
ScriptImpl script = scriptImpl(filename);
assertEquals(mockExecFile, script.createExecuteFile(mockConfiguration));
verifyCreateExecuteFile(filename);
}
private void verifyAssignStandardOutputs(InOrder inOrder){
inOrder.verify(mockScriptAssembler).newInputStreamPrinter(inputStream, System.out, userInteractionStrategy);
inOrder.verify(mockInputStreamPrinter).print();
inOrder.verify(mockScriptAssembler).newInputStreamPrinter(errorStream, System.err, userInteractionStrategy);
inOrder.verify(mockErrorStreamPrinter).print();
}
@Test
public void assignStandardOutputs(){
ScriptImpl script = scriptImpl("1_w.sql");
script.assignStandardOutputs(mockProcess, userInteractionStrategy);
verifyAssignStandardOutputs(inOrder(mockScriptAssembler, mockErrorStreamPrinter, mockInputStreamPrinter));
}
private void verifyExecuteScript(final String[] args, InOrder inOrder){
inOrder.verify(mockProcessBuilder).command(args);
inOrder.verify(mockProcessBuilder).start();
verifyAssignStandardOutputs(inOrder);
}
@Test
public void executeScript(){
final String[] args = new String[]{"one", "Two", "Three"};
when(parser.processBuilderArgs(mockExecFile)).thenReturn(args);
ScriptImpl script = scriptImpl("1_w.sql");
script.executeScript(mockExecFile, userInteractionStrategy);
InOrder inOrder = inOrder(mockProcessBuilder, mockScriptAssembler, mockErrorStreamPrinter, mockInputStreamPrinter);
verifyExecuteScript(args, inOrder);
}
private void doExecuteScript(String scriptName, int exitValue, ConditionResult conditionResult, ScriptStatus scriptStatus, String conditionStatus){
when(mockConditionDecoder.ShouldRunScript()).thenReturn(conditionResult);
when(mockProcess.exitValue()).thenReturn(exitValue);
ScriptImpl script = scriptImpl(scriptName);
assertEquals("Check condtion Status before execute", "Not Checked", script.condtionStatus());
assertEquals("Should be able to execute a script", scriptStatus, script.execute(userInteractionStrategy));
assertEquals("Check condtion Status after execute", conditionStatus, script.condtionStatus());
}
private void doExecuteScript(ConditionResult conditionResult, ScriptStatus scriptStatus, String conditionStatus){
doExecuteScript("1_script.sql", 0, conditionResult, scriptStatus, conditionStatus);
}
@Test
public void scriptExecuteShouldReturnHalted() throws IOException, InterruptedException {
doExecuteScript(ConditionResult.HALT, ScriptStatus.HALTED, MOCK_CONDITION_STATUS);
verify(mockProcessBuilder, never()).start();
verify(mockProcess, never()).waitFor();
}
@Test
public void scriptExecuteShouldReturnSkipped() throws IOException, InterruptedException {
doExecuteScript(ConditionResult.SKIP_SCRIPT, ScriptStatus.SKIPPED, MOCK_CONDITION_STATUS);
verify(mockProcessBuilder, never()).start();
verify(mockProcess, never()).waitFor();
}
@Test
public void scriptExecuteHandlesCondtionException() throws InterruptedException {
final String execptionMessage = "need action and command";
when(mockConditionDecoder.conditionStatuses()).thenReturn(MOCK_CONDITION_STATUS);
when(mockConditionDecoder.ShouldRunScript()).thenThrow(new IllegalArgumentException(execptionMessage));
ScriptImpl script = scriptImpl("1_script.sql");
assertEquals(ScriptStatus.ERRORED, script.execute(userInteractionStrategy));
assertEquals("Exception in Condition Handler should return Errored", ScriptStatus.ERRORED, script.execute(userInteractionStrategy));
assertEquals("Exception in Condition Handler should return message in conditionstaut",
"java.lang.IllegalArgumentException: " + execptionMessage, script.condtionStatus());
verify(mockProcessBuilder, never()).start();
verify(mockProcess, never()).waitFor();
}
@Test
public void scriptExecuteShouldReturnCompleted() throws IOException, InterruptedException {
final String scriptName = "32_script.sql";
final String[] args = new String[]{"one", "Two", "Three"};
when(parser.processBuilderArgs(mockExecFile)).thenReturn(args);
doExecuteScript(scriptName, EXIT_OK, ConditionResult.RUN_SCRIPT, ScriptStatus.COMPLETED, MOCK_CONDITION_STATUS);
verifyCreateExecuteFile(scriptName);
InOrder inOrder = inOrder(mockProcessBuilder, mockScriptAssembler, mockErrorStreamPrinter, mockInputStreamPrinter, mockProcess);
verifyExecuteScript(args, inOrder);
inOrder.verify(mockProcess).waitFor();
inOrder.verify(mockProcess).exitValue();
}
@Test
public void scriptExecuteShouldReturnErroredOnNonZeroProcessExitValue() throws IOException, InterruptedException {
final String scriptName = "32_script.sql";
final String[] args = new String[]{"one", "Two", "Three"};
when(parser.processBuilderArgs(mockExecFile)).thenReturn(args);
doExecuteScript(scriptName, EXIT_FAIL, ConditionResult.RUN_SCRIPT, ScriptStatus.ERRORED, MOCK_CONDITION_STATUS);
verifyCreateExecuteFile(scriptName);
InOrder inOrder = inOrder(mockProcessBuilder, mockScriptAssembler, mockErrorStreamPrinter, mockInputStreamPrinter, mockProcess);
verifyExecuteScript(args, inOrder);
inOrder.verify(mockProcess).waitFor();
inOrder.verify(mockProcess).exitValue();
}
@Test
public void scriptExecuteHandlesInterruptedException() throws InterruptedException {
when(mockConditionDecoder.conditionStatuses()).thenReturn("mock condition Statuses");
when(mockConditionDecoder.ShouldRunScript()).thenReturn(ConditionResult.RUN_SCRIPT);
ScriptImpl script = scriptImpl("1_script.sql");
when(mockProcess.waitFor()).thenThrow(new InterruptedException());
assertEquals("Interrupted process should cause script execute to return ERRORED", ScriptStatus.ERRORED, script.execute(userInteractionStrategy));
}
}