1# Copyright 2007 Google Inc. 2# 3# This program is free software; you can redistribute it and/or 4# modify it under the terms of the GNU General Public License 5# as published by the Free Software Foundation; either version 2 6# of the License, or (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program; if not, write to the Free Software Foundation, 15# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16"""Unit tests for nss_cache/config.py.""" 17 18__author__ = 'vasilios@google.com (Vasilios Hoffman)' 19 20import os 21import shutil 22import tempfile 23import unittest 24 25from nss_cache import config 26 27 28class TestConfig(unittest.TestCase): 29 """Unit tests for config.Config().""" 30 31 def testConfigInit(self): 32 env = {'NSSCACHE_CONFIG': 'test.conf'} 33 conf = config.Config(env) 34 35 self.assertEqual(conf.config_file, 36 env['NSSCACHE_CONFIG'], 37 msg='Failed to override NSSCACHE_CONFIG.') 38 39 40class TestMapOptions(unittest.TestCase): 41 """Unit tests for config.MapOptions().""" 42 43 def testMapOptionsInit(self): 44 mapconfig = config.MapOptions() 45 self.assertTrue(isinstance(mapconfig.cache, dict)) 46 self.assertTrue(isinstance(mapconfig.source, dict)) 47 48 49class TestClassMethods(unittest.TestCase): 50 """Unit tests for class-level methods in config.py.""" 51 52 def setUp(self): 53 # create a directory with a writeable copy of nsscache.conf in it 54 self.workdir = tempfile.mkdtemp() 55 conf_filename = 'nsscache.conf' 56 self.conf_filename = os.path.join(self.workdir, conf_filename) 57 shutil.copy(conf_filename, self.conf_filename) 58 os.chmod(self.conf_filename, 0o640) 59 60 # prepare a config object with this config 61 self.conf = config.Config({}) 62 self.conf.config_file = self.conf_filename 63 64 def tearDown(self): 65 shutil.rmtree(self.workdir) 66 67 def testLoadConfigSingleMap(self): 68 conf_file = open(self.conf_filename, 'w') 69 conf_file.write('[DEFAULT]\n' 70 'source = foo\n' 71 'cache = foo\n' 72 'maps = foo\n' 73 'timestamp_dir = foo\n') 74 conf_file.close() 75 76 config.LoadConfig(self.conf) 77 78 self.assertEqual(['foo'], self.conf.maps) 79 80 def testLoadConfigTwoMaps(self): 81 conf_file = open(self.conf_filename, 'w') 82 conf_file.write('[DEFAULT]\n' 83 'source = foo\n' 84 'cache = foo\n' 85 'maps = foo, bar\n' 86 'timestamp_dir = foo\n') 87 conf_file.close() 88 89 config.LoadConfig(self.conf) 90 91 self.assertEqual(['foo', 'bar'], self.conf.maps) 92 93 def testLoadConfigMapsWhitespace(self): 94 conf_file = open(self.conf_filename, 'w') 95 conf_file.write('[DEFAULT]\n' 96 'source = foo\n' 97 'cache = foo\n' 98 'maps = foo, bar , baz\n' 99 'timestamp_dir = foo\n') 100 conf_file.close() 101 102 config.LoadConfig(self.conf) 103 104 self.assertEqual(['foo', 'bar', 'baz'], self.conf.maps) 105 106 def testLoadConfigExample(self): 107 """Test that we parse and load the example config. 108 109 Note that this also tests MapOptions() creation and our overriding 110 of defaults in LoadConfig. 111 112 This requires that nsscache.conf exists in the top of the source tree. 113 Changes to the configuration options may break this test. 114 """ 115 conf = self.conf 116 config.LoadConfig(conf) 117 passwd = conf.options['passwd'] 118 group = conf.options['group'] 119 shadow = conf.options['shadow'] 120 automount = conf.options['automount'] 121 122 self.assertTrue(isinstance(passwd, config.MapOptions)) 123 self.assertTrue(isinstance(group, config.MapOptions)) 124 self.assertTrue(isinstance(shadow, config.MapOptions)) 125 self.assertTrue(isinstance(automount, config.MapOptions)) 126 127 self.assertEqual(passwd.source['name'], 'ldap') 128 self.assertEqual(group.source['name'], 'ldap') 129 self.assertEqual(shadow.source['name'], 'ldap') 130 self.assertEqual(automount.source['name'], 'ldap') 131 132 self.assertEqual(passwd.cache['name'], 'files') 133 self.assertEqual(group.cache['name'], 'files') 134 self.assertEqual(shadow.cache['name'], 'files') 135 self.assertEqual(automount.cache['name'], 'files') 136 137 self.assertEqual(passwd.source['base'], 'ou=people,dc=example,dc=com') 138 self.assertEqual(passwd.source['filter'], '(objectclass=posixAccount)') 139 140 self.assertEqual(group.source['base'], 'ou=group,dc=example,dc=com') 141 self.assertEqual(group.source['filter'], '(objectclass=posixGroup)') 142 143 def testLoadConfigOptionalDefaults(self): 144 conf_file = open(self.conf_filename, 'w') 145 conf_file.write('[DEFAULT]\n' 146 'source = foo\n' 147 'cache = foo\n' 148 'maps = foo, bar , baz\n' 149 'lockfile = foo\n' 150 'timestamp_dir = foo\n') 151 conf_file.close() 152 153 config.LoadConfig(self.conf) 154 155 self.assertEqual(self.conf.lockfile, 'foo') 156 157 def testLoadConfigStripQuotesFromStrings(self): 158 conf_file = open(self.conf_filename, 'w') 159 conf_file.write('[DEFAULT]\n' 160 'source = "ldap"\n' # needs to be ldap due to magic 161 'cache = \'b\'ar\'\n' 162 'maps = quux\n' 163 'timestamp_dir = foo\n' 164 'ldap_tls_require_cert = \'blah\'\n' 165 '[quux]\n' 166 'ldap_klingon = "qep\'a\' wa\'maH loS\'DIch"\n') 167 conf_file.close() 168 config.LoadConfig(self.conf) 169 self.assertEqual('ldap', self.conf.options['quux'].source['name']) 170 self.assertEqual('b\'ar', self.conf.options['quux'].cache['name']) 171 self.assertEqual('blah', 172 self.conf.options['quux'].source['tls_require_cert']) 173 self.assertEqual('qep\'a\' wa\'maH loS\'DIch', 174 self.conf.options['quux'].source['klingon']) 175 176 def testLoadConfigConvertsNumbers(self): 177 conf_file = open(self.conf_filename, 'w') 178 conf_file.write('[DEFAULT]\n' 179 'source = foo\n' 180 'cache = foo\n' 181 'maps = foo\n' 182 'timestamp_dir = foo\n' 183 'foo_string = test\n' 184 'foo_float = 1.23\n' 185 'foo_int = 1\n') 186 conf_file.close() 187 188 config.LoadConfig(self.conf) 189 190 foo_dict = self.conf.options['foo'].source 191 self.assertTrue(isinstance(foo_dict['string'], str)) 192 self.assertTrue(isinstance(foo_dict['float'], float)) 193 self.assertTrue(isinstance(foo_dict['int'], int)) 194 self.assertEqual(foo_dict['string'], 'test') 195 self.assertEqual(foo_dict['float'], 1.23) 196 self.assertEqual(foo_dict['int'], 1) 197 198 def testOptions(self): 199 # check the empty case. 200 options = config.Options([], 'foo') 201 self.assertEqual(options, {}) 202 203 # create a list like from ConfigParser.items() 204 items = [('maps', 'foo, bar, foobar'), ('nssdb_dir', '/path/to/dir'), 205 ('ldap_uri', 'TEST_URI'), ('source', 'foo'), ('cache', 'bar'), 206 ('ldap_base', 'TEST_BASE'), ('ldap_filter', 'TEST_FILTER')] 207 208 options = config.Options(items, 'ldap') 209 210 self.assertTrue('uri' in options) 211 self.assertTrue('base' in options) 212 self.assertTrue('filter' in options) 213 214 self.assertEqual(options['uri'], 'TEST_URI') 215 self.assertEqual(options['base'], 'TEST_BASE') 216 self.assertEqual(options['filter'], 'TEST_FILTER') 217 218 def testParseNSSwitchConf(self): 219 nsswitch_filename = os.path.join(self.workdir, 'nsswitch.conf') 220 nsswitch_file = open(nsswitch_filename, 'w') 221 nsswitch_file.write('passwd: files db\n') 222 nsswitch_file.write('group: files db\n') 223 nsswitch_file.write('shadow: files db\n') 224 nsswitch_file.close() 225 expected_switch = { 226 'passwd': ['files', 'db'], 227 'group': ['files', 'db'], 228 'shadow': ['files', 'db'] 229 } 230 self.assertEqual(expected_switch, 231 config.ParseNSSwitchConf(nsswitch_filename)) 232 os.unlink(nsswitch_filename) 233 234 def testVerifyConfiguration(self): 235 conf_file = open(self.conf_filename, 'w') 236 conf_file.write('[DEFAULT]\n' 237 'source = foo\n' 238 'cache = foo\n' 239 'maps = passwd, group, shadow\n' 240 'timestamp_dir = foo\n') 241 conf_file.close() 242 config.LoadConfig(self.conf) 243 nsswitch_filename = os.path.join(self.workdir, 'nsswitch.conf') 244 nsswitch_file = open(nsswitch_filename, 'w') 245 nsswitch_file.write('passwd: files db\n') 246 nsswitch_file.write('group: files db\n') 247 nsswitch_file.write('shadow: files db\n') 248 nsswitch_file.close() 249 self.assertEqual((0, 0), 250 config.VerifyConfiguration(self.conf, 251 nsswitch_filename)) 252 os.unlink(nsswitch_filename) 253 254 def testVerifyConfigurationWithCache(self): 255 conf_file = open(self.conf_filename, 'w') 256 conf_file.write('[DEFAULT]\n' 257 'source = foo\n' 258 'cache = files\n' 259 'maps = passwd, group, shadow\n' 260 'timestamp_dir = foo\n' 261 'files_cache_filename_suffix = cache') 262 conf_file.close() 263 config.LoadConfig(self.conf) 264 nsswitch_filename = os.path.join(self.workdir, 'nsswitch.conf') 265 nsswitch_file = open(nsswitch_filename, 'w') 266 nsswitch_file.write('passwd: cache\n') 267 nsswitch_file.write('group: cache\n') 268 nsswitch_file.write('shadow: cache\n') 269 nsswitch_file.close() 270 self.assertEqual((0, 0), 271 config.VerifyConfiguration(self.conf, 272 nsswitch_filename)) 273 os.unlink(nsswitch_filename) 274 275 def testVerifyConfigurationWithFiles(self): 276 conf_file = open(self.conf_filename, 'w') 277 conf_file.write('[DEFAULT]\n' 278 'source = foo\n' 279 'cache = files\n' 280 'maps = passwd, group, shadow\n' 281 'timestamp_dir = foo\n') 282 conf_file.close() 283 config.LoadConfig(self.conf) 284 nsswitch_filename = os.path.join(self.workdir, 'nsswitch.conf') 285 nsswitch_file = open(nsswitch_filename, 'w') 286 nsswitch_file.write('passwd: files\n') 287 nsswitch_file.write('group: files\n') 288 nsswitch_file.write('shadow: files\n') 289 nsswitch_file.close() 290 self.assertEqual((0, 0), 291 config.VerifyConfiguration(self.conf, 292 nsswitch_filename)) 293 os.unlink(nsswitch_filename) 294 295 def testVerifyBadConfigurationWithCache(self): 296 conf_file = open(self.conf_filename, 'w') 297 conf_file.write('[DEFAULT]\n' 298 'source = foo\n' 299 'cache = files\n' 300 'maps = passwd, group, shadow\n' 301 'timestamp_dir = foo\n' 302 'files_cache_filename_suffix = cache') 303 conf_file.close() 304 config.LoadConfig(self.conf) 305 nsswitch_filename = os.path.join(self.workdir, 'nsswitch.conf') 306 nsswitch_file = open(nsswitch_filename, 'w') 307 nsswitch_file.write('passwd: files\n') 308 nsswitch_file.write('group: files\n') 309 nsswitch_file.write('shadow: files\n') 310 nsswitch_file.close() 311 self.assertEqual((3, 0), 312 config.VerifyConfiguration(self.conf, 313 nsswitch_filename)) 314 os.unlink(nsswitch_filename) 315 316 def testVerifyBadConfigurationIncrementsWarningCount(self): 317 conf_file = open(self.conf_filename, 'w') 318 conf_file.write('[DEFAULT]\n' 319 'source = foo\n' 320 'cache = foo\n' 321 'maps = passwd, group, shadow\n' 322 'timestamp_dir = foo\n') 323 conf_file.close() 324 config.LoadConfig(self.conf) 325 nsswitch_filename = os.path.join(self.workdir, 'nsswitch.conf') 326 nsswitch_file = open(nsswitch_filename, 'w') 327 nsswitch_file.write('passwd: files ldap\n') 328 nsswitch_file.write('group: files db\n') 329 nsswitch_file.write('shadow: files db\n') 330 nsswitch_file.close() 331 self.assertEqual((1, 0), 332 config.VerifyConfiguration(self.conf, 333 nsswitch_filename)) 334 os.unlink(nsswitch_filename) 335 336 def testVerifyNoMapConfigurationIsError(self): 337 conf_file = open(self.conf_filename, 'w') 338 conf_file.write('[DEFAULT]\n' 339 'source = foo\n' 340 'cache = foo\n' 341 'maps = \n' 342 'timestamp_dir = foo\n') 343 conf_file.close() 344 config.LoadConfig(self.conf) 345 nsswitch_filename = os.path.join(self.workdir, 'nsswitch.conf') 346 nsswitch_file = open(nsswitch_filename, 'w') 347 nsswitch_file.write('passwd: files ldap\n') 348 nsswitch_file.close() 349 self.assertEqual((0, 1), 350 config.VerifyConfiguration(self.conf, 351 nsswitch_filename)) 352 os.unlink(nsswitch_filename) 353 354 355if __name__ == '__main__': 356 unittest.main() 357