Hello community,
here is the log from the commit of package python-azure-agent for
openSUSE:Factory checked in at 2017-10-20 14:47:30
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-azure-agent (Old)
and /work/SRC/openSUSE:Factory/.python-azure-agent.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-azure-agent"
Fri Oct 20 14:47:30 2017 rev:5 rq:535329 version:2.2.18
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-azure-agent/python-azure-agent.changes
2017-10-05 11:59:13.856836982 +0200
+++
/work/SRC/openSUSE:Factory/.python-azure-agent.new/python-azure-agent.changes
2017-10-20 14:47:37.375326718 +0200
@@ -1,0 +2,9 @@
+Thu Oct 12 20:13:42 UTC 2017 - [email protected]
+
+- Update to version 2.2.18
+ + [#868] Fix for sudoer update
+ + [#886] Agent should not update outside of goal state
+ + [#889] Firewall removal should not retry
+ - Fixes issues introduces with 2.2.17
+
+-------------------------------------------------------------------
Old:
----
WALinuxAgent-2.2.17.tar.gz
New:
----
WALinuxAgent-2.2.18.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-azure-agent.spec ++++++
--- /var/tmp/diff_new_pack.YV13X4/_old 2017-10-20 14:47:38.095293050 +0200
+++ /var/tmp/diff_new_pack.YV13X4/_new 2017-10-20 14:47:38.099292863 +0200
@@ -20,7 +20,7 @@
Summary: Microsoft Azure Linux Agent
License: Apache-2.0
Group: System/Daemons
-Version: 2.2.17
+Version: 2.2.18
Release: 0
Url: https://github.com/Azure/WALinuxAgent
Source0: WALinuxAgent-%{version}.tar.gz
++++++ WALinuxAgent-2.2.17.tar.gz -> WALinuxAgent-2.2.18.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/WALinuxAgent-2.2.17/azurelinuxagent/common/future.py
new/WALinuxAgent-2.2.18/azurelinuxagent/common/future.py
--- old/WALinuxAgent-2.2.17/azurelinuxagent/common/future.py 2017-09-14
01:51:29.000000000 +0200
+++ new/WALinuxAgent-2.2.18/azurelinuxagent/common/future.py 2017-09-20
00:48:11.000000000 +0200
@@ -1,10 +1,10 @@
import sys
"""
-Add alies for python2 and python3 libs and fucntions.
+Add alias for python2 and python3 libs and functions.
"""
-if sys.version_info[0]== 3:
+if sys.version_info[0] == 3:
import http.client as httpclient
from urllib.parse import urlparse
@@ -23,5 +23,4 @@
bytebuffer = buffer
else:
- raise ImportError("Unknown python version:{0}".format(sys.version_info))
-
+ raise ImportError("Unknown python version: {0}".format(sys.version_info))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/WALinuxAgent-2.2.17/azurelinuxagent/common/osutil/default.py
new/WALinuxAgent-2.2.18/azurelinuxagent/common/osutil/default.py
--- old/WALinuxAgent-2.2.17/azurelinuxagent/common/osutil/default.py
2017-09-14 01:51:29.000000000 +0200
+++ new/WALinuxAgent-2.2.18/azurelinuxagent/common/osutil/default.py
2017-09-20 00:48:11.000000000 +0200
@@ -96,7 +96,7 @@
return wait
def remove_firewall(self):
- # If a previous attempt threw an exception, do not retry
+ # If a previous attempt failed, do not retry
global _enable_firewall
if not _enable_firewall:
return False
@@ -105,8 +105,8 @@
wait = self.get_firewall_will_wait()
flush_rule = FIREWALL_FLUSH.format(wait)
- if shellutil.run(flush_rule, chk_err=False) != 0:
- logger.warn("Failed to flush firewall")
+ if shellutil.run(flush_rule, chk_err=True) != 0:
+ raise Exception("non-zero return code")
return True
@@ -309,11 +309,11 @@
else:
sudoer = "{0} ALL=(ALL) ALL".format(username)
if not os.path.isfile(sudoers_wagent) or \
- fileutil.findstr_in_file(sudoers_wagent, sudoer) is None:
+ fileutil.findstr_in_file(sudoers_wagent, sudoer) is False:
fileutil.append_file(sudoers_wagent, "{0}\n".format(sudoer))
fileutil.chmod(sudoers_wagent, 0o440)
else:
- #Remove user from sudoers
+ # remove user from sudoers
if os.path.isfile(sudoers_wagent):
try:
content = fileutil.read_file(sudoers_wagent)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/WALinuxAgent-2.2.17/azurelinuxagent/common/protocol/wire.py
new/WALinuxAgent-2.2.18/azurelinuxagent/common/protocol/wire.py
--- old/WALinuxAgent-2.2.17/azurelinuxagent/common/protocol/wire.py
2017-09-14 01:51:29.000000000 +0200
+++ new/WALinuxAgent-2.2.18/azurelinuxagent/common/protocol/wire.py
2017-09-20 00:48:11.000000000 +0200
@@ -51,6 +51,7 @@
PEM_FILE_NAME = "Certificates.pem"
EXT_CONF_FILE_NAME = "ExtensionsConfig.{0}.xml"
MANIFEST_FILE_NAME = "{0}.{1}.manifest.xml"
+AGENTS_MANIFEST_FILE_NAME = "{0}.{1}.agentsManifest"
TRANSPORT_CERT_FILE_NAME = "TransportCert.pem"
TRANSPORT_PRV_FILE_NAME = "TransportPrivate.pem"
@@ -128,8 +129,9 @@
def get_vmagent_pkgs(self, vmagent_manifest):
goal_state = self.client.get_goal_state()
- man = self.client.get_gafamily_manifest(vmagent_manifest, goal_state)
- return man.pkg_list
+ ga_manifest = self.client.get_gafamily_manifest(vmagent_manifest,
goal_state)
+ valid_pkg_list =
self.client.filter_package_list(vmagent_manifest.family, ga_manifest,
goal_state)
+ return valid_pkg_list
def get_ext_handlers(self):
logger.verbose("Get extension handler config")
@@ -813,6 +815,41 @@
raise ProtocolError("Failed to retrieve extension manifest")
+ def filter_package_list(self, family, ga_manifest, goal_state):
+ complete_list = ga_manifest.pkg_list
+ agent_manifest = os.path.join(conf.get_lib_dir(),
+ AGENTS_MANIFEST_FILE_NAME.format(
+ family,
+ goal_state.incarnation))
+
+ if not os.path.exists(agent_manifest):
+ # clear memory cache
+ ga_manifest.allowed_versions = None
+
+ # create disk cache
+ with open(agent_manifest, mode='w') as manifest_fh:
+ for version in complete_list.versions:
+ manifest_fh.write('{0}\n'.format(version.version))
+ fileutil.chmod(agent_manifest, 0o644)
+
+ return complete_list
+
+ else:
+ # use allowed versions from cache, otherwise from disk
+ if ga_manifest.allowed_versions is None:
+ with open(agent_manifest, mode='r') as manifest_fh:
+ ga_manifest.allowed_versions = [v.strip('\n') for v
+ in manifest_fh.readlines()]
+
+ # use the updated manifest urls for allowed versions
+ allowed_list = ExtHandlerPackageList()
+ allowed_list.versions = [version for version
+ in complete_list.versions
+ if version.version
+ in ga_manifest.allowed_versions]
+
+ return allowed_list
+
def get_gafamily_manifest(self, vmagent_manifest, goal_state):
for update_goal_state in [False, True]:
try:
@@ -1418,6 +1455,7 @@
raise ValueError("ExtensionManifest is None")
logger.verbose("Load ExtensionManifest.xml")
self.pkg_list = ExtHandlerPackageList()
+ self.allowed_versions = None
self.parse(xml_text)
def parse(self, xml_text):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/WALinuxAgent-2.2.17/azurelinuxagent/common/utils/fileutil.py
new/WALinuxAgent-2.2.18/azurelinuxagent/common/utils/fileutil.py
--- old/WALinuxAgent-2.2.17/azurelinuxagent/common/utils/fileutil.py
2017-09-14 01:51:29.000000000 +0200
+++ new/WALinuxAgent-2.2.18/azurelinuxagent/common/utils/fileutil.py
2017-09-20 00:48:11.000000000 +0200
@@ -45,6 +45,7 @@
errno.EREMOTEIO # Remote I/O error
]
+
def copy_file(from_path, to_path=None, to_dir=None):
if to_path is None:
to_path = os.path.join(to_dir, os.path.basename(from_path))
@@ -66,11 +67,12 @@
return data
if remove_bom:
- #Remove bom on bytes data before it is converted into string.
+ # remove bom on bytes data before it is converted into string.
data = textutil.remove_bom(data)
data = ustr(data, encoding=encoding)
return data
+
def write_file(filepath, contents, asbin=False, encoding='utf-8',
append=False):
"""
Write 'contents' to 'filepath'.
@@ -82,6 +84,7 @@
with open(filepath, mode) as out_file:
out_file.write(data)
+
def append_file(filepath, contents, asbin=False, encoding='utf-8'):
"""
Append 'contents' to 'filepath'.
@@ -93,6 +96,7 @@
head, tail = os.path.split(path)
return tail
+
def get_line_startingwith(prefix, filepath):
"""
Return line from 'filepath' if the line startswith 'prefix'
@@ -102,7 +106,6 @@
return line
return None
-#End File operation util functions
def mkdir(dirpath, mode=None, owner=None):
if not os.path.isdir(dirpath):
@@ -112,6 +115,7 @@
if owner is not None:
chowner(dirpath, owner)
+
def chowner(path, owner):
if not os.path.exists(path):
logger.error("Path does not exist: {0}".format(path))
@@ -119,19 +123,22 @@
owner_info = pwd.getpwnam(owner)
os.chown(path, owner_info[2], owner_info[3])
+
def chmod(path, mode):
if not os.path.exists(path):
logger.error("Path does not exist: {0}".format(path))
else:
os.chmod(path, mode)
+
def rm_files(*args):
for paths in args:
- #Find all possible file paths
+ # find all possible file paths
for path in glob.glob(paths):
if os.path.isfile(path):
os.remove(path)
+
def rm_dirs(*args):
"""
Remove the contents of each directry
@@ -149,20 +156,24 @@
elif os.path.isdir(path):
shutil.rmtree(path)
+
def trim_ext(path, ext):
if not ext.startswith("."):
ext = "." + ext
return path.split(ext)[0] if path.endswith(ext) else path
+
def update_conf_file(path, line_start, val, chk_err=False):
conf = []
if not os.path.isfile(path) and chk_err:
raise IOError("Can't find config file:{0}".format(path))
conf = read_file(path).split('\n')
- conf = [x for x in conf if x is not None and len(x) > 0 and not
x.startswith(line_start)]
+ conf = [x for x in conf
+ if x is not None and len(x) > 0 and not x.startswith(line_start)]
conf.append(val)
write_file(path, '\n'.join(conf) + '\n')
+
def search_file(target_dir_name, target_file_name):
for root, dirs, files in os.walk(target_dir_name):
for file_name in files:
@@ -170,24 +181,28 @@
return os.path.join(root, file_name)
return None
+
def chmod_tree(path, mode):
for root, dirs, files in os.walk(path):
for file_name in files:
os.chmod(os.path.join(root, file_name), mode)
+
def findstr_in_file(file_path, line_str):
"""
Return True if the line is in the file; False otherwise.
- (Trailing whitespace is ignore.)
+ (Trailing whitespace is ignored.)
"""
try:
for line in (open(file_path, 'r')).readlines():
if line_str == line.rstrip():
return True
- except Exception as e:
+ except Exception:
+ # swallow exception
pass
return False
+
def findre_in_file(file_path, line_re):
"""
Return match object if found in file.
@@ -203,6 +218,7 @@
return None
+
def get_all_files(root_path):
"""
Find all files under the given root path
@@ -213,6 +229,7 @@
return result
+
def clean_ioerror(e, paths=[]):
"""
Clean-up possibly bad files and directories after an IO error.
@@ -228,5 +245,6 @@
shutil.rmtree(path, ignore_errors=True)
else:
os.remove(path)
- except Exception as e:
+ except Exception:
+ # swallow exception
pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/WALinuxAgent-2.2.17/azurelinuxagent/common/version.py
new/WALinuxAgent-2.2.18/azurelinuxagent/common/version.py
--- old/WALinuxAgent-2.2.17/azurelinuxagent/common/version.py 2017-09-14
01:51:29.000000000 +0200
+++ new/WALinuxAgent-2.2.18/azurelinuxagent/common/version.py 2017-09-20
00:48:11.000000000 +0200
@@ -113,7 +113,7 @@
AGENT_NAME = "WALinuxAgent"
AGENT_LONG_NAME = "Azure Linux Agent"
-AGENT_VERSION = '2.2.17'
+AGENT_VERSION = '2.2.18'
AGENT_LONG_VERSION = "{0}-{1}".format(AGENT_NAME, AGENT_VERSION)
AGENT_DESCRIPTION = """
The Azure Linux Agent supports the provisioning and running of Linux
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/WALinuxAgent-2.2.17/tests/common/osutil/test_default.py
new/WALinuxAgent-2.2.18/tests/common/osutil/test_default.py
--- old/WALinuxAgent-2.2.17/tests/common/osutil/test_default.py 2017-09-14
01:51:29.000000000 +0200
+++ new/WALinuxAgent-2.2.18/tests/common/osutil/test_default.py 2017-09-20
00:48:11.000000000 +0200
@@ -629,12 +629,44 @@
self.assertTrue(util.remove_firewall())
mock_run.assert_has_calls([
- call(osutil.FIREWALL_FLUSH.format(wait), chk_err=False)
+ call(osutil.FIREWALL_FLUSH.format(wait), chk_err=True)
])
mock_output.assert_has_calls([
call(osutil.IPTABLES_VERSION)
])
self.assertTrue(osutil._enable_firewall)
+ @patch('os.getuid', return_value=42)
+ @patch('azurelinuxagent.common.utils.shellutil.run_get_output')
+ @patch('azurelinuxagent.common.utils.shellutil.run')
+ def test_remove_firewall_does_not_repeat(self, mock_run, mock_output, _):
+ osutil._enable_firewall = True
+ util = osutil.DefaultOSUtil()
+
+ version = "iptables v{0}".format(osutil.IPTABLES_LOCKING_VERSION)
+ wait = "-w"
+
+ mock_run.side_effect = [1, 0]
+ mock_output.side_effect = [(0, version), (1, "Output")]
+ self.assertFalse(util.remove_firewall())
+
+ mock_run.assert_has_calls([
+ call(osutil.FIREWALL_FLUSH.format(wait), chk_err=True)
+ ])
+ mock_output.assert_has_calls([
+ call(osutil.IPTABLES_VERSION)
+ ])
+ self.assertFalse(osutil._enable_firewall)
+
+ self.assertTrue(mock_run.call_count == 1)
+ self.assertTrue(mock_output.call_count == 1)
+
+ self.assertFalse(util.remove_firewall())
+ self.assertFalse(util.remove_firewall())
+
+ self.assertTrue(mock_run.call_count == 1)
+ self.assertTrue(mock_output.call_count == 1)
+
+
if __name__ == '__main__':
unittest.main()
Binary files old/WALinuxAgent-2.2.17/tests/data/ga/WALinuxAgent-2.2.14.zip and
new/WALinuxAgent-2.2.18/tests/data/ga/WALinuxAgent-2.2.14.zip differ
Binary files old/WALinuxAgent-2.2.17/tests/data/ga/WALinuxAgent-2.2.18.zip and
new/WALinuxAgent-2.2.18/tests/data/ga/WALinuxAgent-2.2.18.zip differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/WALinuxAgent-2.2.17/tests/data/wire/ga_manifest_1.xml
new/WALinuxAgent-2.2.18/tests/data/wire/ga_manifest_1.xml
--- old/WALinuxAgent-2.2.17/tests/data/wire/ga_manifest_1.xml 1970-01-01
01:00:00.000000000 +0100
+++ new/WALinuxAgent-2.2.18/tests/data/wire/ga_manifest_1.xml 2017-09-20
00:48:11.000000000 +0200
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PluginVersionManifest xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
+ <Plugins/>
+ <InternalPlugins>
+ <Plugin>
+ <Version>2.2.13</Version>
+ <Uris>
+ <Uri>url1_13</Uri>
+ </Uris>
+ </Plugin>
+ <Plugin>
+ <Version>2.2.14</Version>
+ <Uris>
+ <Uri>url1_14</Uri>
+ </Uris>
+ </Plugin>
+ </InternalPlugins>
+</PluginVersionManifest>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/WALinuxAgent-2.2.17/tests/data/wire/ga_manifest_2.xml
new/WALinuxAgent-2.2.18/tests/data/wire/ga_manifest_2.xml
--- old/WALinuxAgent-2.2.17/tests/data/wire/ga_manifest_2.xml 1970-01-01
01:00:00.000000000 +0100
+++ new/WALinuxAgent-2.2.18/tests/data/wire/ga_manifest_2.xml 2017-09-20
00:48:11.000000000 +0200
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PluginVersionManifest xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
+ <Plugins/>
+ <InternalPlugins>
+ <Plugin>
+ <Version>2.2.13</Version>
+ <Uris>
+ <Uri>url2_13</Uri>
+ </Uris>
+ </Plugin>
+ <Plugin>
+ <Version>2.2.14</Version>
+ <Uris>
+ <Uri>url2_14</Uri>
+ </Uris>
+ </Plugin>
+ <Plugin>
+ <Version>2.2.15</Version>
+ <Uris>
+ <Uri>url1_15</Uri>
+ </Uris>
+ </Plugin>
+ </InternalPlugins>
+</PluginVersionManifest>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/WALinuxAgent-2.2.17/tests/ga/test_update.py
new/WALinuxAgent-2.2.18/tests/ga/test_update.py
--- old/WALinuxAgent-2.2.17/tests/ga/test_update.py 2017-09-14
01:51:29.000000000 +0200
+++ new/WALinuxAgent-2.2.18/tests/ga/test_update.py 2017-09-20
00:48:11.000000000 +0200
@@ -1548,6 +1548,64 @@
self.assertEqual(None, pid_file)
return
+ @patch('azurelinuxagent.common.protocol.wire.WireClient.get_goal_state',
+ return_value=GoalState(load_data('wire/goal_state.xml')))
+ def test_package_filter_for_agent_manifest(self, _):
+
+ protocol = WireProtocol('12.34.56.78')
+ extension_config = ExtensionsConfig(load_data('wire/ext_conf.xml'))
+ agent_manifest = extension_config.vmagent_manifests.vmAgentManifests[0]
+
+ # has agent versions 13, 14
+ ga_manifest_1 = ExtensionManifest(load_data('wire/ga_manifest_1.xml'))
+
+ # has agent versions 13, 14, 15
+ ga_manifest_2 = ExtensionManifest(load_data('wire/ga_manifest_2.xml'))
+
+ goal_state = protocol.client.get_goal_state()
+ disk_cache = os.path.join(conf.get_lib_dir(),
+ AGENTS_MANIFEST_FILE_NAME.format(
+ agent_manifest.family,
+ goal_state.incarnation))
+
+ self.assertFalse(os.path.exists(disk_cache))
+ self.assertTrue(ga_manifest_1.allowed_versions is None)
+
+ with patch(
+ 'azurelinuxagent.common.protocol.wire.WireClient'
+ '.get_gafamily_manifest',
+ return_value=ga_manifest_1):
+
+ pkg_list_1 = protocol.get_vmagent_pkgs(agent_manifest)
+ self.assertTrue(pkg_list_1 is not None)
+ self.assertTrue(len(pkg_list_1.versions) == 2)
+ self.assertTrue(pkg_list_1.versions[0].version == '2.2.13')
+ self.assertTrue(pkg_list_1.versions[0].uris[0].uri == 'url1_13')
+ self.assertTrue(pkg_list_1.versions[1].version == '2.2.14')
+ self.assertTrue(pkg_list_1.versions[1].uris[0].uri == 'url1_14')
+
+ self.assertTrue(os.path.exists(disk_cache))
+
+ with patch(
+ 'azurelinuxagent.common.protocol.wire.WireClient'
+ '.get_gafamily_manifest',
+ return_value=ga_manifest_2):
+
+ pkg_list_2 = protocol.get_vmagent_pkgs(agent_manifest)
+ self.assertTrue(pkg_list_2 is not None)
+ self.assertTrue(len(pkg_list_2.versions) == 2)
+ self.assertTrue(pkg_list_2.versions[0].version == '2.2.13')
+ self.assertTrue(pkg_list_2.versions[0].uris[0].uri == 'url2_13')
+ self.assertTrue(pkg_list_2.versions[1].version == '2.2.14')
+ self.assertTrue(pkg_list_2.versions[1].uris[0].uri == 'url2_14')
+ # does not contain 2.2.15
+
+ self.assertTrue(os.path.exists(disk_cache))
+ self.assertTrue(ga_manifest_2.allowed_versions is not None)
+ self.assertTrue(len(ga_manifest_2.allowed_versions) == 2)
+ self.assertTrue(ga_manifest_2.allowed_versions[0] == '2.2.13')
+ self.assertTrue(ga_manifest_2.allowed_versions[1] == '2.2.14')
+
class ChildMock(Mock):
def __init__(self, return_value=0, side_effect=None):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/WALinuxAgent-2.2.17/tests/test_agent.py
new/WALinuxAgent-2.2.18/tests/test_agent.py
--- old/WALinuxAgent-2.2.17/tests/test_agent.py 2017-09-14 01:51:29.000000000
+0200
+++ new/WALinuxAgent-2.2.18/tests/test_agent.py 2017-09-20 00:48:11.000000000
+0200
@@ -65,8 +65,7 @@
ResourceDisk.Format = True
ResourceDisk.MountOptions = None
ResourceDisk.MountPoint = /mnt/resource
-ResourceDisk.SwapSizeMB = 0
-""".split('\n')
+ResourceDisk.SwapSizeMB = 0""".split('\n')
class TestAgent(AgentTestCase):
@@ -160,10 +159,11 @@
self.assertFalse(os.path.isdir(ext_log_dir))
mock_log.assert_called_once()
- def test_agent_show_configuration(self):
- if not hasattr(sys.stdout, 'getvalue'):
- self.fail('Test requires at least Python 2.7 with buffered output')
- agent = Agent(False,
- conf_file_path=os.path.join(data_dir, "test_waagent.conf"))
- agent.show_configuration()
- self.assertEqual(EXPECTED_CONFIGURATION,
sys.stdout.getvalue().split('\n'))
+ def test_agent_get_configuration(self):
+ Agent(False, conf_file_path=os.path.join(data_dir,
"test_waagent.conf"))
+
+ actual_configuration = []
+ configuration = conf.get_configuration()
+ for k in sorted(configuration.keys()):
+ actual_configuration.append("{0} = {1}".format(k,
configuration[k]))
+ self.assertEqual(EXPECTED_CONFIGURATION, actual_configuration)