[asterisk-commits] file: branch file/sorcery r378198 - in /team/file/sorcery: include/asterisk/ ...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Dec 24 10:30:48 CST 2012
Author: file
Date: Mon Dec 24 10:30:43 2012
New Revision: 378198
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=378198
Log:
Implement all of the wizard callbacks in res_sorcery_memory, add support for returning multiple objects from retrieve, flush out more stuff, and add more tests.
Modified:
team/file/sorcery/include/asterisk/sorcery.h
team/file/sorcery/main/sorcery.c
team/file/sorcery/res/res_sorcery_memory.c
team/file/sorcery/tests/test_sorcery.c
Modified: team/file/sorcery/include/asterisk/sorcery.h
URL: http://svnview.digium.com/svn/asterisk/team/file/sorcery/include/asterisk/sorcery.h?view=diff&rev=378198&r1=378197&r2=378198
==============================================================================
--- team/file/sorcery/include/asterisk/sorcery.h (original)
+++ team/file/sorcery/include/asterisk/sorcery.h Mon Dec 24 10:30:43 2012
@@ -37,9 +37,7 @@
#endif
#include "asterisk/config_options.h"
-
-/*! \brief Maximum size of an object unique identifier */
-#define MAX_OBJECT_ID 64
+#include "asterisk/uuid.h"
/*! \brief Maximum size of an object type */
#define MAX_OBJECT_TYPE 64
@@ -53,6 +51,12 @@
enum ast_sorcery_retrieve_flags {
/*! \brief Default retrieval flags */
AST_RETRIEVE_FLAG_DEFAULT = 0,
+
+ /*! \brief Return all matching objects */
+ AST_RETRIEVE_FLAG_MULTIPLE = (1 << 0),
+
+ /*! \brief Perform no matching, return all objects */
+ AST_RETRIEVE_FLAG_ALL = (1 << 1),
};
/*!
@@ -68,6 +72,9 @@
/*! \brief End of retrieval parameters */
AST_RETRIEVE_PARAM_END,
};
+
+/*! \brief Forward declaration for the sorcery main structure */
+struct ast_sorcery;
/*!
* \brief A callback function for translating a value into a string
@@ -82,6 +89,25 @@
*/
typedef int (*sorcery_field_handler)(const void *obj, const intptr_t *args, char *buf, size_t len);
+/*!
+ * \brief A callback function for performing a transformation on an object set
+ *
+ * \param set The existing object set
+ *
+ * \retval non-NULL new object set if changed
+ * \retval NULL if no changes present
+ *
+ * \note The returned ast_variable list must be *new*. You can not return the input set.
+ */
+typedef struct ast_variable *(*sorcery_transform_handler)(struct ast_variable *set);
+
+/*!
+ * \brief A callback function for when an object set is successfully applied to an object
+ *
+ * \param obj The object itself
+ */
+typedef void (*sorcery_apply_handler)(void *obj);
+
/*! \brief Interface for a sorcery wizard */
struct ast_sorcery_wizard {
/*! \brief Name of the wizard */
@@ -93,14 +119,23 @@
/*! \brief Callback for opening a wizard */
void *(*open)(const char *data);
+ /*! \brief Optional callback for loading persistent objects */
+ void (*load)(void *data);
+
+ /*! \brief Optional callback for reloading persistent objects */
+ void (*reload)(void *data);
+
/*! \brief Callback for creating an object */
int (*create)(void *data, void *object);
/*! \brief Callback for retrieving an object using an id */
- void *(*retrieve_id)(void *data, const char *id);
+ void *(*retrieve_id)(const struct ast_sorcery *sorcery, void *data, const char *id);
/*! \brief Optional callback for retrieving an object using fields */
- void *(*retrieve_fields)(void *data, const struct ast_variable *fields);
+ void *(*retrieve_fields)(const struct ast_sorcery *sorcery, void *data, const struct ast_variable *fields);
+
+ /*! \brief Optional callback for retrieving multiple objects using some optional field criteria */
+ void (*retrieve_multiple)(const struct ast_sorcery *sorcery, void *data, struct ao2_container *objects, const struct ast_variable *fields);
/*! \brief Callback for updating an object */
int (*update)(void *data, void *object);
@@ -112,13 +147,10 @@
void (*close)(void *data);
};
-/*! \brief Forward declaration for the sorcery main structure */
-struct ast_sorcery;
-
/*! \brief Structure which contains details about a sorcery object */
struct ast_sorcery_object_details {
/*! \brief Unique identifier of this object */
- char id[MAX_OBJECT_ID];
+ char id[AST_UUID_STR_LEN];
/*! \brief Type of object */
char type[MAX_OBJECT_TYPE];
@@ -204,11 +236,13 @@
* \param sorcery Pointer to a sorcery structure
* \param type Type of object
* \param aco_type Configuration framework details for type
- *
- * \retval 0 success
- * \retval -1 failure
- */
-int ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, struct aco_type *aco_type);
+ * \param transform Optional transformation callback
+ * \param apply Optional object set apply callback
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, struct aco_type *aco_type, sorcery_transform_handler transform, sorcery_apply_handler apply);
/*!
* \brief Register a field within an object
@@ -260,6 +294,20 @@
__ast_sorcery_object_field_register(sorcery, type, name, default_val, OPT_CUSTOM_T, config_handler, sorcery_handler, flags, VA_NARGS(__VA_ARGS__), __VA_ARGS__);
/*!
+ * \brief Inform any wizards to load persistent objects
+ *
+ * \param sorcery Pointer to a sorcery structure
+ */
+void ast_sorcery_load(const struct ast_sorcery *sorcery);
+
+/*!
+ * \brief Inform any wizards to reload persistent objects
+ *
+ * \param sorcery Pointer to a sorcery structure
+ */
+void ast_sorcery_reload(const struct ast_sorcery *sorcery);
+
+/*!
* \brief Increase the reference count of a sorcery structure
*
* \param sorcery Pointer to a sorcery structure
@@ -275,7 +323,7 @@
* \retval non-NULL success
* \retval NULL if error occurred
*
- * \note The reference to the returned container must be released using ao2_ref or ao2_cleanup
+ * \note The returned ast_variable list must be destroyed using ast_variables_destroy
*/
struct ast_variable *ast_sorcery_objectset_create(const struct ast_sorcery *sorcery, const void *object);
@@ -352,7 +400,7 @@
* \retval 0 success
* \retval -1 failure
*/
-int ast_sorcery_create(struct ast_sorcery *sorcery, void *object);
+int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object);
/*!
* \brief Retrieve an object or multiple objects
@@ -366,6 +414,9 @@
* \retval NULL if not found
*
* \note The parameters must end with AST_RETRIEVE_PARAM_END
+ *
+ * \note If the AST_RETRIEVE_FLAG_MULTIPLE flag is specified the returned value will be an
+ * ao2_container that must be unreferenced after use.
*/
void *ast_sorcery_retrieve(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, ...);
@@ -378,7 +429,7 @@
* \retval 0 success
* \retval -1 failure
*/
-int ast_sorcery_update(struct ast_sorcery *sorcery, void *object);
+int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object);
/*!
* \brief Delete an object
@@ -389,7 +440,7 @@
* \retval 0 success
* \retval -1 failure
*/
-int ast_sorcery_delete(struct ast_sorcery *sorcery, void *object);
+int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object);
/*!
* \brief Decrease the reference count of a sorcery structure
Modified: team/file/sorcery/main/sorcery.c
URL: http://svnview.digium.com/svn/asterisk/team/file/sorcery/main/sorcery.c?view=diff&rev=378198&r1=378197&r2=378198
==============================================================================
--- team/file/sorcery/main/sorcery.c (original)
+++ team/file/sorcery/main/sorcery.c Mon Dec 24 10:30:43 2012
@@ -53,6 +53,12 @@
/*! \brief Unique name of the object type */
char name[MAX_OBJECT_TYPE];
+ /*! \brief Optional transformation callback */
+ sorcery_transform_handler transform;
+
+ /*! \brief Optional object set apply callback */
+ sorcery_apply_handler apply;
+
/*! \brief Wizard instances */
struct ao2_container *wizards;
@@ -443,7 +449,7 @@
return sorcery_apply_wizard_mapping(sorcery, type, name, data);
}
-int ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, struct aco_type *aco_type)
+int ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, struct aco_type *aco_type, sorcery_transform_handler transform, sorcery_apply_handler apply)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
@@ -451,6 +457,7 @@
return -1;
}
+ object_type->transform = transform;
object_type->file->types[0] = aco_type;
object_type->file->types[1] = NULL;
@@ -516,6 +523,56 @@
return 0;
}
+static int sorcery_wizard_load(void *obj, void *arg, int flags)
+{
+ struct ast_sorcery_object_wizard *wizard = obj;
+
+ if (wizard->wizard->load) {
+ wizard->wizard->load(wizard->data);
+ }
+
+ return 0;
+}
+
+static int sorcery_object_load(void *obj, void *arg, int flags)
+{
+ struct ast_sorcery_object_type *type = obj;
+
+ ao2_callback(type->wizards, OBJ_NODATA, sorcery_wizard_load, NULL);
+
+ return 0;
+}
+
+void ast_sorcery_load(const struct ast_sorcery *sorcery)
+{
+ ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_load, NULL);
+}
+
+static int sorcery_wizard_reload(void *obj, void *arg, int flags)
+{
+ struct ast_sorcery_object_wizard *wizard = obj;
+
+ if (wizard->wizard->reload) {
+ wizard->wizard->reload(wizard->data);
+ }
+
+ return 0;
+}
+
+static int sorcery_object_reload(void *obj, void *arg, int flags)
+{
+ struct ast_sorcery_object_type *type = obj;
+
+ ao2_callback(type->wizards, OBJ_NODATA, sorcery_wizard_reload, NULL);
+
+ return 0;
+}
+
+void ast_sorcery_reload(const struct ast_sorcery *sorcery)
+{
+ ao2_callback(sorcery->types, OBJ_NODATA, sorcery_object_reload, NULL);
+}
+
void ast_sorcery_ref(struct ast_sorcery *sorcery)
{
ao2_ref(sorcery, +1);
@@ -571,6 +628,7 @@
{
const struct ast_sorcery_object_details *details = object;
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
+ RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
struct ast_variable *field;
int res = 0;
@@ -578,10 +636,20 @@
return -1;
}
- for (field = objectset; field; field = field->next) {
+ if (object_type->transform && (transformed = object_type->transform(objectset))) {
+ field = transformed;
+ } else {
+ field = objectset;
+ }
+
+ for (; field; field = field->next) {
if ((res = aco_process_var(object_type->type, details->id, field, object))) {
break;
}
+ }
+
+ if (!res && object_type->apply) {
+ object_type->apply(object);
}
return res;
@@ -639,11 +707,24 @@
if (!object_type || !object_type->type ||
!object_type->type->item_alloc ||
- !(details = object_type->type->item_alloc(id))) {
- return NULL;
- }
-
- ast_copy_string(details->id, id, sizeof(details->id));
+ !(details = object_type->type->item_alloc(""))) {
+ return NULL;
+ }
+
+ if (ast_strlen_zero(id)) {
+ struct ast_uuid *uuid = ast_uuid_generate();
+
+ if (!uuid) {
+ ao2_ref(details, -1);
+ return NULL;
+ }
+
+ ast_uuid_to_str(uuid, details->id, AST_UUID_STR_LEN);
+ ast_free(uuid);
+ } else {
+ ast_copy_string(details->id, id, sizeof(details->id));
+ }
+
ast_copy_string(details->type, type, sizeof(details->type));
if (aco_set_defaults(object_type->type, id, details)) {
@@ -657,7 +738,7 @@
void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
{
const struct ast_sorcery_object_details *details = object;
- void *copy = ast_sorcery_alloc(sorcery, details->type, details->id);
+ struct ast_sorcery_object_details *copy = ast_sorcery_alloc(sorcery, details->type, details->id);
RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
if (!copy ||
@@ -666,6 +747,8 @@
ao2_cleanup(copy);
return NULL;
}
+
+ copy->wizard = details->wizard;
return copy;
}
@@ -724,20 +807,31 @@
va_end(args);
/* Uh... if no parameters are there we obviously can't do anything */
- if (ast_strlen_zero(id) && !fields) {
- return NULL;
+ if (ast_strlen_zero(id) && !fields && (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) || !(flags & AST_RETRIEVE_FLAG_ALL))) {
+ return NULL;
+ }
+
+ /* If returning multiple objects create a container to store them in */
+ if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
+ if (!(object = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
+ return NULL;
+ }
}
/* Inquire with the available wizards for retrieval */
i = ao2_iterator_init(object_type->wizards, 0);
for (; (wizard = ao2_iterator_next(&i)); ao2_ref(wizard, -1)) {
- if (!ast_strlen_zero(id)) {
- object = wizard->wizard->retrieve_id(wizard->data, id);
+ if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
+ if (wizard->wizard->retrieve_multiple) {
+ wizard->wizard->retrieve_multiple(sorcery, wizard->data, object, fields);
+ }
+ } else if (!ast_strlen_zero(id)) {
+ object = wizard->wizard->retrieve_id(sorcery, wizard->data, id);
} else if (fields && wizard->wizard->retrieve_fields) {
- object = wizard->wizard->retrieve_fields(wizard->data, fields);
- }
-
- if (!object) {
+ object = wizard->wizard->retrieve_fields(sorcery, wizard->data, fields);
+ }
+
+ if ((flags & AST_RETRIEVE_FLAG_MULTIPLE) || !object) {
continue;
}
@@ -757,7 +851,7 @@
return !object_wizard->wizard->create(object_wizard->data, arg) ? CMP_MATCH | CMP_STOP : 0;
}
-int ast_sorcery_create(struct ast_sorcery *sorcery, void *object)
+int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
{
struct ast_sorcery_object_details *details = object;
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->type, OBJ_KEY), ao2_cleanup);
@@ -776,9 +870,9 @@
}
}
-int ast_sorcery_update(struct ast_sorcery *sorcery, void *object)
-{
- struct ast_sorcery_object_details *details = object;
+int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
+{
+ const struct ast_sorcery_object_details *details = object;
ast_assert(sorcery != NULL);
ast_assert(details->wizard != NULL);
@@ -786,9 +880,9 @@
return details->wizard->wizard->update(details->wizard->data, object);
}
-int ast_sorcery_delete(struct ast_sorcery *sorcery, void *object)
-{
- struct ast_sorcery_object_details *details = object;
+int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
+{
+ const struct ast_sorcery_object_details *details = object;
ast_assert(sorcery != NULL);
ast_assert(details->wizard != NULL);
Modified: team/file/sorcery/res/res_sorcery_memory.c
URL: http://svnview.digium.com/svn/asterisk/team/file/sorcery/res/res_sorcery_memory.c?view=diff&rev=378198&r1=378197&r2=378198
==============================================================================
--- team/file/sorcery/res/res_sorcery_memory.c (original)
+++ team/file/sorcery/res/res_sorcery_memory.c Mon Dec 24 10:30:43 2012
@@ -41,7 +41,9 @@
static void *sorcery_memory_open(const char *data);
static int sorcery_memory_create(void *data, void *object);
-static void *sorcery_memory_retrieve_id(void *data, const char *id);
+static void *sorcery_memory_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *id);
+static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const struct ast_variable *fields);
+static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, struct ao2_container *objects, const struct ast_variable *fields);
static int sorcery_memory_update(void *data, void *object);
static int sorcery_memory_delete(void *data, void *object);
static void sorcery_memory_close(void *data);
@@ -51,11 +53,25 @@
.open = sorcery_memory_open,
.create = sorcery_memory_create,
.retrieve_id = sorcery_memory_retrieve_id,
+ .retrieve_fields = sorcery_memory_retrieve_fields,
+ .retrieve_multiple = sorcery_memory_retrieve_multiple,
.update = sorcery_memory_update,
.delete = sorcery_memory_delete,
.close = sorcery_memory_close,
};
+/*! \brief Structure used for fields comparison */
+struct sorcery_memory_fields_cmp_params {
+ /*! \brief Pointer to the sorcery structure */
+ const struct ast_sorcery *sorcery;
+
+ /*! \brief Pointer to the fields to check */
+ const struct ast_variable *fields;
+
+ /*! \brief Optional container to put object into */
+ struct ao2_container *container;
+};
+
/*! \brief Hashing function for sorcery objects */
static int sorcery_memory_hash(const void *obj, const int flags)
{
@@ -78,20 +94,87 @@
return 0;
}
-static void *sorcery_memory_retrieve_id(void *data, const char *id)
+static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags)
+{
+ const struct sorcery_memory_fields_cmp_params *params = arg;
+ RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
+ RAII_VAR(struct ast_variable *, diff, NULL, ast_variables_destroy);
+
+ /* If we can't turn the object into an object set OR if differences exist between the fields
+ * passed in and what are present on the object they are not a match.
+ */
+ if (params->fields &&
+ (!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
+ (diff = ast_sorcery_changeset_create(objset, params->fields)))) {
+ return 0;
+ }
+
+ if (params->container) {
+ ao2_link(params->container, obj);
+
+ /* As multiple objects are being returned keep going */
+ return 0;
+ } else {
+ /* Immediately stop and return, we only want a single object */
+ return CMP_MATCH | CMP_STOP;
+ }
+}
+
+static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const struct ast_variable *fields)
+{
+ struct sorcery_memory_fields_cmp_params params = {
+ .sorcery = sorcery,
+ .fields = fields,
+ .container = NULL,
+ };
+
+ /* If no fields are present return nothing, we require *something* */
+ if (!fields) {
+ return NULL;
+ }
+
+ return ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms);
+}
+
+static void *sorcery_memory_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *id)
{
return ao2_find(data, id, OBJ_KEY);
}
+static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, struct ao2_container *objects, const struct ast_variable *fields)
+{
+ struct sorcery_memory_fields_cmp_params params = {
+ .sorcery = sorcery,
+ .fields = fields,
+ .container = objects,
+ };
+
+ ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms);
+}
+
static int sorcery_memory_update(void *data, void *object)
{
- return -1;
+ RAII_VAR(void *, existing, NULL, ao2_cleanup);
+
+ ao2_lock(data);
+
+ if (!(existing = ao2_find(data, ast_sorcery_object_get_id(object), OBJ_KEY | OBJ_UNLINK))) {
+ ao2_unlock(data);
+ return -1;
+ }
+
+ ao2_link(data, object);
+
+ ao2_unlock(data);
+
+ return 0;
}
static int sorcery_memory_delete(void *data, void *object)
{
- ao2_unlink(data, object);
- return 0;
+ RAII_VAR(void *, existing, ao2_find(data, ast_sorcery_object_get_id(object), OBJ_KEY | OBJ_UNLINK), ao2_cleanup);
+
+ return existing ? 0 : -1;
}
static void *sorcery_memory_open(const char *data)
Modified: team/file/sorcery/tests/test_sorcery.c
URL: http://svnview.digium.com/svn/asterisk/team/file/sorcery/tests/test_sorcery.c?view=diff&rev=378198&r1=378197&r2=378198
==============================================================================
--- team/file/sorcery/tests/test_sorcery.c (original)
+++ team/file/sorcery/tests/test_sorcery.c Mon Dec 24 10:30:43 2012
@@ -51,6 +51,32 @@
return ao2_alloc(sizeof(struct test_sorcery_object), NULL);
}
+/*! \brief Internal function for object set transformation */
+static struct ast_variable *test_sorcery_transform(struct ast_variable *set)
+{
+ struct ast_variable *field, *transformed = NULL;
+
+ for (field = set; field; field = field->next) {
+ struct ast_variable *transformed_field;
+
+ if (!strcmp(field->name, "joe")) {
+ transformed_field = ast_variable_new(field->name, "5000", "");
+ } else {
+ transformed_field = ast_variable_new(field->name, field->value, "");
+ }
+
+ if (!transformed_field) {
+ ast_variables_destroy(transformed);
+ return NULL;
+ }
+
+ transformed_field->next = transformed;
+ transformed = transformed_field;
+ }
+
+ return transformed;
+}
+
/*! \brief Configuration framework definition for test object */
static struct aco_type test_object = {
.type = ACO_ITEM,
@@ -190,7 +216,7 @@
return AST_TEST_FAIL;
}
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
ast_test_status_update(test, "Failed to register object type\n");
return AST_TEST_FAIL;
}
@@ -198,7 +224,7 @@
return AST_TEST_PASS;
}
-AST_TEST_DEFINE(object_alloc)
+AST_TEST_DEFINE(object_alloc_with_id)
{
int res = AST_TEST_PASS;
RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
@@ -206,27 +232,27 @@
switch (cmd) {
case TEST_INIT:
- info->name = "object_alloc";
- info->category = "/main/sorcery/";
- info->summary = "sorcery object allocation unit test";
- info->description =
- "Test object allocation in sorcery";
- return AST_TEST_NOT_RUN;
- case TEST_EXECUTE:
- break;
- }
-
- if (!(sorcery = ast_sorcery_open())) {
- ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
- return AST_TEST_FAIL;
- }
-
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
- ast_test_status_update(test, "Failed to set a known wizard as a default\n");
- return AST_TEST_FAIL;
- }
-
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
+ info->name = "object_alloc_with_id";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery object allocation (with id) unit test";
+ info->description =
+ "Test object allocation in sorcery with a provided id";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
ast_test_status_update(test, "Failed to register object type\n");
return AST_TEST_FAIL;
}
@@ -254,6 +280,54 @@
return res;
}
+AST_TEST_DEFINE(object_alloc_without_id)
+{
+ int res = AST_TEST_PASS;
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "object_alloc_without_id";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery object allocation (without id) unit test";
+ info->description =
+ "Test object allocation in sorcery with no provided id";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
+ ast_test_status_update(test, "Failed to register object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_sorcery_object_field_register(sorcery, "test", "bob", "5", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, bob));
+ ast_sorcery_object_field_register(sorcery, "test", "joe", "10", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, joe));
+
+ if (!(obj = ast_sorcery_alloc(sorcery, "test", NULL))) {
+ ast_test_status_update(test, "Failed to allocate a known object type\n");
+ res = AST_TEST_FAIL;
+ } else if (ast_strlen_zero(ast_sorcery_object_get_id(obj))) {
+ ast_test_status_update(test, "Allocated object has empty id when it should not\n");
+ res = AST_TEST_FAIL;
+ }
+
+ return res;
+}
+
+
AST_TEST_DEFINE(object_copy)
{
int res = AST_TEST_PASS;
@@ -283,7 +357,7 @@
return AST_TEST_FAIL;
}
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
ast_test_status_update(test, "Failed to register object type\n");
return AST_TEST_FAIL;
}
@@ -344,7 +418,7 @@
return AST_TEST_FAIL;
}
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
ast_test_status_update(test, "Failed to register object type\n");
return AST_TEST_FAIL;
}
@@ -418,7 +492,7 @@
return AST_TEST_FAIL;
}
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
ast_test_status_update(test, "Failed to register object type\n");
return AST_TEST_FAIL;
}
@@ -485,7 +559,7 @@
return AST_TEST_FAIL;
}
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
ast_test_status_update(test, "Failed to register object type\n");
return AST_TEST_FAIL;
}
@@ -510,6 +584,71 @@
}
return res;
+}
+
+AST_TEST_DEFINE(objectset_transform)
+{
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "objectset_transform";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery object set transformation unit test";
+ info->description =
+ "Test object set transformation in sorcery";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, test_sorcery_transform, NULL)) {
+ ast_test_status_update(test, "Failed to register object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_sorcery_object_field_register(sorcery, "test", "bob", "5", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, bob));
+ ast_sorcery_object_field_register(sorcery, "test", "joe", "10", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, joe));
+
+ if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
+ ast_test_status_update(test, "Failed to allocate a known object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (!(objset = ast_sorcery_objectset_create(sorcery, obj))) {
+ ast_test_status_update(test, "Failed to create an object set for a known sane object\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_objectset_apply(sorcery, obj, objset)) {
+ ast_test_status_update(test, "Failed to apply properly created object set against object\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (obj->bob != 5) {
+ ast_test_status_update(test, "Application of object set produced incorrect value on 'bob'\n");
+ return AST_TEST_FAIL;
+ } else if (obj->joe == 10) {
+ ast_test_status_update(test, "Transformation callback did not change value of 'joe' from provided value\n");
+ return AST_TEST_FAIL;
+ } else if (obj->joe != 5000) {
+ ast_test_status_update(test, "Value of 'joe' differs from default AND from transformation value\n");
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
}
AST_TEST_DEFINE(changeset_create)
@@ -647,7 +786,7 @@
return AST_TEST_FAIL;
}
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
ast_test_status_update(test, "Failed to register object type\n");
return AST_TEST_FAIL;
}
@@ -668,34 +807,34 @@
return AST_TEST_PASS;
}
-AST_TEST_DEFINE(object_retrieve)
+AST_TEST_DEFINE(object_retrieve_id)
{
RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
switch (cmd) {
case TEST_INIT:
- info->name = "object_retrieve";
- info->category = "/main/sorcery/";
- info->summary = "sorcery object retrieval unit test";
- info->description =
- "Test object retrieval in sorcery";
- return AST_TEST_NOT_RUN;
- case TEST_EXECUTE:
- break;
- }
-
- if (!(sorcery = ast_sorcery_open())) {
- ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
- return AST_TEST_FAIL;
- }
-
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
- ast_test_status_update(test, "Failed to set a known wizard as a default\n");
- return AST_TEST_FAIL;
- }
-
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
+ info->name = "object_retrieve_id";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery object retrieval using id unit test";
+ info->description =
+ "Test object retrieval using id in sorcery";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
ast_test_status_update(test, "Failed to register object type\n");
return AST_TEST_FAIL;
}
@@ -713,57 +852,320 @@
ao2_cleanup(obj);
if (!(obj = ast_sorcery_retrieve(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, AST_RETRIEVE_PARAM_ID, "blah", AST_RETRIEVE_PARAM_END))) {
- ast_test_status_update(test, "Failed to retrieve properly created object\n");
+ ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
return AST_TEST_FAIL;
}
return AST_TEST_PASS;
}
-AST_TEST_DEFINE(object_delete)
+AST_TEST_DEFINE(object_retrieve_field)
{
RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
switch (cmd) {
case TEST_INIT:
- info->name = "object_delete";
- info->category = "/main/sorcery/";
- info->summary = "sorcery object deletion unit test";
- info->description =
- "Test object deletion in sorcery";
- return AST_TEST_NOT_RUN;
- case TEST_EXECUTE:
- break;
- }
-
- if (!(sorcery = ast_sorcery_open())) {
- ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
- return AST_TEST_FAIL;
- }
-
- if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
- ast_test_status_update(test, "Failed to set a known wizard as a default\n");
- return AST_TEST_FAIL;
- }
-
- if (ast_sorcery_object_register(sorcery, "test", &test_object)) {
- ast_test_status_update(test, "Failed to register object type\n");
- return AST_TEST_FAIL;
- }
+ info->name = "object_retrieve_field";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery object retrieval using a specific field unit test";
+ info->description =
+ "Test object retrieval using a specific field in sorcery";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
+ ast_test_status_update(test, "Failed to register object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_sorcery_object_field_register(sorcery, "test", "bob", "5", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, bob));
+ ast_sorcery_object_field_register(sorcery, "test", "joe", "10", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, joe));
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
ast_test_status_update(test, "Failed to allocate a known object type\n");
return AST_TEST_FAIL;
}
+ obj->joe = 42;
+
if (ast_sorcery_create(sorcery, obj)) {
ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
return AST_TEST_FAIL;
}
+ ao2_cleanup(obj);
+
+ if (!(obj = ast_sorcery_retrieve(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, AST_RETRIEVE_PARAM_FIELD, "joe", "42", AST_RETRIEVE_PARAM_END))) {
+ ast_test_status_update(test, "Failed to retrieve properly created object using 'joe' field\n");
+ return AST_TEST_FAIL;
+ }
+
+ ao2_cleanup(obj);
+
+ if ((obj = ast_sorcery_retrieve(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, AST_RETRIEVE_PARAM_FIELD, "joe", "49", AST_RETRIEVE_PARAM_END))) {
+ ast_test_status_update(test, "Retrieved an object using a field with an in-correct value... that should not happen\n");
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(object_retrieve_multiple_all)
+{
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "object_retrieve_multiple_all";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery multiple object retrieval unit test";
+ info->description =
+ "Test multiple object retrieval in sorcery";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
+ ast_test_status_update(test, "Failed to register object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
+ ast_test_status_update(test, "Failed to allocate a known object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_create(sorcery, obj)) {
+ ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (!(objects = ast_sorcery_retrieve(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_PARAM_END))) {
+ ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
+ return AST_TEST_FAIL;
+ } else if (!ao2_container_count(objects)) {
+ ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(object_retrieve_multiple_field)
+{
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "object_retrieve_multiple_field";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery multiple object retrieval unit test";
+ info->description =
+ "Test multiple object retrieval in sorcery using fields";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
+ ast_test_status_update(test, "Failed to register object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_sorcery_object_field_register(sorcery, "test", "bob", "5", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, bob));
+ ast_sorcery_object_field_register(sorcery, "test", "joe", "10", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, joe));
+
+ if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
+ ast_test_status_update(test, "Failed to allocate a known object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ obj->joe = 6;
+
+ if (ast_sorcery_create(sorcery, obj)) {
+ ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (!(objects = ast_sorcery_retrieve(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, AST_RETRIEVE_PARAM_FIELD, "joe", "6", AST_RETRIEVE_PARAM_END))) {
+ ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
+ return AST_TEST_FAIL;
+ } else if (!ao2_container_count(objects)) {
+ ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
+ return AST_TEST_FAIL;
+ }
+
+ ao2_cleanup(objects);
+
+ if (!(objects = ast_sorcery_retrieve(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, AST_RETRIEVE_PARAM_FIELD, "joe", "7", AST_RETRIEVE_PARAM_END))) {
+ ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
+ return AST_TEST_FAIL;
+ } else if (ao2_container_count(objects)) {
+ ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
+ return AST_TEST_FAIL;
+ }
+
+ return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(object_update)
+{
+ RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
+ RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
+ RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = "object_update";
+ info->category = "/main/sorcery/";
+ info->summary = "sorcery object update unit test";
+ info->description =
+ "Test object updating in sorcery";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ if (!(sorcery = ast_sorcery_open())) {
+ ast_test_status_update(test, "Failed to open sorcery with NULL name\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_apply_default(sorcery, "test", "memory", NULL)) {
+ ast_test_status_update(test, "Failed to set a known wizard as a default\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_object_register(sorcery, "test", &test_object, NULL, NULL)) {
+ ast_test_status_update(test, "Failed to register object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ ast_sorcery_object_field_register(sorcery, "test", "bob", "5", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, bob));
+ ast_sorcery_object_field_register(sorcery, "test", "joe", "10", OPT_UINT_T, PARSE_DEFAULT, FLDSET(struct test_sorcery_object, joe));
+
+ if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
+ ast_test_status_update(test, "Failed to allocate a known object type\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (ast_sorcery_create(sorcery, obj)) {
+ ast_test_status_update(test, "Failed to create object using in-memory wizard\n");
+ return AST_TEST_FAIL;
+ }
+
+ if (!(obj2 = ast_sorcery_copy(sorcery, obj))) {
+ ast_test_status_update(test, "Failed to allocate a known object type for updating\n");
+ return AST_TEST_FAIL;
+ }
+
+ ao2_cleanup(obj);
+
+ if (ast_sorcery_update(sorcery, obj2)) {
+ ast_test_status_update(test, "Failed to update sorcery with new object\n");
+ return AST_TEST_FAIL;
+ }
+
[... 114 lines stripped ...]
More information about the asterisk-commits
mailing list