aboutsummaryrefslogtreecommitdiff
path: root/lava_dispatcher/test/test_devices.py
blob: b440a20a968a0ec78328e5f35f5834f845a3bf74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# Copyright (C) 2014 Linaro Limited
#
# Author: Neil Williams <neil.williams@linaro.org>
#
# This file is part of LAVA Dispatcher.
#
# LAVA Dispatcher is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LAVA Dispatcher is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along
# with this program; if not, see <http://www.gnu.org/licenses>.

import os
import yaml
import unittest
from lava_dispatcher.action import Action
from lava_common.exceptions import ConfigurationError, JobError
from lava_dispatcher.device import NewDevice
from lava_dispatcher.parser import JobParser
from lava_dispatcher.actions.deploy import DeployAction
from lava_dispatcher.actions.boot import BootAction
from lava_dispatcher.actions.boot.u_boot import BootloaderInterruptAction, UBootAction
from lava_dispatcher.test.test_basic import StdoutTestCase, Factory
from lava_dispatcher.test.utils import DummyLogger, infrastructure_error

# Test the loading of test definitions within the deploy stage


class TestDeviceParser(StdoutTestCase):  # pylint: disable=too-many-public-methods

    def test_new_device(self):
        factory = Factory()
        (rendered, _) = factory.create_device('kvm01.jinja2')
        kvm01 = yaml.safe_load(rendered)
        try:
            self.assertIsNotNone(kvm01['actions'])
        except Exception:
            self.fail("missing actions block for device")
        try:
            self.assertIsNotNone(kvm01['actions']['boot'])
        except Exception:
            self.fail("missing boot block for device")
        try:
            self.assertIsNotNone(kvm01['actions']['deploy'])
        except Exception:
            self.fail("missing boot block for device")
        self.assertTrue('qemu' in kvm01['actions']['boot']['methods'])
        self.assertTrue('image' in kvm01['actions']['deploy']['methods'])


class FakeAction(Action):

    name = "fake"
    description = "fake action for unit tests"
    summary = "fake action"


class TestJobDeviceParameters(StdoutTestCase):  # pylint: disable=too-many-public-methods
    """
    Test parsing of device configuration into job parameters
    """

    def test_device_parser(self):
        job_parser = JobParser()
        factory = Factory()
        job = factory.create_job('bbb-01.jinja2', 'sample_jobs/uboot-ramdisk.yaml')
        uboot_action = None
        device = job.device
        for action in job.pipeline.actions:
            if isinstance(action, DeployAction):
                self.assertIn('ramdisk', action.parameters)
            if isinstance(action, BootAction):
                self.assertIn('method', action.parameters)
                self.assertEqual('u-boot', action.parameters['method'])

                methods = device['actions']['boot']['methods']
                self.assertIn('ramdisk', methods['u-boot'])
                self.assertIn('bootloader_prompt', methods['u-boot']['parameters'])
                self.assertIsNotNone(
                    methods[action.parameters['method']][action.parameters['commands']]['commands'])
                for line in methods[action.parameters['method']][action.parameters['commands']]['commands']:
                    self.assertIsNotNone(line)
                self.assertIsInstance(action, UBootAction)
                uboot_action = action
        self.assertIsNotNone(uboot_action)
        uboot_action.validate()
        self.assertTrue(uboot_action.valid)
        for action in uboot_action.internal_pipeline.actions:
            if isinstance(action, BootloaderInterruptAction):
                self.assertIn('power-on', action.job.device['commands'])
                self.assertIn('hard_reset', action.job.device['commands'])
                self.assertIn('connect', action.job.device['commands'])
                self.assertEqual(action.job.device['commands']['connect'].split(' ')[0], 'telnet')
                self.assertTrue(action.interrupt_newline)
            if isinstance(action, UBootAction):
                self.assertIn('method', action.parameters)
                self.assertIn('commands', action.parameters)
                self.assertIn('ramdisk', action.parameters['u-boot'])
                self.assertIn(action.parameters['commands'], action.parameters[action.parameters['method']])
                self.assertIn('commands', action.parameters[action.parameters['method']][action.parameters['commands']])
                self.assertIsNotNone(action.parameters['u-boot']['ramdisk'])
                self.assertIsInstance(action.parameters['u-boot']['ramdisk']['commands'], list)
                self.assertTrue(len(action.parameters['u-boot']['ramdisk']['commands']) > 2)

    def test_device_power(self):
        factory = Factory()
        (rendered, _) = factory.create_device('bbb-01.jinja2')
        device = yaml.safe_load(rendered)
        self.assertNotEqual(device['commands'].get('hard_reset', ''), '')
        (rendered, _) = factory.create_device('kvm01.jinja2')
        device = yaml.safe_load(rendered)
        self.assertNotIn('commands', device)

    def test_device_constants(self):
        factory = Factory()
        (rendered, _) = factory.create_device('bbb-01.jinja2')
        device = NewDevice(yaml.safe_load(rendered))
        self.assertIn('constants', device)
        self.assertEqual(device.get_constant('kernel-start-message'), "Linux version [0-9]")
        self.assertRaises(ConfigurationError,
                          device.get_constant, ('non-existing-const'))


class TestDeviceEnvironment(StdoutTestCase):  # pylint: disable=too-many-public-methods
    """
    Test parsing of device environment support
    """

    def test_empty_device_environment(self):
        factory = Factory()
        data = None
        job_parser = JobParser()
        (rendered, _) = factory.create_device('bbb-01.jinja2')
        device = NewDevice(yaml.safe_load(rendered))
        sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs/uboot-ramdisk.yaml')
        with open(sample_job_file) as sample_job_data:
            job = job_parser.parse(
                sample_job_data, device, 4212, None, "",
                env_dut=data)
        self.assertEqual(
            job.parameters['env_dut'],
            None
        )

    @unittest.skipIf(infrastructure_error('mkimage'), "u-boot-tools not installed")
    def test_device_environment_validity(self):  # pylint: disable=invalid-name
        """
        Use non-YAML syntax a bit like existing device config syntax.
        Ensure this syntax is picked up as invalid.
        """
        data = """
# YAML syntax.
overrides:
 DEBEMAIL = "codehelp@debian.org"
 DEBFULLNAME: "Neil Williams"
        """
        factory = Factory()
        job_parser = JobParser()
        (rendered, _) = factory.create_device('bbb-01.jinja2')
        device = NewDevice(yaml.safe_load(rendered))
        sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs/uboot-ramdisk.yaml')
        with open(sample_job_file) as sample_job_data:
            job = job_parser.parse(
                sample_job_data, device, 4212, None, "",
                env_dut=data)
        job.logger = DummyLogger()
        self.assertEqual(
            job.parameters['env_dut'],
            data
        )
        with self.assertRaises(JobError):
            job.validate()

    @unittest.skipIf(infrastructure_error('mkimage'), "u-boot-tools not installed")
    def test_device_environment(self):
        data = """
# YAML syntax.
overrides:
 DEBEMAIL: "codehelp@debian.org"
 DEBFULLNAME: "Neil Williams"
        """
        factory = Factory()
        job_parser = JobParser()
        (rendered, _) = factory.create_device('bbb-01.jinja2')
        device = NewDevice(yaml.safe_load(rendered))
        sample_job_file = os.path.join(os.path.dirname(__file__), 'sample_jobs/uboot-ramdisk.yaml')
        with open(sample_job_file) as sample_job_data:
            job = job_parser.parse(
                sample_job_data, device, 4212, None, "",
                env_dut=data)
        job.logger = DummyLogger()
        self.assertEqual(
            job.parameters['env_dut'],
            data
        )
        job.validate()
        boot_actions = [
            action.internal_pipeline.actions for action in job.pipeline.actions if action.name == 'uboot-action'][0]
        retry = [action for action in boot_actions if action.name == 'uboot-retry'][0]
        boot_env = [action for action in retry.internal_pipeline.actions if action.name == 'export-device-env'][0]
        found = False
        for line in boot_env.env:
            if 'DEBFULLNAME' in line:
                found = True
                # assert that the string containing a space still contains that space and is quoted
                self.assertIn('\\\'Neil Williams\\\'', line)
        self.assertTrue(found)


class TestCommand(StdoutTestCase):

    def test_silent(self):
        fake = FakeAction()
        command = 'true'
        log = fake.run_command(command.split(' '))
        self.assertEqual(log, '')
        self.assertEqual([], fake.errors)

    def test_allow_silent(self):
        fake = FakeAction()
        command = 'true'
        log = fake.run_command(command.split(' '), allow_silent=True)
        if not log:
            self.fail(log)
        self.assertEqual([], fake.errors)

    def test_error(self):
        fake = FakeAction()
        command = 'false'
        # sets return code non-zero with no output
        log = fake.run_command(command.split(' '))
        self.assertFalse(log)
        self.assertNotEqual([], fake.errors)

    def test_allow_silent_error(self):
        fake = FakeAction()
        command = 'false'
        log = fake.run_command(command.split(' '), allow_silent=True)
        self.assertFalse(log)
        self.assertNotEqual([], fake.errors)

    def test_invalid(self):
        fake = FakeAction()
        command = './no-script'
        log = fake.run_command(command.split(' '))
        self.assertFalse(log)
        self.assertNotEqual([], fake.errors)

    def test_allow_silent_invalid(self):
        fake = FakeAction()
        command = './no-script'
        log = fake.run_command(command.split(' '), allow_silent=True)
        self.assertFalse(log)
        self.assertNotEqual([], fake.errors)