tms-cli 0.0.pre.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/tms.rb ADDED
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require_relative 'preprocessing'
5
+ require_relative 'regression'
6
+ require_relative 'cucumber'
7
+ require_relative 'acceptance_criteria'
8
+ require_relative 'testrail/log'
9
+ require_relative 'db/mysql'
10
+ require_relative 'testrail/dataprep'
11
+ require_relative '../util/script/mergerequest'
12
+ require_relative '../util/script/generate-password'
13
+
14
+ module Tms
15
+ class CLI < Thor
16
+
17
+ include Preprocessing
18
+ include Regression
19
+ include Cucumber
20
+ include Log
21
+ include Dataprep
22
+ include Gitlab
23
+ include AcceptanceCriteria
24
+
25
+ def initialize(*args)
26
+ super
27
+ @starting = Process.clock_gettime(Process::CLOCK_MONOTONIC)
28
+ Dotenv.load(".env")
29
+ end
30
+
31
+ desc 'post_report', 'Process Test Result to TestRail'
32
+ method_option :report_file, :aliases => "-f", :desc => "Report file (.json) - example : ./STG-E2E-MITRA_BANGUNAN-report_tms.json or ./STG-E2E-MITRA_BANGUNAN-report_tms-*.json for multiple report", :default => [], :type => :array
33
+ method_option :milestone_name, :aliases => "-r", :desc => "Release Version of Test", :default => ""
34
+ method_option :attachment_dir, :aliases => "-d", :desc => "Attachment Directory - example : /Home/Attachment/*", :default => ""
35
+ method_option :generate_report, :aliases => "-g", :desc => "Create report on TMS", :type => :boolean, default: false
36
+ method_option :chromedriver_dir, :aliases => "-c", :desc => "Create report on TMS", default: "./chromedriver"
37
+ method_option :email_azure, :aliases => "-u", :desc => "user azure (inclue @azure.bukalapak.io)", :default => ""
38
+ method_option :suite_name, :aliases => "-t", :desc => "suite name", :default => ""
39
+ method_option :section_name, :aliases => "-e", :desc => "section name", :default => ""
40
+ method_option :local, :aliases => "-l", :desc => "running from local", :type => :boolean, default: false
41
+
42
+ def post_report
43
+ begin
44
+ if !options[:suite_name].nil? && !options[:section_name].nil? && !options[:suite_name].empty? && !options[:section_name].empty?
45
+ Preprocessing.execute_preprocessing_bdd(options[:report_file], options[:suite_name], options[:section_name])
46
+ else
47
+ runner_type = ENV['TEST_RUNNER_TYPE'] || ""
48
+ Preprocessing.execute_preprocessing(options[:report_file], options[:milestone_name], options[:attachment_dir], runner_type)
49
+ end
50
+ rescue => e
51
+ Log.error(e, options[:local])
52
+ exit 1
53
+ end
54
+ count_elapsed_time
55
+ end
56
+
57
+ desc 'clean_refs', 'Clean Invalid References format'
58
+ method_option :project_id, :aliases => "-P", :desc => "Project id", :default => ""
59
+ method_option :local, :aliases => "-l", :desc => "running from local", :type => :boolean, default: false
60
+ method_option :email_azure, :aliases => "-u", :desc => "user azure (include @azure.bukalapak.io)", :default => ""
61
+
62
+ def clean_refs
63
+ begin
64
+ Preprocessing.execute_clean_testcase(options[:project_id])
65
+ rescue => e
66
+ Log.error(e, options[:local])
67
+ exit 1
68
+ end
69
+ count_elapsed_time
70
+ end
71
+
72
+ desc 'generate_report', 'Generate Traceability Metric and Coverage Report'
73
+ method_option :project_name, :aliases => "-p", :desc => "Project Name", :default => ""
74
+ method_option :milestone_name, :aliases => "-m", :desc => "Milestone Name", :default => ""
75
+ method_option :chromedriver_dir, :aliases => "-c", :desc => "Create report on TMS", default: "/testrail/chromedriver"
76
+ method_option :local, :aliases => "-l", :desc => "running from local", :type => :boolean, default: false
77
+ method_option :email_azure, :aliases => "-u", :desc => "user azure (inclue @azure.bukalapak.io)", :default => ""
78
+
79
+ def generate_report
80
+ ENV['CHROMEDRIVER'] = options[:chromedriver_dir]
81
+ puts options[:project_name]
82
+ puts options[:milestone_name]
83
+ begin
84
+ Preprocessing.execute_generate_report(options[:project_name], options[:milestone_name])
85
+ rescue => e
86
+ Log.error(e, options[:local])
87
+ exit 1
88
+ end
89
+ count_elapsed_time
90
+ end
91
+
92
+ desc 'capture_mr_result', 'Capture dashboard result for specific test'
93
+ method_option :project_name, :aliases => "-p", :desc => "Project Name", :default => ""
94
+ method_option :milestone_name, :aliases => "-m", :desc => "Milestone Name", :default => ""
95
+ method_option :chromedriver_dir, :aliases => "-c", :desc => "Chromedriver", default: "/testrail/chromedriver"
96
+ method_option :local, :aliases => "-l", :desc => "running from local", :type => :boolean, default: false
97
+ method_option :email_azure, :aliases => "-u", :desc => "user azure (inclue @azure.bukalapak.io)", :default => ""
98
+ method_option :gitlab_project_id, :aliases => "-g", :desc => "The ID of the current project", :default => ""
99
+ method_option :merge_request_iid, :aliases => "-i", :desc => "The project-level IID (internal ID) of the merge request. This ID is unique for the current project.", :default => ""
100
+
101
+ def capture_mr_result
102
+ ENV['CHROMEDRIVER'] = options[:chromedriver_dir]
103
+ begin
104
+ Preprocessing.execute_capture_result(options[:project_name], options[:milestone_name])
105
+ Mergerequest.post_image_to_mr(options[:gitlab_project_id], options[:merge_request_iid], options[:milestone_name])
106
+ Preprocessing.delete_milestones_runs(options[:project_name], options[:milestone_name])
107
+ rescue => e
108
+ Log.error(e, options[:local])
109
+ exit 1
110
+ end
111
+ count_elapsed_time
112
+ end
113
+
114
+ desc 'regression_prep', 'Regression preparation: milestone, test plans and test runs creation'
115
+ method_option :app_version, :aliases => "-v", :desc => "Release Version Name", :default => ""
116
+ method_option :app_name, :aliases => "-p", :desc => "App Release Name", :default => ""
117
+
118
+ def regression_prep
119
+ begin
120
+ Regression.execute_regression_prep(options[:app_name], options[:app_version])
121
+ rescue => e
122
+ Log.error(e, options[:local])
123
+ exit 1
124
+ end
125
+ count_elapsed_time
126
+ end
127
+
128
+ desc 'cucumber_feature_download', 'Downloads .feature files cucumber'
129
+ method_option :project_name, :aliases => "-p", :desc => "Project Name", :default => ""
130
+ method_option :suite_name, :aliases => "-t", :desc => "Test Type/Suite Name", :default => ""
131
+ method_option :section_name, :aliases => "-s", :desc => "Section Name", :default => ""
132
+ method_option :filter_label, :aliases => "-l", :desc => "Custom Label Filtering", :default => ""
133
+ method_option :milestone_name, :aliases => "-r", :desc => "Release Version of Test", :default => ""
134
+
135
+ def cucumber_feature_download
136
+ begin
137
+ puts "Project: " + options[:project_name]
138
+ puts "Suite: " + options[:suite_name]
139
+ puts "Section: " + options[:section_name]
140
+ puts "Label: " + options[:filter_label]
141
+ puts "------------------------------"
142
+ if !options[:milestone_name].nil? && !options[:milestone_name].empty?
143
+ run_id = Cucumber.create_test_run_microservice(
144
+ options[:project_name],
145
+ options[:suite_name],
146
+ options[:section_name],
147
+ options[:filter_label],
148
+ options[:milestone_name]
149
+ )
150
+ Cucumber.feature_download(run_id)
151
+ else
152
+ Cucumber.micr_download_feature_only(
153
+ options[:project_name],
154
+ options[:suite_name],
155
+ options[:section_name],
156
+ options[:filter_label],
157
+ )
158
+ end
159
+ rescue => e
160
+ Log.error(e, options[:local])
161
+ exit 1
162
+ end
163
+ count_elapsed_time
164
+ end
165
+
166
+ desc 'generate_password', 'Encrypt or Decrypt of a string with key'
167
+ method_option :method, :aliases => "-m", :desc => "Method", :default => "encrypt"
168
+ method_option :string_password, :aliases => "-p", :desc => "Password", :default => ""
169
+ method_option :string_key, :aliases => "-k", :desc => "Key", :default => ""
170
+
171
+ def generate_password
172
+ begin
173
+ pass = GeneratePassword.execute_generate_password(
174
+ options[:method],
175
+ options[:string_password],
176
+ options[:string_key]
177
+ )
178
+ puts 'password: ' + pass.to_s
179
+ rescue => e
180
+ Log.error(e, options[:local])
181
+ exit 1
182
+ end
183
+ count_elapsed_time
184
+ end
185
+
186
+ desc 'app_cucumber_feature_download', 'Downloads .feature files cucumber'
187
+ method_option :app_name, :aliases => "-p", :desc => "App Release Name", :default => ""
188
+ method_option :test_type, :aliases => "-t", :desc => "Test Type", :default => ""
189
+ method_option :squad, :aliases => "-s", :desc => "Squad Name", :default => ""
190
+ method_option :filter_label, :aliases => "-l", :desc => "Filter Label", :default => ""
191
+ method_option :environment_name, :aliases => "-e", :desc => "Environment Name", :default => ""
192
+ method_option :custom_section, :aliases => "-c", :desc => "Custom Section Run Name", :default => ""
193
+ method_option :pipeline_id, :aliases => "-i", :desc => "Pipeline ID", :default => ""
194
+
195
+ def app_cucumber_feature_download
196
+ begin
197
+ if options[:test_type] == 'regression'
198
+ run_id = Regression.get_latest_automation_run(
199
+ options[:app_name],
200
+ options[:squad],
201
+ options[:environment_name],
202
+ options[:custom_section]
203
+ )
204
+ Cucumber.feature_download(run_id)
205
+ else
206
+ Cucumber.app_download_feature_only(
207
+ options[:app_name],
208
+ options[:squad],
209
+ options[:environment_name],
210
+ options[:test_type],
211
+ options[:filter_label],
212
+ options[:custom_section],
213
+ )
214
+ end
215
+ rescue => e
216
+ Log.error(e, options[:local])
217
+ exit 1
218
+ end
219
+ count_elapsed_time
220
+ end
221
+
222
+ desc 'delete_cases', 'Delete cases from specific section'
223
+ method_option :suite_id, :aliases => "-s", :desc => "suite id", :default => ""
224
+ method_option :group_name, :aliases => "-g", :desc => "group name", :default => ""
225
+ method_option :limit, :aliases => "-l", :desc => "limit for deleting in batch", :default => "10"
226
+
227
+ def delete_cases
228
+ begin
229
+ if options[:suite_id].eql?('') || options[:group_name].eql?('')
230
+ raise "No suite id or group name submitted. Please input mandatory parameter"
231
+ end
232
+
233
+ Preprocessing.delete_cases_from_section(options[:suite_id], options[:group_name], options[:limit].to_i)
234
+ rescue => e
235
+ Log.error(e, options[:local])
236
+ exit 1
237
+ end
238
+ count_elapsed_time
239
+ end
240
+
241
+ desc 'post_feature', 'Create or update test cases to Testrail'
242
+ method_option :project_name, :aliases => "-p", :desc => "project name", :default => ""
243
+ method_option :scenario_dir, :aliases => "-d", :desc => "directory of scenarios", :default => ""
244
+
245
+ def post_feature
246
+ begin
247
+ Preprocessing.upload_feature(options[:scenario_dir])
248
+ rescue => e
249
+ Log.error(e, options[:local])
250
+ exit 1
251
+ end
252
+ count_elapsed_time
253
+ end
254
+
255
+ desc 'close_test_run', 'Close test run after test'
256
+ method_option :run_id, :aliases => "-r", :desc => "run id", :default => ""
257
+
258
+ def close_test_run
259
+ client = Dataprep.client_tr
260
+ Testrun.close_test_run(client, options[:run_id])
261
+ end
262
+
263
+ desc 'completed_milestone', 'Completed milestone after test'
264
+ method_option :milestone_id, :aliases => "-m", :desc => "milestone id", :default => ""
265
+
266
+ def completed_milestone
267
+ client = Dataprep.client_tr
268
+ Milestone.completed_milestone(client, options[:milestone_id])
269
+ end
270
+
271
+ desc 'clean_testrail', 'Completes milestones that started a specified number of months before the current date'
272
+ method_option :type, :aliases => "-t", :desc => "clean types", :required => true
273
+ method_option :prev_months, :aliases => "-m", :desc => "previous month", :required => true
274
+
275
+ def clean_testrail
276
+ client = Dataprep.client_tr
277
+ prev_month_to_i = options[:prev_months].to_i
278
+ prev_x_month = Dataprep.get_timestamp_prev_month(prev_month_to_i)
279
+ if options[:type].empty?
280
+ puts 'Fill the clean of types like milestone/plan/run'
281
+ else
282
+ case "#{options[:type]}"
283
+ when 'milestone'
284
+ Milestone.completed_milestone_months_before(client, prev_x_month)
285
+ when 'plan'
286
+ Testplan.close_test_plan_months_before(client, prev_x_month)
287
+ when 'run'
288
+ Testrun.close_test_run_months_before(client, prev_x_month)
289
+ else
290
+ puts "There is no type option: #{options[:type]}"
291
+ end
292
+ end
293
+ end
294
+
295
+ desc 'create_ac_to_tc', 'Migrate AC from Jira to Testrail'
296
+ method_option :jira_key, :aliases => "-k", :desc => "issue key", :required => true
297
+
298
+ def create_ac_to_tc
299
+ begin
300
+ client = Dataprep.client_tr
301
+ squad, hash_projects = AcceptanceCriteria.generate_features(options[:jira_key])
302
+ puts "squad: #{squad}"
303
+ puts "hash_projects: #{hash_projects}"
304
+ case_ids = AcceptanceCriteria.upload_tc_from_feature(options[:jira_key], squad, hash_projects)
305
+ puts "List Case IDs: #{case_ids}"
306
+ # AcceptanceCriteria.embed_tc_to_testrun(case_ids)
307
+ rescue => e
308
+ Log.error(e, options[:local])
309
+ exit 1
310
+ end
311
+ count_elapsed_time
312
+ end
313
+
314
+ desc 'update_ac_to_tc', 'Update AC from Jira to Testrail'
315
+ method_option :jira_key, :aliases => "-k", :desc => "issue key", :required => true
316
+
317
+ def update_ac_to_tc
318
+ begin
319
+ client = Dataprep.client_tr
320
+ AcceptanceCriteria.generate_features(options[:jira_key])
321
+ rescue => e
322
+ Log.error(e, options[:local])
323
+ exit 1
324
+ end
325
+ count_elapsed_time
326
+ end
327
+
328
+ no_commands do
329
+ def count_elapsed_time
330
+ ending = Process.clock_gettime(Process::CLOCK_MONOTONIC)
331
+ elapsed = ending - @starting
332
+ puts "Running time : #{elapsed}(s)"
333
+ end
334
+ end
335
+ end
336
+ Tms::CLI.start(ARGV)
337
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require 'openssl'
5
+ require 'base64'
6
+
7
+ module Tms
8
+ module GeneratePassword
9
+ module_function
10
+
11
+ def execute_generate_password(method, password, key)
12
+ if method == nil
13
+ abort('put your method : encrypt or decrypt')
14
+ end
15
+
16
+ if password == nil
17
+ abort('put your password or encrypt string')
18
+ end
19
+
20
+ if key == nil
21
+ abort('put yout secret key')
22
+ end
23
+
24
+ if method.eql?'encrypt'
25
+ encrypt(password, key)
26
+ elsif method.eql?'decrypt'
27
+ decrypt(password, key)
28
+ else
29
+ abort('invalid method name : encrypt or decrypt')
30
+ end
31
+ end
32
+
33
+ def encrypt(str, key)
34
+ cipher = OpenSSL::Cipher.new('RC4')
35
+ cipher.decrypt
36
+ cipher.key = OpenSSL::Digest.digest('md5', key)
37
+ Base64.encode64(cipher.update(str) + cipher.final)
38
+ end
39
+
40
+ def decrypt(encrypted_string, key)
41
+ decipher = OpenSSL::Cipher.new('RC4')
42
+ decipher.decrypt
43
+ decipher.key = OpenSSL::Digest.digest('md5', key)
44
+ decipher.update(Base64.decode64(encrypted_string)) + decipher.final
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'webdrivers'
4
+ require 'openssl'
5
+ require 'base64'
6
+ require 'fileutils'
7
+ require_relative './generate-password'
8
+
9
+ module Tms
10
+ module GenerateReport
11
+ module_function
12
+
13
+ include GeneratePassword
14
+
15
+ def generate(project_id, milestone_name)
16
+ puts 'generate report...'
17
+ service = Selenium::WebDriver::Service.chrome(path: ENV['CHROMEDRIVER'])
18
+ options = Selenium::WebDriver::Chrome::Options.new
19
+ options.add_argument('--headless')
20
+ options.add_argument('--no-sandbox')
21
+ options.add_argument("--disable-extensions")
22
+ options.add_argument("--disable-gpu")
23
+ driver = Selenium::WebDriver.for :chrome, options: options, service: service
24
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
25
+ driver.get("#{ENV['TR_BASEURL']}index.php?/auth/login")
26
+ driver.manage.window.maximize
27
+ login(driver, wait)
28
+ traceablity_report(driver, wait, project_id, milestone_name)
29
+ coverage_report(driver, wait, project_id, milestone_name)
30
+ end
31
+
32
+ def capture_dashboard(project_id, milestone_name)
33
+ service = Selenium::WebDriver::Service.chrome(path: ENV['CHROMEDRIVER'])
34
+ options = Selenium::WebDriver::Chrome::Options.new
35
+ options.add_argument('--headless')
36
+ options.add_argument('--no-sandbox')
37
+ options.add_argument("--disable-extensions")
38
+ options.add_argument("--disable-gpu")
39
+ options.add_argument("--window-size=1500,960")
40
+ driver = Selenium::WebDriver.for :chrome, options: options, service: service
41
+ wait = Selenium::WebDriver::Wait.new(:timeout => 10)
42
+ driver.get("#{ENV['TR_BASEURL']}index.php?/auth/login")
43
+ driver.manage.window.maximize
44
+ login(driver, wait)
45
+ screenshot_dashboard(driver, wait, project_id, milestone_name)
46
+ end
47
+
48
+ def login(driver, wait)
49
+ driver.find_element(id: 'name').send_keys(ENV['TR_USERNAME'])
50
+ password = GeneratePassword.decrypt(ENV['TR_PASSWORD'], ENV['TR_SECRET'])
51
+ driver.find_element(id: 'password').send_keys(password)
52
+ driver.find_element(id: 'button_primary').click
53
+ wait.until { driver.find_element(id: 'navigation-dashboard')}
54
+ end
55
+
56
+ def traceablity_report(driver, wait, project_id, milestone_name)
57
+ driver.get("#{ENV['TR_BASEURL']}index.php?/reports/overview/#{project_id}")
58
+ driver.find_element(xpath: "//*[@href='index.php?/reports/add_job/#{project_id}&plugin=references_case_coverage']").click
59
+ wait.until { driver.find_element(class: 'report-box-title')}
60
+ driver.find_element(id: 'name').clear
61
+ driver.find_element(id: 'name').send_keys("Traceability Report - #{milestone_name}")
62
+ driver.find_element(id: 'access_shared').click
63
+ driver.find_element(id: 'submit').click
64
+ end
65
+
66
+ def coverage_report(driver, wait, project_id, milestone_name)
67
+ driver.get("#{ENV['TR_BASEURL']}index.php?/reports/overview/#{project_id}")
68
+ driver.find_element(xpath: "//*[@href='index.php?/reports/add_job/#{project_id}&plugin=milestones_summary']").click
69
+ wait.until { driver.find_element(class: 'report-box-title')}
70
+ driver.find_element(id: 'name').clear
71
+ driver.find_element(id: 'name').send_keys("Coverage Report - #{milestone_name}")
72
+ driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
73
+ driver.find_element(id: 'custom_milestones_id').click
74
+ driver.find_element(xpath: "//*[.='#{milestone_name}']").click
75
+ driver.find_element(id: 'access_shared').click
76
+ driver.find_element(id: 'submit').click
77
+ end
78
+
79
+ def screenshot_dashboard(driver, wait, project_id, milestone_name)
80
+ driver.get("#{ENV['TR_BASEURL']}index.php?/milestones/overview/#{project_id}")
81
+
82
+ driver.find_element(xpath: "//*[text()[contains(.,'#{milestone_name}')]]").click
83
+ image = driver.find_element(id: 'content-inner')
84
+ ss_path = File.expand_path("../" + milestone_name + '.png')
85
+ sleep 3
86
+ image.save_screenshot ss_path
87
+ puts "Dashboard test result captured!"
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ require 'gitlab'
3
+ require_relative '../../lib/preprocessing'
4
+
5
+ module Tms
6
+ module Mergerequest
7
+ module_function
8
+
9
+ def client
10
+ Gitlab::Client.new(endpoint: ENV['GITLAB_API_ENDPOINT'], private_token: ENV['GITLAB_RAGABOT_API_TOKEN'])
11
+ end
12
+
13
+ def post_image_to_mr(gitlab_project_id, merge_request_iid, milestone_name)
14
+ ss_path = File.expand_path("../" + milestone_name + '.png')
15
+ response = client.upload_file(gitlab_project_id, ss_path)
16
+
17
+ content_body = response['markdown']
18
+ comment_id = ragabot_comment_exists?(gitlab_project_id, merge_request_iid)
19
+
20
+ if comment_id
21
+ puts "Updating report to merge request notes..."
22
+ client.delete_merge_request_note(gitlab_project_id,merge_request_iid, comment_id)
23
+ client.create_merge_request_note(gitlab_project_id, merge_request_iid, content_body)
24
+ else
25
+ puts "Post report to merge request notes..."
26
+ client.create_merge_request_note(gitlab_project_id, merge_request_iid, content_body)
27
+ end
28
+ end
29
+
30
+ def ragabot_comment_exists?(project_id, merge_request_id)
31
+ comments = client.merge_request_comments(project_id, merge_request_id)
32
+ comment = comments.select { |comment| comment['author']['username'] == "Ragabot" }.first
33
+ return comment['id'] if comment
34
+ return nil
35
+ end
36
+
37
+ end
38
+ end