Comment 9 for bug 1833685

Revision history for this message
Kenneth Loafman (kenneth-loafman) wrote : Re: [Bug 1833685] Re: [0.8] VerifyTest fails with AttributeError ('bytes' object has no attribute 'encode'")

One thing to watch out for in testing is the fact that the tests run
duplicity as a subprocess using the default python. That's why we use tox
for testing, a controlled environment. The command 'setup.py test' is
coming into disfavor, probably due to its reliance on a possibly wonky
environment. We're encountering that on the Launchpad build environment as
well. I'm thinking of making setup.py test run tox instead, but it just
seems like overkill.

On Tue, Jul 16, 2019 at 8:45 AM Sebastien Bacher <email address hidden> wrote:

> Ok, you are right, something is confusing those in the chroot/pbuilder
> environment, it works on a builder, sorry for the noise
>
> ** Changed in: duplicity
> Status: New => Fix Released
>
> --
> You received this bug notification because you are subscribed to
> Duplicity.
> https://bugs.launchpad.net/bugs/1833685
>
> Title:
> [0.8] VerifyTest fails with AttributeError ('bytes' object has no
> attribute 'encode'")
>
> Status in Duplicity:
> Fix Released
>
> Bug description:
> Using 0.8 r1377
>
> $ cd /tmp
> $ bzr branch lp:duplicity
> $ cd duplicity
> $ python3.7 setup.py build --force
> $ PYTHONPATH=/tmp/duplicity/build/lib.linux-i686-3.7/ python3.7
> ./setup.py test
> (that's on an i386 chroot, path to adapt for amd64)
>
> The tests have some errors, including that one
>
> ___________ VerifyTest.test_verify_compare_data_changed_source_file
> ____________
>
> self = <testing.functional.test_verify.VerifyTest
> testMethod=test_verify_compare_data_changed_source_file>
>
> def test_verify_compare_data_changed_source_file(self):
> u"""Test verify with --compare-data gives an error if a source
> file is changed"""
> > self.backup(u"full", u"testfiles/various_file_types", options=[])
>
> functional/test_verify.py:83:
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> _ _ _ _
> functional/__init__.py:182: in backup
> result = self.run_duplicity(options=options, **kwargs)
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> _ _ _ _
>
> self = <testing.functional.test_verify.VerifyTest
> testMethod=test_verify_compare_data_changed_source_file>
> options = ['full', 'testfiles/various_file_types',
> 'file://testfiles/output', '--volsize', '1']
> current_time = None, fail = None, passphrase_input = []
>
> def run_duplicity(self, options=[], current_time=None, fail=None,
> passphrase_input=[]):
> u"""
> Run duplicity binary with given arguments and options
> """
> # We run under setsid and take input from /dev/null (below)
> because
> # this way we force a failure if duplicity tries to read from the
> # console unexpectedly (like for gpg password or such).
>
> # Check all string inputs are unicode -- we will convert to
> system encoding before running the command
> for item in options:
> if sys.version_info.major == 2:
> assert not isinstance(item, str), u"item " +
> unicode(item) + u" in options is not unicode"
>
> for item in passphrase_input:
> assert isinstance(item, u"".__class__), u"item " +
> unicode(item) + u" in passphrase_input is not unicode"
>
> if platform.platform().startswith(u'Linux'):
> cmd_list = [u'setsid']
> if self._setsid_w:
> cmd_list.extend([u"-w"])
> else:
> cmd_list = []
> cmd_list.extend([u"../bin/duplicity"])
> cmd_list.extend(options)
> cmd_list.extend([u"-v0"])
> cmd_list.extend([u"--no-print-statistics"])
> cmd_list.extend([u"--allow-source-mismatch"])
> cmd_list.extend([u"--archive-dir=testfiles/cache"])
> if current_time:
> cmd_list.extend([u"--current-time", current_time])
> cmd_list.extend(self.class_args)
> if fail:
> cmd_list.extend([u"--fail", u"".__class__(fail)])
> cmdline = u" ".join([u'"%s"' % x for x in cmd_list])
>
> if not passphrase_input:
> cmdline += u" < /dev/null"
>
> # The immediately following block is the nicer way to execute
> pexpect with
> # unicode strings, but we need to have the pre-4.0 version for
> some time yet,
> # so for now this is commented out so tests execute the same way
> on all systems.
>
> # if parse_version(pexpect.__version__) >= parse_version("4.0"):
> # # pexpect.spawn only supports unicode from version 4.0
> # # there was a separate pexpect.spawnu in 3.x, but it has
> an error on readline
> # child = pexpect.spawn(u'/bin/sh', [u'-c', cmdline],
> timeout=None, encoding=sys.getfilesystemencoding())
> #
> # for passphrase in passphrase_input:
> # child.expect(u'passphrase.*:')
> # child.sendline(passphrase)
> # else:
>
> # Manually encode to filesystem encoding and send to spawn as
> bytes
> # ToDo: Remove this once we no longer have to support systems
> with pexpect < 4.0
> if sys.version_info.major > 2:
> child = pexpect.spawn(u'/bin/sh', [u'-c', cmdline],
> timeout=None)
> else:
> child = pexpect.spawn(b'/bin/sh', [b'-c',
> cmdline.encode(sys.getfilesystemencoding(),
>
> u'replace')],
> timeout=None)
>
> for passphrase in passphrase_input:
> child.expect(b'passphrase.*:')
> child.sendline(passphrase)
>
> # if the command fails, we need to clear its output
> # so it will terminate cleanly.
> child.expect_exact(pexpect.EOF)
> lines = child.before.splitlines()
> child.wait()
> child.ptyproc.delayafterclose = 0.0
> return_val = child.exitstatus
>
> if fail:
> self.assertEqual(30, return_val)
> elif return_val:
> print(u"\n...command:", cmdline, file=sys.stderr)
> print(u"...cwd:", os.getcwd(), file=sys.stderr)
> print(u"...output:", file=sys.stderr)
> for line in lines:
> line = line.rstrip()
> if line:
> print(line, file=sys.stderr)
> print(u"...return_val:", return_val, file=sys.stderr)
> > raise CmdError(return_val)
> E testing.functional.CmdError: 30
>
> functional/__init__.py:165: CmdError
> ----------------------------- Captured stderr call
> -----------------------------
>
> ...command: "setsid" "-w" "../bin/duplicity" "full"
> "testfiles/various_file_types" "file://testfiles/output" "--volsize" "1"
> "-v0" "--no-print-statistics" "--allow-source-mismatch"
> "--archive-dir=testfiles/cache" < /dev/null
> ...cwd: /build/duplicity/testing
> ...output:
> b'Traceback (innermost last):'
> b' File "../bin/duplicity", line 1706, in <module>'
> b' with_tempdir(main)'
> b' File "../bin/duplicity", line 1692, in with_tempdir'
> b' fn()'
> b' File "../bin/duplicity", line 1538, in main'
> b' do_backup(action)'
> b' File "../bin/duplicity", line 1662, in do_backup'
> b' full_backup(col_stats)'
> b' File "../bin/duplicity", line 568, in full_backup'
> b' globals.backend)'
> b' File "../bin/duplicity", line 425, in write_multivol'
> b' globals.volsize)'
> b' File "/build/duplicity/duplicity/gpg.py", line 393, in GPGWriteFile'
> b' data = block_iter.__next__().data'
> b' File "/build/duplicity/duplicity/diffdir.py", line 543, in __next__'
> b' result = self.process(next(self.input_iter)) # pylint:
> disable=assignment-from-no-return'
> b' File "/build/duplicity/duplicity/diffdir.py", line 235, in
> get_delta_iter'
> b' (new_path, sig_path, sigTarFile))'
> b' File "/build/duplicity/duplicity/robust.py", line 41, in
> check_common_error'
> b' return function(*args)'
> b' File "/build/duplicity/duplicity/diffdir.py", line 160, in
> get_delta_path'
> b' sigTarFile.addfile(ti)'
> b' File "/usr/lib/python3.7/tarfile.py", line 1966, in addfile'
> b' buf = tarinfo.tobuf(self.format, self.encoding, self.errors)'
> b' File "/usr/lib/python3.7/tarfile.py", line 816, in tobuf'
> b' return self.create_gnu_header(info, encoding, errors)'
> b' File "/usr/lib/python3.7/tarfile.py", line 847, in create_gnu_header'
> b' return buf + self._create_header(info, GNU_FORMAT, encoding,
> errors)'
> b' File "/usr/lib/python3.7/tarfile.py", line 937, in _create_header'
> b' stn(info.get("gname", ""), 32, encoding, errors),'
> b' File "/usr/lib/python3.7/tarfile.py", line 161, in stn'
> b' s = s.encode(encoding, errors)'
> b" AttributeError: 'bytes' object has no attribute 'encode'"
> ...return_val: 30
>
> To manage notifications about this bug go to:
> https://bugs.launchpad.net/duplicity/+bug/1833685/+subscriptions
>