From a4ff0b37f73243c77934c60cd242424a391dcbb1 Mon Sep 17 00:00:00 2001 From: Rohit Paul Kuruvilla Date: Thu, 4 Dec 2014 22:15:04 +0530 Subject: [PATCH 1/8] failing test --- tests/py/test_billing_payday.py | 42 +++++++++++++++++---------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/tests/py/test_billing_payday.py b/tests/py/test_billing_payday.py index c4a9c2a442..69e72f9812 100644 --- a/tests/py/test_billing_payday.py +++ b/tests/py/test_billing_payday.py @@ -101,39 +101,41 @@ def test_update_cached_amounts(self): bob = self.make_participant('bob', claimed_time='now', last_bill_result=None) carl = self.make_participant('carl', claimed_time='now', last_bill_result="Fail!") dana = self.make_participant('dana', claimed_time='now') - emma = self.make_elsewhere('github', 58946, 'emma').participant + emma = self.make_participant('emma', claimed_time='now') + michael = self.make_elsewhere('github', 58946, 'michael').participant roy = self.make_elsewhere('github', 58947, 'roy', is_locked=True).participant - alice.set_tip_to(dana, '3.00') - alice.set_tip_to(bob, '6.00') - alice.set_tip_to(emma, '1.00') - alice.set_tip_to(team, '4.00') - alice.set_tip_to(roy, '10.00') - bob.set_tip_to(alice, '5.00') - bob.set_tip_to(dana, '2.00') - carl.set_tip_to(dana, '2.08') + alice.set_tip_to(bob, '50.00') + alice.set_tip_to(team, '10.00') + alice.set_tip_to(michael, '30.00') + alice.set_tip_to(roy, '70.00') team.add_member(bob) team.set_take_for(bob, D('1.00'), bob) - + bob.set_tip_to(dana, '51.00') + dana.set_tip_to(emma, '5.00') + emma.set_tip_to(bob, '20.00') # Unfunded + carl.set_tip_to(dana, '30.00') # Unfunded def check(): alice = Participant.from_username('alice') bob = Participant.from_username('bob') carl = Participant.from_username('carl') dana = Participant.from_username('dana') - emma = AccountElsewhere.from_user_name('github','emma').participant - assert alice.giving == D('13.00') - assert alice.pledging == D('1.00') - assert alice.receiving == D('5.00') - assert bob.giving == D('5.00') - assert bob.receiving == D('7.00') + emma = Participant.from_username('emma') + michael = AccountElsewhere.from_user_name('github','michael').participant + assert alice.giving == D('60.00') + assert alice.pledging == D('30.00') + assert bob.receiving == D('51.00') + assert bob.giving == D('51.00') assert bob.taking == D('1.00') assert carl.giving == D('0.00') - assert carl.receiving == D('0.00') - assert dana.receiving == D('3.00') + assert dana.giving == D('5.00') + assert dana.receiving == D('51.00') assert dana.npatrons == 1 - assert emma.receiving == D('1.00') + assert emma.receiving == D('5.00') assert emma.npatrons == 1 + assert michael.receiving == D('30.00') + assert michael.npatrons == 1 funded_tips = self.db.all("SELECT amount FROM tips WHERE is_funded ORDER BY id") - assert funded_tips == [3, 6, 1, 4, 10, 5] + assert funded_tips == [50, 10, 30, 70, 51, 5] # Pre-test check check() From 8d5fcfe5346b839d009966d13aed79770a478cb9 Mon Sep 17 00:00:00 2001 From: Rohit Paul Kuruvilla Date: Thu, 4 Dec 2014 22:41:25 +0530 Subject: [PATCH 2/8] fix update_giving --- gratipay/models/participant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gratipay/models/participant.py b/gratipay/models/participant.py index 6cd4aba32e..4e905848db 100644 --- a/gratipay/models/participant.py +++ b/gratipay/models/participant.py @@ -598,7 +598,7 @@ def update_giving(self, cursor=None): AND p2.is_suspicious IS NOT true ORDER BY p2.claimed_time IS NULL, t.ctime ASC """, (self.username,)) - fake_balance = self.balance + self.receiving - self.taking + fake_balance = self.balance + self.receiving for tip in tips: if tip.amount > fake_balance: is_funded = False From 5069db4c38aaec296bc4ab4015fc72b4ffe6ec0c Mon Sep 17 00:00:00 2001 From: Rohit Paul Kuruvilla Date: Thu, 4 Dec 2014 22:41:53 +0530 Subject: [PATCH 3/8] update participant's giving after team take is changed. --- gratipay/models/_mixin_team.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gratipay/models/_mixin_team.py b/gratipay/models/_mixin_team.py index 68c3fc9fee..45851c5997 100644 --- a/gratipay/models/_mixin_team.py +++ b/gratipay/models/_mixin_team.py @@ -158,6 +158,8 @@ def __set_take_for(self, member, amount, recorder, cursor=None): new_takes = self.compute_actual_takes(cursor) # Update receiving amounts in the participants table self.update_taking(old_takes, new_takes, cursor, member) + # Update is_funded on member's tips + member.update_giving(cursor) def update_taking(self, old_takes, new_takes, cursor=None, member=None): """Update `taking` amounts based on the difference between `old_takes` From 039389e682a742b21edba5f051dcc318d315379b Mon Sep 17 00:00:00 2001 From: Rohit Paul Kuruvilla Date: Thu, 4 Dec 2014 22:47:31 +0530 Subject: [PATCH 4/8] Fix fake_payday to add loop --- fake_payday.sql | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/fake_payday.sql b/fake_payday.sql index a2b90b9237..c3b0469cb5 100644 --- a/fake_payday.sql +++ b/fake_payday.sql @@ -112,6 +112,34 @@ CREATE OR REPLACE FUNCTION fake_take() RETURNS trigger AS $$ END; $$ LANGUAGE plpgsql; + +-- Create a function to settle whole tip graph + +CREATE OR REPLACE FUNCTION settle_tip_graph() RETURNS void AS $$ + DECLARE + count integer NOT NULL DEFAULT 0; + i integer := 0; + BEGIN + LOOP + i := i + 1; + WITH updated_rows AS ( + UPDATE temp_tips + SET is_funded = true + WHERE is_funded IS NOT true + RETURNING * + ) + SELECT COUNT(*) FROM updated_rows INTO count; + IF (count = 0) THEN + EXIT; + END IF; + IF (i > 50) THEN + RAISE 'Reached the maximum number of iterations'; + END IF; + END LOOP; + END; +$$ LANGUAGE plpgsql; + + CREATE TRIGGER fake_take AFTER INSERT ON temp_takes FOR EACH ROW EXECUTE PROCEDURE fake_take(); @@ -125,12 +153,9 @@ UPDATE temp_tips t WHERE p.username = t.tipper AND p.credit_card_ok; --- Step 2: tips that are covered by the user's balance -UPDATE temp_tips t - SET is_funded = true - WHERE is_funded IS NOT true; +SELECT settle_tip_graph(); --- Step 3: team takes +-- Step 2: team takes INSERT INTO temp_takes SELECT team, member, amount FROM current_takes t @@ -139,7 +164,9 @@ INSERT INTO temp_takes AND t.member IN (SELECT username FROM temp_participants) ORDER BY ctime DESC; --- Step 4: update the real tables +SELECT settle_tip_graph(); + +-- Step 3: update the real tables UPDATE tips t SET is_funded = tt.is_funded FROM temp_tips tt From 301f401118c420f026f3356458e94155ae34bc48 Mon Sep 17 00:00:00 2001 From: Changaco Date: Fri, 5 Dec 2014 11:09:22 +0100 Subject: [PATCH 5/8] fix comments --- fake_payday.sql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fake_payday.sql b/fake_payday.sql index c3b0469cb5..14e89d276e 100644 --- a/fake_payday.sql +++ b/fake_payday.sql @@ -112,6 +112,9 @@ CREATE OR REPLACE FUNCTION fake_take() RETURNS trigger AS $$ END; $$ LANGUAGE plpgsql; +CREATE TRIGGER fake_take AFTER INSERT ON temp_takes + FOR EACH ROW EXECUTE PROCEDURE fake_take(); + -- Create a function to settle whole tip graph @@ -140,13 +143,9 @@ CREATE OR REPLACE FUNCTION settle_tip_graph() RETURNS void AS $$ $$ LANGUAGE plpgsql; -CREATE TRIGGER fake_take AFTER INSERT ON temp_takes - FOR EACH ROW EXECUTE PROCEDURE fake_take(); - - -- Start fake payday --- Step 1: tips that are backed by a credit card +-- Step 1: tips UPDATE temp_tips t SET is_funded = true FROM temp_participants p @@ -164,9 +163,10 @@ INSERT INTO temp_takes AND t.member IN (SELECT username FROM temp_participants) ORDER BY ctime DESC; +-- Step 3: tips again SELECT settle_tip_graph(); --- Step 3: update the real tables +-- Step 4: update the real tables UPDATE tips t SET is_funded = tt.is_funded FROM temp_tips tt From 93cff7567a62275268f5a9ba1a831eb5c06398ac Mon Sep 17 00:00:00 2001 From: Changaco Date: Fri, 5 Dec 2014 14:19:02 +0100 Subject: [PATCH 6/8] Revert "failing test" This reverts commit a4ff0b37f73243c77934c60cd242424a391dcbb1. --- tests/py/test_billing_payday.py | 42 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/tests/py/test_billing_payday.py b/tests/py/test_billing_payday.py index 69e72f9812..c4a9c2a442 100644 --- a/tests/py/test_billing_payday.py +++ b/tests/py/test_billing_payday.py @@ -101,41 +101,39 @@ def test_update_cached_amounts(self): bob = self.make_participant('bob', claimed_time='now', last_bill_result=None) carl = self.make_participant('carl', claimed_time='now', last_bill_result="Fail!") dana = self.make_participant('dana', claimed_time='now') - emma = self.make_participant('emma', claimed_time='now') - michael = self.make_elsewhere('github', 58946, 'michael').participant + emma = self.make_elsewhere('github', 58946, 'emma').participant roy = self.make_elsewhere('github', 58947, 'roy', is_locked=True).participant - alice.set_tip_to(bob, '50.00') - alice.set_tip_to(team, '10.00') - alice.set_tip_to(michael, '30.00') - alice.set_tip_to(roy, '70.00') + alice.set_tip_to(dana, '3.00') + alice.set_tip_to(bob, '6.00') + alice.set_tip_to(emma, '1.00') + alice.set_tip_to(team, '4.00') + alice.set_tip_to(roy, '10.00') + bob.set_tip_to(alice, '5.00') + bob.set_tip_to(dana, '2.00') + carl.set_tip_to(dana, '2.08') team.add_member(bob) team.set_take_for(bob, D('1.00'), bob) - bob.set_tip_to(dana, '51.00') - dana.set_tip_to(emma, '5.00') - emma.set_tip_to(bob, '20.00') # Unfunded - carl.set_tip_to(dana, '30.00') # Unfunded + def check(): alice = Participant.from_username('alice') bob = Participant.from_username('bob') carl = Participant.from_username('carl') dana = Participant.from_username('dana') - emma = Participant.from_username('emma') - michael = AccountElsewhere.from_user_name('github','michael').participant - assert alice.giving == D('60.00') - assert alice.pledging == D('30.00') - assert bob.receiving == D('51.00') - assert bob.giving == D('51.00') + emma = AccountElsewhere.from_user_name('github','emma').participant + assert alice.giving == D('13.00') + assert alice.pledging == D('1.00') + assert alice.receiving == D('5.00') + assert bob.giving == D('5.00') + assert bob.receiving == D('7.00') assert bob.taking == D('1.00') assert carl.giving == D('0.00') - assert dana.giving == D('5.00') - assert dana.receiving == D('51.00') + assert carl.receiving == D('0.00') + assert dana.receiving == D('3.00') assert dana.npatrons == 1 - assert emma.receiving == D('5.00') + assert emma.receiving == D('1.00') assert emma.npatrons == 1 - assert michael.receiving == D('30.00') - assert michael.npatrons == 1 funded_tips = self.db.all("SELECT amount FROM tips WHERE is_funded ORDER BY id") - assert funded_tips == [50, 10, 30, 70, 51, 5] + assert funded_tips == [3, 6, 1, 4, 10, 5] # Pre-test check check() From 6d4d7b05738b91bd8accc441c959cf20271d592a Mon Sep 17 00:00:00 2001 From: Changaco Date: Fri, 5 Dec 2014 14:40:05 +0100 Subject: [PATCH 7/8] fix test --- tests/py/test_billing_payday.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/py/test_billing_payday.py b/tests/py/test_billing_payday.py index c4a9c2a442..1f7381553f 100644 --- a/tests/py/test_billing_payday.py +++ b/tests/py/test_billing_payday.py @@ -109,10 +109,11 @@ def test_update_cached_amounts(self): alice.set_tip_to(team, '4.00') alice.set_tip_to(roy, '10.00') bob.set_tip_to(alice, '5.00') - bob.set_tip_to(dana, '2.00') - carl.set_tip_to(dana, '2.08') team.add_member(bob) team.set_take_for(bob, D('1.00'), bob) + bob.set_tip_to(dana, '2.00') # funded by bob's take + bob.set_tip_to(emma, '7.00') # not funded, insufficient receiving + carl.set_tip_to(dana, '2.08') # not funded, failing card def check(): alice = Participant.from_username('alice') @@ -123,17 +124,17 @@ def check(): assert alice.giving == D('13.00') assert alice.pledging == D('1.00') assert alice.receiving == D('5.00') - assert bob.giving == D('5.00') + assert bob.giving == D('7.00') assert bob.receiving == D('7.00') assert bob.taking == D('1.00') assert carl.giving == D('0.00') assert carl.receiving == D('0.00') - assert dana.receiving == D('3.00') - assert dana.npatrons == 1 + assert dana.receiving == D('5.00') + assert dana.npatrons == 2 assert emma.receiving == D('1.00') assert emma.npatrons == 1 funded_tips = self.db.all("SELECT amount FROM tips WHERE is_funded ORDER BY id") - assert funded_tips == [3, 6, 1, 4, 10, 5] + assert funded_tips == [3, 6, 1, 4, 10, 5, 2] # Pre-test check check() From 12b9e798403e1baaec2ff9637cb4945cc9868d6f Mon Sep 17 00:00:00 2001 From: Changaco Date: Fri, 5 Dec 2014 16:48:39 +0100 Subject: [PATCH 8/8] test multiple iterations of the tips loop --- gratipay/models/participant.py | 3 +++ tests/py/test_billing_payday.py | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/gratipay/models/participant.py b/gratipay/models/participant.py index 4e905848db..b0b3f7a811 100644 --- a/gratipay/models/participant.py +++ b/gratipay/models/participant.py @@ -66,6 +66,9 @@ def __ne__(self, other): return False return self.username != other.username + def __repr__(self): + return '' % repr(self.username) + # Constructors # ============ diff --git a/tests/py/test_billing_payday.py b/tests/py/test_billing_payday.py index 1f7381553f..1198ed8072 100644 --- a/tests/py/test_billing_payday.py +++ b/tests/py/test_billing_payday.py @@ -156,6 +156,30 @@ def check(): Payday.start().update_cached_amounts() check() + def test_update_cached_amounts_depth(self): + alice = self.make_participant('alice', claimed_time='now', last_bill_result='') + usernames = ('bob', 'carl', 'dana', 'emma', 'fred', 'greg') + users = [self.make_participant(username, claimed_time='now') for username in usernames] + + prev = alice + for user in reversed(users): + prev.set_tip_to(user, '1.00') + prev = user + + def check(): + for username in reversed(usernames[1:]): + user = Participant.from_username(username) + assert user.giving == D('1.00') + assert user.pledging == D('0.00') + assert user.receiving == D('1.00') + assert user.npatrons == 1 + funded_tips = self.db.all("SELECT id FROM tips WHERE is_funded ORDER BY id") + assert len(funded_tips) == 6 + + check() + Payday.start().update_cached_amounts() + check() + @mock.patch('gratipay.billing.payday.log') def test_start_prepare(self, log): self.clear_tables()