[svn-commits] file: branch file/bucket r395617 - in /team/file/bucket: include/asterisk/ ma...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sun Jul 28 16:45:02 CDT 2013


Author: file
Date: Sun Jul 28 16:44:59 2013
New Revision: 395617

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=395617
Log:
Add most of the file API along with tests. JSON for it is still left to do, then clean up/tweaking/reducing duplication.

Modified:
    team/file/bucket/include/asterisk/bucket.h
    team/file/bucket/main/bucket.c
    team/file/bucket/tests/test_bucket.c

Modified: team/file/bucket/include/asterisk/bucket.h
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/include/asterisk/bucket.h?view=diff&rev=395617&r1=395616&r2=395617
==============================================================================
--- team/file/bucket/include/asterisk/bucket.h (original)
+++ team/file/bucket/include/asterisk/bucket.h Sun Jul 28 16:44:59 2013
@@ -74,6 +74,13 @@
 struct ast_bucket_file {
 	/*! \brief Sorcery object information */
 	SORCERY_OBJECT(details);
+	/*! \brief Stringfields */
+	AST_DECLARE_STRING_FIELDS(
+		/*! \brief Full URI to the bucket */
+		AST_STRING_FIELD(uri);
+		/*! \brief Scheme in use */
+		AST_STRING_FIELD(scheme);
+	);
 	/*! \brief When this file was created */
 	struct timeval created;
 	/*! \brief When this file was last modified */
@@ -230,6 +237,92 @@
  */
 struct ast_json *ast_bucket_json(const struct ast_bucket *bucket);
 
+/*!
+ * \brief Allocate a new bucket file
+ *
+ * \param uri Complete URI for the bucket file
+ *
+ * \param non-NULL success
+ * \param NULL failure
+ *
+ * \note This only creates a local bucket file object, to persist in backend storage you must call
+ * ast_bucket_file_create
+ */
+struct ast_bucket_file *ast_bucket_file_alloc(const char *uri);
+
+/*!
+ * \brief Create a new bucket file in backend storage
+ *
+ * \param file The bucket file
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_bucket_file_create(struct ast_bucket_file *file);
+
+/*!
+ * \brief Update an existing bucket file in backend storage
+ *
+ * \param file The bucket file
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_bucket_file_update(struct ast_bucket_file *file);
+
+/*!
+ * \brief Delete a bucket file from backend storage
+ *
+ * \param file The bucket file
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ */
+int ast_bucket_file_delete(struct ast_bucket_file *file);
+
+/*!
+ * \brief Retrieve a bucket file
+ *
+ * \param uri Complete URI of the bucket file
+ *
+ * \retval non-NULL if found
+ * \retval NULL if not found
+ *
+ * \note The object is returned with reference count increased
+ */
+struct ast_bucket_file *ast_bucket_file_retrieve(const char *uri);
+
+/*!
+ * \brief Add an observer for bucket file creation and deletion operations
+ *
+ * \param callbacks Implementation of the sorcery observer interface
+ *
+ * \retval 0 success
+ * \retval -1 failure
+ *
+ * \note You must be ready to accept observer invocations before this function is called
+ */
+int ast_bucket_file_observer_add(const struct ast_sorcery_observer *callbacks);
+
+/*!
+ * \brief Remove an observer from bucket file creation and deletion
+ *
+ * \param callbacks Implementation of the sorcery observer interface
+ */
+void ast_bucket_file_observer_remove(struct ast_sorcery_observer *callbacks);
+
+/*!
+ * \brief Get a JSON representation of a bucket file
+ *
+ * \param file The specific bucket file
+ *
+ * \retval non-NULL success
+ * \retval NULL failure
+ *
+ * \note The returned ast_json object must be unreferenced using ast_json_unref
+ */
+struct ast_json *ast_bucket_file_json(const struct ast_bucket_file *file);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: team/file/bucket/main/bucket.c
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/main/bucket.c?view=diff&rev=395617&r1=395616&r2=395617
==============================================================================
--- team/file/bucket/main/bucket.c (original)
+++ team/file/bucket/main/bucket.c Sun Jul 28 16:44:59 2013
@@ -51,6 +51,9 @@
 /*! \brief Number of buckets for the container of file URIs in a bucket */
 #define FILE_BUCKETS 53
 
+/*! \brief Number of buckets for the container of metadata in a file */
+#define METADATA_BUCKETS 53
+
 /*! \brief Sorcery instance for all bucket operations */
 static struct ast_sorcery *bucket_sorcery;
 
@@ -135,9 +138,86 @@
 	.delete = bucket_wizard_delete,
 };
 
+/*! \brief Callback function for creating a bucket file */
+static int bucket_file_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
+{
+	struct ast_bucket_file *file = object;
+	RAII_VAR(struct bucket_scheme *, scheme, ao2_find(schemes, file->scheme, OBJ_KEY), ao2_cleanup);
+
+	if (!scheme) {
+		return -1;
+	}
+
+	return scheme->file->create(sorcery, data, object);
+}
+
+/*! \brief Callback function for retrieving a bucket file */
+static void *bucket_file_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
+	const char *id)
+{
+	char *full_uri, *scheme_name = DEFAULT_UNSPECIFIED_SCHEME, *tmp;
+	RAII_VAR(struct bucket_scheme *, scheme, NULL, ao2_cleanup);
+
+	if (!(full_uri = ast_strdupa(id))) {
+		return NULL;
+	}
+
+	/* Assume no scheme until proven otherwise */
+	if ((tmp = strstr(full_uri, "://"))) {
+		scheme_name = full_uri;
+		*tmp++ = '\0';
+
+		/* If only a scheme has been specified this URI is invalid */
+		if (ast_strlen_zero(tmp)) {
+			return NULL;
+		}
+	}
+
+	if (ast_strlen_zero(scheme_name)) {
+		return NULL;
+	}
+
+	scheme = ao2_find(schemes, scheme_name, OBJ_KEY);
+	if (!scheme) {
+		return NULL;
+	}
+
+	return scheme->file->retrieve_id(sorcery, data, type, id);
+}
+
+/*! \brief Callback function for updating a bucket file */
+static int bucket_file_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
+{
+	struct ast_bucket_file *file = object;
+	RAII_VAR(struct bucket_scheme *, scheme, ao2_find(schemes, file->scheme, OBJ_KEY), ao2_cleanup);
+
+	if (!scheme) {
+		return -1;
+	}
+
+	return scheme->file->update(sorcery, data, object);
+}
+
+/*! \brief Callback function for deleting a bucket file */
+static int bucket_file_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
+{
+	struct ast_bucket_file *file = object;
+	RAII_VAR(struct bucket_scheme *, scheme, ao2_find(schemes, file->scheme, OBJ_KEY), ao2_cleanup);
+
+	if (!scheme) {
+		return -1;
+	}
+
+	return scheme->file->delete(sorcery, data, object);
+}
+
 /*! \brief Intermediary file wizard */
 static struct ast_sorcery_wizard bucket_file_wizard = {
 	.name = "bucket_file",
+	.create = bucket_file_wizard_create,
+	.retrieve_id = bucket_file_wizard_retrieve,
+	.update = bucket_file_wizard_update,
+	.delete = bucket_file_wizard_delete,
 };
 
 int ast_bucket_scheme_register(const char *name, struct ast_sorcery_wizard *bucket,
@@ -422,6 +502,24 @@
 	return json;
 }
 
+/*! \brief Hashing function for file metadata */
+static int bucket_file_metadata_hash(const void *obj, const int flags)
+{
+	const struct ast_bucket_metadata *metadata = obj;
+	const char *name = obj;
+
+	return ast_str_hash(flags & OBJ_KEY ? name : metadata->name);
+}
+
+/*! \brief Comparison function for file metadata */
+static int bucket_file_metadata_cmp(void *obj, void *arg, int flags)
+{
+	struct ast_bucket_metadata *metadata1 = obj, *metadata2 = arg;
+	const char *name = arg;
+
+	return !strcmp(metadata1->name, flags & OBJ_KEY ? name : metadata2->name) ? CMP_MATCH | CMP_STOP : 0;
+}
+
 /*! \brief Destructor for bucket files */
 static void bucket_file_destroy(void *obj)
 {
@@ -433,13 +531,98 @@
 /*! \brief Allocator for bucket files */
 static void *bucket_file_alloc(const char *name)
 {
-	struct ast_bucket_file *file = ast_sorcery_generic_alloc(sizeof(*file), bucket_file_destroy);
-
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+
+	file = ast_sorcery_generic_alloc(sizeof(*file), bucket_file_destroy);
 	if (!file) {
 		return NULL;
 	}
 
+	if (ast_string_field_init(file, 128)) {
+		return NULL;
+	}
+
+	file->metadata = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, METADATA_BUCKETS,
+		bucket_file_metadata_hash, bucket_file_metadata_cmp);
+	if (!file->metadata) {
+		return NULL;
+	}
+
+	ao2_ref(file, +1);
 	return file;
+}
+
+struct ast_bucket_file *ast_bucket_file_alloc(const char *uri)
+{
+	char *full_uri, *scheme = DEFAULT_UNSPECIFIED_SCHEME, *name, *tmp;
+	struct ast_bucket_file *file;
+
+	if (ast_strlen_zero(uri) || !(full_uri = ast_strdupa(uri))) {
+		return NULL;
+	}
+
+	/* Assume the naming starts at the front until proven otherwise */
+	name = full_uri;
+
+	/* Determine the scheme from the provided URI */
+	if ((tmp = strstr(full_uri, "://"))) {
+		scheme = full_uri;
+		*tmp++ = '\0';
+		name = tmp;
+	}
+
+	/* Determine the name of the bucket */
+	if ((tmp = strrchr(name, '/'))) {
+		name = tmp + 1;
+	}
+
+	/* If no scheme and name are available the URI is invalid */
+	if (ast_strlen_zero(scheme) || ast_strlen_zero(name)) {
+		return NULL;
+	}
+
+	if (!(file = ast_sorcery_alloc(bucket_sorcery, "file", name))) {
+		return NULL;
+	}
+
+	ast_string_field_set(file, uri, uri);
+	ast_string_field_set(file, scheme, scheme);
+
+	return file;
+}
+
+int ast_bucket_file_create(struct ast_bucket_file *file)
+{
+	return ast_sorcery_create(bucket_sorcery, file);
+}
+
+struct ast_bucket_file *ast_bucket_file_retrieve(const char *uri)
+{
+	if (ast_strlen_zero(uri)) {
+		return NULL;
+	}
+
+	return ast_sorcery_retrieve_by_id(bucket_sorcery, "file", uri);
+}
+
+int ast_bucket_file_observer_add(const struct ast_sorcery_observer *callbacks)
+{
+	return ast_sorcery_observer_add(bucket_sorcery, "file", callbacks);
+}
+
+void ast_bucket_file_observer_remove(struct ast_sorcery_observer *callbacks)
+{
+	ast_sorcery_observer_remove(bucket_sorcery, "file", callbacks);
+}
+
+int ast_bucket_file_update(struct ast_bucket_file *file)
+{
+	return ast_sorcery_update(bucket_sorcery, file);
+}
+
+int ast_bucket_file_delete(struct ast_bucket_file *file)
+{
+	return ast_sorcery_delete(bucket_sorcery, file);
 }
 
 /*! \brief Hashing function for scheme container */
@@ -537,6 +720,11 @@
 		goto failure;
 	}
 
+	ast_sorcery_object_field_register(bucket_sorcery, "file", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket_file, uri));
+	ast_sorcery_object_field_register(bucket_sorcery, "file", "scheme", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket_file, scheme));
+	ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "created", "", timeval_str2struct, timeval_struct2str, 0, FLDSET(struct ast_bucket_file, created));
+	ast_sorcery_object_field_register_custom(bucket_sorcery, "file", "modified", "", timeval_str2struct, timeval_struct2str, 0, FLDSET(struct ast_bucket_file, modified));
+
 	ast_register_cleanup(bucket_cleanup);
 
 	return 0;

Modified: team/file/bucket/tests/test_bucket.c
URL: http://svnview.digium.com/svn/asterisk/team/file/bucket/tests/test_bucket.c?view=diff&rev=395617&r1=395616&r2=395617
==============================================================================
--- team/file/bucket/tests/test_bucket.c (original)
+++ team/file/bucket/tests/test_bucket.c Sun Jul 28 16:44:59 2013
@@ -71,11 +71,24 @@
 	return 0;
 }
 
+static int bucket_test_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
+{
+	if (bucket_test_wizard_state.updated) {
+		return -1;
+	}
+
+	bucket_test_wizard_state.updated = 1;
+
+	return 0;
+}
+
 static void *bucket_test_wizard_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, 
 	const char *id)
 {
 	if (!strcmp(type, "bucket")) {
 		return ast_bucket_alloc(id);
+	} else if (!strcmp(type, "file")) {
+		return ast_bucket_file_alloc(id);
 	} else {
 		return NULL;
 	}
@@ -102,6 +115,7 @@
 static struct ast_sorcery_wizard bucket_file_test_wizard = {
 	.name = "test",
 	.create = bucket_test_wizard_create,
+	.update = bucket_test_wizard_update,
 	.retrieve_id = bucket_test_wizard_retrieve_id,
 	.delete = bucket_test_wizard_delete,
 };
@@ -429,6 +443,356 @@
 	return AST_TEST_PASS;
 }
 
+AST_TEST_DEFINE(bucket_file_alloc)
+{
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "bucket_file_alloc";
+		info->category = "/main/bucket/";
+		info->summary = "bucket file allocation unit test";
+		info->description =
+			"Test allocation of bucket files";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if ((file = ast_bucket_file_alloc(""))) {
+		ast_test_status_update(test, "Allocated a file with no URI provided\n");
+		return AST_TEST_FAIL;
+	}
+
+	if ((file = ast_bucket_file_alloc("goat://"))) {
+		ast_test_status_update(test, "Allocated a file with no name\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!(file = ast_bucket_file_alloc("goat:///tmp/bob"))) {
+		ast_test_status_update(test, "Failed to allocate file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (strcmp(file->uri, "goat:///tmp/bob")) {
+		ast_test_status_update(test, "URI within allocated file is '%s' and should be goat:///tmp/bob\n",
+			file->uri);
+		return AST_TEST_FAIL;
+	}
+
+	if (strcmp(file->scheme, "goat")) {
+		ast_test_status_update(test, "Scheme within allocated file is '%s' and should be goat\n",
+			file->scheme);
+		return AST_TEST_FAIL;
+	}
+
+	if (strcmp(ast_sorcery_object_get_id(file), "bob")) {
+		ast_test_status_update(test, "File id is '%s' and should be bob\n",
+			ast_sorcery_object_get_id(file));
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(bucket_file_create)
+{
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+	RAII_VAR(void *, dummy, bucket_test_scheme_register(), bucket_test_scheme_unregister);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "bucket_file_create";
+		info->category = "/main/bucket/";
+		info->summary = "file creation unit test";
+		info->description =
+			"Test creation of files";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
+		ast_test_status_update(test, "Failed to allocate file\n");
+		return AST_TEST_FAIL;
+	}
+
+	bucket_test_wizard_clear();
+
+	if (ast_bucket_file_create(file)) {
+		ast_test_status_update(test, "Failed to create file with URI '%s'\n",
+			file->uri);
+		return AST_TEST_FAIL;
+	}
+
+	if (!bucket_test_wizard_state.created) {
+		ast_test_status_update(test, "Successfully returned file was created, but it was not\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!ast_bucket_file_create(file)) {
+		ast_test_status_update(test, "Successfully created file with URI '%s' twice\n",
+			file->uri);
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(bucket_file_retrieve)
+{
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+	RAII_VAR(void *, dummy, bucket_test_scheme_register(), bucket_test_scheme_unregister);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "bucket_file_retrieve";
+		info->category = "/main/bucket/";
+		info->summary = "file retrieval unit test";
+		info->description =
+			"Test retrieval of files";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(file = ast_bucket_file_retrieve("test://tmp/bob"))) {
+		ast_test_status_update(test, "Failed to retrieve known valid file\n");
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(bucket_file_update)
+{
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+	RAII_VAR(void *, dummy, bucket_test_scheme_register(), bucket_test_scheme_unregister);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "bucket_file_update";
+		info->category = "/main/bucket/";
+		info->summary = "file updating unit test";
+		info->description =
+			"Test updating of files";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
+		ast_test_status_update(test, "Failed to allocate file\n");
+		return AST_TEST_FAIL;
+	}
+
+	bucket_test_wizard_clear();
+
+	if (ast_bucket_file_update(file)) {
+		ast_test_status_update(test, "Failed to update file with URI '%s'\n",
+			file->uri);
+		return AST_TEST_FAIL;
+	}
+
+	if (!bucket_test_wizard_state.updated) {
+		ast_test_status_update(test, "Successfully returned file was updated, but it was not\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!ast_bucket_file_update(file)) {
+		ast_test_status_update(test, "Successfully updated file with URI '%s' twice\n",
+			file->uri);
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(bucket_file_delete)
+{
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+	RAII_VAR(void *, dummy, bucket_test_scheme_register(), bucket_test_scheme_unregister);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "bucket_file_delete";
+		info->category = "/main/bucket/";
+		info->summary = "file deletion unit test";
+		info->description =
+			"Test deletion of files";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
+		ast_test_status_update(test, "Failed to allocate file\n");
+		return AST_TEST_FAIL;
+	}
+
+	bucket_test_wizard_clear();
+
+	if (ast_bucket_file_delete(file)) {
+		ast_test_status_update(test, "Failed to delete file with URI '%s'\n",
+			file->uri);
+		return AST_TEST_FAIL;
+	}
+
+	if (!bucket_test_wizard_state.deleted) {
+		ast_test_status_update(test, "Successfully returned file was deleted, but it was not\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!ast_bucket_file_delete(file)) {
+		ast_test_status_update(test, "Successfully deleted file with URI '%s' twice\n",
+			file->uri);
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(bucket_file_metadata_set)
+{
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "bucket_file_metadata_set";
+		info->category = "/main/bucket/";
+		info->summary = "file metadata setting unit test";
+		info->description =
+			"Test setting of metadata on files";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
+		ast_test_status_update(test, "Failed to allocate file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ao2_container_count(file->metadata) != 0) {
+		ast_test_status_update(test, "Newly allocated file has metadata count of '%d' when should be 0\n",
+			ao2_container_count(file->metadata));
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
+		ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!(metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
+		ast_test_status_update(test, "Failed to find set metadata 'bob' on newly allocated file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (strcmp(metadata->value, "joe")) {
+		ast_test_status_update(test, "Metadata has value '%s' when should be 'joe'\n",
+			metadata->value);
+		return AST_TEST_FAIL;
+	}
+
+	ao2_cleanup(metadata);
+	metadata = NULL;
+
+	if (ast_bucket_file_metadata_set(file, "bob", "fred")) {
+		ast_test_status_update(test, "Failed to overwrite metadata 'bob' with new value 'fred'\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!(metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
+		ast_test_status_update(test, "Failed to find overwritten metadata 'bob' on newly allocated file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (strcmp(metadata->value, "fred")) {
+		ast_test_status_update(test, "Metadata has value '%s' when should be 'fred'\n",
+			metadata->value);
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(bucket_file_metadata_unset)
+{
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "bucket_file_metadata_unset";
+		info->category = "/main/bucket/";
+		info->summary = "file metadata unsetting unit test";
+		info->description =
+			"Test unsetting of metadata on files";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
+		ast_test_status_update(test, "Failed to allocate file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
+		ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_bucket_file_metadata_unset(file, "bob")) {
+		ast_test_status_update(test, "Failed to unset metadata 'bob' on newly allocated file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if ((metadata = ao2_find(file->metadata, "bob", OBJ_KEY))) {
+		ast_test_status_update(test, "Metadata 'bob' was unset, but can still be found\n");
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
+AST_TEST_DEFINE(bucket_file_metadata_get)
+{
+	RAII_VAR(struct ast_bucket_file *, file, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_bucket_metadata *, metadata, NULL, ao2_cleanup);
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "bucket_file_metadata_get";
+		info->category = "/main/bucket/";
+		info->summary = "file metadata getting unit test";
+		info->description =
+			"Test getting of metadata on files";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	if (!(file = ast_bucket_file_alloc("test:///tmp/bob"))) {
+		ast_test_status_update(test, "Failed to allocate file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (ast_bucket_file_metadata_set(file, "bob", "joe")) {
+		ast_test_status_update(test, "Failed to set metadata 'bob' to 'joe' on newly allocated file\n");
+		return AST_TEST_FAIL;
+	}
+
+	if (!(metadata = ast_bucket_file_metadata_get(file, "bob"))) {
+		ast_test_status_update(test, "Failed to retrieve metadata 'bob' that was just set\n");
+		return AST_TEST_FAIL;
+	}
+
+	return AST_TEST_PASS;
+}
+
 static int unload_module(void)
 {
 	AST_TEST_UNREGISTER(bucket_scheme_register_unregister);
@@ -437,6 +801,14 @@
 	AST_TEST_UNREGISTER(bucket_delete);
 	AST_TEST_UNREGISTER(bucket_retrieve);
 	AST_TEST_UNREGISTER(bucket_json);
+	AST_TEST_UNREGISTER(bucket_file_alloc);
+	AST_TEST_UNREGISTER(bucket_file_create);
+	AST_TEST_UNREGISTER(bucket_file_retrieve);
+	AST_TEST_UNREGISTER(bucket_file_update);
+	AST_TEST_UNREGISTER(bucket_file_delete);
+	AST_TEST_UNREGISTER(bucket_file_metadata_set);
+	AST_TEST_UNREGISTER(bucket_file_metadata_unset);
+	AST_TEST_UNREGISTER(bucket_file_metadata_get);
 	return 0;
 }
 
@@ -448,6 +820,14 @@
 	AST_TEST_REGISTER(bucket_delete);
 	AST_TEST_REGISTER(bucket_retrieve);
 	AST_TEST_REGISTER(bucket_json);
+	AST_TEST_REGISTER(bucket_file_alloc);
+	AST_TEST_REGISTER(bucket_file_create);
+	AST_TEST_REGISTER(bucket_file_retrieve);
+	AST_TEST_REGISTER(bucket_file_update);
+	AST_TEST_REGISTER(bucket_file_delete);
+	AST_TEST_REGISTER(bucket_file_metadata_set);
+	AST_TEST_REGISTER(bucket_file_metadata_unset);
+	AST_TEST_REGISTER(bucket_file_metadata_get);
 	return AST_MODULE_LOAD_SUCCESS;
 }
 




More information about the svn-commits mailing list