Skip to content

Commit 23729ba

Browse files
authored
Merge pull request #1 from fknight3/feature/interactive_uploader
Uploader Template
2 parents 85eb202 + 4ca8d51 commit 23729ba

File tree

4 files changed

+208
-5
lines changed

4 files changed

+208
-5
lines changed

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
inquirer>=2.6.3
2+
pyfiglet>=0.8.post1

src/testlink/testcaseuploader.py

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
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()

src/testlink/testlinkapi.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -533,10 +533,7 @@ def bulkTestCaseUpload(self, login, file_contents, testfile_class):
533533
'external_id']:
534534
testfile_class.testlink_params['keywords']})
535535
i += 1
536-
if i == 0:
537-
print('There were no test cases to upload' + '\nBulk Test Upload Complete')
538-
else:
539-
print('[' + str(i) + ']' + ' Test Cases Created in TestLink' + '\nBulk Test Upload Complete')
536+
return i
540537

541538
def _parseFileToObject(self, tree_path, path):
542539
file_contents = open(path, 'r').read()

src/testlink/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@
1717
#
1818
# ------------------------------------------------------------------------
1919

20-
VERSION = '0.7.0'
20+
VERSION = '0.7.1'
2121
TL_RELEASE = '1.9.16'
2222

0 commit comments

Comments
 (0)