1
0
Fork 0

added tests for task management

This commit is contained in:
Jan Steemann 2014-05-10 00:43:14 +02:00
parent 1168f089da
commit cfc2d407d7
16 changed files with 4923 additions and 136 deletions

View File

@ -1,13 +1,19 @@
v2.1.0 (XXXX-XX-XX) v2.1.0 (XXXX-XX-XX)
------------------- -------------------
* added server-side periodic task management functions:
- internal.executeTask(): executes a periodic task
- internal.deleteTask(): removes a periodic task
- internal.getTasks(): lists all periodic tasks
the previous undocumented function `internal.definePeriodic` is now
deprecated and will be removed in a future release.
* decrease the size of some seldomly used system collections on creation. * decrease the size of some seldomly used system collections on creation.
This will make these collections use less disk space and mapped memory. This will make these collections use less disk space and mapped memory.
* fixed issue #848: db.someEdgeCollection.inEdge does not return correct
value when called the 2nd time after a .save to the edge collection
* added AQL date functions * added AQL date functions
* added AQL FLATTEN() and FLATTEN_RECURSIVE() list functions * added AQL FLATTEN() and FLATTEN_RECURSIVE() list functions
@ -127,6 +133,9 @@ v2.0.8 (XXXX-XX-XX)
watch API crashed it. This was because atomic operations worked on data watch API crashed it. This was because atomic operations worked on data
structures that were not properly aligned on 32 bit systems. structures that were not properly aligned on 32 bit systems.
* fixed issue #848: db.someEdgeCollection.inEdge does not return correct
value when called the 2nd time after a .save to the edge collection
v2.0.7 (2014-05-05) v2.0.7 (2014-05-05)
------------------- -------------------

View File

@ -370,6 +370,7 @@ SHELL_COMMON = \
SHELL_SERVER_ONLY = \ SHELL_SERVER_ONLY = \
@top_srcdir@/js/server/tests/shell-sharding-helpers.js \ @top_srcdir@/js/server/tests/shell-sharding-helpers.js \
@top_srcdir@/js/server/tests/shell-compaction-noncluster.js \ @top_srcdir@/js/server/tests/shell-compaction-noncluster.js \
@top_srcdir@/js/server/tests/shell-tasks.js \
@top_srcdir@/js/server/tests/shell-transactions-noncluster.js \ @top_srcdir@/js/server/tests/shell-transactions-noncluster.js \
@top_srcdir@/js/server/tests/shell-routing.js \ @top_srcdir@/js/server/tests/shell-routing.js \
@top_srcdir@/js/server/tests/shell-any-noncluster.js \ @top_srcdir@/js/server/tests/shell-any-noncluster.js \

View File

@ -28,7 +28,9 @@
#include "V8PeriodicJob.h" #include "V8PeriodicJob.h"
#include "Basics/StringUtils.h" #include "Basics/StringUtils.h"
#include "BasicsC/json.h"
#include "BasicsC/logging.h" #include "BasicsC/logging.h"
#include "V8/v8-conv.h"
#include "V8/v8-utils.h" #include "V8/v8-utils.h"
#include "V8Server/ApplicationV8.h" #include "V8Server/ApplicationV8.h"
#include "VocBase/vocbase.h" #include "VocBase/vocbase.h"
@ -48,15 +50,13 @@ using namespace triagens::arango;
V8PeriodicJob::V8PeriodicJob (TRI_vocbase_t* vocbase, V8PeriodicJob::V8PeriodicJob (TRI_vocbase_t* vocbase,
ApplicationV8* v8Dealer, ApplicationV8* v8Dealer,
string const& module, string const& command,
string const& func, TRI_json_t const* parameters)
string const& parameter)
: Job("V8 Periodic Job"), : Job("V8 Periodic Job"),
_vocbase(vocbase), _vocbase(vocbase),
_v8Dealer(v8Dealer), _v8Dealer(v8Dealer),
_module(module), _command(command),
_func(func), _parameters(parameters),
_parameter(parameter),
_canceled(0) { _canceled(0) {
} }
@ -101,17 +101,43 @@ Job::status_t V8PeriodicJob::work () {
// now execute the function within this context // now execute the function within this context
{ {
v8::HandleScope scope; v8::HandleScope scope;
// get built-in Function constructor (see ECMA-262 5th edition 15.3.2)
v8::Handle<v8::Object> current = v8::Context::GetCurrent()->Global();
v8::Local<v8::Function> ctor = v8::Local<v8::Function>::Cast(current->Get(v8::String::New("Function")));
// Invoke Function constructor to create function with the given body and no arguments
v8::Handle<v8::Value> args[2] = { v8::String::New("params"), v8::String::New(_command.c_str(), _command.size()) };
v8::Local<v8::Object> function = ctor->NewInstance(2, args);
string module = StringUtils::escape(_module, "\""); v8::Handle<v8::Function> action = v8::Local<v8::Function>::Cast(function);
string func = StringUtils::escape(_func, "\"");
string parameter = StringUtils::escape(_parameter, "\""); if (action.IsEmpty()) {
_v8Dealer->exitContext(context);
string command = "(require(\"" + module + "\")[\"" + func + "\"])(\"" + parameter + "\")"; // TODO: adjust exit code??
return status_t(JOB_DONE);
TRI_ExecuteJavaScriptString(context->_context, }
v8::String::New(command.c_str(), (int) command.size()),
v8::String::New("periodic function"), v8::Handle<v8::Value> fArgs;
true); if (_parameters != 0) {
fArgs = TRI_ObjectJson(_parameters);
}
else {
fArgs = v8::Undefined();
}
// call the function
v8::TryCatch tryCatch;
action->Call(current, 1, &fArgs);
if (tryCatch.HasCaught()) {
if (tryCatch.CanContinue()) {
TRI_LogV8Exception(&tryCatch);
}
else {
LOG_WARNING("caught non-printable exception in periodic task");
}
}
} }
_v8Dealer->exitContext(context); _v8Dealer->exitContext(context);

View File

@ -31,6 +31,10 @@
#include "Dispatcher/Job.h" #include "Dispatcher/Job.h"
#include "VocBase/vocbase.h" #include "VocBase/vocbase.h"
extern "C" {
struct TRI_json_s;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- class V8PeriodicJob // --SECTION-- class V8PeriodicJob
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -56,9 +60,8 @@ namespace triagens {
V8PeriodicJob (TRI_vocbase_t*, V8PeriodicJob (TRI_vocbase_t*,
ApplicationV8*, ApplicationV8*,
string const& module, std::string const&,
string const& func, struct TRI_json_s const*);
string const& parameter);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- Job methods // --SECTION-- Job methods
@ -76,7 +79,7 @@ namespace triagens {
/// {@inheritDoc} /// {@inheritDoc}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const string& queue (); const std::string& queue ();
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc} /// {@inheritDoc}
@ -127,22 +130,16 @@ namespace triagens {
ApplicationV8* _v8Dealer; ApplicationV8* _v8Dealer;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief module name /// @brief the command to execute
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const std::string _module; std::string const _command;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief function name /// @brief paramaters
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const std::string _func; struct TRI_json_s const* _parameters;
////////////////////////////////////////////////////////////////////////////////
/// @brief paramater string
////////////////////////////////////////////////////////////////////////////////
const std::string _parameter;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief cancel flag /// @brief cancel flag

View File

@ -27,8 +27,10 @@
#include "V8PeriodicTask.h" #include "V8PeriodicTask.h"
#include "BasicsC/json.h"
#include "Dispatcher/Dispatcher.h" #include "Dispatcher/Dispatcher.h"
#include "Scheduler/Scheduler.h" #include "Scheduler/Scheduler.h"
#include "V8/v8-conv.h"
#include "V8Server/V8PeriodicJob.h" #include "V8Server/V8PeriodicJob.h"
#include "VocBase/server.h" #include "VocBase/server.h"
@ -52,17 +54,15 @@ V8PeriodicTask::V8PeriodicTask (string const& id,
Dispatcher* dispatcher, Dispatcher* dispatcher,
double offset, double offset,
double period, double period,
string const& module, string const& command,
string const& func, TRI_json_t* parameters)
string const& parameter)
: Task(id, name), : Task(id, name),
PeriodicTask(offset, period), PeriodicTask(offset, period),
_vocbase(vocbase), _vocbase(vocbase),
_v8Dealer(v8Dealer), _v8Dealer(v8Dealer),
_dispatcher(dispatcher), _dispatcher(dispatcher),
_module(module), _command(command),
_func(func), _parameters(parameters) {
_parameter(parameter) {
assert(vocbase != 0); assert(vocbase != 0);
@ -77,12 +77,30 @@ V8PeriodicTask::V8PeriodicTask (string const& id,
V8PeriodicTask::~V8PeriodicTask () { V8PeriodicTask::~V8PeriodicTask () {
// decrease reference counter for the database used // decrease reference counter for the database used
TRI_ReleaseVocBase(_vocbase); TRI_ReleaseVocBase(_vocbase);
if (_parameters != 0) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _parameters);
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- PeriodicTask methods // --SECTION-- PeriodicTask methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief get a task specific description in JSON format
////////////////////////////////////////////////////////////////////////////////
void V8PeriodicTask::getDescription (TRI_json_t* json) {
PeriodicTask::getDescription(json);
TRI_json_t* cmd = TRI_CreateString2CopyJson(TRI_UNKNOWN_MEM_ZONE, _command.c_str(), _command.size());
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "command", cmd);
TRI_json_t* db = TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, _vocbase->_name);
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "database", db);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief handles the next tick /// @brief handles the next tick
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -91,10 +109,9 @@ bool V8PeriodicTask::handlePeriod () {
V8PeriodicJob* job = new V8PeriodicJob( V8PeriodicJob* job = new V8PeriodicJob(
_vocbase, _vocbase,
_v8Dealer, _v8Dealer,
_module, "(function (params) { " + _command + " } )(params);",
_func, _parameters);
_parameter);
_dispatcher->addJob(job); _dispatcher->addJob(job);
return true; return true;

View File

@ -32,6 +32,10 @@
#include "VocBase/vocbase.h" #include "VocBase/vocbase.h"
extern "C" {
struct TRI_json_s;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- class V8PeriodicTask // --SECTION-- class V8PeriodicTask
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -65,9 +69,8 @@ namespace triagens {
rest::Dispatcher*, rest::Dispatcher*,
double, double,
double, double,
string const&, std::string const&,
string const&, struct TRI_json_s*);
string const&);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief destructor /// @brief destructor
@ -81,6 +84,12 @@ namespace triagens {
protected: protected:
////////////////////////////////////////////////////////////////////////////////
/// @brief get a task specific description in JSON format
////////////////////////////////////////////////////////////////////////////////
virtual void getDescription (struct TRI_json_s*);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the task is user-defined /// @brief whether or not the task is user-defined
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -126,22 +135,16 @@ namespace triagens {
rest::Dispatcher* _dispatcher; rest::Dispatcher* _dispatcher;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief module name /// @brief command to execute
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string const _module; std::string const _command;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief function name /// @brief paramaters
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string const _func; struct TRI_json_s* _parameters;
////////////////////////////////////////////////////////////////////////////////
/// @brief paramater string
////////////////////////////////////////////////////////////////////////////////
std::string const _parameter;
}; };
} }

View File

@ -48,6 +48,7 @@
#include "V8Server/V8PeriodicTask.h" #include "V8Server/V8PeriodicTask.h"
#include "V8Server/v8-vocbase.h" #include "V8Server/v8-vocbase.h"
#include "VocBase/server.h" #include "VocBase/server.h"
#include "VocBase/vocbase.h"
#ifdef TRI_ENABLE_CLUSTER #ifdef TRI_ENABLE_CLUSTER
@ -75,12 +76,6 @@ static TRI_action_result_t ExecuteActionVocbase (TRI_vocbase_t* vocbase,
// --SECTION-- private variables // --SECTION-- private variables
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief global VocBase
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_t* GlobalVocbase = 0;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief global V8 dealer /// @brief global V8 dealer
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1153,7 +1148,7 @@ static v8::Handle<v8::Value> JS_ClusterTest (v8::Arguments const& argv) {
#endif #endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief defines and executes a periodic task /// @brief defines and executes a task
/// ///
/// @FUN{internal.executeTask(@FA{task})} /// @FUN{internal.executeTask(@FA{task})}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1203,70 +1198,52 @@ static v8::Handle<v8::Value> JS_ExecuteTask (v8::Arguments const& argv) {
// period in seconds & count // period in seconds & count
double period = 0.0; double period = 0.0;
int64_t count;
if (obj->HasOwnProperty(TRI_V8_SYMBOL("period"))) { if (obj->HasOwnProperty(TRI_V8_SYMBOL("period"))) {
period = TRI_ObjectToDouble(obj->Get(TRI_V8_SYMBOL("period"))); period = TRI_ObjectToDouble(obj->Get(TRI_V8_SYMBOL("period")));
}
if (period <= 0.0) { if (period <= 0.0) {
TRI_V8_EXCEPTION_PARAMETER(scope, "task period must be specified and positive"); TRI_V8_EXCEPTION_PARAMETER(scope, "task period must be specified and positive");
} }
if (obj->HasOwnProperty(TRI_V8_SYMBOL("count"))) {
// check for count attribute // extract the command
count = TRI_ObjectToInt64(obj->Get(TRI_V8_SYMBOL("count"))); if (! obj->HasOwnProperty(TRI_V8_SYMBOL("command"))) {
TRI_V8_EXCEPTION_PARAMETER(scope, "command must be specified");
}
if (count <= 0) { string command;
TRI_V8_EXCEPTION_PARAMETER(scope, "task execution count must be specified and positive"); if (obj->Get(TRI_V8_SYMBOL("command"))->IsFunction()) {
} // need to add ( and ) around function because call would otherwise break
} command = "(" + TRI_ObjectToString(obj->Get(TRI_V8_SYMBOL("command"))) + ")(params)";
else {
// no count specified. this means the job will go on forever
count = -1;
}
} }
else { else {
count = 1; // single execution command = TRI_ObjectToString(obj->Get(TRI_V8_SYMBOL("command")));
} }
assert(count == -1 || count > 0); // extract the parameters
TRI_json_t* parameters = 0;
// TODO: count is currently not used if (obj->HasOwnProperty(TRI_V8_SYMBOL("params"))) {
parameters = TRI_ObjectToJson(obj->Get(TRI_V8_SYMBOL("params")));
// extract the module name
if (! obj->HasOwnProperty(TRI_V8_SYMBOL("module"))) {
TRI_V8_EXCEPTION_PARAMETER(scope, "module must be specified");
}
string const module = TRI_ObjectToString(obj->Get(TRI_V8_SYMBOL("module")));
// extract the function name
if (! obj->HasOwnProperty(TRI_V8_SYMBOL("funcname"))) {
TRI_V8_EXCEPTION_PARAMETER(scope, "funcname must be specified");
}
string const func = TRI_ObjectToString(obj->Get(TRI_V8_SYMBOL("funcname")));
// extract the parameter
string parameter;
if (obj->HasOwnProperty(TRI_V8_SYMBOL("parameter"))) {
parameter = TRI_ObjectToString(obj->Get(TRI_V8_SYMBOL("parameter")));
} }
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
// create a new periodic task // create a new periodic task
V8PeriodicTask* task = new V8PeriodicTask( V8PeriodicTask* task = new V8PeriodicTask(
id, id,
name, name,
GlobalVocbase, static_cast<TRI_vocbase_t*>(v8g->_vocbase),
GlobalV8Dealer, GlobalV8Dealer,
GlobalScheduler, GlobalScheduler,
GlobalDispatcher, GlobalDispatcher,
offset, offset,
period, period,
module, command,
func, parameters);
parameter);
int res = GlobalScheduler->registerTask(task); int res = GlobalScheduler->registerTask(task);
@ -1276,17 +1253,21 @@ static v8::Handle<v8::Value> JS_ExecuteTask (v8::Arguments const& argv) {
TRI_V8_EXCEPTION(scope, res); TRI_V8_EXCEPTION(scope, res);
} }
// return the result // get the JSON representation of the task
v8::Handle<v8::Object> result = v8::Object::New(); TRI_json_t* json = task->toJson();
result->Set(TRI_V8_SYMBOL("id"), v8::String::New(id.c_str(), (int) id.size())); if (json != 0) {
result->Set(TRI_V8_SYMBOL("name"), v8::String::New(name.c_str(), (int) name.size())); v8::Handle<v8::Value> result = TRI_ObjectJson(json);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
return scope.Close(result); return scope.Close(result);
}
TRI_V8_EXCEPTION(scope, TRI_ERROR_INTERNAL);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief deletes a periodic task /// @brief deletes a task
/// ///
/// @FUN{internal.deleteTask(@FA{id})} /// @FUN{internal.deleteTask(@FA{id})}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1298,7 +1279,17 @@ static v8::Handle<v8::Value> JS_DeleteTask (v8::Arguments const& argv) {
TRI_V8_EXCEPTION_USAGE(scope, "deleteTask(<id>)"); TRI_V8_EXCEPTION_USAGE(scope, "deleteTask(<id>)");
} }
string const id = TRI_ObjectToString(argv[0]); string id;
if (argv[0]->IsObject()) {
// extract "id" from object
v8::Handle<v8::Object> obj = argv[0].As<v8::Object>();
if (obj->Has(TRI_V8_SYMBOL("id"))) {
id = TRI_ObjectToString(obj->Get(TRI_V8_SYMBOL("id")));
}
}
else {
id = TRI_ObjectToString(argv[0]);
}
if (GlobalScheduler == 0 || GlobalDispatcher == 0) { if (GlobalScheduler == 0 || GlobalDispatcher == 0) {
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_INTERNAL, "no scheduler found"); TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_INTERNAL, "no scheduler found");
@ -1314,7 +1305,7 @@ static v8::Handle<v8::Value> JS_DeleteTask (v8::Arguments const& argv) {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief gets all registered periodic tasks /// @brief gets all registered tasks
/// ///
/// @FUN{internal.getTasks()} /// @FUN{internal.getTasks()}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -1357,7 +1348,6 @@ void TRI_InitV8Actions (v8::Handle<v8::Context> context,
ApplicationV8* applicationV8) { ApplicationV8* applicationV8) {
v8::HandleScope scope; v8::HandleScope scope;
GlobalVocbase = vocbase;
GlobalV8Dealer = applicationV8; GlobalV8Dealer = applicationV8;
// check the isolate // check the isolate

View File

@ -758,6 +758,13 @@
if (typeof SYS_EXECUTE_TASK !== "undefined") { if (typeof SYS_EXECUTE_TASK !== "undefined") {
exports.executeTask = SYS_EXECUTE_TASK; exports.executeTask = SYS_EXECUTE_TASK;
delete SYS_EXECUTE_TASK; delete SYS_EXECUTE_TASK;
// TODO: remove this in next release
exports.definePeriodic = function (offset, period, module, funcname) {
require("console").warn("definePeriodic() is deprecated. please use executeTask() instead");
var command = "require('" + module + "')." + funcname + "();"
exports.executeTask({ offset: offset, period: period, command: command });
};
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -758,6 +758,13 @@
if (typeof SYS_EXECUTE_TASK !== "undefined") { if (typeof SYS_EXECUTE_TASK !== "undefined") {
exports.executeTask = SYS_EXECUTE_TASK; exports.executeTask = SYS_EXECUTE_TASK;
delete SYS_EXECUTE_TASK; delete SYS_EXECUTE_TASK;
// TODO: remove this in next release
exports.definePeriodic = function (offset, period, module, funcname) {
require("console").warn("definePeriodic() is deprecated. please use executeTask() instead");
var command = "require('" + module + "')." + funcname + "();";
exports.executeTask({ offset: offset, period: period, command: command });
};
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -54,10 +54,10 @@ if (cluster.isCluster()) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief reloads the user authentication data /// @brief creates a statistics entry
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
exports.historian = function (param) { exports.historian = function () {
"use strict"; "use strict";
try { try {

View File

@ -58,9 +58,7 @@ var Buffer = require("buffer").Buffer;
name: "statistics-collector", name: "statistics-collector",
offset: 1, offset: 1,
period: 10, period: 10,
module: "org/arangodb/statistics", command: "require('org/arangodb/statistics').historian();"
funcname: "historian",
parameter: "_statistics"
}); });
} }
}()); }());

View File

@ -0,0 +1,433 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief test the task manager
///
/// @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 Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var jsunity = require("jsunity");
var arangodb = require("org/arangodb");
var internal = require("internal");
var db = arangodb.db;
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function TaskSuite () {
var cn = "UnitTestsTasks";
var cleanTasks = function () {
internal.getTasks().forEach(function(task) {
if (task.id.match(/^UnitTest/) || task.name.match(/^UnitTest/)) {
internal.deleteTask(task);
}
});
};
var getTasks = function () {
var sorter = function (l, r) {
if (l.id !== r.id) {
return (l.id < r.id ? -1 : 1);
}
return 0;
};
return internal.getTasks().filter(function (task) {
return task.name.match(/^UnitTest/);
}).sort(sorter);
};
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
cleanTasks();
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
cleanTasks();
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task without an id
////////////////////////////////////////////////////////////////////////////////
testCreateTaskNoId : function () {
try {
internal.executeTask({ });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task without a period
////////////////////////////////////////////////////////////////////////////////
testCreateTaskNoPeriod : function () {
try {
internal.executeTask({ id: "UnitTestsNoPeriod", command: "1+1;" });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task with an invalid period
////////////////////////////////////////////////////////////////////////////////
testCreateTaskInvalidPeriod1 : function () {
try {
internal.executeTask({ id: "UnitTestsNoPeriod", period: -1, command: "1+1;" });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task with an invalid period
////////////////////////////////////////////////////////////////////////////////
testCreateTaskInvalidPeriod2 : function () {
try {
internal.executeTask({ id: "UnitTestsNoPeriod", period: 0, command: "1+1;" });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task without a command
////////////////////////////////////////////////////////////////////////////////
testCreateTaskNoCommand : function () {
try {
internal.executeTask({ id: "UnitTestsNoPeriod", period: 1 });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task with an automatic id
////////////////////////////////////////////////////////////////////////////////
testCreateTaskAutomaticId : function () {
var task = internal.executeTask({ name: "UnitTests1", command: "1+1;", period: 1 });
assertMatch(/^\d+$/, task.id);
assertEqual("UnitTests1", task.name);
assertEqual("periodic", task.type);
assertEqual(1, task.period);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task with a duplicate id
////////////////////////////////////////////////////////////////////////////////
testCreateTaskDuplicateId : function () {
var task = internal.executeTask({ id: "UnitTests1", name: "UnitTests1", command: "1+1;", period: 1 });
assertEqual("UnitTests1", task.id);
assertEqual("UnitTests1", task.name);
assertEqual("periodic", task.type);
assertEqual(1, task.period);
try {
internal.executeTask({ id: "UnitTests1", name: "UnitTests1", command: "1+1;", period: 1 });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_TASK_DUPLICATE_ID.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief remove without an id
////////////////////////////////////////////////////////////////////////////////
testCreateTaskRemoveWithoutId : function () {
try {
internal.deleteTask();
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_BAD_PARAMETER.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task and remove it
////////////////////////////////////////////////////////////////////////////////
testCreateTaskRemoveByTask : function () {
var task = internal.executeTask({ id: "UnitTests1", name: "UnitTests1", command: "1+1;", period: 1 });
assertEqual("UnitTests1", task.id);
assertEqual("UnitTests1", task.name);
assertEqual("periodic", task.type);
assertEqual(1, task.period);
internal.deleteTask(task);
try {
// deleting again should fail
internal.deleteTask(task);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_TASK_NOT_FOUND.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task and remove it
////////////////////////////////////////////////////////////////////////////////
testCreateTaskRemoveById : function () {
var task = internal.executeTask({ id: "UnitTests1", name: "UnitTests1", command: "1+1;", period: 1 });
assertEqual("UnitTests1", task.id);
assertEqual("UnitTests1", task.name);
assertEqual("periodic", task.type);
assertEqual(1, task.period);
internal.deleteTask(task.id);
try {
// deleting again should fail
internal.deleteTask(task.id);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_TASK_NOT_FOUND.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief get list of tasks
////////////////////////////////////////////////////////////////////////////////
testGetTasks : function () {
var task1 = internal.executeTask({
id: "UnitTests1",
name: "UnitTests1",
command: "1+1;",
period: 1
});
var task2 = internal.executeTask({
id: "UnitTests2",
name: "UnitTests2",
command: "2+2;",
period: 2
});
var tasks = getTasks();
assertEqual(2, tasks.length);
assertEqual(task1.id, tasks[0].id);
assertEqual(task1.name, tasks[0].name);
assertEqual(task1.type, tasks[0].type);
assertEqual(task1.period, tasks[0].period);
assertEqual(task1.database, tasks[0].database);
assertEqual(task2.id, tasks[1].id);
assertEqual(task2.name, tasks[1].name);
assertEqual(task2.type, tasks[1].type);
assertEqual(task2.period, tasks[1].period);
assertEqual(task2.database, tasks[1].database);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief get list of tasks pre and post task deletion
////////////////////////////////////////////////////////////////////////////////
testGetTasks : function () {
var task1 = internal.executeTask({
id: "UnitTests1",
name: "UnitTests1",
command: "1+1;",
period: 1
});
var tasks = getTasks();
assertEqual(1, tasks.length);
assertEqual(task1.id, tasks[0].id);
assertEqual(task1.name, tasks[0].name);
assertEqual(task1.type, tasks[0].type);
assertEqual(task1.period, tasks[0].period);
assertEqual(task1.database, tasks[0].database);
var task2 = internal.executeTask({
id: "UnitTests2",
name: "UnitTests2",
command: "2+2;",
period: 2
});
tasks = getTasks();
assertEqual(2, tasks.length);
assertEqual(task1.id, tasks[0].id);
assertEqual(task1.name, tasks[0].name);
assertEqual(task1.type, tasks[0].type);
assertEqual(task1.period, tasks[0].period);
assertEqual(task1.database, tasks[0].database);
assertEqual(task2.id, tasks[1].id);
assertEqual(task2.name, tasks[1].name);
assertEqual(task2.type, tasks[1].type);
assertEqual(task2.period, tasks[1].period);
assertEqual(task2.database, tasks[1].database);
internal.deleteTask(task1);
tasks = getTasks();
assertEqual(1, tasks.length);
assertEqual(task2.id, tasks[0].id);
assertEqual(task2.name, tasks[0].name);
assertEqual(task2.type, tasks[0].type);
assertEqual(task2.period, tasks[0].period);
assertEqual(task2.database, tasks[0].database);
internal.deleteTask(task2);
tasks = getTasks();
assertEqual(0, tasks.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task and run it
////////////////////////////////////////////////////////////////////////////////
testCreateStringCommand : function () {
db._drop(cn);
db._create(cn);
assertEqual(0, db[cn].count());
var command = "require('internal').db." + cn + ".save({ value: params });";
var task = internal.executeTask({
id: "UnitTests1",
name: "UnitTests1",
command: command,
period: 1,
params: 23
});
assertEqual("UnitTests1", task.id);
assertEqual("UnitTests1", task.name);
assertEqual("periodic", task.type);
assertEqual(1, task.period);
assertEqual("_system", task.database);
internal.wait(5);
internal.deleteTask(task);
assertTrue(db[cn].count() > 0);
assertTrue(db[cn].byExample({ value: 23 }).count() > 0);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create a task and run it
////////////////////////////////////////////////////////////////////////////////
testCreateFunctionCommand : function () {
db._drop(cn);
db._create(cn);
assertEqual(0, db[cn].count());
var command = function (params) {
require('internal').db[params.cn].save({ value: params.val });
};
var task = internal.executeTask({
id: "UnitTests1",
name: "UnitTests1",
command: command,
period: 1,
params: { cn: cn, val: 42 }
});
assertEqual("UnitTests1", task.id);
assertEqual("UnitTests1", task.name);
assertEqual("periodic", task.type);
assertEqual(1, task.period);
assertEqual("_system", task.database);
internal.wait(5);
internal.deleteTask(task);
assertTrue(db[cn].count() > 0);
assertTrue(db[cn].byExample({ value: 23 }).count() === 0);
assertTrue(db[cn].byExample({ value: 42 }).count() > 0);
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- main
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief executes the test suite
////////////////////////////////////////////////////////////////////////////////
jsunity.run(TaskSuite);
return jsunity.done();
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -238,16 +238,11 @@ TRI_json_t* Scheduler::getUserTasks () {
Task* task = (*i).first; Task* task = (*i).first;
if (task->isUserDefined()) { if (task->isUserDefined()) {
TRI_json_t* obj = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE); TRI_json_t* obj = task->toJson();
if (obj != 0) { if (obj != 0) {
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, obj, "id", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, task->id().c_str())); TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, json, obj);
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, obj, "name", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, task->name().c_str()));
task->getDescription(obj);
} }
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, json, obj);
} }
++i; ++i;

View File

@ -59,9 +59,26 @@ Task::~Task () {
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// protected methods // public methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief get a JSON representation of the task
////////////////////////////////////////////////////////////////////////////////
TRI_json_t* Task::toJson () {
TRI_json_t* json = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE);
if (json != 0) {
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "id", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, this->id().c_str()));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, json, "name", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, this->name().c_str()));
this->getDescription(json);
}
return json;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the task is user-defined /// @brief whether or not the task is user-defined
/// note: this function may be overridden /// note: this function may be overridden
@ -71,14 +88,6 @@ bool Task::isUserDefined () const {
return false; return false;
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief get a task specific description in JSON format
/// this does nothing for basic tasks, but derived classes may override it
////////////////////////////////////////////////////////////////////////////////
void Task::getDescription (TRI_json_t* json) {
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief allow thread to run on slave event loop /// @brief allow thread to run on slave event loop
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -87,3 +96,15 @@ bool Task::needsMainEventLoop () const {
return false; return false;
} }
// -----------------------------------------------------------------------------
// protected methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief get a task specific description in JSON format
/// this does nothing for basic tasks, but derived classes may override it
////////////////////////////////////////////////////////////////////////////////
void Task::getDescription (TRI_json_t* json) {
}

View File

@ -99,10 +99,10 @@ namespace triagens {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief get a task specific description in JSON format /// @brief get a JSON representation of the task
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
virtual void getDescription (struct TRI_json_s*); struct TRI_json_s* toJson ();
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the task is a user task /// @brief whether or not the task is a user task
@ -138,6 +138,12 @@ namespace triagens {
protected: protected:
////////////////////////////////////////////////////////////////////////////////
/// @brief get a task specific description in JSON format
////////////////////////////////////////////////////////////////////////////////
virtual void getDescription (struct TRI_json_s*);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief called to set up the callback information /// @brief called to set up the callback information
/// ///