~free.ekanayaka/landscape-client/karmic-updates-1.4.4-0ubuntu0.9.10

« back to all changes in this revision

Viewing changes to landscape/package/tests/test_taskhandler.py

  • Committer: Bazaar Package Importer
  • Author(s): Rick Clark
  • Date: 2008-09-08 16:35:57 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080908163557-l3ixzj5dxz37wnw2
Tags: 1.0.18-0ubuntu1
New upstream release 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import os
 
2
import sys
 
3
 
 
4
from cStringIO import StringIO
 
5
 
 
6
from twisted.internet import reactor
 
7
from twisted.internet.defer import Deferred, fail
 
8
 
 
9
from landscape.lib.lock import lock_path
 
10
 
 
11
from landscape.deployment import Configuration
 
12
from landscape.broker.remote import RemoteBroker
 
13
 
 
14
from landscape.package.taskhandler import PackageTaskHandler, run_task_handler
 
15
from landscape.package.facade import SmartFacade
 
16
from landscape.package.store import PackageStore
 
17
from landscape.package.tests.helpers import SmartFacadeHelper
 
18
 
 
19
from landscape.tests.helpers import (
 
20
    LandscapeIsolatedTest, LandscapeTest, RemoteBrokerHelper)
 
21
from landscape.tests.mocker import ANY, ARGS, MATCH
 
22
 
 
23
 
 
24
def ISTYPE(match_type):
 
25
    return MATCH(lambda arg: type(arg) is match_type)
 
26
 
 
27
 
 
28
class PackageTaskHandlerTest(LandscapeIsolatedTest):
 
29
 
 
30
    helpers = [SmartFacadeHelper, RemoteBrokerHelper]
 
31
 
 
32
    def setUp(self):
 
33
        super(PackageTaskHandlerTest, self).setUp()
 
34
 
 
35
        self.store = PackageStore(self.makeFile())
 
36
 
 
37
        self.handler = PackageTaskHandler(self.store, self.facade, self.remote)
 
38
 
 
39
    def test_ensure_channels_reloaded(self):
 
40
        self.assertEquals(len(self.facade.get_packages()), 0)
 
41
        self.handler.ensure_channels_reloaded()
 
42
        self.assertEquals(len(self.facade.get_packages()), 3)
 
43
 
 
44
        # Calling it once more won't reload channels again.
 
45
        self.facade.get_packages_by_name("name1")[0].installed = True
 
46
        self.handler.ensure_channels_reloaded()
 
47
        self.assertTrue(self.facade.get_packages_by_name("name1")[0].installed)
 
48
 
 
49
    def test_run(self):
 
50
        handler_mock = self.mocker.patch(self.handler)
 
51
        handler_mock.handle_tasks()
 
52
        self.mocker.result("WAYO!")
 
53
 
 
54
        self.mocker.replay()
 
55
 
 
56
        self.assertEquals(self.handler.run(), "WAYO!")
 
57
 
 
58
    def test_handle_tasks(self):
 
59
        queue_name = PackageTaskHandler.queue_name
 
60
 
 
61
        self.store.add_task(queue_name, 0)
 
62
        self.store.add_task(queue_name, 1)
 
63
        self.store.add_task(queue_name, 2)
 
64
 
 
65
        results = [Deferred() for i in range(3)]
 
66
 
 
67
        stash = []
 
68
        def handle_task(task):
 
69
            result = results[task.data]
 
70
            result.addCallback(lambda x: stash.append(task.data))
 
71
            return result
 
72
 
 
73
        handler_mock = self.mocker.patch(self.handler)
 
74
        handler_mock.handle_task(ANY)
 
75
        self.mocker.call(handle_task)
 
76
        self.mocker.count(3)
 
77
        self.mocker.replay()
 
78
 
 
79
        handle_tasks_result = self.handler.handle_tasks()
 
80
 
 
81
        self.assertEquals(stash, [])
 
82
 
 
83
        results[1].callback(None)
 
84
        self.assertEquals(stash, [])
 
85
        self.assertEquals(self.store.get_next_task(queue_name).data, 0)
 
86
 
 
87
        results[0].callback(None)
 
88
        self.assertEquals(stash, [0, 1])
 
89
        self.assertFalse(handle_tasks_result.called)
 
90
        self.assertEquals(self.store.get_next_task(queue_name).data, 2)
 
91
 
 
92
        results[2].callback(None)
 
93
        self.assertEquals(stash, [0, 1, 2])
 
94
        self.assertTrue(handle_tasks_result.called)
 
95
        self.assertEquals(self.store.get_next_task(queue_name), None)
 
96
 
 
97
        handle_tasks_result = self.handler.handle_tasks()
 
98
        self.assertTrue(handle_tasks_result.called)
 
99
 
 
100
    def test_handle_tasks_hooks_errback(self):
 
101
        queue_name = PackageTaskHandler.queue_name
 
102
 
 
103
        self.store.add_task(queue_name, 0)
 
104
 
 
105
        class MyException(Exception): pass
 
106
 
 
107
        def handle_task(task):
 
108
            result = Deferred()
 
109
            result.errback(MyException())
 
110
            return result
 
111
 
 
112
        handler_mock = self.mocker.patch(self.handler)
 
113
        handler_mock.handle_task(ANY)
 
114
        self.mocker.call(handle_task)
 
115
        self.mocker.replay()
 
116
 
 
117
        stash = []
 
118
        handle_tasks_result = self.handler.handle_tasks()
 
119
        handle_tasks_result.addErrback(stash.append)
 
120
 
 
121
        self.assertEquals(len(stash), 1)
 
122
        self.assertEquals(stash[0].type, MyException)
 
123
 
 
124
    def test_default_handle_task(self):
 
125
        result = self.handler.handle_task(None)
 
126
        self.assertTrue(isinstance(result, Deferred))
 
127
        self.assertTrue(result.called)
 
128
 
 
129
    def test_run_task_handler(self):
 
130
 
 
131
        # This is a slightly lengthy one, so bear with me.
 
132
 
 
133
        data_path = self.makeDir()
 
134
 
 
135
        # Prepare the mock objects.
 
136
        lock_path_mock = self.mocker.replace("landscape.lib.lock.lock_path",
 
137
                                             passthrough=False)
 
138
        install_mock = self.mocker.replace("twisted.internet."
 
139
                                           "glib2reactor.install")
 
140
        reactor_mock = self.mocker.replace("twisted.internet.reactor",
 
141
                                           passthrough=False)
 
142
        init_logging_mock = self.mocker.replace("landscape.deployment"
 
143
                                                ".init_logging",
 
144
                                                passthrough=False)
 
145
        HandlerMock = self.mocker.proxy(PackageTaskHandler)
 
146
 
 
147
        # The goal of this method is to perform a sequence of tasks
 
148
        # where the ordering is important.
 
149
        self.mocker.order()
 
150
 
 
151
        # As the very first thing, install the twisted glib2 reactor
 
152
        # so that we can use DBUS safely.
 
153
        install_mock()
 
154
 
 
155
        # Then, we must acquire a lock as the same task handler should
 
156
        # never have two instances running in parallel.  The 'default'
 
157
        # below comes from the queue_name attribute.
 
158
        lock_path_mock(os.path.join(data_path, "package/default.lock"))
 
159
 
 
160
        # Once locking is done, it's safe to start logging without
 
161
        # corrupting the file.  We don't want any output unless it's
 
162
        # breaking badly, so the quiet option should be set.
 
163
        init_logging_mock(ISTYPE(Configuration), "package-default")
 
164
 
 
165
        # Then, it must create an instance of the TaskHandler subclass
 
166
        # passed in as a parameter.  We'll keep track of the arguments
 
167
        # given and verify them later.
 
168
        handler_args = []
 
169
        handler_mock = HandlerMock(ANY, ANY, ANY)
 
170
        self.mocker.passthrough() # Let the real constructor run for testing.
 
171
        self.mocker.call(lambda *args: handler_args.extend(args))
 
172
 
 
173
        # Finally, the task handler must be run, and will return a deferred.
 
174
        # We'll return a real deferred so that we can call it back and test
 
175
        # whatever was hooked in as well.
 
176
        deferred = Deferred()
 
177
        handler_mock.run()
 
178
        self.mocker.result(deferred)
 
179
 
 
180
        # With all of that done, the Twisted reactor must be run, so that
 
181
        # deferred tasks are correctly performed.
 
182
        reactor_mock.run()
 
183
 
 
184
        self.mocker.unorder()
 
185
 
 
186
        # The following tasks are hooked in as callbacks of our deferred.
 
187
        # We must use callLater() so that stop() won't happen before run().
 
188
        reactor_mock.callLater(0, "STOP METHOD")
 
189
        reactor_mock.stop
 
190
        self.mocker.result("STOP METHOD")
 
191
 
 
192
        # We also expect the umask to be set appropriately before running the
 
193
        # commands
 
194
        umask = self.mocker.replace("os.umask")
 
195
        umask(022)
 
196
 
 
197
        # Okay, the whole playground is set.
 
198
        self.mocker.replay()
 
199
 
 
200
        try:
 
201
            # DO IT!
 
202
            result = run_task_handler(HandlerMock,
 
203
                                      ["--data-path", data_path,
 
204
                                       "--bus", "session"])
 
205
 
 
206
            # reactor.stop() wasn't run yet, so it must fail right now.
 
207
            self.assertRaises(AssertionError, self.mocker.verify)
 
208
 
 
209
            # DO THE REST OF IT! :-)
 
210
            result.callback(None)
 
211
 
 
212
            # Are we there yet!?
 
213
            self.mocker.verify()
 
214
        finally:
 
215
            # Put reactor back in place before returning.
 
216
            self.mocker.reset()
 
217
 
 
218
        store, facade, broker = handler_args
 
219
 
 
220
        # Verify if the arguments to the reporter constructor were correct.
 
221
        self.assertEquals(type(store), PackageStore)
 
222
        self.assertEquals(type(facade), SmartFacade)
 
223
        self.assertEquals(type(broker), RemoteBroker)
 
224
 
 
225
        # Let's see if the store path is where it should be.
 
226
        filename = os.path.join(data_path, "package/database")
 
227
        store.add_available([1, 2, 3])
 
228
        other_store = PackageStore(filename)
 
229
        self.assertEquals(other_store.get_available(), [1, 2, 3])
 
230
 
 
231
    def test_run_task_handler_when_already_locked(self):
 
232
        data_path = self.makeDir()
 
233
 
 
234
        install_mock = self.mocker.replace("twisted.internet."
 
235
                                           "glib2reactor.install")
 
236
        install_mock()
 
237
 
 
238
        self.mocker.replay()
 
239
 
 
240
        os.mkdir(os.path.join(data_path, "package"))
 
241
        lock_path(os.path.join(data_path, "package/default.lock"))
 
242
 
 
243
        try:
 
244
            run_task_handler(PackageTaskHandler, ["--data-path", data_path])
 
245
        except SystemExit, e:
 
246
            self.assertIn("default is already running", str(e))
 
247
        else:
 
248
            self.fail("SystemExit not raised")
 
249
 
 
250
    def test_run_task_handler_when_already_locked_and_quiet_option(self):
 
251
        data_path = self.makeDir()
 
252
 
 
253
        install_mock = self.mocker.replace("twisted.internet."
 
254
                                           "glib2reactor.install")
 
255
        install_mock()
 
256
 
 
257
        self.mocker.replay()
 
258
 
 
259
        os.mkdir(os.path.join(data_path, "package"))
 
260
        lock_path(os.path.join(data_path, "package/default.lock"))
 
261
 
 
262
        try:
 
263
            run_task_handler(PackageTaskHandler,
 
264
                             ["--data-path", data_path, "--quiet"])
 
265
        except SystemExit, e:
 
266
            self.assertEquals(str(e), "")
 
267
        else:
 
268
            self.fail("SystemExit not raised")
 
269
 
 
270
    def test_errors_in_tasks_are_printed_and_exit_program(self):
 
271
        # Ignore a bunch of crap that we don't care about
 
272
        install_mock = self.mocker.replace("twisted.internet."
 
273
                                           "glib2reactor.install")
 
274
        install_mock()
 
275
        reactor_mock = self.mocker.proxy(reactor)
 
276
        init_logging_mock = self.mocker.replace("landscape.deployment"
 
277
                                                ".init_logging",
 
278
                                                passthrough=False)
 
279
        init_logging_mock(ARGS)
 
280
        reactor_mock.run()
 
281
 
 
282
        # Get a deferred which will fire when the reactor is stopped, so the
 
283
        # test runs until the reactor is stopped.
 
284
        done = Deferred()
 
285
        self.expect(reactor_mock.stop()).call(lambda: done.callback(None))
 
286
 
 
287
        class MyException(Exception): pass
 
288
 
 
289
        self.log_helper.ignore_errors(MyException)
 
290
 
 
291
        # Simulate a task handler which errors out.
 
292
        handler_factory_mock = self.mocker.proxy(PackageTaskHandler)
 
293
        handler_mock = handler_factory_mock(ARGS)
 
294
        self.expect(handler_mock.run()).result(fail(MyException("Hey error")))
 
295
 
 
296
        self.mocker.replay()
 
297
 
 
298
        # Ok now for some real stuff
 
299
 
 
300
        result = run_task_handler(handler_factory_mock,
 
301
                                  ["--data-path", self.data_path,
 
302
                                   "--bus", "session"],
 
303
                                  reactor=reactor_mock)
 
304
 
 
305
        def everything_stopped(result):
 
306
            self.assertIn("MyException", self.logfile.getvalue())
 
307
 
 
308
        return done.addCallback(everything_stopped)