1
from twisted.internet.defer import fail, succeed
3
from landscape.lib import bpickle_dbus
4
from landscape.monitor.hardwareinventory import HardwareInventory
5
from landscape.tests.test_hal import MockHALManager, MockRealHALDevice
6
from landscape.tests.helpers import LandscapeTest, MonitorHelper
7
from landscape.tests.mocker import ANY
8
from landscape.message_schemas import HARDWARE_INVENTORY
11
class HardwareInventoryTest(LandscapeTest):
13
helpers = [MonitorHelper]
16
super(HardwareInventoryTest, self).setUp()
17
self.mstore.set_accepted_types(["hardware-inventory"])
18
devices = [MockRealHALDevice({u"info.udi": u"wubble",
19
u"info.product": u"Wubble",}),
20
MockRealHALDevice({u"info.udi": u"ooga",
21
u"info.product": u"Ooga",})]
22
self.hal_manager = MockHALManager(devices)
23
self.plugin = HardwareInventory(hal_manager=self.hal_manager)
24
self.monitor.add(self.plugin)
26
def assertSchema(self, devices):
27
full_message = {"type": "hardware-inventory", "devices": devices}
28
self.assertEquals(HARDWARE_INVENTORY.coerce(full_message), full_message)
30
def test_hal_devices(self):
32
The first time the plugin runs it should report information
33
about all HAL devices found on the system. Every UDI provided
34
by HAL should be present in the devices list as is from HAL.
36
message = self.plugin.create_message()
37
actual_udis = [part[1][u"info.udi"] for part in message]
38
expected_udis = [device.udi for device
39
in self.hal_manager.get_devices()]
40
self.assertEquals(set(actual_udis), set(expected_udis))
42
def test_first_message(self):
44
The first time the plugin runs it should report information
45
about all HAL devices found on the system. All new devices
46
will be reported with 'create' actions.
48
message = self.plugin.create_message()
49
actions = [part[0] for part in message]
50
self.assertEquals(set(actions), set(["create"]))
51
self.assertSchema(message)
53
def test_no_changes(self):
55
Messages should not be created if hardware information is
56
unchanged since the last server exchange.
58
self.plugin.exchange()
59
self.assertNotEquals(len(self.mstore.get_pending_messages()), 0)
61
messages = self.mstore.get_pending_messages()
62
self.plugin.exchange()
63
self.assertEquals(self.mstore.get_pending_messages(), messages)
65
def test_update(self):
67
If a change is detected for a device that was previously
68
reported to the server, the changed device should be reported
69
with an 'update' action. Property changes are reported at a
72
self.hal_manager.devices = [
73
MockRealHALDevice({u"info.udi": u"wubble",
74
u"info.product": u"Wubble",}),]
76
message = self.plugin.create_message()
77
self.plugin.persist_data(None)
78
self.assertEquals(message, [("create", {u"info.udi": u"wubble",
79
u"info.product": u"Wubble"}),])
81
self.hal_manager.devices[0] = MockRealHALDevice(
82
{u"info.udi": u"wubble", u"info.product": u"Ooga",})
83
message = self.plugin.create_message()
84
self.plugin.persist_data(None)
85
self.assertEquals(message, [("update", u"wubble",
86
{}, {u"info.product": u"Ooga"}, {}),])
87
self.assertSchema(message)
88
self.assertEquals(self.plugin.create_message(), [])
90
def test_update_list(self):
92
An update should be sent to the server when a strlist device
93
property changes. No updates should be sent if a device is
96
self.hal_manager.devices = [
97
MockRealHALDevice({u"info.udi": u"wubble",
98
u"info.product": u"Wubble",
99
u"info.capabilities": [u"foo", u"bar"]}),]
101
message = self.plugin.create_message()
102
self.plugin.persist_data(None)
103
self.assertEquals(message, [("create",
104
{u"info.udi": u"wubble",
105
u"info.product": u"Wubble",
106
u"info.capabilities": [u"foo", u"bar"]}),
109
self.assertSchema(message)
111
self.hal_manager.devices[0] = MockRealHALDevice(
112
{u"info.udi": u"wubble", u"info.product": u"Wubble",
113
u"info.capabilities": [u"foo"]})
114
message = self.plugin.create_message()
115
self.plugin.persist_data(None)
116
self.assertEquals(message, [("update", u"wubble",
117
{}, {u"info.capabilities": [u"foo"]}, {}),
119
self.assertSchema(message)
121
self.assertEquals(self.plugin.create_message(), [])
123
def test_update_complex(self):
125
The 'update' action reports property create, update and
128
self.hal_manager.devices = [
129
MockRealHALDevice({u"info.udi": u"wubble",
130
u"info.product": u"Wubble",
131
u"linux.acpi_type": 11}),]
133
message = self.plugin.create_message()
134
self.plugin.persist_data(None)
135
self.assertEquals(message, [("create", {u"info.udi": u"wubble",
136
u"info.product": u"Wubble",
137
u"linux.acpi_type": 11}),])
139
self.hal_manager.devices[0] = MockRealHALDevice(
140
{u"info.udi": u"wubble", u"info.product": u"Ooga",
141
u"info.category": u"unittest"})
142
message = self.plugin.create_message()
143
self.plugin.persist_data(None)
144
self.assertEquals(message, [("update", u"wubble",
145
{u"info.category": u"unittest"},
146
{u"info.product": u"Ooga"},
147
{u"linux.acpi_type": 11}),])
148
self.assertSchema(message)
150
self.assertEquals(self.plugin.create_message(), [])
152
def test_delete(self):
154
If a device that was previously reported is no longer present
155
in a system a device entry should be created with a 'delete'
158
self.hal_manager.devices = [
159
MockRealHALDevice({u"info.udi": u"wubble",
160
u"info.product": u"Wubble",}),
161
MockRealHALDevice({u"info.udi": u"ooga",
162
u"info.product": u"Ooga",})]
164
message = self.plugin.create_message()
165
self.plugin.persist_data(None)
166
self.assertEquals(message, [("create", {u"info.udi": u"wubble",
167
u"info.product": u"Wubble"}),
168
("create", {u"info.udi": u"ooga",
169
u"info.product": u"Ooga"}),])
170
self.assertSchema(message)
172
self.hal_manager.devices.pop(1)
173
message = self.plugin.create_message()
174
self.plugin.persist_data(None)
175
self.assertEquals(message, [("delete", u"ooga"),])
176
self.assertSchema(message)
177
self.assertEquals(self.plugin.create_message(), [])
179
def test_minimal_delete(self):
180
self.hal_manager.devices = [
181
MockRealHALDevice({u"info.udi": u"wubble",
182
u"block.device": u"/dev/scd",
183
u"storage.removable": True}),
184
MockRealHALDevice({u"info.udi": u"wubble0",
185
u"block.device": u"/dev/scd0",
186
u"info.parent": u"wubble"}),
187
MockRealHALDevice({u"info.udi": u"wubble1",
188
u"block.device": u"/dev/scd1",
189
u"info.parent": u"wubble"}),
190
MockRealHALDevice({u"info.udi": u"wubble2",
191
u"block.device": u"/dev/scd1",
192
u"info.parent": u"wubble0"}),
193
MockRealHALDevice({u"info.udi": u"wubble3",
194
u"block.device": u"/dev/scd1",
195
u"info.parent": u"wubble2"}),]
197
message = self.plugin.create_message()
198
self.plugin.persist_data(None)
200
del self.hal_manager.devices[:]
202
message = self.plugin.create_message()
203
self.plugin.persist_data(None)
205
self.assertEquals(message, [("delete", u"wubble"),])
206
self.assertEquals(self.plugin.create_message(), [])
208
def test_resynchronize(self):
210
If a 'resynchronize' reactor event is fired, the plugin should
211
send a message that contains all data as if the server has
214
self.plugin.exchange()
215
self.reactor.fire("resynchronize")
216
self.plugin.exchange()
218
messages = self.mstore.get_pending_messages()
219
self.assertEquals(len(messages), 2)
220
self.assertEquals(messages[0]["devices"], messages[1]["devices"])
222
def test_call_on_accepted(self):
223
remote_broker_mock = self.mocker.replace(self.remote)
224
remote_broker_mock.send_message(ANY, urgent=True)
225
self.mocker.result(succeed(None))
228
self.reactor.fire(("message-type-acceptance-changed",
229
"hardware-inventory"),
232
def test_no_message_if_not_accepted(self):
234
Don't add any messages at all if the broker isn't currently
235
accepting their type.
237
self.mstore.set_accepted_types([])
238
self.reactor.advance(self.monitor.step_size * 2)
239
self.monitor.exchange()
241
self.mstore.set_accepted_types(["hardware-inventory"])
242
self.assertMessages(list(self.mstore.get_pending_messages()), [])
244
def test_do_not_persist_changes_when_send_message_fails(self):
246
When the plugin is run it persists data that it uses on
247
subsequent checks to calculate the delta to send. It should
248
only persist data when the broker confirms that the message
249
sent by the plugin has been sent.
251
class MyException(Exception): pass
252
self.log_helper.ignore_errors(MyException)
254
broker_mock = self.mocker.replace(self.monitor.broker)
255
broker_mock.send_message(ANY, urgent=ANY)
256
self.mocker.result(fail(MyException()))
259
message = self.plugin.create_message()
261
def assert_message(message_id):
262
self.assertEquals(message, self.plugin.create_message())
264
result = self.plugin.exchange()
265
result.addCallback(assert_message)