mirror of https://gitee.com/bigwinds/arangodb
wrote tests for shell return codes
This commit is contained in:
parent
38e18a9e65
commit
0ff5e4c07c
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,6 @@ void ConsoleFeature::printWelcomeInfo() {
|
|||
|
||||
void ConsoleFeature::printByeBye() {
|
||||
if (!_quiet) {
|
||||
printLine("<ctrl-D>");
|
||||
printLine(TRI_BYE_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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('Starting arangosh with exception throwing script:');
|
||||
print(title);
|
||||
print('--------------------------------------------------------------------------------');
|
||||
|
||||
let args = makeArgsArangosh(options);
|
||||
args['javascript.execute-string'] = "throw('foo')";
|
||||
args['javascript.execute-string'] = command;
|
||||
args['log.level'] = 'error';
|
||||
|
||||
for (let op in opts) {
|
||||
args[op] = opts[op];
|
||||
}
|
||||
|
||||
const startTime = time();
|
||||
print(args);
|
||||
let rc = executeExternalAndWait(ARANGOSH_BIN, toArgv(args));
|
||||
const deltaTime = time() - startTime;
|
||||
const failSuccess = (rc.hasOwnProperty('exit') && rc.exit === 1);
|
||||
const failSuccess = (rc.hasOwnProperty('exit') && rc.exit === expectedReturnCode);
|
||||
|
||||
if (!failSuccess) {
|
||||
ret.testArangoshExitCodeFail['message'] =
|
||||
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();
|
||||
|
||||
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 via echo');
|
||||
print('--------------------------------------------------------------------------------');
|
||||
|
||||
fs.write(execFile,
|
||||
'echo "db._databases();" | ' + fs.makeAbsolute(ARANGOSH_BIN) + ' --server.endpoint tcp://127.0.0.1:0');
|
||||
|
||||
executeExternalAndWait('sh', ['-c', 'chmod a+x ' + execFile]);
|
||||
|
||||
const startTime2 = time();
|
||||
let rc = executeExternalAndWait('sh', ['-c', execFile]);
|
||||
deltaTime2 = time() - startTime2;
|
||||
|
||||
echoSuccess = (rc.hasOwnProperty('exit') && rc.exit === 1);
|
||||
|
||||
if (!echoSuccess) {
|
||||
ret.testArangoshExitCodeEcho['message'] =
|
||||
"didn't get expected return code (1): \n" +
|
||||
yaml.safeDump(rc);
|
||||
}
|
||||
|
||||
++ret.testArangoshExitCodeFail['total'];
|
||||
ret.testArangoshExitCodeFail['status'] = failSuccess;
|
||||
ret.testArangoshExitCodeFail['duration'] = deltaTime;
|
||||
print((failSuccess ? GREEN : RED) + 'Status: ' + (failSuccess ? 'SUCCESS' : 'FAIL') + RESET);
|
||||
fs.remove(execFile);
|
||||
|
||||
print('\n--------------------------------------------------------------------------------');
|
||||
print('Starting arangosh with regular terminating script:');
|
||||
print('--------------------------------------------------------------------------------');
|
||||
|
||||
args['javascript.execute-string'] = ';';
|
||||
args['log.level'] = 'warning';
|
||||
|
||||
const startTime2 = time();
|
||||
rc = executeExternalAndWait(ARANGOSH_BIN, toArgv(args));
|
||||
const deltaTime2 = time() - startTime2;
|
||||
|
||||
const successSuccess = (rc.hasOwnProperty('exit') && rc.exit === 0);
|
||||
|
||||
if (!successSuccess) {
|
||||
ret.testArangoshExitCodeFail['message'] =
|
||||
"didn't get expected return code (0): \n" +
|
||||
yaml.safeDump(rc);
|
||||
++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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue