mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-16 18:25:11 -06:00
Add a read-only attribute to QofBook and check of same to
qof_instance_begin_edit. Add qof_session_safe_save. Add unit tests for these changes. QofBook read-only attribute is to prevent starting an edit when the version of Gnucash which created a dataset is newer than the one currently running. This is to prevent writing records of an old format into an existing data set. The user can use File>Save As to create a new QofSession which will write a completely new dataset in the current format. This is an important safety feature for future versions of Gnucash which will not bring all of a dataset into memory, instead loading only what is immediately needed. Safe-save is the Qof access to allow writing out a dataset to an existing server database (i.e., postgresql or mysql) while maintaining the ability to both transaction-protect saving individual records while maintaining the ability to rollback the entire save if something goes wrong. The unit test framework is added to enable testing these components. More tests will be added in a later commit. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@20103 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
parent
d8733bf204
commit
886da7638d
@ -1,3 +1,5 @@
|
||||
SUBDIRS = test
|
||||
|
||||
lib_LTLIBRARIES = libgnc-qof.la
|
||||
|
||||
libgnc_qof_la_LDFLAGS= -version-info $(LIBQOF_LIBRARY_VERSION)
|
||||
|
@ -311,6 +311,7 @@ struct QofBackend_s
|
||||
void (*run_query) (QofBackend *, gpointer);
|
||||
|
||||
void (*sync) (QofBackend *, /*@ dependent @*/ QofBook *);
|
||||
void (*safe_sync) (QofBackend *, /*@ dependent @*/ QofBook *);
|
||||
void (*load_config) (QofBackend *, KvpFrame *);
|
||||
/*@ observer @*/
|
||||
KvpFrame* (*get_config) (QofBackend *);
|
||||
|
@ -129,6 +129,7 @@ qof_backend_init(QofBackend *be)
|
||||
be->run_query = NULL;
|
||||
|
||||
be->sync = NULL;
|
||||
be->safe_sync = NULL;
|
||||
be->load_config = NULL;
|
||||
|
||||
be->events_pending = NULL;
|
||||
|
@ -107,6 +107,7 @@ typedef enum
|
||||
/* database errors */
|
||||
ERR_SQL_MISSING_DATA = 3000, /**< database doesn't contain expected data */
|
||||
ERR_SQL_DB_TOO_OLD, /**< database is old and needs upgrading */
|
||||
ERR_SQL_DB_TOO_NEW, /**< database is newer, we can't write to it */
|
||||
ERR_SQL_DB_BUSY, /**< database is busy, cannot upgrade version */
|
||||
|
||||
/* RPC errors */
|
||||
|
@ -76,6 +76,7 @@ qof_book_init (QofBook *book)
|
||||
book->data_table_finalizers = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
book->book_open = 'y';
|
||||
book->read_only = FALSE;
|
||||
book->version = 0;
|
||||
}
|
||||
|
||||
@ -301,6 +302,20 @@ qof_book_get_data (const QofBook *book, const char *key)
|
||||
return g_hash_table_lookup (book->data_tables, (gpointer)key);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
||||
gboolean
|
||||
qof_book_is_readonly(const QofBook *book)
|
||||
{
|
||||
g_return_val_if_fail( book != NULL, TRUE );
|
||||
return book->read_only;
|
||||
}
|
||||
|
||||
void
|
||||
qof_book_mark_readonly(QofBook *book)
|
||||
{
|
||||
g_return_if_fail( book != NULL );
|
||||
book->read_only = TRUE;
|
||||
}
|
||||
/* ====================================================================== */
|
||||
|
||||
QofCollection *
|
||||
|
@ -96,6 +96,12 @@ struct _QofBook
|
||||
/* Hash table of destroy callbacks for the data table. */
|
||||
GHashTable *data_table_finalizers;
|
||||
|
||||
/* Boolean indicates whether book is safe to write to (true means
|
||||
* that it isn't. The usual reason will be a database version
|
||||
* mismatch with the running instance of Gnucash.
|
||||
*/
|
||||
gboolean read_only;
|
||||
|
||||
/* state flag: 'y' means 'open for editing',
|
||||
* 'n' means 'book is closed'
|
||||
* xxxxx shouldn't this be replaced by the instance editlevel ???
|
||||
@ -221,6 +227,12 @@ void qof_book_set_data_fin (QofBook *book, const gchar *key, gpointer data,
|
||||
/** Retrieves arbitrary pointers to structs stored by qof_book_set_data. */
|
||||
gpointer qof_book_get_data (const QofBook *book, const gchar *key);
|
||||
|
||||
/** Return whether the book is read only. */
|
||||
gboolean qof_book_is_readonly(const QofBook *book);
|
||||
|
||||
/** Mark the book as read only. */
|
||||
void qof_book_mark_readonly(QofBook *book);
|
||||
|
||||
#endif /* SWIG */
|
||||
|
||||
/** Returns flag indicating whether this book uses trading accounts */
|
||||
|
@ -1055,6 +1055,7 @@ qof_begin_edit (QofInstance *inst)
|
||||
if (!inst) return FALSE;
|
||||
|
||||
priv = GET_PRIVATE(inst);
|
||||
if (qof_book_is_readonly(priv->book)) return FALSE;
|
||||
priv->editlevel++;
|
||||
if (1 < priv->editlevel) return FALSE;
|
||||
if (0 >= priv->editlevel)
|
||||
|
@ -1250,9 +1250,10 @@ qof_session_load (QofSession *session,
|
||||
*/
|
||||
err = qof_session_get_error(session);
|
||||
if ((err != ERR_BACKEND_NO_ERR) &&
|
||||
(err != ERR_FILEIO_FILE_TOO_OLD) &&
|
||||
(err != ERR_FILEIO_NO_ENCODING) &&
|
||||
(err != ERR_SQL_DB_TOO_OLD))
|
||||
(err != ERR_FILEIO_FILE_TOO_OLD) &&
|
||||
(err != ERR_FILEIO_NO_ENCODING) &&
|
||||
(err != ERR_SQL_DB_TOO_OLD) &&
|
||||
(err != ERR_SQL_DB_TOO_NEW))
|
||||
{
|
||||
/* Something broke, put back the old stuff */
|
||||
qof_book_set_backend (newbook, NULL);
|
||||
@ -1262,7 +1263,6 @@ qof_session_load (QofSession *session,
|
||||
LEAVE("error from backend %d", qof_session_get_error(session));
|
||||
return;
|
||||
}
|
||||
|
||||
for (node = oldbooks; node; node = node->next)
|
||||
{
|
||||
ob = node->data;
|
||||
@ -1450,6 +1450,27 @@ leave:
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
qof_session_safe_save(QofSession *session, QofPercentageFunc percentage_func)
|
||||
{
|
||||
QofBackend *be = session->backend;
|
||||
gint err;
|
||||
char *msg = NULL;
|
||||
g_return_if_fail( be != NULL );
|
||||
g_return_if_fail( be->safe_sync != NULL );
|
||||
be->percentage = percentage_func;
|
||||
(be->safe_sync)( be, qof_session_get_book( session ));
|
||||
err = qof_backend_get_error(session->backend);
|
||||
msg = qof_backend_get_message(session->backend);
|
||||
if (err != ERR_BACKEND_NO_ERR)
|
||||
{
|
||||
g_free(session->book_id);
|
||||
session->book_id = NULL;
|
||||
qof_session_push_error (session, err, msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================== */
|
||||
gboolean
|
||||
qof_session_save_in_progress(const QofSession *session)
|
||||
|
@ -234,6 +234,17 @@ gboolean qof_session_save_in_progress(const QofSession *session);
|
||||
*/
|
||||
void qof_session_save (QofSession *session,
|
||||
QofPercentageFunc percentage_func);
|
||||
|
||||
/**
|
||||
* A special version of save used in the sql backend which moves the
|
||||
* existing tables aside, then saves everything to new tables, then
|
||||
* deletes the old tables after the save is completed without
|
||||
* error. If there are errors, it removes the old tables and renames
|
||||
* the new tables back.
|
||||
*/
|
||||
void qof_session_safe_save (QofSession *session,
|
||||
QofPercentageFunc percentage_func);
|
||||
|
||||
/**
|
||||
* The qof_session_end() method will release the session lock. For the
|
||||
* file backend, it will *not* save the data to a file. Thus,
|
||||
|
34
src/libqof/qof/test/Makefile.am
Normal file
34
src/libqof/qof/test/Makefile.am
Normal file
@ -0,0 +1,34 @@
|
||||
# A template Makefile.am for GLib g_test-based test directories.
|
||||
# Copyright 2011 John Ralls <jralls@ceridwen.us>
|
||||
|
||||
include $(top_srcdir)/test-templates/Makefile.decl
|
||||
|
||||
|
||||
#You will only need one of these: It points to the module directory
|
||||
#after $(top_srcdir) or $(top_builddir):
|
||||
MODULEPATH = src/libqof/qof
|
||||
|
||||
test_qof_SOURCES = \
|
||||
test-qof.c \
|
||||
test-qofbook.c \
|
||||
test-qofinstance.c \
|
||||
test-qofsession.c
|
||||
|
||||
test_qof_HEADERSS = \
|
||||
$(top_srcdir)/${MODULEPATH}/qofbook.h \
|
||||
$(top_srcdir)/${MODULEPATH}/qofinstance.h \
|
||||
$(top_srcdir)/${MODULEPATH/}qofsession.h
|
||||
|
||||
TEST_PROGS += test-qof
|
||||
|
||||
noinst_PROGRAMS = ${TEST_PROGS}
|
||||
|
||||
#The tests might require more libraries, but try to keep them
|
||||
#as independent as possible.
|
||||
test_qof_LDADD = ${top_builddir}/${MODULEPATH}/libgnc-qof.la
|
||||
|
||||
test_qof_CFLAGS = \
|
||||
${DEFAULT_INCLUDES} \
|
||||
-I$(top_srcdir)/${MODULEPATH}/ \
|
||||
-DTESTPROG=test_qof \
|
||||
${GLIB_CFLAGS}
|
45
src/libqof/qof/test/test-qof.c
Normal file
45
src/libqof/qof/test/test-qof.c
Normal file
@ -0,0 +1,45 @@
|
||||
/********************************************************************
|
||||
* testmain.c: GLib g_test test execution file. *
|
||||
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
extern void test_suite_qofbook();
|
||||
extern void test_suite_qofinstance();
|
||||
extern void test_suite_qofsession();
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
g_type_init(); /* Initialize the GObject system */
|
||||
g_test_init ( &argc, &argv ); /* initialize test program */
|
||||
qof_log_init_filename_special("/dev/null"); /* Init the log system */
|
||||
|
||||
test_suite_qofbook();
|
||||
test_suite_qofinstance();
|
||||
test_suite_qofsession();
|
||||
|
||||
return g_test_run( );
|
||||
}
|
||||
|
||||
|
31
src/libqof/qof/test/test-qofbackend.c
Normal file
31
src/libqof/qof/test/test-qofbackend.c
Normal file
@ -0,0 +1,31 @@
|
||||
/********************************************************************
|
||||
* test_qofbackend.c: GLib g_test test suite for qofbackend. *
|
||||
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#include <glib/glib.h>
|
||||
|
||||
static const gchar *suitename = "qof/qofbackend";
|
||||
|
||||
GTestSuite*
|
||||
test_suite_qofbackend ( void )
|
||||
{
|
||||
|
||||
}
|
59
src/libqof/qof/test/test-qofbook.c
Normal file
59
src/libqof/qof/test/test-qofbook.c
Normal file
@ -0,0 +1,59 @@
|
||||
/********************************************************************
|
||||
* test_qofbook.c: GLib g_test test suite for qofbook. *
|
||||
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <qof.h>
|
||||
|
||||
static const gchar *suitename = "/qof/qofbook";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QofBook *book;
|
||||
} Fixture;
|
||||
|
||||
static void
|
||||
setup( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
fixture->book = qof_book_new();
|
||||
}
|
||||
|
||||
static void
|
||||
teardown( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
qof_book_destroy( fixture->book );
|
||||
}
|
||||
|
||||
static void
|
||||
test_book_readonly( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
g_assert( fixture->book != NULL );
|
||||
g_assert( !qof_book_is_readonly( fixture->book ) );
|
||||
qof_book_mark_readonly( fixture->book );
|
||||
g_assert( qof_book_is_readonly( fixture->book ) );
|
||||
}
|
||||
|
||||
void
|
||||
test_suite_qofbook ( void )
|
||||
{
|
||||
g_test_add( suitename, Fixture, NULL, setup, test_book_readonly, teardown );
|
||||
}
|
63
src/libqof/qof/test/test-qofinstance.c
Normal file
63
src/libqof/qof/test/test-qofinstance.c
Normal file
@ -0,0 +1,63 @@
|
||||
/********************************************************************
|
||||
* test_qofinstance.c: GLib g_test test suite for qofinstance. *
|
||||
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <qof.h>
|
||||
|
||||
static const gchar *suitename = "/qof/qofinstance";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QofInstance *instance;
|
||||
} Fixture;
|
||||
|
||||
static void
|
||||
setup( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
fixture->instance = g_object_new(QOF_TYPE_INSTANCE, NULL);
|
||||
qof_instance_set_book( fixture->instance, qof_book_new() );
|
||||
}
|
||||
|
||||
static void
|
||||
teardown( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
qof_book_destroy( qof_instance_get_book( fixture->instance ) );
|
||||
g_object_unref(fixture->instance);
|
||||
}
|
||||
|
||||
static void
|
||||
test_book_readonly( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
QofBook *book = qof_instance_get_book( fixture->instance );
|
||||
g_assert( !qof_book_is_readonly( book ) );
|
||||
qof_book_mark_readonly( book );
|
||||
g_assert( qof_book_is_readonly( book ) );
|
||||
g_assert( !qof_begin_edit( fixture->instance ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
test_suite_qofinstance ( void )
|
||||
{
|
||||
g_test_add( suitename, Fixture, NULL, setup, test_book_readonly, teardown );
|
||||
|
||||
}
|
76
src/libqof/qof/test/test-qofsession.c
Normal file
76
src/libqof/qof/test/test-qofsession.c
Normal file
@ -0,0 +1,76 @@
|
||||
/********************************************************************
|
||||
* test_qofsession.c: GLib g_test test suite for qofsession. *
|
||||
* Copyright 2011 John Ralls <jralls@ceridwen.us> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License as *
|
||||
* published by the Free Software Foundation; either version 2 of *
|
||||
* the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License*
|
||||
* along with this program; if not, contact: *
|
||||
* *
|
||||
* Free Software Foundation Voice: +1-617-542-5942 *
|
||||
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
|
||||
* Boston, MA 02110-1301, USA gnu@gnu.org *
|
||||
\********************************************************************/
|
||||
|
||||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <qof.h>
|
||||
#include <qofbackend-p.h>
|
||||
#include <qofsession-p.h>
|
||||
|
||||
static const gchar *suitename = "/qof/qofsession";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
QofSession *session;
|
||||
} Fixture;
|
||||
|
||||
static void
|
||||
safe_sync( QofBackend *be, QofBook *book )
|
||||
{
|
||||
qof_backend_set_error( be, ERR_BACKEND_DATA_CORRUPT );
|
||||
qof_backend_set_message( be, "Just Kidding!" );
|
||||
}
|
||||
|
||||
static void
|
||||
percentage_fn ( const char* message, double percent )
|
||||
{
|
||||
g_print( "%s %f complete", message, percent );
|
||||
}
|
||||
|
||||
static void
|
||||
setup( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
fixture->session = qof_session_new();
|
||||
fixture->session->backend = g_new0( QofBackend, 1 );
|
||||
fixture->session->backend->safe_sync = safe_sync;
|
||||
}
|
||||
|
||||
static void
|
||||
teardown( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
qof_session_destroy( fixture->session );
|
||||
}
|
||||
|
||||
static void
|
||||
test_session_safe_save( Fixture *fixture, gconstpointer pData )
|
||||
{
|
||||
qof_session_safe_save( fixture->session, percentage_fn );
|
||||
g_assert_cmpint( ERR_BACKEND_DATA_CORRUPT, ==,
|
||||
qof_session_get_error( fixture->session ));
|
||||
g_assert( NULL == qof_session_get_url( fixture->session ));
|
||||
}
|
||||
|
||||
GTestSuite*
|
||||
test_suite_qofsession ( void )
|
||||
{
|
||||
g_test_add( suitename, Fixture, NULL, setup, test_session_safe_save, teardown );
|
||||
}
|
Loading…
Reference in New Issue
Block a user