Merge lp:~gmb/lpsetup/death-to-doctests-in-subcommands into lp:lpsetup

Proposed by Graham Binns
Status: Merged
Approved by: Graham Binns
Approved revision: 52
Merged at revision: 51
Proposed branch: lp:~gmb/lpsetup/death-to-doctests-in-subcommands
Merge into: lp:lpsetup
Diff against target: 236 lines (+114/-83)
2 files modified
lpsetup/subcommands/inithost.py (+2/-82)
lpsetup/tests/subcommands/test_inithost.py (+112/-1)
To merge this branch: bzr merge lp:~gmb/lpsetup/death-to-doctests-in-subcommands
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+114393@code.launchpad.net

Commit message

The doctests in the subcommands package have been turned into unit tests.

Description of the change

This branch removes all the subcommands doctests and turns them into unit tests. I'll tackle other doctests in separate branches.

To post a comment you must log in.
50. By Graham Binns

Fixed conflicts and lint.

Revision history for this message
Brad Crittenden (bac) wrote :

Looks good Graham.

On IRC we discussed:

1) ORing the expected file stat masks together and then using XOR with the actual mode to allow a single assertion.

2) Taking into account the new behavior of write_file_contents where it no longer added the \n.

Thanks,
Brad

review: Approve (code)
51. By Graham Binns

Bitwise funk.

52. By Graham Binns

Test tweak.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lpsetup/subcommands/inithost.py'
--- lpsetup/subcommands/inithost.py 2012-07-10 19:06:12 +0000
+++ lpsetup/subcommands/inithost.py 2012-07-11 11:50:23 +0000
@@ -53,39 +53,7 @@
5353
5454
55def write_file_contents(filename, contents, mode, header=None):55def write_file_contents(filename, contents, mode, header=None):
56 """Write `contents` to filename and chmod it to 0644.56 """Write `contents` to filename and chmod it to 0644."""
57
58 >>> write_file_contents('/tmp/foo', 'Hello, world', 'w')
59 >>> print open('/tmp/foo', 'r').read()
60 Hello, world
61 >>> os.remove('/tmp/foo')
62
63 If the file already exists, `mode` is set to 'w', and the file's
64 contents differ from `contents`, write_file_contents() raises an
65 Exception.
66
67 >>> write_file_contents('/tmp/foo', 'Hello, world', 'w')
68 >>> write_file_contents(
69 ... '/tmp/foo', 'Hello again, world', 'w') # doctest: +ELLIPSIS
70 Traceback (most recent call last):
71 Exception: File /tmp/foo already exists with different contents...
72 >>> os.remove('/tmp/foo')
73
74 If the existing file's contents don't differ from `contents`,
75 write_file_contents() will simply return.
76
77 >>> write_file_contents('/tmp/foo', 'Hello, world', 'w')
78 >>> write_file_contents(
79 ... '/tmp/foo', 'Hello, world', 'w') # doctest: +ELLIPSIS
80 >>> os.remove('/tmp/foo')
81
82 Passing a `mode` other than "a" or "w" will cause an Exception.
83
84 >>> write_file_contents(
85 ... '/tmp/foo', 'Hello, world', 'w+') # doctest: +ELLIPSIS
86 Traceback (most recent call last):
87 AssertionError: Mode should be 'w' or 'a' only...
88 """
89 assert mode in ('w', 'a'), "Mode should be 'w' or 'a' only."57 assert mode in ('w', 'a'), "Mode should be 'w' or 'a' only."
90 if mode == 'w' and os.path.exists(filename):58 if mode == 'w' and os.path.exists(filename):
91 with open(filename, 'r') as existing_file:59 with open(filename, 'r') as existing_file:
@@ -104,55 +72,7 @@
10472
105def ensure_ssh_keys(ssh_dir, private_key, public_key, valid_ssh_keys,73def ensure_ssh_keys(ssh_dir, private_key, public_key, valid_ssh_keys,
106 ssh_key_path):74 ssh_key_path):
107 """Ensure that SSH is configured correctly for the user.75 """Ensure that SSH is configured correctly for the user."""
108
109 If valid SSH keys are passed to the function, they will be written
110 out to `ssh_key_path`
111
112 >>> public = "Public key"
113 >>> private = "Private key"
114 >>> ssh_dir = "/tmp"
115 >>> ensure_ssh_keys(ssh_dir, private, public, True, '/tmp/test_key')
116 >>> public_keyfile = open('/tmp/test_key.pub', 'r')
117 >>> print public_keyfile.read() # doctest: +ELLIPSIS
118 # This file created at ...
119 Public key
120 >>> private_keyfile = open('/tmp/test_key', 'r')
121 >>> print private_keyfile.read() # doctest: +ELLIPSIS
122 # This file created at ...
123 Private key
124
125 Two other files will have been generated: authorized_keys and known_hosts
126
127 >>> print open(
128 ... '/tmp/authorized_keys', 'r').read() # doctest: +ELLIPSIS
129 # This file created at ...
130 Public key
131 >>> print open('/tmp/known_hosts', 'r').read() # doctest: +ELLIPSIS
132 # This file created at ...
133 bazaar.launchpad.net ...
134 >>> os.remove('/tmp/test_key')
135 >>> os.remove('/tmp/test_key.pub')
136 >>> os.remove('/tmp/authorized_keys')
137 >>> os.remove('/tmp/known_hosts')
138
139 If valid keys are not passed, new keys will be generated.
140
141 >>> ensure_ssh_keys(ssh_dir, None, None, False, '/tmp/test_key')
142 >>> os.path.exists('/tmp/test_key')
143 True
144 >>> os.path.exists('/tmp/test_key.pub')
145 True
146 >>> os.path.exists('/tmp/authorized_keys')
147 True
148 >>> os.path.exists('/tmp/known_hosts')
149 True
150 >>> os.remove('/tmp/test_key')
151 >>> os.remove('/tmp/test_key.pub')
152 >>> os.remove('/tmp/authorized_keys')
153 >>> os.remove('/tmp/known_hosts')
154
155 """
156 # Set up the user's ssh directory. The ssh key must be associated76 # Set up the user's ssh directory. The ssh key must be associated
157 # with the lpuser's Launchpad account.77 # with the lpuser's Launchpad account.
158 mkdirs(ssh_dir)78 mkdirs(ssh_dir)
15979
=== modified file 'lpsetup/tests/subcommands/test_inithost.py'
--- lpsetup/tests/subcommands/test_inithost.py 2012-07-09 21:18:21 +0000
+++ lpsetup/tests/subcommands/test_inithost.py 2012-07-11 11:50:23 +0000
@@ -4,6 +4,10 @@
44
5"""Tests for the inithost sub command."""5"""Tests for the inithost sub command."""
66
7import os
8import shutil
9import stat
10import tempfile
7import unittest11import unittest
812
9from lpsetup import handlers13from lpsetup import handlers
@@ -36,7 +40,7 @@
36 '-v', private_key, '-b', public_key, '-S', ssh_key_name)40 '-v', private_key, '-b', public_key, '-S', ssh_key_name)
3741
3842
39class InithostTest(StepsBasedSubCommandTestMixin, unittest.TestCase):43class InithostSmokeTest(StepsBasedSubCommandTestMixin, unittest.TestCase):
4044
41 sub_command_class = inithost.SubCommand45 sub_command_class = inithost.SubCommand
42 expected_arguments = get_arguments()46 expected_arguments = get_arguments()
@@ -51,3 +55,110 @@
51 initialize_lxc_step,55 initialize_lxc_step,
52 setup_apt_step,)56 setup_apt_step,)
53 needs_root = True57 needs_root = True
58
59
60class WriteFileContentsTestCase(unittest.TestCase):
61 """Tests for inithost.write_file_contents()."""
62
63 def setUp(self):
64 temp_file = tempfile.NamedTemporaryFile()
65 # Calling close() on the temp_file will delete it, but its name
66 # will live on...
67 temp_file.close()
68 self.temp_filename = temp_file.name
69
70 def test_write_file_contents_writes_file_contents(self):
71 # inithost.write_file_contents writes the supplied file contents
72 # to a given file using the mode provided and chmods the file to
73 # 0644 for the current user.
74 self.addCleanup(os.remove, self.temp_filename)
75 inithost.write_file_contents(self.temp_filename, 'Hello, world!', 'w')
76 with open(self.temp_filename, 'r') as the_file:
77 contents = the_file.read()
78 self.assertEqual('Hello, world!', contents)
79 file_mode = os.stat(self.temp_filename).st_mode
80 # The file permissions should be 0644. So, we do a bitwise
81 # dance...
82 expected_mode = (
83 stat.S_IWUSR | stat.S_IRUSR | stat.S_IRGRP | stat.S_IWGRP |
84 stat.S_IROTH | ~ stat.S_IXUSR | ~ stat.S_IWGRP |
85 ~ stat.S_IXGRP | ~ stat.S_IWOTH | ~ stat.S_IXOTH)
86 self.assertTrue(file_mode ^ expected_mode)
87
88 def test_write_file_contents_wont_overwrite_existing_files(self):
89 # If the file already exists, `mode` is set to 'w', and the file's
90 # contents differ from `contents`, write_file_contents() raises an
91 # Exception.
92 self.addCleanup(os.remove, self.temp_filename)
93 inithost.write_file_contents(self.temp_filename, 'Hello, world!', 'w')
94 self.assertRaises(
95 Exception, inithost.write_file_contents, self.temp_filename,
96 'Hello again!', 'w')
97
98 def test_write_file_contents_returns_if_file_contents_dont_change(self):
99 # If the existing file's contents don't differ from `contents`,
100 # write_file_contents() will simply return.
101 self.addCleanup(os.remove, self.temp_filename)
102 inithost.write_file_contents(self.temp_filename, 'Hello, world!', 'w')
103 # This second call shouldn't raise an exception.
104 inithost.write_file_contents(self.temp_filename, 'Hello, world!', 'w')
105
106 def test_write_file_contents_accepts_modes_a_or_w(self):
107 # Passing a `mode` other than "a" or "w" to write_file_contents()
108 # will cause an Exception.
109 self.assertRaises(
110 AssertionError, inithost.write_file_contents,
111 '/tmp/foo', 'Hello, world!', 'a+')
112
113
114class EnsureSSHKeysTestCase(unittest.TestCase):
115 """Tests for inithost.ensure_ssh_keys()."""
116
117 def setUp(self):
118 temp_file = tempfile.NamedTemporaryFile()
119 temp_file.close()
120 self.temp_filename = temp_file.name
121 self.ssh_dir = tempfile.mkdtemp()
122 self.addCleanup(shutil.rmtree, self.ssh_dir)
123 self.addCleanup(os.remove, self.temp_filename)
124 self.addCleanup(os.remove, self.temp_filename + ".pub")
125
126 def test_ensure_ssh_keys_writes_to_ssh_key_path(self):
127 # If inithost.ensure_ssh_keys() is told that the keys it has
128 # been passed are valid, it will write them out to the provided
129 # ssh_key_path.
130 public_key = "Public"
131 private_key = "Private"
132 inithost.ensure_ssh_keys(
133 self.ssh_dir, private_key, public_key, True, self.temp_filename)
134 with open(self.temp_filename + '.pub', 'r') as pub_file:
135 self.assertIn(public_key, pub_file.read())
136 with open(self.temp_filename, 'r') as priv_file:
137 self.assertIn(private_key, priv_file.read())
138
139 def test_ensure_ssh_keys_generates_keys_if_not_passed(self):
140 # If SSH keys aren't passed to ensure_ssh_keys(), the function
141 # will generate some.
142 inithost.ensure_ssh_keys(
143 self.ssh_dir, None, None, False, self.temp_filename)
144 self.assertTrue(os.path.exists(self.temp_filename))
145 self.assertTrue(os.path.exists(self.temp_filename + ".pub"))
146
147 def test_ensure_ssh_keys_generates_other_files(self):
148 # ensure_ssh_keys() also generates an authorized_keys file and a
149 # known_hosts file in the ssh dir.
150 inithost.ensure_ssh_keys(
151 self.ssh_dir, None, None, False, self.temp_filename)
152 self.assertTrue(
153 os.path.exists(os.path.join(self.ssh_dir, 'authorized_keys')))
154 self.assertTrue(
155 os.path.exists(os.path.join(self.ssh_dir, 'known_hosts')))
156
157 def test_ensure_ssh_keys_creates_ssh_dir(self):
158 # If the ssh_dir passed to ensure_ssh_keys() doesn't exist, it
159 # will be created.
160 shutil.rmtree(self.ssh_dir)
161 inithost.ensure_ssh_keys(
162 self.ssh_dir, None, None, False, self.temp_filename)
163 self.assertTrue(os.path.exists(self.ssh_dir))
164 self.assertTrue(os.path.isdir(self.ssh_dir))

Subscribers

People subscribed via source and target branches