Completed
Pull Request — master (#24)
by Olivier
02:42
created

tests.test_xml   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 394
Duplicated Lines 6.09 %

Importance

Changes 0
Metric Value
eloc 276
dl 24
loc 394
rs 9.84
c 0
b 0
f 0
wmc 32

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
import os
2
import uuid
3
import pytz
4
import pytest
5
import logging
6
import datetime
7
8
import pytest
9
10
from asyncua import ua, Node, uamethod
11
from asyncua.ua import uaerrors
12
13
logger = logging.getLogger("asyncua.common.xmlimporter")
14
logger.setLevel(logging.DEBUG)
15
logger = logging.getLogger("asyncua.common.xmlparser")
16
logger.setLevel(logging.DEBUG)
17
18
pytestmark = pytest.mark.asyncio
19
20
CUSTOM_NODES_XML_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "custom_nodes.xml"))
21
CUSTOM_NODES_NS_XML_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "custom_nodesns.xml"))
22
23
24
@uamethod
25
def func(parent, value, string):
26
    return value * 2
27
28
29
async def test_xml_import(opc):
30
    await opc.opc.import_xml(CUSTOM_NODES_XML_PATH)
31
    o = opc.opc.get_objects_node()
32
    v = await o.get_child(["1:MyXMLFolder", "1:MyXMLObject", "1:MyXMLVariable"])
33
    val = await v.get_value()
34
    assert "StringValue" == val
35
    node_path = ["Types", "DataTypes", "BaseDataType", "Enumeration", "1:MyEnum", "0:EnumStrings"]
36
    o = await opc.opc.get_root_node().get_child(node_path)
37
    assert 3 == len(await o.get_value())
38
    # Check if method is imported
39
    node_path = ["Types", "ObjectTypes", "BaseObjectType", "1:MyObjectType", "1:MyMethod"]
40
    o = await opc.opc.get_root_node().get_child(node_path)
41
    assert 4 == len(await o.get_referenced_nodes())
42
    # Check if InputArgs are imported and can be read
43
    node_path = ["Types", "ObjectTypes", "BaseObjectType", "1:MyObjectType", "1:MyMethod", "InputArguments"]
44
    o = await opc.opc.get_root_node().get_child(node_path)
45
    input_arg = (await o.get_data_value()).Value.Value[0]
46
    assert "Context" == input_arg.Name
47
48
49
async def test_xml_import_additional_ns(opc):
50
    # if not already shift the new namespaces
51
    await opc.server.register_namespace("http://placeholder.toincrease.nsindex")
52
    # "tests/custom_nodes.xml" isn't created with namespaces in mind, provide new test file
53
    # the ns=1 in to file now should be mapped to ns=2
54
    await opc.opc.import_xml(CUSTOM_NODES_NS_XML_PATH)
55
    ns = await opc.opc.get_namespace_index("http://examples.freeopcua.github.io/")
56
    o = opc.opc.get_objects_node()
57
    o2 = await o.get_child([f"{ns}:MyBaseObject"])
58
    assert o2 is not None
59
    v1 = await o.get_child([f"{ns}:MyBaseObject", f"{ns}:MyVar"])
60
    assert v1 is not None
61
    r1 = (await o2.get_references(refs=ua.ObjectIds.HasComponent))[0]
62
    assert ns == r1.NodeId.NamespaceIndex
63
    r3 = (await v1.get_references(refs=ua.ObjectIds.HasComponent))[0]
64
    assert ns == r3.NodeId.NamespaceIndex
65
66
67
@pytest.mark.skip("FIXME")
68
async def test_xml_method(opc, tmpdir):
69
    await opc.opc.register_namespace("foo")
70
    await opc.opc.register_namespace("bar")
71
    o = await opc.opc.nodes.objects.add_object(2, "xmlexportmethod")
72
    m = await o.add_method(2, "callme", func, [ua.VariantType.Double, ua.VariantType.String], [ua.VariantType.Float])
73
    # set an arg dimension to a list to test list export
74
    inputs = await m.get_child("InputArguments")
75
    val = await inputs.get_value()
76
    val[0].ArrayDimensions = [2, 2]
77
    desc = "My nce description"
78
    val[0].Description = ua.LocalizedText(desc)
79
    await inputs.set_value(val)
80
    # get all nodes and export
81
    nodes = [o, m]
82
    nodes.extend(await m.get_children())
83
    tmp_path = tmpdir.join("tmp_test_export.xml").strpath
84
    await opc.opc.export_xml(nodes, tmp_path)
85
    await opc.opc.delete_nodes(nodes)
86
    await opc.opc.import_xml(tmp_path)
87
    # now see if our nodes are here
88
    val = await inputs.get_value()
89
    assert 2 == len(val)
90
    assert [2, 2] == val[0].ArrayDimensions
91
    assert desc == val[0].Description.Text
92
93
94
async def test_xml_vars(opc, tmpdir):
95
    tmp_path = tmpdir.join("tmp_test_export-vars.xml").strpath
96
    await opc.opc.register_namespace("foo")
97
    await opc.opc.register_namespace("bar")
98
    o = await opc.opc.nodes.objects.add_object(2, "xmlexportobj")
99
    v = await o.add_variable(3, "myxmlvar", 6.78, ua.VariantType.Double)
100
    a = await o.add_variable(3, "myxmlvar-array", [6, 1], ua.VariantType.UInt16)
101
    a2 = await o.add_variable(3, "myxmlvar-2dim", [[1, 2], [3, 4]], ua.VariantType.UInt32)
102
    a3 = await o.add_variable(3, "myxmlvar-2dim", [[]], ua.VariantType.ByteString)
103
    nodes = [o, v, a, a2, a3]
104
    await opc.opc.export_xml(nodes, tmp_path)
105
    await opc.opc.delete_nodes(nodes)
106
    await opc.opc.import_xml(tmp_path)
107
    assert 6.78 == await v.get_value()
108
    assert ua.NodeId(ua.ObjectIds.Double) == await v.get_data_type()
109
    assert ua.NodeId(ua.ObjectIds.UInt16) == await a.get_data_type()
110
    assert await a.get_value_rank() in (0, 1)
111
    assert [6, 1] == await a.get_value()
112
    assert [[1, 2], [3, 4]] == await a2.get_value()
113
    assert ua.NodeId(ua.ObjectIds.UInt32) == await a2.get_data_type()
114
    assert await a2.get_value_rank() in (0, 2)
115
    assert [2, 2] == (await a2.get_attribute(ua.AttributeIds.ArrayDimensions)).Value.Value
116
    # assert a3.get_value(), [[]])  # would require special code ...
117
    assert ua.NodeId(ua.ObjectIds.ByteString) == await a3.get_data_type()
118
    assert await a3.get_value_rank() in (0, 2)
119
    assert [1, 0] == (await a3.get_attribute(ua.AttributeIds.ArrayDimensions)).Value.Value
120
121
122
async def test_xml_ns(opc, tmpdir):
123
    """
124
    This test is far too complicated but catches a lot of things...
125
    """
126
    ns_array = await opc.opc.get_namespace_array()
127
    if len(ns_array) < 3:
128
        await opc.opc.register_namespace("dummy_ns")
129
    ref_ns = await opc.opc.register_namespace("ref_namespace")
130
    new_ns = await opc.opc.register_namespace("my_new_namespace")
131
    bname_ns = await opc.opc.register_namespace("bname_namespace")
132
    o = await opc.opc.nodes.objects.add_object(0, "xmlns0")
133
    o50 = await opc.opc.nodes.objects.add_object(50, "xmlns20")
134
    o200 = await opc.opc.nodes.objects.add_object(200, "xmlns200")
135
    onew = await opc.opc.nodes.objects.add_object(new_ns, "xmlns_new")
136
    vnew = await onew.add_variable(new_ns, "xmlns_new_var", 9.99)
137
    o_no_export = await opc.opc.nodes.objects.add_object(ref_ns, "xmlns_parent")
138
    v_no_parent = await o_no_export.add_variable(new_ns, "xmlns_new_var_no_parent", 9.99)
139
    o_bname = await onew.add_object("ns={0};i=4000".format(new_ns), "{0}:BNAME".format(bname_ns))
140
    nodes = [o, o50, o200, onew, vnew, v_no_parent, o_bname]
141
    tmp_path = tmpdir.join("tmp_test_export-ns.xml").strpath
142
    await opc.opc.export_xml(nodes, tmp_path)
143
    # delete node and change index og new_ns before re-importing
144
    await opc.opc.delete_nodes(nodes)
145
    ns_node = opc.opc.get_node(ua.NodeId(ua.ObjectIds.Server_NamespaceArray))
146
    nss = await ns_node.get_value()
147
    nss.remove("my_new_namespace")
148
    # nss.remove("ref_namespace")
149
    nss.remove("bname_namespace")
150
    await ns_node.set_value(nss)
151
    new_ns = await opc.opc.register_namespace("my_new_namespace_offsett")
152
    new_ns = await opc.opc.register_namespace("my_new_namespace")
153
    new_nodes = await opc.opc.import_xml(tmp_path)
154
    for i in [o, o50, o200]:
155
        await i.get_browse_name()
156
    with pytest.raises(uaerrors.BadNodeIdUnknown):
157
        await onew.get_browse_name()
158
    # since my_new_namesspace2 is referenced byt a node it should have been reimported
159
    nss = await opc.opc.get_namespace_array()
160
    assert "bname_namespace" in nss
161
    # get index of namespaces after import
162
    new_ns = await opc.opc.register_namespace("my_new_namespace")
163
    bname_ns = await opc.opc.register_namespace("bname_namespace")
164
    onew.nodeid.NamespaceIndex = new_ns
165
    await onew.get_browse_name()
166
    vnew2 = (await onew.get_children())[0]
167
    assert vnew2.nodeid.NamespaceIndex == new_ns
168
169
170
async def test_xml_float(opc, tmpdir):
171
    o = await opc.opc.nodes.objects.add_variable(2, "xmlfloat", 5.67)
172
    dtype = await o.get_data_type()
173
    dv = await o.get_data_value()
174
    tmp_path = tmpdir.join("tmp_test_export-float.xml").strpath
175
    await opc.opc.export_xml([o], tmp_path)
176
    await opc.opc.delete_nodes([o])
177
    new_nodes = await opc.opc.import_xml(tmp_path)
178
    o2 = opc.opc.get_node(new_nodes[0])
179
    assert o2 == o
180
    assert await o2.get_data_type() == dtype
181
    assert (await o2.get_data_value()).Value == dv.Value
182
183
184
async def test_xml_bool(opc, tmpdir):
185
    o = await opc.opc.nodes.objects.add_variable(2, "xmlbool", True)
186
    await _test_xml_var_type(opc, tmpdir, o, "bool")
187
188
189
async def test_xml_string(opc, tmpdir):
190
    o = await opc.opc.nodes.objects.add_variable(2, "xmlstring", "mystring")
191
    await _test_xml_var_type(opc, tmpdir, o, "string")
192
193
194
async def test_xml_string_array(opc, tmpdir):
195
    o = await opc.opc.nodes.objects.add_variable(2, "xmlstringarray", ["mystring2", "mystring3"])
196
    node2 = await _test_xml_var_type(opc, tmpdir, o, "stringarray")
197
    dv = await node2.get_data_value()
198
199
200
async def test_xml_guid(opc, tmpdir):
201
    o = await opc.opc.nodes.objects.add_variable(2, "xmlguid", uuid.uuid4())
202
    await _test_xml_var_type(opc, tmpdir, o, "guid")
203
204
205
async def test_xml_guid_array(opc, tmpdir):
206
    o = await opc.opc.nodes.objects.add_variable(2, "xmlguid", [uuid.uuid4(), uuid.uuid4()])
207
    await _test_xml_var_type(opc, tmpdir, o, "guid_array")
208
209
210
async def test_xml_datetime(opc, tmpdir):
211
    o = await opc.opc.nodes.objects.add_variable(3, "myxmlvar-dt", datetime.datetime.utcnow(), ua.VariantType.DateTime)
212
    await _test_xml_var_type(opc, tmpdir, o, "datetime")
213
214
215
async def test_xml_datetime_array(opc, tmpdir):
216
    o = await opc.opc.nodes.objects.add_variable(3, "myxmlvar-array", [
217
        datetime.datetime.now(),
218
        datetime.datetime.utcnow(),
219
        datetime.datetime.now(pytz.timezone("Asia/Tokyo"))
220
    ], ua.VariantType.DateTime)
221
    await _test_xml_var_type(opc, tmpdir, o, "datetime_array")
222
223
224
# async def test_xml_qualifiedname(opc):
225
#    o = opc.opc.nodes.objects.add_variable(2, "xmlltext", ua.QualifiedName("mytext", 5))
226
#    await _test_xml_var_type(o, "qualified_name")
227
228
# async def test_xml_qualifiedname_array(opc):
229
#    o = opc.opc.nodes.objects.add_variable(2, "xmlltext_array", [ua.QualifiedName("erert", 5), ua.QualifiedName("erert33", 6)])
230
#    await _test_xml_var_type(o, "qualified_name_array")
231
232
async def test_xml_bytestring(opc, tmpdir):
233
    o = await opc.opc.nodes.objects.add_variable(2, "xmlltext", "mytext".encode("utf8"), ua.VariantType.ByteString)
234
    await _test_xml_var_type(opc, tmpdir, o, "bytestring")
235
236
237
async def test_xml_bytestring_array(opc, tmpdir):
238
    o = await opc.opc.nodes.objects.add_variable(2, "xmlltext_array",
239
        ["mytext".encode("utf8"), "errsadf".encode("utf8")], ua.VariantType.ByteString)
240
    await _test_xml_var_type(opc, tmpdir, o, "bytestring_array")
241
242
243
async def test_xml_localizedtext(opc, tmpdir):
244
    o = await opc.opc.nodes.objects.add_variable(2, "xmlltext", ua.LocalizedText("mytext"))
245
    await _test_xml_var_type(opc, tmpdir, o, "localized_text")
246
247
248
async def test_xml_localizedtext_array(opc, tmpdir):
249
    o = await opc.opc.nodes.objects.add_variable(2, "xmlltext_array",
250
        [ua.LocalizedText("erert"), ua.LocalizedText("erert33")])
251
    await _test_xml_var_type(opc, tmpdir, o, "localized_text_array")
252
253
254
async def test_xml_nodeid(opc, tmpdir):
255
    o = await opc.opc.nodes.objects.add_variable(2, "xmlnodeid", ua.NodeId("mytext", 1))
256
    await _test_xml_var_type(opc, tmpdir, o, "nodeid")
257
258
259
async def test_xml_ext_obj(opc, tmpdir):
260
    arg = ua.Argument()
261
    arg.DataType = ua.NodeId(ua.ObjectIds.Float)
262
    arg.Description = ua.LocalizedText("Nice description")
263
    arg.ArrayDimensions = [1, 2, 3]
264
    arg.Name = "MyArg"
265
    node = await opc.opc.nodes.objects.add_variable(2, "xmlexportobj2", arg)
266
    node2 = await _test_xml_var_type(opc, tmpdir, node, "ext_obj", test_equality=False)
267
    arg2 = await node2.get_value()
268
    assert arg.Name == arg2.Name
269
    assert arg.ArrayDimensions == arg2.ArrayDimensions
270
    assert arg.Description == arg2.Description
271
    assert arg.DataType == arg2.DataType
272
273
274
async def test_xml_ext_obj_array(opc, tmpdir):
275
    arg = ua.Argument()
276
    arg.DataType = ua.NodeId(ua.ObjectIds.Float)
277
    arg.Description = ua.LocalizedText("Nice description")
278
    arg.ArrayDimensions = [1, 2, 3]
279
    arg.Name = "MyArg"
280
    arg2 = ua.Argument()
281
    arg2.DataType = ua.NodeId(ua.ObjectIds.Int32)
282
    arg2.Description = ua.LocalizedText("Nice description2")
283
    arg2.ArrayDimensions = [4, 5, 6]
284
    arg2.Name = "MyArg2"
285
    args = [arg, arg2]
286
    node = await opc.opc.nodes.objects.add_variable(2, "xmlexportobj2", args)
287
    node2 = await _test_xml_var_type(opc, tmpdir, node, "ext_obj_array", test_equality=False)
288
    read_args = await node2.get_value()
289
    for i, arg in enumerate(read_args):
290
        assert args[i].Name == read_args[i].Name
291
        assert args[i].ArrayDimensions == read_args[i].ArrayDimensions
292
        assert args[i].Description == read_args[i].Description
293
        assert args[i].DataType == read_args[i].DataType
294
295
296
async def test_xml_enum(opc, tmpdir):
297
    o = await opc.opc.nodes.objects.add_variable(2, "xmlenum", 0, varianttype=ua.VariantType.Int32,
298
        datatype=ua.ObjectIds.ApplicationType)
299
    await _test_xml_var_type(opc, tmpdir, o, "enum")
300
301
302
async def test_xml_enumvalues(opc, tmpdir):
303
    o = await opc.opc.nodes.objects.add_variable(2, "xmlenumvalues", 0, varianttype=ua.VariantType.UInt32,
304
        datatype=ua.ObjectIds.AttributeWriteMask)
305
    await _test_xml_var_type(opc, tmpdir, o, "enumvalues")
306
307
308
async def test_xml_custom_uint32(opc, tmpdir):
309
    # t = opc.opc.nodes. create_custom_data_type(2, 'MyCustomUint32', ua.ObjectIds.UInt32)
310
    t = await opc.opc.get_node(ua.ObjectIds.UInt32).add_data_type(2, 'MyCustomUint32')
311
    o = await opc.opc.nodes.objects.add_variable(2, "xmlcustomunit32", 0, varianttype=ua.VariantType.UInt32,
312
        datatype=t.nodeid)
313
    await _test_xml_var_type(opc, tmpdir, o, "cuint32")
314
315
316
async def test_xml_var_nillable(opc):
317
    xml = """
318
    <UANodeSet xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd" xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
319
      <NamespaceUris>    
320
      </NamespaceUris>
321
      <Aliases>
322
        <Alias Alias="Boolean">i=1</Alias>
323
        <Alias Alias="String">i=12</Alias>
324
        <Alias Alias="HasTypeDefinition">i=40</Alias>
325
        <Alias Alias="HasComponent">i=47</Alias>
326
      </Aliases>
327
      <UAVariable BrowseName="2:xmlstring" DataType="String" NodeId="ns=2;s=test_xml.string.nillabel" ParentNodeId="i=85">
328
        <DisplayName>xmlstring</DisplayName>
329
        <Description>xmlstring</Description>
330
        <References>
331
          <Reference IsForward="false" ReferenceType="HasComponent">i=85</Reference>
332
          <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
333
        </References>
334
        <Value>
335
            <uax:String></uax:String>
336
        </Value>    
337
      </UAVariable>
338
      
339
     <UAVariable BrowseName="2:xmlbool" DataType="Boolean" NodeId="ns=2;s=test_xml.bool.nillabel" ParentNodeId="i=85">
340
        <DisplayName>xmlbool</DisplayName>
341
        <Description>xmlbool</Description>
342
        <References>
343
          <Reference IsForward="false" ReferenceType="HasComponent">i=85</Reference>
344
          <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
345
        </References>
346
        <Value>
347
          <uax:Boolean></uax:Boolean>
348
        </Value>
349
      </UAVariable>  
350
      
351
    </UANodeSet>
352
    """
353
    _new_nodes = await opc.opc.import_xml(xmlstring=xml)
354
    var_string = opc.opc.get_node(ua.NodeId('test_xml.string.nillabel', 2))
355
    var_bool = opc.opc.get_node(ua.NodeId('test_xml.bool.nillabel', 2))
356
    assert await var_string.get_value() is None
357
    assert await var_bool.get_value() is None
358
359
360
async def _test_xml_var_type(opc, tmpdir, node: Node, typename: str, test_equality: bool = True):
361
    dtype = await node.get_data_type()
362
    dv = await node.get_data_value()
363
    rank = await node.get_value_rank()
364
    dim = await node.get_array_dimensions()
365
    nclass = await node.get_node_class()
366
    tmp_path = tmpdir.join(f"tmp_test_export-{typename}.xml").strpath
367
    await opc.opc.export_xml([node], tmp_path)
368
    await opc.opc.delete_nodes([node])
369
    new_nodes = await opc.opc.import_xml(tmp_path)
370
    node2 = opc.opc.get_node(new_nodes[0])
371
    assert node == node
372
    assert dtype == await node2.get_data_type()
373
    if test_equality:
374
        print("DEBUG", node, dv, node2, await node2.get_value())
375
        assert dv.Value == (await node2.get_data_value()).Value
376
    assert rank == await node2.get_value_rank()
377
    assert dim == await node2.get_array_dimensions()
378
    assert nclass == await node2.get_node_class()
379
    return node2
380
381
382
async def test_xml_byte(opc, tmpdir):
383
    o = await opc.opc.nodes.objects.add_variable(2, "byte", 255, ua.VariantType.Byte)
384
    dtype = await o.get_data_type()
385
    dv = await o.get_data_value()
386
    tmp_path = tmpdir.join("export-byte.xml").strpath
387
    await opc.opc.export_xml([o], tmp_path)
388
    await opc.opc.delete_nodes([o])
389
    new_nodes = await opc.opc.import_xml(tmp_path)
390
    o2 = opc.opc.get_node(new_nodes[0])
391
    assert o == o2
392
    assert dtype == await o2.get_data_type()
393
    assert dv.Value == (await o2.get_data_value()).Value
394