From 4893f3525b19e29ba32af6a4382d43d9d435127c Mon Sep 17 00:00:00 2001 From: Jonathan Buchanan Date: Sun, 21 Jun 2020 16:44:15 -0400 Subject: improved backenddb tests --- src/backenddb/plugin_merchantdb_postgres.c | 60 ++++- src/backenddb/test_merchantdb.c | 346 +++++++++++++++-------------- 2 files changed, 238 insertions(+), 168 deletions(-) (limited to 'src/backenddb') diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c index 12dc3498..831c676a 100644 --- a/src/backenddb/plugin_merchantdb_postgres.c +++ b/src/backenddb/plugin_merchantdb_postgres.c @@ -4472,10 +4472,10 @@ lookup_pending_reserves_cb (void *cls, struct GNUNET_PQ_ResultSpec rs[] = { GNUNET_PQ_result_spec_auto_from_type ("reserve_pub", &reserve_pub), + GNUNET_PQ_result_spec_string ("merchant_id", + &instance_id), GNUNET_PQ_result_spec_string ("exchange_url", &exchange_url), - GNUNET_PQ_result_spec_string ("instance_id", - &instance_id), TALER_PQ_RESULT_SPEC_AMOUNT ("merchant_initial_balance", &merchant_initial_balance), GNUNET_PQ_result_spec_end @@ -6112,6 +6112,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " creation_time > $4" " AND" " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial ASC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6155,6 +6159,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " creation_time > $4" " AND" " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial ASC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6200,6 +6208,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " creation_time > $4" " AND" " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial ASC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6244,6 +6256,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ " AND" " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial ASC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6291,6 +6307,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ " AND" " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial ASC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6336,6 +6356,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ " AND" " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial ASC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6384,6 +6408,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ " AND" " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial ASC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6472,6 +6500,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " creation_time < $4" " AND" " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial DESC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6515,6 +6547,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " creation_time < $4" " AND" " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial DESC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6560,6 +6596,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " creation_time < $4" " AND" " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial DESC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6604,6 +6644,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ " AND" " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial DESC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6651,6 +6695,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " NOT CAST($5 as BOOL)" /* unclaimed orders are never paid */ " AND" " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial DESC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6696,6 +6744,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ " AND" " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial DESC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ @@ -6744,6 +6796,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls) " NOT CAST($6 as BOOL)"/* unclaimed orders are never refunded */ " AND" " NOT CAST($7 as BOOL)" /* unclaimed orders are never wired */ + " AND" + " order_serial NOT IN" + " (SELECT order_serial" + " FROM merchant_contract_terms)" /* only select unclaimed orders */ " ORDER BY order_serial DESC" " LIMIT $2)" "UNION " /* union ensures elements are distinct! */ diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c index 93a7caeb..66c3320e 100644 --- a/src/backenddb/test_merchantdb.c +++ b/src/backenddb/test_merchantdb.c @@ -3173,11 +3173,13 @@ lookup_reserves_cb (void *cls, return; for (unsigned int i = 0; cmp->reserves_to_cmp_length > i; ++i) { - if ((cmp->reserves_to_cmp[i].expiration.abs_value_us == - expiration_time.abs_value_us) || + if ((0 == GNUNET_memcmp (&cmp->reserves_to_cmp[i].reserve_pub, + reserve_pub)) && + (cmp->reserves_to_cmp[i].expiration.abs_value_us == + expiration_time.abs_value_us) && (GNUNET_OK == TALER_amount_cmp_currency ( &cmp->reserves_to_cmp[i].initial_amount, - merchant_initial_amount)) || + merchant_initial_amount)) && (0 == TALER_amount_cmp (&cmp->reserves_to_cmp[i].initial_amount, merchant_initial_amount))) { @@ -3233,6 +3235,75 @@ test_lookup_reserves (const char *instance_id, } +static void +lookup_pending_reserves_cb (void *cls, + const char *instance_id, + const char *exchange_url, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_Amount *expected_amount) +{ + struct TestLookupReserves_Closure *cmp = cls; + if (NULL == cmp) + return; + for (unsigned int i = 0; cmp->reserves_to_cmp_length > i; ++i) + { + if ((0 == GNUNET_memcmp (&cmp->reserves_to_cmp[i].reserve_pub, + reserve_pub)) && + (0 == strcmp (cmp->reserves_to_cmp[i].exchange_url, + exchange_url)) && + (GNUNET_OK == TALER_amount_cmp_currency ( + &cmp->reserves_to_cmp[i].initial_amount, + expected_amount)) && + (0 == TALER_amount_cmp (&cmp->reserves_to_cmp[i].initial_amount, + expected_amount))) + { + cmp->results_matching[i] += 1; + } + } + cmp->results_length += 1; +} + + +static int +test_lookup_pending_reserves (unsigned int reserves_length, + const struct ReserveData *reserves) +{ + unsigned int results_matching[reserves_length]; + struct TestLookupReserves_Closure cmp = { + .reserves_to_cmp_length = reserves_length, + .reserves_to_cmp = reserves, + .results_matching = results_matching, + .results_length = 0 + }; + memset (results_matching, 0, sizeof (unsigned int) * reserves_length); + if (0 > plugin->lookup_pending_reserves (plugin->cls, + &lookup_pending_reserves_cb, + &cmp)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup pending reserves failed\n"); + return 1; + } + if (reserves_length != cmp.results_length) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup pending reserves failed: incorrect number of results (%d)\n", + cmp.results_length); + return 1; + } + for (unsigned int i = 0; reserves_length > i; ++i) + { + if (1 != cmp.results_matching[i]) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Lookup pending reserves failed: mismatched data\n"); + return 1; + } + } + return 0; +} + + struct TipData { struct TALER_MERCHANTDB_TipDetails details; @@ -3716,6 +3787,9 @@ run_test_tips (struct TestTips_Closure *cls) TEST_RET_ON_FAIL (test_lookup_reserve (cls->instance.instance.id, &cls->reserve.reserve_pub, &cls->reserve)); + /* Test lookup pending reserves */ + TEST_RET_ON_FAIL (test_lookup_pending_reserves (1, + &cls->reserve)); /* Test reserve activation */ TEST_COND_RET_ON_FAIL (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == plugin->activate_reserve (plugin->cls, @@ -3723,6 +3797,8 @@ run_test_tips (struct TestTips_Closure *cls) &cls->reserve.reserve_pub, &cls->reserve.initial_amount), "Activate reserve failed\n"); + TEST_RET_ON_FAIL (test_lookup_pending_reserves (0, + NULL)); /* Test inserting a tip */ TEST_RET_ON_FAIL (test_authorize_tip (&cls->instance, &cls->reserve, @@ -4369,22 +4445,6 @@ test_refunds (void *cls) } -/** - * Convenience function for testing lookup orders with filters - */ -static void -order_data_subarray (unsigned int indices_length, - const unsigned int *indices, - struct OrderData *dst, - const struct OrderData *src) -{ - for (unsigned int i = 0; i < indices_length; ++i) - { - dst[i] = src[indices[i]]; - } -} - - /** * Convenience function for testing lookup orders with filters */ @@ -4406,10 +4466,10 @@ struct TestLookupOrdersAllFilters_Closure struct TALER_MERCHANTDB_AccountDetails account; struct ExchangeSignkeyData signkey; - char *order_ids[16]; - struct OrderData orders[16]; - struct DepositData deposits[16]; - struct RefundData refunds[16]; + char *order_ids[64]; + struct OrderData orders[64]; + struct DepositData deposits[64]; + struct RefundData refunds[64]; }; @@ -4421,7 +4481,7 @@ pre_test_lookup_orders_all_filters (struct &cls->instance); make_account (&cls->account); make_exchange_signkey (&cls->signkey); - for (unsigned int i = 0; i < 16; ++i) + for (unsigned int i = 0; i < 64; ++i) { (void) GNUNET_asprintf (&cls->order_ids[i], "test_orders_filter_od_%u", @@ -4447,7 +4507,7 @@ post_test_lookup_orders_all_filters (struct TestLookupOrdersAllFilters_Closure *cls) { free_instance_data (&cls->instance); - for (unsigned int i = 0; i < 16; ++i) + for (unsigned int i = 0; i < 64; ++i) { free_order_data (&cls->orders[i]); GNUNET_free (cls->order_ids[i]); @@ -4460,23 +4520,29 @@ run_test_lookup_orders_all_filters (struct TestLookupOrdersAllFilters_Closure *cls) { /* Order filter extravaganza */ - struct OrderData expected_orders[16]; - struct TALER_MERCHANTDB_OrderFilter filter_inc = { - .paid = TALER_EXCHANGE_YNA_ALL, - .refunded = TALER_EXCHANGE_YNA_ALL, - .wired = TALER_EXCHANGE_YNA_ALL, - .date = GNUNET_TIME_absolute_get_zero_ (), - .start_row = 0, - .delta = 16 - }; - struct TALER_MERCHANTDB_OrderFilter filter_dec = { - .paid = TALER_EXCHANGE_YNA_ALL, - .refunded = TALER_EXCHANGE_YNA_ALL, - .wired = TALER_EXCHANGE_YNA_ALL, - .date = GNUNET_TIME_UNIT_FOREVER_ABS, - .start_row = 23, - .delta = -16 - }; + struct + { + bool claimed; + bool paid; + bool refunded; + bool wired; + } order_status[64]; + unsigned int *permutation; + + /* Pseudorandomly generate variations for the filter to differentiate */ + GNUNET_CRYPTO_seed_weak_random (1); + permutation = GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, + 64); + for (unsigned int i = 0; i < 64; ++i) + { + unsigned int dest = permutation[i]; + order_status[dest].claimed = (i & 1) ? true : false; + order_status[dest].paid = (3 == (i & 3)) ? true : false; + order_status[dest].refunded = (5 == (i & 5)) ? true : false; + order_status[dest].wired = (9 == (i & 9)) ? true : false; + } + GNUNET_free (permutation); + TEST_RET_ON_FAIL (test_insert_instance (&cls->instance, GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); @@ -4485,24 +4551,28 @@ run_test_lookup_orders_all_filters (struct GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); TEST_RET_ON_FAIL (test_insert_exchange_signkey (&cls->signkey, GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); - for (unsigned int i = 0; i < 16; ++i) + for (unsigned int i = 0; i < 64; ++i) { - expected_orders[i] = cls->orders[i]; TEST_RET_ON_FAIL (test_insert_order (&cls->instance, &cls->orders[i], GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); - TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance, - &cls->orders[i], - GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); - /* Mark every other order as paid for */ - if (0 == i % 2) + if (order_status[i].claimed) + { + TEST_RET_ON_FAIL (test_insert_contract_terms (&cls->instance, + &cls->orders[i], + GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); + } + else + { + continue; + } + + if (order_status[i].paid) TEST_RET_ON_FAIL (test_mark_contract_paid (&cls->instance, &cls->orders[i], GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); - /* Refund every fouth order and a couple unpaid orders */ - if ((0 == i % 4) || - (i < 2)) + if (order_status[i].refunded) { TEST_RET_ON_FAIL (test_insert_deposit (&cls->instance, &cls->signkey, @@ -4517,123 +4587,67 @@ run_test_lookup_orders_all_filters (struct cls->refunds[i].coin_pub, cls->refunds[i].reason), "Refund coin failed\n"); - /* Mark every eigth as wired */ - if (0 == i % 8) - TEST_RET_ON_FAIL (test_mark_order_wired (7 + i, - GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); } + + if (order_status[i].wired) + TEST_RET_ON_FAIL (test_mark_order_wired (7 + i, + GNUNET_DB_STATUS_SUCCESS_ONE_RESULT)); + } + + /* There are 3^3 = 27 possibilities here, not counting inc/dec and start row */ + for (unsigned int i = 0; i < 27; ++i) + { + struct TALER_MERCHANTDB_OrderFilter filter = { + .paid = (i % 3) + 1, + .refunded = ((i / 3) % 3) + 1, + .wired = ((i / 9) % 3) + 1, + .date = GNUNET_TIME_absolute_get_zero_ (), + .start_row = 0, + .delta = 64 + }; + unsigned int orders_length = 0; + struct OrderData orders[64]; + + /* Now figure out which orders should make it through the filter */ + for (unsigned int j = 0; j < 64; ++j) + { + if (((TALER_EXCHANGE_YNA_YES == filter.paid) && + (true != order_status[j].paid)) || + ((TALER_EXCHANGE_YNA_NO == filter.paid) && + (false != order_status[j].paid)) || + ((TALER_EXCHANGE_YNA_YES == filter.refunded) && + (true != order_status[j].refunded)) || + ((TALER_EXCHANGE_YNA_NO == filter.refunded) && + (false != order_status[j].refunded)) || + ((TALER_EXCHANGE_YNA_YES == filter.wired) && + (true != order_status[j].wired)) || + ((TALER_EXCHANGE_YNA_NO == filter.wired) && + (false != order_status[j].wired))) + continue; + orders[orders_length] = cls->orders[j]; + orders_length += 1; + } + + /* Test the lookup */ + TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, + &filter, + orders_length, + orders)); + + /* Now test decreasing */ + filter.start_row = 256; + filter.date = GNUNET_TIME_UNIT_FOREVER_ABS; + filter.delta = -64; + + reverse_order_data_array (orders_length, + orders); + + TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, + &filter, + orders_length, + orders)); } - /* We have 16 different cases to cover */ - /* lookup_orders_inc */ - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_inc, - 16, - expected_orders)); - /* lookup_orders_dec */ - reverse_order_data_array (16, - expected_orders); - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_dec, - 16, - expected_orders)); - /* lookup_orders_inc_paid */ - filter_inc.paid = TALER_EXCHANGE_YNA_YES; - for (unsigned int i = 0; i < 8; ++i) - expected_orders[i] = cls->orders[2 * i]; - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_inc, - 8, - expected_orders)); - /* lookup_orders_dec_paid */ - filter_dec.paid = TALER_EXCHANGE_YNA_YES; - reverse_order_data_array (8, - expected_orders); - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_dec, - 8, - expected_orders)); - filter_inc.paid = TALER_EXCHANGE_YNA_NO; - for (unsigned int i = 0; i < 8; ++i) - expected_orders[i] = cls->orders[(2 * i) + 1]; - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_inc, - 8, - expected_orders)); - filter_dec.paid = TALER_EXCHANGE_YNA_NO; - reverse_order_data_array (8, - expected_orders); - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_dec, - 8, - expected_orders)); - /* lookup_orders_inc_refunded */ - filter_inc.paid = TALER_EXCHANGE_YNA_ALL; - filter_inc.refunded = TALER_EXCHANGE_YNA_YES; - unsigned int indices[] = { - 0, 1, 4, 8, 12 - }; - order_data_subarray (5, - indices, - expected_orders, - cls->orders); - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_inc, - 5, - expected_orders)); - /* lookup_orders_dec_refunded */ - filter_dec.paid = TALER_EXCHANGE_YNA_ALL; - filter_dec.refunded = TALER_EXCHANGE_YNA_YES; - reverse_order_data_array (5, - expected_orders); - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_dec, - 5, - expected_orders)); - /* lookup_orders_inc_wired */ - expected_orders[0] = cls->orders[0]; - expected_orders[1] = cls->orders[8]; - filter_inc.refunded = TALER_EXCHANGE_YNA_ALL; - filter_inc.wired = TALER_EXCHANGE_YNA_YES; - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_inc, - 2, - expected_orders)); - /* lookup_orders_dec_wired */ - filter_dec.refunded = TALER_EXCHANGE_YNA_ALL; - filter_dec.wired = TALER_EXCHANGE_YNA_YES; - reverse_order_data_array (2, - expected_orders); - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_dec, - 2, - expected_orders)); - /* lookup_orders_inc_paid_refunded */ - filter_inc.refunded = TALER_EXCHANGE_YNA_YES; - filter_inc.wired = TALER_EXCHANGE_YNA_ALL; - filter_inc.paid = TALER_EXCHANGE_YNA_YES; - for (unsigned int i = 0; i < 4; ++i) - expected_orders[i] = cls->orders[4 * i]; - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_inc, - 4, - expected_orders)); - /* lookup_orders_dec_paid_refunded */ - filter_dec.refunded = TALER_EXCHANGE_YNA_YES; - filter_dec.wired = TALER_EXCHANGE_YNA_ALL; - filter_dec.paid = TALER_EXCHANGE_YNA_YES; - reverse_order_data_array (4, - expected_orders); - TEST_RET_ON_FAIL (test_lookup_orders (&cls->instance, - &filter_dec, - 4, - expected_orders)); - /* lookup_orders_inc_paid_wired */ - /* lookup_orders_dec_paid_wired */ - /* lookup_orders_inc_refunded_wired */ - /* lookup_orders_dec_refunded_wired */ - /* lookup_orders_inc_paid_refunded_wired */ - /* lookup_orders_dec_paid_refunded_wired */ return 0; } -- cgit v1.2.3