diff --git a/src/_zkapauthorizer/model.py b/src/_zkapauthorizer/model.py index 308947daf520c647c60959daab1341adbc020eff..ab0a19a6fc4046970a1b09750d9ef361d0c44bf4 100644 --- a/src/_zkapauthorizer/model.py +++ b/src/_zkapauthorizer/model.py @@ -119,13 +119,16 @@ def open_and_initialize(path, required_schema_version, connect=None): ) cursor.execute( + # A denormalized schema because, for now, it's simpler. :/ """ CREATE TABLE IF NOT EXISTS [vouchers] ( [number] text, [created] text, -- An ISO8601 date+time string. - [redeemed] num DEFAULT 0, -- 0 if the voucher has not been redeemed, 1 otherwise. - [token-count] num DEFAULT NULL, -- NULL if the voucher has not been redeemed, - -- a number of tokens received on its redemption otherwise. + [state] text DEFAULT "pending", -- pending, double-spend, redeemed + + [token-count] num DEFAULT NULL, -- Set in the redeemed state to the number + -- of tokens received on this voucher's + -- redemption. PRIMARY KEY([number]) ) @@ -221,7 +224,7 @@ class VoucherStore(object): cursor.execute( """ SELECT - [number], [created], [redeemed], [token-count] + [number], [created], [state], [token-count] FROM [vouchers] WHERE @@ -279,7 +282,7 @@ class VoucherStore(object): """ cursor.execute( """ - SELECT [number], [created], [redeemed], [token-count] FROM [vouchers] + SELECT [number], [created], [state], [token-count] FROM [vouchers] """, ) refs = cursor.fetchall() @@ -315,7 +318,7 @@ class VoucherStore(object): cursor.execute( """ UPDATE [vouchers] - SET [redeemed] = 1 + SET [state] = "redeemed" , [token-count] = ? WHERE [number] = ? """, @@ -434,7 +437,7 @@ class Voucher(object): """ number = attr.ib() created = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of(datetime))) - redeemed = attr.ib(default=False, validator=attr.validators.instance_of(bool)) + state = attr.ib(default=u"pending", validator=attr.validators.in_((u"pending", u"double-spend", u"redeemed"))) token_count = attr.ib(default=None, validator=attr.validators.optional(attr.validators.instance_of((int, long)))) @classmethod @@ -447,7 +450,7 @@ class Voucher(object): # Python to generate the data in the first place, it should never # represent a leap second... I hope. parse_datetime(row[1], delimiter=u" "), - bool(row[2]), + row[2], row[3], ) @@ -463,7 +466,7 @@ class Voucher(object): return cls( number=values[u"number"], created=None if values[u"created"] is None else parse_datetime(values[u"created"]), - redeemed=values[u"redeemed"], + state=values[u"state"], token_count=values[u"token-count"], ) @@ -480,7 +483,7 @@ class Voucher(object): return { u"number": self.number, u"created": None if self.created is None else self.created.isoformat(), - u"redeemed": self.redeemed, + u"state": self.state, u"token-count": self.token_count, u"version": 1, } diff --git a/src/_zkapauthorizer/tests/strategies.py b/src/_zkapauthorizer/tests/strategies.py index 9f9e254f170517e1e06c932aca9db391c4aca517..07e8ce73adbbb067f85e025f015228f9e097b7dc 100644 --- a/src/_zkapauthorizer/tests/strategies.py +++ b/src/_zkapauthorizer/tests/strategies.py @@ -26,7 +26,6 @@ from hypothesis.strategies import ( one_of, just, none, - booleans, binary, characters, text, @@ -220,6 +219,17 @@ def vouchers(): ) +def voucher_states(): + """ + Build unicode strings giving states a Voucher can be in. + """ + return one_of( + just(u"pending"), + just(u"double-spend"), + just(u"redeemed"), + ) + + def voucher_objects(): """ Build ``Voucher`` instances. @@ -228,7 +238,7 @@ def voucher_objects(): Voucher, number=vouchers(), created=one_of(none(), datetimes()), - redeemed=booleans(), + state=voucher_states(), token_count=one_of(none(), integers(min_value=1)), ) diff --git a/src/_zkapauthorizer/tests/test_client_resource.py b/src/_zkapauthorizer/tests/test_client_resource.py index 1df93936c70090dc31f36ac5db75b93b1365458f..397e8c01fcfc4817b20fa22dfca62765f8dd02f4 100644 --- a/src/_zkapauthorizer/tests/test_client_resource.py +++ b/src/_zkapauthorizer/tests/test_client_resource.py @@ -669,7 +669,7 @@ class VoucherTests(TestCase): MatchesStructure( number=Equals(voucher), created=Equals(now), - redeemed=Equals(redeemed), + state=Equals(u"redeemed" if redeemed else u"pending"), token_count=token_count_comparison, ), ), @@ -731,7 +731,7 @@ class VoucherTests(TestCase): Voucher( voucher, created=now, - redeemed=True, + state=u"redeemed", # Value duplicated from # PaymentController.redeem default. # Should do this better. diff --git a/src/_zkapauthorizer/tests/test_controller.py b/src/_zkapauthorizer/tests/test_controller.py index 032ed0962b286bac7c7125452a1254c685599d72..bb72c6604de84d8f661ef019cf24072eb522cf3f 100644 --- a/src/_zkapauthorizer/tests/test_controller.py +++ b/src/_zkapauthorizer/tests/test_controller.py @@ -140,8 +140,8 @@ class PaymentControllerTests(TestCase): persisted_voucher = store.get(voucher) self.assertThat( - persisted_voucher.redeemed, - Equals(False), + persisted_voucher.state, + Equals(u"pending"), ) @given(tahoe_configs(), datetimes(), vouchers()) @@ -163,8 +163,8 @@ class PaymentControllerTests(TestCase): persisted_voucher = store.get(voucher) self.assertThat( - persisted_voucher.redeemed, - Equals(True), + persisted_voucher.state, + Equals(u"redeemed"), ) diff --git a/src/_zkapauthorizer/tests/test_model.py b/src/_zkapauthorizer/tests/test_model.py index 925f464fe664fe85d0a18ef0b16bd98f65d59ccc..615d202bc0f76bba753dfb3d6e9d7d5b7b9f38b2 100644 --- a/src/_zkapauthorizer/tests/test_model.py +++ b/src/_zkapauthorizer/tests/test_model.py @@ -134,7 +134,7 @@ class VoucherStoreTests(TestCase): store.get(voucher), MatchesStructure( number=Equals(voucher), - redeemed=Equals(False), + state=Equals(u"pending"), created=Equals(now), ), ) @@ -159,7 +159,7 @@ class VoucherStoreTests(TestCase): MatchesStructure( number=Equals(voucher), created=Equals(now), - redeemed=Equals(False), + state=Equals(u"pending"), token_count=Equals(None), ), ) @@ -339,7 +339,7 @@ class UnblindedTokenStoreTests(TestCase): self.assertThat( loaded_voucher, MatchesStructure( - redeemed=Equals(True), + state=Equals(u"redeemed"), token_count=Equals(num_tokens), ), )