def testTimeZone(self): config = configuration.CoreConfig() self.assertEqual(None, config._get_option('TIMEZONE').set("0")) # not a valid timezone self.assertRaises(configuration.OptionValueError, config._get_option('TIMEZONE').set, "Zot") # 25 is not a valid UTC offset: -12 - +14 is range # possibly +/- 1 for DST. But roundup.date doesn't # constrain to this range. #self.assertRaises(configuration.OptionValueError, # config._get_option('TIMEZONE').set, "25") try: import pytz self.assertEqual(None, config._get_option('TIMEZONE').set("UTC")) self.assertEqual(None, config._get_option('TIMEZONE').set("America/New_York")) except ImportError: self.assertRaises(configuration.OptionValueError, config._get_option('TIMEZONE').set, "UTC") self.assertRaises(configuration.OptionValueError, config._get_option('TIMEZONE').set, "America/New_York")
def run_demo(home): """Run the demo tracker instance from its ``home`` directory""" print("Demo Tracker Home:", home) cfg = configuration.CoreConfig(home) url = cfg["TRACKER_WEB"] hostname, port = urlparse.urlparse(url)[1].split(':') port = int(port) success_message = '''Server running - connect to: %(url)s 1. Log in as "demo"/"demo" or "admin"/"admin". 2. Hit Control-C to stop the server. 3. Re-start the server by running "%(script)s" again. 4. Reset the tracker by running "%(script)s nuke". By default the demo tracker is set up to be accessed from "localhost". If you want to run it on a server, edit "%(datadir)s/config.ini" and set the "web" option in section "[tracker]" to your host name, then restart demo. If you want to change backend types, you must use "nuke". ''' % dict(url=url, script=sys.argv[0], datadir=TRACKER_HOME) # disable command line processing in roundup_server sys.argv = sys.argv[:1] + ['-p', str(port), '-n', hostname, 'demo=' + home] roundup_server.run(success_message=success_message)
def testConfigSave(self): config = configuration.CoreConfig() # make scratch directory to create files in self.startdir = os.getcwd() self.dirname = os.getcwd() + '_test_config' os.mkdir(self.dirname) try: os.chdir(self.dirname) self.assertFalse(os.access("config.ini", os.F_OK)) self.assertFalse(os.access("config.bak", os.F_OK)) config.save() config.save() # creates .bak file self.assertTrue(os.access("config.ini", os.F_OK)) self.assertTrue(os.access("config.bak", os.F_OK)) self.assertFalse(os.access("foo.bar", os.F_OK)) self.assertFalse(os.access("foo.bak", os.F_OK)) config.save("foo.bar") config.save("foo.bar") # creates .bak file self.assertTrue(os.access("foo.bar", os.F_OK)) self.assertTrue(os.access("foo.bak", os.F_OK)) finally: # cleanup scratch directory and files try: os.chdir(self.startdir) shutil.rmtree(self.dirname) except OSError as error: if error.errno not in (errno.ENOENT, errno.ESRCH): raise
def testTimeZone(self): config = configuration.CoreConfig() self.assertEqual(None, config._get_option('TIMEZONE').set("0")) # not a valid timezone self.assertRaises(configuration.OptionValueError, config._get_option('TIMEZONE').set, "Zot") # 25 is not a valid UTC offset: -12 - +14 is range # possibly +/- 1 for DST. But roundup.date doesn't # constrain to this range. #self.assertRaises(configuration.OptionValueError, # config._get_option('TIMEZONE').set, "25") try: import pytz self.assertEqual(None, config._get_option('TIMEZONE').set("UTC")) self.assertEqual( None, config._get_option('TIMEZONE').set("America/New_York")) self.assertEqual(None, config._get_option('TIMEZONE').set("EST")) self.assertRaises(configuration.OptionValueError, config._get_option('TIMEZONE').set, "Zool/Zot") except ImportError: # UTC is a known offset of 0 coded into roundup.date # so it works even without pytz. self.assertEqual(None, config._get_option('TIMEZONE').set("UTC")) # same with EST known timeone offset of 5 self.assertEqual(None, config._get_option('TIMEZONE').set("EST")) self.assertRaises(configuration.OptionValueError, config._get_option('TIMEZONE').set, "America/New_York")
def testWebSecretKey(self): config = configuration.CoreConfig() self.assertEqual(None, config._get_option('WEB_SECRET_KEY').set("skskskd")) self.assertRaises(configuration.OptionValueError, config._get_option('WEB_SECRET_KEY').set, "")
def testOctalNumberOption(self): config = configuration.CoreConfig() with self.assertRaises(configuration.OptionValueError) as cm: config._get_option('UMASK').set("xyzzy") print(type(config._get_option('UMASK')))
def testStaticFiles(self): config = configuration.CoreConfig() self.assertEqual( None, config._get_option('STATIC_FILES').set("foo /tmp/bar")) self.assertEqual(config.STATIC_FILES, ["./foo", "/tmp/bar"]) self.assertEqual(config['STATIC_FILES'], ["./foo", "/tmp/bar"])
def new_config(debug=False): config = configuration.CoreConfig() config.DATABASE = "db" #config.logging = MockNull() # these TRACKER_WEB and MAIL_DOMAIN values are used in mailgw tests if debug: config.LOGGING_LEVEL = "DEBUG" config.MAIL_DOMAIN = "your.tracker.email.domain.example" config.TRACKER_WEB = "http://tracker.example/cgi-bin/roundup.cgi/bugs/" return config
def testUnsetMailPassword_with_unset_username(self): """ Set [mail] username but don't set the [mail] password. Should get an OptionValueError. """ config = configuration.CoreConfig() config.load(self.dirname) self.assertEqual(config['MAIL_USERNAME'], '') with self.assertRaises(configuration.OptionUnsetError) as cm: self.assertEqual(config['MAIL_PASSWORD'], 'NO DEFAULT')
def testFloatAndInt_with_update_option(self): config = configuration.CoreConfig() # Update existing IntegerNumberGeqZeroOption to IntegerNumberOption config.update_option('WEB_LOGIN_ATTEMPTS_MIN', configuration.IntegerNumberOption, "0", description="new desc") # -1 is allowed now that it is an int. self.assertEqual( None, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set("-1")) # but can't float this self.assertRaises(configuration.OptionValueError, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set, "2.4") # but fred is still an issue self.assertRaises(configuration.OptionValueError, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set, "fred") # Update existing IntegerNumberOption to FloatNumberOption config.update_option('WEB_LOGIN_ATTEMPTS_MIN', configuration.FloatNumberOption, "0.0") self.assertEqual(config['WEB_LOGIN_ATTEMPTS_MIN'], -1) # can float this self.assertEqual( None, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set("3.1415926")) # but fred is still an issue self.assertRaises(configuration.OptionValueError, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set, "fred") self.assertAlmostEqual(config['WEB_LOGIN_ATTEMPTS_MIN'], 3.1415926, places=6) # test removal of .0 on floats that are integers self.assertEqual( None, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set("3.0")) self.assertEqual( "3", config._get_option('WEB_LOGIN_ATTEMPTS_MIN')._value2str(3.00))
def testIsolationLevel(self): config = configuration.CoreConfig() self.assertEqual(None, config._get_option('RDBMS_ISOLATION_LEVEL').set("read uncommitted")) self.assertEqual(None, config._get_option('RDBMS_ISOLATION_LEVEL').set("read committed")) self.assertEqual(None, config._get_option('RDBMS_ISOLATION_LEVEL').set("repeatable read")) self.assertRaises(configuration.OptionValueError, config._get_option('RDBMS_ISOLATION_LEVEL').set, "not a level")
def testNullableSecret_with_value(self): self.munge_configini(mods=[ ("password = "******"test"), ]) config = configuration.CoreConfig() config.load(self.dirname) v = config['RDBMS_PASSWORD'] self.assertEqual(v, "test")
def testOptionAsString(self): config = configuration.CoreConfig() config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set("2552") v = config._get_option('WEB_LOGIN_ATTEMPTS_MIN').__str__() print(v) self.assertIn("55", v) v = config._get_option('WEB_LOGIN_ATTEMPTS_MIN').__repr__() print(v) self.assertIn("55", v)
def new_config(debug=False): config = configuration.CoreConfig() config.detectors = configuration.UserConfig( "share/roundup/templates/classic/detectors/config.ini") config.ext = configuration.UserConfig( "share/roundup/templates/classic/extensions/config.ini") config.DATABASE = "db" #config.logging = MockNull() # these TRACKER_WEB and MAIL_DOMAIN values are used in mailgw tests if debug: config.LOGGING_LEVEL = "DEBUG" config.MAIL_DOMAIN = "your.tracker.email.domain.example" config.TRACKER_WEB = "http://tracker.example/cgi-bin/roundup.cgi/bugs/" return config
def testOriginHeader(self): config = configuration.CoreConfig() with self.assertRaises(configuration.OptionValueError) as cm: config._get_option('WEB_ALLOWED_API_ORIGINS').set( "* https://foo.edu") config._get_option('WEB_ALLOWED_API_ORIGINS').set( "https://foo.edu HTTP://baR.edu") self.assertEqual(config['WEB_ALLOWED_API_ORIGINS'][0], 'https://foo.edu') self.assertEqual(config['WEB_ALLOWED_API_ORIGINS'][1], 'HTTP://baR.edu')
def open(self, tracker_home, optimize=0): """Open the tracker. Parameters: tracker_home: tracker home directory optimize: if set, precompile html templates Raise ValueError if the tracker home doesn't exist. """ import imp # sanity check existence of tracker home if not os.path.exists(tracker_home): raise ValueError('no such directory: "%s"' % tracker_home) # sanity check tracker home contents for reqd in 'config dbinit select_db interfaces'.split(): if not os.path.exists(os.path.join(tracker_home, '%s.py' % reqd)): raise TrackerError('File "%s.py" missing from tracker '\ 'home "%s"'%(reqd, tracker_home)) if tracker_home in self.trackers: return imp.load_package(self.trackers[tracker_home], tracker_home) # register all available backend modules backends.list_backends() self.number = self.number + 1 modname = '_roundup_tracker_%s' % self.number self.trackers[tracker_home] = modname # load the tracker tracker = imp.load_package(modname, tracker_home) # ensure the tracker has all the required bits for required in 'open init Client MailGW'.split(): if not hasattr(tracker, required): raise TrackerError('Required tracker attribute "%s" missing' % required) # load and apply the config tracker.config = configuration.CoreConfig(tracker_home) tracker.dbinit.config = tracker.config tracker.optimize = optimize tracker.templates = templating.get_loader(tracker.config["TEMPLATES"]) if optimize: tracker.templates.precompile() return tracker
def testSecretMandatory_missing_file(self): # SETUP: self.munge_configini(mods=[ ("secret_key = ", "file://secret_key"), ]) config = configuration.CoreConfig() with self.assertRaises(configuration.OptionValueError) as cm: config.load(self.dirname) print(cm.exception) self.assertEqual(cm.exception.args[0].setting, "secret_key")
def testLoadConfigNoConfig(self): """ run load on a directory missing config.ini """ c = os.path.join(self.dirname, configuration.Config.INI_FILE) if os.path.exists(c): os.remove(c) else: self.assertFalse("setup failed missing config.ini") config = configuration.CoreConfig() with self.assertRaises(configuration.NoConfigError) as cm: config.load(self.dirname) print(cm.exception) self.assertEqual(cm.exception.args[0], self.dirname)
def testSetMailPassword_with_set_username(self): """ Set [mail] username and set the password. Should have both values set. """ # SETUP: set mail username self.munge_configini(mods=[("username = "******"foo"), ("#password = "******"passwordfoo", "password = "******"[mail]") config = configuration.CoreConfig() config.load(self.dirname) self.assertEqual(config['MAIL_USERNAME'], 'foo') self.assertEqual(config['MAIL_PASSWORD'], 'passwordfoo')
def new_config(debug=False, prefix=default_prefix): if not prefix.startswith('/'): prefix = os.path.join(os.path.dirname(__file__), prefix) config = configuration.CoreConfig() config.detectors = configuration.UserConfig( os.path.join(prefix, "detectors/config.ini")) config.ext = configuration.UserConfig( os.path.join(prefix, "extensions/config.ini")) config.DATABASE = "db" #config.logging = MockNull() # these TRACKER_WEB and MAIL_DOMAIN values are used in mailgw tests if debug: config.LOGGING_LEVEL = "DEBUG" config.MAIL_DOMAIN = "your.tracker.email.domain.example" config.TRACKER_WEB = "http://tracker.example/cgi-bin/roundup.cgi/bugs/" return config
def testSecretMandatory_load_from_file(self): # SETUP: self.munge_configini(mods=[ ("secret_key = ", "file://secret_key"), ]) secret = "ASDQWEZXCRFVBGTYHNMJU" with open(self.dirname + "/secret_key", "w") as f: f.write(secret + "\n") config = configuration.CoreConfig() config.load(self.dirname) self.assertEqual(config['WEB_SECRET_KEY'], secret)
def testLoginAttemptsMin(self): config = configuration.CoreConfig() self.assertEqual(None, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set("0")) self.assertEqual(None, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set("200")) self.assertRaises(configuration.OptionValueError, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set, "fred") self.assertRaises(configuration.OptionValueError, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set, "-1") self.assertRaises(configuration.OptionValueError, config._get_option('WEB_LOGIN_ATTEMPTS_MIN').set, "")
def testNullableSecret_with_file_value(self): self.munge_configini(mods=[ ("password = "******"file://db_password"), ]) # file with no value just newline. with open(self.dirname + "/db_password", "w") as f: f.write("test\n") config = configuration.CoreConfig() config.load(self.dirname) v = config['RDBMS_PASSWORD'] self.assertEqual(v, "test")
def testInvalidIndexerLanguage_w_empty_no_xapian(self): """ Test case for empty indexer if xapian really isn't installed This should behave like testInvalidIndexerLanguage_xapian_missing but without all the sys.modules mangling. """ print("Testing when xapian is not installed") # SETUP: set indexer_language value to an invalid value. self.munge_configini(mods=[("indexer = ", ""), ("indexer_language = ", "NO_LANG")]) config = configuration.CoreConfig() config.load(self.dirname) self.assertEqual(config['INDEXER_LANGUAGE'], 'NO_LANG')
def testSecretMandatory_empty_file(self): self.munge_configini(mods=[ ("secret_key = ", "file:// secret_key"), ]) # file with no value just newline. with open(self.dirname + "/secret_key", "w") as f: f.write("\n") config = configuration.CoreConfig() with self.assertRaises(configuration.OptionValueError) as cm: config.load(self.dirname) print(cm.exception.args) self.assertEqual(cm.exception.args[2], "Value must not be empty.")
def testTrackerWeb(self): config = configuration.CoreConfig() self.assertEqual(None, config._get_option('TRACKER_WEB').set("http://foo.example/bar/")) self.assertEqual(None, config._get_option('TRACKER_WEB').set("https://foo.example/bar/")) self.assertRaises(configuration.OptionValueError, config._get_option('TRACKER_WEB').set, "https://foo.example/bar") self.assertRaises(configuration.OptionValueError, config._get_option('TRACKER_WEB').set, "htt://foo.example/bar/") self.assertRaises(configuration.OptionValueError, config._get_option('TRACKER_WEB').set, "htt://foo.example/bar") self.assertRaises(configuration.OptionValueError, config._get_option('TRACKER_WEB').set, "")
def testUnsetMailPassword_with_set_username(self): """ Set [mail] username but don't set the [mail] password. Should get an OptionValueError. """ # SETUP: set mail username self.munge_configini(mods=[ ("username = "******"foo"), ], section="[mail]") config = configuration.CoreConfig() with self.assertRaises(configuration.OptionValueError) as cm: config.load(self.dirname) print(cm.exception) # test repr. The type is right since it passed assertRaises. self.assertIn("OptionValueError", repr(cm.exception)) # look for 'not defined' self.assertEqual("not defined", cm.exception.args[1])
def __init__(self, tracker_home, optimize=0): """New-style tracker instance constructor Parameters: tracker_home: tracker home directory optimize: if set, precompile html templates """ self.tracker_home = tracker_home self.optimize = optimize # if set, call schema_hook after executing schema.py will get # same variables (in particular db) as schema.py main purpose is # for regression tests self.schema_hook = None self.config = configuration.CoreConfig(tracker_home) self.actions = {} self.cgi_actions = {} self.templating_utils = {} libdir = os.path.join(self.tracker_home, 'lib') self.libdir = os.path.isdir(libdir) and libdir or '' self.load_interfaces() self.templates = templating.get_loader(self.config["TEMPLATES"], self.config["TEMPLATE_ENGINE"]) rdbms_backend = self.config.RDBMS_BACKEND self.backend = backends.get_backend(rdbms_backend) if self.optimize: self.templates.precompile() # initialize tracker extensions for extension in self.get_extensions('extensions'): extension(self) # load database schema self.schema = self._compile('schema.py') # load database detectors self.detectors = self.get_extensions('detectors') # db_open is set to True after first open() self.db_open = 0
def testCopyConfig(self): self.munge_configini(mods=[("html_version = ", "xhtml")]) config = configuration.CoreConfig() # verify config is initalized to defaults self.assertEqual(config['HTML_VERSION'], 'html4') # load config config.load(self.dirname) # loaded new option self.assertEqual(config['HTML_VERSION'], 'xhtml') # copy config config_copy = config.copy() # this should work self.assertEqual(config_copy['HTML_VERSION'], 'xhtml')
def testSecretMandatory_load_from_abs_file(self): abs_file = "/tmp/secret_key.%s" % os.getpid() # SETUP: self.munge_configini(mods=[ ("secret_key = ", "file://%s" % abs_file), ]) secret = "ASDQWEZXCRFVBGTYHNMJU" with open(abs_file, "w") as f: f.write(secret + "\n") config = configuration.CoreConfig() config.load(self.dirname) self.assertEqual(config['WEB_SECRET_KEY'], secret) os.remove(abs_file)