Merge lp:~jdstrand/click-reviewers-tools/lint-snapv2 into lp:click-reviewers-tools

Proposed by Jamie Strandboge on 2016-02-10
Status: Merged
Merged at revision: 575
Proposed branch: lp:~jdstrand/click-reviewers-tools/lint-snapv2
Merge into: lp:click-reviewers-tools
Prerequisite: lp:~jdstrand/click-reviewers-tools/initial-snapv2
Diff against target: 4475 lines (+3980/-171)
15 files modified
.bzrignore (+2/-0)
Makefile (+7/-0)
README (+1/-0)
bin/click-review (+4/-3)
bin/snap-check-lint (+24/-0)
check-names.list (+63/-0)
clickreviews/common.py (+89/-0)
clickreviews/cr_lint.py (+9/-50)
clickreviews/cr_tests.py (+1/-34)
clickreviews/sr_common.py (+10/-2)
clickreviews/sr_lint.py (+1203/-0)
clickreviews/sr_tests.py (+20/-36)
clickreviews/tests/test_cr_lint.py (+2/-2)
clickreviews/tests/test_sr_lint.py (+2396/-0)
clickreviews/tests/utils.py (+149/-44)
To merge this branch: bzr merge lp:~jdstrand/click-reviewers-tools/lint-snapv2
Reviewer Review Type Date Requested Status
Daniel Holbach (community) 2016-02-10 Approve on 2016-02-15
Review via email: mp+285666@code.launchpad.net

Description of the Change

add lint checks for snap.yaml
- add sr_lint.py. This adds complete snap.yaml checks. A few lint checks were dropped over cr_common.py, but these will be added in a future commit
- add clickreviews/tests/test_sr_lint.py which should provide full test coverage (coverage will be added in future commit)
- add bin/snap-check-lint
- update README for the above
- add coverage and coverage-report targets
- bin/click-review: make module sections more descriptive
- bin/click-review: rename click_fn variable as pkg_fn

Testing:
# click (same as prerequisite refactor branch)
PYTHONPATH=./ ./bin/click-review -v ../rottentomatoes/rottentomatoes.jdstrand_0.11.2_all.click | grep 'OK' |wc -l
120

# snap v1 (same as prerequisite refactor branch)
$ PYTHONPATH=./ ./bin/click-review -v ../ufw-trunk/ufw_0.35_all.snap | grep OK|wc -l
264

# snap v2 (these aren't all the tests since this is a simple snap, but does show the lint tests are being run)
$ PYTHONPATH=./ ./bin/click-review -v ../snappy-debug/snappy-debug_0.12_all.snap | grep OK|wc -l
26

To post a comment you must log in.
Jamie Strandboge (jdstrand) wrote :

I implemented the remaining lint tests but need to update the testsuite.

Jamie Strandboge (jdstrand) wrote :

With r597, we should have complete snap.yaml checks and all missing TODOs checks are present. The lint checks are now on par with existing click and snap v1 checks. The testsuite covers all the checks and there is 100% coverage for these lint checks.

Next up, sr_security.py which will be in another MP.

Daniel Holbach (dholbach) wrote :

This by and large looks good to me. I'm no expert though on the specific checks required for snapv2 - would you like another review from somebody on the snappy team for this?

review: Approve
Jamie Strandboge (jdstrand) wrote :

I don't think that is required (they are quite busy)-- I'm going to run the tests through the existing snaps and I followed doc/meta.md for these. Anything that isn't right can just be a bug that I'll fix.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2013-09-26 12:41:57 +0000
3+++ .bzrignore 2016-02-11 18:32:45 +0000
4@@ -9,3 +9,5 @@
5 debian/click-reviewers-tools.substvars
6 debian/files
7 debian/tmp
8+.coverage
9+check-names.list.orig
10
11=== modified file 'Makefile'
12--- Makefile 2015-10-26 22:00:58 +0000
13+++ Makefile 2016-02-11 18:32:45 +0000
14@@ -7,6 +7,12 @@
15 test:
16 ./run-tests
17
18+coverage:
19+ python3 -m coverage run ./run-tests
20+
21+coverage-report:
22+ python3 -m coverage report --show-missing --omit="*skeleton*,*/dist-packages/*"
23+
24 syntax-check: clean
25 ./run-pyflakes
26 ./run-pep8
27@@ -23,6 +29,7 @@
28
29 clean:
30 rm -rf ./clickreviews/__pycache__ ./clickreviews/tests/__pycache__
31+ rm -rf ./.coverage
32
33 .PHONY: check-names.list
34 check-names.list:
35
36=== modified file 'README'
37--- README 2016-02-10 19:32:10 +0000
38+++ README 2016-02-11 18:32:45 +0000
39@@ -14,6 +14,7 @@
40 - bin/click-run-checks: all tests
41
42 Runnable snap v2 tests:
43+- bin/snap-check-lint: lint tests
44 - bin/snap-run-checks: all tests
45
46 This gives an alternate view on bin/click-run-checks:
47
48=== modified file 'bin/click-review'
49--- bin/click-review 2016-02-09 21:45:25 +0000
50+++ bin/click-review 2016-02-11 18:32:45 +0000
51@@ -32,7 +32,7 @@
52
53 def __init__(self, args):
54 self.args = args
55- self.click_fn = self.args.filename
56+ self.pkg_fn = self.args.filename
57 self.modules = modules.get_modules()
58
59 def _sumarise_results(self):
60@@ -86,8 +86,9 @@
61 # review.do_checks()
62 # rc = review.do_report()
63 #
64- section = module.replace('cr_', '')
65- review = modules.init_main_class(module, self.click_fn)
66+ section = module.replace('cr_', 'click,snap.v1_')
67+ section = section.replace('sr_', 'snap.v2_')
68+ review = modules.init_main_class(module, self.pkg_fn)
69 if review:
70 review.do_checks()
71 self.results[section] = review.click_report
72
73=== added file 'bin/snap-check-lint'
74--- bin/snap-check-lint 1970-01-01 00:00:00 +0000
75+++ bin/snap-check-lint 2016-02-11 18:32:45 +0000
76@@ -0,0 +1,24 @@
77+#!/usr/bin/python3
78+'''snap-check-lint: perform snap lint checks'''
79+#
80+# Copyright (C) 2013-2016 Canonical Ltd.
81+#
82+# This program is free software: you can redistribute it and/or modify
83+# it under the terms of the GNU General Public License as published by
84+# the Free Software Foundation; version 3 of the License.
85+#
86+# This program is distributed in the hope that it will be useful,
87+# but WITHOUT ANY WARRANTY; without even the implied warranty of
88+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
89+# GNU General Public License for more details.
90+#
91+# You should have received a copy of the GNU General Public License
92+# along with this program. If not, see <http://www.gnu.org/licenses/>.
93+
94+from __future__ import print_function
95+
96+import clickreviews.common as common
97+import clickreviews.sr_lint as sr_lint
98+
99+if __name__ == "__main__":
100+ common.run_check(sr_lint.SnapReviewLint)
101
102=== modified file 'check-names.list'
103--- check-names.list 2016-02-09 21:45:25 +0000
104+++ check-names.list 2016-02-11 18:32:45 +0000
105@@ -94,6 +94,69 @@
106 lint:snappy_type_valid|
107 lint:snappy_unknown|
108 lint:snappy_version_valid|
109+lint-snap-v2:apps|
110+lint-snap-v2:apps_entry|
111+lint-snap-v2:apps_present|
112+lint-snap-v2:apps_required|
113+lint-snap-v2:apps_unknown|
114+lint-snap-v2:architecture_specified_needed|
115+lint-snap-v2:architecture_valid|
116+lint-snap-v2:attributes|
117+lint-snap-v2:bus-name|
118+lint-snap-v2:bus-name_framework|
119+lint-snap-v2:bus-name|http://dbus.freedesktop.org/doc/dbus-specification.html
120+lint-snap-v2:bus-name_matches_name|
121+lint-snap-v2:command|
122+lint-snap-v2:config_hook_executable|
123+lint-snap-v2:daemon|
124+lint-snap-v2:daemon_required|
125+lint-snap-v2:description|
126+lint-snap-v2:description_present|
127+lint-snap-v2:external_symlinks|
128+lint-snap-v2:frameworks|http://askubuntu.com/questions/460512/what-framework-should-i-use-in-my-manifest-file
129+lint-snap-v2:icon_absolute_path|
130+lint-snap-v2:icon_empty|
131+lint-snap-v2:icon_exists|
132+lint-snap-v2:icon_present|
133+lint-snap-v2:is_squashfs|
134+lint-snap-v2:license-agreement|
135+lint-snap-v2:license-agreement_present|
136+lint-snap-v2:license-version|
137+lint-snap-v2:license-version_present|
138+lint-snap-v2:listen-stream|
139+lint-snap-v2:listen-stream_matches_name|
140+lint-snap-v2:migration-skill|
141+lint-snap-v2:name_valid|
142+lint-snap-v2:nonexistent|
143+lint-snap-v2:ports|
144+lint-snap-v2:ports_ext1_format|
145+lint-snap-v2:ports_ext2_format|
146+lint-snap-v2:ports_int1_format|
147+lint-snap-v2:ports_unknown_key|
148+lint-snap-v2:ports_unknown_subkey|
149+lint-snap-v2:poststop|
150+lint-snap-v2:restart-condition|
151+lint-snap-v2:snap_type_redflag|https://developer.ubuntu.com/en/snappy/guides/frameworks/
152+lint-snap-v2:snap_type_valid|
153+lint-snap-v2:socket|
154+lint-snap-v2:socket-group|
155+lint-snap-v2:socket-group_matches_name|
156+lint-snap-v2:socket-group_reserved|
157+lint-snap-v2:socket-user|
158+lint-snap-v2:socket-user_matches_name|
159+lint-snap-v2:socket-user_reserved|
160+lint-snap-v2:stop|
161+lint-snap-v2:stop-timeout|
162+lint-snap-v2:stop-timeout_range|
163+lint-snap-v2:summary|
164+lint-snap-v2:summary_present|
165+lint-snap-v2:type|
166+lint-snap-v2:unknown_field|
167+lint-snap-v2:uses|
168+lint-snap-v2:uses_slot_reference|
169+lint-snap-v2:valid_contents_for_architecture|
170+lint-snap-v2:vcs_files|
171+lint-snap-v2:version_valid|
172 online_accounts:account-application_hook|
173 online_accounts:account-application_id|
174 online_accounts:account-application_root|
175
176=== modified file 'clickreviews/common.py'
177--- clickreviews/common.py 2016-02-09 21:45:25 +0000
178+++ clickreviews/common.py 2016-02-11 18:32:45 +0000
179@@ -33,6 +33,7 @@
180 DEBUGGING = False
181 UNPACK_DIR = None
182 RAW_UNPACK_DIR = None
183+MKSQUASHFS_OPTS = ['-noappend', '-comp', 'xz', '-all-root']
184
185
186 def cleanup_unpack():
187@@ -512,3 +513,91 @@
188 recursive_rm(unpack_dir)
189
190 return (pkgtype, pkgver)
191+
192+
193+def find_external_symlinks(unpack_dir, pkg_files):
194+ '''Check if symlinks in the package go out to the system.'''
195+ common = '(-[0-9.]+)?\.so(\.[0-9.]+)?'
196+ libc6_libs = ['ld-*.so',
197+ 'libanl',
198+ 'libBrokenLocale',
199+ 'libc',
200+ 'libcidn',
201+ 'libcrypt',
202+ 'libdl',
203+ 'libmemusage',
204+ 'libm',
205+ 'libnsl',
206+ 'libnss_compat',
207+ 'libnss_dns',
208+ 'libnss_files',
209+ 'libnss_hesiod',
210+ 'libnss_nisplus',
211+ 'libnss_nis',
212+ 'libpcprofile',
213+ 'libpthread',
214+ 'libresolv',
215+ 'librt',
216+ 'libSegFault',
217+ 'libthread_db',
218+ 'libutil',
219+ ]
220+ libc6_pats = []
221+ for lib in libc6_libs:
222+ libc6_pats.append(re.compile(r'%s%s' % (lib, common)))
223+ libc6_pats.append(re.compile(r'ld-*.so$'))
224+ libc6_pats.append(re.compile(r'ld-linux-*.so\.[0-9.]+$'))
225+
226+ def _in_patterns(pats, f):
227+ for pat in pats:
228+ if pat.search(f):
229+ return True
230+ return False
231+
232+ external_symlinks = list(filter(lambda link: not
233+ os.path.realpath(link).startswith(
234+ unpack_dir) and
235+ not _in_patterns(libc6_pats,
236+ os.path.basename(link)),
237+ pkg_files))
238+
239+ return external_symlinks
240+
241+
242+# check_results(report, expected_counts, expected)
243+# Verify exact counts of types
244+# expected_counts={'info': 1, 'warn': 0, 'error': 0}
245+# self.check_results(report, expected_counts)
246+# Verify counts of warn and error types
247+# expected_counts={'info': None, 'warn': 0, 'error': 0}
248+# self.check_results(report, expected_counts)
249+# Verify exact messages:
250+# expected = dict()
251+# expected['info'] = dict()
252+# expected['warn'] = dict()
253+# expected['warn']['skeleton_baz'] = "TODO"
254+# expected['error'] = dict()
255+# self.check_results(r, expected=expected)
256+
257+
258+def check_results(testobj, report,
259+ expected_counts={'info': 1, 'warn': 0, 'error': 0},
260+ expected=None):
261+ if expected is not None:
262+ for t in expected.keys():
263+ for r in expected[t]:
264+ testobj.assertTrue(r in report[t],
265+ "Could not find '%s' (%s) in:\n%s" %
266+ (r, t, json.dumps(report, indent=2)))
267+ for k in expected[t][r]:
268+ testobj.assertTrue(k in report[t][r],
269+ "Could not find '%s' (%s) in:\n%s" %
270+ (k, r, json.dumps(report, indent=2)))
271+ testobj.assertEqual(expected[t][r][k], report[t][r][k])
272+ else:
273+ for k in expected_counts.keys():
274+ if expected_counts[k] is None:
275+ continue
276+ testobj.assertEqual(len(report[k]), expected_counts[k],
277+ "(%s not equal)\n%s" %
278+ (k, json.dumps(report, indent=2)))
279
280=== modified file 'clickreviews/cr_lint.py'
281--- clickreviews/cr_lint.py 2016-02-10 19:29:39 +0000
282+++ clickreviews/cr_lint.py 2016-02-11 18:32:45 +0000
283@@ -27,13 +27,14 @@
284 from clickreviews.cr_common import (
285 ClickReview,
286 )
287-
288 from clickreviews.common import (
289 open_file_read,
290 cmd,
291 error,
292 )
293-
294+from clickreviews.common import (
295+ find_external_symlinks,
296+)
297
298 CONTROL_FILE_NAMES = ["control", "manifest", "preinst"]
299 MINIMUM_CLICK_FRAMEWORK_VERSION = "0.4"
300@@ -538,61 +539,19 @@
301 '''Check if symlinks in the click package go out to the system.'''
302 if not self.is_click and not self.is_snap1:
303 return
304- if self.is_snap1 and self.pkg_yaml['type'] not in ['app', 'framework']:
305+
306+ if self.is_snap1 and 'type' in self.snap_yaml and \
307+ self.snap_yaml['type'] not in ['app', 'framework']:
308 return
309
310 t = 'info'
311 n = self._get_check_name('external_symlinks')
312 s = 'OK'
313
314- common = '(-[0-9.]+)?\.so(\.[0-9.]+)?'
315- libc6_libs = ['ld-*.so',
316- 'libanl',
317- 'libBrokenLocale',
318- 'libc',
319- 'libcidn',
320- 'libcrypt',
321- 'libdl',
322- 'libmemusage',
323- 'libm',
324- 'libnsl',
325- 'libnss_compat',
326- 'libnss_dns',
327- 'libnss_files',
328- 'libnss_hesiod',
329- 'libnss_nisplus',
330- 'libnss_nis',
331- 'libpcprofile',
332- 'libpthread',
333- 'libresolv',
334- 'librt',
335- 'libSegFault',
336- 'libthread_db',
337- 'libutil',
338- ]
339- libc6_pats = []
340- for lib in libc6_libs:
341- libc6_pats.append(re.compile(r'%s%s' % (lib, common)))
342- libc6_pats.append(re.compile(r'ld-*.so$'))
343- libc6_pats.append(re.compile(r'ld-linux-*.so\.[0-9.]+$'))
344-
345- def _in_patterns(pats, f):
346- for pat in pats:
347- if pat.search(f):
348- return True
349- return False
350-
351- external_symlinks = list(filter(lambda link: not
352- os.path.realpath(link).startswith(
353- self.unpack_dir) and
354- not _in_patterns(libc6_pats,
355- os.path.basename(link)),
356- self.pkg_files))
357-
358- if external_symlinks:
359+ links = find_external_symlinks(self.unpack_dir, self.pkg_files)
360+ if len(links) > 0:
361 t = 'error'
362- s = 'package contains external symlinks: %s' % \
363- ', '.join(external_symlinks)
364+ s = 'package contains external symlinks: %s' % ', '.join(links)
365 self._add_result(t, n, s)
366
367 def check_pkgname(self):
368
369=== modified file 'clickreviews/cr_scope.py' (properties changed: +x to -x)
370=== modified file 'clickreviews/cr_tests.py'
371--- clickreviews/cr_tests.py 2016-02-09 22:26:36 +0000
372+++ clickreviews/cr_tests.py 2016-02-11 18:32:45 +0000
373@@ -713,43 +713,10 @@
374 self.test_control['Version'],
375 self.test_control['Architecture'])
376
377- #
378- # check_results(report, expected_counts, expected)
379- # Verify exact counts of types
380- # expected_counts={'info': 1, 'warn': 0, 'error': 0}
381- # self.check_results(report, expected_counts)
382- # Verify counts of warn and error types
383- # expected_counts={'info': None, 'warn': 0, 'error': 0}
384- # self.check_results(report, expected_counts)
385- # Verify exact messages:
386- # expected = dict()
387- # expected['info'] = dict()
388- # expected['warn'] = dict()
389- # expected['warn']['skeleton_baz'] = "TODO"
390- # expected['error'] = dict()
391- # self.check_results(r, expected=expected)
392- #
393 def check_results(self, report,
394 expected_counts={'info': 1, 'warn': 0, 'error': 0},
395 expected=None):
396- if expected is not None:
397- for t in expected.keys():
398- for r in expected[t]:
399- self.assertTrue(r in report[t],
400- "Could not find '%s' (%s) in:\n%s" %
401- (r, t, json.dumps(report, indent=2)))
402- for k in expected[t][r]:
403- self.assertTrue(k in report[t][r],
404- "Could not find '%s' (%s) in:\n%s" %
405- (k, r, json.dumps(report, indent=2)))
406- self.assertEqual(expected[t][r][k], report[t][r][k])
407- else:
408- for k in expected_counts.keys():
409- if expected_counts[k] is None:
410- continue
411- self.assertEqual(len(report[k]), expected_counts[k],
412- "(%s not equal)\n%s" %
413- (k, json.dumps(report, indent=2)))
414+ common.check_results(self, report, expected_counts, expected)
415
416 def check_manual_review(self, report, check_name,
417 result_type='error', manual_review=True):
418
419=== added directory 'clickreviews/data'
420=== added file 'clickreviews/data/icon.png'
421Binary files clickreviews/data/icon.png 1970-01-01 00:00:00 +0000 and clickreviews/data/icon.png 2016-02-11 18:32:45 +0000 differ
422=== modified file 'clickreviews/sr_common.py'
423--- clickreviews/sr_common.py 2016-02-10 19:32:10 +0000
424+++ clickreviews/sr_common.py 2016-02-11 18:32:45 +0000
425@@ -92,7 +92,7 @@
426 if snap_yaml:
427 try:
428 self.snap_yaml = yaml.safe_load(snap_yaml)
429- except Exception:
430+ except Exception: # pragma: nocover
431 error("Could not load snap.yaml. Is it properly formatted?")
432
433 # default to 'app'
434@@ -108,13 +108,21 @@
435 if 'type' in self.snap_yaml and self.snap_yaml['type'] == 'gadget':
436 self.is_snap_gadget = True
437
438- def _extract_snap_yaml(self):
439+ # Since coverage is looked at via the testsuite and the testsuite mocks
440+ # this out, don't cover this
441+ def _extract_snap_yaml(self): # pragma: nocover
442 '''Extract and read the snappy 16.04 snap.yaml'''
443 y = os.path.join(self.unpack_dir, "meta/snap.yaml")
444 if not os.path.isfile(y):
445 return None # snappy packaging is still optional
446 return open_file_read(y)
447
448+ # Since coverage is looked at via the testsuite and the testsuite mocks
449+ # this out, don't cover this
450+ def _get_unpack_dir(self): # pragma: nocover
451+ '''Get unpack directory'''
452+ return self.unpack_dir
453+
454 def _verify_pkgname(self, n):
455 '''Verify package name'''
456 pat = re.compile(r'^[a-z0-9][a-z0-9+-]+$')
457
458=== added file 'clickreviews/sr_lint.py'
459--- clickreviews/sr_lint.py 1970-01-01 00:00:00 +0000
460+++ clickreviews/sr_lint.py 2016-02-11 18:32:45 +0000
461@@ -0,0 +1,1203 @@
462+'''sr_lint.py: lint checks'''
463+#
464+# Copyright (C) 2013-2016 Canonical Ltd.
465+#
466+# This program is free software: you can redistribute it and/or modify
467+# it under the terms of the GNU General Public License as published by
468+# the Free Software Foundation; version 3 of the License.
469+#
470+# This program is distributed in the hope that it will be useful,
471+# but WITHOUT ANY WARRANTY; without even the implied warranty of
472+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
473+# GNU General Public License for more details.
474+#
475+# You should have received a copy of the GNU General Public License
476+# along with this program. If not, see <http://www.gnu.org/licenses/>.
477+
478+from __future__ import print_function
479+from clickreviews.frameworks import Frameworks
480+from clickreviews.sr_common import (
481+ SnapReview,
482+)
483+from clickreviews.common import (
484+ find_external_symlinks,
485+)
486+import glob
487+import os
488+import re
489+
490+
491+class SnapReviewLint(SnapReview):
492+ '''This class represents snap lint reviews'''
493+
494+ def __init__(self, fn, overrides=None):
495+ '''Set up the class.'''
496+ SnapReview.__init__(self, fn, "lint-snap-v2", overrides=overrides)
497+ if not self.is_snap2:
498+ return
499+
500+ self.valid_compiled_architectures = ['armhf',
501+ 'i386',
502+ 'amd64',
503+ 'arm64',
504+ ]
505+ self.valid_architectures = ['all'] + self.valid_compiled_architectures
506+ self.vcs_files = ['.bzr*',
507+ # '.excludes', # autogenerated by SDK
508+ '.git*',
509+ '.idea',
510+ '.svn*',
511+ '.hg',
512+ '.project',
513+ 'CVS*',
514+ 'RCS*'
515+ ]
516+
517+ self._list_all_compiled_binaries()
518+
519+ # Valid values for 'type' in packaging yaml
520+ # - app
521+ # - framework
522+ # - kernel
523+ # - gadget
524+ # - os
525+ self.valid_snap_types = ['app',
526+ 'framework',
527+ 'kernel',
528+ 'gadget',
529+ 'os',
530+ ]
531+ self.redflagged_snap_types = ['framework',
532+ 'kernel',
533+ 'gadget',
534+ 'os',
535+ ]
536+
537+ def check_architectures(self):
538+ '''Check architectures in snap.yaml is valid'''
539+ if not self.is_snap2:
540+ return
541+
542+ t = 'info'
543+ n = self._get_check_name('architecture_valid')
544+ s = 'OK'
545+
546+ key = 'architectures'
547+ if key not in self.snap_yaml:
548+ s = 'OK (%s not specified)' % key
549+ self._add_result(t, n, s)
550+ return
551+
552+ if not isinstance(self.snap_yaml[key], list):
553+ t = 'error'
554+ s = "invalid %s entry: %s (not a list)" % (key,
555+ self.snap_yaml[key])
556+ else:
557+ bad_archs = []
558+ for arch in self.snap_yaml[key]:
559+ if arch not in self.valid_architectures:
560+ bad_archs.append(arch)
561+ if len(bad_archs) > 0:
562+ t = 'error'
563+ s = "invalid multi architecture: %s" % ",".join(bad_archs)
564+ self._add_result(t, n, s)
565+
566+ def check_description(self):
567+ '''Check description'''
568+ if not self.is_snap2:
569+ return
570+
571+ key = 'description'
572+
573+ t = 'info'
574+ n = self._get_check_name('%s_present' % key)
575+ s = 'OK'
576+ if key not in self.snap_yaml:
577+ s = 'OK (optional %s field not specified)' % key
578+ self._add_result(t, n, s)
579+ return
580+ self._add_result(t, n, s)
581+
582+ t = 'info'
583+ n = self._get_check_name(key)
584+ s = 'OK'
585+ if not isinstance(self.snap_yaml[key], str):
586+ t = 'error'
587+ s = "invalid %s entry: %s (not a str)" % (key, self.snap_yaml[key])
588+ self._add_result(t, n, s)
589+ return
590+ elif len(self.snap_yaml[key]) < 1:
591+ t = 'error'
592+ s = "invalid %s entry (empty)" % (key)
593+ elif len(self.snap_yaml[key]) < len(self.snap_yaml['name']):
594+ t = 'info'
595+ s = "%s is too short: '%s'" % (key, self.snap_yaml[key])
596+ self._add_result(t, n, s)
597+
598+ def check_frameworks(self):
599+ '''Check framework'''
600+ if not self.is_snap2:
601+ return
602+
603+ key = 'frameworks'
604+
605+ t = 'info'
606+ n = self._get_check_name(key)
607+ l = "http://askubuntu.com/questions/460512/what-framework-should-i-use-in-my-manifest-file"
608+
609+ if key not in self.snap_yaml:
610+ s = 'OK (%s not specified)' % key
611+ self._add_result(t, n, s)
612+ return
613+
614+ if not isinstance(self.snap_yaml[key], list):
615+ t = 'error'
616+ s = "invalid %s entry: %s (not a list)" % (key,
617+ self.snap_yaml[key])
618+ self._add_result(t, n, s)
619+ return
620+ elif len(self.snap_yaml[key]) < 1:
621+ t = 'error'
622+ s = "invalid %s entry (empty)" % (key)
623+ self._add_result(t, n, s)
624+ return
625+
626+ framework_overrides = self.overrides.get('framework', {})
627+ frameworks = Frameworks(overrides=framework_overrides)
628+
629+ for framework in self.snap_yaml[key]:
630+ if framework in frameworks.AVAILABLE_FRAMEWORKS:
631+ t = 'info'
632+ s = 'OK'
633+ self._add_result(t, n, s)
634+ # If it's an available framework, we're done checking
635+ return
636+ elif framework in frameworks.DEPRECATED_FRAMEWORKS:
637+ t = 'warn'
638+ s = "'%s' is deprecated. Please use a newer framework" % \
639+ framework
640+ self._add_result(t, n, s, l)
641+ return
642+ elif framework in frameworks.OBSOLETE_FRAMEWORKS:
643+ t = 'error'
644+ s = "'%s' is obsolete. Please use a newer framework" % \
645+ framework
646+ self._add_result(t, n, s, l)
647+ return
648+ else:
649+ # None of the above checks triggered, this is an unknown
650+ # framework
651+ t = 'error'
652+ s = "'%s' is not a supported framework" % \
653+ framework
654+ self._add_result(t, n, s, l)
655+
656+ # TODO: verify this is a field
657+ def check_license_agreement(self):
658+ '''Check license-agreement'''
659+ if not self.is_snap2:
660+ return
661+
662+ key = 'license-agreement'
663+
664+ t = 'info'
665+ n = self._get_check_name('%s_present' % key)
666+ s = 'OK'
667+ if key not in self.snap_yaml:
668+ s = 'OK (optional %s field not specified)' % key
669+ self._add_result(t, n, s)
670+ return
671+ self._add_result(t, n, s)
672+
673+ t = 'info'
674+ n = self._get_check_name(key)
675+ s = 'OK'
676+ if not isinstance(self.snap_yaml[key], str):
677+ t = 'error'
678+ s = "invalid %s entry: %s (not a str)" % (key, self.snap_yaml[key])
679+ self._add_result(t, n, s)
680+ return
681+ elif len(self.snap_yaml[key]) < 1:
682+ t = 'error'
683+ s = "invalid %s entry (empty)" % (key)
684+ self._add_result(t, n, s)
685+ return
686+ self._add_result(t, n, s)
687+
688+ def check_license_version(self):
689+ '''license-version'''
690+ if not self.is_snap2:
691+ return
692+
693+ key = 'license-version'
694+ t = 'info'
695+ n = self._get_check_name('%s_present' % key)
696+ s = 'OK'
697+ if key not in self.snap_yaml:
698+ s = 'OK (optional %s field not specified)' % key
699+ self._add_result(t, n, s)
700+ return
701+ self._add_result(t, n, s)
702+
703+ t = 'info'
704+ n = self._get_check_name(key)
705+ s = 'OK'
706+ if not isinstance(self.snap_yaml[key], str):
707+ t = 'error'
708+ s = "invalid %s entry: %s (not a str)" % (key, self.snap_yaml[key])
709+ self._add_result(t, n, s)
710+ return
711+ elif len(self.snap_yaml[key]) < 1:
712+ t = 'error'
713+ s = "invalid %s entry (empty)" % (key)
714+ self._add_result(t, n, s)
715+ return
716+ self._add_result(t, n, s)
717+
718+ def check_name(self):
719+ '''Check package name'''
720+ if not self.is_snap2:
721+ return
722+
723+ t = 'info'
724+ n = self._get_check_name('name_valid')
725+ s = 'OK'
726+ if 'name' not in self.snap_yaml:
727+ t = 'error'
728+ s = "could not find 'name' in yaml"
729+ elif not isinstance(self.snap_yaml['name'], str):
730+ t = 'error'
731+ s = "malformed 'name': %s (not a str)" % (self.snap_yaml['name'])
732+ elif not self._verify_pkgname(self.snap_yaml['name']):
733+ t = 'error'
734+ s = "malformed 'name': '%s'" % self.snap_yaml['name']
735+ self._add_result(t, n, s)
736+
737+ def check_summary(self):
738+ '''Check summary'''
739+ if not self.is_snap2:
740+ return
741+
742+ key = 'summary'
743+
744+ t = 'info'
745+ n = self._get_check_name('%s_present' % key)
746+ s = 'OK'
747+ if key not in self.snap_yaml:
748+ s = 'OK (optional %s field not specified)' % key
749+ self._add_result(t, n, s)
750+ return
751+ self._add_result(t, n, s)
752+
753+ t = 'info'
754+ n = self._get_check_name(key)
755+ s = 'OK'
756+ if not isinstance(self.snap_yaml[key], str):
757+ t = 'error'
758+ s = "invalid %s entry: %s (not a str)" % (key, self.snap_yaml[key])
759+ self._add_result(t, n, s)
760+ return
761+ elif len(self.snap_yaml[key]) < 1:
762+ t = 'error'
763+ s = "invalid %s entry (empty)" % (key)
764+ elif len(self.snap_yaml[key]) < len(self.snap_yaml['name']):
765+ t = 'info'
766+ s = "%s is too short: '%s'" % (key, self.snap_yaml[key])
767+ self._add_result(t, n, s)
768+
769+ def check_type(self):
770+ '''Check type'''
771+ if not self.is_snap2 or 'type' not in self.snap_yaml:
772+ return
773+
774+ t = 'info'
775+ n = self._get_check_name('snap_type_valid')
776+ s = 'OK'
777+ if self.snap_yaml['type'] not in self.valid_snap_types:
778+ t = 'error'
779+ s = "unknown 'type': '%s'" % self.snap_yaml['type']
780+ self._add_result(t, n, s)
781+
782+ def check_type_redflagged(self):
783+ '''Check if type is redflagged'''
784+ if not self.is_snap2 or 'type' not in self.snap_yaml:
785+ return
786+
787+ t = 'info'
788+ n = self._get_check_name('snap_type_redflag')
789+ s = "OK"
790+ l = None
791+ manual_review = False
792+ if self.snap_yaml['type'] in self.redflagged_snap_types:
793+ t = 'error'
794+ s = "(NEEDS REVIEW) type '%s' not allowed" % self.snap_yaml['type']
795+ manual_review = True
796+ if self.snap_yaml['type'] == "framework":
797+ l = "https://developer.ubuntu.com/en/snappy/guides/frameworks/"
798+ self._add_result(t, n, s, link=l, manual_review=manual_review)
799+
800+ def check_version(self):
801+ '''Check package version'''
802+ if not self.is_snap2:
803+ return
804+
805+ t = 'info'
806+ n = self._get_check_name('version_valid')
807+ s = 'OK'
808+ if 'version' not in self.snap_yaml:
809+ t = 'error'
810+ s = "could not find 'version' in yaml"
811+ elif not self._verify_pkgversion(self.snap_yaml['version']):
812+ t = 'error'
813+ s = "malformed 'version': '%s'" % self.snap_yaml['version']
814+ self._add_result(t, n, s)
815+
816+ def check_config(self):
817+ '''Check config'''
818+ if not self.is_snap2:
819+ return
820+
821+ fn = os.path.join(self._get_unpack_dir(), 'meta/hooks/config')
822+ if fn not in self.pkg_files:
823+ return
824+
825+ t = 'info'
826+ n = self._get_check_name('config_hook_executable')
827+ s = 'OK'
828+ if not self._check_innerpath_executable(fn):
829+ t = 'error'
830+ s = 'meta/hooks/config is not executable'
831+ self._add_result(t, n, s)
832+
833+ def check_icon(self):
834+ '''Check icon'''
835+ # see docs/meta.md and docs/gadget.md
836+ if not self.is_snap2 or 'icon' not in self.snap_yaml:
837+ return
838+
839+ t = 'info'
840+ n = self._get_check_name('icon_present')
841+ s = 'OK'
842+ if 'type' in self.snap_yaml and self.snap_yaml['type'] != "gadget":
843+ t = 'warn'
844+ s = 'icon only used with gadget snaps'
845+ self._add_result(t, n, s)
846+ return
847+ self._add_result(t, n, s)
848+
849+ t = 'info'
850+ n = self._get_check_name('icon_empty')
851+ s = 'OK'
852+ if len(self.snap_yaml['icon']) == 0:
853+ t = 'error'
854+ s = "icon entry is empty"
855+ self._add_result(t, n, s)
856+ return
857+ self._add_result(t, n, s)
858+
859+ t = 'info'
860+ n = self._get_check_name('icon_absolute_path')
861+ s = 'OK'
862+ if self.snap_yaml['icon'].startswith('/'):
863+ t = 'error'
864+ s = "icon entry '%s' should not specify absolute path" % \
865+ self.snap_yaml['icon']
866+ self._add_result(t, n, s)
867+
868+ t = 'info'
869+ n = self._get_check_name('icon_exists')
870+ s = 'OK'
871+ fn = self._path_join(self._get_unpack_dir(), self.snap_yaml['icon'])
872+ if fn not in self.pkg_files:
873+ t = 'error'
874+ s = "icon entry '%s' does not exist" % self.snap_yaml['icon']
875+ self._add_result(t, n, s)
876+
877+ def check_unknown_entries(self):
878+ '''Check for any unknown fields'''
879+ if not self.is_snap2:
880+ return
881+
882+ t = 'info'
883+ n = self._get_check_name('unknown_field')
884+ s = 'OK'
885+ unknown = []
886+ for f in self.snap_yaml:
887+ if f not in self.snappy_required + self.snappy_optional:
888+ unknown.append(f)
889+ if len(unknown) > 0:
890+ t = 'warn'
891+ s = "unknown entries in snap.yaml: '%s'" % \
892+ (",".join(sorted(unknown)))
893+ self._add_result(t, n, s)
894+
895+ def check_is_squashfs(self):
896+ '''Check snapfs'''
897+ if not self.is_snap2:
898+ return
899+
900+ # Manual review until have squashfs tests
901+ t = 'error'
902+ n = self._get_check_name('is_squashfs')
903+ s = "(NEEDS REVIEW) squashfs pkg"
904+ manual_review = True
905+ self._add_result(t, n, s, manual_review=manual_review)
906+
907+ def check_apps(self):
908+ '''Check apps'''
909+ if not self.is_snap2:
910+ return
911+
912+ key = 'apps'
913+
914+ t = 'info'
915+ n = self._get_check_name('%s_present' % key)
916+ s = 'OK'
917+ if key not in self.snap_yaml:
918+ s = 'OK (optional %s field not specified)' % key
919+ self._add_result(t, n, s)
920+ return
921+ self._add_result(t, n, s)
922+
923+ t = 'info'
924+ n = self._get_check_name(key)
925+ s = 'OK'
926+ if not isinstance(self.snap_yaml[key], dict):
927+ t = 'error'
928+ s = "invalid %s entry: %s (not a dict)" % (key,
929+ self.snap_yaml[key])
930+ self._add_result(t, n, s)
931+ return
932+ elif len(self.snap_yaml[key].keys()) < 1:
933+ t = 'error'
934+ s = "invalid %s entry (empty)" % (key)
935+ self._add_result(t, n, s)
936+ return
937+ self._add_result(t, n, s)
938+
939+ for app in self.snap_yaml[key]:
940+ t = 'info'
941+ n = self._get_check_name('%s_entry' % key, app=app)
942+ s = 'OK'
943+
944+ if not isinstance(self.snap_yaml[key][app], dict):
945+ t = 'error'
946+ s = "invalid entry: %s (not a dict)" % (
947+ self.snap_yaml[key][app])
948+ self._add_result(t, n, s)
949+ continue
950+ elif len(self.snap_yaml[key][app].keys()) < 1:
951+ t = 'error'
952+ s = "invalid entry for '%s' (empty)" % (app)
953+ self._add_result(t, n, s)
954+ continue
955+ self._add_result(t, n, s)
956+
957+ for field in self.apps_required:
958+ t = 'info'
959+ n = self._get_check_name('%s_required' % key, app=app)
960+ s = 'OK'
961+ if field not in self.snap_yaml[key][app]:
962+ t = 'error'
963+ s = "required field '%s' not specified" % field
964+ self._add_result(t, n, s)
965+
966+ t = 'info'
967+ n = self._get_check_name('%s_unknown' % key, app=app)
968+ s = 'OK'
969+ unknown = []
970+ for field in self.snap_yaml[key][app]:
971+ if field not in self.apps_required + self.apps_optional:
972+ unknown.append(field)
973+ if len(unknown) > 0:
974+ t = 'warn'
975+ s = "unknown fields: '%s'" % (",".join(sorted(unknown)))
976+ self._add_result(t, n, s)
977+
978+ def _verify_value_is_file(self, app, key):
979+ t = 'info'
980+ n = self._get_check_name('%s' % key, app=app)
981+ s = 'OK'
982+ if not isinstance(self.snap_yaml['apps'][app][key], str):
983+ t = 'error'
984+ s = "%s '%s' (not a str)" % (key,
985+ self.snap_yaml['apps'][app][key])
986+ self._add_result(t, n, s)
987+ elif len(self.snap_yaml['apps'][app][key]) < 1:
988+ t = 'error'
989+ s = "invalid %s (empty)" % (key)
990+ self._add_result(t, n, s)
991+ else:
992+ fn = self._path_join(self._get_unpack_dir(),
993+ self.snap_yaml['apps'][app][key])
994+ if fn not in self.pkg_files:
995+ t = 'error'
996+ s = "%s does not exist" % (
997+ self.snap_yaml['apps'][app][key])
998+ self._add_result(t, n, s)
999+
1000+ def check_apps_command(self):
1001+ '''Check apps - command'''
1002+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1003+ return
1004+
1005+ for app in self.snap_yaml['apps']:
1006+ key = 'command'
1007+ if key not in self.snap_yaml['apps'][app]:
1008+ # We check for required elsewhere
1009+ continue
1010+
1011+ self._verify_value_is_file(app, key)
1012+
1013+ def check_apps_stop(self):
1014+ '''Check apps - stop'''
1015+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1016+ return
1017+
1018+ for app in self.snap_yaml['apps']:
1019+ key = 'stop'
1020+ if key not in self.snap_yaml['apps'][app]:
1021+ # We check for required elsewhere
1022+ continue
1023+
1024+ self._verify_value_is_file(app, key)
1025+
1026+ def check_apps_poststop(self):
1027+ '''Check apps - poststop'''
1028+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1029+ return
1030+
1031+ for app in self.snap_yaml['apps']:
1032+ key = 'poststop'
1033+ if key not in self.snap_yaml['apps'][app]:
1034+ # We check for required elsewhere
1035+ continue
1036+
1037+ self._verify_value_is_file(app, key)
1038+
1039+ def check_apps_stop_timeout(self):
1040+ '''Check apps - stop-timeout'''
1041+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1042+ return
1043+
1044+ for app in self.snap_yaml['apps']:
1045+ key = 'stop-timeout'
1046+ if key not in self.snap_yaml['apps'][app]:
1047+ # We check for required elsewhere
1048+ continue
1049+
1050+ t = 'info'
1051+ n = self._get_check_name('%s' % key, app=app)
1052+ s = "OK"
1053+ if not isinstance(self.snap_yaml['apps'][app][key], int) and \
1054+ not isinstance(self.snap_yaml['apps'][app][key], str):
1055+ t = 'error'
1056+ s = "'%s' is not a string or integer" % key
1057+ elif not re.search(r'[0-9]+[ms]?$',
1058+ str(self.snap_yaml['apps'][app][key])):
1059+ t = 'error'
1060+ s = "'%s' is not of form NN[ms] (%s)" % \
1061+ (self.snap_yaml['apps'][app][key], key)
1062+ self._add_result(t, n, s)
1063+
1064+ if t == 'error':
1065+ continue
1066+
1067+ t = 'info'
1068+ n = self._get_check_name('%s_range' % key, app=app)
1069+ s = "OK"
1070+ st = int(str(self.snap_yaml['apps'][app][key]).rstrip(r'[ms]'))
1071+ if st < 0 or st > 60:
1072+ t = 'error'
1073+ s = "stop-timeout '%d' out of range (0-60)" % \
1074+ self.snap_yaml['apps'][app][key]
1075+ self._add_result(t, n, s)
1076+
1077+ def _verify_valid_values(self, app, key, valid):
1078+ '''Verify valid values for key in app'''
1079+ t = 'info'
1080+ n = self._get_check_name('%s' % key, app=app)
1081+ s = 'OK'
1082+ if not isinstance(self.snap_yaml['apps'][app][key], str):
1083+ t = 'error'
1084+ s = "%s '%s' (not a str)" % (key,
1085+ self.snap_yaml['apps'][app][key])
1086+ self._add_result(t, n, s)
1087+ elif len(self.snap_yaml['apps'][app][key]) < 1:
1088+ t = 'error'
1089+ s = "invalid %s (empty)" % (key)
1090+ self._add_result(t, n, s)
1091+ elif self.snap_yaml['apps'][app][key] not in valid:
1092+ t = 'error'
1093+ s = "invalid %s: '%s'" % (key, self.snap_yaml['apps'][app][key])
1094+ self._add_result(t, n, s)
1095+
1096+ def check_apps_daemon(self):
1097+ '''Check apps - daemon'''
1098+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1099+ return
1100+
1101+ valid = ["simple",
1102+ "forking",
1103+ "oneshot",
1104+ "dbus",
1105+ ]
1106+
1107+ for app in self.snap_yaml['apps']:
1108+ key = 'daemon'
1109+ if key not in self.snap_yaml['apps'][app]:
1110+ # We check for required elsewhere
1111+ continue
1112+
1113+ self._verify_valid_values(app, key, valid)
1114+
1115+ def check_apps_nondaemon(self):
1116+ '''Check apps - non-daemon'''
1117+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1118+ return
1119+
1120+ # Certain options require 'daemon' so list the keys that are shared
1121+ # by services and binaries
1122+ ok_keys = ['command', 'uses']
1123+
1124+ for app in self.snap_yaml['apps']:
1125+ needs_daemon = []
1126+ for key in self.snap_yaml['apps'][app]:
1127+ if key not in self.apps_optional or \
1128+ key == 'daemon' or \
1129+ key in ok_keys or \
1130+ 'daemon' in self.snap_yaml['apps'][app]:
1131+ continue
1132+ needs_daemon.append(key)
1133+
1134+ t = 'info'
1135+ n = self._get_check_name('daemon_required', app=app)
1136+ s = "OK"
1137+ if len(needs_daemon) > 0:
1138+ t = 'error'
1139+ s = "'%s' must be used with 'daemon'" % ",".join(needs_daemon)
1140+ self._add_result(t, n, s)
1141+
1142+ def check_apps_restart_condition(self):
1143+ '''Check apps - restart-condition'''
1144+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1145+ return
1146+
1147+ valid = ["always",
1148+ "never",
1149+ "on-abnormal",
1150+ "on-abort",
1151+ "on-failure",
1152+ "on-success",
1153+ ]
1154+
1155+ for app in self.snap_yaml['apps']:
1156+ key = 'restart-condition'
1157+ if key not in self.snap_yaml['apps'][app]:
1158+ # We check for required elsewhere
1159+ continue
1160+
1161+ self._verify_valid_values(app, key, valid)
1162+
1163+ def check_apps_busname(self):
1164+ '''Check apps - bus-name'''
1165+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1166+ return
1167+
1168+ for app in self.snap_yaml['apps']:
1169+ key = 'bus-name'
1170+ if key not in self.snap_yaml['apps'][app]:
1171+ # We check for required elsewhere
1172+ continue
1173+
1174+ t = 'info'
1175+ n = self._get_check_name('%s_framework' % key, app=app)
1176+ s = 'OK'
1177+ if 'type' in self.snap_yaml and \
1178+ self.snap_yaml['type'] != 'framework':
1179+ t = 'error'
1180+ s = "Use of bus-name requires package be of 'type: framework'"
1181+ self._add_result(t, n, s)
1182+
1183+ t = 'info'
1184+ n = self._get_check_name('%s' % key, app=app)
1185+ s = 'OK'
1186+ l = None
1187+ if not isinstance(self.snap_yaml['apps'][app][key], str):
1188+ t = 'error'
1189+ s = "%s '%s' (not a str)" % (key,
1190+ self.snap_yaml['apps'][app][key])
1191+ elif len(self.snap_yaml['apps'][app][key]) < 1:
1192+ t = 'error'
1193+ s = "invalid %s (empty)" % (key)
1194+ elif not re.search(
1195+ r'^[A-Za-z0-9][A-Za-z0-9_-]*(\.[A-Za-z0-9][A-Za-z0-9_-]*)+$',
1196+ self.snap_yaml['apps'][app][key]):
1197+ t = 'error'
1198+ l = 'http://dbus.freedesktop.org/doc/dbus-specification.html'
1199+ s = "'%s' is not of form '^[A-Za-z0-9][A-Za-z0-9_-]*(\\.[A-Za-z0-9][A-Za-z0-9_-]*)+$'" % \
1200+ (self.snap_yaml['apps'][app][key])
1201+ self._add_result(t, n, s, l)
1202+ if t == 'error':
1203+ continue
1204+
1205+ t = 'info'
1206+ n = self._get_check_name('%s_matches_name' % key, app=app)
1207+ s = 'OK'
1208+ suggested = [self.snap_yaml['name'],
1209+ "%s.%s" % (self.snap_yaml['name'], app)
1210+ ]
1211+ found = False
1212+ for name in suggested:
1213+ if self.snap_yaml['apps'][app][key].endswith(name):
1214+ found = True
1215+ break
1216+ if not found:
1217+ t = 'error'
1218+ s = "'%s' doesn't end with one of: %s" % \
1219+ (self.snap_yaml['apps'][app][key], ", ".join(suggested))
1220+ self._add_result(t, n, s)
1221+
1222+ def check_apps_ports(self):
1223+ '''Check apps - ports'''
1224+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1225+ return
1226+
1227+ valid_keys = ['internal', 'external']
1228+ valid_subkeys = ['port', 'negotiable']
1229+ for app in self.snap_yaml['apps']:
1230+ if 'ports' not in self.snap_yaml['apps'][app]:
1231+ # We check for required elsewhere
1232+ continue
1233+
1234+ t = 'info'
1235+ n = self._get_check_name('ports', app=app)
1236+ s = 'OK'
1237+ l = None
1238+ if not isinstance(self.snap_yaml['apps'][app]['ports'], dict):
1239+ t = 'error'
1240+ s = "ports '%s' (not a dict)" % (
1241+ self.snap_yaml['apps'][app]['ports'])
1242+ elif len(self.snap_yaml['apps'][app]['ports'].keys()) < 1:
1243+ t = 'error'
1244+ s = "'ports' must contain 'internal' and/or 'external'"
1245+ self._add_result(t, n, s, l)
1246+ if t == 'error':
1247+ continue
1248+
1249+ # unknown
1250+ unknown = []
1251+ for key in self.snap_yaml['apps'][app]['ports']:
1252+ if key not in valid_keys:
1253+ unknown.append(key)
1254+ if len(unknown) > 0:
1255+ t = 'error'
1256+ n = self._get_check_name('ports_unknown_key', extra=key,
1257+ app=app)
1258+ s = "Unknown '%s' for ports" % (",".join(unknown))
1259+ self._add_result(t, n, s)
1260+
1261+ port_pat = re.compile(r'^[0-9]+/[a-z0-9\-]+$')
1262+ for key in valid_keys:
1263+ if key not in self.snap_yaml['apps'][app]['ports']:
1264+ continue
1265+
1266+ if len(self.snap_yaml['apps'][app]['ports'][key].keys()) < 1:
1267+ t = 'error'
1268+ n = self._get_check_name('ports', extra=key, app=app)
1269+ s = 'Could not find any %s ports' % key
1270+ self._add_result(t, n, s)
1271+ continue
1272+
1273+ for tagname in self.snap_yaml['apps'][app]['ports'][key]:
1274+ entry = self.snap_yaml['apps'][app]['ports'][key][tagname]
1275+ if len(entry.keys()) < 1 or ('negotiable' not in entry and
1276+ 'port' not in entry):
1277+ t = 'error'
1278+ n = self._get_check_name('ports', extra=key, app=app)
1279+ s = "Could not find 'port' or 'negotiable' in '%s'" % \
1280+ tagname
1281+ self._add_result(t, n, s)
1282+ continue
1283+
1284+ # unknown
1285+ unknown = []
1286+ for subkey in entry:
1287+ if subkey not in valid_subkeys:
1288+ unknown.append(subkey)
1289+ if len(unknown) > 0:
1290+ t = 'error'
1291+ n = self._get_check_name('ports_unknown_subkey',
1292+ extra=key, app=app)
1293+ s = "Unknown '%s' for %s" % (",".join(unknown),
1294+ tagname)
1295+ self._add_result(t, n, s)
1296+
1297+ # port
1298+ subkey = 'port'
1299+ t = 'info'
1300+ n = self._get_check_name('ports_%s_format' % tagname,
1301+ extra=subkey)
1302+ s = 'OK'
1303+ if subkey not in entry:
1304+ s = 'OK (skipped, not found)'
1305+ elif not isinstance(entry[subkey], str):
1306+ t = 'error'
1307+ s = "invalid entry: %s (not a str)" % (entry[subkey])
1308+ else:
1309+ tmp = entry[subkey].split('/')
1310+ if not port_pat.search(entry[subkey]) or \
1311+ int(tmp[0]) < 1 or int(tmp[0]) > 65535:
1312+ t = 'error'
1313+ s = "'%s' should be of form " % entry[subkey] + \
1314+ "'port/protocol' where port is an integer " + \
1315+ "(1-65535) and protocol is found in " + \
1316+ "/etc/protocols"
1317+ self._add_result(t, n, s)
1318+
1319+ # negotiable
1320+ subkey = 'negotiable'
1321+ t = 'info'
1322+ n = self._get_check_name('ports_%s_format' % tagname,
1323+ extra=subkey)
1324+ s = 'OK'
1325+ if subkey not in entry:
1326+ s = 'OK (skipped, not found)'
1327+ elif not isinstance(entry[subkey], bool):
1328+ t = 'error'
1329+ s = "'%s: %s' should be either 'yes' or 'no'" % \
1330+ (subkey, entry[subkey])
1331+ self._add_result(t, n, s)
1332+
1333+ def check_apps_socket(self):
1334+ '''Check apps - socket'''
1335+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1336+ return
1337+
1338+ for app in self.snap_yaml['apps']:
1339+ key = 'socket'
1340+ if key not in self.snap_yaml['apps'][app]:
1341+ # We check for required elsewhere
1342+ continue
1343+
1344+ t = 'info'
1345+ n = self._get_check_name(key, app=app)
1346+ s = 'OK'
1347+ if not isinstance(self.snap_yaml['apps'][app][key], bool):
1348+ t = 'error'
1349+ s = "'%s: %s' should be either 'yes' or 'no'" % (
1350+ key, self.snap_yaml['apps'][app][key])
1351+ elif 'listen-stream' not in self.snap_yaml['apps'][app]:
1352+ t = 'error'
1353+ s = "'socket' specified without 'listen-stream'"
1354+ self._add_result(t, n, s)
1355+
1356+ def check_apps_listen_stream(self):
1357+ '''Check apps - listen-stream'''
1358+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1359+ return
1360+
1361+ for app in self.snap_yaml['apps']:
1362+ key = 'listen-stream'
1363+ if key not in self.snap_yaml['apps'][app]:
1364+ # We check for required elsewhere
1365+ continue
1366+
1367+ t = 'info'
1368+ n = self._get_check_name(key, app=app)
1369+ s = 'OK'
1370+ if not isinstance(self.snap_yaml['apps'][app][key], str):
1371+ t = 'error'
1372+ s = "invalid entry: %s (not a str)" % (
1373+ self.snap_yaml['apps'][app][key])
1374+ elif len(self.snap_yaml['apps'][app][key]) == 0:
1375+ t = 'error'
1376+ s = "'%s' is empty" % key
1377+ self._add_result(t, n, s)
1378+ if t == 'error':
1379+ continue
1380+
1381+ t = 'info'
1382+ n = self._get_check_name('%s_matches_name' % key, app=app)
1383+ s = 'OK'
1384+ sock = self.snap_yaml['apps'][app][key]
1385+ pkgname = self.snap_yaml['name']
1386+ if sock.startswith('@'):
1387+ if sock != '@%s' % pkgname and \
1388+ not sock.startswith('@%s_' % pkgname):
1389+ t = 'error'
1390+ s = ("abstract socket '%s' is neither '%s' nor starts "
1391+ "with '%s'" % (sock, '@%s' % pkgname,
1392+ '@%s_' % pkgname))
1393+ elif sock.startswith('/'):
1394+ found = False
1395+ for path in ["/tmp/",
1396+ "/var/lib/snaps/%s/" % pkgname,
1397+ "/var/lib/snaps/%s." % pkgname,
1398+ "/run/shm/snaps/%s/" % pkgname,
1399+ "/run/shm/snaps/%s." % pkgname]:
1400+ if sock.startswith(path):
1401+ found = True
1402+ break
1403+ if not found:
1404+ t = 'error'
1405+ s = ("named socket '%s' should be in a writable "
1406+ "app-specific area or /tmp" % sock)
1407+ else:
1408+ t = 'error'
1409+ s = ("'%s' does not specify an abstract socket (starts "
1410+ "with '@') or absolute filename" % (sock))
1411+ self._add_result(t, n, s)
1412+
1413+ def _verify_valid_socket(self, app, key):
1414+ '''Verify valid values for socket key'''
1415+ t = 'info'
1416+ n = self._get_check_name(key, app=app)
1417+ s = 'OK'
1418+ if not isinstance(self.snap_yaml['apps'][app][key], str):
1419+ t = 'error'
1420+ s = "invalid entry: %s (not a str)" % (
1421+ self.snap_yaml['apps'][app][key])
1422+ elif len(self.snap_yaml['apps'][app][key]) == 0:
1423+ t = 'error'
1424+ s = "'%s' is empty" % key
1425+ elif 'listen-stream' not in self.snap_yaml['apps'][app]:
1426+ t = 'error'
1427+ s = "'%s' specified without 'listen-stream'" % key
1428+ self._add_result(t, n, s)
1429+ if t == 'error':
1430+ return
1431+
1432+ t = 'error'
1433+ n = self._get_check_name('%s_reserved' % key, app=app)
1434+ s = "'%s' should not be used until snappy supports per-app users" \
1435+ % key
1436+ self._add_result(t, n, s)
1437+
1438+ t = 'info'
1439+ n = self._get_check_name("%s_matches_name" % key, app=app)
1440+ s = 'OK'
1441+ if self.snap_yaml['apps'][app][key] != self.snap_yaml['name']:
1442+ t = 'error'
1443+ s = "'%s' != '%s'" % (self.snap_yaml['apps'][app][key],
1444+ self.snap_yaml['name'])
1445+ self._add_result(t, n, s)
1446+
1447+ def check_apps_socket_user(self):
1448+ '''Check apps - socket-user'''
1449+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1450+ return
1451+
1452+ for app in self.snap_yaml['apps']:
1453+ key = 'socket-user'
1454+ if key not in self.snap_yaml['apps'][app]:
1455+ # We check for required elsewhere
1456+ continue
1457+
1458+ self._verify_valid_socket(app, key)
1459+
1460+ def check_apps_socket_group(self):
1461+ '''Check apps - socket-group'''
1462+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1463+ return
1464+
1465+ for app in self.snap_yaml['apps']:
1466+ key = 'socket-group'
1467+ if key not in self.snap_yaml['apps'][app]:
1468+ # We check for required elsewhere
1469+ continue
1470+
1471+ self._verify_valid_socket(app, key)
1472+
1473+ def check_uses(self):
1474+ '''Check uses'''
1475+ if not self.is_snap2 or 'uses' not in self.snap_yaml:
1476+ return
1477+
1478+ for slot in self.snap_yaml['uses']:
1479+ # If the 'type' name is the same as the 'slot' name, then 'type'
1480+ # is optional since the type name and the slot name are the same
1481+ skill_type = slot
1482+ if 'type' in self.snap_yaml['uses'][slot]:
1483+ skill_type = self.snap_yaml['uses'][slot]['type']
1484+
1485+ key = 'type'
1486+ t = 'info'
1487+ n = self._get_check_name(key, extra=slot)
1488+ s = 'OK'
1489+ if not isinstance(self.snap_yaml['uses'][slot][key], str):
1490+ t = 'error'
1491+ s = "invalid %s: %s (not a str)" % \
1492+ (key, self.snap_yaml['uses'][slot][key])
1493+ elif len(self.snap_yaml['uses'][slot][key]) == 0:
1494+ t = 'error'
1495+ s = "'%s' is empty" % key
1496+ self._add_result(t, n, s)
1497+ if t == 'error':
1498+ continue
1499+
1500+ t = 'info'
1501+ n = self._get_check_name(skill_type, extra=slot)
1502+ s = 'OK'
1503+ if skill_type not in self.skill_types:
1504+ t = 'error'
1505+ s = "unknown skill type '%s'" % skill_type
1506+ self._add_result(t, n, s)
1507+ if t == 'error':
1508+ continue
1509+
1510+ min = 1
1511+ if 'type' in self.snap_yaml['uses'][slot]:
1512+ min = 2
1513+ t = 'info'
1514+ n = self._get_check_name('attributes')
1515+ s = 'OK'
1516+ if len(self.snap_yaml['uses'][slot]) < min:
1517+ t = 'error'
1518+ s = "'%s' has no attributes" % slot
1519+ self._add_result(t, n, s)
1520+ if t == 'error':
1521+ continue
1522+
1523+ for attrib in self.snap_yaml['uses'][slot]:
1524+ if attrib == 'type':
1525+ continue
1526+ t = 'info'
1527+ n = self._get_check_name('attributes', app=slot, extra=attrib)
1528+ s = "OK"
1529+ if attrib not in self.skill_types[skill_type]:
1530+ t = 'error'
1531+ s = "unknown attribute '%s' for type '%s'" % (attrib,
1532+ skill_type)
1533+ elif not isinstance(self.snap_yaml['uses'][slot][attrib],
1534+ type(self.skill_types[skill_type][attrib])):
1535+ t = 'error'
1536+ s = "'%s' is not '%s'" % \
1537+ (attrib,
1538+ type(self.skill_types[skill_type][attrib]).__name__)
1539+ self._add_result(t, n, s)
1540+
1541+ def check_apps_uses(self):
1542+ '''Check uses'''
1543+ if not self.is_snap2 or 'apps' not in self.snap_yaml:
1544+ return
1545+
1546+ for app in self.snap_yaml['apps']:
1547+ key = 'uses'
1548+ if key not in self.snap_yaml['apps'][app]:
1549+ continue
1550+
1551+ t = 'info'
1552+ n = self._get_check_name(key, app=app)
1553+ s = "OK"
1554+ if not isinstance(self.snap_yaml['apps'][app][key], list):
1555+ t = 'error'
1556+ s = "invalid '%s' entry: '%s' (not a list)" % (
1557+ key, self.snap_yaml['apps'][app][key])
1558+ elif len(self.snap_yaml['apps'][app][key]) < 1:
1559+ t = 'error'
1560+ s = "invalid %s entry (empty)" % (key)
1561+ self._add_result(t, n, s)
1562+ if t == 'error':
1563+ continue
1564+
1565+ # The skill referenced in the app's 'uses' field can either be a
1566+ # known skill type (when the type name and the name of the skill is
1567+ # the same) or can reference a name in the snap's toplevel 'uses'
1568+ # mapping
1569+ for slot_ref in self.snap_yaml['apps'][app][key]:
1570+ t = 'info'
1571+ n = self._get_check_name('uses_slot_reference',
1572+ app=app,
1573+ extra=slot_ref)
1574+ s = "OK"
1575+ if not isinstance(slot_ref, str):
1576+ t = 'error'
1577+ s = "invalid slot skill name reference: '%s' (not a str)" \
1578+ % slot_ref
1579+ elif slot_ref not in self.skill_types and \
1580+ 'uses' not in self.snap_yaml or \
1581+ slot_ref not in self.snap_yaml['uses']:
1582+ t = 'error'
1583+ s = "unknown slot skill name reference '%s'" % slot_ref
1584+ self._add_result(t, n, s)
1585+
1586+ def check_external_symlinks(self):
1587+ '''Check snap for external symlinks'''
1588+ if not self.is_snap2:
1589+ return
1590+
1591+ if 'type' in self.snap_yaml and \
1592+ self.snap_yaml['type'] not in ['app', 'framework']:
1593+ return
1594+
1595+ t = 'info'
1596+ n = self._get_check_name('external_symlinks')
1597+ s = 'OK'
1598+ links = find_external_symlinks(self._get_unpack_dir(), self.pkg_files)
1599+ if len(links) > 0:
1600+ t = 'error'
1601+ s = 'package contains external symlinks: %s' % ', '.join(links)
1602+ self._add_result(t, n, s)
1603+
1604+ def check_architecture_all(self):
1605+ '''Check if actually architecture all'''
1606+ if not self.is_snap2:
1607+ return
1608+
1609+ if 'architectures' in self.snap_yaml and \
1610+ 'all' not in self.snap_yaml['architectures']:
1611+ return
1612+
1613+ t = 'info'
1614+ n = self._get_check_name('valid_contents_for_architecture')
1615+ s = 'OK'
1616+
1617+ # look for compiled code
1618+ x_binaries = []
1619+ for i in self.pkg_bin_files:
1620+ x_binaries.append(os.path.relpath(i, self._get_unpack_dir()))
1621+ if len(x_binaries) > 0:
1622+ t = 'error'
1623+ s = "found binaries for architecture 'all': %s" % \
1624+ ", ".join(x_binaries)
1625+ self._add_result(t, n, s)
1626+
1627+ def check_architecture_specified_needed(self):
1628+ '''Check if the specified architecture is actually needed'''
1629+ if not self.is_snap2:
1630+ return
1631+
1632+ if 'architectures' in self.snap_yaml and \
1633+ 'all' in self.snap_yaml['architectures']:
1634+ return
1635+
1636+ for arch in self.snap_yaml['architectures']:
1637+ t = 'info'
1638+ n = self._get_check_name('architecture_specified_needed',
1639+ extra=arch)
1640+ s = 'OK'
1641+ if len(self.pkg_bin_files) == 0:
1642+ t = 'warn'
1643+ s = "Could not find compiled binaries for architecture '%s'" \
1644+ % arch
1645+ self._add_result(t, n, s)
1646+
1647+ def check_vcs(self):
1648+ '''Check for VCS files in the package'''
1649+ if not self.is_snap2:
1650+ return
1651+
1652+ t = 'info'
1653+ n = self._get_check_name('vcs_files')
1654+ s = 'OK'
1655+ found = []
1656+ for d in self.vcs_files:
1657+ entries = glob.glob("%s/%s" % (self._get_unpack_dir(), d))
1658+ if len(entries) > 0:
1659+ for i in entries:
1660+ found.append(os.path.relpath(i, self.unpack_dir))
1661+ if len(found) > 0:
1662+ t = 'warn'
1663+ s = 'found VCS files in package: %s' % ", ".join(found)
1664+ self._add_result(t, n, s)
1665
1666=== modified file 'clickreviews/sr_tests.py'
1667--- clickreviews/sr_tests.py 2016-02-10 19:32:10 +0000
1668+++ clickreviews/sr_tests.py 2016-02-11 18:32:45 +0000
1669@@ -15,17 +15,20 @@
1670 # along with this program. If not, see <http://www.gnu.org/licenses/>.
1671
1672 import io
1673-import json
1674 import os
1675 import yaml
1676
1677 from unittest.mock import patch
1678 from unittest import TestCase
1679+from clickreviews.common import (
1680+ check_results as common_check_results
1681+)
1682
1683 # These should be set in the test cases
1684 TEST_SNAP_YAML = ""
1685 TEST_PKGFMT_TYPE = "snap"
1686 TEST_PKGFMT_VERSION = "16.04"
1687+TEST_UNPACK_DIR = "/fake"
1688
1689
1690 #
1691@@ -81,6 +84,11 @@
1692 return (TEST_PKGFMT_TYPE, ver)
1693
1694
1695+def __get_unpack_dir(self):
1696+ '''Pretend we found the unpack dir'''
1697+ return TEST_UNPACK_DIR
1698+
1699+
1700 def create_patches():
1701 # http://docs.python.org/3.4/library/unittest.mock-examples.html
1702 # Mock patching. Don't use decorators but instead patch in setUp() of the
1703@@ -116,6 +124,10 @@
1704 'clickreviews.common.Review._check_innerpath_executable',
1705 _check_innerpath_executable))
1706
1707+ # sr_common
1708+ patches.append(patch('clickreviews.sr_common.SnapReview._get_unpack_dir',
1709+ __get_unpack_dir))
1710+
1711 # pkgfmt
1712 patches.append(patch("clickreviews.sr_common.SnapReview._pkgfmt_type",
1713 _pkgfmt_type))
1714@@ -133,7 +145,6 @@
1715 self._reset_test_data()
1716
1717 def _reset_test_data(self):
1718- # dictionary representing DEBIAN/control
1719 self.test_snap_yaml = dict()
1720 self.set_test_pkgfmt("snap", "16.04")
1721
1722@@ -162,43 +173,10 @@
1723 self.test_snap_yaml["version"],
1724 self.test_snap_yaml["architectures"][0])
1725
1726- #
1727- # check_results(report, expected_counts, expected)
1728- # Verify exact counts of types
1729- # expected_counts={'info': 1, 'warn': 0, 'error': 0}
1730- # self.check_results(report, expected_counts)
1731- # Verify counts of warn and error types
1732- # expected_counts={'info': None, 'warn': 0, 'error': 0}
1733- # self.check_results(report, expected_counts)
1734- # Verify exact messages:
1735- # expected = dict()
1736- # expected['info'] = dict()
1737- # expected['warn'] = dict()
1738- # expected['warn']['skeleton_baz'] = "TODO"
1739- # expected['error'] = dict()
1740- # self.check_results(r, expected=expected)
1741- #
1742 def check_results(self, report,
1743 expected_counts={'info': 1, 'warn': 0, 'error': 0},
1744 expected=None):
1745- if expected is not None:
1746- for t in expected.keys():
1747- for r in expected[t]:
1748- self.assertTrue(r in report[t],
1749- "Could not find '%s' (%s) in:\n%s" %
1750- (r, t, json.dumps(report, indent=2)))
1751- for k in expected[t][r]:
1752- self.assertTrue(k in report[t][r],
1753- "Could not find '%s' (%s) in:\n%s" %
1754- (k, r, json.dumps(report, indent=2)))
1755- self.assertEqual(expected[t][r][k], report[t][r][k])
1756- else:
1757- for k in expected_counts.keys():
1758- if expected_counts[k] is None:
1759- continue
1760- self.assertEqual(len(report[k]), expected_counts[k],
1761- "(%s not equal)\n%s" %
1762- (k, json.dumps(report, indent=2)))
1763+ common_check_results(self, report, expected_counts, expected)
1764
1765 def check_manual_review(self, report, check_name,
1766 result_type='error', manual_review=True):
1767@@ -221,6 +199,10 @@
1768 TEST_PKGFMT_TYPE = t
1769 TEST_PKGFMT_VERSION = v
1770
1771+ def set_test_unpack_dir(self, d):
1772+ global TEST_UNPACK_DIR
1773+ TEST_UNPACK_DIR = d
1774+
1775 def setUp(self):
1776 '''Make sure our patches are applied everywhere'''
1777 patches = create_patches()
1778@@ -236,5 +218,7 @@
1779 TEST_PKGFMT_TYPE = "snap"
1780 global TEST_PKGFMT_VERSION
1781 TEST_PKGFMT_VERSION = "16.04"
1782+ global TEST_UNPACK_DIR
1783+ TEST_UNPACK_DIR = "/fake"
1784
1785 self._reset_test_data()
1786
1787=== modified file 'clickreviews/tests/test_cr_lint.py'
1788--- clickreviews/tests/test_cr_lint.py 2016-02-09 21:45:25 +0000
1789+++ clickreviews/tests/test_cr_lint.py 2016-02-11 18:32:45 +0000
1790@@ -1940,8 +1940,8 @@
1791 return tmp_dir
1792
1793 def test_check_dot_click_root(self):
1794- package = utils.make_package(extra_files=['.click/'],
1795- output_dir=self.mkdtemp())
1796+ package = utils.make_click(extra_files=['.click/'],
1797+ output_dir=self.mkdtemp())
1798 c = ClickReviewLint(package)
1799
1800 c.check_dot_click()
1801
1802=== added file 'clickreviews/tests/test_sr_lint.py'
1803--- clickreviews/tests/test_sr_lint.py 1970-01-01 00:00:00 +0000
1804+++ clickreviews/tests/test_sr_lint.py 2016-02-11 18:32:45 +0000
1805@@ -0,0 +1,2396 @@
1806+'''test_sr_lint.py: tests for the sr_lint module'''
1807+#
1808+# Copyright (C) 2013-2016 Canonical Ltd.
1809+#
1810+# This program is free software: you can redistribute it and/or modify
1811+# it under the terms of the GNU General Public License as published by
1812+# the Free Software Foundation; version 3 of the License.
1813+#
1814+# This program is distributed in the hope that it will be useful,
1815+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1816+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1817+# GNU General Public License for more details.
1818+#
1819+# You should have received a copy of the GNU General Public License
1820+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1821+
1822+from unittest.mock import patch
1823+from unittest import TestCase
1824+import os
1825+import shutil
1826+import tempfile
1827+
1828+from clickreviews.common import cleanup_unpack
1829+from clickreviews.common import check_results as common_check_results
1830+from clickreviews.sr_lint import SnapReviewLint
1831+import clickreviews.sr_tests as sr_tests
1832+from clickreviews.tests import utils
1833+
1834+
1835+class TestSnapReviewLint(sr_tests.TestSnapReview):
1836+ """Tests for the lint review tool."""
1837+ def setUp(self):
1838+ '''Make sure we are snap v2'''
1839+ super().setUp()
1840+ self.set_test_pkgfmt("snap", "16.04")
1841+
1842+ def _create_ports(self):
1843+ ports = {'internal': {'int1': {"port": '8081/tcp', "negotiable": True}},
1844+ 'external': {'ext1': {"port": '80/tcp', "negotiable": False},
1845+ 'ext2': {"port": '88/udp'}
1846+ }
1847+ }
1848+ return ports
1849+
1850+ def _create_top_uses(self):
1851+ uses = {'skill-caps': {'type': 'migration-skill',
1852+ 'caps': ['network-client']},
1853+ 'skill-override': {'type': 'migration-skill',
1854+ 'security-override': {"read_path": "/foo/",
1855+ "seccomp": "abc"}},
1856+ 'skill-policy': {'type': 'migration-skill',
1857+ 'security-policy': {"apparmor": "meta/aa",
1858+ "seccomp": "meta/sc"}},
1859+ 'skill-template': {'type': 'migration-skill',
1860+ 'security-template': "unconfined"}
1861+ }
1862+ return uses
1863+
1864+ def _create_apps_uses(self):
1865+ uses = {'app1': {'uses': ['skill-caps']},
1866+ 'app2': {'uses': ['skill-caps', 'skill-template']},
1867+ 'app3': {'uses': ['skill-template', 'skill-override']},
1868+ 'app4': {'uses': ['skill-policy']},
1869+ }
1870+ return uses
1871+
1872+ def patch_frameworks(self):
1873+ def _mock_frameworks(self, overrides=None):
1874+ self.FRAMEWORKS = {
1875+ 'docker-1.3': 'obsolete',
1876+ 'docker': 'available',
1877+ 'hello-dbus-fwk': 'available',
1878+ 'some-fwk': 'deprecated',
1879+ }
1880+ self.AVAILABLE_FRAMEWORKS = ['docker', 'hello-dbus-fwk']
1881+ self.OBSOLETE_FRAMEWORKS = ['docker-1.3']
1882+ self.DEPRECATED_FRAMEWORKS = ['some-fwk']
1883+ p = patch('clickreviews.frameworks.Frameworks.__init__',
1884+ _mock_frameworks)
1885+ p.start()
1886+ self.addCleanup(p.stop)
1887+
1888+ def test_all_checks_as_v2(self):
1889+ '''Test snap v2 has checks'''
1890+ self.set_test_pkgfmt("snap", "16.04")
1891+ c = SnapReviewLint(self.test_name)
1892+ c.do_checks()
1893+ sum = 0
1894+ for i in c.click_report:
1895+ sum += len(c.click_report[i])
1896+ self.assertTrue(sum != 0)
1897+
1898+ def test_all_checks_as_v1(self):
1899+ '''Test snap v1 has no checks'''
1900+ self.set_test_pkgfmt("snap", "15.04")
1901+ c = SnapReviewLint(self.test_name)
1902+ c.do_checks()
1903+ sum = 0
1904+ for i in c.click_report:
1905+ sum += len(c.click_report[i])
1906+ self.assertTrue(sum == 0)
1907+
1908+ def test_all_checks_as_click(self):
1909+ '''Test click format has no checks'''
1910+ self.set_test_pkgfmt("click", "0.4")
1911+ c = SnapReviewLint(self.test_name)
1912+ c.do_checks()
1913+ sum = 0
1914+ for i in c.click_report:
1915+ sum += len(c.click_report[i])
1916+ self.assertTrue(sum == 0)
1917+
1918+ def test_check_frameworks_none(self):
1919+ '''Test check_frameworks() - none'''
1920+ self.patch_frameworks()
1921+ self.set_test_snap_yaml("frameworks", None)
1922+ c = SnapReviewLint(self.test_name)
1923+ c.check_frameworks()
1924+ r = c.click_report
1925+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1926+ self.check_results(r, expected_counts)
1927+
1928+ def test_check_frameworks_empty(self):
1929+ '''Test check_frameworks() - empty'''
1930+ self.patch_frameworks()
1931+ self.set_test_snap_yaml("frameworks", [])
1932+ c = SnapReviewLint(self.test_name)
1933+ c.check_frameworks()
1934+ r = c.click_report
1935+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1936+ self.check_results(r, expected_counts)
1937+
1938+ def test_check_frameworks_multiple(self):
1939+ '''Test check_frameworks() - multiple'''
1940+ self.patch_frameworks()
1941+ self.set_test_snap_yaml("frameworks", ['docker', 'hello-dbus-fwk'])
1942+ c = SnapReviewLint(self.test_name)
1943+ c.check_frameworks()
1944+ r = c.click_report
1945+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1946+ self.check_results(r, expected_counts)
1947+
1948+ def test_check_frameworks_bad(self):
1949+ '''Test check_frameworks() - bad'''
1950+ self.patch_frameworks()
1951+ self.set_test_snap_yaml("frameworks", "bad")
1952+ c = SnapReviewLint(self.test_name)
1953+ c.check_frameworks()
1954+ r = c.click_report
1955+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1956+ self.check_results(r, expected_counts)
1957+
1958+ def test_check_frameworks_nonexistent(self):
1959+ '''Test check_frameworks() - nonexistent'''
1960+ self.patch_frameworks()
1961+ self.set_test_snap_yaml("frameworks", ["nonexistent"])
1962+ c = SnapReviewLint(self.test_name)
1963+ c.check_frameworks()
1964+ r = c.click_report
1965+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1966+ self.check_results(r, expected_counts)
1967+
1968+ def test_check_frameworks_deprecated(self):
1969+ '''Test check_frameworks() - deprecated'''
1970+ self.patch_frameworks()
1971+ self.set_test_snap_yaml("frameworks", ["some-fwk"])
1972+ c = SnapReviewLint(self.test_name)
1973+ c.check_frameworks()
1974+ r = c.click_report
1975+ expected_counts = {'info': None, 'warn': 1, 'error': 0}
1976+ self.check_results(r, expected_counts)
1977+
1978+ def test_check_frameworks_obsolete(self):
1979+ '''Test check_frameworks() - obsolete'''
1980+ self.patch_frameworks()
1981+ self.set_test_snap_yaml("frameworks", ["docker-1.3"])
1982+ c = SnapReviewLint(self.test_name)
1983+ c.check_frameworks()
1984+ r = c.click_report
1985+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1986+ self.check_results(r, expected_counts)
1987+
1988+ def test_check_name_toplevel(self):
1989+ '''Test check_name - toplevel'''
1990+ self.set_test_snap_yaml("name", "foo")
1991+ c = SnapReviewLint(self.test_name)
1992+ c.check_name()
1993+ r = c.click_report
1994+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1995+ self.check_results(r, expected_counts)
1996+
1997+ def test_check_name_flat(self):
1998+ '''Test check_name - obsoleted flat'''
1999+ self.set_test_snap_yaml("name", "foo.bar")
2000+ c = SnapReviewLint(self.test_name)
2001+ c.check_name()
2002+ r = c.click_report
2003+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2004+ self.check_results(r, expected_counts)
2005+
2006+ def test_check_name_reverse_domain(self):
2007+ '''Test check_name - obsoleted reverse domain'''
2008+ self.set_test_snap_yaml("name", "com.ubuntu.develeper.baz.foo")
2009+ c = SnapReviewLint(self.test_name)
2010+ c.check_name()
2011+ r = c.click_report
2012+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2013+ self.check_results(r, expected_counts)
2014+
2015+ def test_check_name_bad(self):
2016+ '''Test check_name - bad'''
2017+ self.set_test_snap_yaml("name", "foo?bar")
2018+ c = SnapReviewLint(self.test_name)
2019+ c.check_name()
2020+ r = c.click_report
2021+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2022+ self.check_results(r, expected_counts)
2023+
2024+ def test_check_name_bad2(self):
2025+ '''Test check_name - empty'''
2026+ self.set_test_snap_yaml("name", "")
2027+ c = SnapReviewLint(self.test_name)
2028+ c.check_name()
2029+ r = c.click_report
2030+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2031+ self.check_results(r, expected_counts)
2032+
2033+ def test_check_name_bad3(self):
2034+ '''Test check_name - list'''
2035+ self.set_test_snap_yaml("name", [])
2036+ c = SnapReviewLint(self.test_name)
2037+ c.check_name()
2038+ r = c.click_report
2039+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2040+ self.check_results(r, expected_counts)
2041+
2042+ def test_check_name_bad4(self):
2043+ '''Test check_name - dict'''
2044+ self.set_test_snap_yaml("name", {})
2045+ c = SnapReviewLint(self.test_name)
2046+ c.check_name()
2047+ r = c.click_report
2048+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2049+ self.check_results(r, expected_counts)
2050+
2051+ def test_check_name_missing(self):
2052+ '''Test check_name - missing'''
2053+ self.set_test_snap_yaml("name", None)
2054+ c = SnapReviewLint(self.test_name)
2055+ c.check_name()
2056+ r = c.click_report
2057+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2058+ self.check_results(r, expected_counts)
2059+
2060+ def test_check_version(self):
2061+ '''Test check_version'''
2062+ self.set_test_snap_yaml("version", 1)
2063+ c = SnapReviewLint(self.test_name)
2064+ c.check_version()
2065+ r = c.click_report
2066+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2067+ self.check_results(r, expected_counts)
2068+
2069+ def test_check_version1(self):
2070+ '''Test check_version - integer'''
2071+ self.set_test_snap_yaml("version", 1)
2072+ c = SnapReviewLint(self.test_name)
2073+ c.check_version()
2074+ r = c.click_report
2075+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2076+ self.check_results(r, expected_counts)
2077+
2078+ def test_check_version2(self):
2079+ '''Test check_version - float'''
2080+ self.set_test_snap_yaml("version", 1.0)
2081+ c = SnapReviewLint(self.test_name)
2082+ c.check_version()
2083+ r = c.click_report
2084+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2085+ self.check_results(r, expected_counts)
2086+
2087+ def test_check_version3(self):
2088+ '''Test check_version - MAJOR.MINOR.MICRO'''
2089+ self.set_test_snap_yaml("version", "1.0.1")
2090+ c = SnapReviewLint(self.test_name)
2091+ c.check_version()
2092+ r = c.click_report
2093+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2094+ self.check_results(r, expected_counts)
2095+
2096+ def test_check_version4(self):
2097+ '''Test check_version - str'''
2098+ self.set_test_snap_yaml("version", "1.0a")
2099+ c = SnapReviewLint(self.test_name)
2100+ c.check_version()
2101+ r = c.click_report
2102+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2103+ self.check_results(r, expected_counts)
2104+
2105+ def test_check_version5(self):
2106+ '''Test check_version - alpha'''
2107+ self.set_test_snap_yaml("version", "a.b")
2108+ c = SnapReviewLint(self.test_name)
2109+ c.check_version()
2110+ r = c.click_report
2111+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2112+ self.check_results(r, expected_counts)
2113+
2114+ def test_check_version_bad(self):
2115+ '''Test check_version - bad'''
2116+ self.set_test_snap_yaml("version", "foo?bar")
2117+ c = SnapReviewLint(self.test_name)
2118+ c.check_version()
2119+ r = c.click_report
2120+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2121+ self.check_results(r, expected_counts)
2122+
2123+ def test_check_version_bad2(self):
2124+ '''Test check_version - empty'''
2125+ self.set_test_snap_yaml("version", "")
2126+ c = SnapReviewLint(self.test_name)
2127+ c.check_version()
2128+ r = c.click_report
2129+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2130+ self.check_results(r, expected_counts)
2131+
2132+ def test_check_version_bad3(self):
2133+ '''Test check_version - list'''
2134+ self.set_test_snap_yaml("version", [])
2135+ c = SnapReviewLint(self.test_name)
2136+ c.check_version()
2137+ r = c.click_report
2138+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2139+ self.check_results(r, expected_counts)
2140+
2141+ def test_check_version_bad4(self):
2142+ '''Test check_version - dict'''
2143+ self.set_test_snap_yaml("version", {})
2144+ c = SnapReviewLint(self.test_name)
2145+ c.check_version()
2146+ r = c.click_report
2147+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2148+ self.check_results(r, expected_counts)
2149+
2150+ def test_check_version_missing(self):
2151+ '''Test check_version - missing'''
2152+ self.set_test_snap_yaml("version", None)
2153+ c = SnapReviewLint(self.test_name)
2154+ c.check_version()
2155+ r = c.click_report
2156+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2157+ self.check_results(r, expected_counts)
2158+
2159+ def test_check_type(self):
2160+ '''Test check_type - unspecified'''
2161+ self.set_test_snap_yaml("type", None)
2162+ c = SnapReviewLint(self.test_name)
2163+ c.check_type()
2164+ r = c.click_report
2165+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2166+ self.check_results(r, expected_counts)
2167+
2168+ def test_check_type_app(self):
2169+ '''Test check_type - app'''
2170+ self.set_test_snap_yaml("type", "app")
2171+ c = SnapReviewLint(self.test_name)
2172+ c.check_type()
2173+ r = c.click_report
2174+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2175+ self.check_results(r, expected_counts)
2176+
2177+ def test_check_type_framework(self):
2178+ '''Test check_type - framework'''
2179+ self.set_test_snap_yaml("type", "framework")
2180+ c = SnapReviewLint(self.test_name)
2181+ c.check_type()
2182+ r = c.click_report
2183+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2184+ self.check_results(r, expected_counts)
2185+
2186+ def test_check_type_redflagged(self):
2187+ '''Test check_type_redflagged - unspecified'''
2188+ self.set_test_snap_yaml("type", None)
2189+ c = SnapReviewLint(self.test_name)
2190+ c.check_type_redflagged()
2191+ r = c.click_report
2192+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2193+ self.check_results(r, expected_counts)
2194+
2195+ def test_check_type_redflagged_app(self):
2196+ '''Test check_type_redflagged - app'''
2197+ self.set_test_snap_yaml("type", "app")
2198+ c = SnapReviewLint(self.test_name)
2199+ c.check_type_redflagged()
2200+ r = c.click_report
2201+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2202+ self.check_results(r, expected_counts)
2203+
2204+ def test_check_type_redflagged_framework(self):
2205+ '''Test check_type_redflagged - framework'''
2206+ self.set_test_snap_yaml("type", "framework")
2207+ c = SnapReviewLint(self.test_name)
2208+ c.check_type_redflagged()
2209+ r = c.click_report
2210+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2211+ self.check_results(r, expected_counts)
2212+
2213+ def test_check_type_redflagged_gadget(self):
2214+ '''Test check_type_redflagged - gadget'''
2215+ self.set_test_snap_yaml("type", "gadget")
2216+ c = SnapReviewLint(self.test_name)
2217+ c.check_type_redflagged()
2218+ r = c.click_report
2219+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2220+ self.check_results(r, expected_counts)
2221+
2222+ def test_check_type_redflagged_kernel(self):
2223+ '''Test check_type_redflagged - kernel'''
2224+ self.set_test_snap_yaml("type", "kernel")
2225+ c = SnapReviewLint(self.test_name)
2226+ c.check_type_redflagged()
2227+ r = c.click_report
2228+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2229+ self.check_results(r, expected_counts)
2230+
2231+ def test_check_type_redflagged_os(self):
2232+ '''Test check_type_redflagged - os'''
2233+ self.set_test_snap_yaml("type", "os")
2234+ c = SnapReviewLint(self.test_name)
2235+ c.check_type_redflagged()
2236+ r = c.click_report
2237+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2238+ self.check_results(r, expected_counts)
2239+
2240+ def test_check_type_unknown(self):
2241+ '''Test check_type - unknown'''
2242+ self.set_test_snap_yaml("type", "nonexistent")
2243+ c = SnapReviewLint(self.test_name)
2244+ c.check_type()
2245+ r = c.click_report
2246+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2247+ self.check_results(r, expected_counts)
2248+
2249+ def test_check_icon(self):
2250+ '''Test check_icon()'''
2251+ self.set_test_snap_yaml("icon", "someicon")
2252+ self.set_test_snap_yaml("type", "gadget")
2253+ self.set_test_unpack_dir = "/nonexistent"
2254+ c = SnapReviewLint(self.test_name)
2255+ c.pkg_files.append(os.path.join(c._get_unpack_dir(), 'someicon'))
2256+ c.check_icon()
2257+ r = c.click_report
2258+ expected_counts = {'info': 4, 'warn': 0, 'error': 0}
2259+ self.check_results(r, expected_counts)
2260+
2261+ def test_check_icon_no_gadget(self):
2262+ '''Test check_icon() - no gadget'''
2263+ self.set_test_snap_yaml("icon", "someicon")
2264+ self.set_test_unpack_dir = "/nonexistent"
2265+ c = SnapReviewLint(self.test_name)
2266+ c.pkg_files.append(os.path.join(c._get_unpack_dir(), 'someicon'))
2267+ c.check_icon()
2268+ r = c.click_report
2269+ expected_counts = {'info': None, 'warn': 1, 'error': 0}
2270+ self.check_results(r, expected_counts)
2271+
2272+ def test_check_icon_unspecified(self):
2273+ '''Test check_icon() - unspecified'''
2274+ self.set_test_snap_yaml("icon", None)
2275+ self.set_test_snap_yaml("type", "gadget")
2276+ c = SnapReviewLint(self.test_name)
2277+ c.check_icon()
2278+ r = c.click_report
2279+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
2280+ self.check_results(r, expected_counts)
2281+
2282+ def test_check_icon_empty(self):
2283+ '''Test check_icon() - empty'''
2284+ self.set_test_snap_yaml("icon", "")
2285+ self.set_test_snap_yaml("type", "gadget")
2286+ c = SnapReviewLint(self.test_name)
2287+ c.check_icon()
2288+ r = c.click_report
2289+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2290+ self.check_results(r, expected_counts)
2291+
2292+ def test_check_icon_absolute_path(self):
2293+ '''Test check_icon() - absolute path'''
2294+ self.set_test_snap_yaml("icon", "/foo/bar/someicon")
2295+ self.set_test_snap_yaml("type", "gadget")
2296+ c = SnapReviewLint(self.test_name)
2297+ c.pkg_files.append('/foo/bar/someicon')
2298+ c.check_icon()
2299+ r = c.click_report
2300+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2301+ self.check_results(r, expected_counts)
2302+
2303+ def test_check_icon_missing(self):
2304+ '''Test check_icon() - missing icon'''
2305+ self.set_test_snap_yaml("icon", "someicon")
2306+ self.set_test_snap_yaml("type", "gadget")
2307+ self.set_test_unpack_dir = "/nonexistent"
2308+ c = SnapReviewLint(self.test_name)
2309+ # since the icon isn't in c.pkg_files, don't add it for this test
2310+ # c.pkg_files.append(os.path.join(c._get_unpack_dir(), 'someicon'))
2311+ c.check_icon()
2312+ r = c.click_report
2313+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2314+ self.check_results(r, expected_counts)
2315+
2316+ def test_check_architectures_bad(self):
2317+ '''Test check_architectures() - bad (dict)'''
2318+ self.set_test_snap_yaml("architectures", {})
2319+ c = SnapReviewLint(self.test_name)
2320+ c.check_architectures()
2321+ r = c.click_report
2322+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2323+ self.check_results(r, expected_counts)
2324+
2325+ def test_check_architectures_missing(self):
2326+ '''Test check_architectures() (missing)'''
2327+ self.set_test_snap_yaml("architectures", None)
2328+ c = SnapReviewLint(self.test_name)
2329+ c.check_architectures()
2330+ r = c.click_report
2331+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2332+ self.check_results(r, expected_counts)
2333+
2334+ def test_check_architectures_all(self):
2335+ '''Test check_architectures() (all)'''
2336+ self.set_test_snap_yaml("architectures", ["all"])
2337+ c = SnapReviewLint(self.test_name)
2338+ c.check_architectures()
2339+ r = c.click_report
2340+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2341+ self.check_results(r, expected_counts)
2342+
2343+ def test_check_architectures_single_armhf(self):
2344+ '''Test check_architectures() (single arch, armhf)'''
2345+ self.set_test_snap_yaml("architectures", ["armhf"])
2346+ c = SnapReviewLint(self.test_name)
2347+ c.check_architectures()
2348+ r = c.click_report
2349+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2350+ self.check_results(r, expected_counts)
2351+
2352+ def test_check_architectures_single_arm64(self):
2353+ '''Test check_architectures() (single arch, arm64)'''
2354+ self.set_test_snap_yaml("architectures", ["arm64"])
2355+ c = SnapReviewLint(self.test_name)
2356+ c.check_architectures()
2357+ r = c.click_report
2358+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2359+ self.check_results(r, expected_counts)
2360+
2361+ def test_check_architectures_single_i386(self):
2362+ '''Test check_architectures() (single arch, i386)'''
2363+ self.set_test_snap_yaml("architectures", ["i386"])
2364+ c = SnapReviewLint(self.test_name)
2365+ c.check_architectures()
2366+ r = c.click_report
2367+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2368+ self.check_results(r, expected_counts)
2369+
2370+ def test_check_architectures_single_amd64(self):
2371+ '''Test check_architectures() (single arch, amd64)'''
2372+ self.set_test_snap_yaml("architectures", ["amd64"])
2373+ c = SnapReviewLint(self.test_name)
2374+ c.check_architectures()
2375+ r = c.click_report
2376+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2377+ self.check_results(r, expected_counts)
2378+
2379+ def test_check_architectures_single_nonexistent(self):
2380+ '''Test check_architectures() (single nonexistent arch)'''
2381+ self.set_test_snap_yaml("architectures", ["nonexistent"])
2382+ c = SnapReviewLint(self.test_name)
2383+ c.check_architectures()
2384+ r = c.click_report
2385+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2386+ self.check_results(r, expected_counts)
2387+
2388+ def test_check_snappy_valid_arch_multi(self):
2389+ '''Test check_architectures() (valid multi)'''
2390+ self.set_test_snap_yaml("architectures", ["amd64", "armhf"])
2391+ c = SnapReviewLint(self.test_name)
2392+ c.check_architectures()
2393+ r = c.click_report
2394+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2395+ self.check_results(r, expected_counts)
2396+
2397+ def test_check_snappy_valid_arch_multi2(self):
2398+ '''Test check_architectures() (valid multi2)'''
2399+ self.set_test_snap_yaml("architectures", ["armhf", "arm64", "i386"])
2400+ c = SnapReviewLint(self.test_name)
2401+ c.check_architectures()
2402+ r = c.click_report
2403+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2404+ self.check_results(r, expected_counts)
2405+
2406+ def test_check_unknown_entries(self):
2407+ '''Test check_unknown_entries - none'''
2408+ c = SnapReviewLint(self.test_name)
2409+ c.check_unknown_entries()
2410+ r = c.click_report
2411+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2412+ self.check_results(r, expected_counts)
2413+
2414+ def test_check_unknown_entries2(self):
2415+ '''Test check_unknown_entries - one'''
2416+ self.set_test_snap_yaml("nonexistent", "bar")
2417+ c = SnapReviewLint(self.test_name)
2418+ c.check_unknown_entries()
2419+ r = c.click_report
2420+ expected_counts = {'info': 0, 'warn': 1, 'error': 0}
2421+ self.check_results(r, expected_counts)
2422+
2423+ def test_check_config(self):
2424+ '''Test check_config()'''
2425+ c = SnapReviewLint(self.test_name)
2426+ self.set_test_unpack_dir("/nonexistent")
2427+ c.pkg_files.append(os.path.join(c._get_unpack_dir(),
2428+ 'meta/hooks/config'))
2429+ c.check_config()
2430+ r = c.click_report
2431+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2432+ self.check_results(r, expected_counts)
2433+
2434+ def test_check_config_nonexecutable(self):
2435+ '''Test check_config() - not executable'''
2436+ c = SnapReviewLint(self.test_name)
2437+ self.set_test_unpack_dir("/nonexistent.nonexec")
2438+ c.pkg_files.append(os.path.join(c._get_unpack_dir(),
2439+ 'meta/hooks/config'))
2440+ c.check_config()
2441+ r = c.click_report
2442+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2443+ self.check_results(r, expected_counts)
2444+
2445+ def test_check_description(self):
2446+ '''Test check_description'''
2447+ self.set_test_snap_yaml("description", "This is a test description")
2448+ c = SnapReviewLint(self.test_name)
2449+ c.check_description()
2450+ r = c.click_report
2451+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
2452+ self.check_results(r, expected_counts)
2453+
2454+ def test_check_description_missing(self):
2455+ '''Test check_description - not present'''
2456+ self.set_test_snap_yaml("description", None)
2457+ c = SnapReviewLint(self.test_name)
2458+ c.check_description()
2459+ r = c.click_report
2460+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2461+ self.check_results(r, expected_counts)
2462+
2463+ def test_check_description_bad(self):
2464+ '''Test check_description - short'''
2465+ self.set_test_snap_yaml("description", "a")
2466+ c = SnapReviewLint(self.test_name)
2467+ c.check_description()
2468+ r = c.click_report
2469+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
2470+ self.check_results(r, expected_counts)
2471+
2472+ def test_check_description_bad2(self):
2473+ '''Test check_description - empty'''
2474+ self.set_test_snap_yaml("description", "")
2475+ c = SnapReviewLint(self.test_name)
2476+ c.check_description()
2477+ r = c.click_report
2478+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2479+ self.check_results(r, expected_counts)
2480+
2481+ def test_check_description_bad3(self):
2482+ '''Test check_description - list'''
2483+ self.set_test_snap_yaml("description", [])
2484+ c = SnapReviewLint(self.test_name)
2485+ c.check_description()
2486+ r = c.click_report
2487+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2488+ self.check_results(r, expected_counts)
2489+
2490+ def test_check_license_agreement(self):
2491+ '''Test check_license_agreement'''
2492+ self.set_test_snap_yaml("license-agreement",
2493+ "This is a test license_agreement")
2494+ c = SnapReviewLint(self.test_name)
2495+ c.check_license_agreement()
2496+ r = c.click_report
2497+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
2498+ self.check_results(r, expected_counts)
2499+
2500+ def test_check_license_agreement_missing(self):
2501+ '''Test check_license_agreement - not present'''
2502+ self.set_test_snap_yaml("license-agreement", None)
2503+ c = SnapReviewLint(self.test_name)
2504+ c.check_license_agreement()
2505+ r = c.click_report
2506+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2507+ self.check_results(r, expected_counts)
2508+
2509+ def test_check_license_agreement_bad(self):
2510+ '''Test check_license_agreement - empty'''
2511+ self.set_test_snap_yaml("license-agreement", "")
2512+ c = SnapReviewLint(self.test_name)
2513+ c.check_license_agreement()
2514+ r = c.click_report
2515+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2516+ self.check_results(r, expected_counts)
2517+
2518+ def test_check_license_agreement_bad2(self):
2519+ '''Test check_license_agreement - list'''
2520+ self.set_test_snap_yaml("license-agreement", [])
2521+ c = SnapReviewLint(self.test_name)
2522+ c.check_license_agreement()
2523+ r = c.click_report
2524+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2525+ self.check_results(r, expected_counts)
2526+
2527+ def test_check_license_version(self):
2528+ '''Test check_license_version'''
2529+ self.set_test_snap_yaml("license-version",
2530+ "This is a test license_version")
2531+ c = SnapReviewLint(self.test_name)
2532+ c.check_license_version()
2533+ r = c.click_report
2534+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
2535+ self.check_results(r, expected_counts)
2536+
2537+ def test_check_license_version_missing(self):
2538+ '''Test check_license_version - not present'''
2539+ self.set_test_snap_yaml("license-version", None)
2540+ c = SnapReviewLint(self.test_name)
2541+ c.check_license_version()
2542+ r = c.click_report
2543+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2544+ self.check_results(r, expected_counts)
2545+
2546+ def test_check_license_version_bad(self):
2547+ '''Test check_license_version - empty'''
2548+ self.set_test_snap_yaml("license-version", "")
2549+ c = SnapReviewLint(self.test_name)
2550+ c.check_license_version()
2551+ r = c.click_report
2552+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2553+ self.check_results(r, expected_counts)
2554+
2555+ def test_check_license_version_bad2(self):
2556+ '''Test check_license_version - list'''
2557+ self.set_test_snap_yaml("license-version", [])
2558+ c = SnapReviewLint(self.test_name)
2559+ c.check_license_version()
2560+ r = c.click_report
2561+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2562+ self.check_results(r, expected_counts)
2563+
2564+ def test_check_summary(self):
2565+ '''Test check_summary'''
2566+ self.set_test_snap_yaml("summary", "This is a test summary")
2567+ c = SnapReviewLint(self.test_name)
2568+ c.check_summary()
2569+ r = c.click_report
2570+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
2571+ self.check_results(r, expected_counts)
2572+
2573+ def test_check_summary_missing(self):
2574+ '''Test check_summary - not present'''
2575+ self.set_test_snap_yaml("summary", None)
2576+ c = SnapReviewLint(self.test_name)
2577+ c.check_summary()
2578+ r = c.click_report
2579+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2580+ self.check_results(r, expected_counts)
2581+
2582+ def test_check_summary_bad(self):
2583+ '''Test check_summary - short'''
2584+ self.set_test_snap_yaml("summary", "a")
2585+ c = SnapReviewLint(self.test_name)
2586+ c.check_summary()
2587+ r = c.click_report
2588+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
2589+ self.check_results(r, expected_counts)
2590+
2591+ def test_check_summary_bad2(self):
2592+ '''Test check_summary - empty'''
2593+ self.set_test_snap_yaml("summary", "")
2594+ c = SnapReviewLint(self.test_name)
2595+ c.check_summary()
2596+ r = c.click_report
2597+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2598+ self.check_results(r, expected_counts)
2599+
2600+ def test_check_summary_bad3(self):
2601+ '''Test check_summary - list'''
2602+ self.set_test_snap_yaml("summary", [])
2603+ c = SnapReviewLint(self.test_name)
2604+ c.check_summary()
2605+ r = c.click_report
2606+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2607+ self.check_results(r, expected_counts)
2608+
2609+ def test_check_apps_one_command(self):
2610+ '''Test check_apps() - one command'''
2611+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/foo"},
2612+ })
2613+ c = SnapReviewLint(self.test_name)
2614+ c.check_apps()
2615+ r = c.click_report
2616+ expected_counts = {'info': 5, 'warn': 0, 'error': 0}
2617+ self.check_results(r, expected_counts)
2618+
2619+ def test_check_apps_one_daemon(self):
2620+ '''Test check_apps() - one daemon'''
2621+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/foo",
2622+ "daemon": "single"},
2623+ })
2624+ c = SnapReviewLint(self.test_name)
2625+ c.check_apps()
2626+ r = c.click_report
2627+ expected_counts = {'info': 5, 'warn': 0, 'error': 0}
2628+ self.check_results(r, expected_counts)
2629+
2630+ def test_check_apps_two_commands(self):
2631+ '''Test check_apps() - two commands'''
2632+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/foo"},
2633+ "bar": {"command": "bin/bar"},
2634+ })
2635+ c = SnapReviewLint(self.test_name)
2636+ c.check_apps()
2637+ r = c.click_report
2638+ expected_counts = {'info': 8, 'warn': 0, 'error': 0}
2639+ self.check_results(r, expected_counts)
2640+
2641+ def test_check_apps_command_plus_daemon(self):
2642+ '''Test check_apps() - command and daemon'''
2643+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/foo"},
2644+ "bar": {"command": "bin/bar",
2645+ "daemon": "single"},
2646+ })
2647+ c = SnapReviewLint(self.test_name)
2648+ c.check_apps()
2649+ r = c.click_report
2650+ expected_counts = {'info': 8, 'warn': 0, 'error': 0}
2651+ self.check_results(r, expected_counts)
2652+
2653+ def test_check_apps_two_daemons(self):
2654+ '''Test check_apps() - command and daemon'''
2655+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/foo",
2656+ "daemon": "single"},
2657+ "bar": {"command": "bin/bar",
2658+ "daemon": "single"},
2659+ })
2660+ c = SnapReviewLint(self.test_name)
2661+ c.check_apps()
2662+ r = c.click_report
2663+ expected_counts = {'info': 8, 'warn': 0, 'error': 0}
2664+ self.check_results(r, expected_counts)
2665+
2666+ def test_check_apps_missing(self):
2667+ '''Test check_apps() - missing'''
2668+ self.set_test_snap_yaml("apps", None)
2669+ c = SnapReviewLint(self.test_name)
2670+ c.check_apps()
2671+ r = c.click_report
2672+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2673+ self.check_results(r, expected_counts)
2674+
2675+ def test_check_apps_bad(self):
2676+ '''Test check_apps() - bad'''
2677+ self.set_test_snap_yaml("apps", [])
2678+ c = SnapReviewLint(self.test_name)
2679+ c.check_apps()
2680+ r = c.click_report
2681+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2682+ self.check_results(r, expected_counts)
2683+
2684+ def test_check_apps_bad2(self):
2685+ '''Test check_apps() - empty'''
2686+ self.set_test_snap_yaml("apps", {})
2687+ c = SnapReviewLint(self.test_name)
2688+ c.check_apps()
2689+ r = c.click_report
2690+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2691+ self.check_results(r, expected_counts)
2692+
2693+ def test_check_apps_bad3(self):
2694+ '''Test check_apps() - missing command'''
2695+ self.set_test_snap_yaml("apps", {"foo": {"daemon": "single"},
2696+ })
2697+ c = SnapReviewLint(self.test_name)
2698+ c.check_apps()
2699+ r = c.click_report
2700+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2701+ self.check_results(r, expected_counts)
2702+
2703+ def test_check_apps_bad4(self):
2704+ '''Test check_apps() - unknown field'''
2705+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/foo",
2706+ "nonexistent": "abc"},
2707+ })
2708+ c = SnapReviewLint(self.test_name)
2709+ c.check_apps()
2710+ r = c.click_report
2711+ expected_counts = {'info': None, 'warn': 1, 'error': 0}
2712+ self.check_results(r, expected_counts)
2713+
2714+ def test_check_apps_bad5(self):
2715+ '''Test check_apps() - invalid field'''
2716+ self.set_test_snap_yaml("apps", {"foo": []})
2717+ c = SnapReviewLint(self.test_name)
2718+ c.check_apps()
2719+ r = c.click_report
2720+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2721+ self.check_results(r, expected_counts)
2722+
2723+ def test_check_apps_bad6(self):
2724+ '''Test check_apps() - empty fields'''
2725+ self.set_test_snap_yaml("apps", {"foo": {}})
2726+ c = SnapReviewLint(self.test_name)
2727+ c.check_apps()
2728+ r = c.click_report
2729+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2730+ self.check_results(r, expected_counts)
2731+
2732+ def test_check_apps_command(self):
2733+ '''Test check_apps_command()'''
2734+ cmd = "bin/foo"
2735+ self.set_test_snap_yaml("apps", {"foo": {"command": cmd},
2736+ })
2737+ c = SnapReviewLint(self.test_name)
2738+ c.pkg_files.append(os.path.join('/fake', cmd))
2739+ c.check_apps_command()
2740+ r = c.click_report
2741+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2742+ self.check_results(r, expected_counts)
2743+
2744+ def test_check_apps_command_missing(self):
2745+ '''Test check_apps_command() - missing'''
2746+ self.set_test_snap_yaml("apps", {"foo": {}})
2747+ c = SnapReviewLint(self.test_name)
2748+ c.check_apps_command()
2749+ r = c.click_report
2750+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
2751+ self.check_results(r, expected_counts)
2752+
2753+ def test_check_apps_command_empty(self):
2754+ '''Test check_apps_command() - empty'''
2755+ self.set_test_snap_yaml("apps", {"foo": {"command": ""},
2756+ })
2757+ c = SnapReviewLint(self.test_name)
2758+ c.check_apps_command()
2759+ r = c.click_report
2760+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2761+ self.check_results(r, expected_counts)
2762+
2763+ def test_check_apps_command_invalid(self):
2764+ '''Test check_apps_command() - list'''
2765+ self.set_test_snap_yaml("apps", {"foo": {"command": []},
2766+ })
2767+ c = SnapReviewLint(self.test_name)
2768+ c.check_apps_command()
2769+ r = c.click_report
2770+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2771+ self.check_results(r, expected_counts)
2772+
2773+ def test_check_apps_command_nonexistent(self):
2774+ '''Test check_apps_command() - nonexistent'''
2775+ cmd = "bin/foo"
2776+ self.set_test_snap_yaml("apps", {"foo": {"command": cmd},
2777+ })
2778+ c = SnapReviewLint(self.test_name)
2779+ c.check_apps_command()
2780+ r = c.click_report
2781+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2782+ self.check_results(r, expected_counts)
2783+
2784+ def test_check_apps_stop(self):
2785+ '''Test check_apps_stop()'''
2786+ cmd = "bin/foo"
2787+ self.set_test_snap_yaml("apps", {"foo": {"stop": cmd},
2788+ })
2789+ c = SnapReviewLint(self.test_name)
2790+ c.pkg_files.append(os.path.join('/fake', cmd))
2791+ c.check_apps_stop()
2792+ r = c.click_report
2793+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2794+ self.check_results(r, expected_counts)
2795+
2796+ def test_check_apps_stop_missing(self):
2797+ '''Test check_apps_stop() - missing'''
2798+ self.set_test_snap_yaml("apps", {"foo": {}})
2799+ c = SnapReviewLint(self.test_name)
2800+ c.check_apps_stop()
2801+ r = c.click_report
2802+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
2803+ self.check_results(r, expected_counts)
2804+
2805+ def test_check_apps_stop_empty(self):
2806+ '''Test check_apps_stop() - empty'''
2807+ self.set_test_snap_yaml("apps", {"foo": {"stop": ""},
2808+ })
2809+ c = SnapReviewLint(self.test_name)
2810+ c.check_apps_stop()
2811+ r = c.click_report
2812+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2813+ self.check_results(r, expected_counts)
2814+
2815+ def test_check_apps_stop_invalid(self):
2816+ '''Test check_apps_stop() - list'''
2817+ self.set_test_snap_yaml("apps", {"foo": {"stop": []},
2818+ })
2819+ c = SnapReviewLint(self.test_name)
2820+ c.check_apps_stop()
2821+ r = c.click_report
2822+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2823+ self.check_results(r, expected_counts)
2824+
2825+ def test_check_apps_stop_nonexistent(self):
2826+ '''Test check_apps_stop() - nonexistent'''
2827+ cmd = "bin/foo"
2828+ self.set_test_snap_yaml("apps", {"foo": {"stop": cmd},
2829+ })
2830+ c = SnapReviewLint(self.test_name)
2831+ c.check_apps_stop()
2832+ r = c.click_report
2833+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2834+ self.check_results(r, expected_counts)
2835+
2836+ def test_check_apps_poststop(self):
2837+ '''Test check_apps_poststop()'''
2838+ cmd = "bin/foo"
2839+ self.set_test_snap_yaml("apps", {"foo": {"poststop": cmd},
2840+ })
2841+ c = SnapReviewLint(self.test_name)
2842+ c.pkg_files.append(os.path.join('/fake', cmd))
2843+ c.check_apps_poststop()
2844+ r = c.click_report
2845+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2846+ self.check_results(r, expected_counts)
2847+
2848+ def test_check_apps_poststop_missing(self):
2849+ '''Test check_apps_poststop() - missing'''
2850+ self.set_test_snap_yaml("apps", {"foo": {}})
2851+ c = SnapReviewLint(self.test_name)
2852+ c.check_apps_poststop()
2853+ r = c.click_report
2854+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
2855+ self.check_results(r, expected_counts)
2856+
2857+ def test_check_apps_poststop_empty(self):
2858+ '''Test check_apps_poststop() - empty'''
2859+ self.set_test_snap_yaml("apps", {"foo": {"poststop": ""},
2860+ })
2861+ c = SnapReviewLint(self.test_name)
2862+ c.check_apps_poststop()
2863+ r = c.click_report
2864+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2865+ self.check_results(r, expected_counts)
2866+
2867+ def test_check_apps_poststop_invalid(self):
2868+ '''Test check_apps_poststop() - list'''
2869+ self.set_test_snap_yaml("apps", {"foo": {"poststop": []},
2870+ })
2871+ c = SnapReviewLint(self.test_name)
2872+ c.check_apps_poststop()
2873+ r = c.click_report
2874+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2875+ self.check_results(r, expected_counts)
2876+
2877+ def test_check_apps_poststop_nonexistent(self):
2878+ '''Test check_apps_poststop() - nonexistent'''
2879+ cmd = "bin/foo"
2880+ self.set_test_snap_yaml("apps", {"foo": {"poststop": cmd},
2881+ })
2882+ c = SnapReviewLint(self.test_name)
2883+ c.check_apps_poststop()
2884+ r = c.click_report
2885+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2886+ self.check_results(r, expected_counts)
2887+
2888+ def test_check_apps_daemon_simple(self):
2889+ '''Test check_apps_daemon() - simple'''
2890+ entry = "simple"
2891+ self.set_test_snap_yaml("apps", {"foo": {"daemon": entry}})
2892+ c = SnapReviewLint(self.test_name)
2893+ c.check_apps_daemon()
2894+ r = c.click_report
2895+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2896+ self.check_results(r, expected_counts)
2897+
2898+ def test_check_apps_daemon_forking(self):
2899+ '''Test check_apps_daemon() - forking'''
2900+ entry = "forking"
2901+ self.set_test_snap_yaml("apps", {"foo": {"daemon": entry}})
2902+ c = SnapReviewLint(self.test_name)
2903+ c.check_apps_daemon()
2904+ r = c.click_report
2905+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2906+ self.check_results(r, expected_counts)
2907+
2908+ def test_check_apps_daemon_oneshot(self):
2909+ '''Test check_apps_daemon() - oneshot'''
2910+ entry = "oneshot"
2911+ self.set_test_snap_yaml("apps", {"foo": {"daemon": entry}})
2912+ c = SnapReviewLint(self.test_name)
2913+ c.check_apps_daemon()
2914+ r = c.click_report
2915+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2916+ self.check_results(r, expected_counts)
2917+
2918+ def test_check_apps_daemon_dbus(self):
2919+ '''Test check_apps_daemon() - dbus'''
2920+ entry = "dbus"
2921+ self.set_test_snap_yaml("apps", {"foo": {"daemon": entry}})
2922+ c = SnapReviewLint(self.test_name)
2923+ c.check_apps_daemon()
2924+ r = c.click_report
2925+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2926+ self.check_results(r, expected_counts)
2927+
2928+ def test_check_apps_daemon_missing(self):
2929+ '''Test check_apps_daemon() - missing'''
2930+ self.set_test_snap_yaml("apps", {"foo": {}})
2931+ c = SnapReviewLint(self.test_name)
2932+ c.check_apps_daemon()
2933+ r = c.click_report
2934+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
2935+ self.check_results(r, expected_counts)
2936+
2937+ def test_check_apps_daemon_empty(self):
2938+ '''Test check_apps_daemon() - empty'''
2939+ self.set_test_snap_yaml("apps", {"foo": {"daemon": ""},
2940+ })
2941+ c = SnapReviewLint(self.test_name)
2942+ c.check_apps_daemon()
2943+ r = c.click_report
2944+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2945+ self.check_results(r, expected_counts)
2946+
2947+ def test_check_apps_daemon_invalid(self):
2948+ '''Test check_apps_daemon() - list'''
2949+ self.set_test_snap_yaml("apps", {"foo": {"daemon": []},
2950+ })
2951+ c = SnapReviewLint(self.test_name)
2952+ c.check_apps_daemon()
2953+ r = c.click_report
2954+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2955+ self.check_results(r, expected_counts)
2956+
2957+ def test_check_apps_daemon_nonexistent(self):
2958+ '''Test check_apps_daemon() - nonexistent'''
2959+ entry = "nonexistent"
2960+ self.set_test_snap_yaml("apps", {"foo": {"daemon": entry}})
2961+ c = SnapReviewLint(self.test_name)
2962+ c.check_apps_daemon()
2963+ r = c.click_report
2964+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
2965+ self.check_results(r, expected_counts)
2966+
2967+ def test_check_apps_nondaemon(self):
2968+ '''Test check_apps_nondaemon()'''
2969+ entry = "simple"
2970+ self.set_test_snap_yaml("apps", {"foo": {"daemon": entry,
2971+ "stop": "bin/bar"}})
2972+ c = SnapReviewLint(self.test_name)
2973+ c.check_apps_nondaemon()
2974+ r = c.click_report
2975+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2976+ self.check_results(r, expected_counts)
2977+
2978+ def test_check_apps_nondaemon_command(self):
2979+ '''Test check_apps_nondaemon() - command'''
2980+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar"}})
2981+ c = SnapReviewLint(self.test_name)
2982+ c.check_apps_nondaemon()
2983+ r = c.click_report
2984+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2985+ self.check_results(r, expected_counts)
2986+
2987+ def test_check_apps_nondaemon_uses(self):
2988+ '''Test check_apps_nondaemon() - uses'''
2989+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
2990+ "uses": {}}})
2991+ c = SnapReviewLint(self.test_name)
2992+ c.check_apps_nondaemon()
2993+ r = c.click_report
2994+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
2995+ self.check_results(r, expected_counts)
2996+
2997+ def test_check_apps_nondaemon_stop(self):
2998+ '''Test check_apps_nondaemon() - stop'''
2999+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3000+ "stop": "bin/bar"}})
3001+ c = SnapReviewLint(self.test_name)
3002+ c.check_apps_nondaemon()
3003+ r = c.click_report
3004+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3005+ self.check_results(r, expected_counts)
3006+
3007+ def test_check_apps_nondaemon_stop_timeout(self):
3008+ '''Test check_apps_nondaemon() - stop-timeout'''
3009+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3010+ "stop-timeout": 60}})
3011+ c = SnapReviewLint(self.test_name)
3012+ c.check_apps_nondaemon()
3013+ r = c.click_report
3014+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3015+ self.check_results(r, expected_counts)
3016+
3017+ def test_check_apps_nondaemon_restart_condition(self):
3018+ '''Test check_apps_nondaemon() - restart-condition'''
3019+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3020+ "restart-condition":
3021+ "never"}})
3022+ c = SnapReviewLint(self.test_name)
3023+ c.check_apps_nondaemon()
3024+ r = c.click_report
3025+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3026+ self.check_results(r, expected_counts)
3027+
3028+ def test_check_apps_nondaemon_poststop(self):
3029+ '''Test check_apps_nondaemon() - poststop'''
3030+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3031+ "poststop": "bin/bar"}})
3032+ c = SnapReviewLint(self.test_name)
3033+ c.check_apps_nondaemon()
3034+ r = c.click_report
3035+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3036+ self.check_results(r, expected_counts)
3037+
3038+ def test_check_apps_nondaemon_ports(self):
3039+ '''Test check_apps_nondaemon() - ports'''
3040+ ports = self._create_ports()
3041+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3042+ "ports": ports}})
3043+ c = SnapReviewLint(self.test_name)
3044+ c.check_apps_nondaemon()
3045+ r = c.click_report
3046+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3047+ self.check_results(r, expected_counts)
3048+
3049+ def test_check_apps_nondaemon_bus_name(self):
3050+ '''Test check_apps_nondaemon() - bus-name'''
3051+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3052+ "bus-name": "tld.foo"}})
3053+ c = SnapReviewLint(self.test_name)
3054+ c.check_apps_nondaemon()
3055+ r = c.click_report
3056+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3057+ self.check_results(r, expected_counts)
3058+
3059+ def test_check_apps_nondaemon_socket(self):
3060+ '''Test check_apps_nondaemon() - socket'''
3061+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3062+ "socket": True}})
3063+ c = SnapReviewLint(self.test_name)
3064+ c.check_apps_nondaemon()
3065+ r = c.click_report
3066+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3067+ self.check_results(r, expected_counts)
3068+
3069+ def test_check_apps_nondaemon_listen_stream(self):
3070+ '''Test check_apps_nondaemon() - listen-stream'''
3071+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3072+ "listen-stream": "@bar"}})
3073+ c = SnapReviewLint(self.test_name)
3074+ c.check_apps_nondaemon()
3075+ r = c.click_report
3076+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3077+ self.check_results(r, expected_counts)
3078+
3079+ def test_check_apps_nondaemon_socket_user(self):
3080+ '''Test check_apps_nondaemon() - socket-user'''
3081+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3082+ "socket-user": "docker"}})
3083+ c = SnapReviewLint(self.test_name)
3084+ c.check_apps_nondaemon()
3085+ r = c.click_report
3086+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3087+ self.check_results(r, expected_counts)
3088+
3089+ def test_check_apps_nondaemon_socket_group(self):
3090+ '''Test check_apps_nondaemon() - socket-group'''
3091+ self.set_test_snap_yaml("apps", {"foo": {"command": "bin/bar",
3092+ "socket-group": "docker"}})
3093+ c = SnapReviewLint(self.test_name)
3094+ c.check_apps_nondaemon()
3095+ r = c.click_report
3096+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3097+ self.check_results(r, expected_counts)
3098+
3099+ def test_check_apps_restart_condition_always(self):
3100+ '''Test check_apps_restart-condition() - always'''
3101+ entry = "always"
3102+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": entry}})
3103+ c = SnapReviewLint(self.test_name)
3104+ c.check_apps_restart_condition()
3105+ r = c.click_report
3106+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
3107+ self.check_results(r, expected_counts)
3108+
3109+ def test_check_apps_restart_condition_never(self):
3110+ '''Test check_apps_restart-condition() - never'''
3111+ entry = "never"
3112+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": entry}})
3113+ c = SnapReviewLint(self.test_name)
3114+ c.check_apps_restart_condition()
3115+ r = c.click_report
3116+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
3117+ self.check_results(r, expected_counts)
3118+
3119+ def test_check_apps_restart_condition_on_abnormal(self):
3120+ '''Test check_apps_restart-condition() - on-abnormal'''
3121+ entry = "on-abnormal"
3122+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": entry}})
3123+ c = SnapReviewLint(self.test_name)
3124+ c.check_apps_restart_condition()
3125+ r = c.click_report
3126+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
3127+ self.check_results(r, expected_counts)
3128+
3129+ def test_check_apps_restart_condition_on_abort(self):
3130+ '''Test check_apps_restart-condition() - on-abort'''
3131+ entry = "on-abort"
3132+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": entry}})
3133+ c = SnapReviewLint(self.test_name)
3134+ c.check_apps_restart_condition()
3135+ r = c.click_report
3136+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
3137+ self.check_results(r, expected_counts)
3138+
3139+ def test_check_apps_restart_condition_on_failure(self):
3140+ '''Test check_apps_restart-condition() - on-failure'''
3141+ entry = "on-failure"
3142+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": entry}})
3143+ c = SnapReviewLint(self.test_name)
3144+ c.check_apps_restart_condition()
3145+ r = c.click_report
3146+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
3147+ self.check_results(r, expected_counts)
3148+
3149+ def test_check_apps_restart_condition_on_success(self):
3150+ '''Test check_apps_restart-condition() - on-success'''
3151+ entry = "on-success"
3152+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": entry}})
3153+ c = SnapReviewLint(self.test_name)
3154+ c.check_apps_restart_condition()
3155+ r = c.click_report
3156+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
3157+ self.check_results(r, expected_counts)
3158+
3159+ def test_check_apps_restart_condition_missing(self):
3160+ '''Test check_apps_restart-condition() - missing'''
3161+ self.set_test_snap_yaml("apps", {"foo": {}})
3162+ c = SnapReviewLint(self.test_name)
3163+ c.check_apps_restart_condition()
3164+ r = c.click_report
3165+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
3166+ self.check_results(r, expected_counts)
3167+
3168+ def test_check_apps_restart_condition_empty(self):
3169+ '''Test check_apps_restart-condition() - empty'''
3170+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": ""},
3171+ })
3172+ c = SnapReviewLint(self.test_name)
3173+ c.check_apps_restart_condition()
3174+ r = c.click_report
3175+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3176+ self.check_results(r, expected_counts)
3177+
3178+ def test_check_apps_restart_condition_invalid(self):
3179+ '''Test check_apps_restart-condition() - list'''
3180+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": []},
3181+ })
3182+ c = SnapReviewLint(self.test_name)
3183+ c.check_apps_restart_condition()
3184+ r = c.click_report
3185+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3186+ self.check_results(r, expected_counts)
3187+
3188+ def test_check_apps_restart_condition_nonexistent(self):
3189+ '''Test check_apps_restart-condition() - nonexistent'''
3190+ entry = "nonexistent"
3191+ self.set_test_snap_yaml("apps", {"foo": {"restart-condition": entry}})
3192+ c = SnapReviewLint(self.test_name)
3193+ c.check_apps_restart_condition()
3194+ r = c.click_report
3195+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3196+ self.check_results(r, expected_counts)
3197+
3198+ def test_check_apps_busname_pkgname(self):
3199+ '''Test check_apps_busname() - pkgname'''
3200+ name = "tld.%s" % self.test_name.split('_')[0].split('.')[0]
3201+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": name}})
3202+ self.set_test_snap_yaml("type", 'framework')
3203+ c = SnapReviewLint(self.test_name)
3204+ c.check_apps_busname()
3205+ r = c.click_report
3206+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
3207+ self.check_results(r, expected_counts)
3208+
3209+ def test_check_apps_busname_appname(self):
3210+ '''Test check_apps_busname() - appname'''
3211+ name = "tld.%s" % self.test_name.split('_')[0].split('.')[0]
3212+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": "%s.bar" % name}})
3213+ self.set_test_snap_yaml("type", 'framework')
3214+ c = SnapReviewLint(self.test_name)
3215+ c.check_apps_busname()
3216+ r = c.click_report
3217+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
3218+ self.check_results(r, expected_counts)
3219+
3220+ def test_check_apps_busname_missing_framework_app(self):
3221+ '''Test check_apps_busname() - missing framework (app)'''
3222+ name = "tld.%s" % self.test_name.split('_')[0].split('.')[0]
3223+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": "%s.bar" % name}})
3224+ self.set_test_snap_yaml("type", 'app')
3225+ c = SnapReviewLint(self.test_name)
3226+ c.check_apps_busname()
3227+ r = c.click_report
3228+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3229+ self.check_results(r, expected_counts)
3230+
3231+ def test_check_apps_busname_missing_framework_gadget(self):
3232+ '''Test check_apps_busname() - missing framework (gadget)'''
3233+ name = "tld.%s" % self.test_name.split('_')[0].split('.')[0]
3234+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": "%s.bar" % name}})
3235+ self.set_test_snap_yaml("type", 'gadget')
3236+ c = SnapReviewLint(self.test_name)
3237+ c.check_apps_busname()
3238+ r = c.click_report
3239+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3240+ self.check_results(r, expected_counts)
3241+
3242+ def test_check_apps_busname_missing_framework_kernel(self):
3243+ '''Test check_apps_busname() - missing framework (kernel)'''
3244+ name = "tld.%s" % self.test_name.split('_')[0].split('.')[0]
3245+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": name}})
3246+ self.set_test_snap_yaml("type", 'kernel')
3247+ c = SnapReviewLint(self.test_name)
3248+ c.check_apps_busname()
3249+ r = c.click_report
3250+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3251+ self.check_results(r, expected_counts)
3252+
3253+ def test_check_apps_busname_pkgname_bad(self):
3254+ '''Test check_apps_busname() - bad pkgname'''
3255+ name = "tld.%s" % self.test_name.split('_')[0].split('.')[0]
3256+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": "%s-bad" % name}})
3257+ self.set_test_snap_yaml("type", 'framework')
3258+ c = SnapReviewLint(self.test_name)
3259+ c.check_apps_busname()
3260+ r = c.click_report
3261+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3262+ self.check_results(r, expected_counts)
3263+
3264+ def test_check_apps_busname_appname_bad(self):
3265+ '''Test check_apps_busname() - bad appname'''
3266+ name = "tld.%s" % self.test_name.split('_')[0].split('.')[0]
3267+ self.set_test_snap_yaml("apps", {"bar": {"bus-name":
3268+ "%s.bar-bad" % name}})
3269+ self.set_test_snap_yaml("type", 'framework')
3270+ c = SnapReviewLint(self.test_name)
3271+ c.check_apps_busname()
3272+ r = c.click_report
3273+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3274+ self.check_results(r, expected_counts)
3275+
3276+ def test_check_apps_busname_empty(self):
3277+ '''Test check_apps_busname() - bad (empty)'''
3278+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": ""}})
3279+ self.set_test_snap_yaml("type", 'framework')
3280+ c = SnapReviewLint(self.test_name)
3281+ c.check_apps_busname()
3282+ r = c.click_report
3283+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3284+ self.check_results(r, expected_counts)
3285+
3286+ def test_check_apps_busname_invalid(self):
3287+ '''Test check_apps_busname() - bad (invalid)'''
3288+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": []}})
3289+ self.set_test_snap_yaml("type", 'framework')
3290+ c = SnapReviewLint(self.test_name)
3291+ c.check_apps_busname()
3292+ r = c.click_report
3293+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3294+ self.check_results(r, expected_counts)
3295+
3296+ def test_check_apps_busname_bad_regex(self):
3297+ '''Test check_apps_busname() - bad (regex)'''
3298+ self.set_test_snap_yaml("apps", {"bar": {"bus-name": "name$"}})
3299+ self.set_test_snap_yaml("type", 'framework')
3300+ c = SnapReviewLint(self.test_name)
3301+ c.check_apps_busname()
3302+ r = c.click_report
3303+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3304+ self.check_results(r, expected_counts)
3305+
3306+ def test_check_apps_ports(self):
3307+ '''Test check_apps_ports()'''
3308+ ports = self._create_ports()
3309+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3310+ c = SnapReviewLint(self.test_name)
3311+ c.check_apps_ports()
3312+ r = c.click_report
3313+ expected_counts = {'info': 7, 'warn': 0, 'error': 0}
3314+ self.check_results(r, expected_counts)
3315+
3316+ def test_check_apps_ports_internal(self):
3317+ '''Test check_apps_ports() - internal'''
3318+ ports = self._create_ports()
3319+ del ports['external']
3320+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3321+ c = SnapReviewLint(self.test_name)
3322+ c.check_apps_ports()
3323+ r = c.click_report
3324+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
3325+ self.check_results(r, expected_counts)
3326+
3327+ def test_check_apps_ports_external(self):
3328+ '''Test check_apps_ports() - external'''
3329+ ports = self._create_ports()
3330+ del ports['internal']
3331+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3332+ c = SnapReviewLint(self.test_name)
3333+ c.check_apps_ports()
3334+ r = c.click_report
3335+ expected_counts = {'info': 5, 'warn': 0, 'error': 0}
3336+ self.check_results(r, expected_counts)
3337+
3338+ def test_check_apps_ports_empty(self):
3339+ '''Test check_apps_ports() - empty'''
3340+ self.set_test_snap_yaml("apps", {"bar": {"ports": {}}})
3341+ c = SnapReviewLint(self.test_name)
3342+ c.check_apps_ports()
3343+ r = c.click_report
3344+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3345+ self.check_results(r, expected_counts)
3346+
3347+ def test_check_apps_ports_invalid(self):
3348+ '''Test check_apps_ports() - invalid'''
3349+ self.set_test_snap_yaml("apps", {"bar": {"ports": []}})
3350+ c = SnapReviewLint(self.test_name)
3351+ c.check_apps_ports()
3352+ r = c.click_report
3353+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3354+ self.check_results(r, expected_counts)
3355+
3356+ def test_check_apps_ports_bad_key(self):
3357+ '''Test check_apps_ports() - bad key'''
3358+ ports = self._create_ports()
3359+ ports['xternal'] = ports['external']
3360+ del ports['external']
3361+
3362+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3363+ c = SnapReviewLint(self.test_name)
3364+ c.check_apps_ports()
3365+ r = c.click_report
3366+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3367+ self.check_results(r, expected_counts)
3368+
3369+ def test_check_apps_ports_missing_internal(self):
3370+ '''Test check_apps_ports() - missing internal'''
3371+ ports = self._create_ports()
3372+ del ports['internal']['int1']
3373+
3374+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3375+ c = SnapReviewLint(self.test_name)
3376+ c.check_apps_ports()
3377+ r = c.click_report
3378+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3379+ self.check_results(r, expected_counts)
3380+
3381+ def test_check_apps_ports_missing_external(self):
3382+ '''Test check_apps_ports() - missing external'''
3383+ ports = self._create_ports()
3384+ del ports['external']['ext1']
3385+ del ports['external']['ext2']
3386+
3387+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3388+ c = SnapReviewLint(self.test_name)
3389+ c.check_apps_ports()
3390+ r = c.click_report
3391+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3392+ self.check_results(r, expected_counts)
3393+
3394+ def test_check_apps_ports_missing_external_subkey(self):
3395+ '''Test check_apps_ports() - missing external subkey'''
3396+ ports = self._create_ports()
3397+ del ports['external']['ext2']['port']
3398+
3399+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3400+ c = SnapReviewLint(self.test_name)
3401+ c.check_apps_ports()
3402+ r = c.click_report
3403+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3404+ self.check_results(r, expected_counts)
3405+
3406+ def test_check_apps_ports_missing_internal_subkey(self):
3407+ '''Test check_apps_ports() - missing internal subkey'''
3408+ ports = self._create_ports()
3409+ del ports['internal']['int1']['port']
3410+ del ports['internal']['int1']['negotiable']
3411+
3412+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3413+ c = SnapReviewLint(self.test_name)
3414+ c.check_apps_ports()
3415+ r = c.click_report
3416+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3417+ self.check_results(r, expected_counts)
3418+
3419+ def test_check_apps_ports_missing_internal_port_subkey(self):
3420+ '''Test check_apps_ports() - missing internal port subkey'''
3421+ ports = self._create_ports()
3422+ del ports['internal']['int1']['port']
3423+
3424+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3425+ c = SnapReviewLint(self.test_name)
3426+ c.check_apps_ports()
3427+ r = c.click_report
3428+ expected_counts = {'info': 7, 'warn': 0, 'error': 0}
3429+ self.check_results(r, expected_counts)
3430+
3431+ def test_check_apps_ports_invalid_internal_subkey(self):
3432+ '''Test check_apps_ports() - invalid internal subkey'''
3433+ ports = self._create_ports()
3434+ ports['internal']['int1']['prt'] = ports['internal']['int1']['port']
3435+
3436+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3437+ c = SnapReviewLint(self.test_name)
3438+ c.check_apps_ports()
3439+ r = c.click_report
3440+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3441+ self.check_results(r, expected_counts)
3442+
3443+ def test_check_apps_ports_invalid_internal_port(self):
3444+ '''Test check_apps_ports() - invalid internal port'''
3445+ ports = self._create_ports()
3446+ ports['internal']['int1']['port'] = "bad/8080"
3447+
3448+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3449+ c = SnapReviewLint(self.test_name)
3450+ c.check_apps_ports()
3451+ r = c.click_report
3452+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3453+ self.check_results(r, expected_counts)
3454+
3455+ def test_check_apps_ports_invalid_external_port(self):
3456+ '''Test check_apps_ports() - invalid external port'''
3457+ ports = self._create_ports()
3458+ ports['external']['ext2']['port'] = []
3459+
3460+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3461+ c = SnapReviewLint(self.test_name)
3462+ c.check_apps_ports()
3463+ r = c.click_report
3464+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3465+ self.check_results(r, expected_counts)
3466+
3467+ def test_check_apps_ports_invalid_internal_low_port(self):
3468+ '''Test check_apps_ports() - invalid internal low port'''
3469+ ports = self._create_ports()
3470+ ports['internal']['int1']['port'] = "0/tcp"
3471+
3472+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3473+ c = SnapReviewLint(self.test_name)
3474+ c.check_apps_ports()
3475+ r = c.click_report
3476+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3477+ self.check_results(r, expected_counts)
3478+
3479+ def test_check_apps_ports_invalid_internal_high_port(self):
3480+ '''Test check_apps_ports() - invalid internal high port'''
3481+ ports = self._create_ports()
3482+ ports['internal']['int1']['port'] = "65536/tcp"
3483+
3484+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3485+ c = SnapReviewLint(self.test_name)
3486+ c.check_apps_ports()
3487+ r = c.click_report
3488+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3489+ self.check_results(r, expected_counts)
3490+
3491+ def test_check_apps_ports_invalid_internal_negotiable(self):
3492+ '''Test check_apps_ports() - invalid internal negotiable'''
3493+ ports = self._create_ports()
3494+ ports['internal']['int1']['negotiable'] = -99999999
3495+
3496+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3497+ c = SnapReviewLint(self.test_name)
3498+ c.check_apps_ports()
3499+ r = c.click_report
3500+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3501+ self.check_results(r, expected_counts)
3502+
3503+ def test_check_apps_ports_invalid_internal_negotiable2(self):
3504+ '''Test check_apps_ports() - invalid internal negotiable'''
3505+ ports = self._create_ports()
3506+ ports['internal']['int1']['negotiable'] = []
3507+
3508+ self.set_test_snap_yaml("apps", {"bar": {"ports": ports}})
3509+ c = SnapReviewLint(self.test_name)
3510+ c.check_apps_ports()
3511+ r = c.click_report
3512+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3513+ self.check_results(r, expected_counts)
3514+
3515+ def test_check_apps_stop_timeout(self):
3516+ '''Test check_apps_stop_timeout()'''
3517+ self.set_test_snap_yaml("apps", {"bar": {"stop-timeout": 30}})
3518+ c = SnapReviewLint(self.test_name)
3519+ c.check_apps_stop_timeout()
3520+ r = c.click_report
3521+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
3522+ self.check_results(r, expected_counts)
3523+
3524+ def test_check_apps_stop_timeout_nonexistent(self):
3525+ '''Test check_apps_stop_timeout_nonexistent()'''
3526+ self.set_test_snap_yaml("apps", {"bar": {}})
3527+ c = SnapReviewLint(self.test_name)
3528+ c.check_apps_stop_timeout()
3529+ r = c.click_report
3530+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
3531+ self.check_results(r, expected_counts)
3532+
3533+ def test_check_apps_stop_timeout_granularity(self):
3534+ '''Test check_apps_stop_timeout()'''
3535+ self.set_test_snap_yaml("apps", {"bar": {"stop-timeout": '30s'}})
3536+ c = SnapReviewLint(self.test_name)
3537+ c.check_apps_stop_timeout()
3538+ r = c.click_report
3539+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
3540+ self.check_results(r, expected_counts)
3541+
3542+ def test_check_apps_stop_timeout_empty(self):
3543+ '''Test check_apps_stop_timeout() - empty'''
3544+ self.set_test_snap_yaml("apps", {"bar": {"stop-timeout": ''}})
3545+ c = SnapReviewLint(self.test_name)
3546+ c.check_apps_stop_timeout()
3547+ r = c.click_report
3548+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3549+ self.check_results(r, expected_counts)
3550+
3551+ def test_check_apps_stop_timeout_bad(self):
3552+ '''Test check_apps_stop_timeout() - bad'''
3553+ self.set_test_snap_yaml("apps", {"bar": {"stop-timeout": 'a'}})
3554+ c = SnapReviewLint(self.test_name)
3555+ c.check_apps_stop_timeout()
3556+ r = c.click_report
3557+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3558+ self.check_results(r, expected_counts)
3559+
3560+ def test_check_apps_stop_timeout_bad2(self):
3561+ '''Test check_apps_stop_timeout() - bad (list)'''
3562+ self.set_test_snap_yaml("apps", {"bar": {"stop-timeout": []}})
3563+ c = SnapReviewLint(self.test_name)
3564+ c.check_apps_stop_timeout()
3565+ r = c.click_report
3566+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3567+ self.check_results(r, expected_counts)
3568+
3569+ def test_check_apps_stop_timeout_bad_granularity(self):
3570+ '''Test check_apps_stop_timeout() - bad with granularity'''
3571+ self.set_test_snap_yaml("apps", {"bar": {"stop-timeout": '30a'}})
3572+ c = SnapReviewLint(self.test_name)
3573+ c.check_apps_stop_timeout()
3574+ r = c.click_report
3575+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3576+ self.check_results(r, expected_counts)
3577+
3578+ def test_check_apps_stop_timeout_range_low(self):
3579+ '''Test check_apps_stop_timeout() - out of range (low)'''
3580+ self.set_test_snap_yaml("apps", {"bar": {"stop-timeout": -1}})
3581+ c = SnapReviewLint(self.test_name)
3582+ c.check_apps_stop_timeout()
3583+ r = c.click_report
3584+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3585+ self.check_results(r, expected_counts)
3586+
3587+ def test_check_apps_stop_timeout_range_high(self):
3588+ '''Test check_apps_stop_timeout() - out of range (high)'''
3589+ self.set_test_snap_yaml("apps", {"bar": {"stop-timeout": 61}})
3590+ c = SnapReviewLint(self.test_name)
3591+ c.check_apps_stop_timeout()
3592+ r = c.click_report
3593+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3594+ self.check_results(r, expected_counts)
3595+
3596+ def test_check_apps_socket(self):
3597+ '''Test check_apps_socket()'''
3598+ name = self.test_snap_yaml['name']
3599+ self.set_test_snap_yaml("apps", {"bar": {"socket": True,
3600+ "listen-stream":
3601+ "@%s" % name}})
3602+ c = SnapReviewLint(self.test_name)
3603+ c.check_apps_socket()
3604+ r = c.click_report
3605+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
3606+ self.check_results(r, expected_counts)
3607+
3608+ def test_check_apps_listen_stream_path(self):
3609+ '''Test check_apps_listen_stream() - path'''
3610+ name = self.test_snap_yaml['name']
3611+ self.set_test_snap_yaml("apps", {"bar": {"listen-stream":
3612+ "/tmp/%s" % name}})
3613+ c = SnapReviewLint(self.test_name)
3614+ c.check_apps_listen_stream()
3615+ r = c.click_report
3616+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
3617+ self.check_results(r, expected_counts)
3618+
3619+ def test_check_apps_socket_no_listen_stream(self):
3620+ '''Test check_apps_socket() - missing listen-stream'''
3621+ self.set_test_snap_yaml("apps", {"bar": {"socket": True}})
3622+ c = SnapReviewLint(self.test_name)
3623+ c.check_apps_socket()
3624+ r = c.click_report
3625+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3626+ self.check_results(r, expected_counts)
3627+
3628+ def test_check_apps_socket_bad(self):
3629+ '''Test check_apps_socket() - bad'''
3630+ self.set_test_snap_yaml("apps", {"bar": {"socket": ""}})
3631+ c = SnapReviewLint(self.test_name)
3632+ c.check_apps_socket()
3633+ r = c.click_report
3634+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3635+ self.check_results(r, expected_counts)
3636+
3637+ def test_check_apps_socket_nonexistent(self):
3638+ '''Test check_apps_socket() - nonexistent'''
3639+ self.set_test_snap_yaml("apps", {"bar": {}})
3640+ c = SnapReviewLint(self.test_name)
3641+ c.check_apps_socket()
3642+ r = c.click_report
3643+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
3644+ self.check_results(r, expected_counts)
3645+
3646+ def test_check_apps_listen_stream_abspkgname(self):
3647+ '''Test check_apps_listen_stream() - @pkgname'''
3648+ name = self.test_snap_yaml['name']
3649+ self.set_test_snap_yaml("apps", {"bar": {"listen-stream":
3650+ "@%s" % name}})
3651+ c = SnapReviewLint(self.test_name)
3652+ c.check_apps_listen_stream()
3653+ r = c.click_report
3654+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
3655+ self.check_results(r, expected_counts)
3656+
3657+ def test_check_apps_listen_stream_abspkgname2(self):
3658+ '''Test check_apps_listen_stream() - @pkgname_'''
3659+ name = self.test_snap_yaml['name']
3660+ self.set_test_snap_yaml("apps", {"bar": {"listen-stream":
3661+ "@%s_something" % name}})
3662+ c = SnapReviewLint(self.test_name)
3663+ c.check_apps_listen_stream()
3664+ r = c.click_report
3665+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
3666+ self.check_results(r, expected_counts)
3667+
3668+ def test_check_apps_listen_stream_nonexistent(self):
3669+ '''Test check_apps_listen_stream() - nonexistent'''
3670+ self.set_test_snap_yaml("apps", {"bar": {}})
3671+ c = SnapReviewLint(self.test_name)
3672+ c.check_apps_listen_stream()
3673+ r = c.click_report
3674+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
3675+ self.check_results(r, expected_counts)
3676+
3677+ def test_check_apps_listen_stream_bad(self):
3678+ '''Test check_apps_listen_stream() - bad (list)'''
3679+ self.set_test_snap_yaml("apps", {"bar": {"listen-stream": []}})
3680+ c = SnapReviewLint(self.test_name)
3681+ c.check_apps_listen_stream()
3682+ r = c.click_report
3683+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3684+ self.check_results(r, expected_counts)
3685+
3686+ def test_check_apps_listen_stream_bad_abstract(self):
3687+ '''Test check_apps_listen_stream() - bad (wrong name)'''
3688+ name = self.test_snap_yaml['name']
3689+ self.set_test_snap_yaml("apps", {"bar": {"listen-stream":
3690+ "@%s/nomatch" % name}})
3691+ c = SnapReviewLint(self.test_name)
3692+ c.check_apps_listen_stream()
3693+ r = c.click_report
3694+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3695+ self.check_results(r, expected_counts)
3696+
3697+ def test_check_apps_listen_stream_bad_relative(self):
3698+ '''Test check_apps_listen_stream() - bad (not / or @)'''
3699+ name = self.test_snap_yaml['name']
3700+ self.set_test_snap_yaml("apps", {"bar": {"listen-stream": name}})
3701+ c = SnapReviewLint(self.test_name)
3702+ c.check_apps_listen_stream()
3703+ r = c.click_report
3704+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3705+ self.check_results(r, expected_counts)
3706+
3707+ def test_check_apps_listen_stream_bad_path(self):
3708+ '''Test check_apps_listen_stream() - bad path'''
3709+ name = self.test_snap_yaml['name']
3710+ self.set_test_snap_yaml("apps", {"bar": {"listen-stream":
3711+ "/var/log/%s" % name}})
3712+ c = SnapReviewLint(self.test_name)
3713+ c.check_apps_listen_stream()
3714+ r = c.click_report
3715+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3716+ self.check_results(r, expected_counts)
3717+
3718+ def test_check_apps_listen_stream_empty(self):
3719+ '''Test check_apps_listen_stream() - empty'''
3720+ self.set_test_snap_yaml("apps", {"bar": {"listen-stream": ""}})
3721+ c = SnapReviewLint(self.test_name)
3722+ c.check_apps_listen_stream()
3723+ r = c.click_report
3724+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3725+ self.check_results(r, expected_counts)
3726+
3727+ def test_check_apps_socket_user(self):
3728+ '''Test check_apps_socket_user()'''
3729+ name = self.test_snap_yaml['name']
3730+ self.set_test_snap_yaml("apps", {"bar": {"socket-user": name,
3731+ "listen-stream":
3732+ "@%s" % name}})
3733+ c = SnapReviewLint(self.test_name)
3734+ c.check_apps_socket_user()
3735+ r = c.click_report
3736+ expected_counts = {'info': 2, 'warn': 0, 'error': 1}
3737+ self.check_results(r, expected_counts)
3738+
3739+ def test_check_apps_socket_user_no_listen_stream(self):
3740+ '''Test check_apps_socket_user() - missing listen-stream'''
3741+ name = self.test_snap_yaml['name']
3742+ self.set_test_snap_yaml("apps", {"bar": {"socket-user": name}})
3743+ c = SnapReviewLint(self.test_name)
3744+ c.check_apps_socket_user()
3745+ r = c.click_report
3746+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3747+ self.check_results(r, expected_counts)
3748+
3749+ def test_check_apps_socket_user_bad(self):
3750+ '''Test check_apps_socket_user() - bad user'''
3751+ name = self.test_snap_yaml['name']
3752+ self.set_test_snap_yaml("apps", {"bar": {"socket-user": name + "-no",
3753+ "listen-stream":
3754+ "@%s" % name}})
3755+ c = SnapReviewLint(self.test_name)
3756+ c.check_apps_socket_user()
3757+ r = c.click_report
3758+ expected_counts = {'info': None, 'warn': 0, 'error': 2}
3759+ self.check_results(r, expected_counts)
3760+
3761+ def test_check_apps_socket_user_bad2(self):
3762+ '''Test check_apps_socket_user() - bad (list)'''
3763+ name = self.test_snap_yaml['name']
3764+ self.set_test_snap_yaml("apps", {"bar": {"socket-user": [],
3765+ "listen-stream":
3766+ "@%s" % name}})
3767+ c = SnapReviewLint(self.test_name)
3768+ c.check_apps_socket_user()
3769+ r = c.click_report
3770+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3771+ self.check_results(r, expected_counts)
3772+
3773+ def test_check_apps_socket_user_empty(self):
3774+ '''Test check_apps_socket_user() - empty'''
3775+ name = self.test_snap_yaml['name']
3776+ self.set_test_snap_yaml("apps", {"bar": {"socket-user": "",
3777+ "listen-stream":
3778+ "@%s" % name}})
3779+ c = SnapReviewLint(self.test_name)
3780+ c.check_apps_socket_user()
3781+ r = c.click_report
3782+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3783+ self.check_results(r, expected_counts)
3784+
3785+ def test_check_apps_socket_user_nonexistent(self):
3786+ '''Test check_apps_socket_user() - nonexistent'''
3787+ self.set_test_snap_yaml("apps", {"bar": {}})
3788+ c = SnapReviewLint(self.test_name)
3789+ c.check_apps_socket_user()
3790+ r = c.click_report
3791+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
3792+ self.check_results(r, expected_counts)
3793+
3794+ def test_check_apps_socket_group(self):
3795+ '''Test check_apps_socket_group()'''
3796+ name = self.test_snap_yaml['name']
3797+ self.set_test_snap_yaml("apps", {"bar": {"socket-group": name,
3798+ "listen-stream":
3799+ "@%s" % name}})
3800+ c = SnapReviewLint(self.test_name)
3801+ c.check_apps_socket_group()
3802+ r = c.click_report
3803+ expected_counts = {'info': 2, 'warn': 0, 'error': 1}
3804+ self.check_results(r, expected_counts)
3805+
3806+ def test_check_apps_socket_group_no_listen_stream(self):
3807+ '''Test check_apps_socket_group() - missing listen-stream'''
3808+ name = self.test_snap_yaml['name']
3809+ self.set_test_snap_yaml("apps", {"bar": {"socket-group": name}})
3810+ c = SnapReviewLint(self.test_name)
3811+ c.check_apps_socket_group()
3812+ r = c.click_report
3813+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3814+ self.check_results(r, expected_counts)
3815+
3816+ def test_check_apps_socket_group_bad(self):
3817+ '''Test check_apps_socket_group() - bad group'''
3818+ name = self.test_snap_yaml['name']
3819+ self.set_test_snap_yaml("apps", {"bar": {"socket-group": name + "-no",
3820+ "listen-stream":
3821+ "@%s" % name}})
3822+ c = SnapReviewLint(self.test_name)
3823+ c.check_apps_socket_group()
3824+ r = c.click_report
3825+ expected_counts = {'info': None, 'warn': 0, 'error': 2}
3826+ self.check_results(r, expected_counts)
3827+
3828+ def test_check_apps_socket_group_bad2(self):
3829+ '''Test check_apps_socket_group() - bad (list)'''
3830+ name = self.test_snap_yaml['name']
3831+ self.set_test_snap_yaml("apps", {"bar": {"socket-group": [],
3832+ "listen-stream":
3833+ "@%s" % name}})
3834+ c = SnapReviewLint(self.test_name)
3835+ c.check_apps_socket_group()
3836+ r = c.click_report
3837+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3838+ self.check_results(r, expected_counts)
3839+
3840+ def test_check_apps_socket_group_empty(self):
3841+ '''Test check_apps_socket_group() - empty'''
3842+ name = self.test_snap_yaml['name']
3843+ self.set_test_snap_yaml("apps", {"bar": {"socket-group": "",
3844+ "listen-stream":
3845+ "@%s" % name}})
3846+ c = SnapReviewLint(self.test_name)
3847+ c.check_apps_socket_group()
3848+ r = c.click_report
3849+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3850+ self.check_results(r, expected_counts)
3851+
3852+ def test_check_apps_socket_group_nonexistent(self):
3853+ '''Test check_apps_socket_group() - nonexistent'''
3854+ self.set_test_snap_yaml("apps", {"bar": {}})
3855+ c = SnapReviewLint(self.test_name)
3856+ c.check_apps_socket_group()
3857+ r = c.click_report
3858+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
3859+ self.check_results(r, expected_counts)
3860+
3861+ def test_check_uses(self):
3862+ '''Test check_uses()'''
3863+ uses = self._create_top_uses()
3864+ self.set_test_snap_yaml("uses", uses)
3865+ c = SnapReviewLint(self.test_name)
3866+ c.check_uses()
3867+ r = c.click_report
3868+ expected_counts = {'info': 13, 'warn': 0, 'error': 0}
3869+ self.check_results(r, expected_counts)
3870+
3871+ def test_check_uses_bad_type(self):
3872+ '''Test check_uses() - bad type (list)'''
3873+ uses = {'skill-caps': {'type': [],
3874+ 'caps': ['network-client']}}
3875+ self.set_test_snap_yaml("uses", uses)
3876+ c = SnapReviewLint(self.test_name)
3877+ c.check_uses()
3878+ r = c.click_report
3879+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3880+ self.check_results(r, expected_counts)
3881+
3882+ def test_check_uses_empty_type(self):
3883+ '''Test check_uses() - empty type'''
3884+ uses = {'skill-caps': {'type': "",
3885+ 'caps': ['network-client']}}
3886+ self.set_test_snap_yaml("uses", uses)
3887+ c = SnapReviewLint(self.test_name)
3888+ c.check_uses()
3889+ r = c.click_report
3890+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3891+ self.check_results(r, expected_counts)
3892+
3893+ def test_check_uses_unspecified_type(self):
3894+ '''Test check_uses() - unspecified type'''
3895+ uses = {'migration-skill': {'caps': ['network-client']}}
3896+ self.set_test_snap_yaml("uses", uses)
3897+ c = SnapReviewLint(self.test_name)
3898+ c.check_uses()
3899+ r = c.click_report
3900+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
3901+ self.check_results(r, expected_counts)
3902+
3903+ def test_check_uses_unknown_type(self):
3904+ '''Test check_uses() - type (unknown)'''
3905+ uses = {'skill-caps': {'type': 'nonexistent',
3906+ 'caps': ['network-client']}}
3907+ self.set_test_snap_yaml("uses", uses)
3908+ c = SnapReviewLint(self.test_name)
3909+ c.check_uses()
3910+ r = c.click_report
3911+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3912+ self.check_results(r, expected_counts)
3913+
3914+ def test_check_uses_unspecified_unknown_type(self):
3915+ '''Test check_uses() - unspecified type (unknown)'''
3916+ uses = {'nonexistent': {'caps': ['network-client']}}
3917+ self.set_test_snap_yaml("uses", uses)
3918+ c = SnapReviewLint(self.test_name)
3919+ c.check_uses()
3920+ r = c.click_report
3921+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3922+ self.check_results(r, expected_counts)
3923+
3924+ def test_check_uses_missing_attrib(self):
3925+ '''Test check_uses() - missing attrib'''
3926+ uses = {'migration-skill': {}}
3927+ self.set_test_snap_yaml("uses", uses)
3928+ c = SnapReviewLint(self.test_name)
3929+ c.check_uses()
3930+ r = c.click_report
3931+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3932+ self.check_results(r, expected_counts)
3933+
3934+ def test_check_uses_missing_attrib_explicit_type(self):
3935+ '''Test check_uses() - missing attrib'''
3936+ uses = {'skill-caps': {'type': 'migration-skill'}}
3937+ self.set_test_snap_yaml("uses", uses)
3938+ c = SnapReviewLint(self.test_name)
3939+ c.check_uses()
3940+ r = c.click_report
3941+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3942+ self.check_results(r, expected_counts)
3943+
3944+ def test_check_uses_unknown_attrib(self):
3945+ '''Test check_uses() - unknown attrib'''
3946+ uses = {'skill-caps': {'type': "migration-skill",
3947+ 'nonexistent': 'abc'}}
3948+ self.set_test_snap_yaml("uses", uses)
3949+ c = SnapReviewLint(self.test_name)
3950+ c.check_uses()
3951+ r = c.click_report
3952+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3953+ self.check_results(r, expected_counts)
3954+
3955+ def test_check_uses_bad_attrib_caps(self):
3956+ '''Test check_uses() - bad attrib - caps'''
3957+ uses = {'skill-caps': {'type': "migration-skill",
3958+ 'caps': 'bad'}}
3959+ self.set_test_snap_yaml("uses", uses)
3960+ c = SnapReviewLint(self.test_name)
3961+ c.check_uses()
3962+ r = c.click_report
3963+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3964+ self.check_results(r, expected_counts)
3965+
3966+ def test_check_uses_bad_attrib_security_override(self):
3967+ '''Test check_uses() - bad attrib - security-override'''
3968+ uses = {'skill-caps': {'type': "migration-skill",
3969+ 'security-override': 'bad'}}
3970+ self.set_test_snap_yaml("uses", uses)
3971+ c = SnapReviewLint(self.test_name)
3972+ c.check_uses()
3973+ r = c.click_report
3974+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3975+ self.check_results(r, expected_counts)
3976+
3977+ def test_check_uses_bad_attrib_security_policy(self):
3978+ '''Test check_uses() - bad attrib - security-policy'''
3979+ uses = {'skill-caps': {'type': "migration-skill",
3980+ 'security-policy': 'bad'}}
3981+ self.set_test_snap_yaml("uses", uses)
3982+ c = SnapReviewLint(self.test_name)
3983+ c.check_uses()
3984+ r = c.click_report
3985+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3986+ self.check_results(r, expected_counts)
3987+
3988+ def test_check_uses_bad_attrib_security_template(self):
3989+ '''Test check_uses() - bad attrib - security-template'''
3990+ uses = {'skill-caps': {'type': "migration-skill",
3991+ 'security-template': []}}
3992+ self.set_test_snap_yaml("uses", uses)
3993+ c = SnapReviewLint(self.test_name)
3994+ c.check_uses()
3995+ r = c.click_report
3996+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
3997+ self.check_results(r, expected_counts)
3998+
3999+ def test_check_apps_uses(self):
4000+ '''Test check_apps_uses()'''
4001+ uses = self._create_top_uses()
4002+ apps_uses = self._create_apps_uses()
4003+ self.set_test_snap_yaml("uses", uses)
4004+ self.set_test_snap_yaml("apps", apps_uses)
4005+ c = SnapReviewLint(self.test_name)
4006+ c.check_apps_uses()
4007+ r = c.click_report
4008+ expected_counts = {'info': 10, 'warn': 0, 'error': 0}
4009+ self.check_results(r, expected_counts)
4010+
4011+ def test_check_apps_no_uses(self):
4012+ '''Test check_apps_uses() - no uses'''
4013+ uses = self._create_top_uses()
4014+ apps_uses = {'bar': {'command': 'bin/bar'}}
4015+ self.set_test_snap_yaml("uses", uses)
4016+ self.set_test_snap_yaml("apps", apps_uses)
4017+ c = SnapReviewLint(self.test_name)
4018+ c.check_apps_uses()
4019+ r = c.click_report
4020+ expected_counts = {'info': 0, 'warn': 0, 'error': 0}
4021+ self.check_results(r, expected_counts)
4022+
4023+ def test_check_apps_uses_bad(self):
4024+ '''Test check_apps_uses() - bad (dict)'''
4025+ uses = self._create_top_uses()
4026+ apps_uses = {'bar': {'uses': {}}}
4027+ self.set_test_snap_yaml("uses", uses)
4028+ self.set_test_snap_yaml("apps", apps_uses)
4029+ c = SnapReviewLint(self.test_name)
4030+ c.check_apps_uses()
4031+ r = c.click_report
4032+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
4033+ self.check_results(r, expected_counts)
4034+
4035+ def test_check_apps_uses_empty(self):
4036+ '''Test check_apps_uses() - empty'''
4037+ uses = self._create_top_uses()
4038+ apps_uses = {'bar': {'uses': []}}
4039+ self.set_test_snap_yaml("uses", uses)
4040+ self.set_test_snap_yaml("apps", apps_uses)
4041+ c = SnapReviewLint(self.test_name)
4042+ c.check_apps_uses()
4043+ r = c.click_report
4044+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
4045+ self.check_results(r, expected_counts)
4046+
4047+ def test_check_apps_uses_bad_entry(self):
4048+ '''Test check_apps_uses() - bad entry (dict)'''
4049+ uses = self._create_top_uses()
4050+ apps_uses = {'bar': {'uses': [{}]}}
4051+ self.set_test_snap_yaml("uses", uses)
4052+ self.set_test_snap_yaml("apps", apps_uses)
4053+ c = SnapReviewLint(self.test_name)
4054+ c.check_apps_uses()
4055+ r = c.click_report
4056+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
4057+ self.check_results(r, expected_counts)
4058+
4059+ def test_check_apps_uses_unknown_entry(self):
4060+ '''Test check_apps_uses() - unknown'''
4061+ uses = self._create_top_uses()
4062+ apps_uses = {'bar': {'uses': ['nonexistent']}}
4063+ self.set_test_snap_yaml("uses", uses)
4064+ self.set_test_snap_yaml("apps", apps_uses)
4065+ c = SnapReviewLint(self.test_name)
4066+ c.check_apps_uses()
4067+ r = c.click_report
4068+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
4069+ self.check_results(r, expected_counts)
4070+
4071+
4072+class TestSnapReviewLintNoMock(TestCase):
4073+ """Tests without mocks where they are not needed."""
4074+ def setUp(self):
4075+ # XXX cleanup_unpack() is required because global variables
4076+ # UNPACK_DIR, RAW_UNPACK_DIR are initialised to None at module
4077+ # load time, but updated when a real (non-Mock) test runs, such as
4078+ # here. While, at the same time, two of the existing tests using
4079+ # mocks depend on both global vars being None. Ideally, those
4080+ # global vars should be refactored away.
4081+ self.addCleanup(cleanup_unpack)
4082+ super().setUp()
4083+
4084+ def mkdtemp(self):
4085+ """Create a temp dir which is cleaned up after test."""
4086+ tmp_dir = tempfile.mkdtemp()
4087+ self.addCleanup(shutil.rmtree, tmp_dir)
4088+ return tmp_dir
4089+
4090+ def check_results(self, report,
4091+ expected_counts={'info': 1, 'warn': 0, 'error': 0},
4092+ expected=None):
4093+ common_check_results(self, report, expected_counts, expected)
4094+
4095+ def test_check_external_symlinks(self):
4096+ '''Test check_external_symlinks()'''
4097+ package = utils.make_snap2(output_dir=self.mkdtemp())
4098+ c = SnapReviewLint(package)
4099+ c.check_external_symlinks()
4100+ r = c.click_report
4101+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
4102+ self.check_results(r, expected_counts)
4103+
4104+ def test_check_external_symlinks_has_symlink(self):
4105+ '''Test check_external_symlinks() - has symlink'''
4106+ package = utils.make_snap2(output_dir=self.mkdtemp(),
4107+ extra_files=['/some/where,outside']
4108+ )
4109+ c = SnapReviewLint(package)
4110+ c.check_external_symlinks()
4111+ r = c.click_report
4112+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
4113+ self.check_results(r, expected_counts)
4114+
4115+ def test_check_architecture_all(self):
4116+ '''Test check_architecture_all()'''
4117+ package = utils.make_snap2(output_dir=self.mkdtemp())
4118+ c = SnapReviewLint(package)
4119+ c.check_architecture_all()
4120+ r = c.click_report
4121+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
4122+ self.check_results(r, expected_counts)
4123+
4124+ def test_check_architecture_all_has_binary(self):
4125+ '''Test check_architecture_all() - has binary'''
4126+ package = utils.make_snap2(output_dir=self.mkdtemp(),
4127+ extra_files=['/bin/ls:ls']
4128+ )
4129+ c = SnapReviewLint(package)
4130+ c.check_architecture_all()
4131+ r = c.click_report
4132+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
4133+ self.check_results(r, expected_counts)
4134+
4135+ def test_check_architecture_specified_needed_has_binary(self):
4136+ '''Test check_architecture_specified_needed() - has binary'''
4137+ output_dir = self.mkdtemp()
4138+ path = os.path.join(output_dir, 'snap.yaml')
4139+ content = '''
4140+name: test
4141+version: 0.1
4142+summary: some thing
4143+description: some desc
4144+architectures: [ amd64 ]
4145+'''
4146+ with open(path, 'w') as f:
4147+ f.write(content)
4148+
4149+ package = utils.make_snap2(output_dir=output_dir,
4150+ extra_files=['%s:meta/snap.yaml' % path,
4151+ '/bin/ls:ls'
4152+ ]
4153+ )
4154+ c = SnapReviewLint(package)
4155+ c.check_architecture_specified_needed()
4156+ r = c.click_report
4157+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
4158+ self.check_results(r, expected_counts)
4159+
4160+ def test_check_architecture_specified_needed(self):
4161+ '''Test check_architecture_specified_needed()'''
4162+ output_dir = self.mkdtemp()
4163+ path = os.path.join(output_dir, 'snap.yaml')
4164+ content = '''
4165+name: test
4166+version: 0.1
4167+summary: some thing
4168+description: some desc
4169+architectures: [ amd64 ]
4170+'''
4171+ with open(path, 'w') as f:
4172+ f.write(content)
4173+
4174+ package = utils.make_snap2(output_dir=output_dir,
4175+ extra_files=['%s:meta/snap.yaml' % path]
4176+ )
4177+ c = SnapReviewLint(package)
4178+ c.check_architecture_specified_needed()
4179+ r = c.click_report
4180+ expected_counts = {'info': None, 'warn': 1, 'error': 0}
4181+ self.check_results(r, expected_counts)
4182+
4183+ def test_check_vcs(self):
4184+ '''Test check_vcs()'''
4185+ package = utils.make_snap2(output_dir=self.mkdtemp())
4186+ c = SnapReviewLint(package)
4187+ c.check_vcs()
4188+ r = c.click_report
4189+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
4190+ self.check_results(r, expected_counts)
4191+
4192+ def test_check_vcs_bzrignore(self):
4193+ '''Test check_vcs() - .bzrignore'''
4194+ package = utils.make_snap2(output_dir=self.mkdtemp(),
4195+ extra_files=['.bzrignore']
4196+ )
4197+ c = SnapReviewLint(package)
4198+ c.check_vcs()
4199+ r = c.click_report
4200+ expected_counts = {'info': None, 'warn': 1, 'error': 0}
4201+ self.check_results(r, expected_counts)
4202
4203=== modified file 'clickreviews/tests/utils.py'
4204--- clickreviews/tests/utils.py 2016-02-09 21:45:25 +0000
4205+++ clickreviews/tests/utils.py 2016-02-11 18:32:45 +0000
4206@@ -1,6 +1,6 @@
4207 '''utils.py: test utils for click reviewer tools'''
4208 #
4209-# Copyright (C) 2013-2015 Canonical Ltd.
4210+# Copyright (C) 2013-2016 Canonical Ltd.
4211 #
4212 # This program is free software: you can redistribute it and/or modify
4213 # it under the terms of the GNU General Public License as published by
4214@@ -14,7 +14,9 @@
4215 # You should have received a copy of the GNU General Public License
4216 # along with this program. If not, see <http://www.gnu.org/licenses/>.
4217
4218-import glob
4219+from clickreviews.common import (
4220+ MKSQUASHFS_OPTS
4221+)
4222 import json
4223 import os
4224 import shutil
4225@@ -22,17 +24,44 @@
4226 import tempfile
4227
4228
4229-def make_package(name='test', pkgfmt_type='click', pkgfmt_version='0.4',
4230- package_types=None, version='1.0', title="An application",
4231- framework='ubuntu-sdk-15.04', extra_files=None,
4232- output_dir=None):
4233+def make_snap2(name='test', pkgfmt_type='snap', pkgfmt_version='16.04',
4234+ version='1.0', summary="An application", extra_files=None,
4235+ output_dir=None):
4236+ '''Return the path to a snap v2 package with the given data.
4237+
4238+ Caller is responsible for deleting the output_dir afterwards.
4239+ '''
4240+ assert(pkgfmt_type == "snap" and pkgfmt_version != "15.04")
4241+
4242+ build_dir = tempfile.mkdtemp()
4243+
4244+ try:
4245+ make_dir_structure(build_dir, pkgfmt_type=pkgfmt_type,
4246+ pkgfmt_version=pkgfmt_version,
4247+ extra_files=extra_files)
4248+ write_icon(build_dir)
4249+ description = summary
4250+ write_meta_data2(build_dir, name, version, summary, description)
4251+ pkg_path = build_package(build_dir, name, version, pkgfmt_type,
4252+ pkgfmt_version, output_dir=output_dir)
4253+ finally:
4254+ shutil.rmtree(build_dir)
4255+
4256+ return pkg_path
4257+
4258+
4259+def make_click(name='test', pkgfmt_type='click', pkgfmt_version='0.4',
4260+ package_types=None, version='1.0', title="An application",
4261+ framework='ubuntu-sdk-15.04', extra_files=None,
4262+ output_dir=None):
4263 """Return the path to a click/snap package with the given data.
4264
4265 Caller is responsible for deleting the output_dir afterwards.
4266 """
4267- is_snap1 = (pkgfmt_type == "snap" and pkgfmt_version == "15.04")
4268- # TODO: implement writing snap2 packages
4269- # is_snap2 = (pkgfmt_type == "snap" and not pkgfmt_version == "15.04")
4270+ assert(pkgfmt_type == "click" or (pkgfmt_type == "snap" and
4271+ pkgfmt_version == "15.04"))
4272+
4273+ is_snap1 = (pkgfmt_type == "snap")
4274 build_dir = tempfile.mkdtemp()
4275 package_types = package_types or []
4276
4277@@ -42,19 +71,19 @@
4278 extra_files=extra_files)
4279 write_icon(build_dir)
4280
4281- if pkgfmt_type == 'click' or pkgfmt_version == 15.04:
4282- write_manifest(build_dir, name, version,
4283- title, framework, package_types,
4284- is_snap1)
4285- write_control(build_dir, name, version, title, pkgfmt_version)
4286- write_preinst(build_dir)
4287- write_apparmor_profile(build_dir, name)
4288- write_other_files(build_dir)
4289- else:
4290+ write_manifest(build_dir, name, version,
4291+ title, framework, package_types,
4292+ is_snap1)
4293+ write_control(build_dir, name, version, title, pkgfmt_version)
4294+ write_preinst(build_dir)
4295+ write_apparmor_profile(build_dir, name)
4296+ write_other_files(build_dir)
4297+
4298+ if pkgfmt_type == 'snap':
4299 write_meta_data(build_dir, name, version, title, framework)
4300
4301 pkg_path = build_package(build_dir, name, version, pkgfmt_type,
4302- output_dir=output_dir)
4303+ pkgfmt_version, output_dir=output_dir)
4304 finally:
4305 shutil.rmtree(build_dir)
4306
4307@@ -62,33 +91,81 @@
4308
4309
4310 def make_dir_structure(path, pkgfmt_type, pkgfmt_version, extra_files=None):
4311+ '''Create the mandatory dir structure and extra_files. Format for
4312+ extra_files:
4313+ path/to/file create empty file in path
4314+ path/to/dir/ create empty dir in path
4315+ path/to/source,path/to/link create symlink in path
4316+ path/to/source:path/to/link copy source to path
4317+
4318+ For symlink and copy, source can be an absolute path for pointing
4319+ outside of the dir (for symlinks) or copying into the package.
4320+ '''
4321 extra_files = extra_files or []
4322- directories = ['meta']
4323+
4324+ directories = ['meta'] # write_icon() and write_manifest() assume this
4325 if pkgfmt_type == 'click' or pkgfmt_version == 15.04:
4326 directories.append('DEBIAN')
4327
4328- directories.extend(
4329- [os.path.dirname(extra_file) for extra_file in extra_files])
4330-
4331+ # enumerate the directories to create
4332+ for extra_file in extra_files:
4333+ if ',' in extra_file:
4334+ extra = extra_file.split(',', 1)[1]
4335+ elif ':' in extra_file:
4336+ extra = extra_file.split(':', 1)[1]
4337+ else:
4338+ extra = extra_file
4339+
4340+ if extra.startswith('/'):
4341+ extra = extra[1:]
4342+
4343+ if extra.endswith('/'):
4344+ directories.append(extra)
4345+ else:
4346+ directories.append(os.path.dirname(extra))
4347+
4348+ # make the enumerated directories
4349 for directory in directories:
4350 directory = os.path.join(path, directory)
4351 if not os.path.exists(directory):
4352 os.makedirs(directory)
4353
4354 for extra_file in extra_files:
4355- dirname, basename = os.path.split(extra_file)
4356+ if extra_file.endswith('/'): # nothing more to do for directories
4357+ continue
4358+
4359+ source_link = None
4360+ source_path = None
4361+ if ',' in extra_file:
4362+ (source_link, target_path) = extra_file.split(',', 1)
4363+ elif ':' in extra_file:
4364+ (source_path, target_path) = extra_file.split(':', 1)
4365+ else:
4366+ target_path = extra_file
4367+
4368+ dirname, basename = os.path.split(target_path)
4369 if basename != '':
4370- with open(os.path.join(path, extra_file), 'wb'):
4371- pass
4372+ if source_path:
4373+ if not source_path.startswith('/'):
4374+ source_path = os.path.join(path, source_path)
4375+ shutil.copyfile(source_path, os.path.join(path, target_path))
4376+ elif source_link:
4377+ cur = os.getcwd()
4378+ if target_path.startswith('/'):
4379+ target_path = os.path.join(path, target_path[1:])
4380+ else:
4381+ os.chdir(path)
4382+ os.symlink(source_link, target_path)
4383+ os.chdir(cur)
4384+ else:
4385+ with open(os.path.join(path, target_path), 'wb'):
4386+ pass
4387
4388
4389 def write_icon(path):
4390- # XXX: Update to use a test icon in the branch to guarantee an icon.
4391- icons = glob.glob('/usr/share/icons/hicolor/256x256/apps/*.png')
4392- if len(icons) > 0:
4393- source_path = icons[0]
4394- target_path = os.path.join(path, 'meta', 'icon.png')
4395- shutil.copyfile(source_path, target_path)
4396+ source_path = os.path.join(os.getcwd(), 'clickreviews/data/icon.png')
4397+ target_path = os.path.join(path, 'meta', 'icon.png')
4398+ shutil.copyfile(source_path, target_path)
4399
4400
4401 def write_manifest(path, name, version, title, framework, types, is_snap):
4402@@ -127,17 +204,37 @@
4403 content = """architectures:
4404 icon: meta/icon.png
4405 name: {}
4406-version: "{}",
4407-framework: {},
4408+version: {}
4409+framework: {}
4410 vendor: 'Someone <someone@example.com>',
4411 """.format(name, version, framework)
4412
4413- with open(yaml_path, 'w') as f:
4414- f.write(content)
4415+ # don't overwrite 'copy' via make_dir_structure()
4416+ if not os.path.exists(yaml_path):
4417+ with open(yaml_path, 'w') as f:
4418+ f.write(content)
4419 with open(os.path.join(path, 'meta', 'readme.md'), 'w') as f:
4420 f.write(title)
4421
4422
4423+def write_meta_data2(path, name, version, summary, description, yaml=None):
4424+ yaml_path = os.path.join(path, 'meta', 'snap.yaml')
4425+ if yaml:
4426+ content = yaml
4427+ else:
4428+ content = """architectures: [ all ]
4429+name: {}
4430+version: {}
4431+summary: {}
4432+description: {}
4433+""".format(name, version, summary, description)
4434+
4435+ # don't overwrite 'copy' via make_dir_structure()
4436+ if not os.path.exists(yaml_path):
4437+ with open(yaml_path, 'w') as f:
4438+ f.write(content)
4439+
4440+
4441 def write_control(path, name, version, title, pkgfmt_version):
4442 control_path = os.path.join(path, 'DEBIAN', 'control')
4443 control_content = {'Package': name,
4444@@ -182,15 +279,23 @@
4445 write_empty_file(os.path.join(path, 'DEBIAN', 'md5sums'))
4446
4447
4448-def build_package(path, name, version, format, output_dir=None):
4449- filename = "{}_{}_all.{}".format(name, version, format)
4450+def build_package(path, name, version, pkgfmt_type, pkgfmt_version,
4451+ output_dir=None):
4452+ filename = "{}_{}_all.{}".format(name, version, pkgfmt_type)
4453 output_dir = output_dir or tempfile.mkdtemp()
4454 output_path = os.path.join(output_dir, filename)
4455
4456- # Note: We're not using 'click build' here as it corrects errors (such
4457- # as filtering out a .click directory present in the build). We want
4458- # to test with manually constructed, potentially tampered-with
4459- # clicks/snaps. Ideally, we'd be using click rather than dpkg to
4460- # construct the click without filtering any files in the build dir.
4461- subprocess.check_call(['dpkg-deb', '-b', path, output_path])
4462+ if pkgfmt_type == "snap" and pkgfmt_version != "15.04":
4463+ args = ['mksquashfs', path, output_path] + MKSQUASHFS_OPTS
4464+ # debugging
4465+ # subprocess.check_call(args)
4466+ # subprocess.check_call(['unsquashfs', '-lls', output_path])
4467+ subprocess.check_call(args, stdout=open(os.devnull, 'w'))
4468+ else: # click and snap v1
4469+ # Note: We're not using 'click build' here as it corrects errors (such
4470+ # as filtering out a .click directory present in the build). We want
4471+ # to test with manually constructed, potentially tampered-with
4472+ # clicks/snaps. Ideally, we'd be using click rather than dpkg to
4473+ # construct the click without filtering any files in the build dir.
4474+ subprocess.check_call(['dpkg-deb', '-b', path, output_path])
4475 return output_path

Subscribers

People subscribed via source and target branches