Skip to main content

opcua_server/address_space/
mod.rs

1//! Implementation of [AddressSpace], and in-memory OPC-UA address space.
2
3mod utils;
4
5pub use opcua_nodes::*;
6pub use utils::*;
7
8#[cfg(feature = "generated-address-space")]
9pub use opcua_core_namespace::CoreNamespace;
10
11use std::collections::VecDeque;
12
13use hashbrown::{HashMap, HashSet};
14use tracing::{debug, error, info, warn};
15
16use crate::node_manager::{ParsedReadValueId, ParsedWriteValue, RequestContext};
17use opcua_types::{
18    node_id::IntoNodeIdRef, BrowseDirection, DataValue, LocalizedText, NodeClass, NodeId,
19    QualifiedName, ReferenceTypeId, StatusCode, TimestampsToReturn,
20};
21
22/// Represents an in-memory address space.
23#[derive(Default)]
24pub struct AddressSpace {
25    node_map: HashMap<NodeId, NodeType>,
26    namespaces: HashMap<u16, String>,
27    references: References,
28}
29
30impl AddressSpace {
31    /// Create a new empty address space.
32    pub fn new() -> Self {
33        Self {
34            node_map: HashMap::new(),
35            namespaces: HashMap::new(),
36            references: References::new(),
37        }
38    }
39
40    /// Import a node set into this address space.
41    /// This will register namespaces from the node set import.
42    pub fn import_node_set<T: NodeSetImport + ?Sized>(
43        &mut self,
44        import: &T,
45        namespaces: &mut NamespaceMap,
46    ) {
47        let mut map = NodeSetNamespaceMapper::new(namespaces);
48        import.register_namespaces(&mut map);
49        let owned_namespaces = import.get_own_namespaces();
50        for ns in owned_namespaces {
51            let idx = map
52                .namespaces()
53                .known_namespaces()
54                .get(&ns)
55                .expect("Node import returned owned namespace not added to the namespace map");
56            self.add_namespace(&ns, *idx);
57        }
58        let mut count = 0;
59        for item in import.load(&map) {
60            count += 1;
61            self.import_node(item);
62        }
63        info!("Imported {count} nodes");
64    }
65
66    /// Load types from this address space into the given type tree.
67    pub fn load_into_type_tree(&self, type_tree: &mut DefaultTypeTree) {
68        let mut found_ids = VecDeque::new();
69        // Populate types first so that we have reference types to browse in the next stage.
70        for node in self.node_map.values() {
71            let nc = node.node_class();
72            if !matches!(
73                nc,
74                NodeClass::DataType
75                    | NodeClass::ObjectType
76                    | NodeClass::VariableType
77                    | NodeClass::ReferenceType
78            ) {
79                continue;
80            }
81
82            let node_id = node.node_id();
83
84            let parent = self
85                .references
86                .find_references(
87                    node_id,
88                    Some((ReferenceTypeId::HasSubtype, false)),
89                    type_tree,
90                    BrowseDirection::Inverse,
91                )
92                .next();
93
94            // If a node somehow lacks a super-type, insert it as a child of the relevant base type.
95            let parent_id = if let Some(parent) = parent {
96                parent.target_node.clone()
97            } else {
98                continue;
99            };
100
101            type_tree.add_type_node(node_id, &parent_id, nc);
102            found_ids.push_back((node_id, node_id, Vec::new(), nc));
103        }
104
105        let mut seen_nodes = HashSet::new();
106
107        // Recursively browse each discovered type for non-type children
108        while let Some((node, root_type, path, node_class)) = found_ids.pop_front() {
109            for child in self.find_references(
110                node,
111                Some((ReferenceTypeId::HierarchicalReferences, true)),
112                type_tree,
113                BrowseDirection::Forward,
114            ) {
115                if child
116                    .reference_type
117                    .as_reference_type_id()
118                    .is_ok_and(|r| r == ReferenceTypeId::HasSubtype)
119                {
120                    continue;
121                }
122                let Some(node_type) = self.node_map.get(child.target_node) else {
123                    continue;
124                };
125
126                let nc = node_type.node_class();
127
128                if matches!(
129                    nc,
130                    NodeClass::DataType
131                        | NodeClass::ObjectType
132                        | NodeClass::VariableType
133                        | NodeClass::ReferenceType
134                ) {
135                    continue;
136                }
137                let mut path = path.clone();
138                path.push(node_type.as_node().browse_name());
139
140                if !seen_nodes.insert(child.target_node) {
141                    warn!(
142                        "Found node {} more than once when browsing hierarchically",
143                        child.target_node
144                    );
145                    continue;
146                }
147
148                found_ids.push_back((child.target_node, root_type, path, nc));
149            }
150
151            if !path.is_empty() {
152                type_tree.add_type_property(node, root_type, &path, node_class);
153            }
154        }
155    }
156
157    /// Add a namespace to this address space.
158    pub fn add_namespace(&mut self, namespace: &str, index: u16) {
159        self.namespaces.insert(index, namespace.to_string());
160    }
161
162    /// Insert a node and a list of references from/to that node.
163    pub fn insert<'a, T, S>(
164        &mut self,
165        node: T,
166        references: Option<&'a [(&'a NodeId, &S, ReferenceDirection)]>,
167    ) -> bool
168    where
169        T: Into<NodeType>,
170        S: Into<NodeId> + Clone,
171    {
172        let node_type = node.into();
173        let node_id = node_type.node_id().clone();
174
175        self.assert_namespace(&node_id);
176
177        if self.node_exists(&node_id) {
178            error!("This node {} already exists", node_id);
179            false
180        } else {
181            // If references are supplied, add them now
182            if let Some(references) = references {
183                self.references.insert::<S>(&node_id, references);
184            }
185            self.node_map.insert(node_id, node_type);
186
187            true
188        }
189    }
190
191    /// Import a node from an [ImportedItem].
192    pub fn import_node(&mut self, node: ImportedItem) -> bool {
193        let node_id = node.node.node_id().clone();
194
195        self.assert_namespace(&node_id);
196        if self.node_exists(&node_id) {
197            error!("This node {} already exists", node_id);
198            false
199        } else {
200            self.node_map.insert(node_id.clone(), node.node);
201            for r in node.references {
202                self.references.import_reference(node_id.clone(), r);
203            }
204
205            true
206        }
207    }
208
209    /// Get the namespace index of the given namespace URI.
210    pub fn namespace_index(&self, namespace: &str) -> Option<u16> {
211        self.namespaces
212            .iter()
213            .find(|(_, ns)| namespace == ns.as_str())
214            .map(|(i, _)| *i)
215    }
216
217    fn assert_namespace(&self, node_id: &NodeId) {
218        if !self.namespaces.contains_key(&node_id.namespace) {
219            panic!("Namespace index {} not in address space", node_id.namespace);
220        }
221    }
222
223    /// Return `true` if the node with the given node ID exists in this address space.
224    pub fn node_exists(&self, node_id: &NodeId) -> bool {
225        self.node_map.contains_key(node_id)
226    }
227
228    /// Insert a references from `source_node` to `target_node` with
229    /// the given reference type.
230    pub fn insert_reference(
231        &mut self,
232        source_node: &NodeId,
233        target_node: &NodeId,
234        reference_type: impl Into<NodeId>,
235    ) {
236        self.references
237            .insert_reference(source_node, target_node, reference_type)
238    }
239
240    /// Insert a list of references.
241    pub fn insert_references<'a>(
242        &mut self,
243        references: impl Iterator<Item = (&'a NodeId, &'a NodeId, impl Into<NodeId>)>,
244    ) {
245        self.references.insert_references(references)
246    }
247
248    /// Delete a reference.
249    pub fn delete_reference<'a>(
250        &mut self,
251        source_node: impl IntoNodeIdRef<'a>,
252        target_node: impl IntoNodeIdRef<'a>,
253        reference_type: impl IntoNodeIdRef<'a>,
254    ) -> bool {
255        self.references
256            .delete_reference(source_node, target_node, reference_type)
257    }
258
259    /// Delete references starting at or pointing to the given node.
260    pub fn delete_node_references(
261        &mut self,
262        source_node: &NodeId,
263        delete_target_references: bool,
264    ) -> bool {
265        self.references
266            .delete_node_references(source_node, delete_target_references)
267    }
268
269    /// Check if the reference given by `source_node`, `target_node` and
270    /// `reference_type` exists in the address space.
271    pub fn has_reference<'a>(
272        &self,
273        source_node: impl IntoNodeIdRef<'a>,
274        target_node: impl IntoNodeIdRef<'a>,
275        reference_type: impl IntoNodeIdRef<'a>,
276    ) -> bool {
277        self.references
278            .has_reference(source_node, target_node, reference_type)
279    }
280
281    /// Return a lazy iterator over references starting at `source_node`
282    /// that match `filter`.
283    pub fn find_references<'a: 'b, 'b>(
284        &'a self,
285        source_node: impl IntoNodeIdRef<'b>,
286        filter: Option<(impl Into<NodeId>, bool)>,
287        type_tree: &'b dyn TypeTree,
288        direction: BrowseDirection,
289    ) -> impl Iterator<Item = ReferenceRef<'a>> + 'b {
290        self.references
291            .find_references(source_node, filter, type_tree, direction)
292    }
293
294    /// Find a child of `source_node` matching the given `filter` with
295    /// browse name equal to `browse_name`.
296    pub fn find_node_by_browse_name<'a: 'b, 'b>(
297        &'a self,
298        source_node: impl IntoNodeIdRef<'b>,
299        filter: Option<(impl Into<NodeId>, bool)>,
300        type_tree: &'b dyn TypeTree,
301        direction: BrowseDirection,
302        browse_name: impl Into<QualifiedName>,
303    ) -> Option<&'a NodeType> {
304        let name = browse_name.into();
305        for rf in self.find_references(source_node, filter, type_tree, direction) {
306            let node = self.find_node(rf.target_node);
307            if let Some(node) = node {
308                if node.as_node().browse_name() == &name {
309                    return Some(node);
310                }
311            }
312        }
313        None
314    }
315
316    /// Find a node by traversing a browse path starting from `source_node`.
317    /// All traversed references must match `filter`.
318    pub fn find_node_by_browse_path<'a: 'b, 'b>(
319        &'a self,
320        source_node: impl IntoNodeIdRef<'b>,
321        filter: Option<(impl Into<NodeId>, bool)>,
322        type_tree: &'b dyn TypeTree,
323        direction: BrowseDirection,
324        browse_path: &[QualifiedName],
325    ) -> Option<&'a NodeType> {
326        let mut node = self.find_node(source_node)?;
327        let filter: Option<(NodeId, bool)> = filter.map(|(id, c)| (id.into(), c));
328        for path_elem in browse_path {
329            let mut found = false;
330            for rf in self.find_references(node.node_id(), filter.clone(), type_tree, direction) {
331                let child = self.find_node(rf.target_node);
332                if let Some(child) = child {
333                    if child.as_node().browse_name() == path_elem {
334                        node = child;
335                        found = true;
336                        break;
337                    }
338                }
339            }
340            if !found {
341                return None;
342            }
343        }
344        Some(node)
345    }
346
347    /// Get the inner namespace map.
348    pub fn namespaces(&self) -> &HashMap<u16, String> {
349        &self.namespaces
350    }
351
352    /// Find node by something that can be turned into a node id and return a reference to it.
353    pub fn find<'b>(&self, node_id: impl IntoNodeIdRef<'b>) -> Option<&NodeType> {
354        self.find_node(node_id)
355    }
356
357    /// Find node by something that can be turned into a node id and return a mutable reference to it.
358    pub fn find_mut<'b>(&mut self, node_id: impl IntoNodeIdRef<'b>) -> Option<&mut NodeType> {
359        self.find_node_mut(node_id)
360    }
361
362    /// Finds a node by its node id and returns a reference to it.
363    pub fn find_node<'b>(&self, node_id: impl IntoNodeIdRef<'b>) -> Option<&NodeType> {
364        self.node_map.get(&node_id.into_node_id_ref())
365    }
366
367    /// Finds a node by its node id and returns a mutable reference to it.
368    pub fn find_node_mut<'b>(&mut self, node_id: impl IntoNodeIdRef<'b>) -> Option<&mut NodeType> {
369        self.node_map.get_mut(&node_id.into_node_id_ref())
370    }
371
372    /// Check if the read is allowed.
373    pub fn validate_node_read<'a>(
374        &'a self,
375        context: &RequestContext,
376        node_to_read: &ParsedReadValueId,
377    ) -> Result<&'a NodeType, StatusCode> {
378        let Some(node) = self.find(&node_to_read.node_id) else {
379            debug!(
380                "read_node_value result for read node id {}, attribute {:?} cannot find node",
381                node_to_read.node_id, node_to_read.attribute_id
382            );
383            return Err(StatusCode::BadNodeIdUnknown);
384        };
385
386        validate_node_read(node, context, node_to_read)?;
387
388        Ok(node)
389    }
390
391    /// Invoke the `Read` service on the given node, returning the
392    /// data value. The returned data value can be an error.
393    pub fn read(
394        &self,
395        context: &RequestContext,
396        node_to_read: &ParsedReadValueId,
397        max_age: f64,
398        timestamps_to_return: TimestampsToReturn,
399    ) -> DataValue {
400        let node = match self.validate_node_read(context, node_to_read) {
401            Ok(n) => n,
402            Err(e) => {
403                return DataValue {
404                    status: Some(e),
405                    ..Default::default()
406                };
407            }
408        };
409
410        read_node_value(node, context, node_to_read, max_age, timestamps_to_return)
411    }
412
413    /// Check if the given write is allowed.
414    pub fn validate_node_write<'a>(
415        &'a mut self,
416        context: &RequestContext,
417        node_to_write: &ParsedWriteValue,
418        type_tree: &dyn TypeTree,
419    ) -> Result<&'a mut NodeType, StatusCode> {
420        let Some(node) = self.find_mut(&node_to_write.node_id) else {
421            debug!(
422                "write_node_value result for read node id {}, attribute {:?} cannot find node",
423                node_to_write.node_id, node_to_write.attribute_id
424            );
425            return Err(StatusCode::BadNodeIdUnknown);
426        };
427
428        validate_node_write(node, context, node_to_write, type_tree)?;
429
430        Ok(node)
431    }
432
433    /// Remove a node from the address space.
434    pub fn delete(&mut self, node_id: &NodeId, delete_target_references: bool) -> Option<NodeType> {
435        let n = self.node_map.remove(node_id);
436        self.references
437            .delete_node_references(node_id, delete_target_references);
438
439        n
440    }
441
442    /// Add a `FolderType` node.
443    pub fn add_folder(
444        &mut self,
445        node_id: &NodeId,
446        browse_name: impl Into<QualifiedName>,
447        display_name: impl Into<LocalizedText>,
448        parent_node_id: &NodeId,
449    ) -> bool {
450        self.assert_namespace(node_id);
451        ObjectBuilder::new(node_id, browse_name, display_name)
452            .is_folder()
453            .organized_by(parent_node_id.clone())
454            .insert(self)
455    }
456
457    /// Add a list of variables to the address space.
458    pub fn add_variables(
459        &mut self,
460        variables: Vec<Variable>,
461        parent_node_id: &NodeId,
462    ) -> Vec<bool> {
463        variables
464            .into_iter()
465            .map(|v| {
466                self.insert(
467                    v,
468                    Some(&[(
469                        parent_node_id,
470                        &ReferenceTypeId::Organizes,
471                        ReferenceDirection::Inverse,
472                    )]),
473                )
474            })
475            .collect()
476    }
477}
478
479impl NodeInsertTarget for AddressSpace {
480    fn insert<'a>(
481        &mut self,
482        node: impl Into<NodeType>,
483        references: Option<&'a [(&'a NodeId, &NodeId, opcua_nodes::ReferenceDirection)]>,
484    ) -> bool {
485        let node_type = node.into();
486        let node_id = node_type.node_id().clone();
487
488        self.assert_namespace(&node_id);
489
490        if self.node_exists(&node_id) {
491            error!("This node {} already exists", node_id);
492            false
493        } else {
494            // If references are supplied, add them now
495            if let Some(references) = references {
496                self.references.insert(&node_id, references);
497            }
498            self.node_map.insert(node_id, node_type);
499
500            true
501        }
502    }
503}
504
505#[cfg(test)]
506mod tests {
507    use crate::address_space::{
508        CoreNamespace, EventNotifier, MethodBuilder, NodeBase, NodeType, Object, ObjectBuilder,
509        ObjectTypeBuilder, Variable, VariableBuilder,
510    };
511    use opcua_nodes::{DefaultTypeTree, NamespaceMap, TypeTree};
512    use opcua_types::{
513        argument::Argument, Array, BrowseDirection, DataTypeId, LocalizedText, NodeClass, NodeId,
514        NumericRange, ObjectId, ObjectTypeId, QualifiedName, ReferenceTypeId, TimestampsToReturn,
515        UAString, Variant, VariantScalarTypeId,
516    };
517
518    use super::AddressSpace;
519
520    fn make_sample_address_space() -> AddressSpace {
521        let mut address_space = AddressSpace::new();
522        address_space.add_namespace("http://opcfoundation.org/UA/", 0);
523        let mut namespaces = NamespaceMap::default();
524        address_space.import_node_set(&CoreNamespace, &mut namespaces);
525        add_sample_vars_to_address_space(&mut address_space);
526        address_space
527    }
528
529    fn add_sample_vars_to_address_space(address_space: &mut AddressSpace) {
530        address_space.add_namespace("urn:test", 1);
531        let ns = 1;
532
533        // Create a sample folder under objects folder
534        let sample_folder_id = NodeId::next_numeric(ns);
535        ObjectBuilder::new(&sample_folder_id, "Sample", "Sample")
536            .organized_by(ObjectId::ObjectsFolder)
537            .insert(address_space);
538
539        // Add some variables to our sample folder
540        let vars = vec![
541            Variable::new(&NodeId::new(ns, "v1"), "v1", "v1", 30i32),
542            Variable::new(&NodeId::new(ns, 300), "v2", "v2", true),
543            Variable::new(&NodeId::new(ns, "v3"), "v3", "v3", "Hello world"),
544            Variable::new(&NodeId::new(ns, "v4"), "v4", "v4", 100.123f64),
545        ];
546        for var in vars {
547            let node_id = var.node_id().clone();
548            address_space.insert::<_, NodeId>(var, None);
549            address_space.insert_reference(
550                &sample_folder_id,
551                &node_id,
552                ReferenceTypeId::HasComponent,
553            );
554        }
555    }
556
557    #[test]
558    fn find_root_folder() {
559        let address_space = make_sample_address_space();
560        let node_type = address_space.find_node(&NodeId::new(0, 84));
561        assert!(node_type.is_some());
562
563        let node = node_type.unwrap().as_node();
564        assert_eq!(node.node_id(), &NodeId::new(0, 84));
565        assert_eq!(node.node_id(), &ObjectId::RootFolder);
566    }
567
568    #[test]
569    fn find_objects_folder() {
570        let address_space = make_sample_address_space();
571        let node_type = address_space.find(ObjectId::ObjectsFolder);
572        assert!(node_type.is_some());
573    }
574
575    #[test]
576    fn find_types_folder() {
577        let address_space = make_sample_address_space();
578        let node_type = address_space.find(ObjectId::TypesFolder);
579        assert!(node_type.is_some());
580    }
581
582    #[test]
583    fn find_views_folder() {
584        let address_space = make_sample_address_space();
585        let node_type = address_space.find(ObjectId::ViewsFolder);
586        assert!(node_type.is_some());
587    }
588
589    #[test]
590    fn find_common_nodes() {
591        let address_space = make_sample_address_space();
592        let nodes: Vec<NodeId> = vec![
593            ObjectId::RootFolder.into(),
594            ObjectId::ObjectsFolder.into(),
595            ObjectId::TypesFolder.into(),
596            ObjectId::ViewsFolder.into(),
597            ObjectId::DataTypesFolder.into(),
598            DataTypeId::BaseDataType.into(),
599            // Types
600            DataTypeId::Boolean.into(),
601            DataTypeId::ByteString.into(),
602            DataTypeId::DataValue.into(),
603            DataTypeId::DateTime.into(),
604            DataTypeId::DiagnosticInfo.into(),
605            DataTypeId::Enumeration.into(),
606            DataTypeId::ExpandedNodeId.into(),
607            DataTypeId::Guid.into(),
608            DataTypeId::LocalizedText.into(),
609            DataTypeId::NodeId.into(),
610            DataTypeId::Number.into(),
611            DataTypeId::QualifiedName.into(),
612            DataTypeId::StatusCode.into(),
613            DataTypeId::String.into(),
614            DataTypeId::Structure.into(),
615            DataTypeId::XmlElement.into(),
616            DataTypeId::Double.into(),
617            DataTypeId::Float.into(),
618            DataTypeId::Integer.into(),
619            DataTypeId::SByte.into(),
620            DataTypeId::Int16.into(),
621            DataTypeId::Int32.into(),
622            DataTypeId::Int64.into(),
623            DataTypeId::Byte.into(),
624            DataTypeId::UInt16.into(),
625            DataTypeId::UInt32.into(),
626            DataTypeId::UInt64.into(),
627            ObjectId::OPCBinarySchema_TypeSystem.into(),
628            ObjectTypeId::DataTypeSystemType.into(),
629            // Refs
630            ObjectId::ReferenceTypesFolder.into(),
631            ReferenceTypeId::References.into(),
632            ReferenceTypeId::HierarchicalReferences.into(),
633            ReferenceTypeId::HasChild.into(),
634            ReferenceTypeId::HasSubtype.into(),
635            ReferenceTypeId::Organizes.into(),
636            ReferenceTypeId::NonHierarchicalReferences.into(),
637            ReferenceTypeId::HasTypeDefinition.into(),
638        ];
639        for n in nodes {
640            assert!(address_space.find_node(&n).is_some());
641        }
642    }
643
644    #[test]
645    fn object_attributes() {
646        let on = NodeId::new(1, "o1");
647        let o = Object::new(&on, "Browse01", "Display01", EventNotifier::empty());
648        assert_eq!(o.node_class(), NodeClass::Object);
649        assert_eq!(o.node_id(), &on);
650        assert_eq!(o.browse_name(), &QualifiedName::new(0, "Browse01"));
651        assert_eq!(o.display_name(), &"Display01".into());
652    }
653
654    #[test]
655    fn find_node_by_id() {
656        let address_space = make_sample_address_space();
657        let ns = 1;
658
659        assert!(!address_space.node_exists(&NodeId::null()));
660        assert!(!address_space.node_exists(&NodeId::new(11, "v3")));
661
662        assert!(address_space.node_exists(&NodeId::new(ns, "v1")));
663        assert!(address_space.node_exists(&NodeId::new(ns, 300)));
664        assert!(address_space.node_exists(&NodeId::new(ns, "v3")));
665    }
666
667    #[test]
668    fn find_references() {
669        let address_space = make_sample_address_space();
670
671        let references: Vec<_> = address_space
672            .find_references(
673                &NodeId::root_folder_id(),
674                Some((ReferenceTypeId::Organizes, false)),
675                &DefaultTypeTree::new(),
676                BrowseDirection::Forward,
677            )
678            .collect();
679        assert_eq!(references.len(), 3);
680
681        let references: Vec<_> = address_space
682            .find_references(
683                &NodeId::root_folder_id(),
684                None::<(NodeId, bool)>,
685                &DefaultTypeTree::new(),
686                BrowseDirection::Forward,
687            )
688            .collect();
689        assert_eq!(references.len(), 4);
690
691        let references: Vec<_> = address_space
692            .find_references(
693                &NodeId::objects_folder_id(),
694                Some((ReferenceTypeId::Organizes, false)),
695                &DefaultTypeTree::new(),
696                BrowseDirection::Forward,
697            )
698            .collect();
699        assert_eq!(references.len(), 4);
700
701        let r1 = &references[0];
702        assert_eq!(r1.reference_type, &ReferenceTypeId::Organizes);
703        let child_node_id = r1.target_node.clone();
704
705        let child = address_space.find_node(&child_node_id);
706        assert!(child.is_some());
707    }
708
709    #[test]
710    fn find_inverse_references() {
711        let address_space = make_sample_address_space();
712
713        //println!("{:#?}", address_space);
714        let references: Vec<_> = address_space
715            .find_references(
716                &NodeId::root_folder_id(),
717                Some((ReferenceTypeId::Organizes, false)),
718                &DefaultTypeTree::new(),
719                BrowseDirection::Inverse,
720            )
721            .collect();
722        assert!(references.is_empty());
723
724        let references: Vec<_> = address_space
725            .find_references(
726                &NodeId::objects_folder_id(),
727                Some((ReferenceTypeId::Organizes, false)),
728                &DefaultTypeTree::new(),
729                BrowseDirection::Inverse,
730            )
731            .collect();
732        assert_eq!(references.len(), 1);
733    }
734
735    #[test]
736    fn find_reference_subtypes() {
737        let address_space = make_sample_address_space();
738        let mut type_tree = DefaultTypeTree::new();
739        address_space.load_into_type_tree(&mut type_tree);
740
741        let reference_types = [
742            (
743                ReferenceTypeId::References,
744                ReferenceTypeId::HierarchicalReferences,
745            ),
746            (ReferenceTypeId::References, ReferenceTypeId::HasChild),
747            (ReferenceTypeId::References, ReferenceTypeId::HasSubtype),
748            (ReferenceTypeId::References, ReferenceTypeId::Organizes),
749            (ReferenceTypeId::References, ReferenceTypeId::Aggregates),
750            (ReferenceTypeId::References, ReferenceTypeId::HasProperty),
751            (ReferenceTypeId::References, ReferenceTypeId::HasComponent),
752            (
753                ReferenceTypeId::References,
754                ReferenceTypeId::HasOrderedComponent,
755            ),
756            (ReferenceTypeId::References, ReferenceTypeId::HasEventSource),
757            (ReferenceTypeId::References, ReferenceTypeId::HasNotifier),
758            (ReferenceTypeId::References, ReferenceTypeId::GeneratesEvent),
759            (
760                ReferenceTypeId::References,
761                ReferenceTypeId::AlwaysGeneratesEvent,
762            ),
763            (ReferenceTypeId::References, ReferenceTypeId::HasEncoding),
764            (
765                ReferenceTypeId::References,
766                ReferenceTypeId::HasModellingRule,
767            ),
768            (ReferenceTypeId::References, ReferenceTypeId::HasDescription),
769            (
770                ReferenceTypeId::References,
771                ReferenceTypeId::HasTypeDefinition,
772            ),
773            (
774                ReferenceTypeId::HierarchicalReferences,
775                ReferenceTypeId::HasChild,
776            ),
777            (
778                ReferenceTypeId::HierarchicalReferences,
779                ReferenceTypeId::HasSubtype,
780            ),
781            (
782                ReferenceTypeId::HierarchicalReferences,
783                ReferenceTypeId::Organizes,
784            ),
785            (
786                ReferenceTypeId::HierarchicalReferences,
787                ReferenceTypeId::Aggregates,
788            ),
789            (
790                ReferenceTypeId::HierarchicalReferences,
791                ReferenceTypeId::HasProperty,
792            ),
793            (
794                ReferenceTypeId::HierarchicalReferences,
795                ReferenceTypeId::HasComponent,
796            ),
797            (
798                ReferenceTypeId::HierarchicalReferences,
799                ReferenceTypeId::HasOrderedComponent,
800            ),
801            (
802                ReferenceTypeId::HierarchicalReferences,
803                ReferenceTypeId::HasEventSource,
804            ),
805            (
806                ReferenceTypeId::HierarchicalReferences,
807                ReferenceTypeId::HasNotifier,
808            ),
809            (ReferenceTypeId::HasChild, ReferenceTypeId::Aggregates),
810            (ReferenceTypeId::HasChild, ReferenceTypeId::HasComponent),
811            (
812                ReferenceTypeId::HasChild,
813                ReferenceTypeId::HasHistoricalConfiguration,
814            ),
815            (ReferenceTypeId::HasChild, ReferenceTypeId::HasProperty),
816            (
817                ReferenceTypeId::HasChild,
818                ReferenceTypeId::HasOrderedComponent,
819            ),
820            (ReferenceTypeId::HasChild, ReferenceTypeId::HasSubtype),
821            (ReferenceTypeId::Aggregates, ReferenceTypeId::HasComponent),
822            (
823                ReferenceTypeId::Aggregates,
824                ReferenceTypeId::HasHistoricalConfiguration,
825            ),
826            (ReferenceTypeId::Aggregates, ReferenceTypeId::HasProperty),
827            (
828                ReferenceTypeId::Aggregates,
829                ReferenceTypeId::HasOrderedComponent,
830            ),
831            (
832                ReferenceTypeId::HasComponent,
833                ReferenceTypeId::HasOrderedComponent,
834            ),
835            (
836                ReferenceTypeId::HasEventSource,
837                ReferenceTypeId::HasNotifier,
838            ),
839            (
840                ReferenceTypeId::HierarchicalReferences,
841                ReferenceTypeId::HasNotifier,
842            ),
843            (
844                ReferenceTypeId::References,
845                ReferenceTypeId::NonHierarchicalReferences,
846            ),
847            (
848                ReferenceTypeId::NonHierarchicalReferences,
849                ReferenceTypeId::GeneratesEvent,
850            ),
851            (
852                ReferenceTypeId::NonHierarchicalReferences,
853                ReferenceTypeId::AlwaysGeneratesEvent,
854            ),
855            (
856                ReferenceTypeId::NonHierarchicalReferences,
857                ReferenceTypeId::HasEncoding,
858            ),
859            (
860                ReferenceTypeId::NonHierarchicalReferences,
861                ReferenceTypeId::HasModellingRule,
862            ),
863            (
864                ReferenceTypeId::NonHierarchicalReferences,
865                ReferenceTypeId::HasDescription,
866            ),
867            (
868                ReferenceTypeId::NonHierarchicalReferences,
869                ReferenceTypeId::HasTypeDefinition,
870            ),
871            (
872                ReferenceTypeId::GeneratesEvent,
873                ReferenceTypeId::AlwaysGeneratesEvent,
874            ),
875        ];
876
877        // Make sure that subtypes match when subtypes are to be compared and doesn't when they should
878        // not be compared.
879        reference_types.iter().for_each(|r| {
880            let r1 = r.0.into();
881            let r2 = r.1.into();
882            assert!(type_tree.is_subtype_of(&r2, &r1));
883        });
884    }
885
886    /// This test is to ensure that adding a Variable with a value of Array to address space sets the
887    /// ValueRank and ArrayDimensions attributes correctly.
888    #[test]
889    fn array_as_variable() {
890        // 1 dimensional array with 100 element
891        let values = (0..100).map(Variant::Int32).collect::<Vec<Variant>>();
892
893        // Get the variable node back from the address space, ensure that the ValueRank and ArrayDimensions are correct
894        let node_id = NodeId::new(2, 1);
895        let v = Variable::new(&node_id, "x", "x", (VariantScalarTypeId::Int32, values));
896
897        let value_rank = v.value_rank();
898        assert_eq!(value_rank, 1);
899        let array_dimensions = v.array_dimensions().unwrap();
900        assert_eq!(array_dimensions, vec![100u32]);
901    }
902
903    /// This test is to ensure that adding a Variable with a value of Array to address space sets the
904    /// ValueRank and ArrayDimensions attributes correctly.
905    #[test]
906    fn multi_dimension_array_as_variable() {
907        // 2 dimensional array with 10x10 elements
908
909        let values = (0..100).map(Variant::Int32).collect::<Vec<Variant>>();
910        let mda = Array::new_multi(VariantScalarTypeId::Int32, values, vec![10u32, 10u32]).unwrap();
911        assert!(mda.is_valid());
912
913        // Get the variable node back from the address space, ensure that the ValueRank and ArrayDimensions are correct
914        let node_id = NodeId::new(2, 1);
915        let v = Variable::new(&node_id, "x", "x", mda);
916
917        let value_rank = v.value_rank();
918        assert_eq!(value_rank, 2);
919        let array_dimensions = v.array_dimensions().unwrap();
920        assert_eq!(array_dimensions, vec![10u32, 10u32]);
921    }
922
923    #[test]
924    fn browse_nodes() {
925        let address_space = make_sample_address_space();
926
927        // Test that a node can be found
928        let object_id = ObjectId::RootFolder.into();
929        let result = address_space.find_node_by_browse_path(
930            &object_id,
931            None::<(NodeId, bool)>,
932            &DefaultTypeTree::new(),
933            BrowseDirection::Forward,
934            &["Objects".into(), "Sample".into(), "v1".into()],
935        );
936        let node = result.unwrap();
937        assert_eq!(node.as_node().browse_name(), &QualifiedName::from("v1"));
938
939        // Test that a non existent node cannot be found
940        let result = address_space.find_node_by_browse_path(
941            &object_id,
942            None::<(NodeId, bool)>,
943            &DefaultTypeTree::new(),
944            BrowseDirection::Forward,
945            &["Objects".into(), "Sample".into(), "vxxx".into()],
946        );
947        assert!(result.is_none());
948    }
949
950    #[test]
951    fn object_builder() {
952        let mut address_space = make_sample_address_space();
953
954        let node_type_id = NodeId::new(1, "HelloType");
955        let _ot = ObjectTypeBuilder::new(&node_type_id, "HelloType", "HelloType")
956            .subtype_of(ObjectTypeId::BaseObjectType)
957            .insert(&mut address_space);
958
959        let node_id = NodeId::new(1, "Hello");
960        let _o = ObjectBuilder::new(&node_id, "Foo", "Foo")
961            .event_notifier(EventNotifier::SUBSCRIBE_TO_EVENTS)
962            .organized_by(ObjectId::ObjectsFolder)
963            .has_type_definition(node_type_id.clone())
964            .insert(&mut address_space);
965
966        // Verify the variable is there
967        let _o = match address_space.find_node(&node_id).unwrap() {
968            NodeType::Object(o) => o,
969            _ => panic!(),
970        };
971
972        // Verify the reference to the objects folder is there
973        assert!(address_space.has_reference(
974            &ObjectId::ObjectsFolder.into(),
975            &node_id,
976            ReferenceTypeId::Organizes
977        ));
978        assert!(address_space.has_reference(
979            &node_id,
980            &node_type_id,
981            ReferenceTypeId::HasTypeDefinition
982        ));
983    }
984
985    #[test]
986    fn object_type_builder() {
987        let mut address_space = make_sample_address_space();
988
989        let node_type_id = NodeId::new(1, "HelloType");
990        let _ot = ObjectTypeBuilder::new(&node_type_id, "HelloType", "HelloType")
991            .subtype_of(ObjectTypeId::BaseObjectType)
992            .insert(&mut address_space);
993
994        let _ot = match address_space.find_node(&node_type_id).unwrap() {
995            NodeType::ObjectType(ot) => ot,
996            _ => panic!(),
997        };
998
999        assert!(address_space.has_reference(
1000            &ObjectTypeId::BaseObjectType.into(),
1001            &node_type_id,
1002            ReferenceTypeId::HasSubtype
1003        ));
1004    }
1005
1006    #[test]
1007    fn variable_builder() {
1008        let result = std::panic::catch_unwind(|| {
1009            // This should panic
1010            let _v = VariableBuilder::new(&NodeId::null(), "", "").build();
1011        });
1012        assert!(result.is_err());
1013
1014        // This should build
1015        let _v = VariableBuilder::new(&NodeId::new(1, 1), "", "")
1016            .data_type(DataTypeId::Boolean)
1017            .build();
1018
1019        // Check a variable with a bunch of fields set
1020        let v = VariableBuilder::new(&NodeId::new(1, "Hello"), "BrowseName", "DisplayName")
1021            .description("Desc")
1022            .data_type(DataTypeId::UInt32)
1023            .value_rank(10)
1024            .array_dimensions(&[1, 2, 3])
1025            .historizing(true)
1026            .value(Variant::from(999))
1027            .minimum_sampling_interval(123.0)
1028            .build();
1029
1030        assert_eq!(v.node_id(), &NodeId::new(1, "Hello"));
1031        assert_eq!(v.browse_name(), &QualifiedName::new(0, "BrowseName"));
1032        assert_eq!(v.display_name(), &"DisplayName".into());
1033        assert_eq!(v.data_type(), DataTypeId::UInt32);
1034        assert_eq!(v.description().unwrap(), &"Desc".into());
1035        assert_eq!(v.value_rank(), 10);
1036        assert_eq!(v.array_dimensions().unwrap(), vec![1, 2, 3]);
1037        assert!(v.historizing());
1038        assert_eq!(
1039            v.value(
1040                TimestampsToReturn::Neither,
1041                &NumericRange::None,
1042                &opcua_types::DataEncoding::Binary,
1043                0.0
1044            )
1045            .value
1046            .unwrap(),
1047            Variant::from(999)
1048        );
1049        assert_eq!(v.minimum_sampling_interval().unwrap(), 123.0);
1050
1051        // Add a variable to the address space
1052
1053        let mut address_space = make_sample_address_space();
1054        let node_id = NodeId::new(1, "Hello");
1055        let _v = VariableBuilder::new(&node_id, "BrowseName", "DisplayName")
1056            .description("Desc")
1057            .value_rank(10)
1058            .data_type(DataTypeId::UInt32)
1059            .array_dimensions(&[1, 2, 3])
1060            .historizing(true)
1061            .value(Variant::from(999))
1062            .minimum_sampling_interval(123.0)
1063            .organized_by(ObjectId::ObjectsFolder)
1064            .insert(&mut address_space);
1065
1066        // Verify the variable is there
1067        assert!(address_space.find_node(&node_id).is_some());
1068        // Verify the reference to the objects folder is there
1069        assert!(address_space.has_reference(
1070            &ObjectId::ObjectsFolder.into(),
1071            &node_id,
1072            ReferenceTypeId::Organizes
1073        ));
1074    }
1075
1076    #[test]
1077    fn method_builder() {
1078        let mut address_space = make_sample_address_space();
1079
1080        address_space.add_namespace("urn:test", 1);
1081        let ns = 1;
1082
1083        let object_id: NodeId = ObjectId::ObjectsFolder.into();
1084
1085        let fn_node_id = NodeId::new(ns, "HelloWorld");
1086        let out_args = NodeId::new(ns, "HelloWorldOut");
1087
1088        let inserted = MethodBuilder::new(&fn_node_id, "HelloWorld", "HelloWorld")
1089            .component_of(object_id.clone())
1090            .output_args(
1091                &mut address_space,
1092                &out_args,
1093                &[("Result", DataTypeId::String).into()],
1094            )
1095            .insert(&mut address_space);
1096        assert!(inserted);
1097
1098        assert!(matches!(
1099            address_space.find_node(&fn_node_id),
1100            Some(NodeType::Method(_))
1101        ));
1102
1103        let refs: Vec<_> = address_space
1104            .find_references(
1105                &fn_node_id,
1106                Some((ReferenceTypeId::HasProperty, false)),
1107                &DefaultTypeTree::new(),
1108                BrowseDirection::Forward,
1109            )
1110            .collect();
1111        assert_eq!(refs.len(), 1);
1112
1113        let child = address_space
1114            .find_node(refs.first().unwrap().target_node)
1115            .unwrap();
1116        if let NodeType::Variable(v) = child {
1117            // verify OutputArguments
1118            // verify OutputArguments / Argument value
1119            assert_eq!(v.data_type(), DataTypeId::Argument);
1120            assert_eq!(v.display_name(), &LocalizedText::from("OutputArguments"));
1121            let v = v
1122                .value(
1123                    TimestampsToReturn::Neither,
1124                    &NumericRange::None,
1125                    &opcua_types::DataEncoding::Binary,
1126                    0.0,
1127                )
1128                .value
1129                .unwrap();
1130            if let Variant::Array(array) = v {
1131                let v = array.values;
1132                assert_eq!(v.len(), 1);
1133                let v = v.first().unwrap().clone();
1134                if let Variant::ExtensionObject(v) = v {
1135                    // deserialize the Argument here
1136                    let argument = v.inner_as::<Argument>().unwrap();
1137                    assert_eq!(argument.name, UAString::from("Result"));
1138                    assert_eq!(argument.data_type, DataTypeId::String);
1139                    assert_eq!(argument.value_rank, -1);
1140                    assert_eq!(argument.array_dimensions, None);
1141                    assert_eq!(argument.description, LocalizedText::null());
1142                } else {
1143                    panic!("Variant was expected to be extension object, was {v:?}");
1144                }
1145            } else {
1146                panic!("Variant was expected to be array, was {v:?}");
1147            }
1148        } else {
1149            panic!();
1150        }
1151    }
1152
1153    #[test]
1154    fn simple_delete_node() {
1155        // This is a super basic, debuggable delete test. There is a single Root node, and a
1156        // child object. After deleting the child, only the Root should exist with no references at
1157        // all to the child.
1158
1159        // A blank address space, with nothing at all in it
1160        let mut address_space = make_sample_address_space();
1161
1162        // Add a root node
1163        let root_node = NodeId::root_folder_id();
1164
1165        let node = Object::new(&root_node, "Root", "", EventNotifier::empty());
1166        let _ = address_space.insert::<Object, ReferenceTypeId>(node, None);
1167
1168        let node_id = NodeId::new(1, "Hello");
1169        let _o = ObjectBuilder::new(&node_id, "Foo", "Foo")
1170            .organized_by(root_node.clone())
1171            .insert(&mut address_space);
1172
1173        // Verify the object and refs are there
1174        assert!(address_space.find_node(&node_id).is_some());
1175        assert!(address_space.has_reference(&root_node, &node_id, ReferenceTypeId::Organizes));
1176
1177        // Try one time deleting references, the other time not deleting them.
1178        address_space.delete(&node_id, true);
1179        // Delete the node and the refs
1180        assert!(address_space.find_node(&node_id).is_none());
1181        assert!(address_space.find_node(&root_node).is_some());
1182        assert!(!address_space.has_reference(&root_node, &node_id, ReferenceTypeId::Organizes));
1183    }
1184
1185    #[test]
1186    fn delete_node() {
1187        // Try creating and deleting a node, verifying that it's totally gone afterwards
1188        (0..2).for_each(|i| {
1189            let mut address_space = make_sample_address_space();
1190
1191            let node_type_id = NodeId::new(1, "HelloType");
1192            let _ot = ObjectTypeBuilder::new(&node_type_id, "HelloType", "HelloType")
1193                .subtype_of(ObjectTypeId::BaseObjectType)
1194                .insert(&mut address_space);
1195
1196            let node_id = NodeId::new(1, "Hello");
1197            let _o = ObjectBuilder::new(&node_id, "Foo", "Foo")
1198                .event_notifier(EventNotifier::SUBSCRIBE_TO_EVENTS)
1199                .organized_by(ObjectId::ObjectsFolder)
1200                .has_type_definition(node_type_id.clone())
1201                .insert(&mut address_space);
1202
1203            // Verify the object and refs are there
1204            assert!(address_space.find_node(&node_id).is_some());
1205            assert!(address_space.has_reference(
1206                &ObjectId::ObjectsFolder.into(),
1207                &node_id,
1208                ReferenceTypeId::Organizes
1209            ));
1210            assert!(!address_space.has_reference(
1211                &node_id,
1212                &ObjectId::ObjectsFolder.into(),
1213                ReferenceTypeId::Organizes
1214            ));
1215            assert!(address_space.has_reference(
1216                &node_id,
1217                &node_type_id,
1218                ReferenceTypeId::HasTypeDefinition
1219            ));
1220
1221            // Try one time deleting references, the other time not deleting them.
1222            let delete_target_references = i == 1;
1223            address_space.delete(&node_id, delete_target_references);
1224            if !delete_target_references {
1225                // Deleted the node and outgoing refs, but not incoming refs
1226                assert!(address_space.find_node(&node_id).is_none());
1227                assert!(address_space.has_reference(
1228                    &ObjectId::ObjectsFolder.into(),
1229                    &node_id,
1230                    ReferenceTypeId::Organizes
1231                ));
1232                assert!(!address_space.has_reference(
1233                    &node_id,
1234                    &node_type_id,
1235                    ReferenceTypeId::HasTypeDefinition
1236                ));
1237            } else {
1238                // Delete the node and the refs
1239                assert!(address_space.find_node(&node_id).is_none());
1240                assert!(!address_space.has_reference(
1241                    &ObjectId::ObjectsFolder.into(),
1242                    &node_id,
1243                    ReferenceTypeId::Organizes
1244                ));
1245                assert!(!address_space.has_reference(
1246                    &node_id,
1247                    &node_type_id,
1248                    ReferenceTypeId::HasTypeDefinition
1249                ));
1250            }
1251        });
1252    }
1253}