From 26d3869076f02351a821a3e4dd7049fd234f6bb6 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@lothar.com>
Date: Sun, 10 Jun 2012 17:46:38 -0700
Subject: [PATCH] node.py: add get_private_config()

Also add tests for this and the pre-existing private-config methods.
---
 src/allmydata/node.py           | 17 +++++++++++++++++
 src/allmydata/test/test_node.py | 30 +++++++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/src/allmydata/node.py b/src/allmydata/node.py
index 486650e1..a0f6b138 100644
--- a/src/allmydata/node.py
+++ b/src/allmydata/node.py
@@ -230,6 +230,23 @@ class Node(service.MultiService):
         privname = os.path.join(self.basedir, "private", name)
         open(privname, "w").write(value)
 
+    def get_private_config(self, name, default=_None):
+        """Read the (string) contents of a private config file (which is a
+        config file that resides within the subdirectory named 'private'),
+        and return it. Return a default, or raise an error if one was not
+        given.
+        """
+        privname = os.path.join(self.basedir, "private", name)
+        try:
+            return fileutil.read(privname)
+        except EnvironmentError:
+            if os.path.exists(privname):
+                raise
+            if default is _None:
+                raise MissingConfigEntry("The required configuration file %s is missing."
+                                         % (quote_output(privname),))
+            return default
+
     def get_or_create_private_config(self, name, default=_None):
         """Try to get the (string) contents of a private config file (which
         is a config file that resides within the subdirectory named
diff --git a/src/allmydata/test/test_node.py b/src/allmydata/test/test_node.py
index 4c1bbc01..72d6ef8c 100644
--- a/src/allmydata/test/test_node.py
+++ b/src/allmydata/test/test_node.py
@@ -8,7 +8,7 @@ from mock import patch
 
 from foolscap.api import flushEventualQueue
 from twisted.application import service
-from allmydata.node import Node, formatTimeTahoeStyle
+from allmydata.node import Node, formatTimeTahoeStyle, MissingConfigEntry
 from allmydata.util import fileutil
 import allmydata.test.common_util as testutil
 
@@ -87,6 +87,34 @@ class TestCase(testutil.SignalMixin, unittest.TestCase):
                                                        u"\u2621"))
         return d
 
+    def test_private_config(self):
+        basedir = "test_node/test_private_config"
+        privdir = os.path.join(basedir, "private")
+        fileutil.make_dirs(privdir)
+        f = open(os.path.join(privdir, 'already'), 'wt')
+        f.write("secret")
+        f.close()
+
+        n = TestNode(basedir)
+        self.failUnlessEqual(n.get_private_config("already"), "secret")
+        self.failUnlessEqual(n.get_private_config("not", "default"), "default")
+        self.failUnlessRaises(MissingConfigEntry, n.get_private_config, "not")
+        value = n.get_or_create_private_config("new", "start")
+        self.failUnlessEqual(value, "start")
+        self.failUnlessEqual(n.get_private_config("new"), "start")
+        counter = []
+        def make_newer():
+            counter.append("called")
+            return "newer"
+        value = n.get_or_create_private_config("newer", make_newer)
+        self.failUnlessEqual(len(counter), 1)
+        self.failUnlessEqual(value, "newer")
+        self.failUnlessEqual(n.get_private_config("newer"), "newer")
+
+        value = n.get_or_create_private_config("newer", make_newer)
+        self.failUnlessEqual(len(counter), 1) # don't call unless necessary
+        self.failUnlessEqual(value, "newer")
+
     def test_timestamp(self):
         # this modified logger doesn't seem to get used during the tests,
         # probably because we don't modify the LogObserver that trial
-- 
2.45.2