Repository: napalm-automation-community/napalm-arubaos-switch (language: python)

Issue:
get_interfaces added
# One-line summary
Implements `get_interfaces`

## Description
This PR introduces the missing method `get_interfaces`.

## Types of Changes
- New feature (non-breaking change which adds functionality)

## Review
- [ ] Tests
- [ ] Documentation

Interfaces
# Add get_interfaces

## Description
I couldn't find an endpoint to get information about interfaces, but used the cli endpoint to get the output of the cli.

It will be parsed for interfaces and is doing another calls on all interfaces to get more specific information about the interfaces as we need this to fill the expected template by napalm.
Needed to implement the asynchronous call into the method as all other calls are synchronous and this would take much longer to process on all interfaces.
Maybe a good idea to implement only asynchronous calls instead of synchronous calls for all methods!?

I don't know right now if there could be another naming format for interfaces too. On the test device I could only see integers for the interfaces (I guess 1-10). Are there maybe also other formats like ge0/0/0???
Replacing the configuration
## Expected Behavior
Executing `compare_config` after `load_replace_candidate` returns a list of added/removed configuration values.

## Actual Behavior
Executing `compare_config` after `load_replace_candidate` always returns a empty list.

## Steps to Reproduce the Problem

  1. Create a configuration that differs from the current configuration of the switch
  2. Configure task with nornir and nornir napalm plugin: https://github.com/nornir-automation/nornir_napalm/blob/master/nornir_napalm/plugins/tasks/napalm_configure.py
  3.  Alternatively, manually execute the steps in the task.

## Specifications

  - Version: napalm-arubaos-switch - latest development branch
  - Platform: Switch - HP2920-48G-POE+
  - Subsystem:

## Analysis

I think the issue is here: https://github.com/napalm-automation-community/napalm-arubaos-switch/blob/development/napalm_arubaoss/helper/compare_config.py

The switch requires some time to compute the difference. If I add a sleep time between the two API calls in the function, everything works as expected. Currently, 2 sec seems to be enough.

Unfortunately, I have not found a way to check whether the diff is ready. On our switch, the rest API `system/config/cfg_restore/latest_diff` always returns a status `CRS_IN_PROGRESS` but never `CRS_SUCCESS`.

Is it possible to add an optional argument to specify a sleep time for the compare_config function?



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/pythopackage.yml b/.github/workflows/pythopackage.yml
index 87ca3d8..80dd534 100644
--- a/.github/workflows/pythopackage.yml
+++ b/.github/workflows/pythopackage.yml
@@ -9,7 +9,7 @@ jobs:
     strategy:
       max-parallel: 3
       matrix:
-        python-version: [3.5, 3.6, 3.7]
+        python-version: [3.6, 3.7, 3.8]
 
     steps:
     - uses: actions/checkout@v1
diff --git a/README.md b/README.md
index b083160..546f1ab 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
+[![PyPI](https://img.shields.io/pypi/v/napalm-arubaos-switch.svg)](https://pypi.python.org/pypi/napalm-arubaos-switch)
+[![PyPI](https://img.shields.io/pypi/dm/napalm-arubaos-switch.svg)](https://pypi.python.org/pypi/napalm-arubaos-switch)
+[![Building Status](https://github.com/napalm-automation-community/napalm-arubaos-switch/workflows/Python%20package/badge.svg?branch=master)](https://github.com/napalm-automation-community/napalm-arubaos-switch/actions?query=workflow%3A"Python%20package")
 # Napalm-arubaoss
 Driver implementation for Aruba OS Switch. Tested in AOS > WC.16.09.0004, some modules may not work properly in older versions.
 
@@ -7,6 +10,7 @@ Driver implementation for Aruba OS Switch. Tested in AOS > WC.16.09.0004, some m
     * commit_config()                 ✅
     * compare_config()                ✅
     * compliance_report()             ✅
+    * confirm_commit()                ✅
     * discard_config()                ✅  
     * get_arp_table()                 ✅
     * get_bgp_config()                ❌*
@@ -32,6 +36,7 @@ Driver implementation for Aruba OS Switch. Tested in AOS > WC.16.09.0004, some m
     * get_route_to()                  ✅
     * get_snmp_information()          ❌  - Planned
     * get_users()                     ❌  - Planned
+    * has_pending_commit()            ✅
     * is_alive()                      ✅
     * load_merge_candidate()          ✅**
     * load_replace_candidate()        ✅
@@ -75,6 +80,27 @@ rest-interface
 rest-interface session-idle-timeout 120 #optional
 ```
 
+### optional_args
+optional_args can be set during initialization like this:
+```Python
+from napalm import get_network_driver
+
+d = get_network_driver("arubaoss")
+
+with d('1.2.3.4', 'username', 'password', optional_args={'ssl_verify': False, "debugging": True}) as aruba:
+   print(aruba.get_config())
+```
+
+The following values can be set in optional_args:
+- ssl_verify: bool/str = defaults to **True** - will be passed to the requests object (description can be found [here](https://docs.python-requests.org/en/latest/_modules/requests/sessions/#Session.request))
+- keepalive: bool = defaults to **False** - sets the underlying TCP connection to either keep the connection or not and is a workaround for an issue with ArubaOS devices 
+  (discussed [here](https://community.arubanetworks.com/community-home/digestviewer/viewthread?MID=28798#bme4aa3703-e476-4880-9cb4-9b208f86b2f4))
+- keep_alive: bool = same as keepalive, just shadows it to be able to use the same keyword as in older Python requests versions
+- debugging: bool = defaults to **False** - sets the level of the logging handler to logging.DEBUG
+- disable_ssl_warnings: bool = defaults to **False** - disables ssl warnings from urllib3
+- api: string = defaults to **v6** - defines the API version
+- ssl: bool = defaults to **True**, sets http or https
+
 ### Saltstack
 To use the driver with Saltstack, you would typically need a proxy minion.
 
@@ -100,23 +126,23 @@ mine_enabled: true # not required, but nice to have
 
 #### Supported Salt execution modules
 
- - [grains.items](docs/saltstack.md#grains.items)
- - [net.arp](docs/saltstack.md#net.arp)
- - [net.mac](docs/saltstack.md#net.mac)
- - [net.ipaddrs](docs/saltstack.md#net.ipaddrs)
- - [net.lldp](docs/saltstack.md#net.lldp)
- - [net.facts](docs/saltstack.md#net.facts)
- - [net.ping](docs/saltstack.md#net.ping)
- - [net.traceroute](docs/saltstack.md#net.traceroute)
- - [route.show](docs/saltstack.md#route.show)
- - [net.cli](docs/saltstack.md#net.cli)
- - [net.config](docs/saltstack.md#net.config)
- - [net.load_config](docs/saltstack.md#net.load_config)
- - [net.compare_config](docs/saltstack.md#net.load_config)
+ - [grains.items](docs/saltstack.md#grainsitems)
+ - [net.arp](docs/saltstack.md#netarp)
+ - [net.mac](docs/saltstack.md#netmac)
+ - [net.ipaddrs](docs/saltstack.md#netipaddrs)
+ - [net.lldp](docs/saltstack.md#netlldp)
+ - [net.facts](docs/saltstack.md#netfacts)
+ - [net.ping](docs/saltstack.md#netping)
+ - [net.traceroute](docs/saltstack.md#nettraceroute)
+ - [route.show](docs/saltstack.md#routeshow)
+ - [net.cli](docs/saltstack.md#netcli)
+ - [net.config](docs/saltstack.md#netconfig)
+ - [net.load_config](docs/saltstack.md#netload_config)
+ - [net.compare_config](docs/saltstack.md#netload_config)
  - net.load_template ( Issue #18)
  - net.discard_config
- - [ntp.servers](docs/saltstack.md#ntp.servers)
- - [napalm.compliance_report](docs/saltstack.md#napalm.compliance_report)
+ - [ntp.servers](docs/saltstack.md#ntpservers)
+ - [napalm.compliance_report](docs/saltstack.md#napalmcompliance_report)
 
 More details in [Saltstack examples](docs/saltstack.md)
 
diff --git a/napalm_arubaoss/ArubaOS.py b/napalm_arubaoss/ArubaOS.py
index ec821bf..82b2d1f 100644
--- a/napalm_arubaoss/ArubaOS.py
+++ b/napalm_arubaoss/ArubaOS.py
@@ -1,211 +1,226 @@
 """ArubaOS-Switch Napalm driver."""
-import base64
-from itertools import zip_longest
-from time import sleep
-
-import requests
 import logging
-from netaddr import IPNetwork
+import urllib3
+
+from napalm_arubaoss.helper.base import Connection
+from napalm_arubaoss.helper import (
+    backup_config,
+    commit_config,
+    compare_config,
+    confirm_commit,
+    get_mac_address_table,
+    get_facts,
+    get_arp_table,
+    get_config,
+    get_interfaces,
+    get_interfaces_ip,
+    get_lldp_neighbors,
+    get_lldp_neighbors_detail,
+    get_ntp_stats,
+    get_ntp_servers,
+    get_route_to,
+    has_pending_commit,
+    is_alive,
+    load_merge_candidate,
+    load_replace_candidate,
+    ping,
+    rollback,
+    traceroute,
+)
 
-from napalm.base.helpers import textfsm_extractor
 from napalm.base.base import NetworkDriver
-from napalm.base.exceptions import (
-    ConnectAuthError,
-    ConnectionClosedException,
-    CommandErrorException,
-    CommandTimeoutException,
-    MergeConfigException,
-    ReplaceConfigException
-)
 
-""" Debugging
-import http.client
-http.client.HTTPConnection.debuglevel = 1
-logging.basicConfig()
-logging.getLogger().setLevel(logging.DEBUG)
-requests_log = logging.getLogger("requests.packages.urllib3")
-requests_log.setLevel(logging.DEBUG)
-requests_log.propagate = True
-"""
+logger = logging.getLogger("arubaoss")
+logger.setLevel(logging.INFO)
 
-log = logging.getLogger(__name__)
+stream_formatter = logging.Formatter(
+    "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+)
 
-# disable anoying warning
-# requests.packages.urllib3.disable_warnings()
+streamhandler = logging.StreamHandler()
+streamhandler.setFormatter(stream_formatter)
+streamhandler.setLevel(logging.INFO)
+
+logger.addHandler(streamhandler)
 
 
 class ArubaOSS(NetworkDriver):
     """Class for connecting to aruba-os devices using the rest-api."""
 
-    def __init__(self, hostname,
-                 username='',
-                 password='',
-                 timeout=10,
-                 optional_args=None):
-        """Instantiate the module."""
-        self._headers = {'Content-Type': 'application/json'}
+    def __init__(
+            self,
+            hostname,
+            username,
+            password,
+            timeout=60,
+            optional_args=None
+    ):
+        """
+        Initialize Class ArubaOSS.
+
+        :param hostname: Hostname of the device
+        :param username: Username for the login
+        :param password: Password for the login
+        :param timeout: timeout to be passed to Request-Futures
+        :param optional_args: Optional Args to be passed to Request-Futures
+        """
+        if not optional_args:
+            optional_args = {}
+
+        if optional_args.get("debugging", False):
+            logger.setLevel(logging.DEBUG)
+            streamhandler.setLevel(logging.DEBUG)
+
+        if optional_args.get("disable_ssl_warnings", False):
+            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
+
         self.hostname = hostname
         self.username = username
         self.password = password
         self.timeout = timeout
+        self.optional_args = optional_args
 
-        # ----------------------------------------------------------------------------------------
-        # optional arguments
-        # ----------------------------------------------------------------------------------------
-        if optional_args is None:
-            optional_args = {}
+        self.cli_output = {}
 
-        self.api = optional_args.get("api", "v6")
-        ssl = optional_args.get("ssl", True)
-        self.keepalive = optional_args.get("keepalive", None)
-        self.ssl_verify = optional_args.get("ssl_verify", False)
-        if ssl:
-            self.proto = 'https'
-        else:
-            self.proto = 'http'
+        self.connection = Connection()
 
-        # URL encoding
+    def cli(self, commands):
+        """
+        Run CLI commands through the REST API.
 
-        self._api_url = '{}://{}/rest/{}/'.format(self.proto,
-                                                  self.hostname,
-                                                  self.api)
+        :param commands:
+        :return:
+        """
+        ret = self.connection.cli(commands)
 
-    def open(self):
-        """Open connection to the network device."""
-        self._login_url = self._api_url + "login-sessions"
+        return ret
 
-        params = {'userName': self.username, 'password': self.password}
-        self._apisession = requests.Session()
+    def close(self):
+        """
+        Close device connection and delete sessioncookie.
 
-        if not self.ssl_verify:
-            self._apisession.verify = False
+        :return:
+        """
+        ret = self.connection.logout()
 
-        self._apisession.headers = self._headers
-        # bug #4 - random delay while re-using TCP connection - workaroud:
-        if self.keepalive is None:
-            self._apisession.keep_alive = False
+        return ret
 
-        rest_login = self._apisession.post(self._login_url, json=params,
-                                           timeout=self.timeout)
+    def commit_config(self, message="", revert_in=None):
+        """
+        Backups and commit the configuration, and handles commit confirm.
 
-        if rest_login.status_code == 201:
-            session = rest_login.json()
-            self._headers['cookie'] = session['cookie']
-            return True
-        else:
-            raise ConnectAuthError("Login failed")
+        :param message:
+        :param revert_in:
+        :return:
+        """
+        ret = commit_config(self=self, revert_in=revert_in)
 
-    def is_alive(self):
-        """Check if device connection is alive."""
-        """check if session cookie is still valid
-        Returns:
-            True - Session cookie is still valid
-            None - There's an error
-        """
-        url = self._api_url + 'system'
-        endpoint = self._apisession.get(url)
-        if endpoint.status_code == 200:
-            "Session cookie is still valid"
-            return {"is_alive": True}
-        else:
-            raise ConnectionClosedException("HTTP session is closed")
-
-    @staticmethod
-    def _read_candidate(candidate):
-        with open(candidate) as candidate_config:
-            return ''.join(candidate_config.readlines())
-
-    def _transaction_status(self, url):
-        status = 'CRS_IN_PROGRESS'
-        elapsed = 0
-        while status == 'CRS_IN_PROGRESS' and elapsed < self.timeout:
-            call = self._apisession.get(url)
-            if 300 > call.status_code >= 200:
-                status = call.json()
-                return call
-            elapsed += 1
-            sleep(1)
-        if elapsed == (int(self.timeout) - 1) and status == 'CRS_IN_PROGRESS':
-            raise CommandTimeoutException("Transaction timed out")
-
-    @staticmethod
-    def _str_to_b64(spayload):
-        """Convert from str to b64 for aoss API."""
-        payload_b64 = base64.b64encode(spayload.encode())
-        return payload_b64.decode('utf-8')
-
-    @staticmethod
-    def _mac_reformat(mac):
-        t = iter(mac.replace("-", ""))
-        return ':'.join(a+b for a, b in zip_longest(t, t, fillvalue=""))
+        return ret
 
-    def load_replace_candidate(self, filename=None, config=None):
-        """Replace running config with the candidate."""
-        """ Implentation of napalm module load_replace_candidate()
-        ArubaOS-Switch supports payload_type options:
-            - "RPT_PATCH_FILE" -> not implemented
-            - "RPT_BACKUP_FILE" -> Implemented
+    def compare_config(self):
+        """
+        Compare the running config with the candidate one.
 
-        Note: the maximum content_length = 16072,
-        "HTTP/1.1 413 Request Entity Too Large" is returned above that!!!
+        :return:
         """
-        url = self._api_url + 'system/config/payload'
-        payload = {"payload_type": "RPT_BACKUP_FILE"}
-        if filename is not None:
-            config = self._read_candidate(filename)
+        ret = compare_config(self=self)
 
-        if config is not None:
-            payload['config_base64_encoded'] = ArubaOSS._str_to_b64(config)
-            load = self._apisession.post(url, json=payload)
-            if load.status_code != 200:
-                raise ReplaceConfigException("Load configuration failed")
+        return ret
 
-    def load_merge_candidate(self, filename=None, config=None):
-        """Merge candidate configuration with the running one."""
+    def compliance_report(self, validation_file=None, validation_source=None):
         """
-        Imperative config change:
-         Merge new config with existing one. There's no config validation
-         nor atomic commit!. Only configuration commands are supported,
-         "configure terminal" is not required. Use with caution.
+        Get Compliance report - NOT IMPLEMENTED.
 
+        :param validation_file:
+        :param validation_source:
+        :return:
         """
-        if filename is not None:
-            config = self._read_candidate(filename)
+        return super(ArubaOSS, self).compliance_report()
 
-        if config is not None:
-            if isinstance(config, str):
-                config = config.split('\n')
-            if not self._config_batch(cmd_list=config):
-                raise MergeConfigException("Configuration merge failed")
+    def confirm_commit(self):
+        """
+        Confirm the changes requested via commit_config when commit_confirm=True.
 
-        # mimic load_replace_candidate behaviour, by making sure candidate
-        # config exactly matches our merged configuration
-        self._backup_config(destination='REST_Payload_Backup')
+        Should cause self.has_pending_commit to return False when done.
+        :return: None
+        """
+        return confirm_commit(self=self)
 
-    def cli(self, commands):
-        """Run CLI commands through the REST API."""
-        output = {}
-        if isinstance(commands, list):
-            for cmd in commands:
-                output[cmd] = str(self._run_cmd(cmd))
-            return output
-        elif isinstance(commands, str):
-            cmd_list = commands.splitlines()
-            return self.cli(cmd_list)
-
-    def get_arp_table(self):
-        """Get device's ARP table."""
-        raw_arp = self._run_cmd("show arp")
-        arp_table = textfsm_extractor(self, "show_arp", raw_arp)
-        for arp in arp_table:
-            arp['interface'] = arp.pop('port')
-            arp['mac'] = self._mac_reformat(arp['mac'])
-            arp['age'] = 'N/A'
-        return arp_table
+    def connection_tests(self):
+        """
+        Show connection tests - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).connection_tests()
+
+    def discard_config(self):
+        """
+        Discard the candidate configuration.
+
+        :return:
+        """
+        if self.has_pending_commit():
+            self.load_merge_candidate(config="no job ROLLBACK")
+
+        backup_config(self=self, destination="REST_Payload_Backup")
+
+    def get_arp_table(self, vrf=""):
+        """
+        Get device's ARP table.
+
+        :param vrf:
+        :return:
+        """
+        ret = get_arp_table(self=self, vrf=vrf)
+
+        return ret
+
+    def get_bgp_config(self, group="", neighbor=""):
+        """
+        Get BGP config - NOT IMPLEMENTED.
+
+        :param group:
+        :param neighbor:
+        :return:
+        """
+        return super(ArubaOSS, self).get_bgp_config()
+
+    def get_bgp_neighbors(self):
+        """
+        Get BGP neighbors - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_bgp_neighbors()
+
+    def get_bgp_neighbors_detail(self, neighbor_address=""):
+        """
+        Get BGP Neighbors detail - NOT IMPLEMENTED.
+
+        :param neighbor_address:
+        :return:
+        """
+        return super(ArubaOSS, self).get_bgp_neighbors_detail()
+
+    def get_config(self, retrieve="all", full=False, sanitized=False):
+        """
+        Get configuration stored on the device.
+
+        :param retrieve:
+        :param full:
+        :param sanitized:
+        :return:
+        """
+        # TODO check why "full" exists
+        ret = get_config(self=self, retrieve=retrieve)
+
+        return ret
 
     def get_environment(self):
-        """Get environment readings."""
         """
+        Get environment readings - NOT IMPLEMENTED.
+
         Currently (API v7) the API does not support reading information about
         fans, temperature, power or CPU.
         A textfsm template needs to be created to parse:
@@ -214,384 +229,425 @@ def get_environment(self):
          - show system power-consumption
          - show system power-supply
          - show system information (CPU/MEM)
-        """
+
+        :return:
         output = {
-                  "fans": {},
-                  "temperature": {},
-                  "power": {},
-                  "cpu": {},
-                  "memory": {}
-                  }
-        return output
-
-    def get_config(self, retrieve="all"):
-        """Get configuration stored on the device."""
-        out = {'startup': '', 'candidate': '', 'running': ''}
-
-        if (retrieve == 'all' or retrieve == 'startup'):
-            out['startup'] = str(self._run_cmd("display saved-configuration"))
-        if (retrieve == 'all' or retrieve == 'running'):
-            out['running'] = str(self._run_cmd("show running-config"))
-        if (retrieve == 'all' or retrieve == 'candidate'):
-            out['candidate'] = str(self._run_cmd(
-                                "show config REST_Payload_Backup"))
-        return out
+            "fans": {},
+            "temperature": {},
+            "power": {},
+            "cpu": {},
+            "memory": {}
+        }
+        """
+        return super(ArubaOSS, self).get_environment()
 
     def get_facts(self):
-        """Get general device information."""
-        out = {'vendor': 'HPE Aruba'}
-        out['interface_list'] = []
-
-        url = self._api_url + 'system/status'
-        call = self._apisession.get(url)
-        if 300 > call.status_code >= 200:
-            rest_out = call.json()
-            out['hostname'] = rest_out['name']
-            out['os_version'] = rest_out['firmware_version']
-            out['serial_number'] = rest_out['serial_number']
-            out['model'] = rest_out['product_model']
-
-            # get domain name to generate the FQDN
-            url = self._api_url + 'dns'
-            call = self._apisession.get(url)
-            if 300 > call.status_code >= 200:
-                rest_out = call.json()
-                out['fqdn'] = out['hostname'] + "." + \
-                    rest_out['dns_domain_names'][0]
-
-        # Get interface list
-        url = self._api_url + 'system/status/switch'
-        call = self._apisession.get(url)
-        if 300 > call.status_code >= 200:
-            rest_out = call.json()
-            for blade in rest_out['blades']:
-                for ports in blade['data_ports']:
-                    out['interface_list'].append(ports['port_name'])
-
-        return out
+        """
+        Get general device information.
 
-    def discard_config(self):
-        """Discard the candidate configuration."""
-        self._backup_config(destination='REST_Payload_Backup')
+        :return:
+        """
+        ret = get_facts(self=self)
 
-    def compare_config(self):
-        """Compare the running config with the candidate one."""
-        url = self._api_url + 'system/config/cfg_restore/latest_diff'
-        check_url = url + '/status'
-        data = {
-                "server_type": "ST_FLASH",
-                "file_name": "REST_Payload_Backup",
-                "is_oobm": False
-                }
-        # trigger configuration comparison
-        diff = self._apisession.post(url, json=data)
-        if 300 > diff.status_code >= 200:
-            diff_output = self._apisession.get(check_url)
-            if diff_output.status_code == 200:
-                if not diff_output.json()['diff_add_list'] and \
-                        not diff_output.json()['diff_remove_list']:
-                    # return empty string to signal the candidate
-                    # and running configs are the same
-                    return ""
-                else:
-                    return diff_output.json()
-            else:
-                raise CommandErrorException("diff generation failed,\
-                    raise status")
-        else:
-            raise CommandErrorException("diff generation failed, raise status")
-
-    def commit_config(self, message=None, confirm=0):
-        """Backups and commit the configuration, and handles commit confirm."""
-        self._backup_config()
-        log.debug("Confirm rollback time is {}".format(str(confirm)))
-        if confirm > 0:
-            candidate = self.get_config(retrieve='candidate')['candidate'][:-2]
-            candidate_confirm = candidate + 'job ROLLBACK delay {} \
-                "cfg-restore flash backup_running"\n'.format(str(confirm))
-            self.load_replace_candidate(config=candidate_confirm)
-        self._commit_candidate(config='REST_Payload_Backup')
-
-    def _commit_candidate(self, config):
-        """Commit the candidate configuration."""
-        url = self._api_url + 'system/config/cfg_restore'
-        data = {
-                "server_type": "ST_FLASH",
-                "file_name": config,
-                "is_oobm": False
+        return ret
+
+    def get_firewall_policies(self):
+        """
+        Get firewall policies - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_firewall_policies()
+
+    def get_interfaces(self):
+        """
+        Return a dictionary of dictionaries. The keys for the first dictionary will be the \
+        interfaces in the devices. The inner dictionary will contain the following data for \
+        each interface.
+
+         * is_up (True/False)
+         * is_enabled (True/False)
+         * description (string)
+         * last_flapped (float in seconds) - NOT IMPLEMENTED (always -1.0)
+         * speed (int in Mbit)
+         * MTU (in Bytes) - NOT IMPLEMENTED (always -1)
+         * mac_address (string)
+
+        Example::
+
+            {
+            u'Management1':
+                {
+                'is_up': False,
+                'is_enabled': False,
+                'description': '',
+                'last_flapped': -1.0,
+                'speed': 1000,
+                'mtu': 1500,
+                'mac_address': 'FA:16:3E:57:33:61',
+                },
+            u'Ethernet1':
+                {
+                'is_up': True,
+                'is_enabled': True,
+                'description': 'foo',
+                'last_flapped': 1429978575.1554043,
+                'speed': 1000,
+                'mtu': 1500,
+                'mac_address': 'FA:16:3E:57:33:62',
+                },
+            u'Ethernet2':
+                {
+                'is_up': True,
+                'is_enabled': True,
+                'description': 'bla',
+                'last_flapped': 1429978575.1555667,
+                'speed': 1000,
+                'mtu': 1500,
+                'mac_address': 'FA:16:3E:57:33:63',
+                },
+            u'Ethernet3':
+                {
+                'is_up': False,
+                'is_enabled': True,
+                'description': 'bar',
+                'last_flapped': -1.0,
+                'speed': 1000,
+                'mtu': 1500,
+                'mac_address': 'FA:16:3E:57:33:64',
                 }
-        cmd_post = self._apisession.post(url, json=data)
+            }
+        """
+        ret = get_interfaces(self)
 
-        if not cmd_post.json()['failure_reason']:
-            check_url = url + '/status'
-            return self._transaction_status(check_url).json()
+        return ret
 
-    def get_mac_address_table(self):
-        """Get the mac-address table of the device."""
-        url = self._api_url + 'mac-table'
-        resp = self._apisession.get(url)
-        if resp.status_code == 200:
-            table = []
-            for entry in resp.json().get('mac_table_entry_element'):
-                item = {}
-                item['mac'] = self._mac_reformat(entry['mac_address'])
-                item['interface'] = entry['port_id']
-                item['vlan'] = entry['vlan_id']
-                item['active'] = True
-                """ Not supported:
-                item['static'] = False
-                item['moves'] = 0
-                item['last_move'] = 0.0
-                """
-                table.append(item)
-            return table
+    def get_interfaces_counters(self):
+        """
+        Get interfaces counters - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_interfaces_counters()
 
     def get_interfaces_ip(self):
-        """Get IP interface IP addresses."""
-        url = self._api_url + 'ipaddresses'
-        url = self._api_url + 'ipaddresses'
-        "Looks like there's a bug n ArubaOS and is not returning IPv6"
-
-        resp = self._apisession.get(url)
-        if resp.status_code == 200:
-            output = {}
-            for address in resp.json().get('ip_address_subnet_element'):
-                iface_name = "VLAN" + str(address['vlan_id'])
-                if iface_name not in output.keys():
-                    output[iface_name] = {}
-                ip = IPNetwork("{}/{}".format(
-                    address['ip_address']['octets'],
-                    address['ip_mask']['octets']))
-                version = 'ipv' + str(ip.version)
-                if version not in output[iface_name].keys():
-                    output[iface_name][version] = {}
-                output[iface_name][version][str(ip.ip)] = {
-                        'prefix_length': ip.prefixlen}
-            return output
+        """
+        Get IP interface IP addresses.
+
+        Looks like there's a bug on ArubaOS and is not returning IPv6
+
+        :return:
+        """
+        ret = get_interfaces_ip(self=self)
+
+        return ret
+
+    def get_ipv6_neighbors_table(self):
+        """
+        Get IPv6 neighbors table - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_ipv6_neighbors_table()
 
     def get_lldp_neighbors(self):
-        """Get a list of LLDP neighbors."""
-        url = self._api_url + '/lldp/remote-device'
-        resp = self._apisession.get(url)
-        log.debug("API returned {}".format(resp.status_code))
-        if 300 > resp.status_code >= 200:
-            neighbor_table = {}
-            for neighbor in resp.json()['lldp_remote_device_element']:
-                port = neighbor['local_port']
-                if not neighbor_table.get(port):
-                    neighbor_table[port] = []
-                remote_device = {
-                        'hostname': neighbor.get('system_name'),
-                        'port': neighbor.get('port_id')
-                        }
-                neighbor_table[port].append(remote_device)
-            return neighbor_table
-
-    def get_lldp_neighbors_detail(self):
-        """Get LLDP neighbor information."""
-        url = self._api_url + '/lldp/remote-device'
-        resp = self._apisession.get(url)
-        log.debug("API returned {}".format(resp.status_code))
-        if 300 > resp.status_code >= 200:
-            neighbor_table = {}
-            for neighbor in resp.json()['lldp_remote_device_element']:
-                port = neighbor['local_port']
-                if not neighbor_table.get(port):
-                    neighbor_table[port] = []
-                remote_device = {
-                    'remote_system_name': neighbor.get('system_name'),
-                    'remote_chassis_id': neighbor.get('chassis_id'),
-                    'remote_port': neighbor.get('port_id'),
-                    'remote_port_description':
-                        neighbor.get('port_description'),
-                    'remote_system_description':
-                        ''.join(neighbor.get('system_description')),
-                    'remote_system_capab':
-                        [k for k, v in neighbor.get(
-                            'capabilities_supported').items() if v is True],
-                    'remote_system_enable_capab':
-                        [k for k, v in neighbor.get(
-                            'capabilities_enabled').items() if v is True]
-                    }
-                neighbor_table[port].append(remote_device)
-            return neighbor_table
+        """
+        Get a list of LLDP neighbors.
+
+        :return:
+        """
+        ret = get_lldp_neighbors(self=self)
+
+        return ret
+
+    def get_lldp_neighbors_detail(self, interface=""):
+        """
+        Get LLDP neighbor information.
+
+        NOTE: Parent Interface is always empty,
+        as the information isn't available.
+
+        :param interface:
+        :return:
+        """
+        ret = get_lldp_neighbors_detail(self=self, interface=interface)
+
+        return ret
+
+    def get_mac_address_table(self):
+        """
+        Get the mac-address table of the device.
+
+        "static", "moves" and "last_move" have always default values,
+        as there is no helpful information from the device.
+
+        static: False,  # not supported
+        moves: 0,  # not supported
+        last_move: 0.0  # not supported
+
+        :return:
+        """
+        ret = get_mac_address_table(self=self)
+
+        return ret
+
+    def get_network_instances(self, name=""):
+        """
+        Get network instances - NOT IMPLEMENTED.
+
+        :param name:
+        :return:
+        """
+        return super(ArubaOSS, self).get_network_instances()
 
     def get_ntp_peers(self):
-        """Get NTP peers."""
         """
+        Get NTP peers.
+
         ArubaOS does not support NTP "peers", just upstream servers.
         This method is just an alias of get_ntp_servers()
+
+        :return:
         """
-        self.get_ntp_servers()
+        ret = get_ntp_servers(self=self)
+
+        return ret
 
     def get_ntp_servers(self):
-        """Get NTP servers."""
-        " TO-DO: add IPv6 support, currently getting 404 from the API"
-        url = self._api_url + 'config/ntp/server/ip4addr'
-        resp = self._apisession.get(url)
-        if resp.status_code == 200:
-            output = {}
-            for server in resp.json().get('ntpServerIp4addr_element'):
-                output[server['ip4addr']['ip4addr_value']] = {}
-            return output
+        """
+        Get NTP servers.
+
+        TO-DO: add IPv6 support, currently getting 404 from the API
+
+        :return:
+        """
+        ret = get_ntp_servers(self=self)
+
+        return ret
 
     def get_ntp_stats(self):
-        """Get NTP peer statistics."""
-        out = []
-        associations = self.get_ntp_servers()
-
-        for association in associations.keys():
-            url = self._api_url + \
-                'monitoring/ntp/associations/detail/' + association
-            resp = self._apisession.get(url)
-            if resp.status_code == 200:
-                ntp_entry = {}
-                ntp_entry['remote'] = resp.json()['IP Address']
-                ntp_entry['referenceid'] = resp.json()['Reference ID']
-
-                if resp.json()['Status'].find("Master") == -1:
-                    ntp_entry['synchronized'] = False
-                else:
-                    ntp_entry['synchronized'] = True
-
-                ntp_entry['stratum'] = int(resp.json()['Stratum'])
-                ntp_entry['type'] = resp.json()['Peer Mode']
-                ntp_entry['when'] = resp.json()['Origin Time']
-                ntp_entry['hostpoll'] = int(resp.json()['Peer Poll Intvl'])
-                ntp_entry['reachability'] = int(resp.json()['Reach'])
-                ntp_entry['delay'] = \
-                    float(resp.json()['Root Delay'].split(' ')[0])
-                ntp_entry['offset'] = \
-                    float(resp.json()['Offset'].split(' ')[0])
-                ntp_entry['jitter'] = \
-                    float(resp.json()['Root Dispersion'].split(' ')[0])
-                out.append(ntp_entry)
-        return out
+        """
+        Get NTP peer statistics.
+
+        :return:
+        """
+        ret = get_ntp_stats(self=self)
+
+        return ret
 
     def get_optics(self):
-        """Transceiver output/input readings. We need to parse CLI."""
-        """ CMDs:
+        """
+        Transceiver output/input readings. We need to parse CLI.
+
+        CMDs:
          - show interfaces transceiver detail
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_optics()
+
+    def get_probes_config(self):
+        """
+        Get probes config - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_probes_config()
+
+    def get_probes_results(self):
+        """
+        Get probes results - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_probes_results()
+
+    def get_route_to(self, destination="", protocol="", longer=False):
+        """
+        Get route to destination.
+
+        :param destination:
+        :param protocol:
+        :param longer:
+        :return:
+        """
+        ret = get_route_to(
+            self=self,
+            destination=destination,
+            protocol=protocol
+        )
+
+        return ret
+
+    def get_snmp_information(self):
+        """
+        Get SNMP information - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_snmp_information()
+
+    def get_users(self):
+        """
+        Get users - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).get_users()
+
+    def has_pending_commit(self):
+        """
+        Boolean indicates if a commit_config that needs confirmed is in process.
+
+        :return Boolean
+        """
+        return has_pending_commit(self=self)
+
+    def is_alive(self):
         """
-        return super().get_optics()
-
-    def get_route_to(self, destination='', protocol=''):
-        """Get active route for a given destination."""
-        v4_table = []
-        v6_table = []
-        if destination != '':
-            ip_address = IPNetwork(destination)
-            if ip_address.version == 4:
-                raw_v4_table = self._run_cmd(
-                    "show ip route {} {}".format(protocol, ip_address.ip))
-                v4_table = textfsm_extractor(
-                    self, "show_ip_route", raw_v4_table)
-            elif ip_address.version == 6:
-                raw_v6_table = self._run_cmd(
-                    "show ipv6 route {} {}".format(protocol, ip_address.ip))
-                v6_table = textfsm_extractor(
-                    self, "show_ipv6_route", raw_v6_table)
-        else:
-            raw_v4_table = self._run_cmd(
-                "show ip route {} {}".format(protocol, destination))
-            v4_table = textfsm_extractor(
-                self, "show_ip_route", raw_v4_table)
-            raw_v6_table = self._run_cmd(
-                "show ipv6 route {} {}".format(protocol, destination))
-            v6_table = textfsm_extractor(self, "show_ipv6_route", raw_v6_table)
-        route_table = v4_table + v6_table
-
-        out = {}
-        for route in route_table:
-            if not out.get(route['destination']):
-                out[route['destination']] = []
-            new_path = {}
-            new_path['protocol'] = route['type']
-            new_path['preference'] = int(route['distance'])
-            new_path['next_hop'] = route['gateway']
-            out[route['destination']].append(new_path)
-        return out
-
-    def _run_cmd(self, cmd):
-        url = self._api_url + 'cli'
-        data = {}
-        data['cmd'] = cmd
-        cmd_post = self._apisession.post(url, json=data)
-        if cmd_post.status_code == 200:
-            return base64.b64decode(
-                cmd_post.json()['result_base64_encoded']).decode('utf-8')
-        else:
-            raise CommandErrorException("Parsing CLI commands failed")
-
-    def _config_batch(self, cmd_list):
-        url = self._api_url + 'cli_batch'
-        data = {}
-        data['cli_batch_base64_encoded'] = ArubaOSS._str_to_b64(
-                                            '\n'.join(cmd_list))
-        batch_run = self._apisession.post(url, json=data)
-        if batch_run.status_code == 202:
-            check_status = self._apisession.get(url + "/status")
-            if check_status.status_code == 200:
-                for cmd_status in check_status.json()['cmd_exec_logs']:
-                    if cmd_status['status'] != "CCS_SUCCESS":
-                        log.debug("command failed to execute with error \
-                                 {}".format(cmd_status['result']))
-                        return False
-                    else:
-                        return True
-                return True
-        else:
-            log.debug("Failed to paste commands")
-            return False
-
-    def _backup_config(self, config='running', destination='backup'):
-        """Backup config."""
-        """Supported configs
-        API:
-            - "CT_RUNNING_CONFIG",
-            - "CT_STARTUP_CONFIG"
-        """
-        url = self._api_url + 'system/config/cfg_backup_files'
-        payload = {}
-        if destination == 'backup':
-            payload['file_name'] = 'backup_{}'.format(config)
-        elif destination == 'REST_Payload_Backup':
-            """
-            Discard running config by copying running to candidate
-            """
-            payload['file_name'] = 'REST_Payload_Backup'
-
-        if config == 'running':
-            payload['config_type'] = 'CT_RUNNING_CONFIG'
-        elif config == 'startup':
-            payload['config_type'] = 'CT_STARTUP_CONFIG'
-        else:
-            "unsupported argument; raise error"
-            return False
-        cmd_post = self._apisession.post(url, json=payload)
-        if not 300 > cmd_post.status_code >= 200:
-            "raise error"
-            pass
-        else:
-            return cmd_post.json()
+        Is alive method.
+
+        :return:
+        """
+        ret = is_alive(self=self)
+
+        return ret
+
+    def load_merge_candidate(self, filename=None, config=None):
+        """
+        Merge candidate configuration with the running one.
+
+        Imperative config change:
+         Merge new config with existing one. There's no config validation
+         nor atomic commit!. Only configuration commands are supported,
+         "configure terminal" is not required. Use with caution.
+
+        :param filename:
+        :param config:
+        :return:
+        """
+        ret = load_merge_candidate(
+            self=self, filename=filename, config=config
+        )
+
+        return ret
+
+    def load_replace_candidate(self, filename=None, config=None):
+        """
+        Replace running config with the candidate.
+
+        Implentation of napalm module load_replace_candidate()
+        ArubaOS-Switch supports payload_type options:
+            - "RPT_PATCH_FILE" -> not implemented
+            - "RPT_BACKUP_FILE" -> Implemented
+
+        Note: the maximum content_length = 16072,
+        "HTTP/1.1 413 Request Entity Too Large" is returned above that!!!
+
+        :param filename:
+        :param config:
+        :return:
+        """
+        ret = load_replace_candidate(
+            self=self, filename=filename, config=config
+        )
+
+        return ret
+
+    def load_template(
+        self, template_name, template_source=None, template_path=None, **template_vars
+    ):
+        """
+        Load template - NOT IMPLEMENTED.
+
+        :param template_name:
+        :param template_source:
+        :param template_path:
+        :param template_vars:
+        :return:
+        """
+        return super(ArubaOSS, self).load_template()
+
+    def open(self):
+        """
+        Open connection to the network device.
+
+        :return:
+        """
+        self.connection.login(
+            hostname=self.hostname,
+            username=self.username,
+            password=self.password,
+            timeout=self.timeout,
+            optional_args=self.optional_args,
+        )
+
+        return True
+
+    def ping(
+        self,
+        destination,
+        source="",
+        ttl=255,
+        timeout=2,
+        size=100,
+        count=5,
+        vrf="",
+        source_interface=""
+    ):
+        """
+        Execute ping on the device and returns a dictionary with the result.
+
+        :param destination: needed argument
+        :param source: not implemented as not available from device
+        :param ttl: not implemented as not available from device
+        :param timeout: Maximum seconds to wait after sending final packet
+        :param vrf: not implemented as not available from device
+        :param size: not implemented as not available from device
+        :param count: not implemented as not available from device
+        :param source_interface: not  implemented as not available from device
+        :return: returns a dictionary containing the hops and probes
+        """
+        ret = ping(self=self, destination=destination, timeout=timeout)
+        return ret
+
+    def post_connection_tests(self):
+        """
+        Post connection tests - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).post_connection_tests()
+
+    def pre_connection_tests(self):
+        """
+        Pre connection tests - NOT IMPLEMENTED.
+
+        :return:
+        """
+        return super(ArubaOSS, self).pre_connection_tests()
 
     def rollback(self):
-        """Rollback configuration."""
-        diff = self.compare_config()
-        if diff != '' and isinstance(diff, dict):
-            if not (len(diff.get('diff_add_list'))
-                    and len(diff.get('diff_remove_list'))):
-                self._commit_candidate(config='backup_running')
-                return True
-            else:
-                return False
+        """
+        Rollback configuration.
 
-    def close(self):
-        """Close device connection and delete sessioncookie."""
-        rest_logout = self._apisession.delete(self._login_url)
-        self._headers['cookie'] = ''
-
-        if rest_logout.status_code != 204:
-            log.debug("Logout Failed")
-        else:
-            return "logout ok"
+        :return:
+        """
+        ret = rollback(self=self)
+
+        return ret
+
+    def traceroute(self, destination, source="", ttl=255, timeout=2, vrf=""):
+        """
+        Execute traceroute on the device.
+
+        :param destination: needed argument
+        :param source: not implemented as not available from device
+        :param ttl: not implemented as not available from device
+        :param timeout: not implemented as not available from device
+        :param vrf: not implemented as not available from device
+        :return: returns a dictionary containing the hops and probes
+        """
+        ret = traceroute(self=self, destination=destination)
+
+        return ret
diff --git a/napalm_arubaoss/helper/__init__.py b/napalm_arubaoss/helper/__init__.py
new file mode 100644
index 0000000..2b58398
--- /dev/null
+++ b/napalm_arubaoss/helper/__init__.py
@@ -0,0 +1,65 @@
+"""Import all functions of this directory."""
+
+from napalm_arubaoss.helper.base import Connection
+from napalm_arubaoss.helper.commit_config import commit_config
+from napalm_arubaoss.helper.compare_config import compare_config
+from napalm_arubaoss.helper.confirm_commit import confirm_commit
+from napalm_arubaoss.helper.get_arp_table import get_arp_table
+from napalm_arubaoss.helper.get_config import get_config
+from napalm_arubaoss.helper.get_facts import get_facts
+from napalm_arubaoss.helper.get_interfaces import get_interfaces
+from napalm_arubaoss.helper.get_interfaces_ip import get_interfaces_ip
+from napalm_arubaoss.helper.get_lldp_neighbors import get_lldp_neighbors
+from napalm_arubaoss.helper.get_lldp_neighbors_detail import get_lldp_neighbors_detail
+from napalm_arubaoss.helper.get_mac_address_table import get_mac_address_table
+from napalm_arubaoss.helper.get_ntp_servers import get_ntp_servers
+from napalm_arubaoss.helper.get_ntp_stats import get_ntp_stats
+from napalm_arubaoss.helper.get_route_to import get_route_to
+from napalm_arubaoss.helper.has_pending_commit import has_pending_commit
+from napalm_arubaoss.helper.is_alive import is_alive
+from napalm_arubaoss.helper.load_merge_candidate import load_merge_candidate
+from napalm_arubaoss.helper.load_replace_candidate import load_replace_candidate
+from napalm_arubaoss.helper.ping import ping
+from napalm_arubaoss.helper.rollback import rollback
+from napalm_arubaoss.helper.traceroute import traceroute
+from napalm_arubaoss.helper.utils import (
+    backup_config,
+    mac_reformat,
+    commit_candidate,
+    config_batch,
+    read_candidate,
+    str_to_b64,
+    transaction_status,
+)
+
+__all__ = (
+    "Connection",
+    "backup_config",
+    "commit_candidate",
+    "commit_config",
+    "compare_config",
+    "config_batch",
+    "confirm_commit",
+    "get_mac_address_table",
+    "get_facts",
+    "get_arp_table",
+    "get_config",
+    "get_interfaces",
+    "get_interfaces_ip",
+    "get_lldp_neighbors",
+    "get_lldp_neighbors_detail",
+    "get_ntp_stats",
+    "get_ntp_servers",
+    "get_route_to",
+    "has_pending_commit",
+    "is_alive",
+    "load_merge_candidate",
+    "load_replace_candidate",
+    "mac_reformat",
+    "ping",
+    "read_candidate",
+    "rollback",
+    "str_to_b64",
+    "traceroute",
+    "transaction_status",
+)
diff --git a/napalm_arubaoss/helper/base.py b/napalm_arubaoss/helper/base.py
new file mode 100644
index 0000000..f4621e9
--- /dev/null
+++ b/napalm_arubaoss/helper/base.py
@@ -0,0 +1,237 @@
+"""Create the Session."""
+
+
+import base64
+import logging
+
+from json import JSONDecodeError
+
+from requests import Session
+from requests.models import Response
+from napalm.base.exceptions import ConnectAuthError, NapalmException
+
+
+logger = logging.getLogger("arubaoss.helper.base")
+
+
+class KeepAliveBoolError(NapalmException):
+    pass
+
+
+class Connection:
+    """Connection class."""
+
+    config = {"api_url": ""}
+
+    def __init__(self):
+        """Initialize the class."""
+        self._apisession: Session = Session()
+
+        self.hostname = ""
+        self.username = ""
+        self.password = ""
+        self.timeout = 10
+        self.api = "v6"
+        self.proto = "https"
+
+        self.cli_output = {}
+
+    def login(self, hostname, username="", password="", timeout=10, optional_args=None):
+        """
+        Login to the Rest-API.
+
+        :param hostname:
+        :param username:
+        :param password:
+        :param timeout:
+        :param optional_args:
+        :return:
+        """
+        logger.debug("logging in")
+        self.hostname = hostname
+        self.username = username
+        self.password = password
+        self.timeout = timeout
+
+        self.api = optional_args.get("api", "v6")
+
+        if not optional_args:
+            optional_args = {}
+
+        self.proto = "https" if optional_args.get("ssl", True) else "http"
+
+        self.config["api_url"] = "{}://{}/rest/{}/".format(
+            self.proto, self.hostname, self.api
+        )
+
+        url = self.config["api_url"] + "login-sessions"
+
+        self._apisession = Session()
+        self._apisession.verify = optional_args.get("ssl_verify", True)
+        self._apisession.headers = {
+            "Content-Type": "application/json",
+        }
+
+        keep_alive = optional_args.get(
+            "keepalive",
+            optional_args.get(
+                "keep_alive",
+                False
+            )
+        )
+
+        if not isinstance(keep_alive, bool):
+            raise KeepAliveBoolError(
+                "\"keepalive\"/\"keep_alive\" needs to be of type \"bool\""
+            )
+
+        if not keep_alive:
+            self._apisession.headers.update(
+                {"Connection": "close"}
+            )
+
+        params = {"userName": self.username, "password": self.password}
+
+        rest_login = self.post(url, json=params, timeout=self.timeout)
+
+        if not rest_login.status_code == 201:
+            raise ConnectAuthError("Login failed")
+
+        session = rest_login.json()
+        self._apisession.headers["cookie"] = session["cookie"]
+
+    def logout(self):
+        """Close device connection and delete sessioncookie."""
+        url = self.config["api_url"] + "login-sessions"
+
+        rest_logout = self.delete(url, timeout=self.timeout)
+        self._apisession.headers["cookie"] = ""
+
+        if not rest_logout.status_code == 204:
+            logger.debug("Logout Failed")
+        else:
+            self._apisession.close()
+            return "logout ok"
+
+    def get(self, *args, **kwargs) -> Response:
+        """
+        Call a single command (Helper-Function).
+
+        :param args:
+        :param kwargs:
+        :return:
+        """
+        ret = self._apisession.get(*args, **kwargs)
+
+        return ret
+
+    def post(self, *args, **kwargs) -> Response:
+        """
+        Call a single command (Helper-Function).
+
+        :param args:
+        :param kwargs:
+        :return:
+        """
+        ret = self._apisession.post(*args, **kwargs)
+
+        return ret
+
+    def put(self, *args, **kwargs) -> Response:
+        """
+        Call a single command (Helper-Function).
+
+        :param args:
+        :param kwargs:
+        :return:
+        """
+        ret = self._apisession.put(*args, **kwargs)
+
+        return ret
+
+    def delete(self, *args, **kwargs) -> Response:
+        """
+        Call a single command (Helper-Function).
+
+        :param args:
+        :param kwargs:
+        :return:
+        """
+        ret = self._apisession.delete(*args, **kwargs)
+
+        return ret
+
+    def cli(self, commands):
+        """
+        Run CLI commands through the REST API.
+
+        :param commands:
+        :return:
+        """
+        self.cli_output = {}
+
+        url = self.config["api_url"] + "cli"
+
+        if not isinstance(commands, list):
+            self.cli_output["error"] = "Provide a list of commands"
+            return self.cli_output
+
+        for command in commands:
+            self._apisession.post(
+                url=url,
+                json={"cmd": command},
+                timeout=self.timeout,
+                hooks={
+                    "response": self._callback(
+                        output=self.cli_output,
+                        command=command
+                    )
+                }
+            )
+
+        return self.cli_output
+
+    def _callback(self, *args, **kwargs):
+        """
+        Return Callback for request calls.
+
+        ArubaOSS.cli uses it.
+
+        :param args:
+        :param kwargs:
+        :return: callback function
+        """
+
+        def callback(call, *cargs, **ckwargs):
+            cli_output = kwargs.get("output")
+            passed_cmd = kwargs.get("command")
+            try:
+                json_ret = call.json()
+            except JSONDecodeError:
+                json_ret = {}
+
+            cmd = json_ret.get("cmd")
+            result_base64 = json_ret.get("result_base64_encoded", "")
+
+            if not cmd == passed_cmd:
+                cli_output[passed_cmd] = "cmd not found in output"
+                return
+
+            if not result_base64:
+                cli_output[passed_cmd] = "no result found in output"
+                return
+
+            result = base64.b64decode(result_base64).decode("utf-8")
+            cli_output[passed_cmd] = result
+
+        return callback
+
+    def run_cmd(self, cmd):
+        """
+        Run the command on the device and return the raw output.
+
+        :param cmd:
+        :return:
+        """
+        ret = self.cli([cmd])
+        return ret[cmd]
diff --git a/napalm_arubaoss/helper/commit_config.py b/napalm_arubaoss/helper/commit_config.py
new file mode 100644
index 0000000..73e3b86
--- /dev/null
+++ b/napalm_arubaoss/helper/commit_config.py
@@ -0,0 +1,60 @@
+"""Backups and commit the configuration, and handles commit confirm."""
+
+import logging
+
+from napalm.base.exceptions import CommitError
+
+from napalm_arubaoss.helper.utils import backup_config, commit_candidate
+from napalm_arubaoss.helper.get_config import get_config
+from napalm_arubaoss.helper.load_replace_candidate import load_replace_candidate
+from napalm_arubaoss.helper.has_pending_commit import has_pending_commit
+
+logger = logging.getLogger("arubaoss.helper.commit_config")
+
+
+def commit_config(self, message="", revert_in=None):
+    """
+    Backups and commit the configuration, and handles commit confirm.
+
+    :param self: object from class
+    :param message: Optional - configuration session commit message
+    :type message: str
+    :param revert_in: Optional - number of seconds before the configuration
+    will be rolled back using a commit confirm mechanism.
+    :type revert_in: int|None
+    """
+    if message:
+        msg = "\"message\" support has not been added " \
+              "for this getter on this platform."
+        raise NotImplementedError(msg)
+
+    if not revert_in:
+        revert_in = 0
+
+    if not type(revert_in) == int:
+        err_msg = "Invalid \"revert_in\" value, "\
+                  "commit confirn cannot be carried out"
+        logger.error(err_msg)
+        raise TypeError(err_msg)
+
+    if has_pending_commit(self=self):
+        raise CommitError("Pending commit confirm already in process!")
+
+    backup_config(self=self)
+
+    logger.debug('Confirm rollback time is {}'.format(str(revert_in)))
+    if revert_in > 0:
+        candidate = get_config(
+            self=self,
+            retrieve='candidate'
+        )['candidate']
+        candidate = candidate[:-2]  # remove unneeded chars
+
+        candidate_confirm = (
+            f"{candidate}"
+            f"job ROLLBACK delay {str(revert_in)} "
+            "\"cfg-restore flash backup_running\"\n"
+        )
+        load_replace_candidate(self=self, config=candidate_confirm)
+
+    commit_candidate(self=self, config="REST_Payload_Backup")
diff --git a/napalm_arubaoss/helper/compare_config.py b/napalm_arubaoss/helper/compare_config.py
new file mode 100644
index 0000000..82d37ac
--- /dev/null
+++ b/napalm_arubaoss/helper/compare_config.py
@@ -0,0 +1,52 @@
+"""Backups and commit the configuration, and handles commit confirm."""
+
+import logging
+
+from time import sleep
+
+from napalm.base.exceptions import CommandErrorException
+
+logger = logging.getLogger("arubaoss.helper.compare_config")
+
+
+def compare_config(self):
+    """
+    Compare the running config with the candidate one.
+
+    :param self: object from class
+    :return:
+    """
+    url = self.connection.config["api_url"] + "system/config/cfg_restore/latest_diff"
+    check_url = url + "/status"
+    data = {
+        "server_type": "ST_FLASH",
+        "file_name": "REST_Payload_Backup",
+        "is_oobm": False,
+    }
+    # trigger configuration comparison
+    diff = self.connection.post(url, json=data)
+
+    if not diff.ok:
+        raise CommandErrorException("diff generation failed, raise status")
+
+    for loop_round in range(1, 6):
+        # wait a second to give the device time to process
+        logger.debug(f"loop round \"{loop_round}\"")
+        sleep(1)
+
+        diff_output = self.connection.get(check_url)
+
+        if not diff_output.status_code == 200:
+            raise CommandErrorException("diff generation failed, raise status")
+
+        if (
+            not diff_output.json()["diff_add_list"]
+            and not diff_output.json()["diff_remove_list"]
+        ):
+            if loop_round == 5:
+                # return empty string to signal the candidate
+                # and running configs are the same
+                return ""
+            continue
+        else:
+            return diff_output.json()
diff --git a/napalm_arubaoss/helper/confirm_commit.py b/napalm_arubaoss/helper/confirm_commit.py
new file mode 100644
index 0000000..2862203
--- /dev/null
+++ b/napalm_arubaoss/helper/confirm_commit.py
@@ -0,0 +1,23 @@
+"""Confirm the changes requested via commit_config when `type(revert_in)=int`."""
+
+import logging
+
+from napalm_arubaoss.helper.commit_config import commit_config
+from napalm_arubaoss.helper.has_pending_commit import has_pending_commit
+from napalm_arubaoss.helper.load_merge_candidate import load_merge_candidate
+
+logger = logging.getLogger('arubaoss.helper.confirm_commit')
+
+
+def confirm_commit(self):
+    """
+    Confirm the changes requested via commit_config when `type(revert_in)=int`.
+
+    :param self: object from class
+    :return:
+    """
+    if has_pending_commit(self=self):
+        load_merge_candidate(self=self, config="no job ROLLBACK")
+        ret = commit_config(self=self)
+
+        return ret
diff --git a/napalm_arubaoss/helper/get_arp_table.py b/napalm_arubaoss/helper/get_arp_table.py
new file mode 100644
index 0000000..f86d265
--- /dev/null
+++ b/napalm_arubaoss/helper/get_arp_table.py
@@ -0,0 +1,32 @@
+"""Backups and commit the configuration, and handles commit confirm."""
+
+from napalm.base.helpers import textfsm_extractor
+import logging
+
+from napalm_arubaoss.helper.utils import mac_reformat
+
+logger = logging.getLogger("arubaoss.helper.get_arp_table")
+
+
+def get_arp_table(self, vrf):
+    """
+    Get device's ARP table.
+
+    :param self: object from class
+    :param vrf: not supported
+    :return:
+    """
+    if vrf:
+        msg = "VRF support has not been added " \
+              "for this getter on this platform."
+        raise NotImplementedError(msg)
+
+    raw_arp = self.connection.run_cmd("show arp")
+    arp_table = textfsm_extractor(self, "show_arp", raw_arp)
+    for arp in arp_table:
+        arp["interface"] = arp.pop("port")
+        arp["mac"] = mac_reformat(arp["mac"])
+        arp["age"] = -1.00  # needs to be a float - -1.00 to signal "N/A"
+        arp.pop("type")  # pop because it is not present in the napalm model
+
+    return arp_table
diff --git a/napalm_arubaoss/helper/get_config.py b/napalm_arubaoss/helper/get_config.py
new file mode 100644
index 0000000..e4dc113
--- /dev/null
+++ b/napalm_arubaoss/helper/get_config.py
@@ -0,0 +1,45 @@
+"""Get configuration stored on the device."""
+
+import logging
+
+logger = logging.getLogger("arubaoss.helper.get_config")
+
+
+def get_config(self, retrieve="all", full=False):
+    """
+    Get configuration stored on the device.
+
+    :param self: object from class
+    :param retrieve:
+    :param full:
+
+    :return:
+    """
+    if full:
+        msg = "\"full\" is not available " \
+              "for this getter on this platform."
+        raise NotImplementedError(msg)
+
+    out = {"startup": "", "candidate": "", "running": ""}
+
+    cmd_mapping = {
+        "display saved-configuration": "startup",
+        "show config REST_Payload_Backup": "candidate",
+        "show running-config": "running",
+    }
+    cmd_mapping = (
+        {key: value for key, value in cmd_mapping.items() if retrieve == value}
+        if not retrieve == "all"
+        else cmd_mapping
+    )
+
+    outputs = self.connection.cli(
+        [
+            cmd for cmd, config in cmd_mapping.items()
+        ]
+    )
+
+    for okey, ovalue in outputs.items():
+        out[cmd_mapping[okey]] = ovalue
+
+    return out
diff --git a/napalm_arubaoss/helper/get_facts.py b/napalm_arubaoss/helper/get_facts.py
new file mode 100644
index 0000000..3635234
--- /dev/null
+++ b/napalm_arubaoss/helper/get_facts.py
@@ -0,0 +1,92 @@
+"""Get general device information."""
+
+import logging
+
+logger = logging.getLogger("arubaoss.helper.get_facts")
+
+
+def get_facts(self):
+    """
+    Get general device information.
+
+    :param self: object from class
+    :return:
+    """
+    url = "{base_url}{endpoint}"
+
+    system_status_url = url.format(
+        base_url=self.connection.config["api_url"],
+        endpoint="system/status"
+    )
+    switch_status_url = url.format(
+        base_url=self.connection.config["api_url"],
+        endpoint="system/status/switch"
+    )
+    dns_url = url.format(
+        base_url=self.connection.config["api_url"],
+        endpoint="dns"
+    )
+
+    out = {
+        "uptime": -1,
+        "vendor": "HPE Aruba",
+        "model": "",
+        "hostname": "",
+        "fqdn": "",
+        "os_version": "",
+        "serial_number": "",
+        "interface_list": [],
+
+    }
+
+    call = self.connection.get(system_status_url)
+
+    # If it's a Stack, use `/system/status/global_info`
+    if call.status_code == 404:
+        system_status_url = url.format(
+            base_url=self.connection.config["api_url"],
+            endpoint="system/status/global_info"
+        )
+        call = self.connection.get(system_status_url)
+
+    if call.ok:
+        rest_out = call.json()
+        out["hostname"] = rest_out.get("name", "")
+        out["os_version"] = rest_out.get("firmware_version", "")
+        out["serial_number"] = rest_out.get("serial_number", "")
+        out["model"] = rest_out.get("product_model", "")
+
+        # get domain name to generate the FQDN
+        call = self.connection.get(dns_url)
+        if call.ok:
+            rest_out = call.json()
+            # return "{{hostname}}." if no domain is configured
+            domain_names = rest_out.get("dns_domain_names")
+            domain = ".{}".format(domain_names[0]) if domain_names else "."
+            out["fqdn"] = "{hostname}{domain}".format(
+                hostname=out["hostname"],
+                domain=domain
+            )
+
+    # Get interface list
+    call = self.connection.get(switch_status_url)
+    if call.ok:
+        rest_out = call.json()
+        if rest_out.get("switch_type", "ST_STANDALONE") == "ST_STACKED":
+            serial_url = url.format(
+                base_url=self.connection.config["api_url"],
+                endpoint="system/status/members/1"
+            )
+            call = self.connection.get(serial_url)
+
+            if call.ok:
+                out["serial_number"] = call.json().get("serial_number", "")
+                out["model"] = call.json().get("product_model", "")
+
+        for blade in rest_out.get("blades", []):
+            for ports in blade.get("data_ports", []):
+                out["interface_list"].append(
+                    ports.get("port_name", "")
+                )
+
+    return out
diff --git a/napalm_arubaoss/helper/get_interfaces.py b/napalm_arubaoss/helper/get_interfaces.py
new file mode 100644
index 0000000..0949f1a
--- /dev/null
+++ b/napalm_arubaoss/helper/get_interfaces.py
@@ -0,0 +1,74 @@
+"""Get the interfaces of the device."""
+
+import logging
+
+logger = logging.getLogger("arubaoss.helper.get_interfaces")
+
+
+def get_interfaces(self):
+    """Get IP interface IP addresses."""
+    url_ports = self.connection.config["api_url"] + "ports"
+    url_port_stats = self.connection.config["api_url"] + "port-statistics"
+
+    interface_template = {
+        'is_up': False,
+        'is_enabled': False,
+        'description': '',
+        'last_flapped': -1.0,
+        'speed': 1000,
+        'mtu': -1,
+        'mac_address': 'FA:16:3E:57:33:61',
+    }
+    output = {}
+
+    resp_ports = self.connection.get(url_ports)
+    resp_port_stats = self.connection.get(url_port_stats)
+
+    if not resp_ports.status_code == 200:
+        logger.error("didn't get status code 200 from %s", url_ports)
+        return output
+
+    if not resp_port_stats.status_code == 200:
+        logger.error("didn't get status code 200 from %s", url_port_stats)
+        return output
+
+    resp_ports_json = resp_ports.json()
+    for interface in resp_ports_json.get("port_element", []):
+        # show interfaces 1 | include MAC[[:space:]]Address
+        i_id = interface.get("id")
+        description = interface.get("name")
+        is_up = interface.get("is_port_up")
+        is_enabled = interface.get("is_port_enabled")
+
+        if i_id not in output.keys():
+            output[i_id] = interface_template.copy()
+
+        output[i_id]["description"] = description
+        output[i_id]["is_up"] = is_up
+        output[i_id]["is_enabled"] = is_enabled
+
+    resp_port_stats_json = resp_port_stats.json()
+    for interface_stats in resp_port_stats_json.get("port_statistics_element", []):
+        i_id = interface_stats.get("id")
+        speed = interface_stats.get("port_speed_mbps")
+
+        if i_id not in output.keys():
+            output[i_id] = interface_template.copy()
+
+        output[i_id]["speed"] = speed
+
+    for interface_id, interface_values in output.items():
+        resp = self.connection.run_cmd(
+            f"show interfaces {interface_id} | include MAC[[:space:]]Address"
+        )
+
+        resp = resp.replace(" ", "")
+        resp = resp.split(":")
+        mac_raw = resp[1]
+        mac_raw = mac_raw.replace("-", "")
+        mac = ':'.join(mac_raw[i:i+2] for i in range(0, 12, 2))
+        mac = mac.upper()
+
+        output[interface_id]["mac_address"] = mac
+
+    return output
diff --git a/napalm_arubaoss/helper/get_interfaces_ip.py b/napalm_arubaoss/helper/get_interfaces_ip.py
new file mode 100644
index 0000000..94d15b6
--- /dev/null
+++ b/napalm_arubaoss/helper/get_interfaces_ip.py
@@ -0,0 +1,48 @@
+"""Get IP interface IP addresses."""
+
+from netaddr import IPNetwork
+import logging
+
+logger = logging.getLogger("arubaoss.helper.get_interfaces_ip")
+
+
+def get_interfaces_ip(self):
+    """
+    Get IP interface IP addresses.
+
+    !!! Looks like there's a bug n ArubaOS and is not returning IPv6
+
+    :param self: object from class
+    :return:
+    """
+    url = self.connection.config["api_url"] + "ipaddresses"
+    output = {}
+    resp = self.connection.get(url)
+    if resp.status_code == 200:
+        for address in resp.json().get("ip_address_subnet_element", []):
+            vlan_id = address.get("vlan_id", "")
+            iface_name = "VLAN{vlan_id}".format(vlan_id=str(vlan_id))
+
+            if iface_name not in output.keys():
+                output[iface_name] = {}
+
+            ip_address = address.get("ip_address", {}).get("octets")
+            ip_mask = address.get("ip_mask", {}).get("octets")
+
+            if ip_address and ip_mask:
+                ip = IPNetwork(
+                    "{ip_address}/{ip_mask}".format(
+                        ip_address=ip_address,
+                        ip_mask=ip_mask
+                    )
+                )
+
+                version = "ipv{ip_version}".format(ip_version=str(ip.version))
+
+                if version not in output[iface_name].keys():
+                    output[iface_name][version] = {}
+                output[iface_name][version][str(ip.ip)] = {
+                    "prefix_length": ip.prefixlen
+                }
+
+    return output
diff --git a/napalm_arubaoss/helper/get_lldp_neighbors.py b/napalm_arubaoss/helper/get_lldp_neighbors.py
new file mode 100644
index 0000000..9a3f622
--- /dev/null
+++ b/napalm_arubaoss/helper/get_lldp_neighbors.py
@@ -0,0 +1,31 @@
+"""Get a list of LLDP neighbors."""
+
+import logging
+
+logger = logging.getLogger("arubaoss.helper.get_lldp_neighbors")
+
+
+def get_lldp_neighbors(self):
+    """
+    Get a list of LLDP neighbors.
+
+    :param self: object from class
+    :return:
+    """
+    url = self.connection.config["api_url"] + "lldp/remote-device"
+    resp = self.connection.get(url)
+    logger.debug("API returned {}".format(resp.status_code))
+
+    if resp.ok:
+        neighbor_table = {}
+        for neighbor in resp.json()["lldp_remote_device_element"]:
+            port = neighbor["local_port"]
+            if not neighbor_table.get(port):
+                neighbor_table[port] = []
+            remote_device = {
+                "hostname": neighbor.get("system_name"),
+                "port": neighbor.get("port_id"),
+            }
+            neighbor_table[port].append(remote_device)
+
+        return neighbor_table
diff --git a/napalm_arubaoss/helper/get_lldp_neighbors_detail.py b/napalm_arubaoss/helper/get_lldp_neighbors_detail.py
new file mode 100644
index 0000000..e4b399e
--- /dev/null
+++ b/napalm_arubaoss/helper/get_lldp_neighbors_detail.py
@@ -0,0 +1,49 @@
+"""Get LLDP neighbor information."""
+
+import logging
+
+logger = logging.getLogger("arubaoss.helper.get_lldp_neighbors_detail")
+
+
+def get_lldp_neighbors_detail(self, *args, **kwargs):
+    """
+    Get LLDP neighbor information.
+
+    :param self: object from class
+    :param args:
+    :param kwargs:
+    :return:
+    """
+    url = self.connection.config["api_url"] + "lldp/remote-device"
+    resp = self.connection.get(url)
+    logger.debug("API returned {}".format(resp.status_code))
+
+    if resp.ok:
+        neighbor_table = {}
+        for neighbor in resp.json()["lldp_remote_device_element"]:
+            port = neighbor["local_port"]
+            if not neighbor_table.get(port):
+                neighbor_table[port] = []
+            remote_device = {
+                "parent_interface": "",
+                "remote_system_name": neighbor.get("system_name"),
+                "remote_chassis_id": neighbor.get("chassis_id"),
+                "remote_port": neighbor.get("port_id"),
+                "remote_port_description": neighbor.get("port_description"),
+                "remote_system_description": "".join(
+                    neighbor.get("system_description")
+                ),
+                "remote_system_capab": [
+                    k
+                    for k, v in neighbor.get("capabilities_supported").items()
+                    if v is True
+                ],
+                "remote_system_enable_capab": [
+                    k
+                    for k, v in neighbor.get("capabilities_enabled").items()
+                    if v is True
+                ],
+            }
+            neighbor_table[port].append(remote_device)
+
+        return neighbor_table
diff --git a/napalm_arubaoss/helper/get_mac_address_table.py b/napalm_arubaoss/helper/get_mac_address_table.py
new file mode 100644
index 0000000..131540b
--- /dev/null
+++ b/napalm_arubaoss/helper/get_mac_address_table.py
@@ -0,0 +1,33 @@
+"""Get the mac-address table of the device."""
+
+import logging
+
+from napalm_arubaoss.helper.utils import mac_reformat
+
+logger = logging.getLogger("arubaoss.helper.get_mac_address_table")
+
+
+def get_mac_address_table(self):
+    """
+    Get the mac-address table of the device.
+
+    :param self: object from class
+    :return:
+    """
+    url = self.connection.config["api_url"] + "mac-table"
+    resp = self.connection.get(url)
+    if resp.status_code == 200:
+        table = []
+        for entry in resp.json().get("mac_table_entry_element"):
+            item = {
+                "mac": mac_reformat(entry["mac_address"]),
+                "interface": entry["port_id"],
+                "vlan": entry["vlan_id"],
+                "active": True,
+                "static": False,  # not supported
+                "moves": 0,  # not supported
+                "last_move": 0.0  # not supported
+            }
+            table.append(item)
+
+        return table
diff --git a/napalm_arubaoss/helper/get_ntp_servers.py b/napalm_arubaoss/helper/get_ntp_servers.py
new file mode 100644
index 0000000..334448e
--- /dev/null
+++ b/napalm_arubaoss/helper/get_ntp_servers.py
@@ -0,0 +1,34 @@
+"""Get NTP servers."""
+
+import logging
+
+logger = logging.getLogger("arubaoss.helper.get_ntp_servers")
+
+
+def get_ntp_servers(self):
+    """
+    Get NTP servers.
+
+    # TODO: add IPv6 support, currently getting 404 from the API
+
+    :param self: object from class
+    :return:
+    """
+    base_url = self.connection.config["api_url"]
+    ipv4_url = f"{base_url}config/ntp/server/ip4addr"
+    name_url = f"{base_url}config/ntp/server-name/ASCII-STR"
+
+    ipv4_resp = self.connection.get(ipv4_url)
+    name_resp = self.connection.get(name_url)
+
+    output = {}
+
+    if ipv4_resp.status_code == 200:
+        for server in ipv4_resp.json().get("ntpServerIp4addr_element"):
+            output[server["ip4addr"]["ip4addr_value"]] = {}
+
+    if name_resp.status_code == 200:
+        for server in name_resp.json().get("ntpServerNameASCIISTR_element"):
+            output[server["ASCII-STR"]["ASCII-STR_value"]] = {}
+
+        return output
diff --git a/napalm_arubaoss/helper/get_ntp_stats.py b/napalm_arubaoss/helper/get_ntp_stats.py
new file mode 100644
index 0000000..576f760
--- /dev/null
+++ b/napalm_arubaoss/helper/get_ntp_stats.py
@@ -0,0 +1,78 @@
+"""Get NTP peer statistics."""
+
+import logging
+
+logger = logging.getLogger("arubaoss.helper.get_ntp_stats")
+
+
+def get_ntp_stats(self):
+    """
+    Get NTP peer statistics.
+
+    :param self: object from class
+    :return:
+    """
+    out = []
+    base_url = self.connection.config["api_url"]
+    ret = self.connection.get(
+        f"{base_url}monitoring/ntp/servers"
+    )
+
+    ret_json = ret.json() if hasattr(ret, "json") else {}
+
+    ntp_ips = [
+        address.get("Server address")
+        for address in ret_json.get("NTP_Server_Address_Information", [])
+    ]
+
+    for association in ntp_ips:
+        url = f"{base_url}monitoring/ntp/associations/detail/{association}"
+
+        resp = self.connection.get(url)
+        if resp.status_code == 200:
+            data = resp.json() if hasattr(resp, "json") else {}
+
+            ntp_entry = _create_ntp_entry(data)
+
+            if ntp_entry:
+                out.append(ntp_entry)
+
+    if not ntp_ips:
+        # assumes no IPs have been configured but a name
+        url = f"{base_url}monitoring/ntp/associations/detail"
+        resp = self.connection.get(url)
+
+        if resp.status_code == 200:
+            data = resp.json() if hasattr(resp, "json") else {}
+
+            ntp_entry = _create_ntp_entry(data)
+
+            if ntp_entry:
+                out.append(ntp_entry)
+
+    return out
+
+
+def _create_ntp_entry(data):
+    if not data:
+        return None
+
+    ntp_entry = {
+        "remote": data.get("IP Address", ""),
+        "referenceid": data.get("Reference ID", ""),
+        "stratum": int(data.get("Stratum", 0)),
+        "type": data.get("Peer Mode", ""),
+        "when": data.get("Origin Time", ""),
+        "hostpoll": int(data.get("Peer Poll Intvl", 0)),
+        "reachability": int(data.get("Reach", 0)),
+        "delay": float(data.get("Root Delay", "").split(" ")[0]),
+        "offset": float(data.get("Offset", "").split(" ")[0]),
+        "jitter": float(data.get("Root Dispersion", "").split(" ")[0]),
+    }
+
+    if data.get("Status").find("Master") == -1:
+        ntp_entry["synchronized"] = False
+    else:
+        ntp_entry["synchronized"] = True
+
+    return ntp_entry
diff --git a/napalm_arubaoss/helper/get_route_to.py b/napalm_arubaoss/helper/get_route_to.py
new file mode 100644
index 0000000..2547022
--- /dev/null
+++ b/napalm_arubaoss/helper/get_route_to.py
@@ -0,0 +1,106 @@
+"""Get route to destination."""
+
+from napalm.base.helpers import textfsm_extractor
+from netaddr import IPNetwork
+import logging
+
+
+logger = logging.getLogger("arubaoss.helper.get_route_to")
+
+
+def get_route_to(self, destination="", protocol=""):
+    """
+    Get route to destination.
+
+    :param self: object from class
+    :param destination:
+    :param protocol:
+    :return:
+    """
+    inner_dictionary = {
+        "protocol": "",
+        "current_active": True,
+        "last_active": True,
+        "age": -1,
+        "next_hop": "",
+        "outgoing_interface": "",
+        "selected_next_hop": True,
+        "preference": -1,
+        "inactive_reason": "",
+        "routing_table": "",
+        "protocol_attributes": {}
+    }
+
+    bgp_dictionary = {
+        "local_as": -1,
+        "remote_as": -1,
+        "peer_id": "",
+        "as_path": "",
+        "communities": -1,
+        "local_preference": -1,
+        "preference2": -1,
+        "metric": -1,
+        "metric2": -1
+    }
+
+    isis_dictionary = {
+        "level": -1
+    }
+
+    if destination:
+        ip_address = IPNetwork(destination)
+
+        cmds = {
+            4: {
+                "template": "show_ip_route",
+                "command": "show ip route {} {}".format(ip_address.ip, protocol),
+            },
+            6: {
+                "template": "show_ipv6_route",
+                "command": "show ipv6 route {} {}".format(ip_address.ip, protocol),
+            },
+        }
+        cmd_dict = cmds[ip_address.version]
+        ret = self.connection.run_cmd(cmd_dict["command"])
+
+        route_table = textfsm_extractor(self, cmd_dict["template"], ret)
+    else:
+        cmds = [
+            {
+                "template": "show_ip_route",
+                "command": "show ip route {} {}".format(destination, protocol),
+            },
+            {
+                "template": "show_ipv6_route",
+                "command": "show ipv6 route {} {}".format(destination, protocol),
+            },
+        ]
+
+        ret = self.connection.cli([cmd["command"] for cmd in cmds])
+
+        route_table = []
+        for cmd in cmds:
+            route_table.extend(
+                textfsm_extractor(self, cmd["template"], ret[cmd["command"]])
+            )
+
+    out = {}
+    for route in route_table:
+        if not out.get(route["destination"]):
+            out[route["destination"]] = []
+
+        new_path = inner_dictionary.copy()
+        new_path["protocol"] = route["type"]
+        new_path["preference"] = int(route["distance"])
+        new_path["next_hop"] = route["gateway"]
+
+        # doesn't exist, but will be handled to be compliant with the tests
+        if route["type"] == "bgp":
+            new_path["protocol_attributes"] = bgp_dictionary.copy()
+
+        # doesn't exist, but will be handled to be compliant with the tests
+        if route["type"] == "isis":
+            new_path["protocol_attributes"] = isis_dictionary.copy()
+
+        out[route["destination"]].append(new_path)
+    return out
diff --git a/napalm_arubaoss/helper/has_pending_commit.py b/napalm_arubaoss/helper/has_pending_commit.py
new file mode 100644
index 0000000..e1f1b66
--- /dev/null
+++ b/napalm_arubaoss/helper/has_pending_commit.py
@@ -0,0 +1,24 @@
+"""Confirm the changes requested via commit_config when `type(revert_in)=int`."""
+
+import logging
+
+from napalm_arubaoss.helper.get_config import get_config
+
+
+logger = logging.getLogger('arubaoss.helper.has_pending_commit')
+
+
+def has_pending_commit(self):
+    """
+    Boolean indicates if a commit_config that needs confirmed is in process.
+
+    :param self: object from class
+    :return Boolean
+    """
+    running = get_config(self=self, retrieve='running')['running'][:-2]
+
+    for line in running.split("\n"):
+        if line.find("ROLLBACK") > 0:
+            return True
+
+    return False
diff --git a/napalm_arubaoss/helper/is_alive.py b/napalm_arubaoss/helper/is_alive.py
new file mode 100644
index 0000000..ee23a40
--- /dev/null
+++ b/napalm_arubaoss/helper/is_alive.py
@@ -0,0 +1,22 @@
+"""Check if device connection is alive."""
+
+from napalm.base.exceptions import ConnectionClosedException
+import logging
+
+logger = logging.getLogger("arubaoss.helper.is_alive")
+
+
+def is_alive(self):
+    """
+    Check if device connection is alive.
+
+    :param self: object from class
+    :return:
+    """
+    url = self.connection.config["api_url"] + "system"
+    endpoint = self.connection.get(url)
+    if endpoint.status_code == 200:
+        "Session cookie is still valid"
+        return {"is_alive": True}
+    else:
+        raise ConnectionClosedException("HTTP session is closed")
diff --git a/napalm_arubaoss/helper/load_merge_candidate.py b/napalm_arubaoss/helper/load_merge_candidate.py
new file mode 100644
index 0000000..846d55f
--- /dev/null
+++ b/napalm_arubaoss/helper/load_merge_candidate.py
@@ -0,0 +1,36 @@
+"""Merge candidate configuration with the running one."""
+
+from napalm.base.exceptions import MergeConfigException
+import logging
+
+from napalm_arubaoss.helper.utils import read_candidate, config_batch, backup_config
+
+logger = logging.getLogger("arubaoss.helper.load_merge_candidate")
+
+
+def load_merge_candidate(self, filename=None, config=None):
+    """
+    Merge candidate configuration with the running one.
+
+    Imperative config change:
+     Merge new config with existing one. There's no config validation
+     nor atomic commit!. Only configuration commands are supported,
+     "configure terminal" is not required. Use with caution.
+
+    :param self: object from class
+    :param filename:
+    :param config:
+    :return:
+    """
+    if filename:
+        config = read_candidate(candidate=filename)
+
+    if config is not None:
+        if isinstance(config, str):
+            config = config.split("\n")
+        if not config_batch(self=self, cmd_list=config):
+            raise MergeConfigException("Configuration merge failed")
+
+    # mimic load_replace_candidate behaviour, by making sure candidate
+    # config exactly matches our merged configuration
+    backup_config(self=self, destination="REST_Payload_Backup")
diff --git a/napalm_arubaoss/helper/load_replace_candidate.py b/napalm_arubaoss/helper/load_replace_candidate.py
new file mode 100644
index 0000000..188e57a
--- /dev/null
+++ b/napalm_arubaoss/helper/load_replace_candidate.py
@@ -0,0 +1,39 @@
+"""Replace running config with the candidate."""
+
+from napalm.base.exceptions import ReplaceConfigException
+import logging
+
+from napalm_arubaoss.helper.utils import str_to_b64, read_candidate
+
+logger = logging.getLogger("arubaoss.helper.load_replace_candidate")
+
+
+def load_replace_candidate(self, filename=None, config=None):
+    """
+    Replace running config with the candidate.
+
+    Implentation of napalm module load_replace_candidate()
+    ArubaOS-Switch supports payload_type options:
+        - "RPT_PATCH_FILE" -> not implemented
+        - "RPT_BACKUP_FILE" -> Implemented
+
+    Note: the maximum content_length = 16072,
+    "HTTP/1.1 413 Request Entity Too Large" is returned above that!!!
+
+    :param self: object from class
+    :param filename:
+    :param config:
+    :return:
+    """
+    url = self.connection.config["api_url"] + "system/config/payload"
+    payload = {"payload_type": "RPT_BACKUP_FILE"}
+    if filename is not None:
+        config = read_candidate(candidate=filename)
+
+    if config is not None:
+        payload["config_base64_encoded"] = str_to_b64(config)
+        load = self.connection.post(url, json=payload)
+        if load.status_code != 200:
+            raise ReplaceConfigException(
+                f"Load configuration failed - Reason: {load.text}"
+            )
diff --git a/napalm_arubaoss/helper/ping.py b/napalm_arubaoss/helper/ping.py
new file mode 100644
index 0000000..62a4c40
--- /dev/null
+++ b/napalm_arubaoss/helper/ping.py
@@ -0,0 +1,49 @@
+"""Execute ping on the device and returns a dictionary with the result."""
+
+import logging
+
+logger = logging.getLogger("arubaoss.helper.ping")
+
+
+def ping(self, destination, timeout=2):
+    """
+    Execute ping on the device and returns a dictionary with the result.
+
+    :param self: object from class
+    :param destination: needed argument
+    :param timeout: not implemented as not available from device
+    :return: returns a dictionary containing the hops and probes
+    """
+    url = self.connection.config["api_url"] + "ping"
+    data = {
+        "destination": {"ip_address": {"version": "IAV_IP_V4", "octets": destination}},
+        "timeout_in_seconds": timeout,
+    }
+    data_post = self.connection.post(url, json=data)
+
+    if not data_post.status_code == 200:
+        return {"error": "unknown host {}".format(destination)}
+
+    return_post = data_post.json() if hasattr(data_post, "json") else {}
+    result_post = return_post.get("result", "")
+    rtt = return_post.get("rtt_in_milliseconds", 0)
+    rtt_float = float(rtt)
+
+    if "PR_OK" in result_post:
+        result = {
+            "success": {
+                "probes_sent": 1,
+                "packet_loss": 0,
+                "rtt_min": rtt_float,
+                "rtt_max": rtt_float,
+                "rtt_avg": rtt_float,
+                "rtt_stddev": 0.0,
+                "results": [
+                    {
+                        "ip_address": destination,
+                        "rtt": rtt_float
+                    }
+                ]
+            }
+        }
+        return result
diff --git a/napalm_arubaoss/helper/rollback.py b/napalm_arubaoss/helper/rollback.py
new file mode 100644
index 0000000..fbd6c15
--- /dev/null
+++ b/napalm_arubaoss/helper/rollback.py
@@ -0,0 +1,25 @@
+"""Rollback configuration."""
+
+import logging
+
+from napalm_arubaoss.helper.utils import commit_candidate
+from napalm_arubaoss.helper.compare_config import compare_config
+
+logger = logging.getLogger("arubaoss.helper.rollback")
+
+
+def rollback(self):
+    """
+    Rollback configuration.
+
+    :param self: object from class
+    :return:
+    """
+    diff = compare_config(self=self)
+    if diff and isinstance(diff, dict):
+        if not (len(diff.get("diff_add_list")) and len(diff.get("diff_remove_list"))):
+            commit_candidate(self=self, config="backup_running")
+
+            return True
+        else:
+            return False
diff --git a/napalm_arubaoss/helper/traceroute.py b/napalm_arubaoss/helper/traceroute.py
new file mode 100644
index 0000000..e72fbd5
--- /dev/null
+++ b/napalm_arubaoss/helper/traceroute.py
@@ -0,0 +1,55 @@
+"""Execute traceroute on the device and returns a dictionary with the result."""
+
+import socket
+import logging
+
+logger = logging.getLogger("arubaoss.helper.traceroute")
+
+
+def traceroute(self, destination):
+    """
+    Execute traceroute on the device and returns a dictionary with the result.
+
+    :param self: object from class
+    :param destination: needed argument
+    :return: returns a dictionary containing the hops and probes
+    """
+    url = self.connection.config["api_url"] + "trace-route"
+    data = {
+        "destination": {"ip_address": {"version": "IAV_IP_V4", "octets": destination}}
+    }
+    data_post = self.connection.post(url, json=data)
+
+    if not data_post.status_code == 200:
+        return {"error": "unknown host {}".format(destination)}
+
+    ret = {"success": {}}
+    ttl_data = data_post.json().get("ttl_data", [])
+
+    for hop_count in range(len(ttl_data)):
+        ret["success"][hop_count + 1] = {"probes": {}}
+        ttl_probe_data = ttl_data[hop_count].get("ttl_probe_data", [])
+        for probe_count in range(len(ttl_probe_data)):
+            try:
+                hostname, _, _ = socket.gethostbyaddr(
+                    ttl_probe_data[probe_count]
+                    .get("gateway", {})
+                    .get("ip_address", {})
+                    .get("octets", "")
+                )
+            except socket.herror:  # fetch if nothing can be found
+                hostname = ""
+
+            probe = {
+                "rtt": float(ttl_probe_data[probe_count]["probe_time_in_millis"]),
+                "ip_address": ttl_probe_data[probe_count]
+                .get("gateway", {})
+                .get("ip_address", {})
+                .get("octets", ""),
+                "host_name": hostname,
+            }
+
+            ret["success"][hop_count + 1]["probes"][probe_count + 1] = probe
+            del probe
+
+    return ret
diff --git a/napalm_arubaoss/helper/utils.py b/napalm_arubaoss/helper/utils.py
new file mode 100644
index 0000000..dc3d2f8
--- /dev/null
+++ b/napalm_arubaoss/helper/utils.py
@@ -0,0 +1,152 @@
+"""Implement all utilities used by other modules."""
+
+import base64
+import logging
+from time import sleep
+from itertools import zip_longest
+from napalm.base.exceptions import CommandTimeoutException
+
+logger = logging.getLogger("arubaoss.helper.utils")
+
+
+def read_candidate(candidate):
+    """
+    Open the candidate config.
+
+    :param candidate:
+    :return:
+    """
+    with open(candidate) as candidate_config:
+        return "".join(candidate_config.readlines())
+
+
+def str_to_b64(spayload):
+    """
+    Convert from str to b64 for aoss API.
+
+    :param spayload:
+    :return:
+    """
+    payload_b64 = base64.b64encode(spayload.encode())
+
+    return payload_b64.decode("utf-8")
+
+
+def config_batch(self, cmd_list):
+    """
+    Load a batch of configuration commands into the running-config.
+
+    :param self: object from class
+    :param cmd_list:
+    :return:
+    """
+    url = self.connection.config["api_url"] + "cli_batch"
+    data = {"cli_batch_base64_encoded": str_to_b64("\n".join(cmd_list))}
+    batch_run = self.connection.post(url, json=data)
+
+    if not batch_run.status_code == 202:
+        logger.debug("Failed to paste commands")
+
+        return False
+
+    check_status = self.connection.get(url + "/status")
+    if check_status.status_code == 200:
+        for cmd_status in check_status.json()["cmd_exec_logs"]:
+            if not cmd_status["status"] == "CCS_SUCCESS":
+                logger.warning(
+                    "command failed to execute with error {}".format(
+                        cmd_status["result"]
+                    )
+                )
+                return False
+        return True
+
+
+def backup_config(self, config="running", destination="backup"):
+    """
+    Backup config.
+
+    Supported configs
+    API:
+        - "CT_RUNNING_CONFIG",
+        - "CT_STARTUP_CONFIG"
+
+    :param self: object from class
+    :param config:
+    :param destination:
+    :return:
+    """
+    url = self.connection.config["api_url"] + "system/config/cfg_backup_files"
+    payload = {}
+    dest_map = {
+        "backup": "backup_{}".format(config),
+        "REST_Payload_Backup": "REST_Payload_Backup",
+    }
+    conf_map = {
+        "running": "CT_RUNNING_CONFIG",
+        "startup": "CT_STARTUP_CONFIG"
+    }
+    payload["file_name"] = dest_map.get(destination)
+    payload["config_type"] = conf_map.get(config, False)
+
+    if not payload["config_type"]:
+        "unsupported argument; raise error"
+        return False
+
+    cmd_post = self.connection.post(url, json=payload)
+    if not cmd_post.ok:
+        "raise error"
+        pass
+    else:
+        return cmd_post.json()
+
+
+def transaction_status(self, url):
+    """
+    Wait for the requested transaction to finish within the specified timeout.
+
+    :param self: object from class
+    :param url:
+    :return:
+    """
+    status = "CRS_IN_PROGRESS"
+    elapsed = 0
+    while status == "CRS_IN_PROGRESS" and elapsed < self.connection.timeout:
+        call = self.connection.get(url)
+        if call.status_code in range(200, 300):
+            status = call.json()
+            return status
+        elapsed += 1
+        sleep(1)
+    if elapsed == (int(self.connection.timeout) - 1) and status == "CRS_IN_PROGRESS":
+        raise CommandTimeoutException("Transaction timed out")
+
+
+def commit_candidate(self, config):
+    """
+    Commit the candidate configuration.
+
+    :param self: object from class
+    :param config:
+    :return:
+    """
+    url = self.connection.config["api_url"] + "system/config/cfg_restore"
+    data = {"server_type": "ST_FLASH", "file_name": config, "is_oobm": False}
+    cmd_post = self.connection.post(url, json=data)
+
+    if not cmd_post.json()["failure_reason"]:
+        check_url = url + "/status"
+
+        return transaction_status(self=self, url=check_url)
+
+
+def mac_reformat(mac):
+    """
+    Reformat the MAC addresses to standard notation.
+
+    :param mac:
+    :return:
+    """
+    t = iter(mac.replace("-", ""))
+
+    return ":".join(a + b for a, b in zip_longest(t, t, fillvalue=""))
diff --git a/pylama.ini b/pylama.ini
index 3146a20..5f1daf1 100644
--- a/pylama.ini
+++ b/pylama.ini
@@ -1,6 +1,6 @@
 [pylama]
 linters = mccabe,pep257,pep8,pyflakes
-ignore = D203,
+ignore = D203,D212
 
 [pylama:pep8]
 max_line_length = 120
diff --git a/requirements.txt b/requirements.txt
index 89ae1e3..6c8147e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
-napalm>=2.0.0
+napalm>=3.3.0
 netaddr
 requests
-requests-toolbelt
 textfsm>=1.1.0
+urllib3
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
index a42a367..23a7705 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -11,9 +11,11 @@ addopts =
     --cov=napalm_arubaoss
     --cov-report term-missing
     -vs
-    --pylama
+#     --pylama
 json_report = report.json
 jsonapi = true
+testpaths =
+    test
 
 [coverage:run]
 source = napalm_arubaoss
diff --git a/setup.py b/setup.py
index afe915c..44bb06c 100644
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,7 @@
 
 setup(
     name="napalm-arubaos-switch",
-    version="0.1.1",
+    version="0.2.0",
     packages=find_packages(),
     author="Guillermo Cotone",
     author_email="15230109+gcotone@users.noreply.github.com",
@@ -26,6 +26,8 @@
         "Programming Language :: Python :: 3.5",
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
+        "Programming Language :: Python :: 3.8",
+        "Programming Language :: Python :: 3.9",
         "Operating System :: POSIX :: Linux",
     ],
     url="https://github.com/napalm-automation-community/napalm-arubaos-switch/",


Test patch:
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/test/unit/__init__.py b/test/unit/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/test/unit/conftest.py b/test/unit/conftest.py
new file mode 100644
index 0000000..edfe782
--- /dev/null
+++ b/test/unit/conftest.py
@@ -0,0 +1,130 @@
+"""Test fixtures."""
+
+from re import search
+
+import pytest
+from napalm.base.test import conftest as parent_conftest
+
+from napalm.base.test.double import BaseTestDouble
+
+from napalm_arubaoss import ArubaOS
+
+
+@pytest.fixture(scope='class')
+def set_device_parameters(request):
+    """Set up the class."""
+    def fin():
+        request.cls.device.close()
+    request.addfinalizer(fin)
+
+    request.cls.driver = ArubaOS.ArubaOSS
+    request.cls.patched_driver = PatchedArubaOSDriver
+    request.cls.vendor = 'napalm_arubaoss'
+    parent_conftest.set_device_parameters(request)
+
+
+def pytest_generate_tests(metafunc):
+    """Generate test cases dynamically."""
+    parent_conftest.pytest_generate_tests(metafunc, __file__)
+
+
+class PatchedArubaOSDriver(ArubaOS.ArubaOSS):
+    """Patched ArubaOS Driver."""
+
+    def __init__(self, hostname, username, password, timeout=60, optional_args=None):
+        super().__init__(hostname, username, password, timeout, optional_args)
+
+        self.patched_attrs = ['connection']
+        self.connection = FakeArubaOSDevice()
+        self.platform = "arubaos"
+
+    def disconnect(self):
+        pass
+
+    def is_alive(self):
+        return {
+            'is_alive': True  # In testing everything works..
+        }
+
+    def open(self):
+        pass
+
+
+class FakeArubaOSDevice(BaseTestDouble):
+    """ArubaOS device test double."""
+    def __init__(self):
+        super().__init__()
+        self.config = {'api_url': ''}
+
+    def get(self, url: str):
+        full_path = self.find_file('facts.json')
+        facts = self.read_json_file(full_path)
+
+        facts = facts.get(url)
+        resp = Response(
+            facts.get('data', {}),
+            status=facts.get('status', 204),
+            ok=facts.get('ok', True)
+        )
+        return resp
+
+    def post(self, url: str, json=None):
+        full_path = self.find_file('facts.json')
+        facts = self.read_json_file(full_path)
+
+        facts = facts.get(url)
+        resp = Response(
+            facts.get('data', {}),
+            status=facts.get('status', 204),
+            ok=facts.get('ok', True)
+        )
+        return resp
+
+    def cli(self, commands):
+        full_path = self.find_file('cli_mapping.json')
+        cli_mapping = self.read_json_file(full_path)
+
+        fake_return = {}
+
+        for cmd in commands:
+            cli_match = cli_mapping.get(cmd)
+            if not cli_match:
+                return
+            fake_return[cmd] = cli_match
+
+        return fake_return
+
+    def run_cmd(self, cmd):
+        return self.cli([cmd])[cmd]
+
+    def show(self, command, raw_text=False):
+        """Fake show."""
+        filename = '{}.json'.format(command.replace(' ', '_'))
+        full_path = self.find_file(filename)
+
+        if raw_text:
+            result = self.read_txt_file(full_path)
+        else:
+            result = self.read_json_file(full_path)
+
+        return result
+
+    def login(self):
+        pass
+
+    def logout(self):
+        pass
+
+    def config_list(self, command):
+        """Fake config_list."""
+        pass
+
+
+class Response:
+    def __init__(self, data, status=204, ok=True):
+        self.status_code = status
+        self.ok = ok
+        self.data = data
+
+    def json(self):
+        return self.data
diff --git a/test/unit/mocked_data/test_get_arp_table/normal/cli_mapping.json b/test/unit/mocked_data/test_get_arp_table/normal/cli_mapping.json
new file mode 100644
index 0000000..553bcac
--- /dev/null
+++ b/test/unit/mocked_data/test_get_arp_table/normal/cli_mapping.json
@@ -0,0 +1,3 @@
+{
+  "show arp": "\n IP ARP table\n\n  IP Address       MAC Address       Type    Port\n  ---------------  ----------------- ------- ----\n  10.0.4.55        1a2b3c-4d5e6f     dynamic Trk1\n  10.0.65.1       abcdef-123456     dynamic 1/15\n  10.2.3.2       123456-abcdef     dynamic 1/3 \n"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_arp_table/normal/expected_result.json b/test/unit/mocked_data/test_get_arp_table/normal/expected_result.json
new file mode 100644
index 0000000..218006f
--- /dev/null
+++ b/test/unit/mocked_data/test_get_arp_table/normal/expected_result.json
@@ -0,0 +1,20 @@
+[
+  {
+    "interface": "Trk1",
+    "mac": "1a:2b:3c:4d:5e:6f",
+    "ip": "10.0.4.55",
+    "age": -1.00
+  },
+  {
+    "interface": "1/15",
+    "mac": "ab:cd:ef:12:34:56",
+    "ip": "10.0.65.1",
+    "age": -1.00
+  },
+  {
+    "interface": "1/3",
+    "mac": "12:34:56:ab:cd:ef",
+    "ip": "10.2.3.2",
+    "age": -1.00
+  }
+]
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_arp_table/stack/cli_mapping.json b/test/unit/mocked_data/test_get_arp_table/stack/cli_mapping.json
new file mode 100644
index 0000000..553bcac
--- /dev/null
+++ b/test/unit/mocked_data/test_get_arp_table/stack/cli_mapping.json
@@ -0,0 +1,3 @@
+{
+  "show arp": "\n IP ARP table\n\n  IP Address       MAC Address       Type    Port\n  ---------------  ----------------- ------- ----\n  10.0.4.55        1a2b3c-4d5e6f     dynamic Trk1\n  10.0.65.1       abcdef-123456     dynamic 1/15\n  10.2.3.2       123456-abcdef     dynamic 1/3 \n"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_arp_table/stack/expected_result.json b/test/unit/mocked_data/test_get_arp_table/stack/expected_result.json
new file mode 100644
index 0000000..218006f
--- /dev/null
+++ b/test/unit/mocked_data/test_get_arp_table/stack/expected_result.json
@@ -0,0 +1,20 @@
+[
+  {
+    "interface": "Trk1",
+    "mac": "1a:2b:3c:4d:5e:6f",
+    "ip": "10.0.4.55",
+    "age": -1.00
+  },
+  {
+    "interface": "1/15",
+    "mac": "ab:cd:ef:12:34:56",
+    "ip": "10.0.65.1",
+    "age": -1.00
+  },
+  {
+    "interface": "1/3",
+    "mac": "12:34:56:ab:cd:ef",
+    "ip": "10.2.3.2",
+    "age": -1.00
+  }
+]
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config/normal/cli_mapping.json b/test/unit/mocked_data/test_get_config/normal/cli_mapping.json
new file mode 100644
index 0000000..2dccc53
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config/normal/cli_mapping.json
@@ -0,0 +1,5 @@
+{
+  "display saved-configuration": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show config REST_Payload_Backup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show running-config": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config/normal/expected_result.json b/test/unit/mocked_data/test_get_config/normal/expected_result.json
new file mode 100644
index 0000000..b92be02
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config/normal/expected_result.json
@@ -0,0 +1,5 @@
+{
+  "startup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "candidate": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "running": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config/stack/cli_mapping.json b/test/unit/mocked_data/test_get_config/stack/cli_mapping.json
new file mode 100644
index 0000000..2dccc53
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config/stack/cli_mapping.json
@@ -0,0 +1,5 @@
+{
+  "display saved-configuration": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show config REST_Payload_Backup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show running-config": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config/stack/expected_result.json b/test/unit/mocked_data/test_get_config/stack/expected_result.json
new file mode 100644
index 0000000..b92be02
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config/stack/expected_result.json
@@ -0,0 +1,5 @@
+{
+  "startup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "candidate": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "running": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config_filtered/normal/cli_mapping.json b/test/unit/mocked_data/test_get_config_filtered/normal/cli_mapping.json
new file mode 100644
index 0000000..2dccc53
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config_filtered/normal/cli_mapping.json
@@ -0,0 +1,5 @@
+{
+  "display saved-configuration": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show config REST_Payload_Backup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show running-config": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config_filtered/normal/expected_result.json b/test/unit/mocked_data/test_get_config_filtered/normal/expected_result.json
new file mode 100644
index 0000000..8dc7869
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config_filtered/normal/expected_result.json
@@ -0,0 +1,5 @@
+{
+  "startup": "",
+  "candidate": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "running": ""
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config_filtered/stack/cli_mapping.json b/test/unit/mocked_data/test_get_config_filtered/stack/cli_mapping.json
new file mode 100644
index 0000000..2dccc53
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config_filtered/stack/cli_mapping.json
@@ -0,0 +1,5 @@
+{
+  "display saved-configuration": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show config REST_Payload_Backup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show running-config": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config_filtered/stack/expected_result.json b/test/unit/mocked_data/test_get_config_filtered/stack/expected_result.json
new file mode 100644
index 0000000..8dc7869
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config_filtered/stack/expected_result.json
@@ -0,0 +1,5 @@
+{
+  "startup": "",
+  "candidate": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "running": ""
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config_sanitized/normal/cli_mapping.json b/test/unit/mocked_data/test_get_config_sanitized/normal/cli_mapping.json
new file mode 100644
index 0000000..2dccc53
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config_sanitized/normal/cli_mapping.json
@@ -0,0 +1,5 @@
+{
+  "display saved-configuration": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show config REST_Payload_Backup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show running-config": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config_sanitized/normal/expected_result.json b/test/unit/mocked_data/test_get_config_sanitized/normal/expected_result.json
new file mode 100644
index 0000000..b92be02
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config_sanitized/normal/expected_result.json
@@ -0,0 +1,5 @@
+{
+  "startup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "candidate": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "running": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config_sanitized/stack/cli_mapping.json b/test/unit/mocked_data/test_get_config_sanitized/stack/cli_mapping.json
new file mode 100644
index 0000000..2dccc53
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config_sanitized/stack/cli_mapping.json
@@ -0,0 +1,5 @@
+{
+  "display saved-configuration": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show config REST_Payload_Backup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "show running-config": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_config_sanitized/stack/expected_result.json b/test/unit/mocked_data/test_get_config_sanitized/stack/expected_result.json
new file mode 100644
index 0000000..b92be02
--- /dev/null
+++ b/test/unit/mocked_data/test_get_config_sanitized/stack/expected_result.json
@@ -0,0 +1,5 @@
+{
+  "startup": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "candidate": "; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000",
+  "running": "\nRunning configuration:\n\n; hpStack_WC Configuration Editor; Created on release #WC.16.10.0009\n; Ver #14:67.6f.f8.1d.9b.3f.bf.bb.ef.7c.59.fc.6b.fb.9f.fc.ff.ff.37.ef:44\n\nstacking\n   member 1 type \"JL322A\" mac-address 000000-000000\n   exit\nhostname \"Aruba-Stack-2930M\"\nrest-interface session-idle-timeout 120\nweb-management ssl\nip default-gateway 172.16.6.1\nip dns domain-name \"arubaos.napalm\"\nip dns server-address priority 1 8.8.8.8\nip dns server-address priority 2 1.1.1.1\ninterface 1/10\n   name \"test\"\n   exit\ninterface 1/12\n   name \"blubdf\"\n   exit\ninterface 1/48\n   name \"test\"\n   exit\nsnmp-server community \"public\" unrestricted\noobm\n   ip address 172.16.7.3 255.255.254.0\n   ip default-gateway 172.16.6.1\n   ipv6 enable\n   ipv6 address dhcp full\n   member 1\n      ip address dhcp-bootp\n      exit\n   exit\nvlan 1\n   name \"DEFAULT_VLAN\"\n   untagged 1/1-1/48\n   ip address 172.16.7.3 255.255.254.0\n   ipv6 enable\n   ipv6 address dhcp full\n   exit\npassword password\n\n\u0000"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_facts/normal/expected_result.json b/test/unit/mocked_data/test_get_facts/normal/expected_result.json
new file mode 100644
index 0000000..8e757fc
--- /dev/null
+++ b/test/unit/mocked_data/test_get_facts/normal/expected_result.json
@@ -0,0 +1,63 @@
+{
+  "vendor": "HPE Aruba",
+  "interface_list": [
+    "1",
+    "2",
+    "3",
+    "4",
+    "5",
+    "6",
+    "7",
+    "8",
+    "9",
+    "10",
+    "11",
+    "12",
+    "13",
+    "14",
+    "15",
+    "16",
+    "17",
+    "18",
+    "19",
+    "20",
+    "21",
+    "22",
+    "23",
+    "24",
+    "25",
+    "26",
+    "27",
+    "28",
+    "29",
+    "30",
+    "31",
+    "32",
+    "33",
+    "34",
+    "35",
+    "36",
+    "37",
+    "38",
+    "39",
+    "40",
+    "41",
+    "42",
+    "43",
+    "44",
+    "45T",
+    "46T",
+    "47T",
+    "48T",
+    "45S",
+    "46S",
+    "47S",
+    "48S"
+  ],
+  "uptime": -1,
+  "hostname": "Aruba-2930M-48G-PoEP",
+  "os_version": "WC.16.10.0009",
+  "serial_number": "ABC123456",
+  "model": "Aruba2930M-48G-PoE+ Switch(JL322A)",
+  "fqdn": "Aruba-2930M-48G-PoEP.arubaos.napalm"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_facts/normal/facts.json b/test/unit/mocked_data/test_get_facts/normal/facts.json
new file mode 100644
index 0000000..b08bcf7
--- /dev/null
+++ b/test/unit/mocked_data/test_get_facts/normal/facts.json
@@ -0,0 +1,832 @@
+{
+  "system/status/global_info": {
+    "status": 404,
+    "ok": false,
+    "data": {}
+  },
+  "system/status": {
+    "status": 200,
+    "data": {
+      "uri": "/system/status",
+      "name": "Aruba-2930M-48G-PoEP",
+      "serial_number": "ABC123456",
+      "firmware_version": "WC.16.10.0009",
+      "hardware_revision": "JL322A",
+      "product_model": "Aruba2930M-48G-PoE+ Switch(JL322A)",
+      "base_ethernet_address": {
+        "version": "MAV_EUI_48",
+        "octets": "000000-000000"
+      },
+      "current_ip_address": {
+        "version": "IAV_IP_V4",
+        "octets": "172.16.7.3"
+      },
+      "total_memory_in_bytes": 339329536,
+      "total_poe_consumption": 0,
+      "sys_temp": 22,
+      "sys_temp_threshold": 55,
+      "sys_fan_status": true
+    }
+  },
+  "system/status/members/1": {
+    "status": 404,
+    "ok": false,
+    "data": {}
+  },
+  "system/status/switch": {
+    "status": 200,
+    "data": {
+      "uri": "/system/status/switch",
+      "switch_type": "ST_STANDALONE",
+      "product_name": "Aruba2930M-48G-PoE+ Switch(JL322A)",
+      "product_number": "JL322A",
+      "hardware_info": [
+        {
+          "hardware_type": "SHT_FAN",
+          "status": "SHS_OK"
+        },
+        {
+          "hardware_type": "SHT_TEMP",
+          "status": "SHS_OK"
+        },
+        {
+          "hardware_type": "SHT_PS",
+          "status": "SHS_OK"
+        },
+        {
+          "hardware_type": "SHT_PS",
+          "status": "SHS_OK"
+        }
+      ],
+      "oobm_ports": [
+        {
+          "port_id": 4883,
+          "port_name": "OOBM",
+          "type": "PT_RJ45",
+          "sub_type": "10/100TX",
+          "adminStatus": "ADMIN_UP",
+          "operStatus": "OPER_UP",
+          "mode": "PCM_AUTO",
+          "alignment": "PA_TOP"
+        }
+      ],
+      "is_poe_supported": true,
+      "blades": [
+        {
+          "product_number": "JL322A",
+          "data_ports": [
+            {
+              "port_id": 1,
+              "port_name": "1",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 2,
+              "port_name": "2",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 3,
+              "port_name": "3",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 4,
+              "port_name": "4",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 5,
+              "port_name": "5",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 6,
+              "port_name": "6",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 7,
+              "port_name": "7",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 8,
+              "port_name": "8",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 9,
+              "port_name": "9",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 10,
+              "port_name": "10",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 11,
+              "port_name": "11",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 12,
+              "port_name": "12",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 13,
+              "port_name": "13",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 14,
+              "port_name": "14",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 15,
+              "port_name": "15",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 16,
+              "port_name": "16",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 17,
+              "port_name": "17",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 18,
+              "port_name": "18",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 19,
+              "port_name": "19",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 20,
+              "port_name": "20",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 21,
+              "port_name": "21",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 22,
+              "port_name": "22",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 23,
+              "port_name": "23",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 24,
+              "port_name": "24",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 25,
+              "port_name": "25",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 26,
+              "port_name": "26",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 27,
+              "port_name": "27",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 28,
+              "port_name": "28",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 29,
+              "port_name": "29",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 30,
+              "port_name": "30",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 31,
+              "port_name": "31",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 32,
+              "port_name": "32",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 33,
+              "port_name": "33",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 34,
+              "port_name": "34",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 35,
+              "port_name": "35",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 36,
+              "port_name": "36",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 37,
+              "port_name": "37",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 38,
+              "port_name": "38",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 39,
+              "port_name": "39",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 40,
+              "port_name": "40",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 41,
+              "port_name": "41",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 42,
+              "port_name": "42",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 43,
+              "port_name": "43",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 44,
+              "port_name": "44",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 45,
+              "port_name": "45T",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 46,
+              "port_name": "46T",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 47,
+              "port_name": "47T",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 48,
+              "port_name": "48T",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 45,
+              "port_name": "45S",
+              "type": "PT_GBIC",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 46,
+              "port_name": "46S",
+              "type": "PT_GBIC",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 47,
+              "port_name": "47S",
+              "type": "PT_GBIC",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 48,
+              "port_name": "48S",
+              "type": "PT_GBIC",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            }
+          ],
+          "expansion_modules": []
+        }
+      ]
+    }
+  },
+  "dns": {
+    "status": 200,
+    "data": {
+      "uri": "/dns",
+      "dns_config_mode": "DCM_MANUAL",
+      "server_1": {
+        "version": "IAV_IP_V4",
+        "octets": "8.8.8.8"
+      },
+      "server_2": {
+        "version": "IAV_IP_V4",
+        "octets": "1.1.1.1"
+      },
+      "dns_domain_names": [
+        "arubaos.napalm"
+      ],
+      "server_3": null,
+      "server_4": null
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_facts/stack/expected_result.json b/test/unit/mocked_data/test_get_facts/stack/expected_result.json
new file mode 100644
index 0000000..b9b00d3
--- /dev/null
+++ b/test/unit/mocked_data/test_get_facts/stack/expected_result.json
@@ -0,0 +1,63 @@
+{
+  "vendor": "HPE Aruba",
+  "interface_list": [
+    "1/1",
+    "1/2",
+    "1/3",
+    "1/4",
+    "1/5",
+    "1/6",
+    "1/7",
+    "1/8",
+    "1/9",
+    "1/10",
+    "1/11",
+    "1/12",
+    "1/13",
+    "1/14",
+    "1/15",
+    "1/16",
+    "1/17",
+    "1/18",
+    "1/19",
+    "1/20",
+    "1/21",
+    "1/22",
+    "1/23",
+    "1/24",
+    "1/25",
+    "1/26",
+    "1/27",
+    "1/28",
+    "1/29",
+    "1/30",
+    "1/31",
+    "1/32",
+    "1/33",
+    "1/34",
+    "1/35",
+    "1/36",
+    "1/37",
+    "1/38",
+    "1/39",
+    "1/40",
+    "1/41",
+    "1/42",
+    "1/43",
+    "1/44",
+    "1/45T",
+    "1/46T",
+    "1/47T",
+    "1/48T",
+    "1/45S",
+    "1/46S",
+    "1/47S",
+    "1/48S"
+  ],
+  "uptime": -1,
+  "hostname": "Aruba-Stack-2930M",
+  "os_version": "WC.16.10.0009",
+  "serial_number": "ABC123456",
+  "model": "Aruba2930M-48G-PoE+ Swit(JL322A)",
+  "fqdn": "Aruba-Stack-2930M.arubaos.napalm"
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_facts/stack/facts.json b/test/unit/mocked_data/test_get_facts/stack/facts.json
new file mode 100644
index 0000000..2a4e741
--- /dev/null
+++ b/test/unit/mocked_data/test_get_facts/stack/facts.json
@@ -0,0 +1,837 @@
+{
+  "system/status/global_info": {
+    "status": 200,
+    "data": {
+      "name": "Aruba-Stack-2930M",
+      "firmware_version": "WC.16.10.0009",
+      "base_ethernet_address": {
+        "version": "MAV_EUI_48",
+        "octets": "000000-000000"
+      },
+      "current_ip_address": {
+        "version": "IAV_IP_V4",
+        "octets": "172.16.7.3"
+      }
+    }
+  },
+  "system/status": {
+    "status": 404,
+    "ok": false,
+    "data": {}
+  },
+  "system/status/members/1": {
+    "status": 200,
+    "data": {
+      "uri": "/system/status/members/1",
+      "member_id": 1,
+      "serial_number": "ABC123456",
+      "hardware_revision": "JL322A",
+      "product_model": "Aruba2930M-48G-PoE+ Swit(JL322A)",
+      "mac_address": {
+        "version": "MAV_EUI_48",
+        "octets": "000000-000000"
+      },
+      "total_memory_in_bytes": 339329536,
+      "total_poe_consumption": 0,
+      "sys_temp": "22C",
+      "sys_temp_threshold": "55C",
+      "sys_fan_status": false
+    }
+  },
+  "system/status/switch": {
+    "status": 200,
+    "data": {
+      "uri": "/system/status/switch",
+      "switch_type": "ST_STACKED",
+      "blades": [
+        {
+          "stack_member": 1,
+          "product_name": "Aruba2930M-48G-PoE+ Swit(JL322A)",
+          "product_number": "JL322A",
+          "hardware_info": [
+            {
+              "hardware_type": "SHT_FAN",
+              "status": "SHS_OK"
+            },
+            {
+              "hardware_type": "SHT_TEMP",
+              "status": "SHS_OK"
+            },
+            {
+              "hardware_type": "SHT_PS",
+              "status": "SHS_OK"
+            },
+            {
+              "hardware_type": "SHT_PS",
+              "status": "SHS_ERROR"
+            }
+          ],
+          "oobm_ports": [
+            {
+              "port_id": 4884,
+              "port_name": "OOBM",
+              "type": "PT_RJ45",
+              "sub_type": "10/100TX",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_UP",
+              "mode": "PCM_AUTO",
+              "alignment": "PA_TOP"
+            }
+          ],
+          "is_poe_supported": true,
+          "data_ports": [
+            {
+              "port_id": 1,
+              "port_name": "1/1",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 2,
+              "port_name": "1/2",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 3,
+              "port_name": "1/3",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 4,
+              "port_name": "1/4",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 5,
+              "port_name": "1/5",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 6,
+              "port_name": "1/6",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 7,
+              "port_name": "1/7",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 8,
+              "port_name": "1/8",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 9,
+              "port_name": "1/9",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 10,
+              "port_name": "1/10",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 11,
+              "port_name": "1/11",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 12,
+              "port_name": "1/12",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 13,
+              "port_name": "1/13",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 14,
+              "port_name": "1/14",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 15,
+              "port_name": "1/15",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 16,
+              "port_name": "1/16",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 17,
+              "port_name": "1/17",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 18,
+              "port_name": "1/18",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 19,
+              "port_name": "1/19",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 20,
+              "port_name": "1/20",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 21,
+              "port_name": "1/21",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 22,
+              "port_name": "1/22",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 23,
+              "port_name": "1/23",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 24,
+              "port_name": "1/24",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 25,
+              "port_name": "1/25",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 26,
+              "port_name": "1/26",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 27,
+              "port_name": "1/27",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 28,
+              "port_name": "1/28",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 29,
+              "port_name": "1/29",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 30,
+              "port_name": "1/30",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 31,
+              "port_name": "1/31",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 32,
+              "port_name": "1/32",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 33,
+              "port_name": "1/33",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 34,
+              "port_name": "1/34",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 35,
+              "port_name": "1/35",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 36,
+              "port_name": "1/36",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 37,
+              "port_name": "1/37",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 38,
+              "port_name": "1/38",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 39,
+              "port_name": "1/39",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 40,
+              "port_name": "1/40",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 41,
+              "port_name": "1/41",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 42,
+              "port_name": "1/42",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 43,
+              "port_name": "1/43",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 44,
+              "port_name": "1/44",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 45,
+              "port_name": "1/45T",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 46,
+              "port_name": "1/46T",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 47,
+              "port_name": "1/47T",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 48,
+              "port_name": "1/48T",
+              "type": "PT_RJ45",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 45,
+              "port_name": "1/45S",
+              "type": "PT_GBIC",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 46,
+              "port_name": "1/46S",
+              "type": "PT_GBIC",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 47,
+              "port_name": "1/47S",
+              "type": "PT_GBIC",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_TOP",
+              "is_smartrate": false
+            },
+            {
+              "port_id": 48,
+              "port_name": "1/48S",
+              "type": "PT_GBIC",
+              "adminStatus": "ADMIN_UP",
+              "operStatus": "OPER_DOWN",
+              "sub_type": "100/1000T",
+              "mode": "PCM_AUTO",
+              "is_internal": false,
+              "oper_mode": "OM_1000_FDX",
+              "poe_status": "POES_SEARCHING",
+              "alignment": "PA_BOTTOM",
+              "is_smartrate": false
+            }
+          ],
+          "expansion_modules": []
+        }
+      ]
+    }
+  },
+  "dns": {
+    "status": 200,
+    "data": {
+      "uri": "/dns",
+      "dns_config_mode": "DCM_MANUAL",
+      "server_1": {
+        "version": "IAV_IP_V4",
+        "octets": "8.8.8.8"
+      },
+      "server_2": {
+        "version": "IAV_IP_V4",
+        "octets": "1.1.1.1"
+      },
+      "dns_domain_names": [
+        "arubaos.napalm"
+      ],
+      "server_3": null,
+      "server_4": null
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_interfaces/normal/cli_mapping.json b/test/unit/mocked_data/test_get_interfaces/normal/cli_mapping.json
new file mode 100644
index 0000000..96e9b54
--- /dev/null
+++ b/test/unit/mocked_data/test_get_interfaces/normal/cli_mapping.json
@@ -0,0 +1,16 @@
+{
+  "show interfaces 1 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aebf   ",
+  "show interfaces 2 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aebe   ",
+  "show interfaces 3 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aebd   ",
+  "show interfaces 4 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aebc   ",
+  "show interfaces 5 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aebb   ",
+  "show interfaces 6 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeba   ",
+  "show interfaces 7 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeb9   ",
+  "show interfaces 8 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeb8   ",
+  "show interfaces 9 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeb7   ",
+  "show interfaces 10 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeb6   ",
+  "show interfaces 11 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeb5   ",
+  "show interfaces 12 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeb4   ",
+  "show interfaces 13 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeb3   ",
+  "show interfaces 14 | include MAC[[:space:]]Address": "  MAC Address      : 000000-00aeb2   "
+}
diff --git a/test/unit/mocked_data/test_get_interfaces/normal/expected_result.json b/test/unit/mocked_data/test_get_interfaces/normal/expected_result.json
new file mode 100644
index 0000000..e5dbfa0
--- /dev/null
+++ b/test/unit/mocked_data/test_get_interfaces/normal/expected_result.json
@@ -0,0 +1,128 @@
+{
+  "1": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:BF"
+  },
+  "2": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:BE"
+  },
+  "3": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:BD"
+  },
+  "4": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:BC"
+  },
+  "5": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:BB"
+  },
+  "6": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:BA"
+  },
+  "7": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:B9"
+  },
+  "8": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:B8"
+  },
+  "9": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:B7"
+  },
+  "10": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "test-new",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:B6"
+  },
+  "11": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:B5"
+  },
+  "12": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "blah",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:B4"
+  },
+  "13": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:B3"
+  },
+  "14": {
+    "is_up": false,
+    "is_enabled": true,
+    "description": "",
+    "last_flapped": -1.0,
+    "speed": 1000,
+    "mtu": -1,
+    "mac_address": "00:00:00:00:AE:B2"
+  }
+}
diff --git a/test/unit/mocked_data/test_get_interfaces/normal/facts.json b/test/unit/mocked_data/test_get_interfaces/normal/facts.json
new file mode 100644
index 0000000..e3fd26a
--- /dev/null
+++ b/test/unit/mocked_data/test_get_interfaces/normal/facts.json
@@ -0,0 +1,416 @@
+{
+  "ports": {
+    "status": 200,
+    "data": {
+      "collection_result": {
+        "total_elements_count": 14,
+        "filtered_elements_count": 14
+      },
+      "port_element": [
+        {
+          "uri": "/ports/1",
+          "id": "1",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/2",
+          "id": "2",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/3",
+          "id": "3",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/4",
+          "id": "4",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/5",
+          "id": "5",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/6",
+          "id": "6",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/7",
+          "id": "7",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/8",
+          "id": "8",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/9",
+          "id": "9",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/10",
+          "id": "10",
+          "name": "test-new",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/11",
+          "id": "11",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/12",
+          "id": "12",
+          "name": "blah",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/13",
+          "id": "13",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        },
+        {
+          "uri": "/ports/14",
+          "id": "14",
+          "name": "",
+          "is_port_enabled": true,
+          "is_port_up": false,
+          "config_mode": "PCM_AUTO",
+          "trunk_mode": "PTT_NONE",
+          "lacp_status": "LAS_DISABLED",
+          "trunk_group": "",
+          "is_flow_control_enabled": false,
+          "is_dsnoop_port_trusted": false
+        }
+      ]
+    }
+  },
+  "port-statistics": {
+    "status": 200,
+    "data": {
+      "port_statistics_element": [
+        {
+          "uri": "/port-statistics/1",
+          "id": "1",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/2",
+          "id": "2",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/3",
+          "id": "3",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/4",
+          "id": "4",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/5",
+          "id": "5",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/6",
+          "id": "6",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/7",
+          "id": "7",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/8",
+          "id": "8",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/9",
+          "id": "9",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/10",
+          "id": "10",
+          "name": "test-new",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/11",
+          "id": "11",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/12",
+          "id": "12",
+          "name": "blah",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/13",
+          "id": "13",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        },
+        {
+          "uri": "/port-statistics/14",
+          "id": "14",
+          "name": "",
+          "packets_tx": 0,
+          "packets_rx": 0,
+          "bytes_tx": 0,
+          "bytes_rx": 0,
+          "throughput_tx_bps": 0,
+          "throughput_rx_bps": 0,
+          "error_tx": 0,
+          "error_rx": 0,
+          "drop_tx": 0,
+          "port_speed_mbps": 1000
+        }
+      ],
+      "collection_result": {
+        "total_elements_count": 14,
+        "filtered_elements_count": 14
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_interfaces_ip/normal/expected_result.json b/test/unit/mocked_data/test_get_interfaces_ip/normal/expected_result.json
new file mode 100644
index 0000000..a4ed18e
--- /dev/null
+++ b/test/unit/mocked_data/test_get_interfaces_ip/normal/expected_result.json
@@ -0,0 +1,9 @@
+{
+  "VLAN1": {
+    "ipv4": {
+      "172.16.7.3": {
+        "prefix_length": 23
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_interfaces_ip/normal/facts.json b/test/unit/mocked_data/test_get_interfaces_ip/normal/facts.json
new file mode 100644
index 0000000..408ab4f
--- /dev/null
+++ b/test/unit/mocked_data/test_get_interfaces_ip/normal/facts.json
@@ -0,0 +1,26 @@
+{
+  "ipaddresses": {
+    "status": 200,
+    "data": {
+      "collection_result": {
+        "total_elements_count": 1,
+        "filtered_elements_count": 1
+      },
+      "ip_address_subnet_element": [
+        {
+          "uri": "/vlans/1/ipaddresses/IAAM_STATIC-172.16.7.3",
+          "ip_address_mode": "IAAM_STATIC",
+          "vlan_id": 1,
+          "ip_address": {
+            "version": "IAV_IP_V4",
+            "octets": "172.16.7.3"
+          },
+          "ip_mask": {
+            "version": "IAV_IP_V4",
+            "octets": "255.255.254.0"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_interfaces_ip/stack/expected_result.json b/test/unit/mocked_data/test_get_interfaces_ip/stack/expected_result.json
new file mode 100644
index 0000000..a4ed18e
--- /dev/null
+++ b/test/unit/mocked_data/test_get_interfaces_ip/stack/expected_result.json
@@ -0,0 +1,9 @@
+{
+  "VLAN1": {
+    "ipv4": {
+      "172.16.7.3": {
+        "prefix_length": 23
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_interfaces_ip/stack/facts.json b/test/unit/mocked_data/test_get_interfaces_ip/stack/facts.json
new file mode 100644
index 0000000..408ab4f
--- /dev/null
+++ b/test/unit/mocked_data/test_get_interfaces_ip/stack/facts.json
@@ -0,0 +1,26 @@
+{
+  "ipaddresses": {
+    "status": 200,
+    "data": {
+      "collection_result": {
+        "total_elements_count": 1,
+        "filtered_elements_count": 1
+      },
+      "ip_address_subnet_element": [
+        {
+          "uri": "/vlans/1/ipaddresses/IAAM_STATIC-172.16.7.3",
+          "ip_address_mode": "IAAM_STATIC",
+          "vlan_id": 1,
+          "ip_address": {
+            "version": "IAV_IP_V4",
+            "octets": "172.16.7.3"
+          },
+          "ip_mask": {
+            "version": "IAV_IP_V4",
+            "octets": "255.255.254.0"
+          }
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_lldp_neighbors/normal/expected_result.json b/test/unit/mocked_data/test_get_lldp_neighbors/normal/expected_result.json
new file mode 100644
index 0000000..d06d053
--- /dev/null
+++ b/test/unit/mocked_data/test_get_lldp_neighbors/normal/expected_result.json
@@ -0,0 +1,8 @@
+{
+  "oobm": [
+    {
+      "hostname": "LAB-EDGE-SWITCH01",
+      "port": "GigabitEthernet1/0/8"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_lldp_neighbors/normal/facts.json b/test/unit/mocked_data/test_get_lldp_neighbors/normal/facts.json
new file mode 100644
index 0000000..08abafe
--- /dev/null
+++ b/test/unit/mocked_data/test_get_lldp_neighbors/normal/facts.json
@@ -0,0 +1,48 @@
+{
+  "lldp/remote-device": {
+    "status": 200,
+    "data": {
+      "collection_result": {
+        "total_elements_count": 1,
+        "filtered_elements_count": 1
+      },
+      "lldp_remote_device_element": [
+        {
+          "local_port": "oobm",
+          "chassis_type": "RCT_MAC_ADDRESS",
+          "chassis_id": "00 00 00 00 00 00",
+          "port_type": "LPT_INTERFACE_NAME",
+          "port_id": "GigabitEthernet1/0/8",
+          "port_description": "ARUBA-MGMT",
+          "system_name": "LAB-EDGE-SWITCH01",
+          "system_description": "HP Comware Platform Software, Software Version 5.20.99 Release 2222P01",
+          "pvid": null,
+          "capabilities_supported": {
+            "repeater": false,
+            "bridge": true,
+            "wlan_access_point": false,
+            "router": true,
+            "telephone": false,
+            "cable_device": false,
+            "station_only": false
+          },
+          "capabilities_enabled": {
+            "repeater": false,
+            "bridge": true,
+            "wlan_access_point": false,
+            "router": true,
+            "telephone": false,
+            "cable_device": false,
+            "station_only": false
+          },
+          "remote_management_address": [
+            {
+              "type": "AFM_IP4",
+              "address": "192.168.6.6"
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_lldp_neighbors_detail/normal/expected_result.json b/test/unit/mocked_data/test_get_lldp_neighbors_detail/normal/expected_result.json
new file mode 100644
index 0000000..1479369
--- /dev/null
+++ b/test/unit/mocked_data/test_get_lldp_neighbors_detail/normal/expected_result.json
@@ -0,0 +1,20 @@
+{
+  "oobm": [
+    {
+      "parent_interface": "",
+      "remote_system_name": "LAB-EDGE-SWITCH01",
+      "remote_chassis_id": "00 00 00 00 00 00",
+      "remote_port": "GigabitEthernet1/0/8",
+      "remote_port_description": "ARUBA-MGMT",
+      "remote_system_description": "HP Comware Platform Software, Software Version 5.20.99 Release 2222P01",
+      "remote_system_capab": [
+        "bridge",
+        "router"
+      ],
+      "remote_system_enable_capab": [
+        "bridge",
+        "router"
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_lldp_neighbors_detail/normal/facts.json b/test/unit/mocked_data/test_get_lldp_neighbors_detail/normal/facts.json
new file mode 100644
index 0000000..dd4a8e1
--- /dev/null
+++ b/test/unit/mocked_data/test_get_lldp_neighbors_detail/normal/facts.json
@@ -0,0 +1,48 @@
+{
+  "lldp/remote-device": {
+    "status": 200,
+    "data": {
+      "collection_result": {
+        "total_elements_count": 1,
+        "filtered_elements_count": 1
+      },
+      "lldp_remote_device_element": [
+        {
+          "local_port": "oobm",
+          "chassis_type": "RCT_MAC_ADDRESS",
+          "chassis_id": "00 00 00 00 00 00",
+          "port_type": "LPT_INTERFACE_NAME",
+          "port_id": "GigabitEthernet1/0/8",
+          "port_description": "ARUBA-MGMT",
+          "system_name": "LAB-EDGE-SWITCH01",
+          "system_description": "HP Comware Platform Software, Software Version 5.20.99 Release 2222P01",
+          "pvid": null,
+          "capabilities_supported": {
+            "repeater": false,
+            "bridge": true,
+            "wlan_access_point": false,
+            "router": true,
+            "telephone": false,
+            "cable_device": false,
+            "station_only": false
+          },
+          "capabilities_enabled": {
+            "repeater": false,
+            "bridge": true,
+            "wlan_access_point": false,
+            "router": true,
+            "telephone": false,
+            "cable_device": false,
+            "station_only": false
+          },
+          "remote_management_address": [
+            {
+              "type": "AFM_IP4",
+              "address": "192.168.6.6"
+            }
+          ]
+        }
+      ]
+    }
+  }
+}
diff --git a/test/unit/mocked_data/test_get_mac_address_table/normal/expected_result.json b/test/unit/mocked_data/test_get_mac_address_table/normal/expected_result.json
new file mode 100644
index 0000000..4507923
--- /dev/null
+++ b/test/unit/mocked_data/test_get_mac_address_table/normal/expected_result.json
@@ -0,0 +1,56 @@
+[
+  {
+    "mac": "ec:00:8b:f7:00:e5",
+    "interface": "Trk1",
+    "vlan": 1,
+    "active": true,
+    "static": false,
+    "moves": 0,
+    "last_move": 0.0
+  },
+  {
+    "mac": "4e:11:14:b1:11:3c",
+    "interface": "Trk1",
+    "vlan": 48,
+    "active": true,
+    "static": false,
+    "moves": 0,
+    "last_move": 0.0
+  },
+  {
+    "mac": "78:22:77:60:22:3f",
+    "interface": "3/44",
+    "vlan": 64,
+    "active": true,
+    "static": false,
+    "moves": 0,
+    "last_move": 0.0
+  },
+  {
+    "mac": "00:33:98:16:33:85",
+    "interface": "2/32",
+    "vlan": 64,
+    "active": true,
+    "static": false,
+    "moves": 0,
+    "last_move": 0.0
+  },
+  {
+    "mac": "e0:44:43:5d:44:b3",
+    "interface": "Trk1",
+    "vlan": 104,
+    "active": true,
+    "static": false,
+    "moves": 0,
+    "last_move": 0.0
+  },
+  {
+    "mac": "00:55:98:17:55:78",
+    "interface": "4/25",
+    "vlan": 64,
+    "active": true,
+    "static": false,
+    "moves": 0,
+    "last_move": 0.0
+  }
+]
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_mac_address_table/normal/facts.json b/test/unit/mocked_data/test_get_mac_address_table/normal/facts.json
new file mode 100644
index 0000000..312b900
--- /dev/null
+++ b/test/unit/mocked_data/test_get_mac_address_table/normal/facts.json
@@ -0,0 +1,49 @@
+{
+  "mac-table": {
+    "status": 200,
+    "data": {
+      "collection_result": {
+        "total_elements_count": 400,
+        "filtered_elements_count": 400
+      },
+      "mac_table_entry_element": [
+        {
+          "uri": "/mac-table/ec008b-f700e5",
+          "mac_address": "ec008b-f700e5",
+          "port_id": "Trk1",
+          "vlan_id": 1
+        },
+        {
+          "uri": "/mac-table/4e1114-b1113c",
+          "mac_address": "4e1114-b1113c",
+          "port_id": "Trk1",
+          "vlan_id": 48
+        },
+        {
+          "uri": "/mac-table/782277-60223f",
+          "mac_address": "782277-60223f",
+          "port_id": "3/44",
+          "vlan_id": 64
+        },
+        {
+          "uri": "/mac-table/003398-163385",
+          "mac_address": "003398-163385",
+          "port_id": "2/32",
+          "vlan_id": 64
+        },
+        {
+          "uri": "/mac-table/e04443-5d44b3",
+          "mac_address": "e04443-5d44b3",
+          "port_id": "Trk1",
+          "vlan_id": 104
+        },
+        {
+          "uri": "/mac-table/005598-175578",
+          "mac_address": "005598-175578",
+          "port_id": "4/25",
+          "vlan_id": 64
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_ntp_peers/normal/expected_result.json b/test/unit/mocked_data/test_get_ntp_peers/normal/expected_result.json
new file mode 100644
index 0000000..6813943
--- /dev/null
+++ b/test/unit/mocked_data/test_get_ntp_peers/normal/expected_result.json
@@ -0,0 +1,4 @@
+{
+  "116.203.116.168": {},
+  "\"de.pool.ntp.org\"": {}
+}
diff --git a/test/unit/mocked_data/test_get_ntp_peers/normal/facts.json b/test/unit/mocked_data/test_get_ntp_peers/normal/facts.json
new file mode 100644
index 0000000..2061a36
--- /dev/null
+++ b/test/unit/mocked_data/test_get_ntp_peers/normal/facts.json
@@ -0,0 +1,46 @@
+{
+  "config/ntp/server/ip4addr": {
+    "status": 200,
+    "data": {
+      "ntpServerIp4addr_element": [
+        {
+          "ip4addr": {
+            "ip4addr_value": "116.203.116.168",
+            "ip4addr_reference": {
+              "min-poll": {
+                "min-poll_value": 6
+              },
+              "max-poll": {
+                "max-poll_value": 10
+              },
+              "oobm": true
+            }
+          },
+          "uri": "/config/ntp/server/ip4addr/116.203.116.168"
+        }
+      ]
+    }
+  },
+  "config/ntp/server-name/ASCII-STR": {
+    "status": 200,
+    "data": {
+      "ntpServerNameASCIISTR_element": [
+        {
+          "ASCII-STR": {
+            "ASCII-STR_value": "\"de.pool.ntp.org\"",
+            "ASCII-STR_reference": {
+              "min-poll": {
+                "min-poll_value": 6
+              },
+              "max-poll": {
+                "max-poll_value": 10
+              },
+              "oobm": true
+            }
+          },
+          "uri": "/config/ntp/server-name/ASCII-STR/%22de.pool.ntp.org%22"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_ntp_servers/normal/expected_result.json b/test/unit/mocked_data/test_get_ntp_servers/normal/expected_result.json
new file mode 100644
index 0000000..6813943
--- /dev/null
+++ b/test/unit/mocked_data/test_get_ntp_servers/normal/expected_result.json
@@ -0,0 +1,4 @@
+{
+  "116.203.116.168": {},
+  "\"de.pool.ntp.org\"": {}
+}
diff --git a/test/unit/mocked_data/test_get_ntp_servers/normal/facts.json b/test/unit/mocked_data/test_get_ntp_servers/normal/facts.json
new file mode 100644
index 0000000..2061a36
--- /dev/null
+++ b/test/unit/mocked_data/test_get_ntp_servers/normal/facts.json
@@ -0,0 +1,46 @@
+{
+  "config/ntp/server/ip4addr": {
+    "status": 200,
+    "data": {
+      "ntpServerIp4addr_element": [
+        {
+          "ip4addr": {
+            "ip4addr_value": "116.203.116.168",
+            "ip4addr_reference": {
+              "min-poll": {
+                "min-poll_value": 6
+              },
+              "max-poll": {
+                "max-poll_value": 10
+              },
+              "oobm": true
+            }
+          },
+          "uri": "/config/ntp/server/ip4addr/116.203.116.168"
+        }
+      ]
+    }
+  },
+  "config/ntp/server-name/ASCII-STR": {
+    "status": 200,
+    "data": {
+      "ntpServerNameASCIISTR_element": [
+        {
+          "ASCII-STR": {
+            "ASCII-STR_value": "\"de.pool.ntp.org\"",
+            "ASCII-STR_reference": {
+              "min-poll": {
+                "min-poll_value": 6
+              },
+              "max-poll": {
+                "max-poll_value": 10
+              },
+              "oobm": true
+            }
+          },
+          "uri": "/config/ntp/server-name/ASCII-STR/%22de.pool.ntp.org%22"
+        }
+      ]
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_ntp_stats/server-name/expected_result.json b/test/unit/mocked_data/test_get_ntp_stats/server-name/expected_result.json
new file mode 100644
index 0000000..4f871e4
--- /dev/null
+++ b/test/unit/mocked_data/test_get_ntp_stats/server-name/expected_result.json
@@ -0,0 +1,15 @@
+[
+  {
+    "remote": "173.249.33.207",
+    "referenceid": "205.46.178.169",
+    "stratum": 2,
+    "type": "Server",
+    "when": "Wed Nov 10 18:01:18 2021",
+    "hostpoll": 7,
+    "reachability": 17,
+    "delay": 0.01628,
+    "offset": 0.0,
+    "jitter": 0.00075,
+    "synchronized": true
+  }
+]
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_ntp_stats/server-name/facts.json b/test/unit/mocked_data/test_get_ntp_stats/server-name/facts.json
new file mode 100644
index 0000000..5e2201c
--- /dev/null
+++ b/test/unit/mocked_data/test_get_ntp_stats/server-name/facts.json
@@ -0,0 +1,47 @@
+{
+  "monitoring/ntp/servers": {
+    "status": 200,
+    "data": {
+      "NTP_Server_Name_Information": [
+        {
+          "Server Name": "de.pool.ntp.org",
+          "Resolved Address": "173.249.33.207",
+          "Server Status": "Success: NTP server active"
+        },
+        {
+          "Server Name": "0.de.pool.ntp.org",
+          "Resolved Address": "",
+          "Server Status": "Failed: NTP server not active"
+        }
+      ]
+    }
+  },
+  "monitoring/ntp/associations/detail": {
+    "status": 200,
+    "data": {
+      "IP Address": "173.249.33.207",
+      "Peer Mode": "Server",
+      "Status": "Config,Sane,Master",
+      "Peer Poll Intvl": 7,
+      "Stratum": 2,
+      "Root Delay": "0.01628 sec",
+      "Ref Assoc ID": 1,
+      "Root Dispersion": "0.00075 sec",
+      "Assoc Name": "NTP Association 1",
+      "Reach": 17,
+      "Reference ID": "205.46.178.169",
+      "Delay": "0.00000 sec",
+      "Our Mode": "Client",
+      "Offset": "0.00000 sec",
+      "Our Poll Intvl": 7,
+      "Precision": "2**-25",
+      "Dispersion": "15.53054 sec",
+      "Association In Packets": 11,
+      "Association Out Packets": 11,
+      "Association Error Packets": 0,
+      "Origin Time": "Wed Nov 10 18:01:18 2021",
+      "Receive Time": "Wed Nov 10 18:01:18 2021",
+      "Transmit Time": "Wed Nov 10 18:01:18 2021"
+    }
+  }
+}
diff --git a/test/unit/mocked_data/test_get_route_to/normal/cli_mapping.json b/test/unit/mocked_data/test_get_route_to/normal/cli_mapping.json
new file mode 100644
index 0000000..25f16c6
--- /dev/null
+++ b/test/unit/mocked_data/test_get_route_to/normal/cli_mapping.json
@@ -0,0 +1,1 @@
+{"show ip route 1.0.4.0 bgp": "\n                         IP Route Entries to 1.0.4.0\n\n  Destination        Gateway         VLAN Type      Sub-Type   Metric     Dist.\n  ------------------ --------------- ---- --------- ---------- ---------- -----\n  1.0.4.0/24       NET_MGMT        4    bgp            1          0    \n \n\n\u0000"}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_route_to/normal/expected_result.json b/test/unit/mocked_data/test_get_route_to/normal/expected_result.json
new file mode 100644
index 0000000..18aca65
--- /dev/null
+++ b/test/unit/mocked_data/test_get_route_to/normal/expected_result.json
@@ -0,0 +1,27 @@
+{
+  "1.0.4.0/24": [
+    {
+      "protocol": "bgp",
+      "current_active": true,
+      "last_active": true,
+      "age": -1,
+      "next_hop": "NET_MGMT",
+      "outgoing_interface": "",
+      "selected_next_hop": true,
+      "preference": 0,
+      "inactive_reason": "",
+      "routing_table": "",
+      "protocol_attributes": {
+        "local_as": -1,
+        "remote_as": -1,
+        "peer_id": "",
+        "as_path": "",
+        "communities": -1,
+        "local_preference": -1,
+        "preference2": -1,
+        "metric": -1,
+        "metric2": -1
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_route_to_longer/normal/cli_mapping.json b/test/unit/mocked_data/test_get_route_to_longer/normal/cli_mapping.json
new file mode 100644
index 0000000..25f16c6
--- /dev/null
+++ b/test/unit/mocked_data/test_get_route_to_longer/normal/cli_mapping.json
@@ -0,0 +1,1 @@
+{"show ip route 1.0.4.0 bgp": "\n                         IP Route Entries to 1.0.4.0\n\n  Destination        Gateway         VLAN Type      Sub-Type   Metric     Dist.\n  ------------------ --------------- ---- --------- ---------- ---------- -----\n  1.0.4.0/24       NET_MGMT        4    bgp            1          0    \n \n\n\u0000"}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_get_route_to_longer/normal/expected_result.json b/test/unit/mocked_data/test_get_route_to_longer/normal/expected_result.json
new file mode 100644
index 0000000..18aca65
--- /dev/null
+++ b/test/unit/mocked_data/test_get_route_to_longer/normal/expected_result.json
@@ -0,0 +1,27 @@
+{
+  "1.0.4.0/24": [
+    {
+      "protocol": "bgp",
+      "current_active": true,
+      "last_active": true,
+      "age": -1,
+      "next_hop": "NET_MGMT",
+      "outgoing_interface": "",
+      "selected_next_hop": true,
+      "preference": 0,
+      "inactive_reason": "",
+      "routing_table": "",
+      "protocol_attributes": {
+        "local_as": -1,
+        "remote_as": -1,
+        "peer_id": "",
+        "as_path": "",
+        "communities": -1,
+        "local_preference": -1,
+        "preference2": -1,
+        "metric": -1,
+        "metric2": -1
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_is_alive/normal/expected_result.json b/test/unit/mocked_data/test_is_alive/normal/expected_result.json
new file mode 100644
index 0000000..fd599e5
--- /dev/null
+++ b/test/unit/mocked_data/test_is_alive/normal/expected_result.json
@@ -0,0 +1,1 @@
+{"is_alive":  true}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_ping/normal/expected_result.json b/test/unit/mocked_data/test_ping/normal/expected_result.json
new file mode 100644
index 0000000..28fece2
--- /dev/null
+++ b/test/unit/mocked_data/test_ping/normal/expected_result.json
@@ -0,0 +1,16 @@
+{
+  "success": {
+    "probes_sent": 1,
+    "packet_loss": 0,
+    "rtt_min": 21,
+    "rtt_max": 21,
+    "rtt_avg": 21,
+    "rtt_stddev": 0,
+    "results": [
+      {
+        "ip_address": "8.8.8.8",
+        "rtt": 21
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_ping/normal/facts.json b/test/unit/mocked_data/test_ping/normal/facts.json
new file mode 100644
index 0000000..2a518ea
--- /dev/null
+++ b/test/unit/mocked_data/test_ping/normal/facts.json
@@ -0,0 +1,10 @@
+{
+  "ping": {
+    "status": 200,
+    "data": {
+      "uri": "/ping",
+      "result": "PR_OK",
+      "rtt_in_milliseconds": 21
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_traceroute/normal/expected_result.json b/test/unit/mocked_data/test_traceroute/normal/expected_result.json
new file mode 100644
index 0000000..c480013
--- /dev/null
+++ b/test/unit/mocked_data/test_traceroute/normal/expected_result.json
@@ -0,0 +1,99 @@
+{
+  "success": {
+    "1": {
+      "probes": {
+        "1": {
+          "rtt": 2.0,
+          "ip_address": "10.20.4.1",
+          "host_name": ""
+        },
+        "2": {
+          "rtt": 1.0,
+          "ip_address": "10.20.4.1",
+          "host_name": ""
+        },
+        "3": {
+          "rtt": 2.0,
+          "ip_address": "10.20.4.1",
+          "host_name": ""
+        }
+      }
+    },
+    "2": {
+      "probes": {
+        "1": {
+          "rtt": 0.0,
+          "ip_address": "10.191.253.109",
+          "host_name": ""
+        },
+        "2": {
+          "rtt": 1.0,
+          "ip_address": "10.191.253.109",
+          "host_name": ""
+        },
+        "3": {
+          "rtt": 1.0,
+          "ip_address": "10.191.253.109",
+          "host_name": ""
+        }
+      }
+    },
+    "3": {
+      "probes": {
+        "1": {
+          "rtt": 6.0,
+          "ip_address": "10.191.250.69",
+          "host_name": ""
+        },
+        "2": {
+          "rtt": 5.0,
+          "ip_address": "10.191.250.69",
+          "host_name": ""
+        },
+        "3": {
+          "rtt": 5.0,
+          "ip_address": "10.191.250.69",
+          "host_name": ""
+        }
+      }
+    },
+    "4": {
+      "probes": {
+        "1": {
+          "rtt": 20.0,
+          "ip_address": "142.251.225.135",
+          "host_name": ""
+        },
+        "2": {
+          "rtt": 21.0,
+          "ip_address": "142.251.48.177",
+          "host_name": ""
+        },
+        "3": {
+          "rtt": 22.0,
+          "ip_address": "142.250.224.133",
+          "host_name": ""
+        }
+      }
+    },
+    "5": {
+      "probes": {
+        "1": {
+          "rtt": 20.0,
+          "ip_address": "8.8.8.8",
+          "host_name": "dns.google"
+        },
+        "2": {
+          "rtt": 20.0,
+          "ip_address": "8.8.8.8",
+          "host_name": "dns.google"
+        },
+        "3": {
+          "rtt": 21.0,
+          "ip_address": "8.8.8.8",
+          "host_name": "dns.google"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/mocked_data/test_traceroute/normal/facts.json b/test/unit/mocked_data/test_traceroute/normal/facts.json
new file mode 100644
index 0000000..c6b7b43
--- /dev/null
+++ b/test/unit/mocked_data/test_traceroute/normal/facts.json
@@ -0,0 +1,166 @@
+{
+  "trace-route": {
+    "status": 200,
+    "data": {
+      "ttl_data": [
+        {
+          "ttl_probe_data": [
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.20.4.1"
+                }
+              },
+              "probe_time_in_millis": 2
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.20.4.1"
+                }
+              },
+              "probe_time_in_millis": 1
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.20.4.1"
+                }
+              },
+              "probe_time_in_millis": 2
+            }
+          ]
+        },
+        {
+          "ttl_probe_data": [
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.191.253.109"
+                }
+              },
+              "probe_time_in_millis": 0
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.191.253.109"
+                }
+              },
+              "probe_time_in_millis": 1
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.191.253.109"
+                }
+              },
+              "probe_time_in_millis": 1
+            }
+          ]
+        },
+        {
+          "ttl_probe_data": [
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.191.250.69"
+                }
+              },
+              "probe_time_in_millis": 6
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.191.250.69"
+                }
+              },
+              "probe_time_in_millis": 5
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "10.191.250.69"
+                }
+              },
+              "probe_time_in_millis": 5
+            }
+          ]
+        },
+        {
+          "ttl_probe_data": [
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "142.251.225.135"
+                }
+              },
+              "probe_time_in_millis": 20
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "142.251.48.177"
+                }
+              },
+              "probe_time_in_millis": 21
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "142.250.224.133"
+                }
+              },
+              "probe_time_in_millis": 22
+            }
+          ]
+        },
+        {
+          "ttl_probe_data": [
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "8.8.8.8"
+                }
+              },
+              "probe_time_in_millis": 20
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "8.8.8.8"
+                }
+              },
+              "probe_time_in_millis": 20
+            },
+            {
+              "gateway": {
+                "ip_address": {
+                  "version": "IAV_IP_V4",
+                  "octets": "8.8.8.8"
+                }
+              },
+              "probe_time_in_millis": 21
+            }
+          ]
+        }
+      ],
+      "result": "TRR_OK",
+      "uri": "/trace-route"
+    }
+  }
+}
\ No newline at end of file
diff --git a/test/unit/test_getters.py b/test/unit/test_getters.py
new file mode 100644
index 0000000..6a16ea5
--- /dev/null
+++ b/test/unit/test_getters.py
@@ -0,0 +1,10 @@
+"""Tests for getters."""
+
+from napalm.base.test.getters import BaseTestGetters
+
+import pytest
+
+
+@pytest.mark.usefixtures("set_device_parameters")
+class TestGetter(BaseTestGetters):
+    """Test get_* methods."""
diff --git a/test/unit/utils/textfsm_templates/show_arp.tpl b/test/unit/utils/textfsm_templates/show_arp.tpl
new file mode 100644
index 0000000..4dd9c4d
--- /dev/null
+++ b/test/unit/utils/textfsm_templates/show_arp.tpl
@@ -0,0 +1,10 @@
+Value IP (\S+)
+Value MAC ([0-9a-fA-F]{6}-[0-9a-fA-F]{6})
+Value TYPE (\S+)
+Value PORT (\S+)
+
+Start
+  ^.*IP ARP table -> ARP
+
+ARP
+  ^\s+${IP}\s+${MAC}\s+${TYPE}\s+${PORT} -> Record
diff --git a/test/unit/utils/textfsm_templates/show_ip_route.tpl b/test/unit/utils/textfsm_templates/show_ip_route.tpl
new file mode 100644
index 0000000..69ef9a5
--- /dev/null
+++ b/test/unit/utils/textfsm_templates/show_ip_route.tpl
@@ -0,0 +1,15 @@
+Value Required DESTINATION (\S+)
+Value GATEWAY (\S+)
+Value VLAN ([0-9]*)
+Value TYPE (\w+)
+Value SUBTYPE (\S*)
+Value METRIC ([0-9]+)
+Value DISTANCE ([0-9]+)
+
+
+Start
+  ^.*IP Route Entries -> Routes
+
+Routes
+  ^\s+${DESTINATION}\s+${GATEWAY}\s+${VLAN}\s+${TYPE}\s+${SUBTYPE}\s+${METRIC}\s+${DISTANCE} -> Record
+
diff --git a/test/unit/utils/textfsm_templates/show_ipv6_route.tpl b/test/unit/utils/textfsm_templates/show_ipv6_route.tpl
new file mode 100644
index 0000000..5745f71
--- /dev/null
+++ b/test/unit/utils/textfsm_templates/show_ipv6_route.tpl
@@ -0,0 +1,15 @@
+Value DESTINATION ([0-9a-z:/%]+)
+Value GATEWAY (\w+)
+Value VLAN (\w+)
+Value TYPE ([SCOR])
+Value SUBTYPE ([A-Z0-9][A-Z0-9])
+Value METRIC ([0-9]+)
+Value DISTANCE ([0-9]+)
+
+
+Start
+  ^.*IPv6 Route Entries -> Routes
+
+Routes
+  ^\s${DESTINATION}\s+
+  ^\s+${GATEWAY}\s(\(${VLAN}\))?\s+${TYPE}\s+${SUBTYPE}\s+${DISTANCE}\s+${METRIC} -> Record