Hello again, as promised, I uploaded the fix with the attached debdiff.
Martin
diff -Nru sosreport-4.0/debian/changelog sosreport-4.0/debian/changelog --- sosreport-4.0/debian/changelog 2021-01-27 15:29:24.000000000 +0100 +++ sosreport-4.0/debian/changelog 2024-01-10 08:16:54.000000000 +0100 @@ -1,3 +1,12 @@ +sosreport (4.0-2.1) unstable; urgency=medium + + * Non-maintainer upload. + * d/p/0004-unittest-assertEquals.patch: unittest.TestCase.assertEquals() was + deprecated in Python 3, and finally dropped in Python 3.12. Fixes FTBFS + due to unit tests failing. (Closes: #1058214) + + -- Martin Pitt <mp...@debian.org> Wed, 10 Jan 2024 08:16:54 +0100 + sosreport (4.0-2) unstable; urgency=medium * d/p/0003-systemd-prefer-resolvectl-over-systemd-resolve.patch: diff -Nru sosreport-4.0/debian/patches/0004-unittest-assertEquals.patch sosreport-4.0/debian/patches/0004-unittest-assertEquals.patch --- sosreport-4.0/debian/patches/0004-unittest-assertEquals.patch 1970-01-01 01:00:00.000000000 +0100 +++ sosreport-4.0/debian/patches/0004-unittest-assertEquals.patch 2024-01-10 08:16:40.000000000 +0100 @@ -0,0 +1,545 @@ +Description: [tests] Drop obsolete TestCase.assertEquals() +Author: Martin Pitt <mp...@debian.org> +Bug: https://github.com/sosreport/sos/pull/3467 +Bug-Debian: https://bugs.debian.org/1058214 + +Index: sosreport-4.0/tests/archive_tests.py +=================================================================== +--- sosreport-4.0.orig/tests/archive_tests.py ++++ sosreport-4.0/tests/archive_tests.py +@@ -92,7 +92,7 @@ class TarFileArchiveTest(unittest.TestCa + self.tf.add_string('this is my content', 'tests/string_test.txt') + + afp = self.tf.open_file('tests/string_test.txt') +- self.assertEquals('this is my content', afp.read()) ++ self.assertEqual('this is my content', afp.read()) + + def test_rewrite_file(self): + """Test that re-writing a file with add_string() modifies the content. +@@ -101,7 +101,7 @@ class TarFileArchiveTest(unittest.TestCa + self.tf.add_string('this is my new content', 'tests/string_test.txt') + + afp = self.tf.open_file('tests/string_test.txt') +- self.assertEquals('this is my new content', afp.read()) ++ self.assertEqual('this is my new content', afp.read()) + + def test_make_link(self): + self.tf.add_file('tests/ziptest') +Index: sosreport-4.0/tests/cleaner_tests.py +=================================================================== +--- sosreport-4.0.orig/tests/cleaner_tests.py ++++ sosreport-4.0/tests/cleaner_tests.py +@@ -41,12 +41,12 @@ class CleanerMapTests(unittest.TestCase) + + def test_mac_map_skip_ignores(self): + _test = self.mac_map.get('ff:ff:ff:ff:ff:ff') +- self.assertEquals(_test, 'ff:ff:ff:ff:ff:ff') ++ self.assertEqual(_test, 'ff:ff:ff:ff:ff:ff') + + def test_mac_map_avoid_duplicate_obfuscation(self): + _test = self.mac_map.get('ab:cd:ef:fe:dc:ba') + _dup = self.mac_map.get(_test) +- self.assertEquals(_test, _dup) ++ self.assertEqual(_test, _dup) + + def test_ip_map_obfuscate_v4_with_cidr(self): + _test = self.ip_map.get('192.168.1.0/24') +@@ -68,7 +68,7 @@ class CleanerMapTests(unittest.TestCase) + + def test_ip_skip_ignores(self): + _test = self.ip_map.get('127.0.0.1') +- self.assertEquals(_test, '127.0.0.1') ++ self.assertEqual(_test, '127.0.0.1') + + def test_hostname_obfuscate_domain_options(self): + _test = self.host_map.get('www.redhat.com') +Index: sosreport-4.0/tests/option_tests.py +=================================================================== +--- sosreport-4.0.orig/tests/option_tests.py ++++ sosreport-4.0/tests/option_tests.py +@@ -34,10 +34,10 @@ class GlobalOptionTest(unittest.TestCase + ] + + def test_simple_lookup(self): +- self.assertEquals(self.plugin.get_option('test_option'), 'foobar') ++ self.assertEqual(self.plugin.get_option('test_option'), 'foobar') + + def test_cascade(self): +- self.assertEquals(self.plugin.get_option(('baz')), False) ++ self.assertEqual(self.plugin.get_option(('baz')), False) + + + if __name__ == "__main__": +Index: sosreport-4.0/tests/plugin_tests.py +=================================================================== +--- sosreport-4.0.orig/tests/plugin_tests.py ++++ sosreport-4.0/tests/plugin_tests.py +@@ -123,36 +123,36 @@ class PluginToolTests(unittest.TestCase) + ['this is only a test', 'there are only two lines']) + test_fo = StringIO(test_s) + matches = regex_findall(r".*lines$", test_fo) +- self.assertEquals(matches, ['there are only two lines']) ++ self.assertEqual(matches, ['there are only two lines']) + + def test_regex_findall_miss(self): + test_s = u"\n".join( + ['this is only a test', 'there are only two lines']) + test_fo = StringIO(test_s) + matches = regex_findall(r".*not_there$", test_fo) +- self.assertEquals(matches, []) ++ self.assertEqual(matches, []) + + def test_regex_findall_bad_input(self): + matches = regex_findall(r".*", None) +- self.assertEquals(matches, []) ++ self.assertEqual(matches, []) + matches = regex_findall(r".*", []) +- self.assertEquals(matches, []) ++ self.assertEqual(matches, []) + matches = regex_findall(r".*", 1) +- self.assertEquals(matches, []) ++ self.assertEqual(matches, []) + + def test_mangle_command(self): + name_max = 255 +- self.assertEquals("foo", _mangle_command("/usr/bin/foo", name_max)) +- self.assertEquals( ++ self.assertEqual("foo", _mangle_command("/usr/bin/foo", name_max)) ++ self.assertEqual( + "foo_-x", _mangle_command("/usr/bin/foo -x", name_max)) +- self.assertEquals( ++ self.assertEqual( + "foo_--verbose", _mangle_command("/usr/bin/foo --verbose", + name_max)) +- self.assertEquals("foo_.path.to.stuff", _mangle_command( ++ self.assertEqual("foo_.path.to.stuff", _mangle_command( + "/usr/bin/foo /path/to/stuff", name_max)) + longcmd = "foo is " + "a" * 256 + " long_command" + expected = longcmd[0:name_max].replace(' ', '_') +- self.assertEquals(expected, _mangle_command(longcmd, name_max)) ++ self.assertEqual(expected, _mangle_command(longcmd, name_max)) + + + class PluginTests(unittest.TestCase): +@@ -175,7 +175,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.name(), "mockplugin") ++ self.assertEqual(p.name(), "mockplugin") + + def test_plugin_set_name(self): + p = NamedMockPlugin({ +@@ -184,7 +184,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.name(), "testing") ++ self.assertEqual(p.name(), "testing") + + def test_plugin_no_descrip(self): + p = MockPlugin({ +@@ -193,7 +193,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.get_description(), "<no description available>") ++ self.assertEqual(p.get_description(), "<no description available>") + + def test_plugin_has_descrip(self): + p = NamedMockPlugin({ +@@ -202,7 +202,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.get_description(), ++ self.assertEqual(p.get_description(), + "This plugin has a description.") + + def test_set_plugin_option(self): +@@ -213,7 +213,7 @@ class PluginTests(unittest.TestCase): + 'devices': {} + }) + p.set_option("opt", "testing") +- self.assertEquals(p.get_option("opt"), "testing") ++ self.assertEqual(p.get_option("opt"), "testing") + + def test_set_nonexistant_plugin_option(self): + p = MockPlugin({ +@@ -231,7 +231,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.get_option("badopt"), 0) ++ self.assertEqual(p.get_option("badopt"), 0) + + def test_get_unset_plugin_option(self): + p = MockPlugin({ +@@ -240,7 +240,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.get_option("opt"), 0) ++ self.assertEqual(p.get_option("opt"), 0) + + def test_get_unset_plugin_option_with_default(self): + # this shows that even when we pass in a default to get, +@@ -252,7 +252,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.get_option("opt", True), True) ++ self.assertEqual(p.get_option("opt", True), True) + + def test_get_unset_plugin_option_with_default_not_none(self): + # this shows that even when we pass in a default to get, +@@ -265,7 +265,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.get_option("opt2", True), False) ++ self.assertEqual(p.get_option("opt2", True), False) + + def test_get_option_as_list_plugin_option(self): + p = MockPlugin({ +@@ -275,7 +275,7 @@ class PluginTests(unittest.TestCase): + 'devices': {} + }) + p.set_option("opt", "one,two,three") +- self.assertEquals(p.get_option_as_list("opt"), ['one', 'two', 'three']) ++ self.assertEqual(p.get_option_as_list("opt"), ['one', 'two', 'three']) + + def test_get_option_as_list_plugin_option_default(self): + p = MockPlugin({ +@@ -284,7 +284,7 @@ class PluginTests(unittest.TestCase): + 'cmdlineopts': MockOptions(), + 'devices': {} + }) +- self.assertEquals(p.get_option_as_list("opt", default=[]), []) ++ self.assertEqual(p.get_option_as_list("opt", default=[]), []) + + def test_get_option_as_list_plugin_option_not_list(self): + p = MockPlugin({ +@@ -294,17 +294,17 @@ class PluginTests(unittest.TestCase): + 'devices': {} + }) + p.set_option("opt", "testing") +- self.assertEquals(p.get_option_as_list("opt"), ['testing']) ++ self.assertEqual(p.get_option_as_list("opt"), ['testing']) + + def test_copy_dir(self): + self.mp._do_copy_path("tests") +- self.assertEquals( ++ self.assertEqual( + self.mp.archive.m["tests/plugin_tests.py"], + 'tests/plugin_tests.py') + + def test_copy_dir_bad_path(self): + self.mp._do_copy_path("not_here_tests") +- self.assertEquals(self.mp.archive.m, {}) ++ self.assertEqual(self.mp.archive.m, {}) + + def test_copy_dir_forbidden_path(self): + p = ForbiddenMockPlugin({ +@@ -316,7 +316,7 @@ class PluginTests(unittest.TestCase): + p.archive = MockArchive() + p.setup() + p.collect() +- self.assertEquals(p.archive.m, {}) ++ self.assertEqual(p.archive.m, {}) + + def test_postproc_default_on(self): + p = PostprocMockPlugin({ +@@ -348,7 +348,7 @@ class AddCopySpecTests(unittest.TestCase + path = path[1:] + return os.path.join(self.mp.sysroot, path) + expected_paths = set(map(pathmunge, self.expect_paths)) +- self.assertEquals(self.mp.copy_paths, expected_paths) ++ self.assertEqual(self.mp.copy_paths, expected_paths) + + def test_single_file_no_limit(self): + self.mp.add_copy_spec("tests/tail_test.txt") +@@ -366,7 +366,7 @@ class AddCopySpecTests(unittest.TestCase + self.assertTrue("tailed" in fname) + self.assertTrue("tmp" in fname) + self.assertTrue("/" not in fname) +- self.assertEquals(1024 * 1024, len(content)) ++ self.assertEqual(1024 * 1024, len(content)) + os.unlink(fn) + + def test_bad_filename(self): +@@ -384,7 +384,7 @@ class AddCopySpecTests(unittest.TestCase + create_file(2, dir=tmpdir) + create_file(2, dir=tmpdir) + self.mp.add_copy_spec(tmpdir + "/*") +- self.assertEquals(len(self.mp.copy_paths), 2) ++ self.assertEqual(len(self.mp.copy_paths), 2) + shutil.rmtree(tmpdir) + + def test_glob_file_over_limit(self): +@@ -393,19 +393,19 @@ class AddCopySpecTests(unittest.TestCase + create_file(2, dir=tmpdir) + create_file(2, dir=tmpdir) + self.mp.add_copy_spec(tmpdir + "/*", 1) +- self.assertEquals(len(self.mp.copy_strings), 1) ++ self.assertEqual(len(self.mp.copy_strings), 1) + content, fname = self.mp.copy_strings[0] + self.assertTrue("tailed" in fname) +- self.assertEquals(1024 * 1024, len(content)) ++ self.assertEqual(1024 * 1024, len(content)) + shutil.rmtree(tmpdir) + + def test_multiple_files_no_limit(self): + self.mp.add_copy_spec(['tests/tail_test.txt', 'tests/test.txt']) +- self.assertEquals(len(self.mp.copy_paths), 2) ++ self.assertEqual(len(self.mp.copy_paths), 2) + + def test_multiple_files_under_limit(self): + self.mp.add_copy_spec(['tests/tail_test.txt', 'tests/test.txt'], 1) +- self.assertEquals(len(self.mp.copy_paths), 2) ++ self.assertEqual(len(self.mp.copy_paths), 2) + + + class CheckEnabledTests(unittest.TestCase): +@@ -449,7 +449,7 @@ class RegexSubTests(unittest.TestCase): + self.mp.archive = MockArchive() + + def test_file_never_copied(self): +- self.assertEquals(0, self.mp.do_file_sub( ++ self.assertEqual(0, self.mp.do_file_sub( + "never_copied", r"^(.*)$", "foobar")) + + def test_no_replacements(self): +@@ -457,7 +457,7 @@ class RegexSubTests(unittest.TestCase): + self.mp.collect() + replacements = self.mp.do_file_sub( + j("tail_test.txt"), r"wont_match", "foobar") +- self.assertEquals(0, replacements) ++ self.assertEqual(0, replacements) + + def test_replacements(self): + # test uses absolute paths +@@ -466,7 +466,7 @@ class RegexSubTests(unittest.TestCase): + self.mp.collect() + replacements = self.mp.do_file_sub( + j("tail_test.txt"), r"(tail)", "foobar") +- self.assertEquals(1, replacements) ++ self.assertEqual(1, replacements) + self.assertTrue("foobar" in self.mp.archive.m.get(j('tail_test.txt'))) + + +Index: sosreport-4.0/tests/policy_tests.py +=================================================================== +--- sosreport-4.0.orig/tests/policy_tests.py ++++ sosreport-4.0/tests/policy_tests.py +@@ -67,17 +67,17 @@ class PackageManagerTests(unittest.TestC + self.pm = PackageManager() + + def test_default_all_pkgs(self): +- self.assertEquals(self.pm.all_pkgs(), {}) ++ self.assertEqual(self.pm.all_pkgs(), {}) + + def test_default_all_pkgs_by_name(self): +- self.assertEquals(self.pm.all_pkgs_by_name('doesntmatter'), []) ++ self.assertEqual(self.pm.all_pkgs_by_name('doesntmatter'), []) + + def test_default_all_pkgs_by_name_regex(self): +- self.assertEquals( ++ self.assertEqual( + self.pm.all_pkgs_by_name_regex('.*doesntmatter$'), []) + + def test_default_pkg_by_name(self): +- self.assertEquals(self.pm.pkg_by_name('foo'), None) ++ self.assertEqual(self.pm.pkg_by_name('foo'), None) + + + if __name__ == "__main__": +Index: sosreport-4.0/tests/report_tests.py +=================================================================== +--- sosreport-4.0.orig/tests/report_tests.py ++++ sosreport-4.0/tests/report_tests.py +@@ -23,7 +23,7 @@ class ReportTest(unittest.TestCase): + + expected = json.dumps({}) + +- self.assertEquals(expected, str(report)) ++ self.assertEqual(expected, str(report)) + + def test_nested_section(self): + report = Report() +@@ -32,7 +32,7 @@ class ReportTest(unittest.TestCase): + + expected = json.dumps({"section": {}}) + +- self.assertEquals(expected, str(report)) ++ self.assertEqual(expected, str(report)) + + def test_multiple_sections(self): + report = Report() +@@ -45,7 +45,7 @@ class ReportTest(unittest.TestCase): + expected = json.dumps({"section": {}, + "section2": {}, }) + +- self.assertEquals(expected, str(report)) ++ self.assertEqual(expected, str(report)) + + def test_deeply_nested(self): + report = Report() +@@ -61,7 +61,7 @@ class ReportTest(unittest.TestCase): + "return_code": 0, + "href": "does/not/matter"}]}}) + +- self.assertEquals(expected, str(report)) ++ self.assertEqual(expected, str(report)) + + + class TestPlainReport(unittest.TestCase): +@@ -78,13 +78,13 @@ class TestPlainReport(unittest.TestCase) + ]) + + def test_basic(self): +- self.assertEquals(self.pluglist.format(pluglist=""), ++ self.assertEqual(self.pluglist.format(pluglist=""), + PlainTextReport(self.report).unicode()) + + def test_one_section(self): + self.report.add(self.section) + +- self.assertEquals(self.defaultheader, ++ self.assertEqual(self.defaultheader, + PlainTextReport(self.report).unicode() + '\n') + + def test_two_sections(self): +@@ -92,7 +92,7 @@ class TestPlainReport(unittest.TestCase) + section2 = Section(name="second") + self.report.add(section1, section2) + +- self.assertEquals(u''.join([ ++ self.assertEqual(u''.join([ + self.pluglist.format(pluglist=" first second"), + self.div, + "\nfirst", +@@ -108,7 +108,7 @@ class TestPlainReport(unittest.TestCase) + self.section.add(cmd) + self.report.add(self.section) + +- self.assertEquals(u''.join([ ++ self.assertEqual(u''.join([ + self.defaultheader, + "- commands executed:\n * ls -al /foo/bar/baz" + ]), +@@ -119,7 +119,7 @@ class TestPlainReport(unittest.TestCase) + self.section.add(cf) + self.report.add(self.section) + +- self.assertEquals(u''.join([ ++ self.assertEqual(u''.join([ + self.defaultheader, + "- files copied:\n * /etc/hosts" + ]), +@@ -131,7 +131,7 @@ class TestPlainReport(unittest.TestCase) + self.section.add(crf) + self.report.add(self.section) + +- self.assertEquals(u''.join([ ++ self.assertEqual(u''.join([ + self.defaultheader, + "- files created:\n * sample.txt" + ]), +@@ -142,7 +142,7 @@ class TestPlainReport(unittest.TestCase) + self.section.add(alrt) + self.report.add(self.section) + +- self.assertEquals(u''.join([ ++ self.assertEqual(u''.join([ + self.defaultheader, + "- alerts:\n ! this is an alert" + ]), +Index: sosreport-4.0/tests/sosreport_pexpect.py +=================================================================== +--- sosreport-4.0.orig/tests/sosreport_pexpect.py ++++ sosreport-4.0/tests/sosreport_pexpect.py +@@ -26,7 +26,7 @@ class PexpectTest(unittest.TestCase): + def test_batchmode_removes_questions(self): + sos = pexpect.spawn('/usr/sbin/sosreport --batch') + grp = sos.expect('send this file to your support representative.', 15) +- self.assertEquals(grp, 0) ++ self.assertEqual(grp, 0) + kill(sos.pid, SIGINT) + + +Index: sosreport-4.0/tests/utilities_tests.py +=================================================================== +--- sosreport-4.0.orig/tests/utilities_tests.py ++++ sosreport-4.0/tests/utilities_tests.py +@@ -24,32 +24,32 @@ class GrepTest(unittest.TestCase): + ['this is only a test', 'there are only two lines']) + test_fo = StringIO(test_s) + matches = grep(".*test$", test_fo) +- self.assertEquals(matches, ['this is only a test\n']) ++ self.assertEqual(matches, ['this is only a test\n']) + + def test_real_file(self): + matches = grep(".*unittest$", __file__.replace(".pyc", ".py")) +- self.assertEquals(matches, ['import unittest\n']) ++ self.assertEqual(matches, ['import unittest\n']) + + def test_open_file(self): + matches = grep(".*unittest$", open(__file__.replace(".pyc", ".py"))) +- self.assertEquals(matches, ['import unittest\n']) ++ self.assertEqual(matches, ['import unittest\n']) + + def test_grep_multiple_files(self): + matches = grep(".*unittest$", + __file__.replace(".pyc", ".py"), "does_not_exist.txt") +- self.assertEquals(matches, ['import unittest\n']) ++ self.assertEqual(matches, ['import unittest\n']) + + + class TailTest(unittest.TestCase): + + def test_tail(self): + t = tail("tests/tail_test.txt", 10) +- self.assertEquals(t, b"last line\n") ++ self.assertEqual(t, b"last line\n") + + def test_tail_too_many(self): + t = tail("tests/tail_test.txt", 200) + expected = open("tests/tail_test.txt", "r").read() +- self.assertEquals(t, str.encode(expected)) ++ self.assertEqual(t, str.encode(expected)) + + + class ExecutableTest(unittest.TestCase): +@@ -66,24 +66,24 @@ class ExecutableTest(unittest.TestCase): + + def test_output(self): + result = sos_get_command_output("echo executed") +- self.assertEquals(result['status'], 0) +- self.assertEquals(result['output'], "executed\n") ++ self.assertEqual(result['status'], 0) ++ self.assertEqual(result['output'], "executed\n") + + def test_output_non_exe(self): + path = os.path.join(TEST_DIR, 'utility_tests.py') + result = sos_get_command_output(path) +- self.assertEquals(result['status'], 127) +- self.assertEquals(result['output'], b"") ++ self.assertEqual(result['status'], 127) ++ self.assertEqual(result['output'], b"") + + def test_output_chdir(self): + cmd = "/bin/bash -c 'echo $PWD'" + result = sos_get_command_output(cmd, chdir=TEST_DIR) + print(result) +- self.assertEquals(result['status'], 0) +- self.assertEquals(result['output'].strip(), TEST_DIR) ++ self.assertEqual(result['status'], 0) ++ self.assertEqual(result['output'].strip(), TEST_DIR) + + def test_shell_out(self): +- self.assertEquals("executed\n", shell_out('echo executed')) ++ self.assertEqual("executed\n", shell_out('echo executed')) + + + class FindTest(unittest.TestCase): diff -Nru sosreport-4.0/debian/patches/series sosreport-4.0/debian/patches/series --- sosreport-4.0/debian/patches/series 2021-01-27 15:26:38.000000000 +0100 +++ sosreport-4.0/debian/patches/series 2024-01-10 08:13:39.000000000 +0100 @@ -1,3 +1,4 @@ 0001-debian-change-tmp-dir-location.patch 0002-fix-dict-order-py38-incompatibility.patch 0003-systemd-prefer-resolvectl-over-systemd-resolve.patch +0004-unittest-assertEquals.patch