123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- # -*- coding: utf-8 -*-
- '''
- tests.unit.utils.test_configparser
- ==================================
- Test the funcs in the custom parsers in salt.utils.configparser
- '''
- # Import Python Libs
- from __future__ import absolute_import, print_function, unicode_literals
- import copy
- import errno
- import logging
- import os
- log = logging.getLogger(__name__)
- # Import Salt Testing Libs
- from tests.support.runtests import RUNTIME_VARS
- from tests.support.unit import TestCase
- # Import salt libs
- import salt.utils.files
- import salt.utils.stringutils
- import salt.utils.configparser
- import salt.utils.platform
- from salt.ext import six
- # The user.name param here is intentionally indented with spaces instead of a
- # tab to test that we properly load a file with mixed indentation.
- ORIG_CONFIG = '''[user]
- name = Артём Анисимов
- \temail = foo@bar.com
- [remote "origin"]
- \turl = https://github.com/terminalmage/salt.git
- \tfetch = +refs/heads/*:refs/remotes/origin/*
- \tpushurl = git@github.com:terminalmage/salt.git
- [color "diff"]
- \told = 196
- \tnew = 39
- [core]
- \tpager = less -R
- \trepositoryformatversion = 0
- \tfilemode = true
- \tbare = false
- \tlogallrefupdates = true
- [alias]
- \tmodified = ! git status --porcelain | awk 'match($1, "M"){print $2}'
- \tgraph = log --all --decorate --oneline --graph
- \thist = log --pretty=format:\\"%h %ad | %s%d [%an]\\" --graph --date=short
- [http]
- \tsslverify = false'''.split('\n')
- class TestGitConfigParser(TestCase):
- '''
- Tests for salt.utils.configparser.GitConfigParser
- '''
- maxDiff = None
- orig_config = os.path.join(RUNTIME_VARS.TMP, 'test_gitconfig.orig')
- new_config = os.path.join(RUNTIME_VARS.TMP, 'test_gitconfig.new')
- remote = 'remote "origin"'
- def tearDown(self):
- del self.conf
- try:
- os.remove(self.new_config)
- except OSError as exc:
- if exc.errno != errno.ENOENT:
- raise
- def setUp(self):
- if not os.path.exists(self.orig_config):
- with salt.utils.files.fopen(self.orig_config, 'wb') as fp_:
- fp_.write(
- salt.utils.stringutils.to_bytes(
- os.linesep.join(ORIG_CONFIG)
- )
- )
- self.conf = salt.utils.configparser.GitConfigParser()
- with salt.utils.files.fopen(self.orig_config, 'rb') as fp:
- self.conf._read(fp, self.orig_config)
- @classmethod
- def tearDownClass(cls):
- try:
- os.remove(cls.orig_config)
- except OSError as exc:
- if exc.errno != errno.ENOENT:
- raise
- @staticmethod
- def fix_indent(lines):
- '''
- Fixes the space-indented 'user' line, because when we write the config
- object to a file space indentation will be replaced by tab indentation.
- '''
- ret = copy.copy(lines)
- for i, _ in enumerate(ret):
- if ret[i].startswith(salt.utils.configparser.GitConfigParser.SPACEINDENT):
- ret[i] = ret[i].replace(salt.utils.configparser.GitConfigParser.SPACEINDENT, '\t')
- return ret
- @staticmethod
- def get_lines(path):
- with salt.utils.files.fopen(path, 'rb') as fp_:
- return salt.utils.stringutils.to_unicode(fp_.read()).splitlines()
- def _test_write(self, mode):
- kwargs = {'mode': mode}
- if six.PY3 and salt.utils.platform.is_windows() and 'b' not in mode:
- kwargs['encoding'] = 'utf-8'
- with salt.utils.files.fopen(self.new_config, **kwargs) as fp_:
- self.conf.write(fp_)
- self.assertEqual(
- self.get_lines(self.new_config),
- self.fix_indent(ORIG_CONFIG)
- )
- def test_get(self):
- '''
- Test getting an option's value
- '''
- # Numeric values should be loaded as strings
- self.assertEqual(self.conf.get('color "diff"', 'old'), '196')
- # Complex strings should be loaded with their literal quotes and
- # slashes intact
- self.assertEqual(
- self.conf.get('alias', 'modified'),
- """! git status --porcelain | awk 'match($1, "M"){print $2}'"""
- )
- # future lint: disable=non-unicode-string
- self.assertEqual(
- self.conf.get('alias', 'hist'),
- salt.utils.stringutils.to_unicode(
- r"""log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short"""
- )
- )
- # future lint: enable=non-unicode-string
- def test_read_space_indent(self):
- '''
- Test that user.name was successfully loaded despite being indented
- using spaces instead of a tab. Additionally, this tests that the value
- was loaded as a unicode type on PY2.
- '''
- self.assertEqual(self.conf.get('user', 'name'), u'Артём Анисимов')
- def test_set_new_option(self):
- '''
- Test setting a new option in an existing section
- '''
- self.conf.set('http', 'useragent', 'myawesomeagent')
- self.assertEqual(self.conf.get('http', 'useragent'), 'myawesomeagent')
- def test_add_section(self):
- '''
- Test adding a section and adding an item to that section
- '''
- self.conf.add_section('foo')
- self.conf.set('foo', 'bar', 'baz')
- self.assertEqual(self.conf.get('foo', 'bar'), 'baz')
- def test_replace_option(self):
- '''
- Test replacing an existing option
- '''
- # We're also testing the normalization of key names, here. Setting
- # "sslVerify" should actually set an "sslverify" option.
- self.conf.set('http', 'sslVerify', 'true')
- self.assertEqual(self.conf.get('http', 'sslverify'), 'true')
- def test_set_multivar(self):
- '''
- Test setting a multivar and then writing the resulting file
- '''
- orig_refspec = '+refs/heads/*:refs/remotes/origin/*'
- new_refspec = '+refs/tags/*:refs/tags/*'
- # Make sure that the original value is a string
- self.assertEqual(
- self.conf.get(self.remote, 'fetch'),
- orig_refspec
- )
- # Add another refspec
- self.conf.set_multivar(self.remote, 'fetch', new_refspec)
- # The value should now be a list
- self.assertEqual(
- self.conf.get(self.remote, 'fetch'),
- [orig_refspec, new_refspec]
- )
- # Write the config object to a file
- with salt.utils.files.fopen(self.new_config, 'wb') as fp_:
- self.conf.write(fp_)
- # Confirm that the new file was written correctly
- expected = self.fix_indent(ORIG_CONFIG)
- expected.insert(6, '\tfetch = %s' % new_refspec) # pylint: disable=string-substitution-usage-error
- self.assertEqual(self.get_lines(self.new_config), expected)
- def test_remove_option(self):
- '''
- test removing an option, including all items from a multivar
- '''
- for item in ('fetch', 'pushurl'):
- self.conf.remove_option(self.remote, item)
- # To confirm that the option is now gone, a get should raise an
- # NoOptionError exception.
- self.assertRaises(
- salt.utils.configparser.NoOptionError,
- self.conf.get,
- self.remote,
- item)
- def test_remove_option_regexp(self):
- '''
- test removing an option, including all items from a multivar
- '''
- orig_refspec = '+refs/heads/*:refs/remotes/origin/*'
- new_refspec_1 = '+refs/tags/*:refs/tags/*'
- new_refspec_2 = '+refs/foo/*:refs/foo/*'
- # First, add both refspecs
- self.conf.set_multivar(self.remote, 'fetch', new_refspec_1)
- self.conf.set_multivar(self.remote, 'fetch', new_refspec_2)
- # Make sure that all three values are there
- self.assertEqual(
- self.conf.get(self.remote, 'fetch'),
- [orig_refspec, new_refspec_1, new_refspec_2]
- )
- # If the regex doesn't match, no items should be removed
- self.assertFalse(
- self.conf.remove_option_regexp(
- self.remote,
- 'fetch',
- salt.utils.stringutils.to_unicode(r'\d{7,10}') # future lint: disable=non-unicode-string
- )
- )
- # Make sure that all three values are still there (since none should
- # have been removed)
- self.assertEqual(
- self.conf.get(self.remote, 'fetch'),
- [orig_refspec, new_refspec_1, new_refspec_2]
- )
- # Remove one of the values
- self.assertTrue(
- self.conf.remove_option_regexp(self.remote, 'fetch', 'tags'))
- # Confirm that the value is gone
- self.assertEqual(
- self.conf.get(self.remote, 'fetch'),
- [orig_refspec, new_refspec_2]
- )
- # Remove the other one we added earlier
- self.assertTrue(
- self.conf.remove_option_regexp(self.remote, 'fetch', 'foo'))
- # Since the option now only has one value, it should be a string
- self.assertEqual(self.conf.get(self.remote, 'fetch'), orig_refspec)
- # Remove the last remaining option
- self.assertTrue(
- self.conf.remove_option_regexp(self.remote, 'fetch', 'heads'))
- # Trying to do a get now should raise an exception
- self.assertRaises(
- salt.utils.configparser.NoOptionError,
- self.conf.get,
- self.remote,
- 'fetch')
- def test_write(self):
- '''
- Test writing using non-binary filehandle
- '''
- self._test_write(mode='w')
- def test_write_binary(self):
- '''
- Test writing using binary filehandle
- '''
- self._test_write(mode='wb')
|