Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 1 | # Copyright (C) 2017 Intel Corporation |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 2 | # |
| 3 | # SPDX-License-Identifier: MIT |
| 4 | # |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 5 | |
| 6 | import glob |
| 7 | import os |
| 8 | import unittest |
Andrew Geissler | 595f630 | 2022-01-24 19:11:47 +0000 | [diff] [blame] | 9 | import re |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 10 | from checklayer import get_signatures, LayerType, check_command, get_depgraph, compare_signatures |
| 11 | from checklayer.case import OECheckLayerTestCase |
| 12 | |
| 13 | class CommonCheckLayer(OECheckLayerTestCase): |
| 14 | def test_readme(self): |
Andrew Geissler | 517393d | 2023-01-13 08:55:19 -0600 | [diff] [blame] | 15 | if self.tc.layer['type'] == LayerType.CORE: |
| 16 | raise unittest.SkipTest("Core layer's README is top level") |
| 17 | |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 18 | # The top-level README file may have a suffix (like README.rst or README.txt). |
Brad Bishop | 79641f2 | 2019-09-10 07:20:22 -0400 | [diff] [blame] | 19 | readme_files = glob.glob(os.path.join(self.tc.layer['path'], '[Rr][Ee][Aa][Dd][Mm][Ee]*')) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 20 | self.assertTrue(len(readme_files) > 0, |
Andrew Geissler | 595f630 | 2022-01-24 19:11:47 +0000 | [diff] [blame] | 21 | msg="Layer doesn't contain a README file.") |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 22 | |
| 23 | # There might be more than one file matching the file pattern above |
| 24 | # (for example, README.rst and README-COPYING.rst). The one with the shortest |
| 25 | # name is considered the "main" one. |
| 26 | readme_file = sorted(readme_files)[0] |
| 27 | data = '' |
| 28 | with open(readme_file, 'r') as f: |
| 29 | data = f.read() |
| 30 | self.assertTrue(data, |
| 31 | msg="Layer contains a README file but it is empty.") |
| 32 | |
Andrew Geissler | 595f630 | 2022-01-24 19:11:47 +0000 | [diff] [blame] | 33 | # If a layer's README references another README, then the checks below are not valid |
| 34 | if re.search('README', data, re.IGNORECASE): |
| 35 | return |
| 36 | |
| 37 | self.assertIn('maintainer', data.lower()) |
| 38 | self.assertIn('patch', data.lower()) |
| 39 | # Check that there is an email address in the README |
| 40 | email_regex = re.compile(r"[^@]+@[^@]+") |
| 41 | self.assertTrue(email_regex.match(data)) |
| 42 | |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 43 | def test_parse(self): |
| 44 | check_command('Layer %s failed to parse.' % self.tc.layer['name'], |
| 45 | 'bitbake -p') |
| 46 | |
| 47 | def test_show_environment(self): |
| 48 | check_command('Layer %s failed to show environment.' % self.tc.layer['name'], |
| 49 | 'bitbake -e') |
| 50 | |
| 51 | def test_world(self): |
| 52 | ''' |
| 53 | "bitbake world" is expected to work. test_signatures does not cover that |
| 54 | because it is more lenient and ignores recipes in a world build that |
| 55 | are not actually buildable, so here we fail when "bitbake -S none world" |
| 56 | fails. |
| 57 | ''' |
| 58 | get_signatures(self.td['builddir'], failsafe=False) |
| 59 | |
Andrew Geissler | 7e0e3c0 | 2022-02-25 20:34:39 +0000 | [diff] [blame] | 60 | def test_world_inherit_class(self): |
| 61 | ''' |
| 62 | This also does "bitbake -S none world" along with inheriting "yocto-check-layer" |
| 63 | class, which can do additional per-recipe test cases. |
| 64 | ''' |
| 65 | msg = [] |
| 66 | try: |
| 67 | get_signatures(self.td['builddir'], failsafe=False, machine=None, extravars='BB_ENV_PASSTHROUGH_ADDITIONS="$BB_ENV_PASSTHROUGH_ADDITIONS INHERIT" INHERIT="yocto-check-layer"') |
| 68 | except RuntimeError as ex: |
| 69 | msg.append(str(ex)) |
| 70 | if msg: |
| 71 | msg.insert(0, 'Layer %s failed additional checks from yocto-check-layer.bbclass\nSee below log for specific recipe parsing errors:\n' % \ |
| 72 | self.tc.layer['name']) |
| 73 | self.fail('\n'.join(msg)) |
| 74 | |
Andrew Geissler | 6aa7eec | 2023-03-03 12:41:14 -0600 | [diff] [blame^] | 75 | @unittest.expectedFailure |
| 76 | def test_patches_upstream_status(self): |
| 77 | import sys |
| 78 | sys.path.append(os.path.join(sys.path[0], '../../../../meta/lib/')) |
| 79 | import oe.qa |
| 80 | patches = [] |
| 81 | for dirpath, dirs, files in os.walk(self.tc.layer['path']): |
| 82 | for filename in files: |
| 83 | if filename.endswith(".patch"): |
| 84 | ppath = os.path.join(dirpath, filename) |
| 85 | if oe.qa.check_upstream_status(ppath): |
| 86 | patches.append(ppath) |
| 87 | self.assertEqual(len(patches), 0 , \ |
| 88 | msg="Found following patches with malformed or missing upstream status:\n%s" % '\n'.join([str(patch) for patch in patches])) |
| 89 | |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 90 | def test_signatures(self): |
| 91 | if self.tc.layer['type'] == LayerType.SOFTWARE and \ |
| 92 | not self.tc.test_software_layer_signatures: |
| 93 | raise unittest.SkipTest("Not testing for signature changes in a software layer %s." \ |
| 94 | % self.tc.layer['name']) |
| 95 | |
| 96 | curr_sigs, _ = get_signatures(self.td['builddir'], failsafe=True) |
| 97 | msg = compare_signatures(self.td['sigs'], curr_sigs) |
| 98 | if msg is not None: |
| 99 | self.fail('Adding layer %s changed signatures.\n%s' % (self.tc.layer['name'], msg)) |
Brad Bishop | 316dfdd | 2018-06-25 12:45:53 -0400 | [diff] [blame] | 100 | |
| 101 | def test_layerseries_compat(self): |
| 102 | for collection_name, collection_data in self.tc.layer['collections'].items(): |
| 103 | self.assertTrue(collection_data['compat'], "Collection %s from layer %s does not set compatible oe-core versions via LAYERSERIES_COMPAT_collection." \ |
| 104 | % (collection_name, self.tc.layer['name'])) |