1
0
Fork 0

Merge branch 'foxx-pathes' of github.com:triAGENS/ArangoDB into foxx-pathes

This commit is contained in:
Frank Celler 2015-01-18 12:29:39 +01:00
commit bd2a698ab6
22 changed files with 1118 additions and 1309 deletions

View File

@ -7,6 +7,10 @@ v2.5.0 (XXXX-XX-XX)
v2.4.1 (XXXX-XX-XX)
-------------------
* better diagnostics for arangoimp
* fixed invalid result of HTTP REST API method `/_admin/foxx/rescan`
* fixed possible segmentation fault when passing a Buffer object into a V8 function
as a parameter

View File

@ -86,16 +86,16 @@ collection in the default database (*_system*). To specify a different database,
use the *--server.database* option when invoking _arangoimp_.
An _arangoimp_ import run will print out the final results on the command line.
By default, it shows the number of documents created, the number of errors that
By default, it shows the number of documents created, the number of warnings or errors that
occurred on the server side, and the total number of input file lines/documents
that it processed. Additionally, _arangoimp_ will print out details about errors
that it processed. Additionally, _arangoimp_ will print out details about warnings and errors
that happened on the server-side (if any).
*Examples*
```js
created: 2
errors: 0
warnings/errors: 0
total: 2
```

View File

@ -447,6 +447,7 @@ SHELL_COMMON = \
@top_srcdir@/js/common/tests/shell-index.js \
@top_srcdir@/js/common/tests/shell-index-geo.js \
@top_srcdir@/js/common/tests/shell-cap-constraint.js \
@top_srcdir@/js/common/tests/shell-cap-constraint-timecritical.js \
@top_srcdir@/js/common/tests/shell-unique-constraint.js \
@top_srcdir@/js/common/tests/shell-hash-index.js \
@top_srcdir@/js/common/tests/shell-fulltext.js \

View File

@ -3,3 +3,4 @@
{"id": 3, "_from": "UnitTestsImportVertex/v9", "_to": "UnitTestsImportVertex/v4", "what": "v9->v4", "extra": "foo"}
{"id": 4, "_from": "UnitTestsImportVertex/v12", "_to": "UnitTestsImportVertex/what"}
{"id": 5}

View File

@ -153,8 +153,25 @@ void RestImportHandler::registerError (RestImportResult& result,
++result._numErrors;
result._errors.push_back(errorMsg);
}
LOG_WARNING("%s", errorMsg.c_str());
////////////////////////////////////////////////////////////////////////////////
/// @brief construct an error message
////////////////////////////////////////////////////////////////////////////////
std::string RestImportHandler::buildParseError (size_t i,
char const* lineStart) {
if (lineStart != nullptr) {
string part(lineStart);
if (part.size() > 255) {
// UTF-8 chars in string will be escaped so we can truncate it at any point
part = part.substr(0, 255) + "...";
}
return positionise(i) + "invalid JSON type (expecting object, probably parse error), offending context: " + part;
}
return positionise(i) + "invalid JSON type (expecting object, probably parse error)";
}
////////////////////////////////////////////////////////////////////////////////
@ -162,13 +179,25 @@ void RestImportHandler::registerError (RestImportResult& result,
////////////////////////////////////////////////////////////////////////////////
int RestImportHandler::handleSingleDocument (RestImportTransaction& trx,
char const* lineStart,
TRI_json_t const* json,
string& errorMsg,
bool isEdgeCollection,
bool waitForSync,
size_t i) {
if (! TRI_IsObjectJson(json)) {
errorMsg = positionise(i) + "invalid JSON type (expecting array)";
if (json != nullptr) {
string part = JsonHelper::toString(json);
if (part.size() > 255) {
// UTF-8 chars in string will be escaped so we can truncate it at any point
part = part.substr(0, 255) + "...";
}
errorMsg = positionise(i) + "invalid JSON type (expecting object), offending document: " + part;
}
else {
errorMsg = buildParseError(i, lineStart);
}
return TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
}
@ -182,7 +211,13 @@ int RestImportHandler::handleSingleDocument (RestImportTransaction& trx,
char const* to = extractJsonStringValue(json, TRI_VOC_ATTRIBUTE_TO);
if (from == nullptr || to == nullptr) {
errorMsg = positionise(i) + "missing '_from' or '_to' attribute";
string part = JsonHelper::toString(json);
if (part.size() > 255) {
// UTF-8 chars in string will be escaped so we can truncate it at any point
part = part.substr(0, 255) + "...";
}
errorMsg = positionise(i) + "missing '_from' or '_to' attribute, offending document: " + part;
return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE;
}
@ -600,7 +635,7 @@ bool RestImportHandler::createFromJson (string const& type) {
while (ptr < end) {
char const c = *ptr;
if (c == '\r' || c == '\n' || c == '\t' || c == ' ') {
if (c == '\r' || c == '\n' || c == '\t' || c == '\b' || c == '\f' || c == ' ') {
ptr++;
continue;
}
@ -657,7 +692,7 @@ bool RestImportHandler::createFromJson (string const& type) {
// trim whitespace at start of line
while (ptr < end &&
(*ptr == ' ' || *ptr == '\t' || *ptr == '\r')) {
(*ptr == ' ' || *ptr == '\t' || *ptr == '\r' || *ptr == '\b' || *ptr == '\f')) {
++ptr;
}
@ -667,6 +702,7 @@ bool RestImportHandler::createFromJson (string const& type) {
// now find end of line
char const* pos = strchr(ptr, '\n');
char const* oldPtr = nullptr;
TRI_json_t* json = nullptr;
@ -680,18 +716,20 @@ bool RestImportHandler::createFromJson (string const& type) {
// non-empty line
*(const_cast<char*>(pos)) = '\0';
TRI_ASSERT(ptr != nullptr);
json = parseJsonLine(ptr);
oldPtr = ptr;
json = parseJsonLine(ptr, pos);
ptr = pos + 1;
}
else {
// last-line, non-empty
TRI_ASSERT(pos == nullptr);
TRI_ASSERT(ptr != nullptr);
oldPtr = ptr;
json = parseJsonLine(ptr);
ptr = end;
}
res = handleSingleDocument(trx, json, errorMsg, isEdgeCollection, waitForSync, i);
res = handleSingleDocument(trx, oldPtr, json, errorMsg, isEdgeCollection, waitForSync, i);
if (json != nullptr) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
@ -734,7 +772,7 @@ bool RestImportHandler::createFromJson (string const& type) {
for (size_t i = 0; i < n; ++i) {
TRI_json_t const* json = static_cast<TRI_json_t const*>(TRI_AtVector(&documents->_value._objects, i));
res = handleSingleDocument(trx, json, errorMsg, isEdgeCollection, waitForSync, i + 1);
res = handleSingleDocument(trx, nullptr, json, errorMsg, isEdgeCollection, waitForSync, i + 1);
if (res == TRI_ERROR_NO_ERROR) {
++result._numCreated;
@ -1071,12 +1109,12 @@ bool RestImportHandler::createFromKeyValueList () {
// trim line
while (lineStart < bodyEnd &&
(*lineStart == ' ' || *lineStart == '\t' || *lineStart == '\r' || *lineStart == '\n')) {
(*lineStart == ' ' || *lineStart == '\t' || *lineStart == '\r' || *lineStart == '\n' || *lineStart == '\b' || *lineStart == '\f')) {
++lineStart;
}
while (lineEnd > lineStart &&
(*(lineEnd - 1) == ' ' || *(lineEnd - 1) == '\t' || *(lineEnd - 1) == '\r' || *(lineEnd - 1) == '\n')) {
(*(lineEnd - 1) == ' ' || *(lineEnd - 1) == '\t' || *(lineEnd - 1) == '\r' || *(lineEnd - 1) == '\n' || *(lineEnd - 1) == '\b' || *(lineEnd - 1) == '\f')) {
--lineEnd;
}
@ -1084,7 +1122,6 @@ bool RestImportHandler::createFromKeyValueList () {
TRI_json_t* keys = parseJsonLine(lineStart, lineEnd);
if (! checkKeys(keys)) {
LOG_WARNING("no JSON string array found in first line");
generateError(HttpResponse::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"no JSON string array found in first line");
@ -1146,12 +1183,12 @@ bool RestImportHandler::createFromKeyValueList () {
// trim line
while (lineStart < bodyEnd &&
(*lineStart == ' ' || *lineStart == '\t' || *lineStart == '\r' || *lineStart == '\n')) {
(*lineStart == ' ' || *lineStart == '\t' || *lineStart == '\r' || *lineStart == '\n' || *lineStart == '\b' || *lineStart == '\f')) {
++lineStart;
}
while (lineEnd > lineStart &&
(*(lineEnd - 1) == ' ' || *(lineEnd - 1) == '\t' || *(lineEnd - 1) == '\r' || *(lineEnd - 1) == '\n')) {
(*(lineEnd - 1) == ' ' || *(lineEnd - 1) == '\t' || *(lineEnd - 1) == '\r' || *(lineEnd - 1) == '\n' || *(lineEnd - 1) == '\b' || *(lineEnd - 1) == '\f')) {
--lineEnd;
}
@ -1170,7 +1207,7 @@ bool RestImportHandler::createFromKeyValueList () {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, values);
if (json != nullptr) {
res = handleSingleDocument(trx, json, errorMsg, isEdgeCollection, waitForSync, i);
res = handleSingleDocument(trx, lineStart, json, errorMsg, isEdgeCollection, waitForSync, i);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
}
else {
@ -1194,7 +1231,7 @@ bool RestImportHandler::createFromKeyValueList () {
}
}
else {
string errorMsg = positionise(i) + "no valid JSON data";
string errorMsg = buildParseError(i, lineStart);
registerError(result, errorMsg);
}
}

View File

@ -128,11 +128,19 @@ namespace triagens {
void registerError (RestImportResult&,
std::string const&);
////////////////////////////////////////////////////////////////////////////////
/// @brief construct an error message
////////////////////////////////////////////////////////////////////////////////
std::string buildParseError (size_t,
char const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief process a single JSON document
////////////////////////////////////////////////////////////////////////////////
int handleSingleDocument (RestImportTransaction&,
char const*,
TRI_json_t const*,
std::string&,
bool,

View File

@ -708,10 +708,8 @@ namespace triagens {
}
}
TRI_json_t const* importResult;
// look up the "created" flag. This returns a pointer, not a copy
importResult = TRI_LookupObjectJson(json, "created");
TRI_json_t const* importResult = TRI_LookupObjectJson(json, "created");
if (TRI_IsNumberJson(importResult)) {
_numberOk += (size_t) importResult->_value._number;

View File

@ -411,7 +411,7 @@ int main (int argc, char* argv[]) {
// give information about import
if (ok) {
cout << "created: " << ih.getImportedLines() << endl;
cout << "errors: " << ih.getErrorLines() << endl;
cout << "warnings/errors: " << ih.getErrorLines() << endl;
cout << "total: " << ih.getReadLines() << endl;
}
else {

View File

@ -44,124 +44,7 @@ var easyPostCallback = actions.easyPostCallback;
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief fetches a FOXX application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/fetch",
prefix : false,
callback : function (req, res) {
'use strict';
var safe = /^[0-9a-zA-Z_\-\.]+$/;
if (req.suffix.length !== 0) {
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
return;
}
var json = actions.getJsonBody(req, res, actions.HTTP_BAD);
if (json === undefined) {
return;
}
var serverFile = json.filename;
var realFile = fs.join(fs.getTempPath(), serverFile);
if (! fs.isFile(realFile)) {
actions.resultNotFound(req, res, arangodb.errors.ERROR_FILE_NOT_FOUND.code);
return;
}
try {
var name = json.name;
var version = json.version;
if (! safe.test(name)) {
fs.remove(realFile);
throw "rejecting unsafe name '" + name + "'";
}
if (! safe.test(version)) {
fs.remove(realFile);
throw "rejecting unsafe version '" + version + "'";
}
var appPath = module.appPath();
if (typeof appPath === "undefined") {
fs.remove(realFile);
throw "javascript.app-path not set, rejecting app loading";
}
var path = fs.join(appPath, name + "-" + version);
if (!fs.exists(path)) {
fs.makeDirectoryRecursive(path);
fs.unzipFile(realFile, path, false, true);
foxxManager.scanAppDirectory();
}
fs.remove(realFile);
var found = arangodb.db._collection("_aal").firstExample({
type: "app",
path: name + "-" + version
});
if (found !== null) {
found = found.app;
}
actions.resultOk(req, res, actions.HTTP_OK, { path: path, app: found });
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @brief mounts a FOXX application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/mount",
prefix : false,
callback: easyPostCallback({
body: true,
callback: function (body) {
var appId = body.appId;
var mount = body.mount;
var options = body.options || {};
return foxxManager.mount(appId, mount, options);
}
})
});
////////////////////////////////////////////////////////////////////////////////
/// @brief rescans the FOXX application directory
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/rescan",
prefix : false,
callback: easyPostCallback({
body: true,
callback: function () {
foxxManager.scanAppDirectory();
return true;
}
})
});
////////////////////////////////////////////////////////////////////////////////
/// @brief sets up a FOXX application
/// @brief sets up a Foxx application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
@ -179,7 +62,7 @@ actions.defineHttp({
});
////////////////////////////////////////////////////////////////////////////////
/// @brief tears down a FOXX application
/// @brief tears down a Foxx application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
@ -197,11 +80,31 @@ actions.defineHttp({
});
////////////////////////////////////////////////////////////////////////////////
/// @brief unmounts a FOXX application
/// @brief installs a Foxx application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/unmount",
url : "_admin/foxx/install",
prefix : false,
callback: easyPostCallback({
body: true,
callback: function (body) {
var appInfo = body.appInfo;
var mount = body.mount;
var options = body.options;
return foxxManager.install(appInfo, mount, options);
}
})
});
////////////////////////////////////////////////////////////////////////////////
/// @brief uninstalls a Foxx application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/uninstall",
prefix : false,
callback: easyPostCallback({
@ -209,85 +112,51 @@ actions.defineHttp({
callback: function (body) {
var mount = body.mount;
return foxxManager.unmount(mount);
return foxxManager.uninstall(mount);
}
})
});
////////////////////////////////////////////////////////////////////////////////
/// @brief sets up a FOXX dev application
/// @brief replaces a Foxx application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/dev-setup",
url : "_admin/foxx/replace",
prefix : false,
callback: easyPostCallback({
body: true,
callback: function (body) {
var name = body.name;
var appInfo = body.appInfo;
var mount = body.mount;
var options = body.options;
return foxxManager.devSetup(name);
return foxxManager.replace(appInfo, mount, options);
}
})
});
////////////////////////////////////////////////////////////////////////////////
/// @brief tears down a FOXX dev application
/// @brief upgrades a Foxx application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/dev-teardown",
url : "_admin/foxx/upgrade",
prefix : false,
callback: easyPostCallback({
body: true,
callback: function (body) {
var name = body.name;
var appInfo = body.appInfo;
var mount = body.mount;
var options = body.options;
return foxxManager.devTeardown(name);
return foxxManager.upgrade(appInfo, mount, options);
}
})
});
////////////////////////////////////////////////////////////////////////////////
/// @brief purges a FOXX application
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/purge",
prefix : false,
callback: easyPostCallback({
body: true,
callback: function (body) {
var name = body.name;
return foxxManager.purge(name);
}
})
});
////////////////////////////////////////////////////////////////////////////////
/// @brief returns directory information
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/foxx/config",
prefix : false,
callback : function (req, res) {
var result = {
appPath: module.appPath(),
devAppPath: internal.developmentMode ? module.devAppPath() : null,
logFilePath: internal.logfilePath,
startupPath: module.startupPath()
};
actions.resultOk(req, res, actions.HTTP_OK, { result: result });
}
});
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -4,6 +4,7 @@
ArangoError = require('org/arangodb').ArangoError,
<%= repository %> = require('<%= repositoryPath %>').Repository,
<%= model %> = require('<%= modelPath %>').Model,
joi = require('joi'),
_ = require('underscore'),
controller,
<%= repositoryInstance %>;
@ -34,6 +35,18 @@
res.json(<%= repositoryInstance %>.save(<%= modelInstance %>).forClient());
}).bodyParam('<%= modelInstance %>', 'The <%= model %> you want to create', <%= model %>);
/** Reads a <%= model %>
*
* Reads a <%= model %>-Item.
*/
controller.get('/<%= basePath %>/:id', function (req, res) {
var id = req.params('id');
res.json(<%= repositoryInstance %>.byId(id).forClient());
}).pathParam('id', {
description: 'The id of the <%= model %>-Item',
type: 'string'
});
/** Updates a <%= model %>
*
* Changes a <%= model %>-Item. The information has to be in the

File diff suppressed because it is too large Load Diff

View File

@ -1367,16 +1367,9 @@ function require (path) {
/// @brief createApp
////////////////////////////////////////////////////////////////////////////////
Module.prototype.createApp = function (description, options) {
Module.prototype.createApp = function (config) {
'use strict';
return new ArangoApp(
description.id,
description.manifest,
description.root,
description.path,
options
);
return new ArangoApp(config);
};
// -----------------------------------------------------------------------------
@ -1391,16 +1384,18 @@ function require (path) {
/// @brief ArangoApp constructor
////////////////////////////////////////////////////////////////////////////////
ArangoApp = function (id, manifest, root, path, options) {
ArangoApp = function (config) {
'use strict';
this._id = id;
this._manifest = manifest;
this._name = manifest.name;
this._version = manifest.version;
this._root = root;
this._path = path;
this._options = options;
this._id = config.id; // ???
this._manifest = config.manifest;
this._name = config.manifest.name;
this._version = config.manifest.version;
this._root = config.root;
this._path = config.path;
this._options = config.options;
this._mount = config.mount;
this._isSystem = config.isSystem || false;
this._isDevelopment = config.isDevelopment || false;
this._exports = {};
};
@ -1428,6 +1423,35 @@ function require (path) {
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a Json representation of itself to be persisted
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.toJSON = function () {
var json = {
id: this._id,
manifest: this._manifest,
name: this._name,
version: this._version,
root: this._root,
path: this._path,
options: this._options,
mount: this._mount,
isSystem: this._isSystem,
isDevelopment: this._isDevelopment
};
if (this._manifest.hasOwnProperty("author")) {
json.author = this._manifest.author;
}
if (this._manifest.hasOwnProperty("description")) {
json.description = this._manifest.description;
}
if (this._manifest.hasOwnProperty("thumbnail")) {
json.thumbnail = this._manifest.thumbnail;
}
return json;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief createAppModule
////////////////////////////////////////////////////////////////////////////////

View File

@ -39,6 +39,31 @@ var throwDownloadError = arangodb.throwDownloadError;
var errors = arangodb.errors;
var ArangoError = arangodb.ArangoError;
// TODO Only temporary
var tmp_getStorage = function() {
var c = db._tmp_aal;
if (c === undefined) {
c = db._create("_tmp_aal", {isSystem: true});
c.ensureUniqueConstraint("mount");
}
return c;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief comparator for mount points
////////////////////////////////////////////////////////////////////////////////
var compareMounts = function(l, r) {
var left = l.mount.toLowerCase();
var right = r.mount.toLowerCase();
if (left < right) {
return -1;
}
return 1;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief builds a github repository URL
////////////////////////////////////////////////////////////////////////////////
@ -248,31 +273,34 @@ function getStorage () {
////////////////////////////////////////////////////////////////////////////////
/// @brief returns all installed FOXX applications
/// @brief returns all running Foxx applications
////////////////////////////////////////////////////////////////////////////////
function listJson (showPrefix) {
function listJson (showPrefix, onlyDevelopment) {
'use strict';
var aal = getStorage();
var cursor = aal.byExample({ type: "mount" });
var mounts = tmp_getStorage();
var cursor;
if (onlyDevelopment) {
cursor = mounts.byExample({isDevelopment: true});
} else {
cursor = mounts.all();
}
var result = [];
var doc, res;
while (cursor.hasNext()) {
var doc = cursor.next();
doc = cursor.next();
var version = doc.app.replace(/^.+:(\d+(\.\d+)*)$/g, "$1");
var res = {
res = {
mountId: doc._key,
mount: doc.mount,
appId: doc.app,
name: doc.name,
description: doc.description,
author: doc.author,
description: doc.manifest.description,
author: doc.manifest.author,
system: doc.isSystem ? "yes" : "no",
active: doc.active ? "yes" : "no",
version: version
development: doc.isDevelopment ? "yes" : "no",
version: doc.version
};
if (showPrefix) {
@ -285,6 +313,52 @@ function listJson (showPrefix) {
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief prints all running Foxx applications
////////////////////////////////////////////////////////////////////////////////
function list(onlyDevelopment) {
var apps = listJson(undefined, onlyDevelopment);
arangodb.printTable(
apps.sort(compareMounts),
[ "mount", "name", "author", "description", "version", "development" ],
{
prettyStrings: true,
totalString: "%s application(s) found",
emptyString: "no applications found",
rename: {
"mount": "Mount",
"name" : "Name",
"author" : "Author",
"description" : "Description",
"version" : "Version",
"development" : "Development"
}
}
);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns all running Foxx applications in development mode
////////////////////////////////////////////////////////////////////////////////
function listDevelopmentJson (showPrefix) {
'use strict';
return listJson(showPrefix, true);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief prints all running Foxx applications
////////////////////////////////////////////////////////////////////////////////
function listDevelopment() {
'use strict';
return list(true);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validate an app name and fail if it is invalid
////////////////////////////////////////////////////////////////////////////////
@ -302,19 +376,28 @@ function validateAppName (name) {
});
}
function mountedApp (mount) {
"use strict";
return tmp_getStorage().firstExample({mount: mount});
}
////////////////////////////////////////////////////////////////////////////////
/// @brief Exports
////////////////////////////////////////////////////////////////////////////////
exports.mountedApp = mountedApp;
exports.list = list;
exports.listJson = listJson;
exports.listDevelopment = listDevelopment;
exports.listDevelopmentJson = listDevelopmentJson;
exports.buildGithubUrl = buildGithubUrl;
exports.repackZipFile = repackZipFile;
exports.processDirectory = processDirectory;
exports.processGithubRepository = processGithubRepository;
exports.validateAppName = validateAppName;
exports.tmp_getStorage = tmp_getStorage;
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -70,7 +70,7 @@ exports.Helper = {
else if (iterations === 400) {
require("console").log("waited very long for unload of collection " + collection.name());
}
else if (iterations === 800) {
else if (iterations === 1600) {
throw "waited too long for unload of collection " + collection.name();
}
}

View File

@ -0,0 +1,192 @@
/*global require, db, assertEqual, assertTrue, ArangoCollection */
////////////////////////////////////////////////////////////////////////////////
/// @brief test the cap constraint
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var internal = require("internal");
var testHelper = require("org/arangodb/test-helper").Helper;
// -----------------------------------------------------------------------------
// --SECTION-- basic methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite: Creation
/// these tests seem to fail when run in cluster or with valgrind from arangosh
/// (while they succeed when run on the frontend)
/// test-helper.js:Helper.waitUnload expects timeley behaviour
////////////////////////////////////////////////////////////////////////////////
function CapConstraintTimecriticalSuite() {
var ERRORS = internal.errors;
var cn = "UnitTestsCollectionCap";
var collection = null;
var nsort = function (l, r) {
if (l !== r) {
return (l < r) ? -1 : 1;
}
return 0;
};
var assertBadParameter = function (err) {
assertTrue(err.errorNum === ERRORS.ERROR_BAD_PARAMETER.code ||
err.errorNum === ERRORS.ERROR_HTTP_BAD_PARAMETER.code);
};
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
internal.db._drop(cn);
collection = internal.db._create(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
if (collection !== null) {
internal.wait(0);
collection.unload();
collection.drop();
collection = null;
}
internal.wait(0.0);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: reload
////////////////////////////////////////////////////////////////////////////////
testReload : function () {
var idx = collection.ensureCapConstraint(5);
var fun = function(d) { return d.n; };
assertEqual("cap", idx.type);
assertEqual(true, idx.isNewlyCreated);
assertEqual(5, idx.size);
assertEqual(0, idx.byteSize);
assertEqual(0, collection.count());
for (var i = 0; i < 10; ++i) {
collection.save({ n : i });
}
assertEqual(5, collection.count());
assertEqual([5, 6, 7, 8, 9], collection.toArray().map(fun).sort(nsort));
testHelper.waitUnload(collection, true);
assertEqual(5, collection.count());
assertEqual([5, 6, 7, 8, 9], collection.toArray().map(fun).sort(nsort));
collection.save({ n : 10 });
assertEqual(5, collection.count());
assertEqual([6, 7, 8, 9, 10], collection.toArray().map(fun).sort(nsort));
collection.save({ n : 11 });
assertEqual(5, collection.count());
assertEqual([7, 8, 9, 10, 11], collection.toArray().map(fun).sort(nsort));
testHelper.waitUnload(collection, true);
assertEqual(5, collection.count());
assertEqual([7, 8, 9, 10, 11], collection.toArray().map(fun).sort(nsort));
for (var i = 15; i < 20; ++i) {
collection.save({ n : i });
}
assertEqual(5, collection.count());
assertEqual([15, 16, 17, 18, 19], collection.toArray().map(fun).sort(nsort));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: reload
////////////////////////////////////////////////////////////////////////////////
testReloadMulti : function () {
var idx = collection.ensureCapConstraint(5);
var fun = function(d) { return d.n; };
assertEqual("cap", idx.type);
assertEqual(true, idx.isNewlyCreated);
assertEqual(5, idx.size);
assertEqual(0, idx.byteSize);
assertEqual(0, collection.count());
testHelper.waitUnload(collection, true);
assertEqual(0, collection.count());
for (var i = 0; i < 10; ++i) {
collection.save({ n : i });
}
testHelper.waitUnload(collection, true);
assertEqual(5, collection.count());
assertEqual([5, 6, 7, 8, 9], collection.toArray().map(fun).sort(nsort));
collection.save({ n : 10 });
testHelper.waitUnload(collection, true);
assertEqual(5, collection.count());
assertEqual([6, 7, 8, 9, 10], collection.toArray().map(fun).sort(nsort));
collection.save({ n: 0 });
assertEqual([0, 7, 8, 9, 10], collection.toArray().map(fun).sort(nsort));
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- main
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suites
////////////////////////////////////////////////////////////////////////////////
jsunity.run(CapConstraintTimecriticalSuite);
return jsunity.done();
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -398,93 +398,6 @@ function CapConstraintSuite() {
assertEqual([ "abc", "def", "ghi" ], collection.toArray().map(fun).sort());
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: reload
////////////////////////////////////////////////////////////////////////////////
testReload : function () {
var idx = collection.ensureCapConstraint(5);
var fun = function(d) { return d.n; };
assertEqual("cap", idx.type);
assertEqual(true, idx.isNewlyCreated);
assertEqual(5, idx.size);
assertEqual(0, idx.byteSize);
assertEqual(0, collection.count());
for (var i = 0; i < 10; ++i) {
collection.save({ n : i });
}
assertEqual(5, collection.count());
assertEqual([5, 6, 7, 8, 9], collection.toArray().map(fun).sort(nsort));
testHelper.waitUnload(collection, true);
assertEqual(5, collection.count());
assertEqual([5, 6, 7, 8, 9], collection.toArray().map(fun).sort(nsort));
collection.save({ n : 10 });
assertEqual(5, collection.count());
assertEqual([6, 7, 8, 9, 10], collection.toArray().map(fun).sort(nsort));
collection.save({ n : 11 });
assertEqual(5, collection.count());
assertEqual([7, 8, 9, 10, 11], collection.toArray().map(fun).sort(nsort));
testHelper.waitUnload(collection, true);
assertEqual(5, collection.count());
assertEqual([7, 8, 9, 10, 11], collection.toArray().map(fun).sort(nsort));
for (var i = 15; i < 20; ++i) {
collection.save({ n : i });
}
assertEqual(5, collection.count());
assertEqual([15, 16, 17, 18, 19], collection.toArray().map(fun).sort(nsort));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: reload
////////////////////////////////////////////////////////////////////////////////
testReloadMulti : function () {
var idx = collection.ensureCapConstraint(5);
var fun = function(d) { return d.n; };
assertEqual("cap", idx.type);
assertEqual(true, idx.isNewlyCreated);
assertEqual(5, idx.size);
assertEqual(0, idx.byteSize);
assertEqual(0, collection.count());
testHelper.waitUnload(collection, true);
assertEqual(0, collection.count());
for (var i = 0; i < 10; ++i) {
collection.save({ n : i });
}
testHelper.waitUnload(collection, true);
assertEqual(5, collection.count());
assertEqual([5, 6, 7, 8, 9], collection.toArray().map(fun).sort(nsort));
collection.save({ n : 10 });
testHelper.waitUnload(collection, true);
assertEqual(5, collection.count());
assertEqual([6, 7, 8, 9, 10], collection.toArray().map(fun).sort(nsort));
collection.save({ n: 0 });
assertEqual([0, 7, 8, 9, 10], collection.toArray().map(fun).sort(nsort));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: cap with byteSize
////////////////////////////////////////////////////////////////////////////////

View File

@ -1577,8 +1577,15 @@ function resultOk (req, res, httpReturnCode, result, headers) {
result = {};
}
result.error = false;
result.code = httpReturnCode;
// check the type of the result.
if (typeof result !== "string" &&
typeof result !== "number" &&
typeof result !== "boolean") {
// only modify result properties if none of the above types
// otherwise the strict mode will throw
result.error = false;
result.code = httpReturnCode;
}
res.body = JSON.stringify(result);

View File

@ -493,6 +493,9 @@ shutdownActions.startServers = function (dispatchers, cmd, run) {
var i;
var url;
var r;
var serverStates = {};
var error = false;
for (i = 0;i < run.endpoints.length;i++) {
console.info("Using API to shutdown %s", JSON.stringify(run.pids[i]));
url = endpointToURL(run.endpoints[i])+"/_admin/shutdown";
@ -514,13 +517,20 @@ shutdownActions.startServers = function (dispatchers, cmd, run) {
for (i = 0;i < run.pids.length;i++) {
var s = statusExternal(run.pids[i]);
if (s.status !== "TERMINATED") {
console.info("Shutting down %s the hard way...",
JSON.stringify(run.pids[i]));
killExternal(run.pids[i]);
console.info("done.");
if (s.hasOwnProperty('signal')) {
error = true;
console.info("done - with problems: " + s);
}
else {
console.info("Shutting down %s the hard way...",
JSON.stringify(run.pids[i]));
s.killedState = killExternal(run.pids[i]);
console.info("done.");
}
serverStates[run.pids[i]] = s;
}
}
return {"error": false, "isStartServers": true};
return {"error": error, "isStartServers": true, "serverStates" : serverStates};
};
cleanupActions.startAgent = function (dispatchers, cmd) {

View File

@ -152,7 +152,7 @@ BaseMiddleware = function () {
///
/// `request.requestParts()`
///
/// Returns a list containing the individual parts of a multi-part request.
/// Returns an array containing the individual parts of a multi-part request.
/// Each part contains a `headers` attribute with all headers of the part,
/// and a `data` attribute with the content of the part in a Buffer object.
/// If the request is not a multi-part request, this function will throw an

View File

@ -24,10 +24,11 @@
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Dr. Frank Celler, Michael Hackstein
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
/*
var arangodb = require("org/arangodb");
var ArangoError = arangodb.ArangoError;
var errors = arangodb.errors;
@ -50,6 +51,7 @@ var download = require("internal").download;
var throwDownloadError = arangodb.throwDownloadError;
var throwFileNotFound = arangodb.throwFileNotFound;
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
@ -177,52 +179,6 @@ function checkManifest (filename, mf) {
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extend a context with some helper functions
////////////////////////////////////////////////////////////////////////////////
function extendContext (context, app, root) {
"use strict";
var cp = context.collectionPrefix;
var cname = "";
if (cp === "_") {
cname = "_";
}
else if (cp !== "") {
cname = cp + "_";
}
context.collectionName = function (name) {
var replaced = cname + name.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);
if (replaced.length === 0) {
throw new Error("Cannot derive collection name from '" + name + "'");
}
return replaced;
};
context.collection = function (name) {
return arangodb.db._collection(this.collectionName(name));
};
context.path = function (name) {
return fs.join(root, app._path, name);
};
context.comments = [];
context.comment = function (str) {
this.comments.push(str);
};
context.clearComments = function () {
this.comments = [];
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finds mount document from mount path or identifier
////////////////////////////////////////////////////////////////////////////////
@ -865,40 +821,6 @@ exports.mount = function (appId, mount, options) {
return { appId: app._id, mountId: doc._key, mount: mount };
};
////////////////////////////////////////////////////////////////////////////////
/// @brief tears down a Foxx application
///
/// Input:
/// * mount: the mount path starting with a "/"
///
/// Output:
/// -
////////////////////////////////////////////////////////////////////////////////
exports.teardown = function (mount) {
"use strict";
checkParameter(
"teardown(<mount>)",
[ [ "Mount identifier", "string" ] ],
[ mount ] );
var appId;
try {
var doc = mountFromId(mount);
appId = doc.app;
var app = createApp(appId);
teardownApp(app, mount, doc.options.collectionPrefix);
} catch (err) {
console.errorLines(
"Teardown not possible for mount '%s': %s", mount, String(err.stack || err));
throw err;
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief unmounts a Foxx application
///
@ -1209,16 +1131,6 @@ exports.fetchFromGithub = function (url, name, version) {
return "app:" + source.name + ":" + source.version;
};
////////////////////////////////////////////////////////////////////////////////
///// @brief returns all installed FOXX applications
////////////////////////////////////////////////////////////////////////////////
exports.listJson = function () {
"use strict";
return utils.listJson();
};
////////////////////////////////////////////////////////////////////////////////
/// @brief initializes the Foxx apps
////////////////////////////////////////////////////////////////////////////////
@ -1287,6 +1199,7 @@ exports.initializeFoxx = function () {
});
}
};
*/
(function() {
"use strict";
@ -1294,6 +1207,22 @@ exports.initializeFoxx = function () {
// --CHAPTER-- used code
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- imports
// -----------------------------------------------------------------------------
var fs = require("fs");
var utils = require("org/arangodb/foxx/manager-utils");
var store = require("org/arangodb/foxx/store");
var arangodb = require("org/arangodb");
var ArangoError = arangodb.ArangoError;
var checkParameter = arangodb.checkParameter;
var errors = arangodb.errors;
var download = require("internal").download;
var throwDownloadError = arangodb.throwDownloadError;
var throwFileNotFound = arangodb.throwFileNotFound;
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
@ -1321,6 +1250,52 @@ var prefixFromMount = function(mount) {
return mount.substr(1).replace(/-/g, "_").replace(/\//g, "_");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief extend a context with some helper functions
////////////////////////////////////////////////////////////////////////////////
var extendContext = function(context, app, root) {
var cp = context.collectionPrefix;
var cname = "";
if (cp === "_") {
cname = "_";
}
else if (cp !== "") {
cname = cp + "_";
}
context.collectionName = function (name) {
var replaced = cname + name.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);
if (replaced.length === 0) {
throw new Error("Cannot derive collection name from '" + name + "'");
}
return replaced;
};
context.collection = function (name) {
return arangodb.db._collection(this.collectionName(name));
};
context.path = function (name) {
return fs.join(root, app._path, name);
};
context.comments = [];
context.comment = function (str) {
this.comments.push(str);
};
context.clearComments = function () {
this.comments = [];
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief validates a manifest file and returns it.
/// All errors are handled including file not found. Returns undefined if manifest is invalid
@ -1348,16 +1323,22 @@ var validateManifestFile = function(file) {
return mf;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Checks if the mountpoint is reserved for system apps
////////////////////////////////////////////////////////////////////////////////
var isSystemMount = function(mount) {
return (/^\/_/).test(mount);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the root path for application. Knows about system apps
////////////////////////////////////////////////////////////////////////////////
var computeRootAppPath = function(mount) {
if (/^\/_/.test(mount)) {
// Must be a system app
if (isSystemMount(mount)) {
return module.systemAppPath();
}
// A standard app
return module.appPath();
};
@ -1366,7 +1347,9 @@ var computeRootAppPath = function(mount) {
////////////////////////////////////////////////////////////////////////////////
var transformMountToPath = function(mount) {
return fs.join.apply(this, mount.split("/").push("APP"));
var list = mount.split("/");
list.push("APP");
return fs.join.apply(this, list);
};
////////////////////////////////////////////////////////////////////////////////
@ -1415,36 +1398,29 @@ var executeAppScript = function(app, name, mount, prefix) {
app.loadAppScript(appContext, desc[name]);
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief sets up an app
////////////////////////////////////////////////////////////////////////////////
function setupApp (app, mount, prefix) {
"use strict";
return executeAppScript(app, "setup", mount, prefix);
}
var setupApp = function (app, mount, prefix) {
return executeAppScript(app, "setup", mount, prefix);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief tears down an app
////////////////////////////////////////////////////////////////////////////////
function teardownApp (app, mount, prefix) {
"use strict";
return executeAppScript(app, "teardown", mount, prefix);
}
var teardownApp = function (app, mount, prefix) {
return executeAppScript(app, "teardown", mount, prefix);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the app path and manifest
////////////////////////////////////////////////////////////////////////////////
var appDescription = function (mount, options) {
var appConfig = function (mount, options) {
var root = computeRootAppPath(mount);
var path = transformMountToPath(mount);
@ -1462,7 +1438,10 @@ function teardownApp (app, mount, prefix) {
root: root,
path: path,
manifest: manifest,
options: options
options: options,
mount: mount,
isSystem: isSystemMount(mount),
isDevelopment: false
};
};
@ -1473,8 +1452,9 @@ function teardownApp (app, mount, prefix) {
////////////////////////////////////////////////////////////////////////////////
var createApp = function(mount, options) {
var description = appDescription(mount);
var app = module.createApp(description, options || {});
var config = appConfig(mount);
config.options = options || {};
var app = module.createApp(config);
if (app === null) {
console.errorLines(
"Cannot find application '%s'", mount);
@ -1632,7 +1612,7 @@ var installAppFromLocal = function(path, targetPath) {
/// @brief sets up a Foxx application
///
/// Input:
/// * mount: the mount identifier or path
/// * mount: the mount path starting with a "/"
///
/// Output:
/// -
@ -1655,6 +1635,32 @@ var setup = function (mount) {
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief tears down a Foxx application
///
/// Input:
/// * mount: the mount path starting with a "/"
///
/// Output:
/// -
////////////////////////////////////////////////////////////////////////////////
var teardown = function (mount) {
checkParameter(
"teardown(<mount>)",
[ [ "Mount path", "string" ] ],
[ mount ] );
var app = lookupApp(mount);
try {
teardownApp(app, mount, prefixFromMount(mount));
} catch (err) {
console.errorLines(
"Teardown not possible for mount '%s': %s", mount, String(err.stack || err));
throw err;
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Scans the sources of the given mountpoint and publishes the routes
///
@ -1662,22 +1668,16 @@ var setup = function (mount) {
////////////////////////////////////////////////////////////////////////////////
var scanFoxx = function(mount, options) {
delete appCache[mount];
createApp(mount, options);
var app = createApp(mount, options);
utils.tmp_getStorage().save(app.toJSON());
// TODO Routing?
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Installs a new foxx application on the given mount point.
///
/// TODO: Long Documentation!
/// @brief Internal install function. Check install.
/// Does not check parameters and throws errors.
////////////////////////////////////////////////////////////////////////////////
var install = function(appInfo, mount, options) {
checkParameter(
"mount(<appInfo>, <mount>, [<options>])",
[ [ "Install information", "string" ],
[ "Mount path", "string" ] ],
[ appInfo, mount ] );
var _install = function(appInfo, mount, options, runSetup) {
var targetPath = computeAppPath(mount, true);
if (fs.exists(targetPath)) {
throw "An app is already installed at this location.";
@ -1685,7 +1685,7 @@ var install = function(appInfo, mount, options) {
fs.makeDirectoryRecursive(targetPath);
// Remove the empty APP folder.
// Ohterwise move will fail.
fs.removeDirectoryRecursive(targetPath);
fs.removeDirectory(targetPath);
if (appInfo === "EMPTY") {
// Make Empty app
@ -1701,27 +1701,110 @@ var install = function(appInfo, mount, options) {
throw "Not implemented yet";
}
scanFoxx(mount, options);
setup(mount);
if (runSetup) {
setup(mount);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Installs a new foxx application on the given mount point.
///
/// TODO: Long Documentation!
////////////////////////////////////////////////////////////////////////////////
var install = function(appInfo, mount, options) {
checkParameter(
"mount(<appInfo>, <mount>, [<options>])",
[ [ "Install information", "string" ],
[ "Mount path", "string" ] ],
[ appInfo, mount ] );
_install(appInfo, mount, options, true);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Internal install function. Check install.
/// Does not check parameters and throws errors.
////////////////////////////////////////////////////////////////////////////////
var _uninstall = function(mount) {
var targetPath = computeAppPath(mount, true);
if (!fs.exists(targetPath)) {
throw "No foxx app found at this location.";
}
teardown(mount);
// TODO Delete routing?
utils.tmp_getStorage().removeByExample({mount: mount});
delete appCache[mount];
// Remove the APP folder.
fs.removeDirectoryRecursive(targetPath, true);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Uninstalls the foxx application on the given mount point.
///
/// TODO: Long Documentation!
////////////////////////////////////////////////////////////////////////////////
var uninstall = function(mount) {
checkParameter(
"mount(<mount>)",
[ [ "Mount path", "string" ] ],
[ mount ] );
_uninstall(mount);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Replaces a foxx application on the given mount point by an other one.
///
/// TODO: Long Documentation!
////////////////////////////////////////////////////////////////////////////////
var replace = function(appInfo, mount, options) {
checkParameter(
"mount(<appInfo>, <mount>, [<options>])",
[ [ "Install information", "string" ],
[ "Mount path", "string" ] ],
[ appInfo, mount ] );
_uninstall(mount, true);
_install(appInfo, mount, options, true);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief Upgrade a foxx application on the given mount point by a new one.
///
/// TODO: Long Documentation!
////////////////////////////////////////////////////////////////////////////////
var upgrade = function(appInfo, mount, options) {
checkParameter(
"mount(<appInfo>, <mount>, [<options>])",
[ [ "Install information", "string" ],
[ "Mount path", "string" ] ],
[ appInfo, mount ] );
_uninstall(mount, false);
_install(appInfo, mount, options, false);
};
// -----------------------------------------------------------------------------
// --SECTION-- exports
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief Exports
////////////////////////////////////////////////////////////////////////////////
exports.scanFoxx = scanFoxx;
exports.install = install;
/*
exports.uninstall = uninstall;
exports.setup = setup;
exports.teardown = teardown;
exports.list = list;
exports.listJson = listJson;
exports.replace = replace;
exports.mountedApp = mountedApp;
exports.upgrade = upgrade;
exports.scanFoxx = scanFoxx;
exports.developmentMounts = developmentMounts;
exports.developmentMountsJson = developmentMountsJson;
*/
exports.setup = setup;
exports.teardown = teardown;
exports.uninstall = uninstall;
exports.replace = replace;
exports.upgrade = upgrade;
////////////////////////////////////////////////////////////////////////////////
/// @brief Exports from foxx utils module.
////////////////////////////////////////////////////////////////////////////////
exports.mountedApp = utils.mountedApp;
exports.list = utils.list;
exports.listJson = utils.listJson;
exports.listDevelopment = utils.listDevelopment;
exports.listDevelopmentJson = utils.listDevelopmentJson;
////////////////////////////////////////////////////////////////////////////////
/// @brief Exports from foxx store module.

View File

@ -98,6 +98,7 @@ var Planner = require("org/arangodb/cluster").Planner;
var Kickstarter = require("org/arangodb/cluster").Kickstarter;
var endpointToURL = require("org/arangodb/cluster/planner").endpointToURL;
var serverCrashed = false;
var optionsDefaults = { "cluster": false,
"valgrind": false,
@ -394,6 +395,9 @@ function checkInstanceAlive(instanceInfo, options) {
copy("bin/arangod", storeArangodPath);
}
}
if (!ret) {
serverCrashed = true;
}
return ret;
}
var ClusterFit = true;
@ -419,30 +423,69 @@ function checkInstanceAlive(instanceInfo, options) {
}
}
}
return ClusterFit && instanceInfo.kickstarter.isHealthy();
if (ClusterFit && instanceInfo.kickstarter.isHealthy()) {
return true;
}
else {
serverCrashed = true;
return false;
}
}
function shutdownInstance (instanceInfo, options) {
if (!checkInstanceAlive(instanceInfo, options)) {
print("Server already dead, doing nothing. This shouldn't happen?");
}
if (options.cluster) {
instanceInfo.kickstarter.shutdown();
var rc = instanceInfo.kickstarter.shutdown();
if (options.cleanup) {
instanceInfo.kickstarter.cleanup();
}
if (rc.error) {
for (var i in rc.serverStates) {
if (rc.serverStates.hasOwnProperty(i)){
if (rc.serverStates[i].hasOwnProperty('signal')) {
print("Server shut down with : " + rc.serverStates[i] + " marking run as crashy.");
serverCrashed = true;
}
}
}
}
}
else {
if (typeof(instanceInfo.exitStatus) === 'undefined') {
download(instanceInfo.url+"/_admin/shutdown","",
makeAuthorisationHeaders(options));
if (typeof(options.valgrind) === 'string') {
print("Waiting for server shut down");
var res = statusExternal(instanceInfo.pid, true);
print("Server gone: ");
print(res);
}
else {
wait(10);
killExternal(instanceInfo.pid);
print("Waiting for server shut down");
var count = 0;
while (1) {
instanceInfo.exitStatus = statusExternal(instanceInfo.pid, false);
if (instanceInfo.exitStatus.status === "RUNNING") {
count ++;
if (typeof(options.valgrind) === 'string') {
continue;
}
if (count > 10) {
print("forcefully terminating " + instanceInfo.pid + " after 10 s grace period.");
serverCrashed = true;
killExternal(instanceInfo.pid);
break;
}
else {
wait(1);
}
}
else if (instanceInfo.exitStatus.status !== "TERMINATED") {
if (instanceInfo.exitStatus.hasOwnProperty('signal')) {
print("Server shut down with : " + instanceInfo.exitStatus + " marking build as crashy.");
serverCrashed = true;
}
}
else {
print("Server shutdown: Success.");
break; // Success.
}
}
}
else {
@ -1485,7 +1528,7 @@ testFuncs.authentication_parameters = function (options) {
return results;
};
var internalMembers = ["code", "error", "status", "duration", "failed", "total"];
var internalMembers = ["code", "error", "status", "duration", "failed", "total", "crashed", "all_ok", "ok", "message"];
function unitTestPrettyPrintResults(r) {
var testrun;
@ -1498,13 +1541,13 @@ function unitTestPrettyPrintResults(r) {
try {
for (testrun in r) {
if (r.hasOwnProperty(testrun) && (testrun !== 'all_ok')) {
if (r.hasOwnProperty(testrun) && (internalMembers.indexOf(testrun) === -1)) {
var isSuccess = true;
var oneOutput = "";
oneOutput = "Testrun: " + testrun + "\n";
for (test in r[testrun]) {
if (r[testrun].hasOwnProperty(test) && (test !== 'ok')) {
if (r[testrun].hasOwnProperty(test) && (internalMembers.indexOf(test) === -1)) {
if (r[testrun][test].status) {
oneOutput += " [Success] " + test + "\n";
}
@ -1599,6 +1642,7 @@ function UnitTest (which, options) {
results.all_ok = allok;
}
results.all_ok = allok;
results.crashed = serverCrashed;
if (allok) {
cleanupDBDirectories(options);
}
@ -1634,6 +1678,7 @@ function UnitTest (which, options) {
}
r.ok = ok;
results.all_ok = ok;
results.crashed = serverCrashed;
if (allok) {
cleanupDBDirectories(options);
@ -1652,6 +1697,7 @@ function UnitTest (which, options) {
}
}
exports.internalMembers = internalMembers;
exports.testFuncs = testFuncs;
exports.UnitTest = UnitTest;
exports.unitTestPrettyPrintResults = unitTestPrettyPrintResults;

View File

@ -1,7 +1,9 @@
/*jshint unused: false */
/*global require, start_pretty_print */
var internalMembers = ["code", "error", "status", "duration", "failed", "total", "message"];
var UnitTest = require("org/arangodb/testing");
var internalMembers = UnitTest.internalMembers;
var fs = require("fs");
var print = require("internal").print;
@ -46,10 +48,10 @@ function resultsToXml(results, baseName) {
}
for (var testrun in results) {
if ((testrun !== "all_ok") && (results.hasOwnProperty(testrun))) {
if ((internalMembers.indexOf(testrun) === -1) && (results.hasOwnProperty(testrun))) {
for (var test in results[testrun]) {
if ((test !== "ok") &&
if ((internalMembers.indexOf(test) === -1) &&
results[testrun].hasOwnProperty(test) &&
!results[testrun][test].hasOwnProperty('skipped')) {
@ -127,7 +129,6 @@ function main (argv) {
}
}
options.jsonReply = true;
var UnitTest = require("org/arangodb/testing");
start_pretty_print();
try {
@ -139,7 +140,7 @@ function main (argv) {
print(JSON.stringify(r));
}
fs.write("UNITTEST_RESULT.json",JSON.stringify(r));
fs.write("UNITTEST_RESULT_SUMMARY.txt",JSON.stringify(r.all_ok));
fs.write("UNITTEST_RESULT_SUMMARY.txt",JSON.stringify(!r.crashed));
try {
resultsToXml(r, "UNITTEST_RESULT_");
}