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

Proposed by Zygmunt Krynicki
Status: Merged
Merged at revision: 16
Proposed branch: lp:~zyga/lava-core/workspace
Merge into: lp:lava-core
Diff against target: 367 lines (+340/-2)
3 files modified
lava/core/environment.py (+4/-2)
lava/core/tests/test_workspace.py (+198/-0)
lava/core/workspace.py (+138/-0)
To merge this branch: bzr merge lp:~zyga/lava-core/workspace
Reviewer Review Type Date Requested Status
Linaro Validation Team Pending
Review via email: mp+107585@code.launchpad.net

Description of the change

This branch adds the workspace concept and a few tests

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'lava/core/environment.py'
--- lava/core/environment.py 2012-05-07 09:11:28 +0000
+++ lava/core/environment.py 2012-05-28 06:43:19 +0000
@@ -48,7 +48,9 @@
48 "type": "object",48 "type": "object",
49 "properties": {49 "properties": {
50 "name": {50 "name": {
51 "type": "string"51 "type": "string",
52 "optional": True,
53 "default": None
52 },54 },
53 }55 }
54 }56 }
@@ -57,4 +59,4 @@
57 def name(self):59 def name(self):
58 """60 """
59 Human readable name of the environment61 Human readable name of the environment
60 """
61\ No newline at end of file62\ No newline at end of file
63 """
6264
=== added file 'lava/core/tests/test_workspace.py'
--- lava/core/tests/test_workspace.py 1970-01-01 00:00:00 +0000
+++ lava/core/tests/test_workspace.py 2012-05-28 06:43:19 +0000
@@ -0,0 +1,198 @@
1# Copyright (C) 2011-2012 Linaro Limited
2#
3# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
4#
5# This file is part of lava-core
6#
7# lava-core is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Lesser General Public License version 3
9# as published by the Free Software Foundation
10#
11# lava-core is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public License
17# along with lava-core. If not, see <http://www.gnu.org/licenses/>.
18
19"""
20lava.core.tests.test_workspace
21==============================
22
23Tests for lava.core.workspace
24"""
25
26import os
27
28from unittest2 import TestCase
29from mockfs import MockedFileSystem
30
31from lava.core.workspace import Workspace
32from lava.core.environment import Environment
33
34
35class WorkspaceTests(TestCase):
36
37 _location = "location"
38 _location_nested = "location/nested/somewhere"
39 _name = "name"
40
41 def setUp(self):
42 super(WorkspaceTests, self).setUp()
43 self.fs = MockedFileSystem()
44
45 def create_workspace(self, location=".", environment_text="{ }"):
46 """
47 Create a workspace with at the specified location and add the
48 environment json with the specified text to it.
49 """
50 lava_dir = os.path.join(location, ".lava")
51 if not os.path.exists(lava_dir):
52 os.makedirs(lava_dir)
53 env_path = os.path.join(lava_dir, "environment.json")
54 with file(env_path, "wt") as stream:
55 stream.write(environment_text)
56
57 def test__init__with_workspace(self):
58 """
59 Workspace() works when .lava directory is found
60 """
61 with self.fs.record():
62 self.create_workspace(self._location)
63 with self.fs.replay():
64 Workspace(self._location)
65 self.assertTrue(True)
66
67 def test__init__without_workspace(self):
68 """
69 Workspace() raises EnvironmentError when .lava is not found
70 """
71 with self.assertRaises(EnvironmentError):
72 Workspace(self._location)
73
74 def test_location(self):
75 """
76 Workspace().location returns the location of the workspace
77 """
78 with self.fs.record():
79 self.create_workspace(self._location)
80 with self.fs.replay():
81 workspace = Workspace(self._location)
82 self.assertEqual(workspace.location, self._location)
83
84 def test_environment_returns_Environment(self):
85 """
86 Workspace().environment returns an Environment object
87 """
88 with self.fs.record():
89 self.create_workspace(self._location)
90 with self.fs.replay():
91 workspace = Workspace(self._location)
92 self.assertIsInstance(workspace.environment, Environment)
93
94 def test_environment_is_initially_empty(self):
95 """
96 Workspace().environment is initially empty ({})
97
98 Despite .lava/environment.json having content, the environment is empty
99 before we call .load_environment()
100 """
101 with self.fs.record():
102 self.create_workspace(
103 self._location, environment_text='{"I_am_not": "empty" }')
104 with self.fs.replay():
105 workspace = Workspace(self._location)
106 self.assertEqual(workspace.environment.value, {})
107
108 def test_load_environment_loads_json(self):
109 """
110 Workspace().load_environment() loads stuff from disk
111 """
112 with self.fs.record():
113 self.create_workspace(
114 self._location, environment_text='{"name": "Unit test" }')
115 with self.fs.replay():
116 workspace = Workspace(self._location)
117 workspace.load_environment()
118 self.assertEqual(workspace.environment.value,
119 {"name": "Unit test"})
120
121 def test_save_environment_saves_json(self):
122 """
123 Workspace().save_environment() saves stuff to disk
124
125 (it's actually only doing that when modified but I'm not going to test
126 for that here)
127 """
128 with self.fs.record():
129 # NOTE: it's sad but MockedFileSystem cannot open a file twice (it
130 # raises an exception when that is attempted), it's a tradeoff
131 # between ease-of-implementation and features. Once I finish fakefs
132 # we can just call self.create_workspace() here
133 os.makedirs(os.path.join(self._location, ".lava"))
134 workspace = Workspace(self._location)
135 workspace.environment.name = self._name
136 workspace.save_environment()
137 with self.fs.replay():
138 # NOTE: for clarity, it's worth pointing out that replay() puts the
139 # filesystem in read-only mode while record() does not allow one to
140 # read what was written (this was a poor choice from
141 # retrospective). Without those limits the test would have been
142 # less complicated.
143 workspace = Workspace(self._location)
144 workspace.load_environment()
145 self.assertEqual(workspace.environment.name, self._name)
146
147 def test_create(self):
148 """
149 Workspace.create() creates and returns a workspace
150 """
151 with self.fs.record():
152 workspace = Workspace.create(self._location)
153 with self.fs.replay():
154 # Create makes both the location
155 self.assertTrue(os.path.exists(workspace.location))
156 # and the .lava directory inside
157 self.assertTrue(os.path.exists(workspace._lava_dir))
158 # ... and even a stub environment.json file
159 self.assertTrue(os.path.exists(workspace._environment_pathname))
160
161 def test_create_output_works(self):
162 """
163 Workspace.create() creates something that can be used later
164 """
165 with self.fs.record():
166 Workspace.create(self._location)
167 with self.fs.replay():
168 workspace = Workspace(self._location)
169 workspace.load_environment()
170 # how I wish TestCase had provided assertNotRaises()
171 self.assertEqual(workspace.environment.validate(), None)
172
173 def test_find_without_workspace(self):
174 """
175 Workspace.find() raises LookupError if there is no workspace anywhere
176 _above_
177 """
178 with self.fs.replay():
179 with self.assertRaises(LookupError):
180 Workspace.find()
181 with self.fs.record():
182 os.makedirs('foo/.lava/')
183 with self.fs.replay():
184 with self.assertRaises(LookupError):
185 Workspace.find('foo')
186
187 def test_find_with_workspace(self):
188 """
189 Workspace.find() correctly finds workspaces in the current directory
190 and above
191 """
192 with self.fs.record():
193 os.mkdir('/home/user/.lava')
194 os.mkdir('/home/user/.lava/something/')
195 with self.fs.replay():
196 workspace = Workspace.find('/home/user/.lava/something/')
197 self.assertEqual(workspace.location, '/home/user')
198 self.assertEqual(workspace._lava_dir, '/home/user/.lava')
0199
=== added file 'lava/core/workspace.py'
--- lava/core/workspace.py 1970-01-01 00:00:00 +0000
+++ lava/core/workspace.py 2012-05-28 06:43:19 +0000
@@ -0,0 +1,138 @@
1# Copyright (C) 2011-2012 Linaro Limited
2#
3# Author: Zygmunt Krynicki <zygmunt.krynicki@linaro.org>
4#
5# This file is part of lava-core
6#
7# lava-core is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Lesser General Public License version 3
9# as published by the Free Software Foundation
10#
11# lava-core is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public License
17# along with lava-core. If not, see <http://www.gnu.org/licenses/>.
18
19from __future__ import absolute_import
20
21"""
22lava.core.workspace
23===================
24"""
25
26import os
27
28from json_document.shortcuts import persistence
29
30from lava.core.environment import Environment
31from lava.core.logging import LoggingMixIn
32
33
34class Workspace(LoggingMixIn):
35 """
36 Container for LAVA configuration and other runtime data. Also know as the
37 .lava directory
38 """
39
40 def __init__(self, location):
41 """
42 Initialize a workspace with an existing on-disk location. location
43 must point to a directory that has the '.lava' sub-directory.
44 """
45 # self._location = os.path.abspath(location)
46 self._location = location
47 if not os.path.exists(self._lava_dir):
48 raise EnvironmentError("Workspace must have a .lava directory")
49 self._environment = Environment({})
50 self._env_persistence = persistence(
51 self._environment, self._environment_pathname)
52
53 @property
54 def location(self):
55 """
56 location of this workspace
57
58 The location does not include the .lava directory
59 The location is an absolute pathname, regardless of
60 how it was passed to the constructor.
61 """
62 return self._location
63
64 @property
65 def environment(self):
66 """
67 :class:`lava.core.environment.Environment` object of this workspace
68
69 .. note::
70 This object is initially empty (empty environment), to use an
71 actual environment you must call load_environment() and deal with
72 any errors.
73 """
74 return self._environment
75
76 def load_environment(self):
77 """
78 Load and return the workspace environment
79 """
80 # TODO: fs lock
81 self._env_persistence.load()
82 return self._environment
83
84 def save_environment(self):
85 """
86 Save environment back to the filesystem, if needed
87 """
88 # TODO: fs lock
89 self._env_persistence.save()
90
91 @classmethod
92 def create(cls, location='.'):
93 """
94 Create a new workspace in the specified location.
95
96 Parent workspace lookup is _not_ performed. This is a filesystem
97 synchronization/race point, if the caller looses an OSError is raised.
98 """
99 os.makedirs(os.path.join(location, '.lava'))
100 self = cls(location)
101 with open(self._environment_pathname, 'wt') as stream:
102 stream.write("{ }")
103 return self
104
105 @classmethod
106 def find(cls, start_dir='.'):
107 """
108 Find a Workspace, starting the search at start_dir and working up the
109 directory tree
110 """
111 location = start_dir
112 last_location = None
113 # Keep on "going" as long as we're moving
114 while last_location is None or (os.path.abspath(location) !=
115 os.path.abspath(last_location)):
116 candidate = os.path.join(location, '.lava')
117 candidate = os.path.normpath(candidate)
118 # XXX: replace with os.path.isdir once mockfs supports that
119 if os.path.exists(candidate):
120 return cls(location)
121 last_location = location
122 location = os.path.join(location, "..")
123 location = os.path.normpath(location)
124 raise LookupError(".lava directory not found")
125
126 @property
127 def _lava_dir(self):
128 """
129 pathname of the .lava directory
130 """
131 return os.path.join(self._location, '.lava')
132
133 @property
134 def _environment_pathname(self):
135 """
136 pathname of the 'environment.json' file
137 """
138 return os.path.join(self._lava_dir, 'environment.json')

Subscribers

People subscribed via source and target branches