lucy-python-script-2030 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lucy_python_script_2030-0.1.0.dist-info/METADATA +199 -0
- lucy_python_script_2030-0.1.0.dist-info/RECORD +8 -0
- lucy_python_script_2030-0.1.0.dist-info/WHEEL +5 -0
- lucy_python_script_2030-0.1.0.dist-info/top_level.txt +1 -0
- pypi/Scripts/pywin32_postinstall.py +729 -0
- pypi/Scripts/pywin32_testall.py +120 -0
- pypi/Scripts/wmitest.py +732 -0
- pypi/Scripts/wmiweb.py +255 -0
pypi/Scripts/wmitest.py
ADDED
|
@@ -0,0 +1,732 @@
|
|
|
1
|
+
"""Unit tests for WMI modules
|
|
2
|
+
|
|
3
|
+
Some tests are optional, since they rely on remote machines and
|
|
4
|
+
usernames / passwords. To enable these, copy wmitest.master.ini
|
|
5
|
+
to wmitest.ini and set the parameters you have available.
|
|
6
|
+
|
|
7
|
+
The watcher tests spawn temporary processes and temporary
|
|
8
|
+
logical drives. These may get left behind.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# TODO:
|
|
13
|
+
# - Test for negative timezone
|
|
14
|
+
# - Test for share name with embedded single quote
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
import os, sys
|
|
18
|
+
import datetime
|
|
19
|
+
try:
|
|
20
|
+
import ConfigParser
|
|
21
|
+
except ImportError:
|
|
22
|
+
import configparser as ConfigParser
|
|
23
|
+
import operator
|
|
24
|
+
try:
|
|
25
|
+
import Queue
|
|
26
|
+
except ImportError:
|
|
27
|
+
import queue as Queue
|
|
28
|
+
try:
|
|
29
|
+
next
|
|
30
|
+
except NameError:
|
|
31
|
+
def next(iterator): return iterator.next()
|
|
32
|
+
import subprocess
|
|
33
|
+
import tempfile
|
|
34
|
+
import threading
|
|
35
|
+
import time
|
|
36
|
+
import unittest
|
|
37
|
+
import warnings
|
|
38
|
+
try:
|
|
39
|
+
import _winreg
|
|
40
|
+
except ImportError:
|
|
41
|
+
import winreg as _winreg
|
|
42
|
+
|
|
43
|
+
import pythoncom
|
|
44
|
+
import win32api
|
|
45
|
+
import win32con
|
|
46
|
+
import win32file
|
|
47
|
+
|
|
48
|
+
import wmi
|
|
49
|
+
|
|
50
|
+
ini = ConfigParser.SafeConfigParser()
|
|
51
|
+
ini.read(["wmitest.master.ini", "wmitest.ini"])
|
|
52
|
+
settings = {}
|
|
53
|
+
if ini.has_section("settings"):
|
|
54
|
+
settings.update(ini.items("settings"))
|
|
55
|
+
excludes = [i.strip() for i in settings.get("excludes", "").split(",")]
|
|
56
|
+
|
|
57
|
+
COMPUTERS = [None, "."]
|
|
58
|
+
if "machine" in settings:
|
|
59
|
+
COMPUTERS.append(settings['machine'])
|
|
60
|
+
IMPERSONATION_LEVELS = [None, "identify", "impersonate", "delegate"]
|
|
61
|
+
AUTHENTICATION_LEVELS = [None, "default", "none", "connect", "call", "pkt", "pktintegrity", "pktprivacy"]
|
|
62
|
+
AUTHORITIES = [None]
|
|
63
|
+
if set(["domain", "machine"]) <= set(settings):
|
|
64
|
+
#~ AUTHORITIES.append("kerberos:%s" % settings['domain'])
|
|
65
|
+
AUTHORITIES.append("ntlmdomain:%s" % settings['domain'])
|
|
66
|
+
PRIVILEGES = [None, ['security', '!shutdown']]
|
|
67
|
+
NAMESPACES = [None, "root/cimv2", "default"]
|
|
68
|
+
|
|
69
|
+
class TestBasicConnections(unittest.TestCase):
|
|
70
|
+
|
|
71
|
+
def test_basic_connection(self):
|
|
72
|
+
"Check that a standard connection works"
|
|
73
|
+
self.assert_(wmi.WMI())
|
|
74
|
+
|
|
75
|
+
def test_remote_connection(self):
|
|
76
|
+
"Check that a remote connection works, if specified"
|
|
77
|
+
if "machine" in settings:
|
|
78
|
+
self.assert_(wmi.WMI(settings['machine']))
|
|
79
|
+
else:
|
|
80
|
+
warnings.warn("Skipping test_remote_connection")
|
|
81
|
+
|
|
82
|
+
def test_simple_moniker(self):
|
|
83
|
+
"Check that a simple moniker works"
|
|
84
|
+
self.assert_(wmi.WMI(moniker="winmgmts:"))
|
|
85
|
+
|
|
86
|
+
def test_moniker_with_class(self):
|
|
87
|
+
"Check that specifying a class in moniker works"
|
|
88
|
+
c0 = wmi.WMI().Win32_ComputerSystem
|
|
89
|
+
c1 = wmi.WMI(moniker="winmgmts:Win32_ComputerSystem")
|
|
90
|
+
self.assert_(c0 == c1)
|
|
91
|
+
|
|
92
|
+
def test_moniker_with_instance(self):
|
|
93
|
+
"Check that specifying an instance in the moniker works"
|
|
94
|
+
for c0 in wmi.WMI().Win32_ComputerSystem():
|
|
95
|
+
break
|
|
96
|
+
c1 = wmi.WMI(moniker='winmgmts:Win32_ComputerSystem.Name="%s"' % c0.Name)
|
|
97
|
+
self.assert_(c0 == c1)
|
|
98
|
+
|
|
99
|
+
def test_impersonation_levels(self):
|
|
100
|
+
"Check that specifying an impersonation level works"
|
|
101
|
+
for impersonation in IMPERSONATION_LEVELS:
|
|
102
|
+
self.assert_(wmi.WMI(impersonation_level=impersonation))
|
|
103
|
+
|
|
104
|
+
def test_authentication_levels(self):
|
|
105
|
+
"Check that specifying an authentication level works"
|
|
106
|
+
for authentication in AUTHENTICATION_LEVELS:
|
|
107
|
+
try:
|
|
108
|
+
c = wmi.WMI(authentication_level=authentication)
|
|
109
|
+
except wmi.x_access_denied:
|
|
110
|
+
warnings.warn("Access denied for authentication level %s" % authentication)
|
|
111
|
+
else:
|
|
112
|
+
self.assert_(c)
|
|
113
|
+
|
|
114
|
+
def test_authority(self):
|
|
115
|
+
"Check that specifying an authority works"
|
|
116
|
+
for authority in AUTHORITIES:
|
|
117
|
+
self.assert_(wmi.WMI(authority=authority))
|
|
118
|
+
|
|
119
|
+
def test_privileges(self):
|
|
120
|
+
"Check that specifying privileges works"
|
|
121
|
+
for privileges in PRIVILEGES:
|
|
122
|
+
self.assert_(wmi.WMI(privileges=privileges))
|
|
123
|
+
|
|
124
|
+
def test_namespace(self):
|
|
125
|
+
"Check that specifying a namespace works"
|
|
126
|
+
for namespace in NAMESPACES:
|
|
127
|
+
self.assert_(wmi.WMI(namespace=namespace))
|
|
128
|
+
|
|
129
|
+
def test_suffix(self):
|
|
130
|
+
"Check that a suffix returns the class of that name"
|
|
131
|
+
self.assert_(wmi.WMI(namespace="DEFAULT", suffix="StdRegProv") == wmi.WMI(namespace="DEFAULT").StdRegProv)
|
|
132
|
+
|
|
133
|
+
def test_user_password(self):
|
|
134
|
+
"Check that username & password are passed through for a remote connection"
|
|
135
|
+
if set(["machine", "user", "password"]) <= set(settings):
|
|
136
|
+
self.assert_(wmi.WMI(computer=settings['machine'], user=settings['user'], password=settings['password']))
|
|
137
|
+
else:
|
|
138
|
+
warnings.warn("Skipping test_user_password because no machine, user or password")
|
|
139
|
+
|
|
140
|
+
def test_too_much_authentication(self):
|
|
141
|
+
"Check that user/password plus privs / suffix raises exception"
|
|
142
|
+
self.assertRaises(wmi.x_wmi_authentication, wmi.WMI, computer='***', user="***", password="***", privileges=["***"])
|
|
143
|
+
self.assertRaises(wmi.x_wmi_authentication, wmi.WMI, computer='***', user="***", password="***", suffix="***")
|
|
144
|
+
|
|
145
|
+
def test_user_password_with_impersonation_level(self):
|
|
146
|
+
"Check that an impersonation level works with a username / password"
|
|
147
|
+
if not(set(["machine", "user", "password"]) <= set(settings)):
|
|
148
|
+
warnings.warn("Skipping test_user_password_with_impersonation_level because no machine, user or password")
|
|
149
|
+
else:
|
|
150
|
+
self.assert_(
|
|
151
|
+
wmi.WMI(
|
|
152
|
+
computer=settings['machine'],
|
|
153
|
+
user=settings['user'],
|
|
154
|
+
password=settings['password'],
|
|
155
|
+
impersonation_level="impersonate"
|
|
156
|
+
)
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
def test_user_password_with_invalid_impersonation_level(self):
|
|
160
|
+
"Check that an impersonation level works with a username / password"
|
|
161
|
+
if not(set(["machine", "user", "password"]) <= set(settings)):
|
|
162
|
+
warnings.warn("Skipping test_user_password_with_invalid_impersonation_level because no machine, user or password")
|
|
163
|
+
else:
|
|
164
|
+
self.assertRaises(
|
|
165
|
+
wmi.x_wmi_authentication,
|
|
166
|
+
wmi.WMI,
|
|
167
|
+
computer=settings['machine'],
|
|
168
|
+
user=settings['user'],
|
|
169
|
+
password=settings['password'],
|
|
170
|
+
impersonation_level="***"
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
def test_user_password_with_authentication_level(self):
|
|
174
|
+
"Check that an invalid impersonation level raises x_wmi_authentication"
|
|
175
|
+
if not(set(["machine", "user", "password"]) <= set(settings)):
|
|
176
|
+
warnings.warn("Skipping test_user_password_with_authentication_level because no machine, user or password")
|
|
177
|
+
else:
|
|
178
|
+
self.assert_(
|
|
179
|
+
wmi.WMI(
|
|
180
|
+
computer=settings['machine'],
|
|
181
|
+
user=settings['user'],
|
|
182
|
+
password=settings['password'],
|
|
183
|
+
authentication_level="pktIntegrity"
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
def test_user_password_with_invalid_authentication_level(self):
|
|
188
|
+
"Check that an invalid authentication level raises x_wmi_authentication"
|
|
189
|
+
if not(set(["machine", "user", "password"]) <= set(settings)):
|
|
190
|
+
warnings.warn("Skipping test_user_password_with_invalid_authentication_level because no machine, user or password")
|
|
191
|
+
else:
|
|
192
|
+
self.assertRaises(
|
|
193
|
+
wmi.x_wmi_authentication,
|
|
194
|
+
wmi.WMI,
|
|
195
|
+
computer=settings['machine'],
|
|
196
|
+
user=settings['user'],
|
|
197
|
+
password=settings['password'],
|
|
198
|
+
authentication_level="***"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def test_local_user_password(self):
|
|
202
|
+
"Check that user/password for local connection raises exception"
|
|
203
|
+
self.assertRaises(wmi.x_wmi_authentication, wmi.WMI, user="***", password="***")
|
|
204
|
+
|
|
205
|
+
def test_find_classes(self):
|
|
206
|
+
"Check ability to switch class scan on and off"
|
|
207
|
+
self.assert_(wmi.WMI(find_classes=True)._classes)
|
|
208
|
+
self.assertFalse(wmi.WMI(find_classes=False)._classes)
|
|
209
|
+
|
|
210
|
+
def test_find_classes_false(self):
|
|
211
|
+
"By default, don't scan for classes but load them on demand"
|
|
212
|
+
self.assertFalse(wmi.WMI()._classes)
|
|
213
|
+
self.assert_(wmi.WMI().classes)
|
|
214
|
+
|
|
215
|
+
def test_classes_acts_as_list(self):
|
|
216
|
+
self.assert_(wmi.WMI().classes.index)
|
|
217
|
+
|
|
218
|
+
def test_classes_acts_as_dict(self):
|
|
219
|
+
self.assert_(wmi.WMI().classes.keys)
|
|
220
|
+
|
|
221
|
+
class TestThreadedConnection(unittest.TestCase):
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def test_initialised_thread(self):
|
|
225
|
+
"""A WMI connection in a thread which has been initialised for COM
|
|
226
|
+
should succeed.
|
|
227
|
+
"""
|
|
228
|
+
def f(q):
|
|
229
|
+
pythoncom.CoInitialize()
|
|
230
|
+
try:
|
|
231
|
+
try:
|
|
232
|
+
wmi.WMI()
|
|
233
|
+
except:
|
|
234
|
+
q.put(False)
|
|
235
|
+
else:
|
|
236
|
+
q.put(True)
|
|
237
|
+
finally:
|
|
238
|
+
pythoncom.CoUninitialize()
|
|
239
|
+
|
|
240
|
+
q = Queue.Queue()
|
|
241
|
+
threading.Thread(target=f, args=(q,)).start()
|
|
242
|
+
self.assert_(q.get())
|
|
243
|
+
|
|
244
|
+
def test_uninitialised_thread(self):
|
|
245
|
+
"""A WMI connection in a thread which has not been initialised
|
|
246
|
+
for COM should fail with a wmi-specific exception.
|
|
247
|
+
"""
|
|
248
|
+
def f(q):
|
|
249
|
+
try:
|
|
250
|
+
wmi.WMI()
|
|
251
|
+
except wmi.x_wmi_uninitialised_thread:
|
|
252
|
+
q.put(True)
|
|
253
|
+
except:
|
|
254
|
+
q.put(False)
|
|
255
|
+
else:
|
|
256
|
+
q.put(False)
|
|
257
|
+
|
|
258
|
+
q = Queue.Queue()
|
|
259
|
+
threading.Thread(target=f, args=(q,)).start()
|
|
260
|
+
self.assert_(q.get())
|
|
261
|
+
|
|
262
|
+
class TestMoniker(unittest.TestCase):
|
|
263
|
+
|
|
264
|
+
def test_moniker(self):
|
|
265
|
+
"""Look at all possible options for moniker construction and pass
|
|
266
|
+
them through to a WMI connector
|
|
267
|
+
"""
|
|
268
|
+
for computer in COMPUTERS:
|
|
269
|
+
if computer in (None, "."):
|
|
270
|
+
local_authorities = [None]
|
|
271
|
+
else:
|
|
272
|
+
local_authorities = AUTHORITIES
|
|
273
|
+
for impersonation_level in IMPERSONATION_LEVELS:
|
|
274
|
+
for authentication_level in AUTHENTICATION_LEVELS:
|
|
275
|
+
for authority in local_authorities:
|
|
276
|
+
for privileges in PRIVILEGES:
|
|
277
|
+
for namespace in NAMESPACES:
|
|
278
|
+
moniker = wmi.construct_moniker(
|
|
279
|
+
computer=computer,
|
|
280
|
+
impersonation_level=impersonation_level,
|
|
281
|
+
authority=authority,
|
|
282
|
+
privileges=privileges,
|
|
283
|
+
namespace=namespace
|
|
284
|
+
)
|
|
285
|
+
self.assert_(wmi.WMI(moniker=moniker), "Moniker failed: %s" % moniker)
|
|
286
|
+
|
|
287
|
+
def test_moniker_root_namespace(self):
|
|
288
|
+
"Check that namespace is prefixed by root if needed"
|
|
289
|
+
self.assertEquals(wmi.construct_moniker(namespace="default"), "winmgmts:root/default")
|
|
290
|
+
self.assertEquals(wmi.construct_moniker(namespace="root/default"), "winmgmts:root/default")
|
|
291
|
+
|
|
292
|
+
class TestFunctions(unittest.TestCase):
|
|
293
|
+
|
|
294
|
+
times = [
|
|
295
|
+
((2000, 1, 1), "20000101******.******+***"),
|
|
296
|
+
((2000, 1, 1, 10, 0, 0), "20000101100000.******+***"),
|
|
297
|
+
((2000, 1, 1, 10, 0, 0, 100), "20000101100000.000100+***"),
|
|
298
|
+
((2000, 1, 1, 10, 0, 0, 100, "GMT"), "20000101100000.000100+GMT")
|
|
299
|
+
]
|
|
300
|
+
|
|
301
|
+
def test_signed_to_unsigned(self):
|
|
302
|
+
tests = [
|
|
303
|
+
(0, 0),
|
|
304
|
+
(-1, 0xffffffff),
|
|
305
|
+
(+1, 1),
|
|
306
|
+
(0x7fffffff, 0x7fffffff),
|
|
307
|
+
(-0x7fffffff, 0x80000001)
|
|
308
|
+
]
|
|
309
|
+
for signed, unsigned in tests:
|
|
310
|
+
self.assertEquals(wmi.signed_to_unsigned(signed), unsigned)
|
|
311
|
+
|
|
312
|
+
def test_from_1601(self):
|
|
313
|
+
"Check conversion from 100-ns intervals since 1601(!)"
|
|
314
|
+
self.assertEquals(wmi.from_1601(0), datetime.datetime(1601, 1, 1))
|
|
315
|
+
self.assertEquals(wmi.from_1601(24 * 60 * 60 * 10 * 1000 * 1000), datetime.datetime(1601, 1, 2))
|
|
316
|
+
|
|
317
|
+
def test_from_time(self):
|
|
318
|
+
"Check conversion from time-tuple to time-string"
|
|
319
|
+
for t, s in self.times:
|
|
320
|
+
self.assertEquals(wmi.from_time(*t), s)
|
|
321
|
+
|
|
322
|
+
def test_to_time(self):
|
|
323
|
+
"Check conversion from time-string to time-tuple"
|
|
324
|
+
for t, s in self.times:
|
|
325
|
+
t = tuple(list(t) +([None] * 8))[:8]
|
|
326
|
+
self.assertEquals(wmi.to_time(s), t)
|
|
327
|
+
|
|
328
|
+
def test_get_wmi_type(self):
|
|
329
|
+
"Check that namespace, class & instance are identified correctly"
|
|
330
|
+
self.assertEquals(wmi.get_wmi_type(wmi.WMI()), "namespace")
|
|
331
|
+
self.assertEquals(wmi.get_wmi_type(wmi.WMI().Win32_ComputerSystem), "class")
|
|
332
|
+
for i in wmi.WMI().Win32_ComputerSystem():
|
|
333
|
+
self.assertEquals(wmi.get_wmi_type(i), "instance")
|
|
334
|
+
|
|
335
|
+
def test_registry(self):
|
|
336
|
+
"""Convenience Registry function is identical to picking
|
|
337
|
+
the StdRegProv class out of the DEFAULT namespace"""
|
|
338
|
+
self.assertEquals(wmi.Registry(), wmi.WMI(namespace="DEFAULT").StdRegProv)
|
|
339
|
+
|
|
340
|
+
class TestWMI(unittest.TestCase):
|
|
341
|
+
|
|
342
|
+
def setUp(self):
|
|
343
|
+
self.connection = wmi.WMI(namespace="root/cimv2", find_classes=False)
|
|
344
|
+
self.logical_disks = set(self.connection.Win32_LogicalDisk())
|
|
345
|
+
|
|
346
|
+
class TestNamespace(TestWMI):
|
|
347
|
+
|
|
348
|
+
def test_subclasses_of_simple(self):
|
|
349
|
+
self.assert_("Win32_ComputerSystem" in self.connection.subclasses_of())
|
|
350
|
+
|
|
351
|
+
def test_subclasses_of_subtree(self):
|
|
352
|
+
self.assert_("Win32_Desktop" in self.connection.subclasses_of("CIM_Setting"))
|
|
353
|
+
|
|
354
|
+
def test_subclasses_of_pattern(self):
|
|
355
|
+
self.assert_(set(["Win32_LogicalDisk", "Win32_MappedLogicalDisk"]) <= set(self.connection.subclasses_of("CIM_LogicalDevice", "Win32_.*Disk")))
|
|
356
|
+
|
|
357
|
+
def test_instances(self):
|
|
358
|
+
self.assertEquals(self.logical_disks, set(self.connection.instances("Win32_LogicalDisk")))
|
|
359
|
+
|
|
360
|
+
def test_new(self):
|
|
361
|
+
"Check this is an alias for the new method of the equivalent class"
|
|
362
|
+
self.assertEquals(self.connection.new("Win32_Process")._instance_of, self.connection.Win32_Process)
|
|
363
|
+
|
|
364
|
+
def test_query(self):
|
|
365
|
+
self.assertEquals(self.logical_disks, set(self.connection.query("SELECT * FROM Win32_LogicalDisk")))
|
|
366
|
+
|
|
367
|
+
def test_ipython_attributes_with_find_classes(self):
|
|
368
|
+
connection = wmi.WMI(find_classes=True)
|
|
369
|
+
self.assertEquals(sorted(connection._getAttributeNames()), sorted(i for i in connection.classes if not i.startswith("__")))
|
|
370
|
+
|
|
371
|
+
def test_getattr(self):
|
|
372
|
+
"Check that WMI classes are returned by attribute access on their namespace"
|
|
373
|
+
connection = wmi.WMI(find_classes=True)
|
|
374
|
+
for c in list(connection.classes)[:5]:
|
|
375
|
+
wmi_class = getattr(connection, c)
|
|
376
|
+
self.assert_(isinstance(wmi_class, wmi._wmi_class))
|
|
377
|
+
self.assertEquals(wmi_class._class_name, c)
|
|
378
|
+
|
|
379
|
+
def test_watch_for(self):
|
|
380
|
+
"""Check that the watch_for method returns a watcher. The watcher itself
|
|
381
|
+
will be tested elsewhere.
|
|
382
|
+
"""
|
|
383
|
+
watcher = self.connection.watch_for(
|
|
384
|
+
wmi_class="Win32_Process"
|
|
385
|
+
)
|
|
386
|
+
self.assert_(isinstance(watcher, wmi._wmi_watcher))
|
|
387
|
+
|
|
388
|
+
class TestClass(TestWMI):
|
|
389
|
+
|
|
390
|
+
def test_class_from_namespace(self):
|
|
391
|
+
self.assert_(self.connection.Win32_ComputerSystem._namespace is self.connection)
|
|
392
|
+
|
|
393
|
+
def test_class_without_namespace(self):
|
|
394
|
+
wmi_class = wmi.GetObject("winmgmts:Win32_ComputerSystem")
|
|
395
|
+
self.assert_(wmi._wmi_class(None, wmi_class)._namespace)
|
|
396
|
+
|
|
397
|
+
def test_query(self):
|
|
398
|
+
self.assertEquals(
|
|
399
|
+
set(self.connection.Win32_ComputerSystem.query()),
|
|
400
|
+
set(self.connection.query("SELECT * FROM Win32_ComputerSystem"))
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
def test_query_with_where(self):
|
|
404
|
+
this_drive = os.getcwd()[:2]
|
|
405
|
+
for drive in self.connection.Win32_LogicalDisk(Name=this_drive):
|
|
406
|
+
self.assertEquals(drive.Name, this_drive)
|
|
407
|
+
|
|
408
|
+
def test_query_with_fields(self):
|
|
409
|
+
this_drive = os.getcwd()[:2]
|
|
410
|
+
properties = set(["MediaType"])
|
|
411
|
+
self.assert_("Name" not in properties)
|
|
412
|
+
for drive in self.connection.Win32_LogicalDisk(properties, Name=this_drive):
|
|
413
|
+
self.assertEquals(set(drive.properties), set(properties))
|
|
414
|
+
self.assert_(drive.MediaType)
|
|
415
|
+
self.assertRaises(AttributeError, getattr, drive, "Name")
|
|
416
|
+
|
|
417
|
+
def test_watch_for(self):
|
|
418
|
+
"""Check that the watch_for method returns a watcher. The watcher itself
|
|
419
|
+
will be tested elsewhere.
|
|
420
|
+
"""
|
|
421
|
+
watcher = self.connection.Win32_Process.watch_for()
|
|
422
|
+
self.assert_(isinstance(watcher, wmi._wmi_watcher))
|
|
423
|
+
|
|
424
|
+
def test_instances(self):
|
|
425
|
+
self.assertEquals(
|
|
426
|
+
set(self.connection.Win32_LogicalDisk()),
|
|
427
|
+
set(self.connection.Win32_LogicalDisk.instances())
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
def test_new(self):
|
|
431
|
+
process = self.connection.Win32_Process.new()
|
|
432
|
+
self.assertEquals(wmi.get_wmi_type(process), "instance")
|
|
433
|
+
self.assertEquals(process._instance_of, self.connection.Win32_process)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
class TestWatcher(TestWMI):
|
|
437
|
+
|
|
438
|
+
def new_letter(self):
|
|
439
|
+
return \
|
|
440
|
+
set("%s:" % chr(i) for i in range(ord('A'), 1 + ord('Z'))).\
|
|
441
|
+
difference(d.DeviceID for d in self.connection.Win32_LogicalDisk()).\
|
|
442
|
+
pop()
|
|
443
|
+
|
|
444
|
+
@staticmethod
|
|
445
|
+
def create(new_letter):
|
|
446
|
+
#~ print("about to create drive with letter", new_letter)
|
|
447
|
+
here = os.path.dirname(os.path.abspath(__file__))
|
|
448
|
+
win32file.DefineDosDevice(0, new_letter, here)
|
|
449
|
+
try:
|
|
450
|
+
#
|
|
451
|
+
# This sleep is needed for the WMI pollster to react
|
|
452
|
+
#
|
|
453
|
+
time.sleep(2)
|
|
454
|
+
finally:
|
|
455
|
+
win32file.DefineDosDevice(2, new_letter, here)
|
|
456
|
+
|
|
457
|
+
def test_creation(self):
|
|
458
|
+
try:
|
|
459
|
+
new_letter = self.new_letter()
|
|
460
|
+
except KeyError:
|
|
461
|
+
warnings.warn("Unable to find a spare drive letter to map.")
|
|
462
|
+
return
|
|
463
|
+
|
|
464
|
+
watcher = self.connection.Win32_LogicalDisk.watch_for(
|
|
465
|
+
notification_type="Creation",
|
|
466
|
+
DeviceID=new_letter
|
|
467
|
+
)
|
|
468
|
+
t = threading.Timer(2, self.create,(new_letter,))
|
|
469
|
+
t.start()
|
|
470
|
+
found_disk = watcher(timeout_ms=20000)
|
|
471
|
+
self.assert_(isinstance(found_disk, wmi._wmi_object))
|
|
472
|
+
self.assertEqual(found_disk.Caption, new_letter)
|
|
473
|
+
t.join()
|
|
474
|
+
|
|
475
|
+
def test_event_with_no_params(self):
|
|
476
|
+
try:
|
|
477
|
+
new_letter = self.new_letter()
|
|
478
|
+
except KeyError:
|
|
479
|
+
warnings.warn("Unable to find a spare drive letter to map.")
|
|
480
|
+
return
|
|
481
|
+
|
|
482
|
+
#
|
|
483
|
+
# This watcher will return *any* logical disk with some activity. To
|
|
484
|
+
# make sure there is at least some, we'll create a new logical disk
|
|
485
|
+
# but there's no guarantee that this will be the one returned, as
|
|
486
|
+
# activity on, eg, the C: drive will be enough to trigger the event.
|
|
487
|
+
#
|
|
488
|
+
watcher = self.connection.Win32_LogicalDisk.watch_for()
|
|
489
|
+
t = threading.Timer(2, self.create,(new_letter,))
|
|
490
|
+
t.start()
|
|
491
|
+
found_disk = watcher(timeout_ms=20000)
|
|
492
|
+
self.assert_(isinstance(found_disk, wmi._wmi_object))
|
|
493
|
+
self.assertEqual(found_disk.path().Class, "Win32_LogicalDisk")
|
|
494
|
+
t.join()
|
|
495
|
+
|
|
496
|
+
def test_valid_notification_types(self):
|
|
497
|
+
for notification_type in ['operation', 'modification', 'creation', 'deletion']:
|
|
498
|
+
self.assert_(self.connection.Win32_LogicalDisk.watch_for(notification_type=notification_type))
|
|
499
|
+
|
|
500
|
+
def test_invalid_notification_types(self):
|
|
501
|
+
self.assertRaises(wmi.x_wmi, self.connection.Win32_LogicalDisk.watch_for, notification_type="***")
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
def do_not_test_extrinsic_event(self):
|
|
505
|
+
|
|
506
|
+
#
|
|
507
|
+
# This doesn't seem implementable at the moment
|
|
508
|
+
# as a test. I can't find a reproducible extrinsic
|
|
509
|
+
# event except for Win32_DeviceChangeEvent and that
|
|
510
|
+
# one would require someone to, eg, plug in / unplug
|
|
511
|
+
# a USB stick.
|
|
512
|
+
#
|
|
513
|
+
# It looks as though Win32_ProcessStartTrace should work
|
|
514
|
+
# and it does on my laptop; just not on my desktop.
|
|
515
|
+
#
|
|
516
|
+
|
|
517
|
+
def _create(queue):
|
|
518
|
+
queue.put(subprocess.Popen([sys.executable, "-c", "import time; time.sleep(10)"]))
|
|
519
|
+
|
|
520
|
+
watcher = self.connection.Win32_ProcessStartTrace.watch_for(
|
|
521
|
+
fields=["*"]##,
|
|
522
|
+
#~ ProcessName=os.path.basename(sys.executable)
|
|
523
|
+
)
|
|
524
|
+
q = Queue.Queue()
|
|
525
|
+
t = threading.Timer(2, _create,(q,))
|
|
526
|
+
try:
|
|
527
|
+
t.start()
|
|
528
|
+
found_process = watcher(timeout_ms=20000)
|
|
529
|
+
spawned_process = q.get_nowait()
|
|
530
|
+
self.assert_(isinstance(found_process, wmi._wmi_event))
|
|
531
|
+
self.assertEqual(int(found_process.ProcessID), spawned_process.pid)
|
|
532
|
+
finally:
|
|
533
|
+
t.cancel()
|
|
534
|
+
|
|
535
|
+
class TestMethods(TestWMI):
|
|
536
|
+
|
|
537
|
+
def test_exists(self):
|
|
538
|
+
"Check that a well-known method is available by attribute"
|
|
539
|
+
self.assert_(self.connection.Win32_Process.Create)
|
|
540
|
+
|
|
541
|
+
def test_params(self):
|
|
542
|
+
"Check that the names and arrayness of params are picked up when not arrays"
|
|
543
|
+
self.assertEquals(
|
|
544
|
+
[(n, False) for n in ["CommandLine", "CurrentDirectory", "ProcessStartupInformation"]],
|
|
545
|
+
self.connection.Win32_Process.Create.in_parameter_names
|
|
546
|
+
)
|
|
547
|
+
self.assertEquals(
|
|
548
|
+
[("ProcessId", False),("ReturnValue", False)],
|
|
549
|
+
self.connection.Win32_Process.Create.out_parameter_names
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
def test_positional_params(self):
|
|
553
|
+
dir = tempfile.mkdtemp()
|
|
554
|
+
filename = "abc.txt"
|
|
555
|
+
contents = str(datetime.datetime.now())
|
|
556
|
+
handle, result = self.connection.Win32_Process.Create(
|
|
557
|
+
"cmd /c echo %s > %s" %(contents, filename),
|
|
558
|
+
dir,
|
|
559
|
+
self.connection.Win32_ProcessStartup.new(ShowWindow=0)
|
|
560
|
+
)
|
|
561
|
+
time.sleep(0.5)
|
|
562
|
+
with open(os.path.join(dir, filename)) as f:
|
|
563
|
+
self.assertEqual(f.read(), contents + " \n")
|
|
564
|
+
|
|
565
|
+
def test_named_params(self):
|
|
566
|
+
dir = tempfile.mkdtemp()
|
|
567
|
+
filename = "abc.txt"
|
|
568
|
+
contents = str(datetime.datetime.now())
|
|
569
|
+
handle, result = self.connection.Win32_Process.Create(
|
|
570
|
+
ProcessStartupInformation=self.connection.Win32_ProcessStartup.new(ShowWindow=0),
|
|
571
|
+
CurrentDirectory=dir,
|
|
572
|
+
CommandLine="cmd /c echo %s > %s" %(contents, filename)
|
|
573
|
+
)
|
|
574
|
+
time.sleep(0.5)
|
|
575
|
+
with open(os.path.join(dir, filename)) as f:
|
|
576
|
+
self.assertEqual(f.read(), contents + " \n")
|
|
577
|
+
|
|
578
|
+
def test_in_params_with_array(self):
|
|
579
|
+
"Check that the names and arrayness of params are picked up when arrays"
|
|
580
|
+
self.assertEquals(
|
|
581
|
+
[("DNSServerSearchOrder", True)],
|
|
582
|
+
self.connection.Win32_NetworkAdapterConfiguration.SetDNSServerSearchOrder.in_parameter_names
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
def test_instance_methods_are_distinct(self):
|
|
586
|
+
"""Check that the methods of difference instances of a class are distinct.
|
|
587
|
+
This caused a problem when calling .Terminate on one process killed another.
|
|
588
|
+
"""
|
|
589
|
+
methods = [d.Reset for d in self.logical_disks]
|
|
590
|
+
for i in range(len(methods)-1):
|
|
591
|
+
self.assertNotEqual(methods[i], methods[i+1])
|
|
592
|
+
|
|
593
|
+
def test_call_from_class(self):
|
|
594
|
+
"Check that a method can be called from a class"
|
|
595
|
+
self.assert_(self.connection.Win32_Process.Create(
|
|
596
|
+
CommandLine=sys.executable + " -c pass",
|
|
597
|
+
ProcessStartupInformation=self.connection.Win32_ProcessStartup.new(ShowWindow=0)
|
|
598
|
+
))
|
|
599
|
+
|
|
600
|
+
def test_call_from_instance(self):
|
|
601
|
+
"Check that a method can be called from an instance"
|
|
602
|
+
handle, _ = self.connection.Win32_Process.Create(
|
|
603
|
+
CommandLine=sys.executable,
|
|
604
|
+
ProcessStartupInformation=self.connection.Win32_ProcessStartup.new(ShowWindow=0)
|
|
605
|
+
)
|
|
606
|
+
result = 1
|
|
607
|
+
for p in self.connection.Win32_Process(Handle=handle):
|
|
608
|
+
result, = p.Terminate()
|
|
609
|
+
self.assertEqual(result, 0)
|
|
610
|
+
|
|
611
|
+
class TestProperties(TestWMI):
|
|
612
|
+
|
|
613
|
+
def test_access(self):
|
|
614
|
+
"Check that all properties are available as attributes"
|
|
615
|
+
for d in self.logical_disks:
|
|
616
|
+
break
|
|
617
|
+
for p in d.ole_object.Properties_:
|
|
618
|
+
self.assertEqual(p.Value, getattr(d, p.Name))
|
|
619
|
+
|
|
620
|
+
def test_attribute_passthrough(self):
|
|
621
|
+
"Check that unknown attributes are passed through to the underlying object"
|
|
622
|
+
for d in self.logical_disks:
|
|
623
|
+
break
|
|
624
|
+
#
|
|
625
|
+
# Can't rely on the COM Objects testing identical or equal;
|
|
626
|
+
# have to check their values and their emptiness.
|
|
627
|
+
#
|
|
628
|
+
self.assert_(d.Properties_)
|
|
629
|
+
self.assert_(d.ole_object.Properties_)
|
|
630
|
+
self.assertEqual(
|
|
631
|
+
[p.Value for p in d.Properties_],
|
|
632
|
+
[p.Value for p in d.ole_object.Properties_]
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
def test_settable(self):
|
|
636
|
+
"Check that a writeable property can be written"
|
|
637
|
+
name = str(time.time()).split(".")[0]
|
|
638
|
+
old_value = "***"
|
|
639
|
+
new_value = "!!!"
|
|
640
|
+
username = win32api.GetUserNameEx(win32con.NameSamCompatible)
|
|
641
|
+
self.assert_(not self.connection.Win32_Environment(Name=name, UserName=username))
|
|
642
|
+
self.connection.Win32_Environment.new(Name=name, UserName=username, VariableValue=old_value).put()
|
|
643
|
+
for envvar in self.connection.Win32_Environment(Name=name, UserName=username):
|
|
644
|
+
self.assertEqual(envvar.VariableValue, old_value)
|
|
645
|
+
envvar.VariableValue = new_value
|
|
646
|
+
try:
|
|
647
|
+
for envvar in self.connection.Win32_Environment(Name=name, UserName=username):
|
|
648
|
+
self.assertEqual(envvar.VariableValue, new_value)
|
|
649
|
+
finally:
|
|
650
|
+
for envvar in self.connection.Win32_Environment(Name=name, UserName=username):
|
|
651
|
+
envvar.VariableValue = None
|
|
652
|
+
|
|
653
|
+
class TestInstances(TestWMI):
|
|
654
|
+
|
|
655
|
+
def test_hashable(self):
|
|
656
|
+
"Ensure instances are hashable so can be used in a set/dict"
|
|
657
|
+
self.assert_(dict.fromkeys(self.logical_disks))
|
|
658
|
+
|
|
659
|
+
def test_equalable(self):
|
|
660
|
+
"Ensure instances compare equal"
|
|
661
|
+
self.assertEqual(self.logical_disks, self.logical_disks)
|
|
662
|
+
|
|
663
|
+
def test_not_equal_to_anything_else(self):
|
|
664
|
+
"Ensure WMI instances are not equal to non-WMI instances"
|
|
665
|
+
for d in self.logical_disks:
|
|
666
|
+
break
|
|
667
|
+
self.assertNotEqual(d, d.Caption)
|
|
668
|
+
|
|
669
|
+
def test_sortable(self):
|
|
670
|
+
"Ensure instances sort by full path/key"
|
|
671
|
+
self.assertEqual(
|
|
672
|
+
sorted(self.logical_disks),
|
|
673
|
+
sorted(self.logical_disks, key=operator.attrgetter("DeviceID"))
|
|
674
|
+
)
|
|
675
|
+
|
|
676
|
+
def test_references(self):
|
|
677
|
+
"Ensure that associations are special-cased to return wrapped objects"
|
|
678
|
+
for d in self.logical_disks:
|
|
679
|
+
break
|
|
680
|
+
for r in d.references("Win32_LogicalDiskRootDirectory"):
|
|
681
|
+
self.assert_(r.is_association)
|
|
682
|
+
self.assertEqual(r.GroupComponent, d)
|
|
683
|
+
self.assert_(isinstance(r.GroupComponent, wmi._wmi_object))
|
|
684
|
+
self.assert_(isinstance(r.PartComponent, wmi._wmi_object))
|
|
685
|
+
|
|
686
|
+
def test_associators(self):
|
|
687
|
+
"Ensure that associators are returned by association / result"
|
|
688
|
+
for d in self.logical_disks:
|
|
689
|
+
if d.DeviceID == os.path.abspath(__file__)[:2]:
|
|
690
|
+
break
|
|
691
|
+
else:
|
|
692
|
+
raise RuntimeError("Unable to find the logical drive corresponding to this file")
|
|
693
|
+
root_dir = d.associators(wmi_association_class="Win32_LogicalDiskRootDirectory")[0]
|
|
694
|
+
self.assertEqual(root_dir.Name.lower(), d.Name.lower() + "\\".lower())
|
|
695
|
+
root_dir = d.associators(wmi_result_class="Win32_Directory")[0]
|
|
696
|
+
self.assertEqual(root_dir.Name.lower(), d.Name.lower() + "\\")
|
|
697
|
+
|
|
698
|
+
def test_derivation(self):
|
|
699
|
+
"Check that derivation mimics WMI-provided Derivation_ property"
|
|
700
|
+
for d in self.logical_disks:
|
|
701
|
+
break
|
|
702
|
+
self.assertEqual(d.derivation(), d.ole_object.Derivation_)
|
|
703
|
+
|
|
704
|
+
def test_keys(self):
|
|
705
|
+
"Check that the readonly keys property returns the keys for an object"
|
|
706
|
+
self.assertEqual(self.connection.Win32_LogicalDisk.keys, ['DeviceID'])
|
|
707
|
+
self.assertEqual(next(iter(self.logical_disks)).keys, ['DeviceID'])
|
|
708
|
+
|
|
709
|
+
class TestInstanceCreation(TestWMI):
|
|
710
|
+
|
|
711
|
+
def test_create_instance(self):
|
|
712
|
+
self.assert_(isinstance(self.connection.Win32_ProcessStartup.new(ShowWindow=2), wmi._wmi_object))
|
|
713
|
+
|
|
714
|
+
class TestAssociations(TestWMI):
|
|
715
|
+
|
|
716
|
+
def test_all_properties_available(self):
|
|
717
|
+
#
|
|
718
|
+
# An association can contain not only the associated
|
|
719
|
+
# classes but also extra information as well. Ensure
|
|
720
|
+
# that both types of data are correctly handled.
|
|
721
|
+
#
|
|
722
|
+
for q in self.connection.Win32_DiskQuota():
|
|
723
|
+
for p in q.properties:
|
|
724
|
+
try:
|
|
725
|
+
getattr(q, p)
|
|
726
|
+
except wmi.x_wmi:
|
|
727
|
+
assert False, "Error getting %s from %s" % (p, q)
|
|
728
|
+
else:
|
|
729
|
+
assert True
|
|
730
|
+
|
|
731
|
+
if __name__ == '__main__':
|
|
732
|
+
unittest.main()
|