Merge lp:~zyga/lava-core/formats into lp:lava-core

Proposed by Zygmunt Krynicki
Status: Merged
Approved by: Michael Hudson-Doyle
Approved revision: 14
Merged at revision: 14
Proposed branch: lp:~zyga/lava-core/formats
Merge into: lp:lava-core
Diff against target: 267 lines (+258/-0)
2 files modified
lava/core/formats.py (+169/-0)
lava/core/tests/test_formats.py (+89/-0)
To merge this branch: bzr merge lp:~zyga/lava-core/formats
Reviewer Review Type Date Requested Status
Michael Hudson-Doyle (community) Approve
Review via email: mp+107060@code.launchpad.net

Description of the change

This branch adds the well-known but little-specified TestScenario aka 'lava
job' aka 'dispatcher job' JSON file format.

To post a comment you must log in.
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Seems fine. I am really pretty sure that metadata has to a be string -> string mapping and I am reminded again of the subtly different formats of "jobs as accepted by the scheduler" and "jobs as accepted by the dispatcher". Both of those can wait though.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'lava/core/formats.py'
2--- lava/core/formats.py 1970-01-01 00:00:00 +0000
3+++ lava/core/formats.py 2012-05-23 16:16:18 +0000
4@@ -0,0 +1,169 @@
5+# Copyright (C) 2011-2012 Linaro Limited
6+#
7+# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
8+#
9+# This file is part of lava-core
10+#
11+# lava-core is free software: you can redistribute it and/or modify
12+# it under the terms of the GNU Lesser General Public License version 3
13+# as published by the Free Software Foundation
14+#
15+# lava-core is distributed in the hope that it will be useful,
16+# but WITHOUT ANY WARRANTY; without even the implied warranty of
17+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+# GNU General Public License for more details.
19+#
20+# You should have received a copy of the GNU Lesser General Public License
21+# along with lava-core. If not, see <http://www.gnu.org/licenses/>.
22+
23+from __future__ import absolute_import
24+
25+"""
26+lava.core.formats
27+=================
28+"""
29+
30+from json_document.document import Document
31+from json_document import bridge
32+
33+__all__ = ['TestScenario']
34+
35+
36+class ScenarioAction(Document):
37+ """
38+ Fragment of the TestScenario document that describes a single action,
39+ or step, of the test scenario.
40+ """
41+
42+ document_schema = {
43+ 'type': 'object',
44+ 'properties': {
45+ 'command': {
46+ 'type': 'string',
47+ },
48+ 'parameters': {
49+ 'default': {},
50+ 'optional': True,
51+ 'type': 'object',
52+ },
53+ 'metadata': {
54+ 'default': {},
55+ 'optional': True,
56+ # FIXME: meda-data is under-specified
57+ },
58+ },
59+ 'additionalProperties': False
60+ }
61+
62+ @bridge.readwrite
63+ def command(self):
64+ """
65+ Name of the action to perform
66+
67+ Actions can be provided by any third party software. LAVA ships
68+ with a number of useful actions for both Ubuntu and Android.
69+ """
70+
71+ @bridge.fragment
72+ def parameters(self):
73+ """
74+ Dictionary of parameters of this action
75+ """
76+
77+ # XXX: this is ugly, why is it here?
78+ @bridge.readwrite
79+ def metadata(self):
80+ """
81+ Dictionary of meta-data
82+ """
83+
84+
85+class TestScenario(Document):
86+ """
87+ Document describing the test scenario to execute.
88+
89+ The scenario is composed of the target definition and a list of actions to
90+ perform. Each action describes what to do (the action "command" name),
91+ along with any needed parameters.
92+
93+ In addition to actions the scenario describes some additional things such
94+ as the device type, job name or health check flag. They are used for
95+ book-keeping in other parts of LAVA.
96+ """
97+
98+ document_schema = {
99+ 'type': 'object',
100+ 'additionalProperties': {},
101+ 'properties': {
102+ 'actions': {
103+ 'items': ScenarioAction
104+ }
105+ },
106+ 'device_type': {
107+ 'default': None,
108+ 'optional': True,
109+ 'type': 'string',
110+ },
111+ 'job_name': {
112+ 'default': None
113+ 'optional': True,
114+ 'type': 'string',
115+ },
116+ 'health_check': {
117+ 'default': False,
118+ 'optional': True,
119+ 'type': 'bool',
120+ },
121+ 'target': {
122+ 'default': None,
123+ 'optional': True,
124+ 'type': 'string',
125+ },
126+ 'timeout': {
127+ 'default': None,
128+ 'optional': False,
129+ 'type': 'integer',
130+ },
131+ 'logging_level': {
132+ 'default': None
133+ 'enum': ["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"],
134+ 'optional': True,
135+ 'type': 'string',
136+ }
137+ }
138+
139+ @bridge.fragment
140+ def actions(self):
141+ """
142+ List of actions to perform as a part of this scenario
143+ """
144+
145+ @bridge.readwrite
146+ def target(self):
147+ """
148+ Name of the device this test scenario is intended for
149+ """
150+
151+ @bridge.readwrite
152+ def timeout(self):
153+ """
154+ Global job timeout in seconds
155+ """
156+
157+ @bridge.readwrite
158+ def device_type(self):
159+ """"
160+ Type of the device this test scenario is intended for.
161+ """
162+
163+ @bridge.readwrite
164+ def job_name(self):
165+ """
166+ Human-readable name of this job
167+ """
168+
169+ @bridge.readwrite
170+ def health_check(self):
171+ """
172+ Flag used to mark health check jobs
173+ """
174
175=== added file 'lava/core/tests/test_formats.py'
176--- lava/core/tests/test_formats.py 1970-01-01 00:00:00 +0000
177+++ lava/core/tests/test_formats.py 2012-05-23 16:16:18 +0000
178@@ -0,0 +1,89 @@
179+# Copyright (C) 2011-2012 Linaro Limited
180+#
181+# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
182+#
183+# This file is part of lava-core
184+#
185+# lava-core is free software: you can redistribute it and/or modify
186+# it under the terms of the GNU Lesser General Public License version 3
187+# as published by the Free Software Foundation
188+#
189+# lava-core is distributed in the hope that it will be useful,
190+# but WITHOUT ANY WARRANTY; without even the implied warranty of
191+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
192+# GNU General Public License for more details.
193+#
194+# You should have received a copy of the GNU Lesser General Public License
195+# along with lava-core. If not, see <http://www.gnu.org/licenses/>.
196+
197+"""
198+lava.core.tests.test_formats
199+============================
200+
201+Unit tests for the lava.core.formats module
202+"""
203+
204+from unittest2 import TestCase
205+
206+from lava.core.formats import ScenarioAction, TestScenario
207+
208+
209+class ScenarioActionTests(TestCase):
210+
211+ _str1 = "str1"
212+ _str2 = "str2"
213+ _param1 = "param1"
214+
215+ def test_command_getter(self):
216+ """
217+ Getting ScenarioAction.command works
218+ """
219+ action = ScenarioAction({
220+ 'command': self._str1
221+ })
222+ self.assertEqual(action.command, self._str1)
223+
224+ def test_command_setter(self):
225+ """
226+ Setting ScenarioAction.command works
227+ """
228+ action = ScenarioAction({})
229+ action.command = self._str1
230+ self.assertEqual(action.command, self._str1)
231+
232+ def test_command_default(self):
233+ """
234+ ScenarioAction.command has no default
235+ """
236+ action = ScenarioAction({})
237+ # NOTE: KeyError is surprising here, it should be mapped to
238+ # AttributeError
239+ with self.assertRaises(KeyError):
240+ action.command
241+
242+ def test_parameters_getter(self):
243+ """
244+ Getting ScenarioAction.parameters[...] works
245+ """
246+ action = ScenarioAction({'parameters': {self._param1: self._str1}})
247+ param = action.parameters[self._param1]
248+ self.assertEqual(param.value, self._str1)
249+
250+ def test_parameters_setter(self):
251+ """
252+ Setting ScenarioAction.parameters[...] works
253+ """
254+ action = ScenarioAction({})
255+ action.parameters[self._param1] = self._str1
256+ self.assertEqual(action.parameters[self._param1].value, self._str1)
257+
258+
259+class TestScenarioTests(TestCase):
260+
261+ def test_actions(self):
262+ """
263+ Referencing scenario.actions produces a fragment of ScenarioAction
264+ """
265+ scenario = TestScenario({'actions': [{}]})
266+ action0 = scenario.actions[0]
267+ self.assertIsInstance(action0, ScenarioAction)

Subscribers

People subscribed via source and target branches