~ahasenack/landscape-client/landscape-client-1.5.5-0ubuntu0.9.04.0

« back to all changes in this revision

Viewing changes to landscape/monitor/tests/test_mountinfo.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 tempfile
 
2
 
 
3
from landscape.monitor.mountinfo import MountInfo
 
4
from landscape.tests.test_hal import MockHALManager, MockRealHALDevice
 
5
from landscape.tests.helpers import (LandscapeTest, MakePathHelper,
 
6
                                     mock_counter, MonitorHelper)
 
7
from landscape.tests.mocker import ANY
 
8
 
 
9
 
 
10
mb = lambda x: x * 1024 * 1024
 
11
 
 
12
 
 
13
class MountInfoTest(LandscapeTest):
 
14
    """Tests for mount-info plugin."""
 
15
 
 
16
    helpers = [MonitorHelper, MakePathHelper]
 
17
 
 
18
    def setUp(self):
 
19
        LandscapeTest.setUp(self)
 
20
        self.mstore.set_accepted_types(["mount-info", "mount-activity",
 
21
                                        "free-space"])
 
22
 
 
23
    def get_mount_info(self, *args, **kwargs):
 
24
        hal_devices = kwargs.pop("hal_devices", [])
 
25
        kwargs["hal_manager"] = MockHALManager(hal_devices)
 
26
        if "statvfs" not in kwargs:
 
27
            kwargs["statvfs"] = lambda path: (0,)*10
 
28
        return MountInfo(*args, **kwargs)
 
29
 
 
30
    def test_read_proc_mounts(self):
 
31
        """
 
32
        When the mount info plugin runs it reads data from
 
33
        /proc/mounts to discover mounts and calls os.statvfs() to
 
34
        retrieve current data for each mount point.  This test makes
 
35
        sure that os.statvfs() is called without failing, that
 
36
        /proc/mounts is readable, and that messages with the expected
 
37
        datatypes are generated.
 
38
        """
 
39
        plugin = self.get_mount_info(create_time=self.reactor.time)
 
40
        self.monitor.add(plugin)
 
41
        
 
42
        self.reactor.advance(self.monitor.step_size)
 
43
 
 
44
        message = plugin.create_mount_info_message()
 
45
        self.assertTrue(message)
 
46
        self.assertEquals(message["type"], "mount-info")
 
47
        self.assertTrue("mount-info" in message)
 
48
        self.assertTrue(len(message["mount-info"]) > 0)
 
49
 
 
50
        keys = set(["filesystem", "total-space", "device", "mount-point"])
 
51
        for now, mount_info in message["mount-info"]:
 
52
            self.assertEquals(set(mount_info.keys()), keys)
 
53
            self.assertTrue(isinstance(mount_info["filesystem"], basestring))
 
54
            self.assertTrue(isinstance(mount_info["device"], basestring))
 
55
            self.assertTrue(isinstance(mount_info["total-space"], (int, long)))
 
56
            self.assertTrue(isinstance(mount_info["mount-point"], basestring))
 
57
 
 
58
    def test_read_sample_data(self):
 
59
        """
 
60
        Sample data is used to ensure that the free space included in
 
61
        the message is calculated correctly.
 
62
        """
 
63
        def statvfs(path):
 
64
            if path == "/":
 
65
                return (4096, 0, mb(1000L), mb(100L), 0L, 0L, 0L, 0, 0)
 
66
            else:
 
67
                return (4096, 0, mb(10000L), mb(1000L), 0L, 0L, 0L, 0, 0)
 
68
 
 
69
        filename = self.make_path("""\
 
70
rootfs / rootfs rw 0 0
 
71
none /dev ramfs rw 0 0
 
72
/dev/hda1 / ext3 rw 0 0
 
73
/dev/hda1 /dev/.static/dev ext3 rw 0 0
 
74
proc /proc proc rw,nodiratime 0 0
 
75
sysfs /sys sysfs rw 0 0
 
76
usbfs /proc/bus/usb usbfs rw 0 0
 
77
devpts /dev/pts devpts rw 0 0
 
78
tmpfs /dev/shm tmpfs rw 0 0
 
79
tmpfs /lib/modules/2.6.12-10-386/volatile tmpfs rw 0 0
 
80
/dev/hde1 /mnt/hde1 reiserfs rw 0 0
 
81
/dev/hde1 /mnt/bind reiserfs rw 0 0
 
82
/dev/sdb2 /media/Boot\\040OSX hfsplus nls=utf8 0 0
 
83
""")
 
84
 
 
85
        mtab_filename = self.make_path("""\
 
86
rootfs / rootfs rw 0 0
 
87
none /dev ramfs rw 0 0
 
88
/dev/hda1 / ext3 rw 0 0
 
89
/dev/hda1 /dev/.static/dev ext3 rw 0 0
 
90
proc /proc proc rw,nodiratime 0 0
 
91
sysfs /sys sysfs rw 0 0
 
92
usbfs /proc/bus/usb usbfs rw 0 0
 
93
devpts /dev/pts devpts rw 0 0
 
94
tmpfs /dev/shm tmpfs rw 0 0
 
95
tmpfs /lib/modules/2.6.12-10-386/volatile tmpfs rw 0 0
 
96
/dev/hde1 /mnt/hde1 reiserfs rw 0 0
 
97
/dev/hde1 /mnt/bind none rw,bind 0 0
 
98
/dev/sdb2 /media/Boot\\040OSX hfsplus rw 0 0
 
99
""")
 
100
 
 
101
        plugin = self.get_mount_info(mounts_file=filename, statvfs=statvfs,
 
102
                                     create_time=self.reactor.time,
 
103
                                     mtab_file=mtab_filename)
 
104
        self.monitor.add(plugin)
 
105
        self.reactor.advance(self.monitor.step_size)
 
106
 
 
107
        message = plugin.create_mount_info_message()
 
108
        self.assertTrue(message)
 
109
        self.assertEquals(message["type"], "mount-info")
 
110
 
 
111
        mount_info = message.get("mount-info", ())
 
112
 
 
113
        self.assertEquals(len(mount_info), 3)
 
114
 
 
115
        self.assertEquals(mount_info[0][1],
 
116
                          {"device": "/dev/hda1", "mount-point": "/",
 
117
                           "filesystem": "ext3", "total-space": 4096000})
 
118
 
 
119
        self.assertEquals(mount_info[1][1],
 
120
                          {"device": "/dev/hde1", "mount-point": "/mnt/hde1",
 
121
                           "filesystem": "reiserfs", "total-space": 40960000})
 
122
 
 
123
        self.assertEquals(mount_info[2][1],
 
124
                          {"device": "/dev/sdb2", "mount-point": "/media/Boot OSX",
 
125
                           "filesystem": "hfsplus", "total-space": 40960000})
 
126
 
 
127
    def test_read_changing_total_space(self):
 
128
        """
 
129
        Total space measurements are only sent when (a) none have ever
 
130
        been sent, or (b) the value has changed since the last time
 
131
        data was collected.  The test sets the mount info plugin
 
132
        interval to the same value as the step size and advances the
 
133
        reactor such that the plugin will be run twice.  Each time it
 
134
        runs it gets a different value from our sample statvfs()
 
135
        function which should cause it to queue new messages.
 
136
        """
 
137
        def statvfs(path, multiplier=mock_counter(1).next):
 
138
            return (4096, 0, mb(multiplier() * 1000), mb(100), 0, 0, 0, 0, 0)
 
139
 
 
140
        filename = self.make_path("""\
 
141
/dev/hda1 / ext3 rw 0 0
 
142
""")
 
143
        plugin = self.get_mount_info(mounts_file=filename, statvfs=statvfs,
 
144
                                     create_time=self.reactor.time,
 
145
                                     interval=self.monitor.step_size,
 
146
                                     mtab_file=filename)
 
147
        self.monitor.add(plugin)
 
148
 
 
149
        self.reactor.advance(self.monitor.step_size * 2)
 
150
 
 
151
        message = plugin.create_mount_info_message()
 
152
        mount_info = message["mount-info"]
 
153
        self.assertEquals(len(mount_info), 2)
 
154
 
 
155
        for i, total_space in enumerate([4096000, 8192000]):
 
156
            self.assertEquals(mount_info[i][0], (i+1) * self.monitor.step_size)
 
157
            self.assertEquals(mount_info[i][1],
 
158
                              {"device": "/dev/hda1", "filesystem": "ext3",
 
159
                               "mount-point": "/", "total-space": total_space})
 
160
 
 
161
    def test_read_disjointed_changing_total_space(self):
 
162
        """
 
163
        Total space measurements are only sent when (a) none have ever
 
164
        been sent, or (b) the value has changed since the last time
 
165
        data was collected.  This test ensures that the (b) criteria
 
166
        is checked per-mount point.  The sample statvfs() function
 
167
        only provides changing total space for /; therefore, new
 
168
        messages should only be queued for / after the first message
 
169
        is created.
 
170
        """
 
171
        def statvfs(path, multiplier=mock_counter(1).next):
 
172
            if path == "/":
 
173
                return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
174
            return (4096, 0, mb(multiplier() * 1000), mb(100), 0, 0, 0, 0, 0)
 
175
 
 
176
        filename = self.make_path("""\
 
177
/dev/hda1 / ext3 rw 0 0
 
178
/dev/hde1 /mnt/hde1 ext3 rw 0 0
 
179
""")
 
180
        plugin = self.get_mount_info(mounts_file=filename, statvfs=statvfs,
 
181
                                     create_time=self.reactor.time,
 
182
                                     interval=self.monitor.step_size,
 
183
                                     mtab_file=filename)
 
184
        self.monitor.add(plugin)
 
185
 
 
186
        self.reactor.advance(self.monitor.step_size * 2)
 
187
 
 
188
        message = plugin.create_mount_info_message()
 
189
        self.assertTrue(message)
 
190
 
 
191
        mount_info = message.get("mount-info", ())
 
192
        self.assertEquals(len(mount_info), 3)
 
193
 
 
194
        self.assertEquals(mount_info[0][0], self.monitor.step_size)
 
195
        self.assertEquals(mount_info[0][1],
 
196
                          {"device": "/dev/hda1", "mount-point": "/",
 
197
                           "filesystem": "ext3", "total-space": 4096000})
 
198
 
 
199
        self.assertEquals(mount_info[1][0], self.monitor.step_size)
 
200
        self.assertEquals(mount_info[1][1],
 
201
                          {"device": "/dev/hde1", "mount-point": "/mnt/hde1",
 
202
                           "filesystem": "ext3", "total-space": 4096000})
 
203
 
 
204
        self.assertEquals(mount_info[2][0], self.monitor.step_size * 2)
 
205
        self.assertEquals(mount_info[2][1],
 
206
                          {"device": "/dev/hde1", "mount-point": "/mnt/hde1",
 
207
                           "filesystem": "ext3", "total-space": 8192000})
 
208
 
 
209
    def test_exchange_messages(self):
 
210
        """
 
211
        The mount_info plugin queues message when manager.exchange()
 
212
        is called.  Each message should be aligned to a step boundary;
 
213
        messages collected bewteen exchange periods should be
 
214
        delivered in a single message.
 
215
        """
 
216
        def statvfs(path):
 
217
            return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
218
 
 
219
        filename = self.make_path("""\
 
220
/dev/hda1 / ext3 rw 0 0
 
221
""")
 
222
        plugin = self.get_mount_info(mounts_file=filename, statvfs=statvfs,
 
223
                                     create_time=self.reactor.time,
 
224
                                     mtab_file=filename)
 
225
        step_size = self.monitor.step_size
 
226
        self.monitor.add(plugin)
 
227
 
 
228
        self.reactor.advance(step_size * 2)
 
229
        self.monitor.exchange()
 
230
 
 
231
        messages = self.mstore.get_pending_messages()
 
232
        self.assertEquals(len(messages), 3)
 
233
 
 
234
        message = [d for d in messages if d["type"] == "free-space"][0]
 
235
        free_space = message["free-space"]
 
236
        for i in range(1, 1):
 
237
            self.assertEquals(free_space[i][0], i * step_size)
 
238
            self.assertEquals(free_space[i][1], "/")
 
239
            self.assertEquals(free_space[i][2], 409600)
 
240
 
 
241
    def test_messaging_flushes(self):
 
242
        """
 
243
        Duplicate message should never be created.  If no data is
 
244
        available, None will be returned when messages are created.
 
245
        """
 
246
        def statvfs(path):
 
247
            return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
248
 
 
249
        filename = self.make_path("""\
 
250
/dev/hda1 / ext3 rw 0 0
 
251
""")
 
252
        plugin = self.get_mount_info(mounts_file=filename, statvfs=statvfs,
 
253
                                     create_time=self.reactor.time,
 
254
                                     mtab_file=filename)
 
255
        self.monitor.add(plugin)
 
256
 
 
257
        self.reactor.advance(self.monitor.step_size)
 
258
 
 
259
        messages = plugin.create_messages()
 
260
        self.assertEquals(len(messages), 3)
 
261
 
 
262
        messages = plugin.create_messages()
 
263
        self.assertEquals(len(messages), 0)
 
264
 
 
265
    def test_read_multi_bound_mounts(self):
 
266
        """
 
267
        The mount info plugin should handle multi-bound mount points
 
268
        by reporting them only once.  In practice, this test doesn't
 
269
        really test anything since the current behaviour is to ignore
 
270
        any mount point for which the device doesn't start with /dev.
 
271
        """
 
272
        def statvfs(path):
 
273
            return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
274
 
 
275
        filename = self.make_path("""\
 
276
/dev/hdc4 /mm xfs rw 0 0
 
277
/mm/ubuntu-mirror /home/dchroot/warty/mirror none bind 0 0
 
278
/mm/ubuntu-mirror /home/dchroot/hoary/mirror none bind 0 0
 
279
/mm/ubuntu-mirror /home/dchroot/breezy/mirror none bind 0 0
 
280
""")
 
281
        plugin = self.get_mount_info(mounts_file=filename, statvfs=statvfs,
 
282
                                     create_time=self.reactor.time,
 
283
                                     mtab_file=filename)
 
284
        step_size = self.monitor.step_size
 
285
        self.monitor.add(plugin)
 
286
 
 
287
        self.reactor.advance(step_size)
 
288
 
 
289
        message = plugin.create_mount_info_message()
 
290
        self.assertTrue(message)
 
291
 
 
292
        mount_info = message.get("mount-info", ())
 
293
        self.assertEquals(len(mount_info), 1)
 
294
 
 
295
        self.assertEquals(mount_info[0][0], step_size)
 
296
        self.assertEquals(mount_info[0][1],
 
297
                          {"device": "/dev/hdc4", "mount-point": "/mm",
 
298
                           "filesystem": "xfs", "total-space": 4096000})
 
299
 
 
300
    def test_ignore_nfs_mounts(self):
 
301
        """
 
302
        The mount info plugin should only report data about local
 
303
        mount points.
 
304
        """
 
305
 
 
306
        filename = self.make_path("""\
 
307
ennui:/data /data nfs rw,v3,rsize=32768,wsize=32768,hard,lock,proto=udp,addr=ennui 0 0
 
308
""")
 
309
        plugin = self.get_mount_info(mounts_file=filename, mtab_file=filename)
 
310
        self.monitor.add(plugin)
 
311
        plugin.run()
 
312
 
 
313
        message = plugin.create_mount_info_message()
 
314
        self.assertEquals(message, None)
 
315
 
 
316
    def test_ignore_removable_partitions(self):
 
317
        """
 
318
        Partitions on removable devices don't directly report
 
319
        storage.removable : True, but they do point to their parent and the
 
320
        parent will be marked removable if appropriate.
 
321
        """
 
322
        devices = [MockRealHALDevice({"info.udi": "wubble",
 
323
                                      "block.device": "/dev/scd",
 
324
                                      "storage.removable": True}),
 
325
                   MockRealHALDevice({"info.udi": "wubble0",
 
326
                                      "block.device": "/dev/scd0",
 
327
                                      "info.parent": "wubble"}),]
 
328
 
 
329
        filename = self.make_path("""\
 
330
/dev/scd0 /media/Xerox_M750 iso9660 ro,nosuid,nodev,uid=1000,utf8 0 0
 
331
""")
 
332
        plugin = self.get_mount_info(mounts_file=filename, hal_devices=devices,
 
333
                                     mtab_file=filename)
 
334
        self.monitor.add(plugin)
 
335
        plugin.run()
 
336
 
 
337
        message = plugin.create_mount_info_message()
 
338
        self.assertEquals(message, None)
 
339
 
 
340
    def test_ignore_removable_devices(self):
 
341
        """
 
342
        The mount info plugin should only report data about
 
343
        non-removable devices.
 
344
        """
 
345
        devices = [MockRealHALDevice({"info.udi": "wubble",
 
346
                                      "block.device": "/dev/scd0",
 
347
                                      "storage.removable": True}),]
 
348
        filename = self.make_path("""\
 
349
/dev/scd0 /media/Xerox_M750 iso9660 ro,nosuid,nodev,uid=1000,utf8 0 0
 
350
""")
 
351
        plugin = self.get_mount_info(mounts_file=filename, hal_devices=devices,
 
352
                                     mtab_file=filename)
 
353
        self.monitor.add(plugin)
 
354
        plugin.run()
 
355
 
 
356
        message = plugin.create_mount_info_message()
 
357
        self.assertEquals(message, None)
 
358
 
 
359
    def test_ignore_multiparented_removable_devices(self):
 
360
        """
 
361
        Some removable devices might be the grand-children of a device that is
 
362
        marked as "storage.removable".
 
363
        """
 
364
        devices = [MockRealHALDevice({"info.udi": "wubble",
 
365
                                      "block.device": "/dev/scd",
 
366
                                      "storage.removable": True}),
 
367
                   MockRealHALDevice({"info.udi": "wubble0",
 
368
                                      "block.device": "/dev/scd0",
 
369
                                      "info.parent": "wubble"}),
 
370
                   MockRealHALDevice({"info.udi": "wubble0a",
 
371
                                      "block.device": "/dev/scd0a",
 
372
                                      "info.parent": "wubble0"}),
 
373
                   MockRealHALDevice({"info.udi": "wubble0b",
 
374
                                      "block.device": "/dev/scd0b",
 
375
                                      "info.parent": "wubble0"}),]
 
376
 
 
377
 
 
378
        filename = self.make_path("""\
 
379
/dev/scd0a /media/Xerox_M750 iso9660 ro,nosuid,nodev,uid=1000,utf8 0 0
 
380
""")
 
381
        plugin = self.get_mount_info(mounts_file=filename, hal_devices=devices,
 
382
                                     mtab_file=filename)
 
383
        self.monitor.add(plugin)
 
384
        plugin.run()
 
385
 
 
386
        message = plugin.create_mount_info_message()
 
387
        self.assertEquals(message, None)
 
388
 
 
389
    def test_sample_free_space(self):
 
390
        """Test collecting information about free space."""
 
391
        def statvfs(path, multiplier=mock_counter(1).next):
 
392
            return (4096, 0, mb(1000), mb(multiplier() * 100), 0, 0, 0, 0, 0)
 
393
 
 
394
        filename = self.make_path("""\
 
395
/dev/hda2 / xfs rw 0 0
 
396
""")
 
397
        plugin = self.get_mount_info(mounts_file=filename, statvfs=statvfs,
 
398
                                     create_time=self.reactor.time,
 
399
                                     mtab_file=filename)
 
400
        step_size = self.monitor.step_size
 
401
        self.monitor.add(plugin)
 
402
 
 
403
        self.reactor.advance(step_size)
 
404
 
 
405
        message = plugin.create_free_space_message()
 
406
        self.assertTrue(message)
 
407
        self.assertEquals(message.get("type"), "free-space")
 
408
        free_space = message.get("free-space", ())
 
409
        self.assertEquals(len(free_space), 1)
 
410
        self.assertEquals(free_space[0], (step_size, "/", 409600))
 
411
 
 
412
    def test_never_exchange_empty_messages(self):
 
413
        """
 
414
        When the plugin has no data, it's various create_X_message()
 
415
        methods will return None.  Empty or null messages should never
 
416
        be queued.
 
417
        """
 
418
        self.mstore.set_accepted_types(["load-average"])
 
419
 
 
420
        filename = self.make_path("")
 
421
        plugin = self.get_mount_info(mounts_file=filename, mtab_file=filename)
 
422
        self.monitor.add(plugin)
 
423
        self.monitor.exchange()
 
424
        self.assertEquals(len(self.mstore.get_pending_messages()), 0)
 
425
 
 
426
    def test_messages(self):
 
427
        """
 
428
        Test ensures all expected messages are created and contain the
 
429
        right datatypes.
 
430
        """
 
431
        def statvfs(path):
 
432
            return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
433
 
 
434
        filename = self.make_path("""\
 
435
/dev/hda2 / xfs rw 0 0
 
436
""")
 
437
        plugin = self.get_mount_info(mounts_file=filename, statvfs=statvfs,
 
438
                                     create_time=self.reactor.time,
 
439
                                     mtab_file=filename)
 
440
        step_size = self.monitor.step_size
 
441
        self.monitor.add(plugin)
 
442
 
 
443
        self.reactor.advance(step_size)
 
444
        self.monitor.exchange()
 
445
 
 
446
        messages = self.mstore.get_pending_messages()
 
447
        self.assertEquals(len(messages), 3)
 
448
        self.assertEquals(messages[0].get("mount-info"),
 
449
                          [(step_size,
 
450
                            {"device": "/dev/hda2", "mount-point": "/",
 
451
                             "filesystem": "xfs", "total-space": 4096000})])
 
452
        self.assertEquals(messages[1].get("free-space"),
 
453
                          [(step_size, "/", 409600)])
 
454
        self.assertTrue(isinstance(messages[1]["free-space"][0][2],
 
455
                                   (int, long)))
 
456
        self.assertEquals(messages[2].get("activities"),
 
457
                          [(step_size, "/", True)])
 
458
 
 
459
    def test_first_mount_activity_message(self):
 
460
        """
 
461
        Mount activity is only reported when a change from the
 
462
        previous known state is detected.  If mount activity has never
 
463
        been reported, it should be.
 
464
        """
 
465
        filename = self.make_path("""\
 
466
/dev/hda2 / xfs rw 0 0
 
467
""")
 
468
        plugin = self.get_mount_info(mounts_file=filename,
 
469
                                     create_time=self.reactor.time,
 
470
                                     mtab_file=filename)
 
471
        step_size = self.monitor.step_size
 
472
        self.monitor.add(plugin)
 
473
 
 
474
        self.reactor.advance(step_size)
 
475
        message = plugin.create_mount_activity_message()
 
476
        self.assertEquals(message.get("type"), "mount-activity")
 
477
        self.assertEquals(message.get("activities"), [(300, "/", True)])
 
478
 
 
479
        self.reactor.advance(step_size)
 
480
        self.assertEquals(plugin.create_mount_activity_message(), None)
 
481
 
 
482
    def test_wb_umount_activity(self):
 
483
        """Test ensures the plugin reports new umounts."""
 
484
        filename = self.make_path("""\
 
485
/dev/hda2 / xfs rw 0 0
 
486
""")
 
487
        plugin = self.get_mount_info(mounts_file=filename,
 
488
                                     create_time=self.reactor.time,
 
489
                                     mtab_file=filename)
 
490
        step_size = self.monitor.step_size
 
491
        self.monitor.add(plugin)
 
492
 
 
493
        self.reactor.advance(step_size)
 
494
        message = plugin.create_mount_activity_message()
 
495
        self.assertEquals(message.get("type"), "mount-activity")
 
496
        self.assertEquals(message.get("activities"), [(step_size, "/", True)])
 
497
 
 
498
        plugin._mounts_file = self.make_path("""\
 
499
""")
 
500
        self.reactor.advance(step_size)
 
501
        message = plugin.create_mount_activity_message()
 
502
        self.assertEquals(message.get("type"), "mount-activity")
 
503
        self.assertEquals(message.get("activities"),
 
504
                          [(step_size * 2, "/", False)])
 
505
 
 
506
    def test_wb_mount_activity(self):
 
507
        """Test ensures the plugin reports new mounts."""
 
508
        filename = self.make_path("""\
 
509
/dev/hda2 / xfs rw 0 0
 
510
""")
 
511
        plugin = self.get_mount_info(mounts_file=filename,
 
512
                                     create_time=self.reactor.time,
 
513
                                     mtab_file=filename)
 
514
        step_size = self.monitor.step_size
 
515
        self.monitor.add(plugin)
 
516
 
 
517
        self.reactor.advance(step_size)
 
518
        message = plugin.create_mount_activity_message()
 
519
        self.assertEquals(message.get("type"), "mount-activity")
 
520
        self.assertEquals(message.get("activities"), [(step_size, "/", True)])
 
521
 
 
522
        mount_dir = self.make_dir()
 
523
        plugin._mounts_file = self.make_path("""\
 
524
/dev/hda2 / xfs rw 0 0
 
525
/dev/hdb5 %s xfs rw 0 0
 
526
""" % mount_dir)
 
527
        self.reactor.advance(step_size)
 
528
        message = plugin.create_mount_activity_message()
 
529
        self.assertEquals(message.get("type"), "mount-activity")
 
530
        self.assertEquals(message.get("activities"),
 
531
                          [(step_size * 2, mount_dir, True)])
 
532
 
 
533
 
 
534
    def test_resynchronize(self):
 
535
        """
 
536
        On the reactor "resynchronize" event, new mount-info messages
 
537
        should be sent.
 
538
        """
 
539
        def statvfs(path):
 
540
            return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
541
        filename = self.make_path("""\
 
542
/dev/hda1 / ext3 rw 0 0
 
543
""")
 
544
        plugin = self.get_mount_info(mounts_file=filename,
 
545
                                     create_time=self.reactor.time,
 
546
                                     statvfs=statvfs, mtab_file=filename)
 
547
        self.monitor.add(plugin)
 
548
 
 
549
        plugin.run()
 
550
        plugin.exchange()
 
551
        self.reactor.fire("resynchronize")
 
552
        plugin.run()
 
553
        plugin.exchange()
 
554
        messages = self.mstore.get_pending_messages()
 
555
        messages = [message for message in messages
 
556
                    if message["type"] == "mount-info"]
 
557
        expected_message = {
 
558
            'type': 'mount-info',
 
559
            'mount-info': [(0, {'device': '/dev/hda1', 'mount-point': '/',
 
560
                                'total-space': 4096000, 'filesystem': 'ext3'})]}
 
561
        self.assertMessages(messages, [expected_message, expected_message])
 
562
 
 
563
    def test_bind_mounts(self):
 
564
        """
 
565
        Mounted devices that are mounted using Linux's "--bind" option
 
566
        shouldn't be listed, as they have the same free space/used space as the
 
567
        device they're bound to.
 
568
        """
 
569
        def statvfs(path):
 
570
            return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
571
 
 
572
        # From this test data, we expect only two mount points to be returned,
 
573
        # and the other two to be ignored (the rebound /dev/hda2 -> /mnt mounting)
 
574
        filename = self.make_path("""\
 
575
/dev/devices/by-uuid/12345567 / ext3 rw 0 0
 
576
/dev/hda2 /usr ext3 rw 0 0
 
577
/dev/devices/by-uuid/12345567 /mnt ext3 rw 0 0
 
578
/dev/devices/by-uuid/12345567 /media/Boot\\040OSX hfsplus rw 0 0
 
579
""")
 
580
 
 
581
        mtab_filename = self.make_path("""\
 
582
/dev/hda1 / ext3 rw 0 0
 
583
/dev/hda2 /usr ext3 rw 0 0
 
584
/opt /mnt none rw,bind 0 0
 
585
/opt /media/Boot\\040OSX none rw,bind 0 0
 
586
""")
 
587
        plugin = MountInfo(mounts_file=filename, create_time=self.reactor.time,
 
588
                           statvfs=statvfs, mtab_file=mtab_filename)
 
589
        self.monitor.add(plugin)
 
590
        plugin.run()
 
591
        message = plugin.create_mount_info_message()
 
592
        self.assertEquals(message.get("mount-info"),
 
593
            [(0, {"device": "/dev/devices/by-uuid/12345567",
 
594
                  "mount-point": "/", "total-space": 4096000L,
 
595
                  "filesystem": "ext3"}),
 
596
             (0 ,{"device": "/dev/hda2",
 
597
                  "mount-point": "/usr",
 
598
                  "total-space": 4096000L,
 
599
                  "filesystem": "ext3"}),
 
600
             ])
 
601
 
 
602
    def test_no_mtab_file(self):
 
603
        """
 
604
        If there's no mtab file available, then we can make no guesses about
 
605
        bind mounted directories, so any filesystems in /proc/mounts will be
 
606
        reported.
 
607
        """
 
608
        def statvfs(path):
 
609
            return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
610
 
 
611
        # In this test, we expect all mount points to be returned, as we can't
 
612
        # identify any as bind mounts.
 
613
        filename = self.make_path("""\
 
614
/dev/devices/by-uuid/12345567 / ext3 rw 0 0
 
615
/dev/hda2 /usr ext3 rw 0 0
 
616
/dev/devices/by-uuid/12345567 /mnt ext3 rw 0 0
 
617
""")
 
618
        # mktemp isn't normally secure, due to race conditions, but in this
 
619
        # case, we don't actually create the file at all.
 
620
        mtab_filename = tempfile.mktemp()
 
621
        plugin = MountInfo(mounts_file=filename, create_time=self.reactor.time,
 
622
                           statvfs=statvfs, mtab_file=mtab_filename)
 
623
        self.monitor.add(plugin)
 
624
        plugin.run()
 
625
        message = plugin.create_mount_info_message()
 
626
        self.assertEquals(message.get("mount-info"),
 
627
            [(0, {"device": "/dev/devices/by-uuid/12345567",
 
628
                  "mount-point": "/", "total-space": 4096000L,
 
629
                  "filesystem": "ext3"}),
 
630
             (0,{"device": "/dev/hda2",
 
631
                 "mount-point": "/usr",
 
632
                 "total-space": 4096000L,
 
633
                 "filesystem": "ext3"}),
 
634
             (0,{"device": "/dev/devices/by-uuid/12345567",
 
635
                 "mount-point": "/mnt",
 
636
                 "total-space": 4096000L,
 
637
                 "filesystem": "ext3"}),])
 
638
 
 
639
    def test_no_message_if_not_accepted(self):
 
640
        """
 
641
        Don't add any messages at all if the broker isn't currently
 
642
        accepting their type.
 
643
        """
 
644
        self.mstore.set_accepted_types([])
 
645
        def statvfs(path):
 
646
            return (4096, 0, mb(1000), mb(100), 0, 0, 0, 0, 0)
 
647
 
 
648
        # From this test data, we expect only two mount points to be returned,
 
649
        # and the third to be ignored (the rebound /dev/hda2 -> /mnt mounting)
 
650
        filename = self.make_path("""\
 
651
/dev/devices/by-uuid/12345567 / ext3 rw 0 0
 
652
/dev/hda2 /usr ext3 rw 0 0
 
653
/dev/devices/by-uuid/12345567 /mnt ext3 rw 0 0
 
654
""")
 
655
 
 
656
        mtab_filename = self.make_path("""\
 
657
/dev/hda1 / ext3 rw 0 0
 
658
/dev/hda2 /usr ext3 rw 0 0
 
659
/opt /mnt none rw,bind 0 0
 
660
""")
 
661
        plugin = MountInfo(mounts_file=filename, create_time=self.reactor.time,
 
662
                           statvfs=statvfs, mtab_file=mtab_filename)
 
663
        self.monitor.add(plugin)
 
664
        self.reactor.advance(self.monitor.step_size * 2)
 
665
        self.monitor.exchange()
 
666
 
 
667
        self.mstore.set_accepted_types(["mount-info"])
 
668
        self.assertMessages(list(self.mstore.get_pending_messages()), [])
 
669
 
 
670
    def test_call_on_accepted(self):
 
671
        plugin = self.get_mount_info(create_time=self.reactor.time)
 
672
        self.monitor.add(plugin)
 
673
 
 
674
        self.reactor.advance(plugin.run_interval)
 
675
 
 
676
        remote_broker_mock = self.mocker.replace(self.remote)
 
677
        remote_broker_mock.send_message(ANY, urgent=True)
 
678
        self.mocker.count(3)
 
679
        self.mocker.replay()
 
680
 
 
681
        self.reactor.fire(("message-type-acceptance-changed", "mount-info"),
 
682
                          True)