Initial CSIT code drop 03/102903/8
authorMarioDoman <mario.doman@pantheon.tech>
Thu, 27 Oct 2022 13:23:13 +0000 (15:23 +0200)
committerRobert Varga <nite@hq.sk>
Fri, 11 Nov 2022 16:56:32 +0000 (16:56 +0000)
This drops in the system test from integration/distribution,
so that it can be maintained with the corresponding codebase.

Change-Id: I5c05deb5e6e33d436b1af7362ccddfcd6f3a1566
Signed-off-by: MarioDoman <mario.doman@pantheon.tech>
csit/conftest.py [new file with mode: 0644]
csit/pytest.ini [new file with mode: 0644]
csit/pytest_lib.py [new file with mode: 0644]
csit/pytest_test.py [new file with mode: 0644]

diff --git a/csit/conftest.py b/csit/conftest.py
new file mode 100644 (file)
index 0000000..be77459
--- /dev/null
@@ -0,0 +1,37 @@
+# Copyright (c) 2019 PANTHEON.tech s.r.o. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+def pytest_addoption(parser):
+    parser.addoption('--BUNDLEFOLDER', action='store', default="", help='Get BUNDLEFOLDER from shell args')
+    parser.addoption('--BUNDLE_URL', action='store', default="", help='Get BUNDLE_URL from shell args')
+    parser.addoption('--CONTROLLER', action='store', default="", help='Get CONTROLLER from shell args')
+    parser.addoption('--CONTROLLER_USER', action='store', default="", help='Get CONTROLLER_USER from shell args')
+    parser.addoption('--GERRIT_BRANCH', action='store', default="", help='Get GERRIT_BRANCH from shell args')
+    parser.addoption('--GERRIT_PROJECT', action='store', default="", help='Get GERRIT_PROJECT from shell args')
+    parser.addoption('--GERRIT_REFSPEC', action='store', default="", help='Get GERRIT_REFSPEC from shell args')
+    parser.addoption('--JAVA_HOME', action='store', default="", help='Get JAVA_HOME from shell args')
+    parser.addoption('--JDKVERSION', action='store', default="", help='Get JDKVERSION from shell args')
+    parser.addoption('--JENKINS_WORKSPACE', action='store', default="", help='Get JENKINS_WORKSPACE from shell args')
+    parser.addoption('--MININET1', action='store', default="", help='Get MININET1 from shell args')
+    parser.addoption('--MININET2', action='store', default="", help='Get MININET2 from shell args')
+    parser.addoption('--MININET3', action='store', default="", help='Get MININET3 from shell args')
+    parser.addoption('--MININET4', action='store', default="", help='Get MININET4 from shell args')
+    parser.addoption('--MININET5', action='store', default="", help='Get MININET5 from shell args')
+    parser.addoption('--MININET', action='store', default="", help='Get MININET from shell args')
+    parser.addoption('--MININET_USER', action='store', default="", help='Get MININET_USER from shell args')
+    parser.addoption('--NEXUSURL_PREFIX', action='store', default="", help='Get NEXUSURL_PREFIX from shell args')
+    parser.addoption('--NUM_ODL_SYSTEM', action='store', default="", help='Get NUM_ODL_SYSTEM from shell args')
+    parser.addoption('--NUM_TOOLS_SYSTEM', action='store', default="", help='Get NUM_TOOLS_SYSTEM from shell args')
+    parser.addoption('--ODL_STREAM', action='store', default="", help='Get ODL_STREAM from shell args')
+    parser.addoption('--ODL_SYSTEM_1_IP', action='store', default="", help='Get ODL_SYSTEM_1_IP from shell args')
+    parser.addoption('--ODL_SYSTEM_IP', action='store', default="", help='Get ODL_SYSTEM_IP from shell args')
+    parser.addoption('--ODL_SYSTEM_USER', action='store', default="", help='Get ODL_SYSTEM_USER from shell args')
+    parser.addoption('--SUITES', action='store', default="", help='Get SUITES from shell args')
+    parser.addoption('--TOOLS_SYSTEM_IP', action='store', default="", help='Get TOOLS_SYSTEM_IP from shell args')
+    parser.addoption('--TOOLS_SYSTEM_USER', action='store', default="", help='Get TOOLS_SYSTEM_USER from shell args')
+    parser.addoption('--USER_HOME', action='store', default="", help='Get USER_HOME from shell args')
+    parser.addoption('--IS_KARAF_APPL', action='store', default="", help='Get IS_KARAF_APPL from shell args')
+    parser.addoption('--WORKSPACE', action='store', default="", help='Get WORKSPACE from shell args')
diff --git a/csit/pytest.ini b/csit/pytest.ini
new file mode 100644 (file)
index 0000000..6fc7531
--- /dev/null
@@ -0,0 +1,8 @@
+# Copyright (c) 2019 PANTHEON.tech s.r.o. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+[pytest]
+addopts = -p no:warnings
\ No newline at end of file
diff --git a/csit/pytest_lib.py b/csit/pytest_lib.py
new file mode 100644 (file)
index 0000000..23a8f1a
--- /dev/null
@@ -0,0 +1,109 @@
+# Copyright (c) 2019 PANTHEON.tech s.r.o. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+import paramiko
+
+# variables
+# NEW hashes
+YANGMODELS_REPO_COMMIT_HASH = "76b82325c19bd2907acd344e6ef9bf2adfaae5cc"
+OPENCONFIG_REPO_COMMIT_HASH = "00a27a5f0f3c472205ef293ab238e0530b610811"
+# OLD hashes
+# YANGMODELS_REPO_COMMIT_HASH = "cdd14114cdaf130be2b6bfce92538c05f6d7c07d"
+# OPENCONFIG_REPO_COMMIT_HASH = "8062b1b45208b952598ad3c3aa9e5ebc4f03cc67"
+
+YANGMODELS_REPO = "https://github.com/YangModels/yang"
+OPENCONFIG_REPO = "https://github.com/openconfig/public"
+TEST_TOOL_NAME = "yang-model-validator"
+NEXUS_FALLBACK_URL_PART2 = "/content/repositories/opendaylight.release"
+RELEASE_INTEGRATED_COMPONENTS = ["mdsal", "odlparent", "yangtools", "carpeople", "netconf"]
+NEXUS_RELEASE_BASE_URL = "https://nexus.opendaylight.org/content/repositories/opendaylight.release"
+ROOT="src/main/yang"
+
+def execute_ssh_command(hostname, command, username, commands_as_list=False):
+    # created client using paramiko
+    client = paramiko.SSHClient()
+    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+    client.connect(hostname, username=username)
+    if commands_as_list:
+        for command in commands_as_list:
+            (stdin, stdout, stderr) = client.exec_command(command)
+            cmd_output = stdout.read()
+            error = stderr.read()
+    else:
+        (stdin, stdout, stderr) = client.exec_command(command)
+    exit_status=(stdout.channel.recv_exit_status())
+    cmd_output = stdout.read()
+    error = stderr.read()
+    client.close()
+    return [cmd_output, exit_status, error]
+
+COMPONENT_MAPPING = {"netconf":"netconf-impl",
+                     "bgpcep":"pcep-impl",
+                     "carpeople":"clustering-it-model",
+                     "yangtools":"yang-data-impl",
+                     "bindingv1":"mdsal-binding-generator-impl",
+                     "odl-micro":"odlmicro-impl"}
+
+delete_static_paths_list = [
+    "rm -vrf src/main/yang/.git",
+    "rm -vrf src/main/yang/experimental",
+    # excluding ieee/draft from test
+    "rm -vrf src/main/yang/standard/ieee/draft",
+    "rm -vrf src/main/yang/standard/ietf/DRAFT",
+    # excluding 4 files due error "Unexpected error processing source SourceIdentifier [ietf-network@2018-02-26]"
+    # bug reported here https://jira.opendaylight.org/browse/YANGTOOLS-1465
+    "rm -vfr src/main/yang/standard/ietf/RFC/ietf-te-topology-state.yang",
+    "rm -vfr src/main/yang/standard/ietf/RFC/ietf-te-topology-state@2020-08-06.yang",
+    "rm -vfr src/main/yang/standard/ietf/RFC/ietf-te-topology.yang",
+    "rm -vfr src/main/yang/standard/ietf/RFC/ietf-te-topology@2020-08-06.yang",
+    ## Removing entire juniper folder because it creates an OOM Crash with the validator tool.*** Keywords ***
+    ## Unsure if the yang models are the problem or something in the tool. This is being tracked here:
+    ## https://jira.opendaylight.org/browse/YANGTOOLS-1093
+    "rm -vrf src/main/yang/vendor/juniper"
+    ## Removing the cisco folder because there are over 30k yang files there and would increase the test time to something
+    ## unmanageable.
+    "rm -vrf src/main/yang/vendor/cisco",
+    ## Mount points may only be defined at either a container or a list, not anydata, lines 948
+    ## https://tools.ietf.org/html/rfc8528#section-3.1
+    "rm -vrf src/main/yang/standard/ietf/RFC/ietf-connectionless-oam@2019-04-16.yang",
+    ## removed dependency file from test standard/ietf/RFC/ietf-connectionless-oam@2019-04-16.yang
+    "rm -vrf src/main/yang/standard/ietf/RFC/ietf-connectionless-oam.yang",
+    ## removed dependecy file from test standard/ietf/RFC/ietf-connectionless-oam-methods@2019-04-16.yang
+    "rm -vrf src/main/yang/standard/ietf/RFC/ietf-connectionless-oam-methods.yang",
+    "rm -vrf src/main/yang/standard/ietf/RFC/ietf-connectionless-oam-methods@2019-04-16.yang",
+]
+
+yang_model_paths = [
+    "/home/jenkins/src/main/yang/",
+    "/home/jenkins/src/main/yang/standard",
+    "/home/jenkins/src/main/yang/standard/etsi",
+    "/home/jenkins/src/main/yang/standard/etsi/NFV-SOL006-v3.6.1",
+    "/home/jenkins/src/main/yang/standard/etsi/NFV-SOL006-v2.6.1",
+    "/home/jenkins/src/main/yang/standard/etsi/NFV-SOL006-v2.7.1",
+    "/home/jenkins/src/main/yang/standard/etsi/NFV-SOL006-v2.8.1",
+    "/home/jenkins/src/main/yang/standard/etsi/NFV-SOL006-v3.3.1",
+    "/home/jenkins/src/main/yang/standard/etsi/NFV-SOL006-v3.5.1",
+    "/home/jenkins/src/main/yang/standard/odp",
+    "/home/jenkins/src/main/yang/standard/bbf",
+    "/home/jenkins/src/main/yang/standard/ietf",
+    "/home/jenkins/src/main/yang/standard/ietf/RFC",
+    "/home/jenkins/src/main/yang/standard/mef",
+    "/home/jenkins/src/main/yang/standard/ieee",
+    "/home/jenkins/src/main/yang/standard/ieee/published",
+    "/home/jenkins/src/main/yang/standard/ieee/published/802.1",
+    "/home/jenkins/src/main/yang/standard/ieee/published/802.11",
+    "/home/jenkins/src/main/yang/standard/ieee/published/802",
+    "/home/jenkins/src/main/yang/standard/ieee/published/1588",
+    "/home/jenkins/src/main/yang/standard/ieee/published/802.3",
+    "/home/jenkins/src/main/yang/standard/ieee/published/1906.1",
+    "/home/jenkins/src/main/yang/standard/ieee/published/1906.1/Examples",
+    "/home/jenkins/src/main/yang/standard/iana",
+    "/home/jenkins/src/main/yang/vendor",
+    "/home/jenkins/src/main/yang/vendor/fujitsu",
+    "/home/jenkins/src/main/yang/vendor/huawei",
+    "/home/jenkins/src/main/yang/vendor/ciena",
+    "/home/jenkins/src/main/yang/vendor/nokia"
+]
\ No newline at end of file
diff --git a/csit/pytest_test.py b/csit/pytest_test.py
new file mode 100644 (file)
index 0000000..95585dc
--- /dev/null
@@ -0,0 +1,191 @@
+# Copyright (c) 2019 PANTHEON.tech s.r.o. All rights reserved.
+#
+# This program and the accompanying materials are made available under the
+# terms of the Eclipse Public License v1.0 which accompanies this distribution,
+# and is available at http://www.eclipse.org/legal/epl-v10.html
+
+import datetime, os, pytest, socket
+import pytest_lib
+
+# create list of variables
+var_list = ["CONTROLLER_USER", "ODL_SYSTEM_IP"]
+hostname=socket.gethostname()
+global ssh_num
+
+@pytest.fixture
+def bash_arguments(request):
+    # get shell arguments using conftest.py and save it to odl_params
+    global odl_params
+    odl_params = {x: (request.config.getoption('--' + x)) for x in var_list}
+    return odl_params
+
+def test_getting_bash_arguments(bash_arguments):
+    # save arguments to odl_params to not spam ssh connections
+    assert odl_params['CONTROLLER_USER'] != ""
+
+def test_preparing_enviroment():
+    # using commands_as_list and cmd=None to executing more then one command over SSH
+    commands_as_list = [
+        "ps axf | grep org.apache.karaf | grep -v grep | wc -l", # check if karaf is not running
+        "rm -rf target src", # rm dir
+        "mkdir -p src/main", # create dir
+        f"cd src/main && git clone {pytest_lib.YANGMODELS_REPO}", # clone yangmodels
+        # f"cd src/main/yang && git checkout -b ytest {pytest_lib.YANGMODELS_REPO_COMMIT_HASH}", # checkout_yangmodels
+        ]
+    response = pytest_lib.execute_ssh_command(command=None, username=odl_params['CONTROLLER_USER'], hostname=odl_params['ODL_SYSTEM_IP'], commands_as_list=commands_as_list)
+    console_output, exit_code, error = response[0], response[1], response[2]
+    assert exit_code == 0
+
+def test_delete_static_paths():
+    # delete logs from previous testing on locallhost
+    # os.system("rm -rf *yang-model-validator--yangtools-system-txt*")
+    # using commands_as_list and cmd=None to executing more then one command over SSH
+    cmd = None
+    response = pytest_lib.execute_ssh_command(command=cmd, username=odl_params['CONTROLLER_USER'], hostname=odl_params['ODL_SYSTEM_IP'], commands_as_list=pytest_lib.delete_static_paths_list)
+    console_output, exit_code, error = response[0], response[1], response[2]
+    assert exit_code == 0
+
+# Deploy_And_Start_Odl_Yang_Validator_Utility
+def test_get_dirs_to_process():
+    global dirs_to_process
+    # command get full path to directories
+    cmd = f'ls -d $PWD/src/main/yang/*/'
+    response = pytest_lib.execute_ssh_command(command=cmd, username=odl_params['CONTROLLER_USER'], hostname=odl_params['ODL_SYSTEM_IP'])
+    # convert bytes output to list and remove last item
+    dirs_to_process = (response[0].decode("utf-8").split("\n"))[:-1]
+    console_output, exit_code, error = response[0], response[1], response[2]
+    assert exit_code == 0
+
+def test_get_yang_files_to_validate():
+    global yang_files_to_validate
+    yang_files_to_validate = []
+    for dir in dirs_to_process:
+        cmd = f'find {dir} -name "*.yang"'
+        response = pytest_lib.execute_ssh_command(command=cmd, username=odl_params['CONTROLLER_USER'], hostname=odl_params['ODL_SYSTEM_IP'])
+        yang_files_in_dir = (response[0].decode("utf-8").split("\n"))[:-1]
+        yang_files_to_validate.extend(yang_files_in_dir)
+    console_output, exit_code, error = response[0], response[1], response[2]
+    assert exit_code == 0
+
+def test_yang_path_option():
+    global yang_path_option
+    yang_path_option = "--path "
+    for path in pytest_lib.yang_model_paths:
+        if hostname  == "ubuntu2":
+            yang_path_option += (path.replace("jenkins", "ubuntu") + " ")
+        else:
+            yang_path_option += (path + " ")
+    assert len(yang_path_option) > 0
+
+def test_download_yang_model_validator():
+    global url, artifact, version, filename
+    urlbase = pytest_lib.NEXUS_RELEASE_BASE_URL
+    location = "org/opendaylight/yangtools"
+    component="yangtools"
+    artifact=pytest_lib.TEST_TOOL_NAME
+    version = "9.0.2"
+    url = urlbase + "/" + location + "/" + artifact + "/" + version
+    name_prefix = f"{artifact}-"
+    suffix="jar-with-dependencies"
+    extension = "tar" if component == "odl-micro" else "jar"
+    name_suffix = f"-{suffix}.{extension}" if suffix != "" else f".{extension}"
+    filename = name_prefix + version + name_suffix
+    url = url + "/" + filename
+    cmd = f"wget -q -N '{url}' 2>&1"
+    print(cmd)
+    response = pytest_lib.execute_ssh_command(command=cmd, username=odl_params['CONTROLLER_USER'], hostname=odl_params['ODL_SYSTEM_IP'])
+    console_output, exit_code, error = response[0], response[1], response[2]
+    assert exit_code == 0
+
+def test_yang_files_loop():
+    global url
+    EFFECTIVE_MODEL_not_resolved = []
+    not_pass_yang_files = []
+    leaf_is_missing = []
+    Mount_points_may_only_be_defined_at_either_a_container_or_a_list = []
+    Following_components_of_unique_statement = []
+    Leaf_list_is_missing = []
+    statement_has_to_be_present = []
+    An_augment_cannot_add_node_named = []
+    Augment_target = []
+    other = []
+    for x in range (0,10):
+    # for x in range (0,len(yang_files_to_validate)):
+        print("Working on file: ", yang_files_to_validate[x])
+        tool_options=f" {yang_path_option}-- {yang_files_to_validate[x]}"
+        # set java version based on ip (testing on locallhost)
+        base_command = "/usr/lib/jvm/java-17-openjdk/bin/java"
+        if hostname == "ubuntu2":
+            base_command = "/usr/lib/jvm/java-17-openjdk-amd64/bin/java"
+        command = base_command + "  -jar " + filename + tool_options
+        print(command)
+        # generate name for log file
+        name = "yangtools-system-txt"
+        date = datetime.datetime.today()
+        timestamp = str(date.timestamp())[:-3]
+        logfile = f"{artifact}--{name}.{timestamp}.log"
+        cmd =  f"{command} > {logfile} 2>&1"
+        response = pytest_lib.execute_ssh_command(command=cmd, username=odl_params['CONTROLLER_USER'], hostname=odl_params['ODL_SYSTEM_IP'])
+        console_output, exit_code, error = response[0], response[1], response[2]
+        # copy log file and print error to console
+        if exit_code != 0:
+            os.system(f"scp {odl_params['CONTROLLER_USER']}@{odl_params['ODL_SYSTEM_IP']}:{logfile} .")
+            with open(logfile) as f:
+                text_log = f.read()
+                # add log name prefix for change name of file due to error
+                logname_prefix = ""
+                if 'Mount points may only be defined at either a container or a list' in text_log:
+                    logname_prefix = "mount-points-"
+                    Mount_points_may_only_be_defined_at_either_a_container_or_a_list.append(yang_files_to_validate[x])
+                elif "Leaf-list is missing a 'type' statement" in text_log:
+                    logname_prefix = "Leaf-list-is-missing-"
+                    Leaf_list_is_missing.append(yang_files_to_validate[x])
+                elif "At least one enum statement has to be present" in text_log:
+                    logname_prefix = "statement-has-to-be-present-"
+                    statement_has_to_be_present.append(yang_files_to_validate[x])
+                elif "An augment cannot add node named" in text_log:
+                    logname_prefix = "augment-cannot-add-node-named-"
+                    An_augment_cannot_add_node_named.append(yang_files_to_validate[x])
+                elif "Augment target" in text_log:
+                    logname_prefix = "Augment-target-"
+                    Augment_target.append(yang_files_to_validate[x])
+                elif 'Following components of unique statement argument refer to non-existent nodes:' in text_log:
+                    logname_prefix = "following-components-"
+                    Following_components_of_unique_statement.append(yang_files_to_validate[x])
+                elif 'Leaf is missing a' not in text_log and "Some of EFFECTIVE_MODEL modifiers for statements were not resolved" in text_log:
+                    logname_prefix = "effective-model-"
+                    EFFECTIVE_MODEL_not_resolved.append(yang_files_to_validate[x])
+                elif 'Leaf is missing a' in text_log:
+                    logname_prefix = "leaf-"
+                    leaf_is_missing.append(yang_files_to_validate[x])
+                else:
+                    logname_prefix = "others-"
+                    other.append(yang_files_to_validate[x])
+                os.system(f"mv {logfile} {logname_prefix + logfile}")
+                print(40 * "*", f" ERROR IN YANG FILE {yang_files_to_validate[x]} ", 40 * "*")
+                print("LOG FILE = ", logname_prefix + logfile)
+                os.system(f"cat {logname_prefix + logfile}")
+                print(40 * "*", " ERROR ", 40 * "*")
+                not_pass_yang_files.append(yang_files_to_validate[x])
+    print("Augment_target count = ", len(Augment_target))
+    print("Augment_target print:  ", Augment_target)
+    print("An_augment_cannot_add_node_named count = ", len(An_augment_cannot_add_node_named))
+    print("An_augment_cannot_add_node_named print:  ", An_augment_cannot_add_node_named)
+    print("statement_has_to_be_present count = ", len(statement_has_to_be_present))
+    print("statement_has_to_be_present print:  ", statement_has_to_be_present)
+    print("Leaf_list_is_missing count = ", len(Leaf_list_is_missing))
+    print("Leaf_list_is_missing print:  ", Leaf_list_is_missing)
+    print("EFFECTIVE_MODEL_not_resolved count = ", len(EFFECTIVE_MODEL_not_resolved))
+    print("EFFECTIVE_MODEL_not_resolved print:  ", EFFECTIVE_MODEL_not_resolved)
+    print("leaf_is_missing count = ", len(leaf_is_missing))
+    print("leaf_is_missing print:  ", leaf_is_missing)
+    print("Mount_points_may_only_be_defined_at_either_a_container_or_a_list count = ", len(Mount_points_may_only_be_defined_at_either_a_container_or_a_list))
+    print("Mount_points_may_only_be_defined_at_either_a_container_or_a_list print:  ", Mount_points_may_only_be_defined_at_either_a_container_or_a_list)
+    print("Following components of unique statement argument refer to non-existent nodes: count = ", len(Following_components_of_unique_statement))
+    print("Following components of unique statement argument refer to non-existent nodes::  ", Following_components_of_unique_statement)
+    print("other count = ", len(other))
+    print("other print:  ", other)
+    print("all yang_files_to_validate = ", len(yang_files_to_validate))
+    print("all not_pass_yang_files count= ", len(not_pass_yang_files))
+    print("all not_pass_yang_files = ", not_pass_yang_files)
+    assert exit_code == 0
\ No newline at end of file