xref: /rk3399_rockchip-uboot/tools/buildman/func_test.py (revision 8b985eebd0f7582614399fdf6c108a81ab446ae7)
1d4144e45SSimon Glass#
2d4144e45SSimon Glass# Copyright (c) 2014 Google, Inc
3d4144e45SSimon Glass#
4d4144e45SSimon Glass# SPDX-License-Identifier:      GPL-2.0+
5d4144e45SSimon Glass#
6d4144e45SSimon Glass
7d4144e45SSimon Glassimport os
8d4144e45SSimon Glassimport shutil
9d4144e45SSimon Glassimport sys
10d4144e45SSimon Glassimport tempfile
11d4144e45SSimon Glassimport unittest
12d4144e45SSimon Glass
13*8b985eebSSimon Glassimport bsettings
14d4144e45SSimon Glassimport cmdline
15d4144e45SSimon Glassimport command
16d4144e45SSimon Glassimport control
17d4144e45SSimon Glassimport gitutil
18d4144e45SSimon Glassimport terminal
19d4144e45SSimon Glassimport toolchain
20d4144e45SSimon Glass
21*8b985eebSSimon Glasssettings_data = '''
22*8b985eebSSimon Glass# Buildman settings file
23*8b985eebSSimon Glass
24*8b985eebSSimon Glass[toolchain]
25*8b985eebSSimon Glass
26*8b985eebSSimon Glass[toolchain-alias]
27*8b985eebSSimon Glass
28*8b985eebSSimon Glass[make-flags]
29*8b985eebSSimon Glasssrc=/home/sjg/c/src
30*8b985eebSSimon Glasschroot=/home/sjg/c/chroot
31*8b985eebSSimon Glassvboot=USE_STDINT=1 VBOOT_DEBUG=1 MAKEFLAGS_VBOOT=DEBUG=1 CFLAGS_EXTRA_VBOOT=-DUNROLL_LOOPS VBOOT_SOURCE=${src}/platform/vboot_reference
32*8b985eebSSimon Glasschromeos_coreboot=VBOOT=${chroot}/build/link/usr ${vboot}
33*8b985eebSSimon Glasschromeos_daisy=VBOOT=${chroot}/build/daisy/usr ${vboot}
34*8b985eebSSimon Glasschromeos_peach=VBOOT=${chroot}/build/peach_pit/usr ${vboot}
35*8b985eebSSimon Glass'''
36*8b985eebSSimon Glass
37d4144e45SSimon Glassclass TestFunctional(unittest.TestCase):
38d4144e45SSimon Glass    """Functional test for buildman.
39d4144e45SSimon Glass
40d4144e45SSimon Glass    This aims to test from just below the invocation of buildman (parsing
41d4144e45SSimon Glass    of arguments) to 'make' and 'git' invocation. It is not a true
42d4144e45SSimon Glass    emd-to-end test, as it mocks git, make and the tool chain. But this
43d4144e45SSimon Glass    makes it easier to detect when the builder is doing the wrong thing,
44d4144e45SSimon Glass    since in many cases this test code will fail. For example, only a
45d4144e45SSimon Glass    very limited subset of 'git' arguments is supported - anything
46d4144e45SSimon Glass    unexpected will fail.
47d4144e45SSimon Glass    """
48d4144e45SSimon Glass    def setUp(self):
49d4144e45SSimon Glass        self._base_dir = tempfile.mkdtemp()
50d4144e45SSimon Glass        self._git_dir = os.path.join(self._base_dir, 'src')
51d4144e45SSimon Glass        self._buildman_pathname = sys.argv[0]
52d4144e45SSimon Glass        self._buildman_dir = os.path.dirname(sys.argv[0])
53d4144e45SSimon Glass        command.test_result = self._HandleCommand
54d4144e45SSimon Glass        self._toolchains = toolchain.Toolchains()
55d4144e45SSimon Glass        self._toolchains.Add('gcc', test=False)
56*8b985eebSSimon Glass        bsettings.Setup(None)
57*8b985eebSSimon Glass        bsettings.AddFile(settings_data)
58d4144e45SSimon Glass
59d4144e45SSimon Glass    def tearDown(self):
60d4144e45SSimon Glass        shutil.rmtree(self._base_dir)
61d4144e45SSimon Glass
62d4144e45SSimon Glass    def _RunBuildman(self, *args):
63d4144e45SSimon Glass        return command.RunPipe([[self._buildman_pathname] + list(args)],
64d4144e45SSimon Glass                capture=True, capture_stderr=True)
65d4144e45SSimon Glass
66d4144e45SSimon Glass    def _RunControl(self, *args):
67d4144e45SSimon Glass        sys.argv = [sys.argv[0]] + list(args)
68d4144e45SSimon Glass        options, args = cmdline.ParseArgs()
69d4144e45SSimon Glass        return control.DoBuildman(options, args, toolchains=self._toolchains,
70d4144e45SSimon Glass                make_func=self._HandleMake)
71d4144e45SSimon Glass
72d4144e45SSimon Glass    def testFullHelp(self):
73d4144e45SSimon Glass        command.test_result = None
74d4144e45SSimon Glass        result = self._RunBuildman('-H')
75d4144e45SSimon Glass        help_file = os.path.join(self._buildman_dir, 'README')
76d4144e45SSimon Glass        self.assertEqual(len(result.stdout), os.path.getsize(help_file))
77d4144e45SSimon Glass        self.assertEqual(0, len(result.stderr))
78d4144e45SSimon Glass        self.assertEqual(0, result.return_code)
79d4144e45SSimon Glass
80d4144e45SSimon Glass    def testHelp(self):
81d4144e45SSimon Glass        command.test_result = None
82d4144e45SSimon Glass        result = self._RunBuildman('-h')
83d4144e45SSimon Glass        help_file = os.path.join(self._buildman_dir, 'README')
84d4144e45SSimon Glass        self.assertTrue(len(result.stdout) > 1000)
85d4144e45SSimon Glass        self.assertEqual(0, len(result.stderr))
86d4144e45SSimon Glass        self.assertEqual(0, result.return_code)
87d4144e45SSimon Glass
88d4144e45SSimon Glass    def testGitSetup(self):
89d4144e45SSimon Glass        """Test gitutils.Setup(), from outside the module itself"""
90d4144e45SSimon Glass        command.test_result = command.CommandResult(return_code=1)
91d4144e45SSimon Glass        gitutil.Setup()
92d4144e45SSimon Glass        self.assertEqual(gitutil.use_no_decorate, False)
93d4144e45SSimon Glass
94d4144e45SSimon Glass        command.test_result = command.CommandResult(return_code=0)
95d4144e45SSimon Glass        gitutil.Setup()
96d4144e45SSimon Glass        self.assertEqual(gitutil.use_no_decorate, True)
97d4144e45SSimon Glass
98d4144e45SSimon Glass    def _HandleCommandGitLog(self, args):
99d4144e45SSimon Glass        if '-n0' in args:
100d4144e45SSimon Glass            return command.CommandResult(return_code=0)
101d4144e45SSimon Glass
102d4144e45SSimon Glass        # Not handled, so abort
103d4144e45SSimon Glass        print 'git log', args
104d4144e45SSimon Glass        sys.exit(1)
105d4144e45SSimon Glass
106d4144e45SSimon Glass    def _HandleCommandGit(self, in_args):
107d4144e45SSimon Glass        """Handle execution of a git command
108d4144e45SSimon Glass
109d4144e45SSimon Glass        This uses a hacked-up parser.
110d4144e45SSimon Glass
111d4144e45SSimon Glass        Args:
112d4144e45SSimon Glass            in_args: Arguments after 'git' from the command line
113d4144e45SSimon Glass        """
114d4144e45SSimon Glass        git_args = []           # Top-level arguments to git itself
115d4144e45SSimon Glass        sub_cmd = None          # Git sub-command selected
116d4144e45SSimon Glass        args = []               # Arguments to the git sub-command
117d4144e45SSimon Glass        for arg in in_args:
118d4144e45SSimon Glass            if sub_cmd:
119d4144e45SSimon Glass                args.append(arg)
120d4144e45SSimon Glass            elif arg[0] == '-':
121d4144e45SSimon Glass                git_args.append(arg)
122d4144e45SSimon Glass            else:
123d4144e45SSimon Glass                sub_cmd = arg
124d4144e45SSimon Glass        if sub_cmd == 'config':
125d4144e45SSimon Glass            return command.CommandResult(return_code=0)
126d4144e45SSimon Glass        elif sub_cmd == 'log':
127d4144e45SSimon Glass            return self._HandleCommandGitLog(args)
128d4144e45SSimon Glass
129d4144e45SSimon Glass        # Not handled, so abort
130d4144e45SSimon Glass        print 'git', git_args, sub_cmd, args
131d4144e45SSimon Glass        sys.exit(1)
132d4144e45SSimon Glass
133d4144e45SSimon Glass    def _HandleCommandNm(self, args):
134d4144e45SSimon Glass        return command.CommandResult(return_code=0)
135d4144e45SSimon Glass
136d4144e45SSimon Glass    def _HandleCommandObjdump(self, args):
137d4144e45SSimon Glass        return command.CommandResult(return_code=0)
138d4144e45SSimon Glass
139d4144e45SSimon Glass    def _HandleCommandSize(self, args):
140d4144e45SSimon Glass        return command.CommandResult(return_code=0)
141d4144e45SSimon Glass
142d4144e45SSimon Glass    def _HandleCommand(self, **kwargs):
143d4144e45SSimon Glass        """Handle a command execution.
144d4144e45SSimon Glass
145d4144e45SSimon Glass        The command is in kwargs['pipe-list'], as a list of pipes, each a
146d4144e45SSimon Glass        list of commands. The command should be emulated as required for
147d4144e45SSimon Glass        testing purposes.
148d4144e45SSimon Glass
149d4144e45SSimon Glass        Returns:
150d4144e45SSimon Glass            A CommandResult object
151d4144e45SSimon Glass        """
152d4144e45SSimon Glass        pipe_list = kwargs['pipe_list']
153d4144e45SSimon Glass        if len(pipe_list) != 1:
154d4144e45SSimon Glass            print 'invalid pipe', kwargs
155d4144e45SSimon Glass            sys.exit(1)
156d4144e45SSimon Glass        cmd = pipe_list[0][0]
157d4144e45SSimon Glass        args = pipe_list[0][1:]
158d4144e45SSimon Glass        if cmd == 'git':
159d4144e45SSimon Glass            return self._HandleCommandGit(args)
160d4144e45SSimon Glass        elif cmd == './scripts/show-gnu-make':
161d4144e45SSimon Glass            return command.CommandResult(return_code=0, stdout='make')
162d4144e45SSimon Glass        elif cmd == 'nm':
163d4144e45SSimon Glass            return self._HandleCommandNm(args)
164d4144e45SSimon Glass        elif cmd == 'objdump':
165d4144e45SSimon Glass            return self._HandleCommandObjdump(args)
166d4144e45SSimon Glass        elif cmd == 'size':
167d4144e45SSimon Glass            return self._HandleCommandSize(args)
168d4144e45SSimon Glass
169d4144e45SSimon Glass        # Not handled, so abort
170d4144e45SSimon Glass        print 'unknown command', kwargs
171d4144e45SSimon Glass        sys.exit(1)
172d4144e45SSimon Glass        return command.CommandResult(return_code=0)
173d4144e45SSimon Glass
174d4144e45SSimon Glass    def _HandleMake(self, commit, brd, stage, cwd, *args, **kwargs):
175d4144e45SSimon Glass        """Handle execution of 'make'
176d4144e45SSimon Glass
177d4144e45SSimon Glass        Args:
178d4144e45SSimon Glass            commit: Commit object that is being built
179d4144e45SSimon Glass            brd: Board object that is being built
180d4144e45SSimon Glass            stage: Stage that we are at (mrproper, config, build)
181d4144e45SSimon Glass            cwd: Directory where make should be run
182d4144e45SSimon Glass            args: Arguments to pass to make
183d4144e45SSimon Glass            kwargs: Arguments to pass to command.RunPipe()
184d4144e45SSimon Glass        """
185d4144e45SSimon Glass        if stage == 'mrproper':
186d4144e45SSimon Glass            return command.CommandResult(return_code=0)
187d4144e45SSimon Glass        elif stage == 'config':
188d4144e45SSimon Glass            return command.CommandResult(return_code=0,
189d4144e45SSimon Glass                    combined='Test configuration complete')
190d4144e45SSimon Glass        elif stage == 'build':
191d4144e45SSimon Glass            return command.CommandResult(return_code=0)
192d4144e45SSimon Glass
193d4144e45SSimon Glass        # Not handled, so abort
194d4144e45SSimon Glass        print 'make', stage
195d4144e45SSimon Glass        sys.exit(1)
196d4144e45SSimon Glass
197d4144e45SSimon Glass    def testCurrentSource(self):
198d4144e45SSimon Glass        """Very simple test to invoke buildman on the current source"""
199d4144e45SSimon Glass        self._RunControl()
200d4144e45SSimon Glass        lines = terminal.GetPrintTestLines()
201d4144e45SSimon Glass        self.assertTrue(lines[0].text.startswith('Building current source'))
202