Allow unqualified node-identifiers in instance-identifier
[yangtools.git] / csit / yangtools_test.py
1 # Copyright (c) 2019 PANTHEON.tech s.r.o. All rights reserved.
2 #
3 # This program and the accompanying materials are made available under the
4 # terms of the Eclipse Public License v1.0 which accompanies this distribution,
5 # and is available at http://www.eclipse.org/legal/epl-v10.html
6
7 import datetime
8 import os
9 import sys, getopt
10 import pytest_lib
11 import time
12
13 start_time = time.time()
14
15 def get_java():
16     global java_home
17     try:
18         java_home = os.environ['JAVA_HOME']
19         print(f"JAVA_HOME found: {java_home}")
20     except:
21         print("JAVA_HOME not found, trying to get it from system.")
22         try:
23             java_home = os.popen("(dirname $(dirname $(readlink -f $(which javac))))").read().split("\n")[0] + "/bin/java"
24         except:
25             print("JAVA_HOME not found or java not installed, please install java or set JAVA_HOME first.")
26             sys.exit(2)
27
28 # retrieve args from command
29 def main(argv):
30     global log, models, validator
31     log = "N"
32     models = "/src/main/yang/"
33     validator = ""
34     try:
35         opts, args = getopt.getopt(argv,"hl:m:v:",["help", "log=","models=", "validator="])
36     except getopt.GetoptError:
37         print("wrong usage type -h or --help for help")
38         sys.exit(2)
39     for opt, arg in opts:
40         if opt == '-h' or opt == '--help':
41             print("Usage: python3 yangtools_test.py [log] [models] [validator_version]")
42             print("[log]\n-l, --log=y/n    for delete previous logs in ~/yangtools_csit_test/yang_validator_logs/ (omitting will not delete previous logs)")
43             print("[validator_version]\n-v, --validator=10.0.2    will download yang-model-validator-10.0.0-jar-with-dependencies.jar from nexus.opendaylight.org (omitting will build it locally")
44             print("[models]\n-m, --models=/path/to/models/    select directory for testing (omitting will test all models)")
45             print('''models option examples:
46 /src/main/yang/standard/
47 /src/main/yang/vendor/
48 /src/main/yang/standard/ietf/
49 /src/main/yang/standard/ieee/
50 /src/main/yang/standard/iana/
51 /src/main/yang/vendor/ciena/''')
52             sys.exit()
53         elif opt in ("-l", "--log"):
54             log = arg.upper()
55         elif opt in ("-m", "--models"):
56             models = arg
57         elif opt in ("-v", "--validator"):
58             validator = arg
59
60 if __name__ == "__main__":
61    main(sys.argv[1:])
62
63 home_dir = str(os.path.expanduser('~')) # get home dir for local user
64 working_dir = (home_dir) + "/yangtools_csit_test"
65 logfile_path = f"{working_dir}/yang_validator_logs/"
66
67 def prepare_enviroment():
68     os.system(f"rm -rf target {working_dir}/src && mkdir -p {working_dir}/src/main")
69     os.system(f"cd {working_dir}/src/main && git clone --depth 10 {pytest_lib.YANGMODELS_REPO}")
70     os.system(f'mkdir {logfile_path}')
71
72
73 def delete_static_paths():
74     # delete logs from previous testing on locallhost
75     delete_logs = log.upper()
76     if delete_logs == "Y":
77         os.system(f"rm -rf {logfile_path}*")
78     # delete not tested models from pytest_lib.delete_static_paths_list
79     for file in pytest_lib.delete_static_paths_list:
80         print(f"rm -vrf {working_dir + file}")
81         os.system(f"rm -vrf {working_dir + file}")
82
83
84 def get_yang_files_to_validate():
85     # get full path to directories
86     yang_files_to_validate = os.popen(f'find {working_dir}{models}* -name "*.yang"').read().split("\n")[:-1]
87     print(f"Files to validate = {len(yang_files_to_validate)}\nFiles: {yang_files_to_validate}")
88     return (yang_files_to_validate)
89
90
91 def get_yang_path():
92     global yang_path_option
93     yang_path_option = "--path "
94     for path in pytest_lib.yang_model_paths:
95         yang_path_option += (working_dir + path +  " ")
96
97 def download_yang_model_validator():
98     global validator_file_name, validator
99     # check if validator argument received
100     if validator == "":
101         # check if validator was build with maven or built it
102         if check_maven() and get_validator_file_name():
103             return validator_file_name
104         elif check_maven() and not get_validator_file_name():
105             print("building yang-validator with command 'cd ../ && mvn clean install -pl tools/yang-model-validator/'")
106             print(os.popen(f"cd ../ && mvn clean install -pl tools/yang-model-validator/").read())
107             get_validator_file_name()
108         else:
109             print("MAVEN not found, please install MAVEN first and restart python command")
110             sys.exit()
111     else:
112         validator_file_name = f"yang-model-validator-{validator}-jar-with-dependencies.jar"
113         if validator_file_name in os.popen("ls -la").read():
114             print(f"file {validator_file_name} exist...")
115         else:
116             print(f"downloading {validator_file_name}")
117             print(os.system(f"wget https://nexus.opendaylight.org/content/repositories/opendaylight.release/org/opendaylight/yangtools/yang-model-validator/{validator}/{validator_file_name}"))
118
119
120
121 def get_validator_file_name():
122     global validator_file_name, yang_target_dir
123     yang_target_dir = "../tools/yang-model-validator/target/"
124     get_dir_files = os.popen(f"ls {yang_target_dir}").read()
125     if "-SNAPSHOT-jar-with-dependencies.jar" in get_dir_files:
126         for line in get_dir_files.split("\n"):
127             if "-SNAPSHOT-jar-with-dependencies.jar" in line:
128                 validator_file_name = line
129                 return True
130
131 def check_maven():
132     if "Apache Maven" in os.popen("mvn --version").read():
133         return True
134
135
136 def yang_files_loop(yang_files_to_validate):
137     global yang_path_option, yang_target_dir
138     file_counter = 0
139     effective_model_not_resolved, all_not_pass_yang_files, leaf_is_missing, mount_points, following_components = [],[],[],[],[]
140     leaf_list_is_missing, statement_has_to_be_present, augment_cannot_add_node_named, augment_target, other = [],[],[],[],[]
141     for x in range (0,len(yang_files_to_validate)):
142         file_counter +=1
143         print("Working on file: ", yang_files_to_validate[x])
144         print(f"Testing file {file_counter} from total {len(yang_files_to_validate)} files")
145         # update --path option for ietf/RFC/ models to shorten test duration
146         if "/src/main/yang/standard/ietf/RFC" in yang_files_to_validate[x]:
147             yang_path_option = f"--path {working_dir}/src/main/yang/standard/ietf/RFC {working_dir}/src/main/yang/standard/ieee/published/802.1 {working_dir}/src/main/yang/standard/ieee/published/802 {working_dir}/src/main/yang/vendor/ciena "
148         tool_options=f" {yang_path_option}-- {yang_files_to_validate[x]}"
149         # update command if argument --validator given
150         if validator != "":
151             yang_target_dir =  ""
152         command = java_home + "  -jar " + yang_target_dir + validator_file_name + tool_options
153         # generate name for log file
154         name = "yangtools-log"
155         date = datetime.datetime.today()
156         timestamp = str(date.timestamp())[:-3]
157         logfile = f"{name}.{timestamp}.log"
158         cmd =  f"{command} > {logfile_path + logfile} 2>&1"
159         os.popen(cmd).read()
160         # copy log file and print error to console
161         if os.stat(logfile_path + logfile).st_size != 0:
162             print("java command: ", cmd)
163             with open(logfile_path + logfile) as f:
164                 text_log = f.read()
165                 # add log name prefix for change name of file due to error
166                 logname_prefix = ""
167                 if 'Mount points may only be defined at either a container or a list' in text_log:
168                     logname_prefix = "mount-points-"
169                     mount_points.append(yang_files_to_validate[x])
170                 elif "Leaf-list is missing a 'type' statement" in text_log:
171                     logname_prefix = "Leaf-list-is-missing-"
172                     leaf_list_is_missing.append(yang_files_to_validate[x])
173                 elif "At least one enum statement has to be present" in text_log:
174                     logname_prefix = "statement-has-to-be-present-"
175                     statement_has_to_be_present.append(yang_files_to_validate[x])
176                 elif "An augment cannot add node named" in text_log:
177                     logname_prefix = "augment-cannot-add-node-named-"
178                     augment_cannot_add_node_named.append(yang_files_to_validate[x])
179                 elif "Augment target" in text_log:
180                     logname_prefix = "Augment-target-"
181                     augment_target.append(yang_files_to_validate[x])
182                 elif 'Following components of unique statement argument refer to non-existent nodes:' in text_log:
183                     logname_prefix = "following-components-"
184                     following_components.append(yang_files_to_validate[x])
185                 elif 'Leaf is missing a' not in text_log and "Some of EFFECTIVE_MODEL modifiers for statements were not resolved" in text_log:
186                     logname_prefix = "effective-model-"
187                     effective_model_not_resolved.append(yang_files_to_validate[x])
188                 elif 'Leaf is missing a' in text_log:
189                     logname_prefix = "leaf-"
190                     leaf_is_missing.append(yang_files_to_validate[x])
191                 else:
192                     logname_prefix = "others-"
193                     other.append(yang_files_to_validate[x])
194                 os.system(f"mv {logfile_path + logfile} {logfile_path + logname_prefix + logfile}")
195                 print(40 * "*", f" ERROR IN YANG FILE {yang_files_to_validate[x]} ", 40 * "*")
196                 print("LOG FILE = ", logfile_path + logname_prefix + logfile)
197                 os.system(f"cat {logfile_path + logname_prefix + logfile}")
198                 print(40 * "*", " ERROR ", 40 * "*")
199                 all_not_pass_yang_files.append(yang_files_to_validate[x])
200         else:
201             os.system(f"rm -vrf {logfile_path + logfile}")
202     print_files_name = ["all_not_pass_yang_files", "effective_model_not_resolved", "leaf_is_missing", "mount_points", "following_components",
203                         "leaf_list_is_missing", "statement_has_to_be_present", "augment_cannot_add_node_named", "augment_target", "other"]
204     print_files_count = [all_not_pass_yang_files, effective_model_not_resolved, leaf_is_missing, mount_points, following_components,
205                         leaf_list_is_missing, statement_has_to_be_present, augment_cannot_add_node_named, augment_target, other]
206
207     # print test result counts and save txt list with not pass files
208     print("\n\n\n",40 * "*", " TEST RESULTS  ", 40 * "*")
209     print(f"All tested files: {len(yang_files_to_validate)}")
210     for x in range(0, len(print_files_count)):
211         if print_files_count[x]:
212             print(f"{print_files_name[x]} = {len(print_files_count[x])}")
213             with open(f'{logfile_path}_{print_files_name[x]}.txt', 'w') as f:
214                 f.write(str(print_files_count[x]) + '\n')
215     print(f"Detailed LOGS here: {logfile_path}")
216
217 get_java()
218 prepare_enviroment()
219 delete_static_paths()
220 download_yang_model_validator()
221 get_yang_path()
222 yang_files_loop(get_yang_files_to_validate())
223 print("test duration --- %s seconds ---" % (time.time() - start_time))