From e584c5ce7db0adbdcced3427411bbd82c6dc1b68 Mon Sep 17 00:00:00 2001
From: Rohit Thakur <rohitthakur2590@outlook.com>
Date: Fri, 8 May 2020 18:53:03 +0530
Subject: ospfv3 test cases updated

Signed-off-by: Rohit Thakur <rohitthakur2590@outlook.com>
---
 .../network/vyos/argspec/ospfv3/ospfv3.py          | 110 ++---
 .../network/vyos/config/ospfv3/ospfv3.py           | 263 ++++++-----
 plugins/module_utils/network/vyos/facts/facts.py   |   4 +-
 .../network/vyos/facts/ospfv3/ospfv3.py            |  54 ++-
 plugins/module_utils/network/vyos/utils/utils.py   |  11 +-
 plugins/modules/vyos_ospfv3.py                     | 516 ++++++++++++++++++++-
 .../targets/vyos_ospfv3/defaults/main.yaml         |   3 +
 .../integration/targets/vyos_ospfv3/meta/main.yaml |   3 +
 .../integration/targets/vyos_ospfv3/tasks/cli.yaml |  19 +
 .../targets/vyos_ospfv3/tasks/main.yaml            |   4 +
 .../vyos_ospfv3/tests/cli/_parsed_config.cfg       |   8 +
 .../targets/vyos_ospfv3/tests/cli/_populate.yaml   |  13 +
 .../vyos_ospfv3/tests/cli/_remove_config.yaml      |   6 +
 .../targets/vyos_ospfv3/tests/cli/deleted.yaml     |  48 ++
 .../vyos_ospfv3/tests/cli/empty_config.yaml        |  49 ++
 .../targets/vyos_ospfv3/tests/cli/gathered.yaml    |  25 +
 .../targets/vyos_ospfv3/tests/cli/merged.yaml      |  62 +++
 .../vyos_ospfv3/tests/cli/merged_update.yaml       |  61 +++
 .../targets/vyos_ospfv3/tests/cli/parsed.yaml      |  15 +
 .../targets/vyos_ospfv3/tests/cli/rendered.yaml    |  38 ++
 .../targets/vyos_ospfv3/tests/cli/replaced.yaml    |  66 +++
 .../targets/vyos_ospfv3/tests/cli/rtt.yaml         |  75 +++
 .../integration/targets/vyos_ospfv3/vars/main.yaml | 140 ++++++
 .../network/vyos/fixtures/vyos_ospfv3_config.cfg   |   6 +
 .../unit/modules/network/vyos/test_vyos_ospfv3.py  | 348 ++++++++++++++
 tests/unit/modules/network/vyos/vyos_module.py     |   1 +
 26 files changed, 1743 insertions(+), 205 deletions(-)
 create mode 100644 tests/integration/targets/vyos_ospfv3/defaults/main.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/meta/main.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tasks/cli.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tasks/main.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/_parsed_config.cfg
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/_populate.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/_remove_config.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/deleted.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/empty_config.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/gathered.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/merged.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/merged_update.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/parsed.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/rendered.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/replaced.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/tests/cli/rtt.yaml
 create mode 100644 tests/integration/targets/vyos_ospfv3/vars/main.yaml
 create mode 100644 tests/unit/modules/network/vyos/fixtures/vyos_ospfv3_config.cfg
 create mode 100644 tests/unit/modules/network/vyos/test_vyos_ospfv3.py

diff --git a/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py
index 60e208c3..66aaa8c4 100644
--- a/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py
+++ b/plugins/module_utils/network/vyos/argspec/ospfv3/ospfv3.py
@@ -29,80 +29,66 @@ The arg spec for the vyos_ospfv3 module
 class Ospfv3Args(object):  # pylint: disable=R0903
     """The arg spec for the vyos_ospfv3 module
     """
+
     def __init__(self, **kwargs):
         pass
 
     argument_spec = {
-        'config': {
-            'options': {
-                'areas': {
-                    'elements': 'dict',
-                    'options': {
-                        'area_id': {
-                            'type': 'str'
-                        },
-                        'export_list': {
-                            'type': 'str'
-                        },
-                        'import_list': {
-                            'type': 'str'
-                        },
-                        'range': {
-                            'elements': 'dict',
-                            'options': {
-                                'address': {
-                                    'type': 'str'
-                                },
-                                'advertise': {
-                                    'type': 'bool'
-                                },
-                                'not_advertise': {
-                                    'type': 'bool'
-                                }
+        "config": {
+            "options": {
+                "areas": {
+                    "elements": "dict",
+                    "options": {
+                        "area_id": {"type": "str"},
+                        "export_list": {"type": "str"},
+                        "import_list": {"type": "str"},
+                        "range": {
+                            "elements": "dict",
+                            "options": {
+                                "address": {"type": "str"},
+                                "advertise": {"type": "bool"},
+                                "not_advertise": {"type": "bool"},
                             },
-                            'type': 'list'
-                        }
+                            "type": "list",
+                        },
                     },
-                    'type': 'list'
+                    "type": "list",
                 },
-                'parameters': {
-                    'options': {
-                        'router_id': {
-                            'type': 'str'
-                        }
-                    },
-                    'type': 'dict'
+                "parameters": {
+                    "options": {"router_id": {"type": "str"}},
+                    "type": "dict",
                 },
-                'redistribute': {
-                    'elements': 'dict',
-                    'options': {
-                        'route_map': {
-                            'type': 'str'
+                "redistribute": {
+                    "elements": "dict",
+                    "options": {
+                        "route_map": {"type": "str"},
+                        "route_type": {
+                            "choices": [
+                                "bgp",
+                                "connected",
+                                "kernel",
+                                "ripng",
+                                "static",
+                            ],
+                            "type": "str",
                         },
-                        'route_type': {
-                            'choices':
-                            ['bgp', 'connected', 'kernel', 'ripng', 'static'],
-                            'type':
-                            'str'
-                        }
                     },
-                    'type': 'list'
-                }
+                    "type": "list",
+                },
             },
-            'type': 'dict'
-        },
-        'running_config': {
-            'type': 'str'
+            "type": "dict",
         },
         "running_config": {"type": "str"},
-        'state': {
-            'choices': [
-                'merged', 'replaced', 'deleted', 'parsed', 'gathered',
-                'rendered'
+        "state": {
+            "choices": [
+                "merged",
+                "replaced",
+                "deleted",
+                "parsed",
+                "gathered",
+                "rendered",
             ],
-            'default':
-            'merged',
-            'type':
-            'str'
-        }
+            "default": "merged",
+            "type": "str",
+        },
     }  # pylint: disable=C0301
diff --git a/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py
index 38757639..de972bc1 100644
--- a/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py
+++ b/plugins/module_utils/network/vyos/config/ospfv3/ospfv3.py
@@ -11,9 +11,8 @@ necessary to bring the current configuration to it's desired end-state is
 created
 """
 from __future__ import absolute_import, division, print_function
-__metaclass__ = type
 
-import q
+__metaclass__ = type
 
 from copy import deepcopy
 from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base import (
@@ -22,27 +21,33 @@ from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.c
 from ansible_collections.ansible.netcommon.plugins.module_utils.network.common.utils import (
     to_list,
     remove_empties,
-    search_obj_in_list
+    search_obj_in_list,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import (
+    Facts,
 )
-from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import Facts
 from ansible.module_utils.six import iteritems
 
 from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.utils.utils import (
-    list_diff_want_only, _in_target, _is_w_same, _bool_to_str
+    list_diff_want_only,
+    _in_target,
+    _is_w_same,
+    _bool_to_str,
 )
 
+
 class Ospfv3(ConfigBase):
     """
     The vyos_ospfv3 class
     """
 
     gather_subset = [
-        '!all',
-        '!min',
+        "!all",
+        "!min",
     ]
 
     gather_network_resources = [
-        'ospfv3',
+        "ospfv3",
     ]
 
     def __init__(self, module):
@@ -54,10 +59,10 @@ class Ospfv3(ConfigBase):
         :rtype: A dictionary
         :returns: The current configuration as a dictionary
         """
-        facts, _warnings = Facts(self._module).get_facts(self.gather_subset, self.gather_network_resources, data=data)
-        ospfv3_facts = facts['ansible_network_resources'].get('ospfv3')
-        if not ospfv3_facts:
-            return []
+        facts, _warnings = Facts(self._module).get_facts(
+            self.gather_subset, self.gather_network_resources, data=data
+        )
+        ospfv3_facts = facts["ansible_network_resources"].get("ospfv3", {})
         return ospfv3_facts
 
     def execute_module(self):
@@ -66,14 +71,14 @@ class Ospfv3(ConfigBase):
         :rtype: A dictionary
         :returns: The result from module execution
         """
-        result = {'changed': False}
+        result = {"changed": False}
         warnings = list()
         commands = list()
 
         if self.state in self.ACTION_STATES:
             existing_ospfv3_facts = self.get_ospfv3_facts()
         else:
-            existing_ospfv3_facts = []
+            existing_ospfv3_facts = {}
 
         if self.state in self.ACTION_STATES or self.state == "rendered":
             commands.extend(self.set_config(existing_ospfv3_facts))
@@ -96,11 +101,9 @@ class Ospfv3(ConfigBase):
                 self._module.fail_json(
                     msg="value of running_config parameter must not be empty for state parsed"
                 )
-            result["parsed"] = self.get_ospfv3_facts(
-                data=running_config
-            )
+            result["parsed"] = self.get_ospfv3_facts(data=running_config)
         else:
-            changed_ospfv3_facts = []
+            changed_ospfv3_facts = {}
 
         if self.state in self.ACTION_STATES:
             result["before"] = existing_ospfv3_facts
@@ -120,7 +123,7 @@ class Ospfv3(ConfigBase):
         :returns: the commands necessary to migrate the current configuration
                   to the desired configuration
         """
-        want = self._module.params['config']
+        want = self._module.params["config"]
         have = existing_ospfv3_facts
         resp = self.set_state(want, have)
         return to_list(resp)
@@ -135,15 +138,16 @@ class Ospfv3(ConfigBase):
                   to the desired configuration
         """
         commands = []
-        if self.state in ("merged", "replaced", "overridden", "rendered") and not w:
+        if (
+            self.state in ("merged", "replaced", "overridden", "rendered")
+            and not w
+        ):
             self._module.fail_json(
                 msg="value of config parameter must not be empty for state {0}".format(
                     self.state
                 )
             )
-        if self.state == "overridden":
-            commands.extend(self._state_overridden(w, h))
-        elif self.state == "deleted":
+        if self.state == "deleted":
             commands.extend(self._state_deleted(w, h))
         elif self.state in ("merged", "rendered"):
             commands.extend(self._state_merged(w, h))
@@ -151,30 +155,6 @@ class Ospfv3(ConfigBase):
             commands.extend(self._state_replaced(w, h))
         return commands
 
-    '''
-    def search_obj_in_have(self, have, w_name, key):
-        """
-        This function  returns the rule-set/rule if it is present in target config.
-        :param have: target config.
-        :param w_name: rule-set name.
-        :param type: rule_sets/rule/r_list.
-        :return: rule-set/rule.
-        """
-        if have:
-            for item in have:
-                if item[key] == w_name[key]:
-                    return item
-        return None
-
-    def search_obj_in_list(name, lst, key="name"):
-        if not lst:
-            return None
-        else:
-            for item in lst:
-                if item.get(key) == name:
-                    return item
-    '''
-
     def _state_replaced(self, want, have):
         """ The command generator when state is replaced
 
@@ -207,16 +187,8 @@ class Ospfv3(ConfigBase):
                   of the provided objects
         """
         commands = []
-        if want:
-            if have:
-                if have:
-                    for key, val in iteritems(want):
-                        if key in have:
-                            if key == 'areas':
-                                key = 'area'
-                            commands.append(self._compute_command(attr=key, opr=False))
-        elif have:
-            commands.append('delete protocols ospfv3')
+        if have:
+            commands.append("delete protocols ospfv3")
         return commands
 
     def _render_ospf_param(self, want, have, opr=True):
@@ -233,7 +205,7 @@ class Ospfv3(ConfigBase):
         w = deepcopy(remove_empties(want))
         if w:
             for key, val in iteritems(w):
-                    commands.extend(self._render_child_param(w, have, key, opr))
+                commands.extend(self._render_child_param(w, have, key, opr))
         return commands
 
     def _render_child_param(self, w, h, key, opr=True):
@@ -247,11 +219,11 @@ class Ospfv3(ConfigBase):
         :return: list of commands.
         """
         commands = []
-        if key == 'areas':
+        if key == "areas":
             commands.extend(self._render_areas(key, w, h, opr=opr))
-        elif key == 'parameters':
+        elif key == "parameters":
             commands.extend(self._render_dict_param(key, w, h, opr=opr))
-        elif key == 'redistribute':
+        elif key == "redistribute":
             commands.extend(self._render_list_dict_param(key, w, h, opr=opr))
         return commands
 
@@ -271,13 +243,23 @@ class Ospfv3(ConfigBase):
         if not opr and not h:
             commands.append(self._form_attr_cmd(attr=attr, opr=opr))
         elif want[attr]:
-            leaf_dict = {'parameters': "router_id"}
+            leaf_dict = {"parameters": "router_id"}
             leaf = leaf_dict[attr]
             for item, value in iteritems(want[attr]):
-                if opr and item in leaf and not _is_w_same(want[attr], h, item):
-                    commands.append(self._form_attr_cmd(key=attr, attr=item, val=value, opr=opr))
+                if (
+                    opr
+                    and item in leaf
+                    and not _is_w_same(want[attr], h, item)
+                ):
+                    commands.append(
+                        self._form_attr_cmd(
+                            key=attr, attr=item, val=value, opr=opr
+                        )
+                    )
                 elif not opr and item in leaf and not _in_target(h, item):
-                    commands.append(self._form_attr_cmd(key=attr, attr=item, opr=opr))
+                    commands.append(
+                        self._form_attr_cmd(key=attr, attr=item, opr=opr)
+                    )
         return commands
 
     def _render_list_dict_param(self, attr, want, have, cmd=None, opr=True):
@@ -293,12 +275,14 @@ class Ospfv3(ConfigBase):
         """
         commands = []
         h = []
-        name = {'redistribute': 'route_type',
-                'range': 'address',
-                }
-        leaf_dict = {'redistribute': ("route_map", "route_type"),
-                     'range': ("address", "advertise", "not_advertise")
-                     }
+        name = {
+            "redistribute": "route_type",
+            "range": "address",
+        }
+        leaf_dict = {
+            "redistribute": ("route_map", "route_type"),
+            "range": ("address", "advertise", "not_advertise"),
+        }
         leaf = leaf_dict[attr]
         w = want.get(attr) or []
         if have:
@@ -308,27 +292,54 @@ class Ospfv3(ConfigBase):
         elif w:
             for w_item in w:
                 for key, val in iteritems(w_item):
-                    q(key)
-                    q(val)
-                    q(name[attr])
-                    q(w_item)
-                    q(attr)
                     if not cmd:
                         cmd = self._compute_command(opr=opr)
-                    h_item = search_obj_in_list(w_item[name[attr]], h, name[attr])
-                    if opr and key in leaf and not _is_w_same(w_item, h_item, key):
-                        if key == 'route_type' or (key == 'address' and not ('advertise', 'not-advertise') not in w_item):
-                            commands.append(cmd + attr + ' ' + str(val))
-                        elif key in leaf_dict['range'] and key != 'address':
-                            commands.append(cmd + attr + ' ' + w_item[name[attr]] + ' ' + key.replace("_", "-"))
-                        elif key == 'route_map':
-                            commands.append(cmd + attr + ' ' + w_item[name[attr]] + ' ' + key.replace("_", "-") + ' ' + str(val))
-                    elif not opr and key in leaf and not _in_target(h_item, key):
-                        if key in ('route_type', 'address'):
-                            commands.append(cmd + attr + ' ' + str(val))
+                    h_item = search_obj_in_list(
+                        w_item[name[attr]], h, name[attr]
+                    )
+                    if (
+                        opr
+                        and key in leaf
+                        and not _is_w_same(w_item, h_item, key)
+                    ):
+                        if key == "route_type" or (
+                            key == "address"
+                            and "advertise" not in w_item
+                            and "not-advertise" not in w_item
+                        ):
+                            if not val:
+                                cmd = cmd.replace("set", "delete")
+                            commands.append(cmd + attr + " " + str(val))
+                        elif key in leaf_dict["range"] and key != "address":
+                            commands.append(
+                                cmd
+                                + attr
+                                + " "
+                                + w_item[name[attr]]
+                                + " "
+                                + key.replace("_", "-")
+                            )
+                        elif key == "route_map":
+                            commands.append(
+                                cmd
+                                + attr
+                                + " "
+                                + w_item[name[attr]]
+                                + " "
+                                + key.replace("_", "-")
+                                + " "
+                                + str(val)
+                            )
+                    elif (
+                        not opr and key in leaf and not _in_target(h_item, key)
+                    ):
+                        if key in ("route_type", "address"):
+                            commands.append(cmd + attr + " " + str(val))
                         else:
-                            commands.append(cmd + (attr + ' ' + w_item[name[attr]] + ' ' + key))
-                    q(commands)
+                            commands.append(
+                                cmd
+                                + (attr + " " + w_item[name[attr]] + " " + key)
+                            )
         return commands
 
     def _render_areas(self, attr, want, have, opr=True):
@@ -344,32 +355,68 @@ class Ospfv3(ConfigBase):
         commands = []
         h_lst = {}
         w_lst = want.get(attr) or []
-        l_set = ("area_id, export_list, import_list")
+        l_set = ("area_id", "export_list", "import_list")
         if have:
             h_lst = have.get(attr) or []
         if not opr and not h_lst:
-            commands.append(self._form_attr_cmd(attr='area', opr=opr))
+            commands.append(self._form_attr_cmd(attr="area", opr=opr))
         elif w_lst:
             for w_area in w_lst:
-                cmd = self._compute_command(key='area', attr=_bool_to_str(w_area['area_id']), opr=opr) + ' '
-                h_area = search_obj_in_list(w_area['area_id'], h_lst, 'area_id')
+                cmd = (
+                    self._compute_command(
+                        key="area",
+                        attr=_bool_to_str(w_area["area_id"]),
+                        opr=opr,
+                    )
+                    + " "
+                )
+                h_area = search_obj_in_list(
+                    w_area["area_id"], h_lst, "area_id"
+                )
                 if not opr and not h_area:
-                    commands.append(self._form_attr_cmd(key='area', attr=w_area['area_id'], opr=opr))
+                    commands.append(
+                        self._form_attr_cmd(
+                            key="area", attr=w_area["area_id"], opr=opr
+                        )
+                    )
                 else:
                     for key, val in iteritems(w_area):
-                        if opr and key in l_set and not _is_w_same(w_area, h_area, key):
-                            if key == 'area_id':
-                                commands.append(self._form_attr_cmd(attr='area', val=_bool_to_str(val), opr=opr))
+                        if (
+                            opr
+                            and key in l_set
+                            and not _is_w_same(w_area, h_area, key)
+                        ):
+                            if key == "area_id":
+                                commands.append(
+                                    self._form_attr_cmd(
+                                        attr="area",
+                                        val=_bool_to_str(val),
+                                        opr=opr,
+                                    )
+                                )
                             else:
-                                commands.append(cmd + key.replace("_", "-") + ' ' + _bool_to_str(val).replace("_", "-"))
+                                commands.append(
+                                    cmd
+                                    + key.replace("_", "-")
+                                    + " "
+                                    + _bool_to_str(val).replace("_", "-")
+                                )
                         elif not opr and key in l_set:
-                            if key == 'area_id' and not _in_target(h_area, key):
+                            if key == "area_id" and not _in_target(
+                                h_area, key
+                            ):
                                 commands.append(cmd)
                                 continue
-                            elif key != 'area_id' and not _in_target(h_area, key):
-                                commands.append(cmd + val + ' ' + key)
-                        elif key == 'range':
-                            commands.extend(self._render_list_dict_param(key, w_area, h_area, cmd, opr))
+                            elif key != "area_id" and not _in_target(
+                                h_area, key
+                            ):
+                                commands.append(cmd + val + " " + key)
+                        elif key == "range":
+                            commands.extend(
+                                self._render_list_dict_param(
+                                    key, w_area, h_area, cmd, opr
+                                )
+                            )
         return commands
 
     def _form_attr_cmd(self, key=None, attr=None, val=None, opr=True):
@@ -381,9 +428,13 @@ class Ospfv3(ConfigBase):
         :param opr: True/False.
         :return: generated command.
         """
-        return self._compute_command(key, attr=self._map_attrib(attr), val=val, opr=opr)
+        return self._compute_command(
+            key, attr=self._map_attrib(attr), val=val, opr=opr
+        )
 
-    def _compute_command(self, key=None, attr=None, val=None, remove=False, opr=True):
+    def _compute_command(
+        self, key=None, attr=None, val=None, remove=False, opr=True
+    ):
         """
         This function construct the add/delete command based on passed attributes.
         :param key: parent key.
@@ -411,4 +462,4 @@ class Ospfv3(ConfigBase):
         :param attrib: attribute
         :return: regex string
         """
-        return 'disable' if attrib == 'disabled' else attrib.replace("_","-")
+        return "disable" if attrib == "disabled" else attrib.replace("_", "-")
diff --git a/plugins/module_utils/network/vyos/facts/facts.py b/plugins/module_utils/network/vyos/facts/facts.py
index 6ead7fe7..3c87be6b 100644
--- a/plugins/module_utils/network/vyos/facts/facts.py
+++ b/plugins/module_utils/network/vyos/facts/facts.py
@@ -41,7 +41,7 @@ from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.firew
     Firewall_interfacesFacts,
 )
 from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv3.ospfv3 import (
-   Ospfv3Facts,
+    Ospfv3Facts,
 )
 from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.legacy.base import (
     Default,
@@ -61,7 +61,7 @@ FACT_RESOURCE_SUBSETS = dict(
     firewall_rules=Firewall_rulesFacts,
     firewall_global=Firewall_globalFacts,
     firewall_interfaces=Firewall_interfacesFacts,
-    ospfv3=Ospfv3Facts
+    ospfv3=Ospfv3Facts,
 )
 
 
diff --git a/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py b/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py
index a26f9e79..457a9636 100644
--- a/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py
+++ b/plugins/module_utils/network/vyos/facts/ospfv3/ospfv3.py
@@ -9,19 +9,25 @@ It is in this file the configuration is collected from the device
 for a given resource, parsed, and the facts tree is populated
 based on the configuration.
 """
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
 from re import findall, search, M
 from copy import deepcopy
 from ansible_collections.ansible.netcommon.plugins.module_utils.network.common import (
     utils,
 )
-from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv3.ospfv3 import Ospfv3Args
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv3.ospfv3 import (
+    Ospfv3Args,
+)
 
 
 class Ospfv3Facts(object):
     """ The vyos ospfv3 fact class
     """
 
-    def __init__(self, module, subspec='config', options='options'):
+    def __init__(self, module, subspec="config", options="options"):
         self._module = module
         self.argument_spec = Ospfv3Args.argument_spec
         spec = deepcopy(self.argument_spec)
@@ -56,9 +62,9 @@ class Ospfv3Facts(object):
         if ospfv3:
             objs = self.render_config(ospfv3)
         facts = {}
-        params = utils.validate_config(self.argument_spec, {'config': objs})
-        facts['ospfv3'] = utils.remove_empties(params['config'])
-        ansible_facts['ansible_network_resources'].update(facts)
+        params = utils.validate_config(self.argument_spec, {"config": objs})
+        facts["ospfv3"] = utils.remove_empties(params["config"])
+        ansible_facts["ansible_network_resources"].update(facts)
         return ansible_facts
 
     def render_config(self, conf):
@@ -70,9 +76,13 @@ class Ospfv3Facts(object):
         """
         conf = "\n".join(filter(lambda x: x, conf))
         config = {}
-        config["parameters"] = self.parse_attrib(conf, "parameters", "parameters")
+        config["parameters"] = self.parse_attrib(
+            conf, "parameters", "parameters"
+        )
         config["areas"] = self.parse_attrib_list(conf, "area", "area_id")
-        config["redistribute"] = self.parse_attrib_list(conf, "redistribute", "route_type")
+        config["redistribute"] = self.parse_attrib_list(
+            conf, "redistribute", "route_type"
+        )
         return config
 
     def parse_attrib_list(self, conf, attrib, param):
@@ -86,15 +96,15 @@ class Ospfv3Facts(object):
         """
         r_lst = []
         if attrib == "area":
-            items = findall(r"^" + attrib + " (?:\'*)(\\S+)(?:\'*)", conf, M)
+            items = findall(r"^" + attrib + " (?:'*)(\\S+)(?:'*)", conf, M)
         else:
-            items = findall(r"" + attrib + " (?:\'*)(\\S+)(?:\'*)", conf, M)
+            items = findall(r"" + attrib + " (?:'*)(\\S+)(?:'*)", conf, M)
         if items:
             a_lst = []
             for item in set(items):
                 i_regex = r" %s .+$" % item
                 cfg = "\n".join(findall(i_regex, conf, M))
-                if attrib == 'area':
+                if attrib == "area":
                     obj = self.parse_area(cfg, item)
                 else:
                     obj = self.parse_attrib(cfg, attrib)
@@ -112,8 +122,8 @@ class Ospfv3Facts(object):
         :return: generated rule configuration dictionary.
         """
 
-        rule = self.parse_attrib(conf, 'area_id', match=area_id)
-        r_sub = {'range': self.parse_attrib_list(conf, 'range', 'address')}
+        rule = self.parse_attrib(conf, "area_id", match=area_id)
+        r_sub = {"range": self.parse_attrib_list(conf, "range", "address")}
         rule.update(r_sub)
         return rule
 
@@ -124,11 +134,11 @@ class Ospfv3Facts(object):
         :return: generated configuration dictionary
         """
         param_lst = {
-            'area_id': ['export_list', 'import_list'],
-            'redistribute': ["route_map"],
-            'range': ["advertise", "not_advertise"],
-            'parameters': ["router_id"]
-            }
+            "area_id": ["export_list", "import_list"],
+            "redistribute": ["route_map"],
+            "range": ["advertise", "not_advertise"],
+            "parameters": ["router_id"],
+        }
         cfg_dict = self.parse_attr(conf, param_lst[param], match)
         return cfg_dict
 
@@ -176,7 +186,13 @@ class Ospfv3Facts(object):
         :param attrib: attribute
         :return: regex string
         """
-        return 'disable' if attrib == "disabled" else 'enable' if attrib == "enabled" else attrib.replace("_","-")
+        return (
+            "disable"
+            if attrib == "disabled"
+            else "enable"
+            if attrib == "enabled"
+            else attrib.replace("_", "-")
+        )
 
     def is_bool(self, attrib):
         """
@@ -193,5 +209,5 @@ class Ospfv3Facts(object):
         :param attrib: attribute.
         :return: True/false.
         """
-        num_set = ("ospf")
+        num_set = "ospf"
         return True if attrib in num_set else False
diff --git a/plugins/module_utils/network/vyos/utils/utils.py b/plugins/module_utils/network/vyos/utils/utils.py
index 2d5b74b7..f2986aa5 100644
--- a/plugins/module_utils/network/vyos/utils/utils.py
+++ b/plugins/module_utils/network/vyos/utils/utils.py
@@ -232,13 +232,21 @@ def get_route_type(address):
     elif version == 4:
         return "route"
 
+
 def _bool_to_str(val):
     """
     This function converts the bool value into string.
     :param val: bool value.
     :return: enable/disable.
     """
-    return "enable" if str(val) == "True" else "disable" if str(val) == "False" else val
+    return (
+        "enable"
+        if str(val) == "True"
+        else "disable"
+        if str(val) == "False"
+        else val
+    )
+
 
 def _is_w_same(w, h, key):
     """
@@ -251,6 +259,7 @@ def _is_w_same(w, h, key):
     """
     return True if h and key in h and h[key] == w[key] else False
 
+
 def _in_target(h, key):
     """
     This function checks whether the target exist and key present in target config.
diff --git a/plugins/modules/vyos_ospfv3.py b/plugins/modules/vyos_ospfv3.py
index e620fe10..ae93500a 100644
--- a/plugins/modules/vyos_ospfv3.py
+++ b/plugins/modules/vyos_ospfv3.py
@@ -27,21 +27,23 @@ The module file for vyos_ospfv3
 """
 
 from __future__ import absolute_import, division, print_function
+
 __metaclass__ = type
 
-ANSIBLE_METADATA = {
-    'metadata_version': '1.1',
-    'status': ['preview'],
-    'supported_by': 'network'
-}
+ANSIBLE_METADATA = {"metadata_version": "1.1", "supported_by": "Ansible"}
 
 DOCUMENTATION = """
 ---
 module: vyos_ospfv3
 version_added: 2.10
-short_description: OSPFv3 resource module.
+short_description: OSPFV3 resource module.
 description: This resource module configures and manages attributes of OSPFv3 routes on VyOS network devices.
-author: Rohit Thakur (@rohitthakur2590)
+version_added: "1.0.0"
+notes:
+  - Tested against VyOS 1.1.8 (helium).
+  - This module works with connection C(network_cli). See L(the VyOS OS Platform Options,../network/user_guide/platform_vyos.html).
+author:
+- Rohit Thakur (@rohitthakur2590)
 options:
   config:
     description: A provided OSPFv3 route configuration.
@@ -96,7 +98,12 @@ options:
             type: str 
   running_config:
     description:
-      - The configuration to be parsed.
+      - This option is used only with state I(parsed).
+      - The value of this option should be the output received from the VyOS device by executing
+        the command B(show configuration commands | grep ospfv3).
+      - The state I(parsed) reads the configuration from C(running_config) option and transforms
+        it into Ansible structured data as per the resource module's argspec and the value is then
+        returned in the I(parsed) key within the result.
     type: str
   state:
     description:
@@ -112,22 +119,493 @@ options:
     default: merged
 """
 EXAMPLES = """
+# Using merged
+#
+# Before state:
+# -------------
+#
+# vyos@vyos# run show  configuration commands | grep ospfv3
+#
+#
+- name: Merge the provided configuration with the exisiting running configuration
+      vyos.vyos.vyos_ospfv3:
+        config:
+           redistribute:
+             - route_type: 'bgp'
+           parameters:
+             router_id: '192.0.2.10'
+           areas:
+             - area_id: '2'
+               export_list: 'export1'
+               import_list: 'import1'
 
+               range:
+                 - address: '2001:db10::/32'
+                 - address: '2001:db20::/32'
+                 - address: '2001:db30::/32'
+             - area_id: '3'
+               range:
+                 - address: '2001:db40::/32'
+        state: merged
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+# before": {}
+#
+#    "commands": [
+#       "set protocols ospfv3 redistribute bgp",
+#       "set protocols ospfv3 parameters router-id '192.0.2.10'",
+#       "set protocols ospfv3 area 2 range 2001:db10::/32",
+#       "set protocols ospfv3 area 2 range 2001:db20::/32",
+#       "set protocols ospfv3 area 2 range 2001:db30::/32",
+#       "set protocols ospfv3 area '2'",
+#       "set protocols ospfv3 area 2 export-list export1",
+#       "set protocols ospfv3 area 2 import-list import1",
+#       "set protocols ospfv3 area '3'",
+#       "set protocols ospfv3 area 3 range 2001:db40::/32"
+#    ]
+#
+# "after": {
+#        "areas": [
+#            {
+#                "area_id": "2",
+#                "export_list": "export1",
+#                "import_list": "import1",
+#                "range": [
+#                    {
+#                        "address": "2001:db10::/32"
+#                    },
+#                    {
+#                        "address": "2001:db20::/32"
+#                    },
+#                    {
+#                        "address": "2001:db30::/32"
+#                    }
+#                ]
+#            },
+#            {
+#                "area_id": "3",
+#                "range": [
+#                    {
+#                        "address": "2001:db40::/32"
+#                    }
+#                ]
+#            }
+#        ],
+#        "parameters": {
+#            "router_id": "192.0.2.10"
+#        },
+#        "redistribute": [
+#            {
+#                "route_type": "bgp"
+#            }
+#        ]
+#    }
+#
+# After state:
+# -------------
+#
+# vyos@192# run show configuration commands | grep ospfv3
+# set protocols ospfv3 area 2 export-list 'export1'
+# set protocols ospfv3 area 2 import-list 'import1'
+# set protocols ospfv3 area 2 range '2001:db10::/32'
+# set protocols ospfv3 area 2 range '2001:db20::/32'
+# set protocols ospfv3 area 2 range '2001:db30::/32'
+# set protocols ospfv3 area 3 range '2001:db40::/32'
+# set protocols ospfv3 parameters router-id '192.0.2.10'
+# set protocols ospfv3 redistribute 'bgp'
 
 
+# Using replaced
+#
+# Before state:
+# -------------
+#
+# vyos@192# run show configuration commands | grep ospfv3
+# set protocols ospfv3 area 2 export-list 'export1'
+# set protocols ospfv3 area 2 import-list 'import1'
+# set protocols ospfv3 area 2 range '2001:db10::/32'
+# set protocols ospfv3 area 2 range '2001:db20::/32'
+# set protocols ospfv3 area 2 range '2001:db30::/32'
+# set protocols ospfv3 area 3 range '2001:db40::/32'
+# set protocols ospfv3 parameters router-id '192.0.2.10'
+# set protocols ospfv3 redistribute 'bgp'
+#
+- name: Replace ospfv3 routes attributes configuration.
+      vyos.vyos.vyos_ospfv3:
+        config:
+           redistribute:
+             - route_type: 'bgp'
+           parameters:
+             router_id: '192.0.2.10'
+           areas:
+             - area_id: '2'
+               export_list: 'export1'
+               import_list: 'import1'
 
+               range:
+                 - address: '2001:db10::/32'
+                 - address: '2001:db30::/32'
+                 - address: '2001:db50::/32'
+             - area_id: '4'
+               range:
+                 - address: '2001:db60::/32'
+        state: replaced
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#    "before": {
+#        "areas": [
+#            {
+#                "area_id": "2",
+#                "export_list": "export1",
+#                "import_list": "import1",
+#                "range": [
+#                    {
+#                        "address": "2001:db10::/32"
+#                    },
+#                    {
+#                        "address": "2001:db20::/32"
+#                    },
+#                    {
+#                        "address": "2001:db30::/32"
+#                    }
+#                ]
+#            },
+#            {
+#                "area_id": "3",
+#                "range": [
+#                    {
+#                        "address": "2001:db40::/32"
+#                    }
+#                ]
+#            }
+#        ],
+#        "parameters": {
+#            "router_id": "192.0.2.10"
+#        },
+#        "redistribute": [
+#            {
+#                "route_type": "bgp"
+#            }
+#        ]
+#    }
+#
+# "commands": [
+#     "delete protocols ospfv3 area 2 range 2001:db20::/32",
+#     "delete protocols ospfv3 area 3",
+#     "set protocols ospfv3 area 2 range 2001:db50::/32",
+#     "set protocols ospfv3 area '4'",
+#     "set protocols ospfv3 area 4 range 2001:db60::/32"
+#    ]
+#
+#    "after": {
+#        "areas": [
+#            {
+#                "area_id": "2",
+#                "export_list": "export1",
+#                "import_list": "import1",
+#                "range": [
+#                    {
+#                        "address": "2001:db10::/32"
+#                    },
+#                    {
+#                        "address": "2001:db30::/32"
+#                    },
+#                    {
+#                        "address": "2001:db50::/32"
+#                    }
+#                ]
+#            },
+#            {
+#                "area_id": "4",
+#                "range": [
+#                    {
+#                        "address": "2001:db60::/32"
+#                    }
+#                ]
+#            }
+#        ],
+#        "parameters": {
+#            "router_id": "192.0.2.10"
+#        },
+#        "redistribute": [
+#            {
+#                "route_type": "bgp"
+#            }
+#        ]
+#    }
+#
+# After state:
+# -------------
+#
+# vyos@192# run show configuration commands | grep ospfv3
+# set protocols ospfv3 area 2 export-list 'export1'
+# set protocols ospfv3 area 2 import-list 'import1'
+# set protocols ospfv3 area 2 range '2001:db10::/32'
+# set protocols ospfv3 area 2 range '2001:db30::/32'
+# set protocols ospfv3 area 2 range '2001:db50::/32'
+# set protocols ospfv3 area 4 range '2001:db60::/32'
+# set protocols ospfv3 parameters router-id '192.0.2.10'
+# set protocols ospfv3 redistribute 'bgp'
 
 
+# Using rendered
+#
+#
+- name: Render the commands for provided  configuration
+      vyos.vyos.vyos_ospfv3:
+        config:
+           redistribute:
+             - route_type: 'bgp'
+           parameters:
+             router_id: '192.0.2.10'
+           areas:
+             - area_id: '2'
+               export_list: 'export1'
+               import_list: 'import1'
 
+               range:
+                 - address: '2001:db10::/32'
+                 - address: '2001:db20::/32'
+                 - address: '2001:db30::/32'
+             - area_id: '3'
+               range:
+                 - address: '2001:db40::/32'
+        state: rendered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "rendered": [
+#        [
+#       "set protocols ospfv3 redistribute bgp",
+#       "set protocols ospfv3 parameters router-id '192.0.2.10'",
+#       "set protocols ospfv3 area 2 range 2001:db10::/32",
+#       "set protocols ospfv3 area 2 range 2001:db20::/32",
+#       "set protocols ospfv3 area 2 range 2001:db30::/32",
+#       "set protocols ospfv3 area '2'",
+#       "set protocols ospfv3 area 2 export-list export1",
+#       "set protocols ospfv3 area 2 import-list import1",
+#       "set protocols ospfv3 area '3'",
+#       "set protocols ospfv3 area 3 range 2001:db40::/32"
+#    ]
 
 
+# Using parsed
+#
+#
+- name: Parse the commands to provide structured configuration.
+      vyos.vyos.vyos_ospfv3:
+        running_config:
+          "set protocols ospfv3 area 2 export-list 'export1'
+set protocols ospfv3 area 2 import-list 'import1'
+set protocols ospfv3 area 2 range '2001:db10::/32'
+set protocols ospfv3 area 2 range '2001:db20::/32'
+set protocols ospfv3 area 2 range '2001:db30::/32'
+set protocols ospfv3 area 3 range '2001:db40::/32'
+set protocols ospfv3 parameters router-id '192.0.2.10'
+set protocols ospfv3 redistribute 'bgp'"
+        state: parsed
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#
+# "parsed": {
+#        "areas": [
+#            {
+#                "area_id": "2",
+#                "export_list": "export1",
+#                "import_list": "import1",
+#                "range": [
+#                    {
+#                        "address": "2001:db10::/32"
+#                    },
+#                    {
+#                        "address": "2001:db20::/32"
+#                    },
+#                    {
+#                        "address": "2001:db30::/32"
+#                    }
+#                ]
+#            },
+#            {
+#                "area_id": "3",
+#                "range": [
+#                    {
+#                        "address": "2001:db40::/32"
+#                    }
+#                ]
+#            }
+#        ],
+#        "parameters": {
+#            "router_id": "192.0.2.10"
+#        },
+#        "redistribute": [
+#            {
+#                "route_type": "bgp"
+#            }
+#        ]
+#    }
 
 
+# Using gathered
+#
+# Before state:
+# -------------
+#
+# vyos@192# run show configuration commands | grep ospfv3
+# set protocols ospfv3 area 2 export-list 'export1'
+# set protocols ospfv3 area 2 import-list 'import1'
+# set protocols ospfv3 area 2 range '2001:db10::/32'
+# set protocols ospfv3 area 2 range '2001:db20::/32'
+# set protocols ospfv3 area 2 range '2001:db30::/32'
+# set protocols ospfv3 area 3 range '2001:db40::/32'
+# set protocols ospfv3 parameters router-id '192.0.2.10'
+# set protocols ospfv3 redistribute 'bgp'
+#
+- name: Gather ospfv3 routes config with provided configurations
+      vyos.vyos.vyos_ospfv3:
+          config:
+          state: gathered
+#
+#
+# -------------------------
+# Module Execution Result
+# -------------------------
+#
+#    "gathered": {
+#        "areas": [
+#            {
+#                "area_id": "2",
+#                "export_list": "export1",
+#                "import_list": "import1",
+#                "range": [
+#                    {
+#                        "address": "2001:db10::/32"
+#                    },
+#                    {
+#                        "address": "2001:db20::/32"
+#                    },
+#                    {
+#                        "address": "2001:db30::/32"
+#                    }
+#                ]
+#            },
+#            {
+#                "area_id": "3",
+#                "range": [
+#                    {
+#                        "address": "2001:db40::/32"
+#                    }
+#                ]
+#            }
+#        ],
+#        "parameters": {
+#            "router_id": "192.0.2.10"
+#        },
+#        "redistribute": [
+#            {
+#                "route_type": "bgp"
+#            }
+#        ]
+#    }
+#
+# After state:
+# -------------
+#
+# vyos@192# run show configuration commands | grep ospfv3
+# set protocols ospfv3 area 2 export-list 'export1'
+# set protocols ospfv3 area 2 import-list 'import1'
+# set protocols ospfv3 area 2 range '2001:db10::/32'
+# set protocols ospfv3 area 2 range '2001:db20::/32'
+# set protocols ospfv3 area 2 range '2001:db30::/32'
+# set protocols ospfv3 area 3 range '2001:db40::/32'
+# set protocols ospfv3 parameters router-id '192.0.2.10'
+# set protocols ospfv3 redistribute 'bgp'
 
 
-
-
-
+# Using deleted
+#
+# Before state
+# -------------
+#
+# vyos@192# run show configuration commands | grep ospfv3
+# set protocols ospfv3 area 2 export-list 'export1'
+# set protocols ospfv3 area 2 import-list 'import1'
+# set protocols ospfv3 area 2 range '2001:db10::/32'
+# set protocols ospfv3 area 2 range '2001:db20::/32'
+# set protocols ospfv3 area 2 range '2001:db30::/32'
+# set protocols ospfv3 area 3 range '2001:db40::/32'
+# set protocols ospfv3 parameters router-id '192.0.2.10'
+# set protocols ospfv3 redistribute 'bgp'
+#
+- name: Delete attributes of ospfv3 routes.
+      vyos.vyos.vyos_ospfv3:
+        config:
+        state: deleted
+#
+#
+# ------------------------
+# Module Execution Results
+# ------------------------
+#
+#    "before": {
+#        "areas": [
+#            {
+#                "area_id": "2",
+#                "export_list": "export1",
+#                "import_list": "import1",
+#                "range": [
+#                    {
+#                        "address": "2001:db10::/32"
+#                    },
+#                    {
+#                        "address": "2001:db20::/32"
+#                    },
+#                    {
+#                        "address": "2001:db30::/32"
+#                    }
+#                ]
+#            },
+#            {
+#                "area_id": "3",
+#                "range": [
+#                    {
+#                        "address": "2001:db40::/32"
+#                    }
+#                ]
+#            }
+#        ],
+#        "parameters": {
+#            "router_id": "192.0.2.10"
+#        },
+#        "redistribute": [
+#            {
+#                "route_type": "bgp"
+#            }
+#        ]
+#    }
+# "commands": [
+#        "delete protocols ospfv3"
+#    ]
+#
+# "after": {}
+# After state
+# ------------
+# vyos@192# run show configuration commands | grep ospfv3
 
 
 """
@@ -135,12 +613,14 @@ RETURN = """
 before:
   description: The configuration prior to the model invocation.
   returned: always
+  type: dict
   sample: >
     The configuration returned will always be in the same format
      of the parameters above.
 after:
   description: The resulting configuration model invocation.
   returned: when changed
+  type: dict
   sample: >
     The configuration returned will always be in the same format
      of the parameters above.
@@ -148,13 +628,18 @@ commands:
   description: The set of commands pushed to the remote device.
   returned: always
   type: list
-  sample: ['command 1', 'command 2', 'command 3']
+  sample: ['set protocols ospf parameters router-id 192.0.1.1',
+           'set protocols ospfv3 area 2 range '2001:db10::/32']
 """
 
 
 from ansible.module_utils.basic import AnsibleModule
-from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv3.ospfv3 import Ospfv3Args
-from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv3.ospfv3 import Ospfv3
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.ospfv3.ospfv3 import (
+    Ospfv3Args,
+)
+from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.config.ospfv3.ospfv3 import (
+    Ospfv3,
+)
 
 
 def main():
@@ -166,6 +651,7 @@ def main():
     required_if = [
         ("state", "merged", ("config",)),
         ("state", "replaced", ("config",)),
+        ("state", "rendered", ("config",)),
         ("state", "parsed", ("running_config",)),
     ]
     mutually_exclusive = [("config", "running_config")]
@@ -180,5 +666,5 @@ def main():
     module.exit_json(**result)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()
diff --git a/tests/integration/targets/vyos_ospfv3/defaults/main.yaml b/tests/integration/targets/vyos_ospfv3/defaults/main.yaml
new file mode 100644
index 00000000..852a6bee
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/defaults/main.yaml
@@ -0,0 +1,3 @@
+---
+testcase: '[^_].*'
+test_items: []
diff --git a/tests/integration/targets/vyos_ospfv3/meta/main.yaml b/tests/integration/targets/vyos_ospfv3/meta/main.yaml
new file mode 100644
index 00000000..7413320e
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/meta/main.yaml
@@ -0,0 +1,3 @@
+---
+dependencies:
+  - prepare_vyos_tests
diff --git a/tests/integration/targets/vyos_ospfv3/tasks/cli.yaml b/tests/integration/targets/vyos_ospfv3/tasks/cli.yaml
new file mode 100644
index 00000000..93eb2fe4
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tasks/cli.yaml
@@ -0,0 +1,19 @@
+---
+- name: Collect all cli test cases
+  find:
+    paths: '{{ role_path }}/tests/cli'
+    patterns: '{{ testcase }}.yaml'
+    use_regex: true
+  register: test_cases
+  delegate_to: localhost
+
+- name: Set test_items
+  set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
+
+- name: Run test case (connection=ansible.netcommon.network_cli)
+  include: '{{ test_case_to_run }}'
+  vars:
+    ansible_connection: ansible.netcommon.network_cli
+  with_items: '{{ test_items }}'
+  loop_control:
+    loop_var: test_case_to_run
diff --git a/tests/integration/targets/vyos_ospfv3/tasks/main.yaml b/tests/integration/targets/vyos_ospfv3/tasks/main.yaml
new file mode 100644
index 00000000..a3db933e
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tasks/main.yaml
@@ -0,0 +1,4 @@
+---
+- include: cli.yaml
+  tags:
+    - cli
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/_parsed_config.cfg b/tests/integration/targets/vyos_ospfv3/tests/cli/_parsed_config.cfg
new file mode 100644
index 00000000..5e012d5a
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/_parsed_config.cfg
@@ -0,0 +1,8 @@
+set protocols ospfv3 area 2 export-list 'export1'
+set protocols ospfv3 area 2 import-list 'import1'
+set protocols ospfv3 area 2 range '2001:db10::/32'
+set protocols ospfv3 area 2 range '2001:db20::/32'
+set protocols ospfv3 area 2 range '2001:db30::/32'
+set protocols ospfv3 area 3 range '2001:db40::/32'
+set protocols ospfv3 parameters router-id '192.0.2.10'
+set protocols ospfv3 redistribute 'bgp'
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/_populate.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/_populate.yaml
new file mode 100644
index 00000000..fb66d0a5
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/_populate.yaml
@@ -0,0 +1,13 @@
+---
+- name: Setup
+  vars:
+    lines: "set protocols ospfv3 area 2 export-list 'export1' \n
+            set protocols ospfv3 area 2 import-list 'import1' \n
+            set protocols ospfv3 area 2 range '2001:db10::/32' \n
+            set protocols ospfv3 area 2 range '2001:db20::/32' \n
+            set protocols ospfv3 area 2 range '2001:db30::/32' \n
+            set protocols ospfv3 area 3 range '2001:db40::/32' \n
+            set protocols ospfv3 parameters router-id '192.0.2.10' \n
+            set protocols ospfv3 redistribute 'bgp'"
+  ansible.netcommon.cli_config:
+    config: '{{ lines }}'
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/_remove_config.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/_remove_config.yaml
new file mode 100644
index 00000000..2a475050
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/_remove_config.yaml
@@ -0,0 +1,6 @@
+---
+- name: Remove Config
+  vars:
+    lines: "delete protocols ospfv3\n"
+  ansible.netcommon.cli_config:
+    config: '{{ lines }}'
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/deleted.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/deleted.yaml
new file mode 100644
index 00000000..d400ff18
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/deleted.yaml
@@ -0,0 +1,48 @@
+---
+- debug:
+    msg: Start vyos_ospfv3 deleted integration tests ansible_connection={{
+      ansible_connection }}
+
+- include_tasks: _populate.yaml
+
+- block:
+
+    - name: Delete attributes of firewall.
+      register: result
+      vyos.vyos.vyos_ospfv3: &id001
+        config:
+        state: deleted
+
+    - name: Assert that the before dicts were correctly generated
+      assert:
+        that:
+          - "{{ populate == result['before'] }}"
+
+    - name: Assert that the correct set of commands were generated
+      assert:
+        that:
+          - "{{ deleted['commands'] | symmetric_difference(result['commands']) |length\
+            \ == 0 }}"
+
+    - name: Assert that the after dicts were correctly generated
+      assert:
+        that:
+          - "{{ deleted['after'] == result['after'] }}"
+
+    - name: Delete attributes of given interfaces (IDEMPOTENT)
+      register: result
+      vyos.vyos.vyos_ospfv3: *id001
+
+    - name: Assert that the previous task was idempotent
+      assert:
+        that:
+          - result.changed == false
+          - result.commands|length == 0
+
+    - name: Assert that the before dicts were correctly generated
+      assert:
+        that:
+          - "{{ deleted['after'] == result['before'] }}"
+  always:
+
+    - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/empty_config.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/empty_config.yaml
new file mode 100644
index 00000000..fec61abf
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/empty_config.yaml
@@ -0,0 +1,49 @@
+---
+- debug:
+    msg: START vyos_ospfv3 empty_config integration tests on connection={{
+      ansible_connection }}
+
+- name: Merged with empty config should give appropriate error message
+  register: result
+  ignore_errors: true
+  vyos.vyos.vyos_ospfv3:
+    config:
+    state: merged
+
+- assert:
+    that:
+      - result.msg == 'value of config parameter must not be empty for state merged'
+
+- name: Replaced with empty config should give appropriate error message
+  register: result
+  ignore_errors: true
+  vyos.vyos.vyos_ospfv3:
+    config:
+    state: replaced
+
+- assert:
+    that:
+      - result.msg == 'value of config parameter must not be empty for state replaced'
+
+- name: Parsed with empty running_config should give appropriate error message
+  register: result
+  ignore_errors: true
+  vyos.vyos.vyos_ospfv3:
+    running_config:
+    state: parsed
+
+- assert:
+    that:
+      - result.msg == 'value of running_config parameter must not be empty for state
+        parsed'
+
+- name: Rendered with empty config should give appropriate error message
+  register: result
+  ignore_errors: true
+  vyos.vyos.vyos_ospfv3:
+    config:
+    state: rendered
+
+- assert:
+    that:
+      - result.msg == 'value of config parameter must not be empty for state rendered'
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/gathered.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/gathered.yaml
new file mode 100644
index 00000000..6645b99f
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/gathered.yaml
@@ -0,0 +1,25 @@
+---
+- debug:
+    msg: START vyos_ospfv3 gathered integration tests on connection={{
+      ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- include_tasks: _populate.yaml
+
+- block:
+
+    - name: Gather the provided configuration with the exisiting running configuration
+      register: result
+      vyos.vyos.vyos_ospfv3:
+        config:
+        state: gathered
+
+    - name: Assert that gathered dicts was correctly generated
+      assert:
+        that:
+          - "{{ populate  == result['gathered'] }}"
+
+  always:
+
+    - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/merged.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/merged.yaml
new file mode 100644
index 00000000..93095009
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/merged.yaml
@@ -0,0 +1,62 @@
+---
+- debug:
+    msg: START vyos_ospfv3 merged integration tests on connection={{ ansible_connection
+      }}
+
+- include_tasks: _remove_config.yaml
+
+- block:
+
+    - name: Merge the provided configuration with the exisiting running configuration
+      register: result
+      vyos.vyos.vyos_ospfv3: &id001
+        config:
+          areas:
+            - area_id: '2'
+              export_list: 'export1'
+              import_list: 'import1'
+              range:
+                - address: '2001:db10::/32'
+                - address: '2001:db20::/32'
+                - address: '2001:db30::/32'
+            - area_id: '3'
+              range:
+                - address: '2001:db40::/32'
+          parameters:
+            router_id: '192.0.2.10'
+          redistribute:
+            - route_type: 'bgp'
+        state: merged
+
+    - name: Assert that before dicts were correctly generated
+      assert:
+        that: "{{ merged['before'] == result['before'] }}"
+
+    - name: Assert that correct set of commands were generated
+      assert:
+        that:
+          - "{{ merged['commands'] | symmetric_difference(result['commands']) |length\
+            \ == 0 }}"
+
+    - name: Assert that after dicts was correctly generated
+      assert:
+        that:
+          - "{{ merged['after'] == result['after'] }}"
+
+    - name: Merge the provided configuration with the existing running configuration
+        (IDEMPOTENT)
+      register: result
+      vyos.vyos.vyos_ospfv3: *id001
+
+    - name: Assert that the previous task was idempotent
+      assert:
+        that:
+          - result['changed'] == false
+
+    - name: Assert that before dicts were correctly generated
+      assert:
+        that:
+          - "{{ merged['after'] == result['before'] }}"
+  always:
+
+    - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/merged_update.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/merged_update.yaml
new file mode 100644
index 00000000..a65cfaf4
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/merged_update.yaml
@@ -0,0 +1,61 @@
+---
+- debug:
+    msg: START vyos_ospfv3 merged integration tests on connection={{ ansible_connection
+      }}
+
+- include_tasks: _remove_config.yaml
+
+- include_tasks: _populate.yaml
+
+- block:
+
+    - name: Merge the provided configuration with the exisiting running configuration
+      register: result
+      vyos.vyos.vyos_ospfv3: &id001
+        config:
+          areas:
+            - area_id: '2'
+              range:
+                - address: '2001:db10::/32'
+            - area_id: '3'
+              range:
+                - address: '2001:db40::/32'
+                - address: '2001:db70::/32'
+          parameters:
+            router_id: '192.0.2.10'
+          redistribute:
+            - route_type: 'bgp'
+        state: merged
+
+    - name: Assert that before dicts were correctly generated
+      assert:
+        that: "{{ populate == result['before'] }}"
+
+    - name: Assert that correct set of commands were generated
+      assert:
+        that:
+          - "{{ merged_update['commands'] | symmetric_difference(result['commands']) |length\
+            \ == 0 }}"
+
+    - name: Assert that after dicts was correctly generated
+      assert:
+        that:
+          - "{{ merged_update['after'] == result['after'] }}"
+
+    - name: Merge the provided configuration with the existing running configuration
+        (IDEMPOTENT)
+      register: result
+      vyos.vyos.vyos_ospfv3: *id001
+
+    - name: Assert that the previous task was idempotent
+      assert:
+        that:
+          - result['changed'] == false
+
+    - name: Assert that before dicts were correctly generated
+      assert:
+        that:
+          - "{{ merged_update['after'] == result['before'] }}"
+  always:
+
+    - include_tasks: _remove_config.yaml
\ No newline at end of file
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/parsed.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/parsed.yaml
new file mode 100644
index 00000000..62870831
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/parsed.yaml
@@ -0,0 +1,15 @@
+---
+- debug:
+    msg: START vyos_ospfv3 parsed integration tests on connection={{ ansible_connection
+      }}
+
+- name: Parse externally provided ospfv3 config to agnostic model
+  register: result
+  vyos.vyos.vyos_ospfv3:
+    running_config: "{{ lookup('file', '_parsed_config.cfg') }}"
+    state: parsed
+
+- name: Assert that config was correctly parsed
+  assert:
+    that:
+      - "{{ parsed['after'] == result['parsed'] }}"
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/rendered.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/rendered.yaml
new file mode 100644
index 00000000..3f714ced
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/rendered.yaml
@@ -0,0 +1,38 @@
+---
+- debug:
+    msg: START vyos_ospfv3 rendered integration tests on connection={{
+      ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- block:
+
+    - name: Structure provided configuration into device specific commands
+      register: result
+      vyos.vyos.vyos_ospfv3:
+        config:
+          redistribute:
+            - route_type: 'bgp'
+          parameters:
+            router_id: '192.0.2.10'
+          areas:
+            - area_id: '2'
+              export_list: 'export1'
+              import_list: 'import1'
+              range:
+                - address: '2001:db10::/32'
+                - address: '2001:db20::/32'
+                - address: '2001:db30::/32'
+            - area_id: '3'
+              range:
+                - address: '2001:db40::/32'
+        state: rendered
+
+    - name: Assert that correct set of commands were generated
+      assert:
+        that:
+          - "{{ rendered['commands'] | symmetric_difference(result['rendered'])\
+            \ |length == 0 }}"
+
+- debug:
+    msg: END vyos_ospfv3 rendered integration tests on connection={{ ansible_connection }}
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/replaced.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/replaced.yaml
new file mode 100644
index 00000000..74d25dbf
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/replaced.yaml
@@ -0,0 +1,66 @@
+---
+- debug:
+    msg: START vyos_ospfv3 replaced integration tests on connection={{
+      ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- include_tasks: _populate.yaml
+
+- block:
+
+    - name: Replace device configurations of listed ospfv3 routes with provided configurations
+      register: result
+      vyos.vyos.vyos_ospfv3: &id001
+        config:
+          redistribute:
+            - route_type: 'bgp'
+          parameters:
+            router_id: '192.0.2.10'
+          areas:
+            - area_id: '2'
+              export_list: 'export1'
+              import_list: 'import1'
+
+              range:
+                - address: '2001:db10::/32'
+                - address: '2001:db30::/32'
+                - address: '2001:db50::/32'
+            - area_id: '4'
+              range:
+                - address: '2001:db60::/32'
+        state: replaced
+
+    - name: Assert that correct set of commands were generated
+      assert:
+        that:
+          - "{{ replaced['commands'] | symmetric_difference(result['commands'])\
+            \ |length == 0 }}"
+
+    - name: Assert that before dicts are correctly generated
+      assert:
+        that:
+          - "{{ populate == result['before'] }}"
+
+    - name: Assert that after dict is correctly generated
+      assert:
+        that:
+          - "{{ replaced['after'] == result['after'] }}"
+
+    - name: Replace device configurations of listed ospfv3 routes with provided configurarions
+        (IDEMPOTENT)
+      register: result
+      vyos.vyos.vyos_ospfv3: *id001
+
+    - name: Assert that task was idempotent
+      assert:
+        that:
+          - result['changed'] == false
+
+    - name: Assert that before dict is correctly generated
+      assert:
+        that:
+          - "{{ replaced['after'] == result['before'] }}"
+  always:
+
+    - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ospfv3/tests/cli/rtt.yaml b/tests/integration/targets/vyos_ospfv3/tests/cli/rtt.yaml
new file mode 100644
index 00000000..d8175540
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/tests/cli/rtt.yaml
@@ -0,0 +1,75 @@
+---
+- debug:
+    msg: START vyos_ospfv3 round trip integration tests on connection={{
+      ansible_connection }}
+
+- include_tasks: _remove_config.yaml
+
+- block:
+
+    - name: Apply the provided configuration (base config)
+      register: base_config
+      vyos.vyos.vyos_ospfv3:
+        config:
+          areas:
+            - area_id: '2'
+              export_list: 'export1'
+              import_list: 'import1'
+              range:
+                - address: '2001:db10::/32'
+                - address: '2001:db20::/32'
+                - address: '2001:db30::/32'
+            - area_id: '3'
+              range:
+                - address: '2001:db40::/32'
+          parameters:
+            router_id: '192.0.2.10'
+          redistribute:
+            - route_type: 'bgp'
+        state: merged
+
+    - name: Gather ospfv3 facts
+      vyos.vyos.vyos_facts:
+        gather_subset:
+          - default
+        gather_network_resources:
+          - ospfv3
+
+    - name: Apply the provided configuration (config to be reverted)
+      register: result
+      vyos.vyos.vyos_ospfv3:
+        config:
+          redistribute:
+            - route_type: 'bgp'
+          parameters:
+            router_id: '192.0.2.10'
+          areas:
+            - area_id: '2'
+              export_list: 'export1'
+              import_list: 'import1'
+
+              range:
+                - address: '2001:db10::/32'
+                - address: '2001:db30::/32'
+                - address: '2001:db50::/32'
+            - area_id: '4'
+              range:
+                - address: '2001:db60::/32'
+        state: replaced
+
+    - name: Assert that changes were applied
+      assert:
+        that: "{{ round_trip['after'] == result['after'] }}"
+
+    - name: Revert back to base config using facts round trip
+      register: revert
+      vyos.vyos.vyos_ospfv3:
+        config: "{{ ansible_facts['network_resources']['ospfv3'] }}"
+        state: replaced
+
+    - name: Assert that config was reverted
+      assert:
+        that: "{{ base_config['after'] == revert['after']}}"
+  always:
+
+    - include_tasks: _remove_config.yaml
diff --git a/tests/integration/targets/vyos_ospfv3/vars/main.yaml b/tests/integration/targets/vyos_ospfv3/vars/main.yaml
new file mode 100644
index 00000000..d384e2a1
--- /dev/null
+++ b/tests/integration/targets/vyos_ospfv3/vars/main.yaml
@@ -0,0 +1,140 @@
+---
+merged:
+  before: {}
+  commands:
+    - set protocols ospfv3 redistribute bgp
+    - set protocols ospfv3 parameters router-id '192.0.2.10'
+    - set protocols ospfv3 area 2 range 2001:db10::/32
+    - set protocols ospfv3 area 2 range 2001:db20::/32
+    - set protocols ospfv3 area 2 range 2001:db30::/32
+    - set protocols ospfv3 area '2'
+    - set protocols ospfv3 area 2 export-list export1
+    - set protocols ospfv3 area 2 import-list import1
+    - set protocols ospfv3 area '3'
+    - set protocols ospfv3 area 3 range 2001:db40::/32
+  after:
+      areas:
+        - area_id: '2'
+          export_list: 'export1'
+          import_list: 'import1'
+          range:
+            - address: '2001:db10::/32'
+            - address: '2001:db20::/32'
+            - address: '2001:db30::/32'
+        - area_id: '3'
+          range:
+            - address: '2001:db40::/32'
+      parameters:
+        router_id: '192.0.2.10'
+      redistribute:
+        - route_type: 'bgp'
+
+merged_update:
+  commands:
+    - set protocols ospfv3 area 3 range 2001:db70::/32
+  after:
+      areas:
+        - area_id: '2'
+          export_list: 'export1'
+          import_list: 'import1'
+          range:
+            - address: '2001:db10::/32'
+            - address: '2001:db20::/32'
+            - address: '2001:db30::/32'
+        - area_id: '3'
+          range:
+            - address: '2001:db40::/32'
+            - address: '2001:db70::/32'
+      parameters:
+        router_id: '192.0.2.10'
+      redistribute:
+        - route_type: 'bgp'
+populate:
+  areas:
+    - area_id: '2'
+      export_list: 'export1'
+      import_list: 'import1'
+      range:
+        - address: '2001:db10::/32'
+        - address: '2001:db20::/32'
+        - address: '2001:db30::/32'
+    - area_id: '3'
+      range:
+        - address: '2001:db40::/32'
+  parameters:
+    router_id: '192.0.2.10'
+  redistribute:
+    - route_type: 'bgp'
+replaced:
+  commands:
+    - delete protocols ospfv3 area 2 range 2001:db20::/32
+    - delete protocols ospfv3 area 3
+    - set protocols ospfv3 area 2 range 2001:db50::/32
+    - set protocols ospfv3 area '4'
+    - set protocols ospfv3 area 4 range 2001:db60::/32
+  after:
+    areas:
+      - area_id: '2'
+        export_list: 'export1'
+        import_list: 'import1'
+        range:
+          - address: '2001:db10::/32'
+          - address: '2001:db30::/32'
+          - address: '2001:db50::/32'
+      - area_id: '4'
+        range:
+          - address: '2001:db60::/32'
+    parameters:
+      router_id: '192.0.2.10'
+    redistribute:
+      - route_type: 'bgp'
+rendered:
+  commands:
+    - set protocols ospfv3 redistribute bgp
+    - set protocols ospfv3 parameters router-id '192.0.2.10'
+    - set protocols ospfv3 area 2 range 2001:db10::/32
+    - set protocols ospfv3 area 2 range 2001:db20::/32
+    - set protocols ospfv3 area 2 range 2001:db30::/32
+    - set protocols ospfv3 area '2'
+    - set protocols ospfv3 area 2 export-list export1
+    - set protocols ospfv3 area 2 import-list import1
+    - set protocols ospfv3 area '3'
+    - set protocols ospfv3 area 3 range 2001:db40::/32
+parsed:
+  after:
+    areas:
+      - area_id: '2'
+        export_list: 'export1'
+        import_list: 'import1'
+        range:
+          - address: '2001:db10::/32'
+          - address: '2001:db20::/32'
+          - address: '2001:db30::/32'
+      - area_id: '3'
+        range:
+          - address: '2001:db40::/32'
+    parameters:
+      router_id: '192.0.2.10'
+    redistribute:
+      - route_type: 'bgp'
+deleted:
+  commands:
+    - 'delete protocols ospfv3'
+  after: {}
+round_trip:
+  after:
+    areas:
+      - area_id: '2'
+        export_list: 'export1'
+        import_list: 'import1'
+        range:
+          - address: '2001:db10::/32'
+          - address: '2001:db30::/32'
+          - address: '2001:db50::/32'
+      - area_id: '4'
+        range:
+          - address: '2001:db60::/32'
+    parameters:
+      router_id: '192.0.2.10'
+    redistribute:
+      - route_type: 'bgp'
diff --git a/tests/unit/modules/network/vyos/fixtures/vyos_ospfv3_config.cfg b/tests/unit/modules/network/vyos/fixtures/vyos_ospfv3_config.cfg
new file mode 100644
index 00000000..060b9b33
--- /dev/null
+++ b/tests/unit/modules/network/vyos/fixtures/vyos_ospfv3_config.cfg
@@ -0,0 +1,6 @@
+set protocols ospfv3 area 12 export-list 'export1'
+set protocols ospfv3 area 12 import-list 'import1'
+set protocols ospfv3 area 12 range '2001:db11::/32'
+set protocols ospfv3 area 12 range '2001:db22::/32'
+set protocols ospfv3 area 12 range '2001:db33::/32'
+set protocols ospfv3 area 13 range '2001:db44::/32'
\ No newline at end of file
diff --git a/tests/unit/modules/network/vyos/test_vyos_ospfv3.py b/tests/unit/modules/network/vyos/test_vyos_ospfv3.py
new file mode 100644
index 00000000..1d9cb3ab
--- /dev/null
+++ b/tests/unit/modules/network/vyos/test_vyos_ospfv3.py
@@ -0,0 +1,348 @@
+# (c) 2016 Red Hat Inc.
+#
+# This file is part of Ansible
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+# Make coding more python3-ish
+from __future__ import absolute_import, division, print_function
+
+__metaclass__ = type
+
+from ansible_collections.vyos.vyos.tests.unit.compat.mock import patch
+from ansible_collections.vyos.vyos.plugins.modules import vyos_ospfv3
+from ansible_collections.vyos.vyos.tests.unit.modules.utils import (
+    set_module_args,
+)
+from .vyos_module import TestVyosModule, load_fixture
+
+
+class TestVyosFirewallRulesModule(TestVyosModule):
+
+    module = vyos_ospfv3
+
+    def setUp(self):
+        super(TestVyosFirewallRulesModule, self).setUp()
+        self.mock_get_config = patch(
+            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.get_config"
+        )
+        self.get_config = self.mock_get_config.start()
+
+        self.mock_load_config = patch(
+            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.network.Config.load_config"
+        )
+        self.load_config = self.mock_load_config.start()
+
+        self.mock_get_resource_connection_config = patch(
+            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.cfg.base.get_resource_connection"
+        )
+        self.get_resource_connection_config = (
+            self.mock_get_resource_connection_config.start()
+        )
+
+        self.mock_get_resource_connection_facts = patch(
+            "ansible_collections.ansible.netcommon.plugins.module_utils.network.common.facts.facts.get_resource_connection"
+        )
+        self.get_resource_connection_facts = (
+            self.mock_get_resource_connection_facts.start()
+        )
+
+        self.mock_execute_show_command = patch(
+            "ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.ospfv3.ospfv3.Ospfv3Facts.get_device_data"
+        )
+
+        self.execute_show_command = self.mock_execute_show_command.start()
+
+    def tearDown(self):
+        super(TestVyosFirewallRulesModule, self).tearDown()
+        self.mock_get_resource_connection_config.stop()
+        self.mock_get_resource_connection_facts.stop()
+        self.mock_get_config.stop()
+        self.mock_load_config.stop()
+        self.mock_execute_show_command.stop()
+
+    def load_fixtures(self, commands=None, transport="cli", filename=None):
+        if filename is None:
+            filename = "vyos_ospfv3_config.cfg"
+
+        def load_from_file(*args, **kwargs):
+            output = load_fixture(filename)
+            return output
+
+        self.execute_show_command.side_effect = load_from_file
+
+    def test_vyos_ospfv3_merged_new_config(self):
+        set_module_args(
+            dict(
+                config=dict(
+                    redistribute=[dict(route_type="bgp")],
+                    parameters=dict(router_id="192.0.2.10"),
+                    areas=[
+                        dict(
+                            area_id="2",
+                            export_list="export1",
+                            import_list="import1",
+                            range=[
+                                dict(address="2001:db10::/32"),
+                                dict(address="2001:db20::/32"),
+                                dict(address="2001:db30::/32"),
+                            ],
+                        ),
+                        dict(
+                            area_id="3",
+                            range=[dict(address="2001:db40::/32"),],
+                        ),
+                    ],
+                ),
+                state="merged",
+            )
+        )
+        commands = [
+            "set protocols ospfv3 redistribute bgp",
+            "set protocols ospfv3 parameters router-id '192.0.2.10'",
+            "set protocols ospfv3 area 2 range 2001:db10::/32",
+            "set protocols ospfv3 area 2 range 2001:db20::/32",
+            "set protocols ospfv3 area 2 range 2001:db30::/32",
+            "set protocols ospfv3 area '2'",
+            "set protocols ospfv3 area 2 export-list export1",
+            "set protocols ospfv3 area 2 import-list import1",
+            "set protocols ospfv3 area '3'",
+            "set protocols ospfv3 area 3 range 2001:db40::/32",
+        ]
+        self.execute_module(changed=True, commands=commands)
+
+    def test_vyos_ospfv3_merged_idem(self):
+        set_module_args(
+            dict(
+                config=dict(
+                    areas=[
+                        dict(
+                            area_id="12",
+                            export_list="export1",
+                            import_list="import1",
+                            range=[
+                                dict(address="2001:db11::/32"),
+                                dict(address="2001:db22::/32"),
+                                dict(address="2001:db33::/32"),
+                            ],
+                        ),
+                        dict(
+                            area_id="13",
+                            range=[dict(address="2001:db44::/32"),],
+                        ),
+                    ],
+                ),
+                state="merged",
+            )
+        )
+        self.execute_module(changed=False, commands=[])
+
+    def test_vyos_ospfv3_merged_update_existing(self):
+        set_module_args(
+            dict(
+                config=dict(
+                    redistribute=[dict(route_type="bgp")],
+                    parameters=dict(router_id="192.0.2.10"),
+                    areas=[
+                        dict(
+                            area_id="12",
+                            export_list="export1",
+                            import_list="import1",
+                            range=[
+                                dict(address="2001:db11::/32"),
+                                dict(address="2001:db22::/32"),
+                                dict(address="2001:db33::/32"),
+                            ],
+                        ),
+                        dict(
+                            area_id="13",
+                            range=[
+                                dict(address="2001:db44::/32"),
+                                dict(address="2001:db55::/32"),
+                            ],
+                        ),
+                    ],
+                ),
+                state="merged",
+            )
+        )
+        commands = [
+            "set protocols ospfv3 redistribute bgp",
+            "set protocols ospfv3 parameters router-id '192.0.2.10'",
+            "set protocols ospfv3 area 13 range 2001:db55::/32",
+        ]
+        self.execute_module(changed=True, commands=commands)
+
+    def test_vyos_ospfv3_replaced(self):
+        set_module_args(
+            dict(
+                config=dict(
+                    redistribute=[dict(route_type="bgp")],
+                    parameters=dict(router_id="192.0.2.10"),
+                    areas=[
+                        dict(
+                            area_id="12",
+                            export_list="export1",
+                            import_list="import1",
+                            range=[
+                                dict(address="2001:db10::/32"),
+                                dict(address="2001:db22::/32"),
+                                dict(address="2001:db33::/32"),
+                            ],
+                        ),
+                        dict(
+                            area_id="14",
+                            range=[dict(address="2001:db40::/32"),],
+                        ),
+                    ],
+                ),
+                state="replaced",
+            )
+        )
+        commands = [
+            "set protocols ospfv3 redistribute bgp",
+            "set protocols ospfv3 parameters router-id '192.0.2.10'",
+            "delete protocols ospfv3 area 12 range 2001:db11::/32",
+            "set protocols ospfv3 area 12 range 2001:db10::/32",
+            "delete protocols ospfv3 area 13",
+            "set protocols ospfv3 area '14'",
+            "set protocols ospfv3 area 14 range 2001:db40::/32",
+        ]
+        self.execute_module(changed=True, commands=commands)
+
+    def test_vyos_ospfv3_replaced_idem(self):
+        set_module_args(
+            dict(
+                config=dict(
+                    areas=[
+                        dict(
+                            area_id="12",
+                            export_list="export1",
+                            import_list="import1",
+                            range=[
+                                dict(address="2001:db11::/32"),
+                                dict(address="2001:db22::/32"),
+                                dict(address="2001:db33::/32"),
+                            ],
+                        ),
+                        dict(
+                            area_id="13",
+                            range=[dict(address="2001:db44::/32"),],
+                        ),
+                    ],
+                ),
+                state="replaced",
+            )
+        )
+        self.execute_module(changed=False, commands=[])
+
+    def test_vyos_ospfv3_deleted_no_config(self):
+        set_module_args(dict(config=None, state="deleted"))
+        commands = ["delete protocols ospfv3"]
+        self.execute_module(changed=True, commands=commands)
+
+    def test_vyos_ospfv3_gathered(self):
+        set_module_args(dict(state="gathered"))
+        result = self.execute_module(
+            changed=False, filename="vyos_ospfv3_config.cfg"
+        )
+        gather_dict = {
+            "areas": [
+                {
+                    "area_id": "12",
+                    "export_list": "export1",
+                    "import_list": "import1",
+                    "range": [
+                        {"address": "2001:db11::/32"},
+                        {"address": "2001:db22::/32"},
+                        {"address": "2001:db33::/32"},
+                    ],
+                },
+                {"area_id": "13", "range": [{"address": "2001:db44::/32"}]},
+            ],
+        }
+        self.assertEqual(sorted(gather_dict), sorted(result["gathered"]))
+
+    def test_vyos_ospfv3_parsed(self):
+        parsed_str = """set protocols ospfv3 area 2 export-list 'export1'
+set protocols ospfv3 area 2 import-list 'import1'
+set protocols ospfv3 area 2 range '2001:db10::/32'
+set protocols ospfv3 area 2 range '2001:db20::/32'
+set protocols ospfv3 area 2 range '2001:db30::/32'
+set protocols ospfv3 area 3 range '2001:db40::/32'
+set protocols ospfv3 parameters router-id '192.0.2.10'
+set protocols ospfv3 redistribute 'bgp'"""
+        set_module_args(dict(running_config=parsed_str, state="parsed"))
+        result = self.execute_module(changed=False)
+        parsed_dict = {
+            "areas": [
+                {
+                    "area_id": "2",
+                    "export_list": "export1",
+                    "import_list": "import1",
+                    "range": [
+                        {"address": "2001:db10::/32"},
+                        {"address": "2001:db20::/32"},
+                        {"address": "2001:db30::/32"},
+                    ],
+                },
+                {"area_id": "3", "range": [{"address": "2001:db40::/32"}]},
+            ],
+            "parameters": {"router_id": "192.0.2.10"},
+            "redistribute": [{"route_type": "bgp"}],
+        }
+        self.assertEqual(sorted(parsed_dict), sorted(result["parsed"]))
+
+    def test_vyos_ospfv3_rendered(self):
+        set_module_args(
+            dict(
+                config=dict(
+                    redistribute=[dict(route_type="bgp")],
+                    parameters=dict(router_id="192.0.2.10"),
+                    areas=[
+                        dict(
+                            area_id="2",
+                            export_list="export1",
+                            import_list="import1",
+                            range=[
+                                dict(address="2001:db10::/32"),
+                                dict(address="2001:db20::/32"),
+                                dict(address="2001:db30::/32"),
+                            ],
+                        ),
+                        dict(
+                            area_id="3",
+                            range=[dict(address="2001:db40::/32"),],
+                        ),
+                    ],
+                ),
+                state="rendered",
+            )
+        )
+        commands = [
+            "set protocols ospfv3 redistribute bgp",
+            "set protocols ospfv3 parameters router-id '192.0.2.10'",
+            "set protocols ospfv3 area 2 range 2001:db10::/32",
+            "set protocols ospfv3 area 2 range 2001:db20::/32",
+            "set protocols ospfv3 area 2 range 2001:db30::/32",
+            "set protocols ospfv3 area '2'",
+            "set protocols ospfv3 area 2 export-list export1",
+            "set protocols ospfv3 area 2 import-list import1",
+            "set protocols ospfv3 area '3'",
+            "set protocols ospfv3 area 3 range 2001:db40::/32",
+        ]
+        result = self.execute_module(changed=False)
+        self.assertEqual(
+            sorted(result["rendered"]), sorted(commands), result["rendered"]
+        )
diff --git a/tests/unit/modules/network/vyos/vyos_module.py b/tests/unit/modules/network/vyos/vyos_module.py
index fb15c715..49d46522 100644
--- a/tests/unit/modules/network/vyos/vyos_module.py
+++ b/tests/unit/modules/network/vyos/vyos_module.py
@@ -60,6 +60,7 @@ class TestVyosModule(ModuleTestCase):
         commands=None,
         sort=True,
         defaults=False,
+        filename=None,
     ):
         self.load_fixtures(commands)
 
-- 
cgit v1.2.3