1
0
Fork 0

wrote tests for shell return codes

This commit is contained in:
Jan Steemann 2016-11-21 11:33:38 +01:00
parent 38e18a9e65
commit 0ff5e4c07c
13 changed files with 140 additions and 84 deletions

View File

@ -61,9 +61,10 @@ void linenoiseHistoryFree(void);
void linenoiseClearScreen(void);
void linenoiseSetMultiLine(int ml);
void linenoisePrintKeyCodes(void);
/* the following is extension to the original linenoise API */
/* the following are extensions to the original linenoise API */
int linenoiseInstallWindowChangeHandler(void);
int linenoiseGotKey(void);
/* returns type of key pressed: 1 = CTRL-C, 2 = CTRL-D, 0 = other */
int linenoiseKeyType(void);
#ifdef __cplusplus
}

View File

@ -2490,10 +2490,10 @@ static bool isCharacterAlphanumeric(char32_t testChar) {
#ifndef _WIN32
static bool gotResize = false;
#endif
static int gotKey = 0;
static int keyType = 0;
int InputBuffer::getInputLine(PromptBase& pi) {
gotKey = 0;
keyType = 0;
// The latest history entry is always our current buffer
if (len > 0) {
@ -2537,9 +2537,14 @@ int InputBuffer::getInputLine(PromptBase& pi) {
if (terminatingKeystroke == -1) {
c = linenoiseReadChar(); // get a new keystroke
if (c != 0 && (c != ctrlChar('C'))) {
keyType = 0;
if (c != 0) {
// set flag that we got some input
gotKey = 1;
if (c == ctrlChar('C')) {
keyType = 1;
} else if (c == ctrlChar('D')) {
keyType = 2;
}
}
#ifndef _WIN32
@ -3429,6 +3434,6 @@ int linenoiseInstallWindowChangeHandler(void) {
return 0;
}
int linenoiseGotKey(void) {
return gotKey;
int linenoiseKeyType(void) {
return keyType;
}

View File

@ -167,7 +167,7 @@ start_pretty_print();
}
std::string input;
bool eof;
ShellBase::EofType eof;
isolate->CancelTerminateExecution();
@ -176,7 +176,7 @@ start_pretty_print();
input = console.prompt("arangod> ", "arangod", eof);
}
if (eof) {
if (eof == ShellBase::EOF_FORCE_ABORT) {
_userAborted.store(true);
}

View File

@ -681,10 +681,10 @@ static void JS_Debug(v8::FunctionCallbackInfo<v8::Value> const& args) {
if (console != nullptr) {
while (true) {
bool eof;
ShellBase::EofType eof;
std::string input = console->prompt("debug> ", "debug", eof);
if (eof) {
if (eof == ShellBase::EOF_FORCE_ABORT) {
break;
}

View File

@ -362,7 +362,6 @@ void ConsoleFeature::printWelcomeInfo() {
void ConsoleFeature::printByeBye() {
if (!_quiet) {
printLine("<ctrl-D>");
printLine(TRI_BYE_MESSAGE);
}
}

View File

@ -338,11 +338,11 @@ int V8ShellFeature::runShell(std::vector<std::string> const& positionals) {
_console->setPromptError(promptError);
auto prompt = _console->buildPrompt(client);
bool eof;
ShellBase::EofType eof = ShellBase::EOF_NONE;
std::string input =
v8LineEditor.prompt(prompt._colored, prompt._plain, eof);
if (eof && lastEmpty) {
if (eof == ShellBase::EOF_FORCE_ABORT || (eof == ShellBase::EOF_ABORT && lastEmpty)) {
break;
}

View File

@ -2038,69 +2038,111 @@ testFuncs.fail = function (options) {
// //////////////////////////////////////////////////////////////////////////////
testFuncs.arangosh = function (options) {
let ret = {
'testArangoshExitCodeFail': {
status: true,
total: 0
},
'testArangoshExitCodeSuccess': {
status: true,
total: 0
},
'testArangoshShebang': {
status: true,
total: 0
let ret = {};
[
'testArangoshExitCodeNoConnect',
'testArangoshExitCodeFail',
'testArangoshExitCodeFailButCaught',
'testArangoshExitCodeEmpty',
'testArangoshExitCodeSuccess',
'testArangoshExitCodeStatements',
'testArangoshExitCodeStatements2',
'testArangoshExitCodeNewlines',
'testArangoshExitCodeEcho',
'testArangoshShebang',
].forEach(function(what) {
ret[what] = { status: true, total: 0 };
});
function runTest(section, title, command, expectedReturnCode, opts) {
print('--------------------------------------------------------------------------------');
print(title);
print('--------------------------------------------------------------------------------');
let args = makeArgsArangosh(options);
args['javascript.execute-string'] = command;
args['log.level'] = 'error';
for (let op in opts) {
args[op] = opts[op];
}
};
print('--------------------------------------------------------------------------------');
print('Starting arangosh with exception throwing script:');
print('--------------------------------------------------------------------------------');
const startTime = time();
print(args);
let rc = executeExternalAndWait(ARANGOSH_BIN, toArgv(args));
const deltaTime = time() - startTime;
const failSuccess = (rc.hasOwnProperty('exit') && rc.exit === expectedReturnCode);
let args = makeArgsArangosh(options);
args['javascript.execute-string'] = "throw('foo')";
args['log.level'] = 'error';
const startTime = time();
let rc = executeExternalAndWait(ARANGOSH_BIN, toArgv(args));
const deltaTime = time() - startTime;
const failSuccess = (rc.hasOwnProperty('exit') && rc.exit === 1);
if (!failSuccess) {
ret.testArangoshExitCodeFail['message'] =
"didn't get expected return code (1): \n" +
yaml.safeDump(rc);
if (!failSuccess) {
ret[section]['message'] =
"didn't get expected return code (" + expectedReturnCode + "): \n" +
yaml.safeDump(rc);
}
++ret[section]['total'];
ret[section]['status'] = failSuccess;
ret[section]['duration'] = deltaTime;
print((failSuccess ? GREEN : RED) + 'Status: ' + (failSuccess ? 'SUCCESS' : 'FAIL') + RESET);
}
runTest('testArangoshExitCodeNoConnect', 'Starting arangosh with failing connect:', "db._databases();", 1, { 'server.endpoint' : 'tcp://127.0.0.1:0' });
print();
++ret.testArangoshExitCodeFail['total'];
ret.testArangoshExitCodeFail['status'] = failSuccess;
ret.testArangoshExitCodeFail['duration'] = deltaTime;
print((failSuccess ? GREEN : RED) + 'Status: ' + (failSuccess ? 'SUCCESS' : 'FAIL') + RESET);
runTest('testArangoshExitCodeFail', 'Starting arangosh with exception throwing script:', "throw('foo')", 1, {});
print();
runTest('testArangoshExitCodeFailButCaught', 'Starting arangosh with a caught exception:', "try { throw('foo'); } catch (err) {}", 0, {});
print();
runTest('testArangoshExitCodeEmpty', 'Starting arangosh with empty script:', "", 0, {});
print();
runTest('testArangoshExitCodeSuccess', 'Starting arangosh with regular terminating script:', ";", 0, {});
print();
runTest('testArangoshExitCodeStatements', 'Starting arangosh with multiple statements:', "var a = 1; if (a !== 1) throw('boom!');", 0, {});
print();
runTest('testArangoshExitCodeStatements2', 'Starting arangosh with multiple statements:', "var a = 1;\nif (a !== 1) throw('boom!');\nif (a === 1) print('success');", 0, {});
print();
runTest('testArangoshExitCodeNewlines', 'Starting arangosh with newlines:', "q = `FOR i\nIN [1,2,3]\nRETURN i`;\nq += 'abc'\n", 0, {});
print();
if (platform.substr(0, 3) !== 'win') {
var echoSuccess = true;
var deltaTime2 = 0;
var execFile = fs.getTempFile();
print('\n--------------------------------------------------------------------------------');
print('Starting arangosh with regular terminating script:');
print('--------------------------------------------------------------------------------');
print('\n--------------------------------------------------------------------------------');
print('Starting arangosh via echo');
print('--------------------------------------------------------------------------------');
fs.write(execFile,
'echo "db._databases();" | ' + fs.makeAbsolute(ARANGOSH_BIN) + ' --server.endpoint tcp://127.0.0.1:0');
args['javascript.execute-string'] = ';';
args['log.level'] = 'warning';
executeExternalAndWait('sh', ['-c', 'chmod a+x ' + execFile]);
const startTime2 = time();
rc = executeExternalAndWait(ARANGOSH_BIN, toArgv(args));
const deltaTime2 = time() - startTime2;
const startTime2 = time();
let rc = executeExternalAndWait('sh', ['-c', execFile]);
deltaTime2 = time() - startTime2;
const successSuccess = (rc.hasOwnProperty('exit') && rc.exit === 0);
echoSuccess = (rc.hasOwnProperty('exit') && rc.exit === 1);
if (!successSuccess) {
ret.testArangoshExitCodeFail['message'] =
"didn't get expected return code (0): \n" +
yaml.safeDump(rc);
if (!echoSuccess) {
ret.testArangoshExitCodeEcho['message'] =
"didn't get expected return code (1): \n" +
yaml.safeDump(rc);
}
fs.remove(execFile);
++ret.testArangoshExitCodeEcho['total'];
ret.testArangoshExitCodeEcho['status'] = echoSuccess;
ret.testArangoshExitCodeEcho['duration'] = deltaTime2;
print((echoSuccess ? GREEN : RED) + 'Status: ' + (echoSuccess ? 'SUCCESS' : 'FAIL') + RESET);
}
++ret.testArangoshExitCodeSuccess['total'];
ret.testArangoshExitCodeSuccess['status'] = failSuccess;
ret.testArangoshExitCodeSuccess['duration'] = deltaTime2;
print((successSuccess ? GREEN : RED) + 'Status: ' + (successSuccess ? 'SUCCESS' : 'FAIL') + RESET);
// test shebang execution with arangosh
if (!options.skipShebang && platform.substr(0, 3) !== 'win') {
var shebangSuccess = true;
@ -2122,7 +2164,7 @@ testFuncs.arangosh = function (options) {
executeExternalAndWait('sh', ['-c', 'chmod a+x ' + shebangFile]);
const startTime3 = time();
rc = executeExternalAndWait('sh', ['-c', shebangFile]);
let rc = executeExternalAndWait('sh', ['-c', shebangFile]);
deltaTime3 = time() - startTime3;
if (options.verbose) {

View File

@ -63,7 +63,7 @@ bool LineEditor::close() { return _shell->close(); }
////////////////////////////////////////////////////////////////////////////////
std::string LineEditor::prompt(std::string const& prompt,
std::string const& begin, bool& eof) {
std::string const& begin, ShellBase::EofType& eof) {
return _shell->prompt(prompt, begin, eof);
}

View File

@ -25,9 +25,9 @@
#define ARANGODB_UTILITIES_LINE_EDITOR_H 1
#include "Basics/Common.h"
#include "Utilities/ShellBase.h"
namespace arangodb {
class ShellBase;
////////////////////////////////////////////////////////////////////////////////
/// @brief line editor
@ -73,7 +73,7 @@ class LineEditor {
//////////////////////////////////////////////////////////////////////////////
std::string prompt(std::string const& prompt, std::string const& begin,
bool& eof);
ShellBase::EofType&);
//////////////////////////////////////////////////////////////////////////////
/// @brief add to history

View File

@ -27,6 +27,7 @@ extern "C" {
#include <linenoise.h>
}
#include "Logger/Logger.h"
#include "Utilities/Completer.h"
using namespace arangodb;
@ -94,19 +95,24 @@ bool LinenoiseShell::writeHistory() {
return true;
}
std::string LinenoiseShell::getLine(std::string const& prompt, bool& eof) {
std::string LinenoiseShell::getLine(std::string const& prompt, EofType& eof) {
char* line = linenoise(prompt.c_str());
if (line != nullptr) {
eof = false;
eof = EOF_NONE;
std::string stringValue(line);
::free(line);
return stringValue;
}
if (!linenoiseGotKey() || !isatty(STDIN_FILENO)) {
// only set eof if we did not get any key presses from linenoise
eof = true;
// no input from user (e.g. if CTRL-C was pressed)
eof = EOF_ABORT;
int keyType = linenoiseKeyType();
if (keyType == 2 || !isatty(STDIN_FILENO)) {
// force eof if CTRL-D was pressed or if we are not a tty
eof = EOF_FORCE_ABORT;
}
return "";

View File

@ -33,7 +33,7 @@ class Completer;
/// @brief LinenoiseShell
////////////////////////////////////////////////////////////////////////////////
class LinenoiseShell : public ShellBase {
class LinenoiseShell final : public ShellBase {
public:
LinenoiseShell(std::string const& history, Completer*);
@ -48,7 +48,7 @@ class LinenoiseShell : public ShellBase {
bool writeHistory() override final;
std::string getLine(std::string const& prompt, bool& eof) override final;
std::string getLine(std::string const& prompt, EofType& eof) override final;
//////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the shell implementation supports colors

View File

@ -90,21 +90,21 @@ void ShellBase::signal() {
////////////////////////////////////////////////////////////////////////////////
std::string ShellBase::prompt(std::string const& prompt,
std::string const& plain, bool& eof) {
std::string const& plain, EofType& eof) {
size_t lineno = 0;
std::string dotdot = "...> ";
std::string p = prompt;
std::string sep = "";
std::string line;
eof = false;
eof = EOF_NONE;
while (true) {
// calling concrete implementation of the shell
line = getLine(p, eof);
p = dotdot;
if (eof) {
if (eof != EOF_NONE) {
// give up, if the user pressed control-D on the top-most level
if (_current.empty()) {
return "";
@ -112,7 +112,7 @@ std::string ShellBase::prompt(std::string const& prompt,
// otherwise clear current content
_current.clear();
eof = false;
eof = EOF_NONE;
break;
}

View File

@ -43,6 +43,9 @@ class ShellBase {
enum console_state_e { STATE_NONE = 0, STATE_OPENED = 1, STATE_CLOSED = 2 };
public:
enum EofType { EOF_NONE = 0, EOF_ABORT = 1, EOF_FORCE_ABORT = 2 };
//////////////////////////////////////////////////////////////////////////////
/// @brief creates a shell
//////////////////////////////////////////////////////////////////////////////
@ -66,7 +69,7 @@ class ShellBase {
//////////////////////////////////////////////////////////////////////////////
std::string prompt(std::string const& prompt, std::string const& begin,
bool& eof);
EofType& eof);
public:
//////////////////////////////////////////////////////////////////////////////
@ -103,7 +106,7 @@ class ShellBase {
/// @brief get next line
//////////////////////////////////////////////////////////////////////////////
virtual std::string getLine(std::string const& prompt, bool& eof) = 0;
virtual std::string getLine(std::string const& prompt, EofType& eof) = 0;
//////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the shell implementation supports colors