|
| 1 | +""" |
| 2 | + This module is the terminal interface for the TestLink Uploader. The expected workflow is that |
| 3 | + once an engineer has completed creating new test cases they will use this tool to upload their |
| 4 | + new test cases to the TestLink Application. The only inputs the application expects from users |
| 5 | + are the files they would like to upload and the location of their test projects library files. |
| 6 | +""" |
| 7 | + |
| 8 | +import os |
| 9 | +import sys |
| 10 | +import getpass |
| 11 | +import re |
| 12 | +from pprint import pprint |
| 13 | +from time import sleep |
| 14 | +from pyfiglet import Figlet |
| 15 | +import inquirer |
| 16 | +import testlink |
| 17 | + |
| 18 | + |
| 19 | +def update_sys_path(lib_path): |
| 20 | + """Adds the path for the projects libraries to the sys.path |
| 21 | +
|
| 22 | + This is needed to avoid any errors with loading the dependencies for the test file(s). |
| 23 | +
|
| 24 | + Args: |
| 25 | + lib_path (str): The path to the test projects library files |
| 26 | +
|
| 27 | + """ |
| 28 | + sys.path.append(os.path.abspath(lib_path)) |
| 29 | + |
| 30 | + |
| 31 | +def call_test_link_api(file_path): |
| 32 | + """Handles the API calls to TestLink |
| 33 | +
|
| 34 | + Args: |
| 35 | + file_path (str): The path to a file containing test cases to upload |
| 36 | +
|
| 37 | + Returns: |
| 38 | + tl_api_response (dict): Metadata about the API response |
| 39 | +
|
| 40 | + """ |
| 41 | + sys.path.append(os.path.split(file_path)[0]) |
| 42 | + test_file_path = os.path.split(file_path)[1].split('.py')[0] |
| 43 | + imported_test_file = __import__(test_file_path) |
| 44 | + test_class_name = test_file_path.replace('test', 'Tc').replace('_', ' ').title().replace( |
| 45 | + ' ', '') |
| 46 | + tls = testlink.TestLinkHelper().connect(testlink.TestlinkAPIClient) |
| 47 | + count_cases_uploaded = tls.bulkTestCaseUpload(getpass.getuser(), file_path, |
| 48 | + getattr(imported_test_file, test_class_name)) |
| 49 | + tl_api_response = {'test_file': test_file_path, 'uploaded_cases': count_cases_uploaded} |
| 50 | + return tl_api_response |
| 51 | + |
| 52 | + |
| 53 | +def upload_test_cases(files_list): |
| 54 | + """Uploads a group of test files to TestLink. |
| 55 | +
|
| 56 | + Args: |
| 57 | + files_list (list): A list of full paths for each file to be uploaded to TestLink |
| 58 | +
|
| 59 | + """ |
| 60 | + for file_path in files_list: |
| 61 | + tl_output = call_test_link_api(file_path) |
| 62 | + if tl_output['uploaded_cases'] is not 0: |
| 63 | + print(tl_output['test_file'] + ': Uploaded ' + str(tl_output['uploaded_cases']) + |
| 64 | + ' new test cases.') |
| 65 | + else: |
| 66 | + print(tl_output['test_file'] + ': There were no test cases to import.') |
| 67 | + |
| 68 | + |
| 69 | +def get_tests_to_upload(test_prefix='test_'): |
| 70 | + """Get information from the user regarding the files they are uploading via the API. |
| 71 | +
|
| 72 | + Uses the inquirer command line user interface to query the user. The inquirer cli will validate |
| 73 | + all data submitted. A user may choose to upload a single file or upload an entire folder. |
| 74 | + Note - that when uploading a folder, all of the root folders' subdirectories will be searched |
| 75 | + for test files to upload. The default prefix for a test files is "test_". |
| 76 | +
|
| 77 | + Args: |
| 78 | + test_prefix (str): The naming convention used for files containing test cases |
| 79 | + that should be uploaded to TestLink. |
| 80 | +
|
| 81 | + Returns: |
| 82 | + A dict containing the data that will be uploaded. Either the the test_file key or |
| 83 | + test_folder will be returned depending on what type of upload the user has selected. |
| 84 | + Example: |
| 85 | + {'libs_dir': '/home/johndoe/test_project', |
| 86 | + 'test_file': 'home/johndoe/test_project/test_item.py'} |
| 87 | +
|
| 88 | + """ |
| 89 | + if inquirer.list_input('How many test files do you need to upload?', |
| 90 | + choices=['Single', 'Multiple']) == 'Single': |
| 91 | + questions = [ |
| 92 | + inquirer.Path('test_file', message="Which test file are you uploading?", |
| 93 | + path_type=inquirer.Path.FILE), |
| 94 | + inquirer.Path('libs_dir', message="Whats the path to your projects library files?", |
| 95 | + path_type=inquirer.Path.DIRECTORY) |
| 96 | + ] |
| 97 | + else: |
| 98 | + questions = [ |
| 99 | + inquirer.Path('test_folder', message="Which test folder are you uploading?", |
| 100 | + path_type=inquirer.Path.DIRECTORY), |
| 101 | + inquirer.Path('libs_dir', message="Whats the path to your projects library files?", |
| 102 | + path_type=inquirer.Path.DIRECTORY) |
| 103 | + ] |
| 104 | + answers = inquirer.prompt(questions) |
| 105 | + files_to_upload = [] |
| 106 | + |
| 107 | + if 'test_folder' in answers: |
| 108 | + for root, dirs, files in os.walk(answers['test_folder']): |
| 109 | + for file in files: |
| 110 | + if re.search(test_prefix + '.*.py$', file) is not None: |
| 111 | + files_to_upload.append(root + '/' + file) |
| 112 | + else: |
| 113 | + files_to_upload.append(answers['test_file']) |
| 114 | + |
| 115 | + upload_data = {'tests': files_to_upload, 'libs_dir': answers['libs_dir']} |
| 116 | + upload_data['confirmed'] = confirm_upload(upload_data['tests']) |
| 117 | + return upload_data |
| 118 | + |
| 119 | + |
| 120 | +def confirm_upload(test_file_list): |
| 121 | + """Confirm if the user would like to proceed with uploading test data. |
| 122 | +
|
| 123 | + For folder uploads, the arg value will be presented to the user in a list. The intention is |
| 124 | + that they will be able to review the list of files the program found and confirm if they would |
| 125 | + like to proceed. |
| 126 | +
|
| 127 | + For single file uploads, the arg value will be presented to the user for confirmation that the |
| 128 | + path they previously submitted was correct. |
| 129 | +
|
| 130 | + Args: |
| 131 | + test_file_list (list): A list of test files that were identified as upload candidates |
| 132 | +
|
| 133 | + Returns: |
| 134 | + A string value of 'Yes' or 'No' |
| 135 | +
|
| 136 | + """ |
| 137 | + if len(test_file_list) > 1: |
| 138 | + print('\nFound ' + str(len(test_file_list)) + ' test(s) to upload.\n') |
| 139 | + print('Test(s):') |
| 140 | + pprint(test_file_list) |
| 141 | + print('\n') |
| 142 | + message_content = 'Are you sure you would like to upload these files?' |
| 143 | + else: |
| 144 | + message_content = 'Are you sure you would like to upload: ' + \ |
| 145 | + os.path.split(test_file_list[0])[1] + '?' |
| 146 | + confirmed = inquirer.list_input(message_content, choices=['Yes', 'No']) |
| 147 | + return confirmed |
| 148 | + |
| 149 | + |
| 150 | +def display_splash_screen(): |
| 151 | + """Print out an ASCII Text Banner.""" |
| 152 | + print(Figlet(font='slant').renderText('TestLink\nUploader')) |
| 153 | + |
| 154 | + |
| 155 | +def restart_application(): |
| 156 | + """Restart the application. |
| 157 | +
|
| 158 | + This process includes clearing the screen and displaying the splash screen again. The sleep was |
| 159 | + added to give the terminal time to catch up with the code. |
| 160 | +
|
| 161 | + """ |
| 162 | + os.system('clear') |
| 163 | + sleep(0.5) |
| 164 | + display_splash_screen() |
| 165 | + |
| 166 | + |
| 167 | +def exit_application(): |
| 168 | + """Exit the application. |
| 169 | +
|
| 170 | + This process gives the user notification that we are stopping the application. Clear the |
| 171 | + terminal for them and then exit the python application. |
| 172 | +
|
| 173 | + """ |
| 174 | + print('Exiting the TestLink Uploader...') |
| 175 | + sleep(1) |
| 176 | + os.system('clear') |
| 177 | + sys.exit() |
| 178 | + |
| 179 | + |
| 180 | +def main(): |
| 181 | + os.system('clear') |
| 182 | + display_splash_screen() |
| 183 | + |
| 184 | + # Get Test Case Data |
| 185 | + info = get_tests_to_upload() |
| 186 | + while info['confirmed'] == 'No': |
| 187 | + if inquirer.list_input('Would you like to exit the application?', |
| 188 | + choices=['Yes', 'No']) == 'Yes': |
| 189 | + exit_application() |
| 190 | + restart_application() |
| 191 | + info = get_tests_to_upload() |
| 192 | + update_sys_path(info['libs_dir']) |
| 193 | + upload_test_cases(info['tests']) |
| 194 | + |
| 195 | + # Upload Data |
| 196 | + |
| 197 | + # Verify the user is finished |
| 198 | + if inquirer.list_input('Do you have more tests to upload?', choices=['Yes', 'No']) == 'Yes': |
| 199 | + main() |
| 200 | + else: |
| 201 | + exit_application() |
| 202 | + |
| 203 | + |
| 204 | +main() |
0 commit comments