|
1
|
|
|
""" |
|
2
|
|
|
Run common tests on server side |
|
3
|
|
|
Tests that can only be run on server side must be defined here |
|
4
|
|
|
""" |
|
5
|
|
|
import asyncio |
|
6
|
|
|
import pytest |
|
7
|
|
|
import logging |
|
8
|
|
|
import os |
|
9
|
|
|
import shelve |
|
10
|
|
|
from datetime import timedelta |
|
11
|
|
|
from enum import Enum, EnumMeta |
|
12
|
|
|
|
|
13
|
|
|
import asyncua |
|
14
|
|
|
from asyncua import Server, Client, ua, uamethod, BaseEvent, AuditEvent, AuditChannelEvent, AuditSecurityEvent, AuditOpenSecureChannelEvent |
|
15
|
|
|
from asyncua.common import ua_utils |
|
16
|
|
|
|
|
17
|
|
|
pytestmark = pytest.mark.asyncio |
|
18
|
|
|
_logger = logging.getLogger(__name__) |
|
19
|
|
|
|
|
20
|
|
|
|
|
21
|
|
|
async def test_discovery(server, discovery_server): |
|
22
|
|
|
client = Client(discovery_server.endpoint.geturl()) |
|
23
|
|
|
async with client: |
|
24
|
|
|
servers = await client.find_servers() |
|
25
|
|
|
new_app_uri = 'urn:freeopcua:python:server:test_discovery' |
|
26
|
|
|
server.application_uri = new_app_uri |
|
27
|
|
|
await server.register_to_discovery(discovery_server.endpoint.geturl(), 0) |
|
28
|
|
|
# let server register registration |
|
29
|
|
|
await asyncio.sleep(0.1) |
|
30
|
|
|
new_servers = await client.find_servers() |
|
31
|
|
|
assert len(new_servers) - len(servers) == 1 |
|
32
|
|
|
assert new_app_uri not in [s.ApplicationUri for s in servers] |
|
33
|
|
|
assert new_app_uri in [s.ApplicationUri for s in new_servers] |
|
34
|
|
|
|
|
35
|
|
|
|
|
36
|
|
|
async def test_find_servers2(server, discovery_server): |
|
37
|
|
|
client = Client(discovery_server.endpoint.geturl()) |
|
38
|
|
|
async with client: |
|
39
|
|
|
servers = await client.find_servers() |
|
40
|
|
|
new_app_uri1 = 'urn:freeopcua:python:server:test_discovery1' |
|
41
|
|
|
server.application_uri = new_app_uri1 |
|
42
|
|
|
await server.register_to_discovery(discovery_server.endpoint.geturl(), period=0) |
|
43
|
|
|
new_app_uri2 = 'urn:freeopcua:python:test_discovery2' |
|
44
|
|
|
server.application_uri = new_app_uri2 |
|
45
|
|
|
await server.register_to_discovery(discovery_server.endpoint.geturl(), period=0) |
|
46
|
|
|
await asyncio.sleep(0.1) # let server register registration |
|
47
|
|
|
new_servers = await client.find_servers() |
|
48
|
|
|
assert len(new_servers) - len(servers) == 2 |
|
49
|
|
|
assert new_app_uri1 not in [s.ApplicationUri for s in servers] |
|
50
|
|
|
assert new_app_uri2 not in [s.ApplicationUri for s in servers] |
|
51
|
|
|
assert new_app_uri1 in [s.ApplicationUri for s in new_servers] |
|
52
|
|
|
assert new_app_uri2 in [s.ApplicationUri for s in new_servers] |
|
53
|
|
|
# now do a query with filer |
|
54
|
|
|
new_servers = await client.find_servers(['urn:freeopcua:python:server']) |
|
55
|
|
|
assert len(new_servers) - len(servers) == 0 |
|
56
|
|
|
assert new_app_uri1 in [s.ApplicationUri for s in new_servers] |
|
57
|
|
|
assert new_app_uri2 not in [s.ApplicationUri for s in new_servers] |
|
58
|
|
|
# now do a query with filer |
|
59
|
|
|
new_servers = await client.find_servers(['urn:freeopcua:python']) |
|
60
|
|
|
assert len(new_servers) - len(servers) == 2 |
|
61
|
|
|
assert new_app_uri1 in [s.ApplicationUri for s in new_servers] |
|
62
|
|
|
assert new_app_uri2 in [s.ApplicationUri for s in new_servers] |
|
63
|
|
|
|
|
64
|
|
|
|
|
65
|
|
|
async def test_register_namespace(server): |
|
66
|
|
|
uri = 'http://mycustom.Namespace.com' |
|
67
|
|
|
idx1 = await server.register_namespace(uri) |
|
68
|
|
|
idx2 = await server.get_namespace_index(uri) |
|
69
|
|
|
assert idx1 == idx2 |
|
70
|
|
|
|
|
71
|
|
|
|
|
72
|
|
|
async def test_register_existing_namespace(server): |
|
73
|
|
|
uri = 'http://mycustom.Namespace.com' |
|
74
|
|
|
idx1 = await server.register_namespace(uri) |
|
75
|
|
|
idx2 = await server.register_namespace(uri) |
|
76
|
|
|
idx3 = await server.get_namespace_index(uri) |
|
77
|
|
|
assert idx1 == idx2 |
|
78
|
|
|
assert idx1 == idx3 |
|
79
|
|
|
|
|
80
|
|
|
|
|
81
|
|
|
async def test_register_use_namespace(server): |
|
82
|
|
|
uri = 'http://my_very_custom.Namespace.com' |
|
83
|
|
|
idx = await server.register_namespace(uri) |
|
84
|
|
|
root = server.get_root_node() |
|
85
|
|
|
myvar = await root.add_variable(idx, 'var_in_custom_namespace', [5]) |
|
86
|
|
|
myid = myvar.nodeid |
|
87
|
|
|
assert idx == myid.NamespaceIndex |
|
88
|
|
|
|
|
89
|
|
|
|
|
90
|
|
|
async def test_server_method(server): |
|
91
|
|
|
def func(parent, variant): |
|
92
|
|
|
variant.Value *= 2 |
|
93
|
|
|
return [variant] |
|
94
|
|
|
|
|
95
|
|
|
o = server.get_objects_node() |
|
96
|
|
|
v = await o.add_method(3, 'Method1', func, [ua.VariantType.Int64], [ua.VariantType.Int64]) |
|
97
|
|
|
result = await o.call_method(v, ua.Variant(2.1)) |
|
98
|
|
|
assert result == 4.2 |
|
99
|
|
|
|
|
100
|
|
|
|
|
101
|
|
|
async def test_historize_variable(server): |
|
102
|
|
|
o = server.get_objects_node() |
|
103
|
|
|
var = await o.add_variable(3, "test_hist", 1.0) |
|
104
|
|
|
await server.iserver.enable_history_data_change(var, timedelta(days=1)) |
|
105
|
|
|
await asyncio.sleep(1) |
|
106
|
|
|
await var.set_value(2.0) |
|
107
|
|
|
await var.set_value(3.0) |
|
108
|
|
|
await server.iserver.disable_history_data_change(var) |
|
109
|
|
|
|
|
110
|
|
|
|
|
111
|
|
|
async def test_historize_events(server): |
|
112
|
|
|
srv_node = server.get_node(ua.ObjectIds.Server) |
|
113
|
|
|
assert await srv_node.get_event_notifier() == {ua.EventNotifier.SubscribeToEvents} |
|
114
|
|
|
srvevgen = await server.get_event_generator() |
|
115
|
|
|
await server.iserver.enable_history_event(srv_node, period=None) |
|
116
|
|
|
assert await srv_node.get_event_notifier() == {ua.EventNotifier.SubscribeToEvents, ua.EventNotifier.HistoryRead} |
|
117
|
|
|
srvevgen.trigger(message='Message') |
|
118
|
|
|
await server.iserver.disable_history_event(srv_node) |
|
119
|
|
|
|
|
120
|
|
|
|
|
121
|
|
|
async def test_references_for_added_nodes_method(server): |
|
122
|
|
|
objects = server.get_objects_node() |
|
123
|
|
|
o = await objects.add_object(3, 'MyObject') |
|
124
|
|
|
nodes = await objects.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Forward, |
|
125
|
|
|
includesubtypes=False) |
|
126
|
|
|
assert o in nodes |
|
127
|
|
|
nodes = await o.get_referenced_nodes(refs=ua.ObjectIds.Organizes, direction=ua.BrowseDirection.Inverse, |
|
128
|
|
|
includesubtypes=False) |
|
129
|
|
|
assert objects in nodes |
|
130
|
|
|
assert await o.get_parent() == objects |
|
131
|
|
|
assert (await o.get_type_definition()).Identifier == ua.ObjectIds.BaseObjectType |
|
132
|
|
|
|
|
133
|
|
|
@uamethod |
|
134
|
|
|
def callback(parent): |
|
135
|
|
|
return |
|
136
|
|
|
|
|
137
|
|
|
m = await o.add_method(3, 'MyMethod', callback) |
|
138
|
|
|
nodes = await o.get_referenced_nodes(refs=ua.ObjectIds.HasComponent, direction=ua.BrowseDirection.Forward, |
|
139
|
|
|
includesubtypes=False) |
|
140
|
|
|
assert m in nodes |
|
141
|
|
|
nodes = await m.get_referenced_nodes(refs=ua.ObjectIds.HasComponent, direction=ua.BrowseDirection.Inverse, |
|
142
|
|
|
includesubtypes=False) |
|
143
|
|
|
assert o in nodes |
|
144
|
|
|
assert await m.get_parent() == o |
|
145
|
|
|
|
|
146
|
|
|
|
|
147
|
|
|
async def test_get_event_from_type_node_BaseEvent(server): |
|
148
|
|
|
""" |
|
149
|
|
|
This should work for following BaseEvent tests to work |
|
150
|
|
|
(maybe to write it a bit differentlly since they are not independent) |
|
151
|
|
|
""" |
|
152
|
|
|
ev = await asyncua.common.events.get_event_obj_from_type_node( |
|
153
|
|
|
asyncua.Node(server.iserver.isession, ua.NodeId(ua.ObjectIds.BaseEventType)) |
|
154
|
|
|
) |
|
155
|
|
|
check_base_event(ev) |
|
156
|
|
|
|
|
157
|
|
|
|
|
158
|
|
|
async def test_get_event_from_type_node_Inhereted_AuditEvent(server): |
|
159
|
|
|
ev = await asyncua.common.events.get_event_obj_from_type_node( |
|
160
|
|
|
asyncua.Node(server.iserver.isession, ua.NodeId(ua.ObjectIds.AuditEventType)) |
|
161
|
|
|
) |
|
162
|
|
|
# we did not receive event |
|
163
|
|
|
assert ev is not None |
|
164
|
|
|
assert isinstance(ev, BaseEvent) |
|
165
|
|
|
assert isinstance(ev, AuditEvent) |
|
166
|
|
|
assert ev.EventType == ua.NodeId(ua.ObjectIds.AuditEventType) |
|
167
|
|
|
assert ev.Severity == 1 |
|
168
|
|
|
assert ev.ActionTimeStamp is None |
|
169
|
|
|
assert ev.Status == False |
|
170
|
|
|
assert ev.ServerId is None |
|
171
|
|
|
assert ev.ClientAuditEntryId is None |
|
172
|
|
|
assert ev.ClientUserId is None |
|
173
|
|
|
|
|
174
|
|
|
|
|
175
|
|
|
async def test_get_event_from_type_node_MultiInhereted_AuditOpenSecureChannelEvent(server): |
|
176
|
|
|
ev = await asyncua.common.events.get_event_obj_from_type_node( |
|
177
|
|
|
asyncua.Node(server.iserver.isession, ua.NodeId(ua.ObjectIds.AuditOpenSecureChannelEventType)) |
|
178
|
|
|
) |
|
179
|
|
|
assert ev is not None |
|
180
|
|
|
assert isinstance(ev, BaseEvent) |
|
181
|
|
|
assert isinstance(ev, AuditEvent) |
|
182
|
|
|
assert isinstance(ev, AuditSecurityEvent) |
|
183
|
|
|
assert isinstance(ev, AuditChannelEvent) |
|
184
|
|
|
assert isinstance(ev, AuditOpenSecureChannelEvent) |
|
185
|
|
|
assert ev.EventType == ua.NodeId(ua.ObjectIds.AuditOpenSecureChannelEventType) |
|
186
|
|
|
assert ev.Severity == 1 |
|
187
|
|
|
assert ev.ClientCertificate is None |
|
188
|
|
|
assert ev.ClientCertificateThumbprint is None |
|
189
|
|
|
assert ev.RequestType is None |
|
190
|
|
|
assert ev.SecurityPolicyUri is None |
|
191
|
|
|
assert ev.SecurityMode is None |
|
192
|
|
|
assert ev.RequestedLifetime is None |
|
193
|
|
|
|
|
194
|
|
|
|
|
195
|
|
|
async def test_eventgenerator_default(server): |
|
196
|
|
|
evgen = await server.get_event_generator() |
|
197
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
198
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
199
|
|
|
|
|
200
|
|
|
|
|
201
|
|
|
async def test_eventgenerator_BaseEvent_object(server): |
|
202
|
|
|
evgen = await server.get_event_generator(BaseEvent()) |
|
203
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
204
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
205
|
|
|
|
|
206
|
|
|
|
|
207
|
|
|
async def test_eventgenerator_BaseEvent_Node(server): |
|
208
|
|
|
evgen = await server.get_event_generator(asyncua.Node(server.iserver.isession, ua.NodeId(ua.ObjectIds.BaseEventType))) |
|
209
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
210
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
211
|
|
|
|
|
212
|
|
|
|
|
213
|
|
|
async def test_eventgenerator_BaseEvent_NodeId(server): |
|
214
|
|
|
evgen = await server.get_event_generator(ua.NodeId(ua.ObjectIds.BaseEventType)) |
|
215
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
216
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
217
|
|
|
|
|
218
|
|
|
|
|
219
|
|
|
async def test_eventgenerator_BaseEvent_ObjectIds(server): |
|
220
|
|
|
evgen = await server.get_event_generator(ua.ObjectIds.BaseEventType) |
|
221
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
222
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
223
|
|
|
|
|
224
|
|
|
|
|
225
|
|
|
async def test_eventgenerator_BaseEvent_Identifier(server): |
|
226
|
|
|
evgen = await server.get_event_generator(2041) |
|
227
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
228
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
229
|
|
|
|
|
230
|
|
|
|
|
231
|
|
|
async def test_eventgenerator_sourceServer_Node(server): |
|
232
|
|
|
evgen = await server.get_event_generator(emitting_node=asyncua.Node(server.iserver.isession, ua.NodeId(ua.ObjectIds.Server))) |
|
233
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
234
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
235
|
|
|
|
|
236
|
|
|
|
|
237
|
|
|
async def test_eventgenerator_sourceServer_NodeId(server): |
|
238
|
|
|
evgen = await server.get_event_generator(emitting_node=ua.NodeId(ua.ObjectIds.Server)) |
|
239
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
240
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
241
|
|
|
|
|
242
|
|
|
|
|
243
|
|
|
async def test_eventgenerator_sourceServer_ObjectIds(server): |
|
244
|
|
|
evgen = await server.get_event_generator(emitting_node=ua.ObjectIds.Server) |
|
245
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
246
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
247
|
|
|
|
|
248
|
|
|
|
|
249
|
|
|
async def test_eventgenerator_sourceMyObject(server): |
|
250
|
|
|
objects = server.get_objects_node() |
|
251
|
|
|
o = await objects.add_object(3, 'MyObject') |
|
252
|
|
|
evgen = await server.get_event_generator(emitting_node=o) |
|
253
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
254
|
|
|
await check_event_generator_object(evgen, o) |
|
255
|
|
|
|
|
256
|
|
|
|
|
257
|
|
|
async def test_eventgenerator_source_collision(server): |
|
258
|
|
|
objects = server.get_objects_node() |
|
259
|
|
|
o = await objects.add_object(3, 'MyObject') |
|
260
|
|
|
event = BaseEvent(sourcenode=o.nodeid) |
|
261
|
|
|
evgen = await server.get_event_generator(event, ua.ObjectIds.Server) |
|
262
|
|
|
await check_eventgenerator_base_event(evgen, server) |
|
263
|
|
|
await check_event_generator_object(evgen, o, emitting_node=asyncua.Node(server.iserver.isession, ua.ObjectIds.Server)) |
|
264
|
|
|
|
|
265
|
|
|
|
|
266
|
|
|
async def test_eventgenerator_inherited_event(server): |
|
267
|
|
|
evgen = await server.get_event_generator(ua.ObjectIds.AuditEventType) |
|
268
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
269
|
|
|
ev = evgen.event |
|
270
|
|
|
assert ev is not None # we did not receive event |
|
271
|
|
|
assert isinstance(ev, BaseEvent) |
|
272
|
|
|
assert isinstance(ev, AuditEvent) |
|
273
|
|
|
assert ua.NodeId(ua.ObjectIds.AuditEventType) == ev.EventType |
|
274
|
|
|
assert 1 == ev.Severity |
|
275
|
|
|
assert ev.ActionTimeStamp is None |
|
276
|
|
|
assert False == ev.Status |
|
277
|
|
|
assert ev.ServerId is None |
|
278
|
|
|
assert ev.ClientAuditEntryId is None |
|
279
|
|
|
assert ev.ClientUserId is None |
|
280
|
|
|
|
|
281
|
|
|
|
|
282
|
|
|
async def test_eventgenerator_multi_inherited_event(server): |
|
283
|
|
|
evgen = await server.get_event_generator(ua.ObjectIds.AuditOpenSecureChannelEventType) |
|
284
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
285
|
|
|
ev = evgen.event |
|
286
|
|
|
assert ev is not None # we did not receive event |
|
287
|
|
|
assert isinstance(ev, BaseEvent) |
|
288
|
|
|
assert isinstance(ev, AuditEvent) |
|
289
|
|
|
assert isinstance(ev, AuditSecurityEvent) |
|
290
|
|
|
assert isinstance(ev, AuditChannelEvent) |
|
291
|
|
|
assert isinstance(ev, AuditOpenSecureChannelEvent) |
|
292
|
|
|
assert ua.NodeId(ua.ObjectIds.AuditOpenSecureChannelEventType) == ev.EventType |
|
293
|
|
|
assert 1 == ev.Severity |
|
294
|
|
|
assert ev.ClientCertificate is None |
|
295
|
|
|
assert ev.ClientCertificateThumbprint is None |
|
296
|
|
|
assert ev.RequestType is None |
|
297
|
|
|
assert ev.SecurityPolicyUri is None |
|
298
|
|
|
assert ev.SecurityMode is None |
|
299
|
|
|
assert ev.RequestedLifetime is None |
|
300
|
|
|
|
|
301
|
|
|
|
|
302
|
|
|
async def test_create_custom_data_type_object_id(server): |
|
303
|
|
|
""" |
|
304
|
|
|
For the custom events all posibilites are tested. |
|
305
|
|
|
For other custom types only one test case is done since they are using the same code |
|
306
|
|
|
""" |
|
307
|
|
|
type = await server.create_custom_data_type(2, 'MyDataType', ua.ObjectIds.BaseDataType, |
|
308
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
309
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
310
|
|
|
await check_custom_type(type, ua.ObjectIds.BaseDataType, server) |
|
311
|
|
|
|
|
312
|
|
|
|
|
313
|
|
|
async def test_create_custom_event_type_object_id(server): |
|
314
|
|
|
type = await server.create_custom_event_type(2, 'MyEvent', ua.ObjectIds.BaseEventType, |
|
315
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
316
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
317
|
|
|
await check_custom_type(type, ua.ObjectIds.BaseEventType, server) |
|
318
|
|
|
|
|
319
|
|
|
|
|
320
|
|
|
async def test_create_custom_object_type_object_id(server): |
|
321
|
|
|
def func(parent, variant): |
|
322
|
|
|
return [ua.Variant(ret, ua.VariantType.Boolean)] |
|
323
|
|
|
|
|
324
|
|
|
properties = [('PropertyNum', ua.VariantType.Int32), |
|
325
|
|
|
('PropertyString', ua.VariantType.String)] |
|
326
|
|
|
variables = [('VariableString', ua.VariantType.String), |
|
327
|
|
|
('MyEnumVar', ua.VariantType.Int32, ua.NodeId(ua.ObjectIds.ApplicationType))] |
|
328
|
|
|
methods = [('MyMethod', func, [ua.VariantType.Int64], [ua.VariantType.Boolean])] |
|
329
|
|
|
node_type = await server.create_custom_object_type(2, 'MyObjectType', ua.ObjectIds.BaseObjectType, properties, |
|
330
|
|
|
variables, methods) |
|
331
|
|
|
await check_custom_type(node_type, ua.ObjectIds.BaseObjectType, server) |
|
332
|
|
|
variables = await node_type.get_variables() |
|
333
|
|
|
assert await node_type.get_child("2:VariableString") in variables |
|
334
|
|
|
assert ua.VariantType.String == ( |
|
335
|
|
|
await(await node_type.get_child("2:VariableString")).get_data_value()).Value.VariantType |
|
336
|
|
|
assert await node_type.get_child("2:MyEnumVar") in variables |
|
337
|
|
|
assert ua.VariantType.Int32 == (await(await node_type.get_child("2:MyEnumVar")).get_data_value()).Value.VariantType |
|
338
|
|
|
assert ua.NodeId(ua.ObjectIds.ApplicationType) == await (await node_type.get_child("2:MyEnumVar")).get_data_type() |
|
339
|
|
|
methods = await node_type.get_methods() |
|
340
|
|
|
assert await node_type.get_child("2:MyMethod") in methods |
|
341
|
|
|
|
|
342
|
|
|
|
|
343
|
|
|
async def test_create_custom_variable_type_object_id(server): |
|
344
|
|
|
type = await server.create_custom_variable_type(2, 'MyVariableType', ua.ObjectIds.BaseVariableType, |
|
345
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
346
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
347
|
|
|
await check_custom_type(type, ua.ObjectIds.BaseVariableType, server) |
|
348
|
|
|
|
|
349
|
|
|
|
|
350
|
|
|
async def test_create_custom_event_type_node_id(server): |
|
351
|
|
|
etype = await server.create_custom_event_type(2, 'MyEvent', ua.NodeId(ua.ObjectIds.BaseEventType), |
|
352
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
353
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
354
|
|
|
await check_custom_type(etype, ua.ObjectIds.BaseEventType, server) |
|
355
|
|
|
|
|
356
|
|
|
|
|
357
|
|
|
async def test_create_custom_event_type_node(server): |
|
358
|
|
|
etype = await server.create_custom_event_type(2, 'MyEvent', asyncua.Node(server.iserver.isession, |
|
359
|
|
|
ua.NodeId(ua.ObjectIds.BaseEventType)), |
|
360
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
361
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
362
|
|
|
await check_custom_type(etype, ua.ObjectIds.BaseEventType, server) |
|
363
|
|
|
|
|
364
|
|
|
|
|
365
|
|
|
async def test_get_event_from_type_node_custom_event(server): |
|
366
|
|
|
etype = await server.create_custom_event_type(2, 'MyEvent', ua.ObjectIds.BaseEventType, |
|
367
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
368
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
369
|
|
|
ev = await asyncua.common.events.get_event_obj_from_type_node(etype) |
|
370
|
|
|
check_custom_event(ev, etype) |
|
371
|
|
|
assert 0 == ev.PropertyNum |
|
372
|
|
|
assert ev.PropertyString is None |
|
373
|
|
|
|
|
374
|
|
|
|
|
375
|
|
|
async def test_eventgenerator_custom_event(server): |
|
376
|
|
|
etype = await server.create_custom_event_type(2, 'MyEvent', ua.ObjectIds.BaseEventType, |
|
377
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
378
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
379
|
|
|
evgen = await server.get_event_generator(etype, ua.ObjectIds.Server) |
|
380
|
|
|
check_eventgenerator_custom_event(evgen, etype, server) |
|
381
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
382
|
|
|
assert 0 == evgen.event.PropertyNum |
|
383
|
|
|
assert evgen.event.PropertyString is None |
|
384
|
|
|
|
|
385
|
|
|
|
|
386
|
|
|
async def test_eventgenerator_double_custom_event(server): |
|
387
|
|
|
event1 = await server.create_custom_event_type(3, 'MyEvent1', ua.ObjectIds.BaseEventType, |
|
388
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
389
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
390
|
|
|
event2 = await server.create_custom_event_type(4, 'MyEvent2', event1, [('PropertyBool', ua.VariantType.Boolean), |
|
391
|
|
|
('PropertyInt', ua.VariantType.Int32)]) |
|
392
|
|
|
evgen = await server.get_event_generator(event2, ua.ObjectIds.Server) |
|
393
|
|
|
check_eventgenerator_custom_event(evgen, event2, server) |
|
394
|
|
|
await check_eventgenerator_source_server(evgen, server) |
|
395
|
|
|
# Properties from MyEvent1 |
|
396
|
|
|
assert 0 == evgen.event.PropertyNum |
|
397
|
|
|
assert evgen.event.PropertyString is None |
|
398
|
|
|
# Properties from MyEvent2 |
|
399
|
|
|
assert not evgen.event.PropertyBool |
|
400
|
|
|
assert 0 == evgen.event.PropertyInt |
|
401
|
|
|
|
|
402
|
|
|
|
|
403
|
|
|
async def test_eventgenerator_custom_event_my_object(server): |
|
404
|
|
|
objects = server.get_objects_node() |
|
405
|
|
|
o = await objects.add_object(3, 'MyObject') |
|
406
|
|
|
etype = await server.create_custom_event_type(2, 'MyEvent', ua.ObjectIds.BaseEventType, |
|
407
|
|
|
[('PropertyNum', ua.VariantType.Int32), |
|
408
|
|
|
('PropertyString', ua.VariantType.String)]) |
|
409
|
|
|
|
|
410
|
|
|
evgen = await server.get_event_generator(etype, o) |
|
411
|
|
|
check_eventgenerator_custom_event(evgen, etype, server) |
|
412
|
|
|
await check_event_generator_object(evgen, o) |
|
413
|
|
|
assert 0 == evgen.event.PropertyNum |
|
414
|
|
|
assert evgen.event.PropertyString is None |
|
415
|
|
|
|
|
416
|
|
|
|
|
417
|
|
|
async def test_context_manager(): |
|
418
|
|
|
# Context manager calls start() and stop() |
|
419
|
|
|
state = [0] |
|
420
|
|
|
|
|
421
|
|
|
async def increment_state(self, *args, **kwargs): |
|
422
|
|
|
state[0] += 1 |
|
423
|
|
|
|
|
424
|
|
|
# create server and replace instance methods with dummy methods |
|
425
|
|
|
server = Server() |
|
426
|
|
|
server.start = increment_state.__get__(server) |
|
427
|
|
|
server.stop = increment_state.__get__(server) |
|
428
|
|
|
assert state[0] == 0 |
|
429
|
|
|
async with server: |
|
430
|
|
|
# test if server started |
|
431
|
|
|
assert 1 == state[0] |
|
432
|
|
|
# test if server stopped |
|
433
|
|
|
assert 2 == state[0] |
|
434
|
|
|
|
|
435
|
|
|
|
|
436
|
|
|
async def test_get_node_by_ns(server): |
|
437
|
|
|
def get_ns_of_nodes(nodes): |
|
438
|
|
|
ns_list = set() |
|
439
|
|
|
for node in nodes: |
|
440
|
|
|
ns_list.add(node.nodeid.NamespaceIndex) |
|
441
|
|
|
return ns_list |
|
442
|
|
|
|
|
443
|
|
|
# incase other testss created nodes in unregistered namespace |
|
444
|
|
|
_idx_d = await server.register_namespace('dummy1') |
|
445
|
|
|
_idx_d = await server.register_namespace('dummy2') |
|
446
|
|
|
_idx_d = await server.register_namespace('dummy3') |
|
447
|
|
|
# create the test namespaces and vars |
|
448
|
|
|
idx_a = await server.register_namespace('a') |
|
449
|
|
|
idx_b = await server.register_namespace('b') |
|
450
|
|
|
idx_c = await server.register_namespace('c') |
|
451
|
|
|
o = server.get_objects_node() |
|
452
|
|
|
_myvar2 = await o.add_variable(idx_a, "MyBoolVar2", True) |
|
453
|
|
|
_myvar3 = await o.add_variable(idx_b, "MyBoolVar3", True) |
|
454
|
|
|
_myvar4 = await o.add_variable(idx_c, "MyBoolVar4", True) |
|
455
|
|
|
# the tests |
|
456
|
|
|
nodes = await ua_utils.get_nodes_of_namespace(server, namespaces=[idx_a, idx_b, idx_c]) |
|
457
|
|
|
assert 3 == len(nodes) |
|
458
|
|
|
assert set([idx_a, idx_b, idx_c]) == get_ns_of_nodes(nodes) |
|
459
|
|
|
|
|
460
|
|
|
nodes = await ua_utils.get_nodes_of_namespace(server, namespaces=[idx_a]) |
|
461
|
|
|
assert 1 == len(nodes) |
|
462
|
|
|
assert set([idx_a]) == get_ns_of_nodes(nodes) |
|
463
|
|
|
|
|
464
|
|
|
nodes = await ua_utils.get_nodes_of_namespace(server, namespaces=[idx_b]) |
|
465
|
|
|
assert 1 == len(nodes) |
|
466
|
|
|
assert set([idx_b]) == get_ns_of_nodes(nodes) |
|
467
|
|
|
|
|
468
|
|
|
nodes = await ua_utils.get_nodes_of_namespace(server, namespaces=['a']) |
|
469
|
|
|
assert 1 == len(nodes) |
|
470
|
|
|
assert set([idx_a]) == get_ns_of_nodes(nodes) |
|
471
|
|
|
|
|
472
|
|
|
nodes = await ua_utils.get_nodes_of_namespace(server, namespaces=['a', 'c']) |
|
473
|
|
|
assert 2 == len(nodes) |
|
474
|
|
|
assert set([idx_a, idx_c]) == get_ns_of_nodes(nodes) |
|
475
|
|
|
|
|
476
|
|
|
nodes = await ua_utils.get_nodes_of_namespace(server, namespaces='b') |
|
477
|
|
|
assert 1 == len(nodes) |
|
478
|
|
|
assert set([idx_b]) == get_ns_of_nodes(nodes) |
|
479
|
|
|
|
|
480
|
|
|
nodes = await ua_utils.get_nodes_of_namespace(server, namespaces=idx_b) |
|
481
|
|
|
assert 1 == len(nodes) |
|
482
|
|
|
assert set([idx_b]) == get_ns_of_nodes(nodes) |
|
483
|
|
|
with pytest.raises(ValueError): |
|
484
|
|
|
await ua_utils.get_nodes_of_namespace(server, namespaces='non_existing_ns') |
|
485
|
|
|
|
|
486
|
|
|
|
|
487
|
|
|
async def test_load_enum_strings(server): |
|
488
|
|
|
dt = await server.nodes.enum_data_type.add_data_type(0, "MyStringEnum") |
|
489
|
|
|
await dt.add_variable(0, "EnumStrings", [ua.LocalizedText("e1"), ua.LocalizedText("e2"), ua.LocalizedText("e3"), |
|
490
|
|
|
ua.LocalizedText("e 4")]) |
|
491
|
|
|
await server.load_enums() |
|
492
|
|
|
e = getattr(ua, "MyStringEnum") |
|
493
|
|
|
assert isinstance(e, EnumMeta) |
|
494
|
|
|
assert hasattr(e, "e1") |
|
495
|
|
|
assert hasattr(e, "e4") |
|
496
|
|
|
assert 3 == getattr(e, "e4") |
|
497
|
|
|
|
|
498
|
|
|
|
|
499
|
|
|
async def test_load_enum_values(server): |
|
500
|
|
|
dt = await server.nodes.enum_data_type.add_data_type(0, "MyValuesEnum") |
|
501
|
|
|
v1 = ua.EnumValueType() |
|
502
|
|
|
v1.DisplayName.Text = "v1" |
|
503
|
|
|
v1.Value = 2 |
|
504
|
|
|
v2 = ua.EnumValueType() |
|
505
|
|
|
v2.DisplayName.Text = "v2" |
|
506
|
|
|
v2.Value = 3 |
|
507
|
|
|
v3 = ua.EnumValueType() |
|
508
|
|
|
v3.DisplayName.Text = "v 3 " |
|
509
|
|
|
v3.Value = 4 |
|
510
|
|
|
await dt.add_variable(0, "EnumValues", [v1, v2, v3]) |
|
511
|
|
|
await server.load_enums() |
|
512
|
|
|
e = getattr(ua, "MyValuesEnum") |
|
513
|
|
|
assert isinstance(e, EnumMeta) |
|
514
|
|
|
assert hasattr(e, "v1") |
|
515
|
|
|
assert hasattr(e, "v3") |
|
516
|
|
|
assert 4 == getattr(e, "v3") |
|
517
|
|
|
|
|
518
|
|
|
|
|
519
|
|
|
async def check_eventgenerator_source_server(evgen, server: Server): |
|
520
|
|
|
server_node = server.get_server_node() |
|
521
|
|
|
assert evgen.event.SourceName == (await server_node.get_browse_name()).Name |
|
522
|
|
|
assert evgen.event.SourceNode == ua.NodeId(ua.ObjectIds.Server) |
|
523
|
|
|
assert await server_node.get_event_notifier() == {ua.EventNotifier.SubscribeToEvents} |
|
524
|
|
|
refs = await server_node.get_referenced_nodes(ua.ObjectIds.GeneratesEvent, ua.BrowseDirection.Forward, |
|
525
|
|
|
ua.NodeClass.ObjectType, False) |
|
526
|
|
|
assert len(refs) >= 1 |
|
527
|
|
|
|
|
528
|
|
|
|
|
529
|
|
|
async def check_event_generator_object(evgen, obj, emitting_node=None): |
|
530
|
|
|
assert evgen.event.SourceName == (await obj.get_browse_name()).Name |
|
531
|
|
|
assert evgen.event.SourceNode == obj.nodeid |
|
532
|
|
|
|
|
533
|
|
|
if not emitting_node: |
|
534
|
|
|
assert await obj.get_event_notifier() == {ua.EventNotifier.SubscribeToEvents} |
|
535
|
|
|
refs = await obj.get_referenced_nodes(ua.ObjectIds.GeneratesEvent, ua.BrowseDirection.Forward, ua.NodeClass.ObjectType, False) |
|
536
|
|
|
else: |
|
537
|
|
|
assert await emitting_node.get_event_notifier() == {ua.EventNotifier.SubscribeToEvents} |
|
538
|
|
|
refs = await emitting_node.get_referenced_nodes(ua.ObjectIds.GeneratesEvent, ua.BrowseDirection.Forward, ua.NodeClass.ObjectType, False) |
|
539
|
|
|
|
|
540
|
|
|
assert evgen.event.EventType in [x.nodeid for x in refs] |
|
541
|
|
|
|
|
542
|
|
|
|
|
543
|
|
|
async def check_eventgenerator_base_event(evgen, server: Server): |
|
544
|
|
|
# we did not receive event generator |
|
545
|
|
|
assert evgen is not None |
|
546
|
|
|
assert evgen.isession is server.iserver.isession |
|
547
|
|
|
check_base_event(evgen.event) |
|
548
|
|
|
|
|
549
|
|
|
|
|
550
|
|
|
def check_base_event(ev): |
|
551
|
|
|
# we did not receive event |
|
552
|
|
|
assert ev is not None |
|
553
|
|
|
assert isinstance(ev, BaseEvent) |
|
554
|
|
|
assert ev.EventType == ua.NodeId(ua.ObjectIds.BaseEventType) |
|
555
|
|
|
assert ev.Severity == 1 |
|
556
|
|
|
|
|
557
|
|
|
|
|
558
|
|
|
def check_eventgenerator_custom_event(evgen, etype, server: Server): |
|
559
|
|
|
# we did not receive event generator |
|
560
|
|
|
assert evgen is not None |
|
561
|
|
|
assert evgen.isession is server.iserver.isession |
|
562
|
|
|
check_custom_event(evgen.event, etype) |
|
563
|
|
|
|
|
564
|
|
|
|
|
565
|
|
|
def check_custom_event(ev, etype): |
|
566
|
|
|
# we did not receive event |
|
567
|
|
|
assert ev is not None |
|
568
|
|
|
assert isinstance(ev, BaseEvent) |
|
569
|
|
|
assert ev.EventType == etype.nodeid |
|
570
|
|
|
assert ev.Severity == 1 |
|
571
|
|
|
|
|
572
|
|
|
|
|
573
|
|
|
async def check_custom_type(type, base_type, server: Server): |
|
574
|
|
|
base = asyncua.Node(server.iserver.isession, ua.NodeId(base_type)) |
|
575
|
|
|
assert type in await base.get_children() |
|
576
|
|
|
nodes = await type.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse, |
|
577
|
|
|
includesubtypes=True) |
|
578
|
|
|
assert base == nodes[0] |
|
579
|
|
|
properties = await type.get_properties() |
|
580
|
|
|
assert properties is not None |
|
581
|
|
|
assert len(properties) == 2 |
|
582
|
|
|
assert await type.get_child("2:PropertyNum") in properties |
|
583
|
|
|
assert (await(await type.get_child("2:PropertyNum")).get_data_value()).Value.VariantType == ua.VariantType.Int32 |
|
584
|
|
|
assert await type.get_child("2:PropertyString") in properties |
|
585
|
|
|
assert (await(await type.get_child("2:PropertyString")).get_data_value()).Value.VariantType == ua.VariantType.String |
|
586
|
|
|
|
|
587
|
|
|
|
|
588
|
|
|
""" |
|
589
|
|
|
class TestServerCaching(unittest.TestCase): |
|
590
|
|
|
def runTest(self): |
|
591
|
|
|
return # FIXME broken |
|
592
|
|
|
tmpfile = NamedTemporaryFile() |
|
593
|
|
|
path = tmpfile.name |
|
594
|
|
|
tmpfile.close() |
|
595
|
|
|
|
|
596
|
|
|
# create cache file |
|
597
|
|
|
server = Server(shelffile=path) |
|
598
|
|
|
|
|
599
|
|
|
# modify cache content |
|
600
|
|
|
id = ua.NodeId(ua.ObjectIds.Server_ServerStatus_SecondsTillShutdown) |
|
601
|
|
|
s = shelve.open(path, "w", writeback=True) |
|
602
|
|
|
s[id.to_string()].attributes[ua.AttributeIds.Value].value = ua.DataValue(123) |
|
603
|
|
|
s.close() |
|
604
|
|
|
|
|
605
|
|
|
# ensure that we are actually loading from the cache |
|
606
|
|
|
server = Server(shelffile=path) |
|
607
|
|
|
assert server.get_node(id).get_value(), 123) |
|
608
|
|
|
|
|
609
|
|
|
os.remove(path) |
|
610
|
|
|
|
|
611
|
|
|
class TestServerStartError(unittest.TestCase): |
|
612
|
|
|
|
|
613
|
|
|
def test_port_in_use(self): |
|
614
|
|
|
|
|
615
|
|
|
server1 = Server() |
|
616
|
|
|
server1.set_endpoint('opc.tcp://127.0.0.1:{0:d}'.format(port_num + 1)) |
|
617
|
|
|
server1.start() |
|
618
|
|
|
|
|
619
|
|
|
server2 = Server() |
|
620
|
|
|
server2.set_endpoint('opc.tcp://127.0.0.1:{0:d}'.format(port_num + 1)) |
|
621
|
|
|
try: |
|
622
|
|
|
server2.start() |
|
623
|
|
|
except Exception: |
|
624
|
|
|
pass |
|
625
|
|
|
|
|
626
|
|
|
server1.stop() |
|
627
|
|
|
server2.stop() |
|
628
|
|
|
""" |
|
629
|
|
|
|