/******************************************************************************
* Copyright (c) 2000-2019 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
*  Jozsef Gyurusi - initial implementation and initial documentation
*  Adam Delic
*  Antal Wuh.Hen.Chang
*  Attila Balasko
*  Gabor Szalai
*  Istvan Sandor
*  Peter Kremer
*  Zoltan Jasz
******************************************************************************/

module PipeTest {

import from PIPEasp_Types all;
import from PIPEasp_PortType all;
import from PIPEasp_Templates all;

type component PIPE_CT {
  port PIPEasp_PT PIPE_PCO;
  var ASP_PExecute v_ASP_PExecute;
  var ASP_PResult v_ASP_PResult;
  var ASP_PExecuteBinary v_ASP_PExecuteBinary;
  var ASP_PResultBinary v_ASP_PResultBinary;
  var ASP_PExecuteBackground v_ASP_PExecuteBackground;
  var ASP_PStdin v_ASP_PStdin;
  var ASP_PStdout v_ASP_PStdout;
  var ASP_PStderr v_ASP_PStderr;
  var ASP_PStdinBinary v_ASP_PStdinBinary;
  var ASP_PStdoutBinary v_ASP_PStdoutBinary;
  var ASP_PStderrBinary v_ASP_PStderrBinary;
  var ASP_PKill v_ASP_PKill;
  var ASP_PExit v_ASP_PExit;
  var ASP_PLineMode v_ASP_PLineMode;
  var ASP_PError v_ASP_PError;
}

altstep handle_default() runs on PIPE_CT {
    [] PIPE_PCO.receive(t_PError(?)) -> value v_ASP_PError {
      log("Error msg received: ", v_ASP_PError);
      repeat;
    }
    [] PIPE_PCO.receive(t_PExit(?)) -> value v_ASP_PExit {
      if (v_ASP_PExit.code != 0) {
        setverdict(fail);
      }
      repeat;
    }
    [] PIPE_PCO.receive(t_PStdout(?)) -> value v_ASP_PStdout {
      log("Stdout msg received: ", v_ASP_PStdout);
      repeat;
    }
    [] PIPE_PCO.receive(t_PStderr(?)) -> value v_ASP_PStderr {
      log("Stderr msg received: ", v_ASP_PStderr);
      repeat;
    }
    [] PIPE_PCO.receive(t_PResult(?, ?, ?)) -> value v_ASP_PResult {
      log("PResult msg received: ", v_ASP_PResult);
      repeat;
    }
    [] PIPE_PCO.receive(t_PResultBinary(?, ?, ?)) -> value v_ASP_PResultBinary {
      log("PResultBinary msg received: ", v_ASP_PResultBinary);
      repeat;
    }
}

testcase TC_basic() runs on PIPE_CT {
  map(self:PIPE_PCO, system:PIPE_PCO);

  var default default_as := activate(handle_default());
  timer t_guard;
  
  PIPE_PCO.send(t_PKill(-10)); // will result in: PError: No process executing
  PIPE_PCO.send(t_PLineMode(false));
  PIPE_PCO.send(t_PLineMode(true));

  // wait for response
  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }

/*// These cannot be sent:
  log("Sending forbidden messages...");
  PIPE_PCO.send(t_PResult("Dummy stdout", "Dummy stderr", 123));
  PIPE_PCO.send(t_PResultBinary('1234'O, 'ABCD'O, 123));
  PIPE_PCO.send(t_PStdout("Dummy stdout"));
  PIPE_PCO.send(t_PStderr("Dummy stderr"));
  PIPE_PCO.send(t_PStdoutBinary('ABCDEF'O));
  PIPE_PCO.send(t_PStderrBinary('12345678'O));
  PIPE_PCO.send(t_PError("Dummy error"));
  PIPE_PCO.send(t_PExit(123));
  log("Forbidden messages sent.");
  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }
*/  

  // no such file, ExitCode: 512:
  PIPE_PCO.send(t_PExecuteBackground("neditxxx"));
  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }
  // OK, but Exitcode is 256
  PIPE_PCO.send(t_PExecuteBackground("nedit -v"));
  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }

  // Will exit if not closed manually within 5 sec
  PIPE_PCO.send(t_PExecuteBackground("nedit xxx"));
  PIPE_PCO.send(t_PStdinBinary('ABCD'O));
  PIPE_PCO.send(t_PStdin("abcd"));

  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }

  // Kill nedit if not closed, otherwise: No process executing is received
  PIPE_PCO.send(t_PKill(9));
  
  // If nedit is killed: exitcode: 9, otherwise: 0
  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }

  // start shell and execute commands:
  PIPE_PCO.send(t_PExecuteBackground("tcsh"));
  PIPE_PCO.send(t_PStdin("ls"));
  PIPE_PCO.send(t_PStdinBinary('ABCD'O));
  PIPE_PCO.send(t_PStdin("abcd"));
  
  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }

  // execute more commands, then exit the shell, exitcode: 0
  PIPE_PCO.send(t_PStdin("ls -ltr"));
  PIPE_PCO.send(t_PStdin("exit"));

  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }

  // other way to execute shell commands, exitcodes: 0
  PIPE_PCO.send(t_PExecute("tcsh", "ls a*;exit"));
  // this should return PError: command already executing:
  PIPE_PCO.send(t_PExecute("echo XXX", ""));
  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }

  // start nedit, should be stopped manually
  // execution stops here until nedit exits with 0
  PIPE_PCO.send(t_PExecute("nedit yyy_PLEASE_CLOSE_MANUALLY", "abcd"));
  PIPE_PCO.send(t_PStdin("ls -ltr")); // should get a PError for this

  // exit code 0
  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }

  // same, but with binary data
  PIPE_PCO.send(t_PExecuteBinary("nedit zzz", 'abcd'O));

  t_guard.start(5.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, continue...");
    }
  }
  // This should kill the nedit process.
  PIPE_PCO.send(t_PKill(9));

  // wait 10 sec then exit the testcase
  t_guard.start(10.0);
  alt {
    [] t_guard.timeout {
      log("Timer expired, exiting...");
    }
  }
  setverdict(pass);
}

testcase TC_executeSomeUnixCommands() runs on PIPE_CT {
  map(self:PIPE_PCO, system:PIPE_PCO);

  PIPE_PCO.send(t_PLineMode(false));
  PIPE_PCO.send(t_PExecute("echo shaap", ""));
  PIPE_PCO.receive(t_PResult(?,?,?));
  PIPE_PCO.send(t_PLineMode(true));

  PIPE_PCO.send(t_PExecute("/bin/ls -l PipeTest.ttcn", ""));
  PIPE_PCO.receive(t_PResult(?,?,?));

  PIPE_PCO.send(t_PExecuteBinary("echo foo", ''O));
  PIPE_PCO.receive(t_PResultBinary(?,?,?));
  PIPE_PCO.send(t_PKill(9));
  PIPE_PCO.receive(t_PError(?));

  PIPE_PCO.send(t_PExecuteBackground("tcsh"));
  PIPE_PCO.send(t_PStdin("barf"));
  PIPE_PCO.receive(t_PStderr(?));
  PIPE_PCO.send(t_PStdin("echo 1; echo 2"));
  PIPE_PCO.receive(t_PStdout(?));
  PIPE_PCO.receive(t_PStdout(?));
  PIPE_PCO.send(t_PStdin("echo going...; kill -9 $$"));
  PIPE_PCO.receive(t_PStdout(?));
  PIPE_PCO.receive(t_PExit(?));

  setverdict(pass);
}

function WindowNotice(in charstring pl_notice) runs on PIPE_CT {

  var charstring v_WindowCommand := "";
  PIPE_PCO.send(t_PExecute("sh", "echo $ShellTestDir/ShellNotice.sh; exit"));
  alt {
    [] PIPE_PCO.receive(t_PResult(?,?,0)) -> value v_ASP_PResult {
      v_WindowCommand := v_ASP_PResult.stdout;

      PIPE_PCO.send(t_PExecute(v_WindowCommand, pl_notice));
      alt {
        [] PIPE_PCO.receive(t_PResult("",?,0)) -> value v_ASP_PResult {
        }
        [] PIPE_PCO.receive {
          setverdict(fail);
        }
      }
    }
    [] PIPE_PCO.receive {
      setverdict(fail);
    }
  }
}

function WindowQuestionString(
  in charstring pl_question,
  out charstring pl_answer) runs on PIPE_CT {

  var charstring v_WindowCommand := "";
  PIPE_PCO.send(t_PExecute("sh", "echo $ShellTestDir/ShellQuestionString.sh; exit"));
  alt {
    [] PIPE_PCO.receive(t_PResult(?,?,0)) -> value v_ASP_PResult {
      v_WindowCommand := v_ASP_PResult.stdout;

      PIPE_PCO.send(t_PExecute(v_WindowCommand, pl_question));
      alt {
        [] PIPE_PCO.receive(t_PResult(?,?,0)) -> value v_ASP_PResult {
          pl_answer := v_ASP_PResult.stdout;
        }
        [] PIPE_PCO.receive {
          setverdict(fail);
        }
      }
    }
    [] PIPE_PCO.receive {
      setverdict(fail);
    }
  }
}

function WindowQuestionYesNo(
  in charstring pl_question,
  out boolean pl_answer) runs on PIPE_CT {

  var charstring v_WindowCommand := "";
  PIPE_PCO.send(t_PExecute("sh", "echo $ShellTestDir/ShellQuestionYesNo.sh; exit"));
  alt {
    [] PIPE_PCO.receive(t_PResult(?,?,0)) -> value v_ASP_PResult {
      v_WindowCommand := v_ASP_PResult.stdout;

      PIPE_PCO.send(t_PExecute(v_WindowCommand, pl_question));
      alt {
        [] PIPE_PCO.receive(t_PResult("Yes",?,0)) -> value v_ASP_PResult {
          pl_answer := true;
        }
        [] PIPE_PCO.receive(t_PResult("No",?,0)) -> value v_ASP_PResult {
          pl_answer := false;
        }
        [] PIPE_PCO.receive {
          setverdict(fail);
        }
      }
    }
    [] PIPE_PCO.receive {
      setverdict(fail);
    }
  }
}

testcase TC_TrySomeWindows() runs on PIPE_CT {
  map(self:PIPE_PCO, system:PIPE_PCO);

  var charstring v_answerS := "";
  var boolean v_answerB := false;
  label L;
  WindowNotice("This is the first notice!");
  WindowQuestionString("This is the first question", v_answerS);
  log("Answer is: ", v_answerS);

  WindowQuestionYesNo("Shall we repeat this again?", v_answerB);
  log("Continue? :", v_answerB);
  if (v_answerB) {
    goto L;
  }
  setverdict(pass);
}

testcase TC_simple() runs on PIPE_CT {
  map(self:PIPE_PCO, system:PIPE_PCO);

  PIPE_PCO.send(t_PExecute("/bin/ls -l PipeTest.ttcn", ""));
  PIPE_PCO.receive(t_PResult(?,?,?));

  unmap(self:PIPE_PCO, system:PIPE_PCO);

  setverdict(pass);
}

testcase TC_unmap() runs on PIPE_CT {
  map(self:PIPE_PCO, system:PIPE_PCO);

  PIPE_PCO.send(t_PExecute("xclock", ""));
  //timer t := 1.0; t.start; t.timeout;

  unmap(self:PIPE_PCO, system:PIPE_PCO);

  map(self:PIPE_PCO, system:PIPE_PCO);

  PIPE_PCO.send(t_PExecute("ksh", "pwd;exit"));
  PIPE_PCO.receive(t_PResult(?,?,?));

  unmap(self:PIPE_PCO, system:PIPE_PCO);

  setverdict(pass);
}

}
