Merge lp:~ack/landscape-client/package-description-decode-fix into lp:~landscape/landscape-client/trunk

Proposed by Alberto Donato
Status: Merged
Approved by: Alberto Donato
Approved revision: 929
Merged at revision: 928
Proposed branch: lp:~ack/landscape-client/package-description-decode-fix
Merge into: lp:~landscape/landscape-client/trunk
Diff against target: 238 lines (+46/-29)
4 files modified
landscape/package/skeleton.py (+4/-2)
landscape/package/tests/helpers.py (+12/-6)
landscape/package/tests/test_skeleton.py (+29/-20)
landscape/tests/helpers.py (+1/-1)
To merge this branch: bzr merge lp:~ack/landscape-client/package-description-decode-fix
Reviewer Review Type Date Requested Status
Simon Poirier (community) Approve
🤖 Landscape Builder test results Approve
Free Ekanayaka (community) Approve
Review via email: mp+314444@code.launchpad.net

Commit message

Avoid double-decoding package descriptions in build_skeleton_apt, which causes an error with Xenial python-apt.

Description of the change

Avoid double-decoding package descriptions in build_skeleton_apt, which causes an error with Xenial python-apt.

Note that python-apt replaces non-ascii chars in the description with "?".
This happens because no locale is set, but we can't arbitrarily set one in the client and we don't want to report localized versions of package descriptions.

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 927
Branch: lp:~ack/landscape-client/package-description-decode-fix
Jenkins: https://ci.lscape.net/job/latch-test-precise/845/

review: Approve (test results)
Revision history for this message
Free Ekanayaka (free.ekanayaka) wrote :

Nice, +1

review: Approve
928. By Alberto Donato

Add comment.

Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 928
Branch: lp:~ack/landscape-client/package-description-decode-fix
Jenkins: https://ci.lscape.net/job/latch-test-precise/846/

review: Approve (test results)
Revision history for this message
Simon Poirier (simpoir) wrote :

The change looks good, but your test doesn't seem to be calling build_skeleton(). And quick coverage run tells me your code is not exercised through test.

review: Needs Fixing
929. By Alberto Donato

Fix test (Simon's review)

Revision history for this message
Alberto Donato (ack) wrote :

> The change looks good, but your test doesn't seem to be calling
> build_skeleton(). And quick coverage run tells me your code is not exercised
> through test.

Good catch, I think something got messed up while I was experimenting with the test.
It's fixed now. I also dropped the self.build_skeleton() helper in the test class, since it's a usless indirection.
Thanks!

Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Fail
Revno: 929
Branch: lp:~ack/landscape-client/package-description-decode-fix
Jenkins: https://ci.lscape.net/job/latch-test-precise/848/

review: Needs Fixing (test results)
Revision history for this message
🤖 Landscape Builder (landscape-builder) :
review: Abstain (executing tests)
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: TRIAL_ARGS=-j4 make check
Result: Success
Revno: 929
Branch: lp:~ack/landscape-client/package-description-decode-fix
Jenkins: https://ci.lscape.net/job/latch-test-precise/849/

review: Approve (test results)
Revision history for this message
Simon Poirier (simpoir) wrote :

+1 thanks

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'landscape/package/skeleton.py'
2--- landscape/package/skeleton.py 2013-05-31 12:27:27 +0000
3+++ landscape/package/skeleton.py 2017-01-12 08:01:46 +0000
4@@ -67,7 +67,6 @@
5 self._hash = package_hash
6
7
8-
9 def relation_to_string(relation_tuple):
10 """Convert an apt relation to a string representation.
11
12@@ -150,5 +149,8 @@
13 if with_unicode:
14 skeleton.section = skeleton.section.decode("utf-8")
15 skeleton.summary = skeleton.summary.decode("utf-8")
16- skeleton.description = skeleton.description.decode("utf-8")
17+ # Avoid double-decoding package descriptions in build_skeleton_apt,
18+ # which causes an error with newer python-apt (Xenial onwards)
19+ if not isinstance(skeleton.description, unicode):
20+ skeleton.description = skeleton.description.decode("utf-8")
21 return skeleton
22
23=== modified file 'landscape/package/tests/helpers.py'
24--- landscape/package/tests/helpers.py 2016-07-06 11:06:09 +0000
25+++ landscape/package/tests/helpers.py 2017-01-12 08:01:46 +0000
26@@ -30,7 +30,8 @@
27 test_case._hash_packages_by_name = self._hash_packages_by_name
28
29 def _add_package(self, packages_file, name, architecture="all",
30- version="1.0", control_fields=None):
31+ version="1.0", description="description",
32+ control_fields=None):
33 if control_fields is None:
34 control_fields = {}
35 package_stanza = textwrap.dedent("""
36@@ -42,9 +43,12 @@
37 Architecture: %(architecture)s
38 Source: source
39 Version: %(version)s
40- Description: description
41- """ % {"name": name, "version": version,
42- "architecture": architecture})
43+ Description: short description
44+ %(description)s
45+ """ % {
46+ "name": name, "version": version,
47+ "architecture": architecture,
48+ "description": description.encode("utf-8")})
49 package_stanza = apt_pkg.rewrite_section(
50 apt_pkg.TagSection(package_stanza), apt_pkg.REWRITE_PACKAGE_ORDER,
51 control_fields.items())
52@@ -72,7 +76,8 @@
53 append_file(self.dpkg_status, status + "\n\n")
54
55 def _add_package_to_deb_dir(self, path, name, architecture="all",
56- version="1.0", control_fields=None):
57+ version="1.0", description="description",
58+ control_fields=None):
59 """Add fake package information to a directory.
60
61 There will only be basic information about the package
62@@ -83,7 +88,8 @@
63 control_fields = {}
64 self._add_package(
65 os.path.join(path, "Packages"), name, architecture=architecture,
66- version=version, control_fields=control_fields)
67+ version=version, description=description,
68+ control_fields=control_fields)
69
70 def _touch_packages_file(self, deb_dir):
71 """Make sure the Packages file gets a newer mtime value.
72
73=== modified file 'landscape/package/tests/test_skeleton.py'
74--- landscape/package/tests/test_skeleton.py 2013-05-31 07:57:06 +0000
75+++ landscape/package/tests/test_skeleton.py 2017-01-12 08:01:46 +0000
76@@ -59,18 +59,14 @@
77 package = self.facade._cache[name]
78 return package.candidate
79
80- def build_skeleton(self, *args, **kwargs):
81- """Build the skeleton to be tested."""
82- return build_skeleton_apt(*args, **kwargs)
83-
84 def test_build_skeleton(self):
85 """
86- C{build_skeleton} builds a C{PackageSkeleton} from a package. If
87+ build_skeleton_apt builds a C{PackageSkeleton} from a package. If
88 with_info isn't passed, C{section}, C{summary}, C{description},
89 C{size} and C{installed_size} will be C{None}.
90 """
91 pkg1 = self.get_package("name1")
92- skeleton = self.build_skeleton(pkg1)
93+ skeleton = build_skeleton_apt(pkg1)
94 self.assertEqual("name1", skeleton.name)
95 self.assertEqual("version1-release1", skeleton.version)
96 self.assertEqual(None, skeleton.section)
97@@ -90,35 +86,35 @@
98
99 def test_build_skeleton_without_unicode(self):
100 """
101- If C{with_unicode} isn't passed to C{build_skeleton}, the name
102+ If C{with_unicode} isn't passed to build_skeleton_apt, the name
103 and version of the skeleton are byte strings. The hash doesn't
104 change, though.
105 """
106 pkg1 = self.get_package("name1")
107- skeleton = self.build_skeleton(pkg1)
108+ skeleton = build_skeleton_apt(pkg1)
109 self.assertTrue(isinstance(skeleton.name, str))
110 self.assertTrue(isinstance(skeleton.version, str))
111 self.assertEqual(HASH1, skeleton.get_hash())
112
113 def test_build_skeleton_with_unicode(self):
114 """
115- If C{with_unicode} is passed to C{build_skeleton}, the name
116+ If C{with_unicode} is passed to build_skeleton_apt, the name
117 and version of the skeleton are unicode strings.
118 """
119 pkg1 = self.get_package("name1")
120- skeleton = self.build_skeleton(pkg1, with_unicode=True)
121+ skeleton = build_skeleton_apt(pkg1, with_unicode=True)
122 self.assertTrue(isinstance(skeleton.name, unicode))
123 self.assertTrue(isinstance(skeleton.version, unicode))
124 self.assertEqual(HASH1, skeleton.get_hash())
125
126 def test_build_skeleton_with_info(self):
127 """
128- If C{with_info} is passed to C{build_skeleton}, C{section},
129+ If C{with_info} is passed to build_skeleton_apt, C{section},
130 C{summary}, C{description} and the size fields will be extracted
131 from the package.
132 """
133 pkg1 = self.get_package("name1")
134- skeleton = self.build_skeleton(pkg1, with_info=True)
135+ skeleton = build_skeleton_apt(pkg1, with_info=True)
136 self.assertEqual("Group1", skeleton.section)
137 self.assertEqual("Summary1", skeleton.summary)
138 self.assertEqual("Description1", skeleton.description)
139@@ -128,11 +124,11 @@
140 def test_build_skeleton_with_unicode_and_extra_info(self):
141 """
142 If C{with_unicode} and C{with_info} are passed to
143- C{build_skeleton}, the name, version and the extra info of the
144+ build_skeleton_apt, the name, version and the extra info of the
145 skeleton are unicode strings.
146 """
147 pkg1 = self.get_package("name1")
148- skeleton = self.build_skeleton(pkg1, with_unicode=True, with_info=True)
149+ skeleton = build_skeleton_apt(pkg1, with_unicode=True, with_info=True)
150 self.assertTrue(isinstance(skeleton.name, unicode))
151 self.assertTrue(isinstance(skeleton.version, unicode))
152 self.assertTrue(isinstance(skeleton.section, unicode))
153@@ -140,13 +136,26 @@
154 self.assertTrue(isinstance(skeleton.description, unicode))
155 self.assertEqual(HASH1, skeleton.get_hash())
156
157+ def test_build_skeleton_with_unicode_and_non_ascii(self):
158+ """
159+ If with_unicode and with_info are passed to build_skeleton_apt,
160+ the description is decoded and non-ascii chars replaced.
161+ """
162+ self._add_package_to_deb_dir(
163+ self.skeleton_repository_dir, "pkg", description=u"T\xe9st")
164+ self.facade._cache.update(None)
165+ self.facade._cache.open(None)
166+ pkg = self.get_package("pkg")
167+ skeleton = build_skeleton_apt(pkg, with_unicode=True, with_info=True)
168+ self.assertEqual(u"T?st", skeleton.description)
169+
170 def test_build_skeleton_minimal(self):
171 """
172 A package that has only the required fields will still have some
173 relations defined.
174 """
175 minimal_package = self.get_package("minimal")
176- skeleton = self.build_skeleton(minimal_package)
177+ skeleton = build_skeleton_apt(minimal_package)
178 self.assertEqual("minimal", skeleton.name)
179 self.assertEqual("1.0", skeleton.version)
180 self.assertEqual(None, skeleton.section)
181@@ -166,7 +175,7 @@
182 be either an empty string or None, depending on which field.
183 """
184 package = self.get_package("minimal")
185- skeleton = self.build_skeleton(package, True)
186+ skeleton = build_skeleton_apt(package, True)
187 self.assertEqual("", skeleton.section)
188 self.assertEqual(
189 "A minimal package with no dependencies or other relations.",
190@@ -181,7 +190,7 @@
191 simple, i.e. not specifying a version.
192 """
193 package = self.get_package("simple-relations")
194- skeleton = self.build_skeleton(package)
195+ skeleton = build_skeleton_apt(package)
196 self.assertEqual("simple-relations", skeleton.name)
197 self.assertEqual("1.0", skeleton.version)
198 relations = [
199@@ -201,7 +210,7 @@
200 version dependent.
201 """
202 package = self.get_package("version-relations")
203- skeleton = self.build_skeleton(package)
204+ skeleton = build_skeleton_apt(package)
205 self.assertEqual("version-relations", skeleton.name)
206 self.assertEqual("1.0", skeleton.version)
207 relations = [
208@@ -222,7 +231,7 @@
209 skeleton.
210 """
211 package = self.get_package("multiple-relations")
212- skeleton = self.build_skeleton(package)
213+ skeleton = build_skeleton_apt(package)
214 self.assertEqual("multiple-relations", skeleton.name)
215 self.assertEqual("1.0", skeleton.version)
216 relations = [
217@@ -248,7 +257,7 @@
218 is considered to be a single relation, with a special type.
219 """
220 package = self.get_package("or-relations")
221- skeleton = self.build_skeleton(package)
222+ skeleton = build_skeleton_apt(package)
223 self.assertEqual("or-relations", skeleton.name)
224 self.assertEqual("1.0", skeleton.version)
225 relations = [
226
227=== modified file 'landscape/tests/helpers.py'
228--- landscape/tests/helpers.py 2016-08-17 20:31:48 +0000
229+++ landscape/tests/helpers.py 2017-01-12 08:01:46 +0000
230@@ -94,7 +94,7 @@
231 "%s" % (diff, extra))
232
233
234-class LandscapeTest(MessageTestCase, HelperTestCase, TestCase, ):
235+class LandscapeTest(MessageTestCase, HelperTestCase, TestCase):
236
237 def setUp(self):
238 self._old_config_filenames = BaseConfiguration.default_config_filenames

Subscribers

People subscribed via source and target branches

to all changes: