From 58841cab38c5d9d09184e28452d388add3c2eafa Mon Sep 17 00:00:00 2001
From: Daira Hopwood <daira@jacaranda.org>
Date: Mon, 21 Dec 2015 21:59:15 +0000
Subject: [PATCH] Refactor tahoe.cfg handling to configutil.

Author: David Stainton <david@leastauthority.com>
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
---
 src/allmydata/node.py                 | 19 +++------------
 src/allmydata/test/test_configutil.py | 34 +++++++++++++++++++++++++++
 src/allmydata/util/configutil.py      | 29 +++++++++++++++++++++++
 3 files changed, 66 insertions(+), 16 deletions(-)
 create mode 100644 src/allmydata/test/test_configutil.py
 create mode 100644 src/allmydata/util/configutil.py

diff --git a/src/allmydata/node.py b/src/allmydata/node.py
index 98ce3cb7..f77c2ac2 100644
--- a/src/allmydata/node.py
+++ b/src/allmydata/node.py
@@ -12,6 +12,7 @@ from allmydata.util import fileutil, iputil, observer
 from allmydata.util.assertutil import precondition, _assert
 from allmydata.util.fileutil import abspath_expanduser_unicode
 from allmydata.util.encodingutil import get_filesystem_encoding, quote_output
+from allmydata.util import configutil
 
 # Add our application versions to the data that Foolscap's LogPublisher
 # reports.
@@ -133,27 +134,13 @@ class Node(service.MultiService):
                                          % (quote_output(fn), section, option))
             return default
 
-    def set_config(self, section, option, value):
-        if not self.config.has_section(section):
-            self.config.add_section(section)
-        self.config.set(section, option, value)
-        assert self.config.get(section, option) == value
-
     def read_config(self):
         self.error_about_old_config_files()
         self.config = ConfigParser.SafeConfigParser()
 
         tahoe_cfg = os.path.join(self.basedir, "tahoe.cfg")
         try:
-            f = open(tahoe_cfg, "rb")
-            try:
-                # Skip any initial Byte Order Mark. Since this is an ordinary file, we
-                # don't need to handle incomplete reads, and can assume seekability.
-                if f.read(3) != '\xEF\xBB\xBF':
-                    f.seek(0)
-                self.config.readfp(f)
-            finally:
-                f.close()
+            self.config = configutil.get_config(tahoe_cfg)
         except EnvironmentError:
             if os.path.exists(tahoe_cfg):
                 raise
@@ -165,7 +152,7 @@ class Node(service.MultiService):
             # provide a value.
             try:
                 file_tubport = fileutil.read(self._portnumfile).strip()
-                self.set_config("node", "tub.port", file_tubport)
+                configutil.set_config(self.config, "node", "tub.port", file_tubport)
             except EnvironmentError:
                 if os.path.exists(self._portnumfile):
                     raise
diff --git a/src/allmydata/test/test_configutil.py b/src/allmydata/test/test_configutil.py
new file mode 100644
index 00000000..14f87fbd
--- /dev/null
+++ b/src/allmydata/test/test_configutil.py
@@ -0,0 +1,34 @@
+import os.path
+
+from twisted.trial import unittest
+
+from allmydata.util import configutil
+from allmydata.test.no_network import GridTestMixin
+from .test_cli import CLITestMixin
+
+
+class ConfigUtilTests(CLITestMixin, GridTestMixin, unittest.TestCase):
+
+    def test_config_utils(self):
+        self.basedir = "cli/ConfigUtilTests/test-config-utils"
+        self.set_up_grid()
+        tahoe_cfg = os.path.join(self.get_clientdir(i=0), "tahoe.cfg")
+
+        # test that at least one option was read correctly
+        config = configutil.get_config(tahoe_cfg)
+        self.failUnlessEqual(config.get("node", "nickname"), "client-0")
+
+        # test that set_config can mutate an existing option
+        configutil.set_config(config, "node", "nickname", "Alice!")
+        configutil.write_config(tahoe_cfg, config)
+
+        config = configutil.get_config(tahoe_cfg)
+        self.failUnlessEqual(config.get("node", "nickname"), "Alice!")
+
+        # test that set_config can set a new option
+        descriptor = "Twas brillig, and the slithy toves Did gyre and gimble in the wabe"
+        configutil.set_config(config, "node", "descriptor", descriptor)
+        configutil.write_config(tahoe_cfg, config)
+
+        config = configutil.get_config(tahoe_cfg)
+        self.failUnlessEqual(config.get("node", "descriptor"), descriptor)
diff --git a/src/allmydata/util/configutil.py b/src/allmydata/util/configutil.py
new file mode 100644
index 00000000..19f712dc
--- /dev/null
+++ b/src/allmydata/util/configutil.py
@@ -0,0 +1,29 @@
+
+from ConfigParser import SafeConfigParser
+
+
+def get_config(tahoe_cfg):
+    config = SafeConfigParser()
+    f = open(tahoe_cfg, "rb")
+    try:
+        # Skip any initial Byte Order Mark. Since this is an ordinary file, we
+        # don't need to handle incomplete reads, and can assume seekability.
+        if f.read(3) != '\xEF\xBB\xBF':
+            f.seek(0)
+        config.readfp(f)
+    finally:
+        f.close()
+    return config
+
+def set_config(config, section, option, value):
+    if not config.has_section(section):
+        config.add_section(section)
+    config.set(section, option, value)
+    assert config.get(section, option) == value
+
+def write_config(tahoe_cfg, config):
+    f = open(tahoe_cfg, "wb")
+    try:
+        config.write(f)
+    finally:
+        f.close()
-- 
2.45.2