tms-cli 0.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
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