From 9afc2fc598ad458247f7c3591147d9ef3702acb9 Mon Sep 17 00:00:00 2001 From: Dave Peticolas Date: Tue, 16 Oct 2001 09:13:07 +0000 Subject: [PATCH] 2001-10-16 Dave Peticolas * src/engine/test-core/test-engine-stuff.c: work on test infrastructure for making changes to existing data * src/engine/gnc-book.c: keep backends up to date * src/engine/gnc-session.c: keep backends up to date * src/backend/postgres/test/db-control.sh: bring down postmaster on database create and destroy * src/backend/postgres/test/test-db.c: work on single-update test * src/backend/postgres/txn.c: fix bug -- when deleting splits from the database that aren't in the engine, can't use xaccSplitLookup. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@5661 57a11ea4-9604-0410-9ed3-97b8803252fd --- ChangeLog | 20 +- src/backend/postgres/test/db-control.sh | 2 + src/backend/postgres/test/test-db.c | 103 ++++++++- src/backend/postgres/txn.c | 65 ++++-- src/engine/gnc-book.c | 10 +- src/engine/gnc-session.c | 23 +- src/engine/test-core/test-engine-stuff.c | 257 +++++++++++++++++++++++ src/engine/test-core/test-engine-stuff.h | 6 + 8 files changed, 459 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6686e05caa..7b63ff91ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2001-10-16 Dave Peticolas + + * src/engine/test-core/test-engine-stuff.c: work on test + infrastructure for making changes to existing data + + * src/engine/gnc-book.c: keep backends up to date + + * src/engine/gnc-session.c: keep backends up to date + + * src/backend/postgres/test/db-control.sh: bring down postmaster + on database create and destroy + + * src/backend/postgres/test/test-db.c: work on single-update + test + + * src/backend/postgres/txn.c: fix bug -- when deleting splits + from the database that aren't in the engine, can't use + xaccSplitLookup. + 2001-10-14 Joshua Sled * src/gnome/dialog-scheduledxaction.c (delete_button_clicked): @@ -22,7 +41,6 @@ * src/app-utils/prefs.scm: Updates to wording, defaults for Scheduled Transaction preferences. - 2001-10-14 Rob Browning * src/backend/file/test/Makefile.am diff --git a/src/backend/postgres/test/db-control.sh b/src/backend/postgres/test/db-control.sh index b588939bab..1d8d94376d 100755 --- a/src/backend/postgres/test/db-control.sh +++ b/src/backend/postgres/test/db-control.sh @@ -8,10 +8,12 @@ PG_CTL="pg_ctl -D $DB -o -p7777" case $1 in create) + $PG_CTL status | grep "pid" && $PG_CTL stop rm -rf $DB initdb $DB || EXIT_VALUE=1 ;; destroy) + $PG_CTL status | grep "pid" && $PG_CTL stop rm -rf $DB ;; start) diff --git a/src/backend/postgres/test/test-db.c b/src/backend/postgres/test/test-db.c index d876436d84..ce6b4bd785 100644 --- a/src/backend/postgres/test/test-db.c +++ b/src/backend/postgres/test/test-db.c @@ -201,6 +201,100 @@ test_access (const char *db_name, const char *mode, gboolean multi_user) return TRUE; } +static gboolean +test_updates (GNCSession *session, const char *db_name, const char *mode, + gboolean multi_user) +{ + GNCBackendError io_err; + GNCSession *session_2; + char *filename; + gboolean ok; + + g_return_val_if_fail (session && db_name && mode, FALSE); + + filename = db_file_url (db_name, mode); + + gnc_session_begin (session, filename, FALSE, FALSE); + io_err = gnc_session_get_error (session); + if (!do_test_args (io_err == ERR_BACKEND_NO_ERR, + "Beginning db update session", + __FILE__, __LINE__, + "can't begin session for %s in mode %s", + db_name, mode)) + return FALSE; + + /* make_random_changes_to_session (session); */ + { + Account *account; + + account = xaccGroupGetAccount (gnc_book_get_group (gnc_session_get_book (session)), 0); + + if (account) + { + xaccAccountBeginEdit (account); + + switch (xaccAccountGetType (account)) + { + case BANK: + xaccAccountSetType (account, CHECKING); + break; + default: + xaccAccountSetType (account, BANK); + break; + } + + xaccAccountCommitEdit (account); + } + else + failure ("no account"); + } + + if (!multi_user) + { + gnc_session_end (session); + io_err = gnc_session_get_error (session); + if (!do_test_args (io_err == ERR_BACKEND_NO_ERR, + "Ending db session", + __FILE__, __LINE__, + "can't end session for %s in mode %s", + db_name, mode)) + return FALSE; + } + + session_2 = gnc_session_new (); + + if (!load_db_file (session_2, db_name, mode)) + return FALSE; + + ok = gnc_book_equal (gnc_session_get_book (session), + gnc_session_get_book (session_2)); + + do_test_args (ok, "Books equal after update", __FILE__, __LINE__, + "Books not equal for session %s in mode %s", + db_name, mode); + + if (!ok) + { + save_xml_files (session, session_2); + return FALSE; + } + + if (multi_user) + { + gnc_session_end (session); + io_err = gnc_session_get_error (session); + if (!do_test_args (io_err == ERR_BACKEND_NO_ERR, + "Ending db session", + __FILE__, __LINE__, + "can't end session for %s in mode %s", + db_name, mode)) + return FALSE; + } + + gnc_session_destroy (session_2); + g_free (filename); +} + static gboolean test_mode (const char *db_name, const char *mode, gboolean updates, gboolean multi_user) @@ -237,6 +331,9 @@ test_mode (const char *db_name, const char *mode, ok = test_access (db_name, mode, multi_user); + if (updates && !test_updates (session_db, db_name, mode, multi_user)) + return FALSE; + gnc_session_destroy (session); gnc_session_destroy (session_db); @@ -249,7 +346,7 @@ run_test (void) if (!test_mode ("single_file", "single-file", FALSE, FALSE)) return; - if (!test_mode ("single_update", "single-update", FALSE, FALSE)) + if (!test_mode ("single_update", "single-update", TRUE, FALSE)) return; } @@ -259,7 +356,7 @@ guile_main (int argc, char **argv) gnc_module_system_init (); gnc_module_load ("gnucash/engine", 0); - g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); + /* g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); */ glist_exclude_type (KVP_TYPE_BINARY); glist_exclude_type (KVP_TYPE_GLIST); @@ -287,8 +384,6 @@ guile_main (int argc, char **argv) int main (int argc, char ** argv) { - /* getchar (); */ - gh_enter (argc, argv, guile_main); return 0; diff --git a/src/backend/postgres/txn.c b/src/backend/postgres/txn.c index 4f961d6a0d..225d67f790 100644 --- a/src/backend/postgres/txn.c +++ b/src/backend/postgres/txn.c @@ -97,6 +97,13 @@ is_trans_empty (Transaction *trans) * it locks the tables appropriately. */ +typedef struct +{ + GUID guid; + char *guid_str; + guint32 iguid; +} DeleteTransInfo; + static gpointer delete_list_cb (PGBackend *be, PGresult *result, int j, gpointer data) { @@ -104,13 +111,22 @@ delete_list_cb (PGBackend *be, PGresult *result, int j, gpointer data) GUID guid = nullguid; string_to_guid (DB_GET_VAL ("entryGuid", j), &guid); + /* If the database has splits that the engine doesn't, * collect 'em up & we'll have to delete em */ if (NULL == xaccSplitLookup (&guid, be->session)) { - deletelist = g_list_prepend (deletelist, - g_strdup(DB_GET_VAL ("entryGuid", j))); + DeleteTransInfo *dti; + + dti = g_new (DeleteTransInfo, 1); + + dti->guid = guid; + dti->guid_str = g_strdup (DB_GET_VAL ("entryGuid", j)); + dti->iguid = atoi (DB_GET_VAL ("iguid", j)); + + deletelist = g_list_prepend (deletelist, dti); } + return deletelist; } @@ -136,7 +152,7 @@ pgendStoreTransactionNoLock (PGBackend *be, Transaction *trans, * since what is there may not match what we have cached in * the engine. */ p = be->buff; *p = 0; - p = stpcpy (p, "SELECT entryGuid FROM gncEntry WHERE transGuid='"); + p = stpcpy (p, "SELECT entryGuid, iguid FROM gncEntry WHERE transGuid='"); p = guid_to_string_buff(xaccTransGetGUID(trans), p); p = stpcpy (p, "';"); @@ -147,16 +163,28 @@ pgendStoreTransactionNoLock (PGBackend *be, Transaction *trans, p = be->buff; *p = 0; for (node=deletelist; node; node=node->next) { - Split *s; - GUID guid; - string_to_guid ((char *)(node->data), &guid); - s = xaccSplitLookup(&guid, be->session); - pgendStoreAuditSplit (be, s, SQL_DELETE); + DeleteTransInfo *dti = node->data; + GList *split_node; + + /* find the old split in the saved original */ + if (trans->orig && trans->orig->splits) + for (split_node = trans->orig->splits; split_node; + split_node = split_node->next) + { + Split *s = split_node->data; + + if (s && guid_equal (&s->guid, &dti->guid)) + { + pgendStoreAuditSplit (be, s, SQL_DELETE); + break; + } + } p = stpcpy (p, "DELETE FROM gncEntry WHERE entryGuid='"); - p = stpcpy (p, node->data); + p = stpcpy (p, dti->guid_str); p = stpcpy (p, "';\n"); } + if (p != be->buff) { PINFO ("%s", be->buff ? be->buff : "(null)"); @@ -166,15 +194,22 @@ pgendStoreTransactionNoLock (PGBackend *be, Transaction *trans, /* destroy any associated kvp data as well */ for (node=deletelist; node; node=node->next) { - Split *s; - GUID guid; - string_to_guid ((char *)(node->data), &guid); - s = xaccSplitLookup(&guid, be->session); - pgendKVPDelete (be, s->idata); - g_free (node->data); + DeleteTransInfo *dti = node->data; + + pgendKVPDelete (be, dti->iguid); } } + for (node = deletelist; node; node = node->next) + { + DeleteTransInfo *dti = node->data; + + g_free (dti->guid_str); + g_free (dti); + } + g_list_free (deletelist); + deletelist = NULL; + /* Update the rest */ start = xaccTransGetSplitList(trans); diff --git a/src/engine/gnc-book.c b/src/engine/gnc-book.c index 82f9b2c015..decdf6a77c 100644 --- a/src/engine/gnc-book.c +++ b/src/engine/gnc-book.c @@ -126,6 +126,8 @@ gnc_book_set_group (GNCBook *book, AccountGroup *grp) xaccGroupSetBook (grp, book); book->topgroup = grp; + + xaccGroupSetBackend (grp, book->backend); } void @@ -133,6 +135,7 @@ gnc_book_set_backend (GNCBook *book, Backend *be) { if (!book) return; + book->backend = be; xaccGroupSetBackend (book->topgroup, be); xaccPriceDBSetBackend (book->pricedb, be); } @@ -168,7 +171,9 @@ void gnc_book_set_pricedb(GNCBook *book, GNCPriceDB *db) { if(!book) return; + book->pricedb = db; + xaccPriceDBSetBackend (db, book->backend); } /* ---------------------------------------------------------------------- */ @@ -184,6 +189,7 @@ void gnc_book_set_schedxactions( GNCBook *book, GList *newList ) { if ( book == NULL ) return; + book->sched_xactions = newList; book->sx_notsaved = TRUE; } @@ -207,6 +213,8 @@ gnc_book_set_template_group (GNCBook *book, AccountGroup *templateGroup) xaccGroupSetBook (templateGroup, book); book->template_group = templateGroup; + + xaccGroupSetBackend (templateGroup, book->backend); } Backend * @@ -241,7 +249,7 @@ gnc_book_mark_saved(GNCBook *book) xaccGroupMarkSaved(gnc_book_get_group(book)); gnc_pricedb_mark_clean(gnc_book_get_pricedb(book)); - + xaccGroupMarkSaved(gnc_book_get_template_group(book)); book_sxns_mark_saved(book); } diff --git a/src/engine/gnc-session.c b/src/engine/gnc-session.c index 79c13f6cae..dfef7d4a3f 100644 --- a/src/engine/gnc-session.c +++ b/src/engine/gnc-session.c @@ -156,6 +156,8 @@ gnc_session_set_book (GNCSession *session, GNCBook *book) return; session->book = book; + + gnc_book_set_backend (book, session->backend); } GNCEntityTable * @@ -215,24 +217,30 @@ gnc_session_load_backend(GNCSession * session, char * backend_name) /* FIXME: this needs to be smarter with version numbers. */ mod = gnc_module_load(mod_name, 0); - if(mod) + + if (mod) { be_new_func = gnc_module_lookup(mod, "gnc_backend_new"); + if(be_new_func) { session->backend = be_new_func(); + + gnc_book_set_backend (session->book, session->backend); } - else + else { gnc_session_int_backend_load_error(session, " can't find backend_new ", - ""); + ""); } } - else + else { - gnc_session_int_backend_load_error(session, " failed to load '%s' backend", - backend_name); + gnc_session_int_backend_load_error(session, + " failed to load '%s' backend", + backend_name); } + g_free(mod_name); } @@ -615,6 +623,9 @@ gnc_session_swap_data (GNCSession *session_1, GNCSession *session_2) session_2->book = book_1; session_2->entity_table = entity_table_1; + + gnc_book_set_backend (book_1, session_2->backend); + gnc_book_set_backend (book_2, session_1->backend); } gboolean diff --git a/src/engine/test-core/test-engine-stuff.c b/src/engine/test-core/test-engine-stuff.c index 9b1c85e566..09d6f01a72 100644 --- a/src/engine/test-core/test-engine-stuff.c +++ b/src/engine/test-core/test-engine-stuff.c @@ -26,6 +26,8 @@ static gint max_group_depth = 4; static gint max_group_accounts = 10; static kvp_value* get_random_kvp_value_depth (int type, gint depth); +static gpointer get_random_list_element (GList *list); +static void add_random_splits(GNCSession *session, Transaction *trn); /***********************************************************************/ @@ -481,6 +483,174 @@ get_random_group (GNCSession *session) return get_random_group_depth (session, depth); } +typedef struct +{ + GUID guid; +} TransInfo; + +static void +change_trans_helper (GNCSession *session, Transaction *trans, GList *accounts) +{ + GList *splits; + GList *node; + Split *split; + + xaccTransBeginEdit (trans); + + make_random_changes_to_transaction (session, trans); + + switch (get_random_int_in_range (0, 6)) + { + case 0: /* delete some splits, add some more */ + do + { + split = xaccTransGetSplit (trans, 0); + + xaccSplitDestroy (split); + } while (split); + + add_random_splits (session, trans); + + /* fall through */ + + case 1: /* move the splits around */ + splits = xaccTransGetSplitList (trans); + for (node = splits; node; node = node->next) + { + Split *split = node->data; + Account *account; + + account = get_random_list_element (accounts); + + xaccAccountInsertSplit (account, split); + } + break; + + case 2: /* destroy the transaction */ + xaccTransDestroy (trans); + xaccTransCommitEdit (trans); + return; + + default: /* do nothing */ + break; + } + + /* mess with the splits */ + splits = xaccTransGetSplitList (trans); + for (node = splits; node; node = node->next) + { + Split *split = node->data; + + if (get_random_boolean ()) + make_random_changes_to_split (split); + } + + xaccTransCommitEdit (trans); +} + +static gboolean +add_trans_helper (Transaction *trans, gpointer data) +{ + TransInfo *ti; + GList **list = data; + + ti = g_new (TransInfo, 1); + + ti->guid = *xaccTransGetGUID (trans); + + *list = g_list_prepend (*list, ti); + + return TRUE; +} + +void +make_random_changes_to_group (GNCSession *session, AccountGroup *group) +{ + Account *new_account; + Account *account; + GList *accounts; + GList *transes; + GList *splits; + GList *node; + + g_return_if_fail (group && session); + + accounts = xaccGroupGetSubAccounts (group); + + /* Add a new account */ + new_account = get_random_account (session); + + if (get_random_boolean ()) + xaccGroupInsertAccount (group, new_account); + else + { + account = get_random_list_element (accounts); + + xaccAccountInsertSubAccount (account, new_account); + } + + /* Mess with the accounts */ + for (node = accounts; node; node = node->next) + { + Account *account = node->data; + + if (get_random_boolean ()) + make_random_changes_to_account (session, account); + } + + /* Mess with the transactions & splits */ + transes = NULL; + xaccGroupForEachTransaction (group, add_trans_helper, &transes); + + for (node = transes; node; node = node->next) + { + TransInfo *ti = node->data; + Transaction *trans = xaccTransLookup (&ti->guid, session); + + if (!trans) + continue; + + g_warning ("got one"); + + change_trans_helper (session, trans, accounts); + } + + for (node = transes; node; node = node->next) + { + TransInfo *ti = node->data; + + g_free (ti); + } + g_list_free (transes); + transes = NULL; + + /* delete an account */ + account = get_random_list_element (accounts); + + splits = xaccAccountGetSplitList (account); + splits = g_list_copy (splits); + + for (node = splits; node; node = node->next) + { + Split *split = node->data; + + do + { + new_account = get_random_list_element (accounts); + } while (new_account == account); + + xaccAccountInsertSplit (new_account, split); + } + + xaccAccountBeginEdit (account); + xaccAccountDestroy (account); + + g_list_free (splits); + g_list_free (accounts); + + /* TODO: move some accounts around */ +} + Account* get_random_account(GNCSession *session) { @@ -508,6 +678,30 @@ get_random_account(GNCSession *session) return ret; } +void +make_random_changes_to_account (GNCSession *session, Account *account) +{ + int tmp_int; + + g_return_if_fail (account); + + xaccAccountBeginEdit (account); + + set_account_random_string (account, xaccAccountSetName); + + tmp_int = get_random_int_in_range (BANK, CREDITLINE); + xaccAccountSetType (account, tmp_int); + + set_account_random_string (account, xaccAccountSetCode); + set_account_random_string (account, xaccAccountSetDescription); + + xaccAccountSetCommodity (account, get_random_commodity(session)); + + xaccAccountSetSlots_nc (account, get_random_kvp_frame()); + + xaccAccountCommitEdit (account); +} + static void set_split_random_string(Split *spl, void(*func)(Split *act, const gchar*str)) @@ -557,7 +751,28 @@ get_random_split(GNCSession *session, gnc_numeric num) void make_random_changes_to_split (Split *split) { + Transaction *trans; + g_return_if_fail (split); + + trans = xaccSplitGetParent (split); + + xaccTransBeginEdit (trans); + + set_split_random_string (split, xaccSplitSetMemo); + set_split_random_string (split, xaccSplitSetAction); + + xaccSplitSetReconcile (split, possible_chars[get_random_int_in_range(0, 4)]); + + xaccSplitSetDateReconciledTS (split, get_random_timespec()); + + xaccSplitSetSlots_nc (split, get_random_kvp_frame()); + + /* Don't change share values/prices here, since that would + * throw transactions out of balance. Do that in the corresponding + * change transaction function. */ + + xaccTransCommitEdit (trans); } static void @@ -629,6 +844,32 @@ get_random_transaction (GNCSession *session) return get_random_transaction_with_currency (session, NULL); } +void +make_random_changes_to_transaction (GNCSession *session, Transaction *trans) +{ + GList *list; + GList *node; + + g_return_if_fail (trans && session); + + xaccTransBeginEdit (trans); + + xaccTransSetCurrency (trans, get_random_commodity (session)); + + set_tran_random_string (trans, xaccTransSetNum); + + trn_add_ran_timespec (trans, xaccTransSetDatePostedTS); + trn_add_ran_timespec (trans, xaccTransSetDateEnteredTS); + + set_tran_random_string (trans, xaccTransSetDescription); + + xaccTransSetSlots_nc (trans, get_random_kvp_frame()); + + /* Do split manipulations in higher-level functions */ + + xaccTransCommitEdit (trans); +} + static gpointer get_random_list_element (GList *list) { @@ -986,3 +1227,19 @@ add_random_transactions_to_session (GNCSession *session, gint num_transactions) g_list_free (accounts); } + +void +make_random_changes_to_book (GNCSession *session, GNCBook *book) +{ + g_return_if_fail (session && book); + + make_random_changes_to_group (session, gnc_book_get_group (book)); +} + +void +make_random_changes_to_session (GNCSession *session) +{ + g_return_if_fail (session); + + make_random_changes_to_book (session, gnc_session_get_book (session)); +} diff --git a/src/engine/test-core/test-engine-stuff.h b/src/engine/test-core/test-engine-stuff.h index 4fdcb596ce..fd40256912 100644 --- a/src/engine/test-core/test-engine-stuff.h +++ b/src/engine/test-core/test-engine-stuff.h @@ -60,5 +60,11 @@ void add_random_transactions_to_session (GNCSession *session, gint num_transactions); void make_random_changes_to_split (Split *split); +void make_random_changes_to_transaction (GNCSession *session, + Transaction *trans); +void make_random_changes_to_account (GNCSession *session, Account *account); +void make_random_changes_to_group (GNCSession *session, AccountGroup *group); +void make_random_changes_to_book (GNCSession *session, GNCBook *book); +void make_random_changes_to_session (GNCSession *session); #endif