1import os
2import json
3import pathlib
4import subprocess
5import tempfile
6import unittest.mock
7
8from oeqa.selftest.case import OESelftestTestCase
9from oeqa.core.decorator import OETestTag
10
11runfvp = pathlib.Path(__file__).parents[5] / "scripts" / "runfvp"
12testdir = pathlib.Path(__file__).parent / "tests"
13
14@OETestTag("meta-arm")
15class RunFVPTests(OESelftestTestCase):
16    def setUpLocal(self):
17        self.assertTrue(runfvp.exists())
18
19    def run_fvp(self, *args, env=None, should_succeed=True):
20        """
21        Call runfvp passing any arguments. If check is True verify return stdout
22        on exit code 0 or fail the test, otherwise return the CompletedProcess
23        instance.
24        """
25        cli = [runfvp,] + list(args)
26        print(f"Calling {cli}")
27        # Set cwd to testdir so that any mock FVPs are found
28        ret = subprocess.run(cli, cwd=testdir, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
29        if should_succeed:
30            self.assertEqual(ret.returncode, 0, f"runfvp exit {ret.returncode}, output: {ret.stdout}")
31            return ret.stdout
32        else:
33            self.assertNotEqual(ret.returncode, 0, f"runfvp exit {ret.returncode}, output: {ret.stdout}")
34            return ret.stdout
35
36    def test_help(self):
37        output = self.run_fvp("--help")
38        self.assertIn("Run images in a FVP", output)
39
40    def test_bad_options(self):
41        self.run_fvp("--this-is-an-invalid-option", should_succeed=False)
42
43    def test_run_auto_tests(self):
44        cases = list(testdir.glob("auto-*.json"))
45        if not cases:
46            self.fail("No tests found")
47        for case in cases:
48            with self.subTest(case=case.stem):
49                self.run_fvp(case)
50
51    def test_fvp_options(self):
52        # test-parameter sets one argument, add another manually
53        self.run_fvp(testdir / "test-parameter.json", "--", "--parameter", "board.dog=woof")
54
55    def test_fvp_environment(self):
56        output = self.run_fvp(testdir / "test-environment.json", env={"DISPLAY": "test_fvp_environment:42"})
57        self.assertEqual(output.strip(), "Found expected DISPLAY")
58
59@OETestTag("meta-arm")
60class ConfFileTests(OESelftestTestCase):
61    def test_no_exe(self):
62        from fvp import conffile
63        with tempfile.NamedTemporaryFile('w') as tf:
64            tf.write('{}')
65            tf.flush()
66
67            with self.assertRaises(ValueError):
68                conffile.load(tf.name)
69
70    def test_minimal(self):
71        from fvp import conffile
72        with tempfile.NamedTemporaryFile('w') as tf:
73            tf.write('{"exe": "FVP_Binary"}')
74            tf.flush()
75
76            conf = conffile.load(tf.name)
77            self.assertTrue('fvp-bindir' in conf)
78            self.assertTrue('fvp-bindir' in conf)
79            self.assertTrue("exe" in conf)
80            self.assertTrue("parameters" in conf)
81            self.assertTrue("data" in conf)
82            self.assertTrue("applications" in conf)
83            self.assertTrue("terminals" in conf)
84            self.assertTrue("args" in conf)
85            self.assertTrue("consoles" in conf)
86            self.assertTrue("env" in conf)
87
88
89@OETestTag("meta-arm")
90class RunnerTests(OESelftestTestCase):
91    def create_mock(self):
92        return unittest.mock.patch("subprocess.Popen")
93
94    @unittest.mock.patch.dict(os.environ, {"PATH": "/path-42:/usr/sbin:/usr/bin:/sbin:/bin"})
95    def test_start(self):
96        from fvp import runner
97        with self.create_mock() as m:
98            fvp = runner.FVPRunner(self.logger)
99            config = {"fvp-bindir": "/usr/bin",
100                    "exe": "FVP_Binary",
101                    "parameters": {'foo': 'bar'},
102                    "data": ['data1'],
103                    "applications": {'a1': 'file'},
104                    "terminals": {},
105                    "args": ['--extra-arg'],
106                    "env": {"FOO": "BAR"}
107                     }
108
109            with tempfile.NamedTemporaryFile('w') as fvpconf:
110                json.dump(config, fvpconf)
111                fvpconf.flush()
112                cwd_mock = os.path.dirname(fvpconf.name)
113                fvp.start(fvpconf.name)
114
115            m.assert_called_once_with(['/usr/bin/FVP_Binary',
116                '--parameter', 'foo=bar',
117                '--data', 'data1',
118                '--application', 'a1=file',
119                '--extra-arg'],
120                stdin=unittest.mock.ANY,
121                stdout=unittest.mock.ANY,
122                stderr=unittest.mock.ANY,
123                env={"FOO":"BAR", "PATH": "/path-42:/usr/sbin:/usr/bin:/sbin:/bin"},
124                cwd=cwd_mock)
125
126    @unittest.mock.patch.dict(os.environ, {"DISPLAY": ":42", "WAYLAND_DISPLAY": "wayland-42", "PATH": "/path-42:/usr/sbin:/usr/bin:/sbin:/bin"})
127    def test_env_passthrough(self):
128        from fvp import runner
129        with self.create_mock() as m:
130            fvp = runner.FVPRunner(self.logger)
131            config = {"fvp-bindir": "/usr/bin",
132                      "exe": "FVP_Binary",
133                      "parameters": {},
134                      "data": [],
135                      "applications": {},
136                      "terminals": {},
137                      "args": [],
138                      "env": {"FOO": "BAR"}
139                     }
140
141            with tempfile.NamedTemporaryFile('w') as fvpconf:
142                json.dump(config, fvpconf)
143                fvpconf.flush()
144                cwd_mock = os.path.dirname(fvpconf.name)
145                fvp.start(fvpconf.name)
146
147            m.assert_called_once_with(['/usr/bin/FVP_Binary'],
148                stdin=unittest.mock.ANY,
149                stdout=unittest.mock.ANY,
150                stderr=unittest.mock.ANY,
151                env={"DISPLAY":":42", "FOO": "BAR", "WAYLAND_DISPLAY": "wayland-42", "PATH": "/path-42:/usr/sbin:/usr/bin:/sbin:/bin"},
152                cwd=cwd_mock)
153