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)
-------------------
* 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.
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 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
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)
-------------------

View File

@ -370,6 +370,7 @@ SHELL_COMMON = \
SHELL_SERVER_ONLY = \
@top_srcdir@/js/server/tests/shell-sharding-helpers.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-routing.js \
@top_srcdir@/js/server/tests/shell-any-noncluster.js \

View File

@ -28,7 +28,9 @@
#include "V8PeriodicJob.h"
#include "Basics/StringUtils.h"
#include "BasicsC/json.h"
#include "BasicsC/logging.h"
#include "V8/v8-conv.h"
#include "V8/v8-utils.h"
#include "V8Server/ApplicationV8.h"
#include "VocBase/vocbase.h"
@ -48,15 +50,13 @@ using namespace triagens::arango;
V8PeriodicJob::V8PeriodicJob (TRI_vocbase_t* vocbase,
ApplicationV8* v8Dealer,
string const& module,
string const& func,
string const& parameter)
string const& command,
TRI_json_t const* parameters)
: Job("V8 Periodic Job"),
_vocbase(vocbase),
_v8Dealer(v8Dealer),
_module(module),
_func(func),
_parameter(parameter),
_command(command),
_parameters(parameters),
_canceled(0) {
}
@ -101,17 +101,43 @@ Job::status_t V8PeriodicJob::work () {
// now execute the function within this context
{
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, "\"");
string func = StringUtils::escape(_func, "\"");
string parameter = StringUtils::escape(_parameter, "\"");
string command = "(require(\"" + module + "\")[\"" + func + "\"])(\"" + parameter + "\")";
TRI_ExecuteJavaScriptString(context->_context,
v8::String::New(command.c_str(), (int) command.size()),
v8::String::New("periodic function"),
true);
v8::Handle<v8::Function> action = v8::Local<v8::Function>::Cast(function);
if (action.IsEmpty()) {
_v8Dealer->exitContext(context);
// TODO: adjust exit code??
return status_t(JOB_DONE);
}
v8::Handle<v8::Value> fArgs;
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);

View File

@ -31,6 +31,10 @@
#include "Dispatcher/Job.h"
#include "VocBase/vocbase.h"
extern "C" {
struct TRI_json_s;
}
// -----------------------------------------------------------------------------
// --SECTION-- class V8PeriodicJob
// -----------------------------------------------------------------------------
@ -56,9 +60,8 @@ namespace triagens {
V8PeriodicJob (TRI_vocbase_t*,
ApplicationV8*,
string const& module,
string const& func,
string const& parameter);
std::string const&,
struct TRI_json_s const*);
// -----------------------------------------------------------------------------
// --SECTION-- Job methods
@ -76,7 +79,7 @@ namespace triagens {
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////
const string& queue ();
const std::string& queue ();
////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
@ -127,22 +130,16 @@ namespace triagens {
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;
////////////////////////////////////////////////////////////////////////////////
/// @brief paramater string
////////////////////////////////////////////////////////////////////////////////
const std::string _parameter;
struct TRI_json_s const* _parameters;
////////////////////////////////////////////////////////////////////////////////
/// @brief cancel flag

View File

@ -27,8 +27,10 @@
#include "V8PeriodicTask.h"
#include "BasicsC/json.h"
#include "Dispatcher/Dispatcher.h"
#include "Scheduler/Scheduler.h"
#include "V8/v8-conv.h"
#include "V8Server/V8PeriodicJob.h"
#include "VocBase/server.h"
@ -52,17 +54,15 @@ V8PeriodicTask::V8PeriodicTask (string const& id,
Dispatcher* dispatcher,
double offset,
double period,
string const& module,
string const& func,
string const& parameter)
string const& command,
TRI_json_t* parameters)
: Task(id, name),
PeriodicTask(offset, period),
_vocbase(vocbase),
_v8Dealer(v8Dealer),
_dispatcher(dispatcher),
_module(module),
_func(func),
_parameter(parameter) {
_command(command),
_parameters(parameters) {
assert(vocbase != 0);
@ -77,12 +77,30 @@ V8PeriodicTask::V8PeriodicTask (string const& id,
V8PeriodicTask::~V8PeriodicTask () {
// decrease reference counter for the database used
TRI_ReleaseVocBase(_vocbase);
if (_parameters != 0) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _parameters);
}
}
// -----------------------------------------------------------------------------
// --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
////////////////////////////////////////////////////////////////////////////////
@ -91,10 +109,9 @@ bool V8PeriodicTask::handlePeriod () {
V8PeriodicJob* job = new V8PeriodicJob(
_vocbase,
_v8Dealer,
_module,
_func,
_parameter);
"(function (params) { " + _command + " } )(params);",
_parameters);
_dispatcher->addJob(job);
return true;

View File

@ -32,6 +32,10 @@
#include "VocBase/vocbase.h"
extern "C" {
struct TRI_json_s;
}
// -----------------------------------------------------------------------------
// --SECTION-- class V8PeriodicTask
// -----------------------------------------------------------------------------
@ -65,9 +69,8 @@ namespace triagens {
rest::Dispatcher*,
double,
double,
string const&,
string const&,
string const&);
std::string const&,
struct TRI_json_s*);
////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
@ -81,6 +84,12 @@ namespace triagens {
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
////////////////////////////////////////////////////////////////////////////////
@ -126,22 +135,16 @@ namespace triagens {
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;
////////////////////////////////////////////////////////////////////////////////
/// @brief paramater string
////////////////////////////////////////////////////////////////////////////////
std::string const _parameter;
struct TRI_json_s* _parameters;
};
}

View File

@ -48,6 +48,7 @@
#include "V8Server/V8PeriodicTask.h"
#include "V8Server/v8-vocbase.h"
#include "VocBase/server.h"
#include "VocBase/vocbase.h"
#ifdef TRI_ENABLE_CLUSTER
@ -75,12 +76,6 @@ static TRI_action_result_t ExecuteActionVocbase (TRI_vocbase_t* vocbase,
// --SECTION-- private variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief global VocBase
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_t* GlobalVocbase = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief global V8 dealer
////////////////////////////////////////////////////////////////////////////////
@ -1153,7 +1148,7 @@ static v8::Handle<v8::Value> JS_ClusterTest (v8::Arguments const& argv) {
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief defines and executes a periodic task
/// @brief defines and executes a 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
double period = 0.0;
int64_t count;
if (obj->HasOwnProperty(TRI_V8_SYMBOL("period"))) {
period = TRI_ObjectToDouble(obj->Get(TRI_V8_SYMBOL("period")));
}
if (period <= 0.0) {
TRI_V8_EXCEPTION_PARAMETER(scope, "task period must be specified and positive");
}
if (period <= 0.0) {
TRI_V8_EXCEPTION_PARAMETER(scope, "task period must be specified and positive");
}
if (obj->HasOwnProperty(TRI_V8_SYMBOL("count"))) {
// check for count attribute
count = TRI_ObjectToInt64(obj->Get(TRI_V8_SYMBOL("count")));
// extract the command
if (! obj->HasOwnProperty(TRI_V8_SYMBOL("command"))) {
TRI_V8_EXCEPTION_PARAMETER(scope, "command must be specified");
}
if (count <= 0) {
TRI_V8_EXCEPTION_PARAMETER(scope, "task execution count must be specified and positive");
}
}
else {
// no count specified. this means the job will go on forever
count = -1;
}
string command;
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 {
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
// 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")));
if (obj->HasOwnProperty(TRI_V8_SYMBOL("params"))) {
parameters = TRI_ObjectToJson(obj->Get(TRI_V8_SYMBOL("params")));
}
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
// create a new periodic task
V8PeriodicTask* task = new V8PeriodicTask(
id,
name,
GlobalVocbase,
static_cast<TRI_vocbase_t*>(v8g->_vocbase),
GlobalV8Dealer,
GlobalScheduler,
GlobalDispatcher,
offset,
period,
module,
func,
parameter);
command,
parameters);
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);
}
// return the result
v8::Handle<v8::Object> result = v8::Object::New();
// get the JSON representation of the task
TRI_json_t* json = task->toJson();
result->Set(TRI_V8_SYMBOL("id"), v8::String::New(id.c_str(), (int) id.size()));
result->Set(TRI_V8_SYMBOL("name"), v8::String::New(name.c_str(), (int) name.size()));
if (json != 0) {
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})}
////////////////////////////////////////////////////////////////////////////////
@ -1298,7 +1279,17 @@ static v8::Handle<v8::Value> JS_DeleteTask (v8::Arguments const& argv) {
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) {
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()}
////////////////////////////////////////////////////////////////////////////////
@ -1357,7 +1348,6 @@ void TRI_InitV8Actions (v8::Handle<v8::Context> context,
ApplicationV8* applicationV8) {
v8::HandleScope scope;
GlobalVocbase = vocbase;
GlobalV8Dealer = applicationV8;
// check the isolate

View File

@ -758,6 +758,13 @@
if (typeof SYS_EXECUTE_TASK !== "undefined") {
exports.executeTask = 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") {
exports.executeTask = 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";
try {

View File

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

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;
if (task->isUserDefined()) {
TRI_json_t* obj = TRI_CreateArrayJson(TRI_UNKNOWN_MEM_ZONE);
TRI_json_t* obj = task->toJson();
if (obj != 0) {
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, obj, "id", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, task->id().c_str()));
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);
}
TRI_PushBack3ListJson(TRI_UNKNOWN_MEM_ZONE, json, obj);
}
++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
/// note: this function may be overridden
@ -71,14 +88,6 @@ bool Task::isUserDefined () const {
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
////////////////////////////////////////////////////////////////////////////////
@ -87,3 +96,15 @@ bool Task::needsMainEventLoop () const {
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
@ -138,6 +138,12 @@ namespace triagens {
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
///