From f68a390531fe10d6b3bac1cf2a48375b76618196 Mon Sep 17 00:00:00 2001
From: Jean-Paul Calderone <exarkun@twistedmatrix.com>
Date: Mon, 5 Aug 2019 11:13:14 -0400
Subject: [PATCH] improved model coverage and behavior

---
 src/_secureaccesstokenauthorizer/model.py     | 26 +++++----
 .../tests/test_model.py                       | 53 +++++++++++++++++--
 2 files changed, 63 insertions(+), 16 deletions(-)

diff --git a/src/_secureaccesstokenauthorizer/model.py b/src/_secureaccesstokenauthorizer/model.py
index f6da694..fb259f1 100644
--- a/src/_secureaccesstokenauthorizer/model.py
+++ b/src/_secureaccesstokenauthorizer/model.py
@@ -26,6 +26,7 @@ from json import (
 )
 
 from sqlite3 import (
+    OperationalError,
     connect as _connect,
 )
 
@@ -36,12 +37,10 @@ from twisted.python.filepath import (
 )
 
 
-class StoreAddError(Exception):
-    def __init__(self, reason):
-        self.reason = reason
-
-
-class StoreDirectoryError(Exception):
+class StoreOpenError(Exception):
+    """
+    There was a problem opening the underlying data store.
+    """
     def __init__(self, reason):
         self.reason = reason
 
@@ -75,12 +74,17 @@ def open_and_initialize(path, required_schema_version, connect=None):
     try:
         path.parent().makedirs(ignoreExistingDirectory=True)
     except OSError as e:
-        raise StoreDirectoryError(e)
+        raise StoreOpenError(e)
+
+    dbfile = path.asBytesMode().path
+    try:
+        conn = connect(
+            dbfile,
+            isolation_level="IMMEDIATE",
+        )
+    except OperationalError as e:
+        raise StoreOpenError(e)
 
-    conn = connect(
-        path.asBytesMode().path,
-        isolation_level="IMMEDIATE",
-    )
     with conn:
         cursor = conn.cursor()
         cursor.execute(
diff --git a/src/_secureaccesstokenauthorizer/tests/test_model.py b/src/_secureaccesstokenauthorizer/tests/test_model.py
index 2e7ba78..3ef54d4 100644
--- a/src/_secureaccesstokenauthorizer/tests/test_model.py
+++ b/src/_secureaccesstokenauthorizer/tests/test_model.py
@@ -1,3 +1,4 @@
+# coding: utf-8
 # Copyright 2019 PrivateStorage.io, LLC
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -53,8 +54,9 @@ from twisted.python.filepath import (
 
 from ..model import (
     SchemaError,
-    StoreDirectoryError,
+    StoreOpenError,
     PaymentReferenceStore,
+    PaymentReference,
     open_and_initialize,
     memory_connect,
 )
@@ -174,12 +176,12 @@ class PaymentReferenceStoreTests(TestCase):
         )
 
 
-    @given(tahoe_configs(), payment_reference_numbers())
-    def test_uncreateable_store_directory(self, get_config, prn):
+    @given(tahoe_configs())
+    def test_uncreateable_store_directory(self, get_config):
         """
         If the underlying directory in the node configuration cannot be created
         then ``PaymentReferenceStore.from_node_config`` raises
-        ``StoreDirectoryError``.
+        ``StoreOpenError``.
         """
         tempdir = self.useFixture(TempDir())
         nodedir = tempdir.join(b"node")
@@ -199,7 +201,7 @@ class PaymentReferenceStoreTests(TestCase):
                 AfterPreprocessing(
                     lambda (type, exc, tb): exc,
                     MatchesAll(
-                        IsInstance(StoreDirectoryError),
+                        IsInstance(StoreOpenError),
                         MatchesStructure(
                             reason=MatchesAll(
                                 IsInstance(OSError),
@@ -212,3 +214,44 @@ class PaymentReferenceStoreTests(TestCase):
                 ),
             ),
         )
+
+
+    @given(tahoe_configs())
+    def test_unopenable_store(self, get_config):
+        """
+        If the underlying database file cannot be opened then
+        ``PaymentReferenceStore.from_node_config`` raises ``StoreOpenError``.
+        """
+        tempdir = self.useFixture(TempDir())
+        nodedir = tempdir.join(b"node")
+
+        config = get_config(nodedir, b"tub.port")
+
+        # Create the underlying database file.
+        store = PaymentReferenceStore.from_node_config(config)
+
+        # Prevent further access to it.
+        store.database_path.chmod(0o000)
+
+        self.assertThat(
+            lambda: PaymentReferenceStore.from_node_config(
+                config,
+            ),
+            raises(StoreOpenError),
+        )
+
+
+class PaymentReferenceTests(TestCase):
+    """
+    Tests for ``PaymentReference``.
+    """
+    @given(payment_reference_numbers())
+    def test_json_roundtrip(self, prn):
+        """
+        ``PaymentReference.to_json . PaymentReference.from_json → id``
+        """
+        ref = PaymentReference(prn)
+        self.assertThat(
+            PaymentReference.from_json(ref.to_json()),
+            Equals(ref),
+        )
-- 
GitLab