testrailtagging 0.3.6.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,369 @@
1
+ require_relative "testrail_apiclient_retry"
2
+ require_relative "TestCase"
3
+
4
+ # =================================================================================
5
+ #
6
+ # API's for Test Rail
7
+ #
8
+ # =================================================================================
9
+
10
+ module TestRailOperations
11
+ def self.set_testrail_ids(pid, sid)
12
+ @@testrail_project_id = pid
13
+ @@testrail_suite_id = sid
14
+ end
15
+
16
+ def self.project_id
17
+ @@testrail_project_id
18
+ end
19
+
20
+ def self.suite_id
21
+ @@testrail_suite_id
22
+ end
23
+
24
+ # Splits a string by a command and returns an array.
25
+ def self.split_by_comma(device_string)
26
+ splits = device_string.split(",")
27
+ key = splits[0].chomp
28
+ val = splits[1].lstrip
29
+ [key, val]
30
+ end
31
+
32
+ # Gets the Test Rail client
33
+ # http://docs.gurock.com/testrail-api2/bindings-ruby
34
+ def self.get_test_rail_client
35
+ url = "https://canvas.testrail.com"
36
+ trclient = TestRail::APIClient.new(url)
37
+ trclient.user = ENV["TESTRAIL_USER"]
38
+ trclient.password = ENV["TESTRAIL_PASSWORD"]
39
+ trclient
40
+ end
41
+
42
+ # Gets the definition of device types that are assigned to our test rail cases.
43
+ # It looks like this:
44
+ # {1=>"Desktop", 2=>"Tablet", 3=>"Phone"}
45
+ def self.get_test_rail_screen_size_codes
46
+ trclient = get_test_rail_client
47
+ case_fields = trclient.send_get("get_case_fields")
48
+
49
+ results = {}
50
+ case_fields.each do |case_field|
51
+ if (case_field["name"] == "screen_size")
52
+ config_array = case_field["configs"] # The array usually has a size of 1, but sometimes 0
53
+ if config_array.size > 0
54
+ config = config_array[0]
55
+ # Some configs have items, like screen size
56
+ items = config["options"]["items"]
57
+ if items
58
+ devices = items.split("\n")
59
+ devices.each do |device|
60
+ key, value = split_by_comma(device)
61
+ results[key.to_i] = value
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ results
68
+ end
69
+
70
+ # Gets the definition of the priority codes that are assigned to our test rail cases.
71
+ # The priority codes on testrail do not match our nice 1,2,3 numbers. Their codes are
72
+ # different from ours. i.e.
73
+ #
74
+ # {1=>"3 - Low Priority", 3=>"2 - Test If Time", 4=>"1 - Must Test", 6=>"Smoke Test"}
75
+ #
76
+ # Therefore this function creates a more bridge friendly translation.
77
+ def self.get_test_rail_priority_codes
78
+ trclient = get_test_rail_client
79
+ # retreive priority information
80
+ # http://docs.gurock.com/testrail-api2/reference-priorities
81
+ priority_response = trclient.send_get("get_priorities")
82
+
83
+ results = {}
84
+ priority_response.each do |priority|
85
+ # find the numeric priority
86
+ name = priority["name"]
87
+ splits = name.split("-")
88
+ key = priority["id"].to_i
89
+ if splits.size == 2 && splits[0].to_i
90
+ val = { name: name, user_friendly_priority: splits[0].to_i }
91
+ results[key] = val
92
+ elsif name == "Smoke Test"
93
+ val = { name: "Smoke", user_friendly_priority: 0 }
94
+ results[key] = val
95
+ elsif name == "STUB"
96
+ val = { name: "Stub", user_friendly_priority: 7 }
97
+ results[key] = val
98
+ end
99
+ end
100
+ results
101
+ end
102
+
103
+ # Gets all the test cases for a particular test suite.
104
+ # The keys are the numeric(integer) test rail case ID's.
105
+ # The Values are the instance of TestCase.
106
+ # Each TestCase instance corresponds to a test case in test rail.
107
+ # return - A hash of TestCase instances
108
+ def self.get_test_rail_cases
109
+ trclient = get_test_rail_client
110
+ screen_sizes = get_test_rail_screen_size_codes
111
+ priorities = get_test_rail_priority_codes
112
+ test_cases = {}
113
+
114
+ # retrieve test cases
115
+ testcases_url = "get_cases/#{self.project_id}&suite_id=#{self.suite_id}"
116
+ response = trclient.send_get(testcases_url)
117
+ response.each do |test_case|
118
+ id = test_case["id"]
119
+ size = test_case["custom_screen_size"]
120
+ screen_size_description = screen_sizes[size]
121
+ priority = test_case["priority_id"]
122
+ priority_description = priorities[priority]
123
+ if priority_description
124
+ priority_code = priority_description[:user_friendly_priority]
125
+ automated = test_case["custom_automated"]
126
+ run_once = test_case["custom_run_once"]
127
+ automatable = test_case["custom_to_be_automated"]
128
+ references = test_case["refs"]
129
+ tc = TestCase.new(
130
+ id.to_s, test_case["title"], priority_code, automated,
131
+ screen_size_description, automatable, references, run_once
132
+ )
133
+ tc.file = test_case["custom_spec_location"]
134
+ test_cases[id] = tc
135
+ end
136
+ end
137
+
138
+ test_cases
139
+ end
140
+
141
+ # Updates a testcase that corresponds to the provided
142
+ # testrail_id. The testcase's reference field will be
143
+ # linked to the provided Jira ticket, given in the format
144
+ # of PROJECT-ID (ex. "BR-1000")
145
+ # param - testrail_id. The integer ID of the testcase
146
+ # param - reference. The string of the JIRA ticket(s)
147
+ def self.update_references(testrail_id, reference)
148
+ puts "id: #{testrail_id} => refs: #{reference}"
149
+ url = "update_case/#{testrail_id}"
150
+ data = { "refs" => reference }
151
+ TestRailOperations.get_test_rail_client.send_post_retry(url, data)
152
+ end
153
+
154
+ # Gets JSON data about the test runs on testrail for the given project and suite
155
+ def self.get_test_rail_runs
156
+ trclient = get_test_rail_client
157
+ request = "get_runs/#{self.project_id}"
158
+ trclient.send_get(request)
159
+ end
160
+
161
+ # Returns a list of test plans for a project.
162
+ # http://docs.gurock.com/testrail-api2/reference-plans#get_plans
163
+ def self.get_test_rail_plans
164
+ trclient = get_test_rail_client
165
+ request = "get_plans/#{self.project_id}"
166
+ trclient.send_get(request)
167
+ end
168
+
169
+ # Gets JSON data about an existing test plan
170
+ # http://docs.gurock.com/testrail-api2/reference-plans#get_plan
171
+ def self.get_test_rail_plan(plan_id)
172
+ trclient = get_test_rail_client
173
+ request = "get_plan/#{plan_id}"
174
+ trclient.send_get(request)
175
+ end
176
+
177
+ def self.create_test_plan(name, description = 'created by api', entries = [])
178
+ request = "add_plan/#{self.project_id}"
179
+ data = {
180
+ "name" => name,
181
+ "description" => description,
182
+ "entries"=> entries}
183
+ get_test_rail_client.send_post(request, data)
184
+ end
185
+
186
+ # new method to create plan entry with runs
187
+ def self.create_test_plan_entry_with_runs(plan_id, data)
188
+ request = "add_plan_entry/#{plan_id}"
189
+ get_test_rail_client.send_post(request, data)
190
+ end
191
+
192
+ # Adds one test run to a test plan
193
+ # Returns hash containing:
194
+ # 1. The test run ID of the test run.
195
+ # 2. The entry ID of the test run which is a large Guid like this:
196
+ # "id"=>"638fd46c-7c3e-4818-9c90-f411a2dec52a"
197
+ def self.create_test_plan_entry(plan_id, name, include_all_cases: true, case_ids: [])
198
+ if !include_all_cases && case_ids.count == 0
199
+ return "Error! Must create a test plan with at least one test case"
200
+ end
201
+
202
+ request = "add_plan_entry/#{plan_id}"
203
+ data = {
204
+ "suite_id" => self.suite_id,
205
+ "name" => name,
206
+ "include_all" => include_all_cases,
207
+ "case_ids" => case_ids
208
+ }
209
+
210
+ trclient = get_test_rail_client
211
+ response = trclient.send_post_retry(request, data)
212
+ { entry_id: response["id"], run_id: response["runs"][0]["id"] }
213
+ end
214
+
215
+ # Updates a test plan with the given entry_id and array of test case IDSs
216
+ def self.add_test_case_to_test_plan(plan_id, entry_id, case_ids)
217
+ request = "update_plan_entry/#{plan_id}/#{entry_id}"
218
+ data = {
219
+ "suite_id" => self.suite_id,
220
+ "case_ids" => case_ids
221
+ }
222
+
223
+ trclient = get_test_rail_client
224
+ trclient.send_post_retry(request, data)
225
+ end
226
+
227
+ def self.keep_only(plan_id, entry_id, case_ids)
228
+ request = "update_plan_entry/#{plan_id}/#{entry_id}"
229
+ data = {
230
+ "suite_id" => self.suite_id,
231
+ "include_all" => false,
232
+ "case_ids" => case_ids
233
+ }
234
+
235
+ trclient = get_test_rail_client
236
+ trclient.send_post_retry(request, data)
237
+ end
238
+
239
+ # Creates a test run on testrail
240
+ # param project_ID - The integer identifier of the project on test rail.
241
+ # param suite_id - The integer identifier of the test suite on test rail.
242
+ # param name - The string name to call the new test run
243
+ # param test_case_ids - The array of numerical integers of test cases to add to the test run
244
+ # returns - The number ID of the test run.
245
+ def self.create_test_run(project_id, suite_id, name, test_case_ids)
246
+ request = "add_run/#{project_id}"
247
+ data = {
248
+ "suite_id" => suite_id,
249
+ "name" => name,
250
+ "include_all" => false,
251
+ "case_ids" => test_case_ids
252
+ }
253
+
254
+ trclient = get_test_rail_client
255
+ response = trclient.send_post_retry(request, data)
256
+ response["id"]
257
+ end
258
+
259
+ def self.add_testcase_to_test_run(test_run_id, case_ids)
260
+ request = "update_run/#{test_run_id}"
261
+ data = { "case_ids" => case_ids }
262
+ trclient = get_test_rail_client
263
+ trclient.send_post_retry(request, data)
264
+ end
265
+
266
+ PASSED = 1
267
+ BLOCKED = 2
268
+ UNTESTED = 3
269
+ RETEST = 4
270
+ FAILED = 5
271
+ PENDING = 6
272
+ @rspec_to_testrail_status_map = {
273
+ passed: PASSED, blocked: BLOCKED, untested: UNTESTED, retest: RETEST, failed: FAILED, pending: PENDING
274
+ }
275
+ # Converts an rspec test result (a symbol) to an integer that TestRail understands.
276
+ def self.status_rspec_to_testrail(result_symbol)
277
+ @rspec_to_testrail_status_map[result_symbol]
278
+ end
279
+
280
+ # Converts the a TestRail integer result status into a symbol (that rspec uses) that is human readable
281
+ def self.status_testrail_to_rspec(int_id)
282
+ @rspec_to_testrail_status_map.key(int_id)
283
+ end
284
+
285
+ # Sends test result data back to testrail to update cases in a test run
286
+ # param run_id - integer value designating the test run to update
287
+ # param data - A hash containing an array of hashes with test results
288
+ def self.post_run_results(run_id, data)
289
+ trclient = get_test_rail_client
290
+ uri = "add_results/#{run_id}"
291
+ trclient.send_post_retry(uri, "results" => data)
292
+ end
293
+
294
+ # When a test run is created, the test cases have new, sort of temporary ID's.
295
+ # These are completely different from the permanent static ID's of the test cases.
296
+ # Given a test run ID, this gets the test cases that are assigned to that test run.
297
+ # It returns a hash where the key is the integer permanent ID, and the value is a TestCase instance.
298
+ def self.get_test_run_cases(run_id)
299
+ result = {}
300
+ trclient = get_test_rail_client
301
+ response = trclient.send_get("get_tests/#{run_id}")
302
+ response.each do |r|
303
+ # Each response hash for a test case in a run looks like this:
304
+ #
305
+ # {"id"=>481664, "case_id"=>152222, "status_id"=>5, "assignedto_id"=>49, "run_id"=>2641,
306
+ # "title"=>"The my Learning page has all my courses listed. Overdue, Next Up, Optional,
307
+ # Completed", "type_id"=>2, "priority_id"=>3, "estimate"=>nil, "estimate_forecast"=>nil,
308
+ # "refs"=>nil, "milestone_id"=>nil, "custom_sprint_date"=>nil, "custom_commit_url"=>nil,
309
+ # "custom_reviewed"=>false, "custom_automated"=>true,
310
+ # "custom_spec_location"=>"regression_spec/learner_management/mylearning_spec.rb",
311
+ # "custom_test_order"=>nil, "custom_screen_size"=>3, "custom_preconds"=>nil,
312
+ # "custom_steps_separated"=>nil, "custom_browser_skip"=>[]}
313
+ #
314
+
315
+ permanent_id = r["case_id"].to_i
316
+ tc = TestCase.new(
317
+ permanent_id, r["title"], r["priority_id"].to_i,
318
+ r["custom_automated"], r["custom_screen_size"].to_i,
319
+ r["custom_to_be_automated"], r["refs"], r["custom_run_once"]
320
+ )
321
+ tc.temp_id = r["id"].to_i
322
+ tc.assigned_to = r["assignedto_id"].to_i
323
+ tc.set_status(status_testrail_to_rspec(r["status_id"].to_i), nil)
324
+
325
+ value = tc
326
+ key = permanent_id
327
+ result[key] = value
328
+ end
329
+ result
330
+ end
331
+
332
+ # Gets the string name of the test run, given the test run id as an integer
333
+ # if the test id is not found, it returns an empty string
334
+ def self.get_test_run_name(run_id)
335
+ runs = get_test_rail_runs(self.project_id)
336
+ runs.each do |run|
337
+ if run_id == run["id"].to_i
338
+ return run["name"]
339
+ end
340
+ end
341
+ ""
342
+ end
343
+
344
+ def self.get_test_rail_users
345
+ # Returns an array of user hashes. Like this:
346
+ # [
347
+ # {
348
+ # "email": "alexis@example.com",
349
+ # "id": 1,
350
+ # "is_active": true,
351
+ # "name": "Alexis Gonzalez"
352
+ # },
353
+ # ....
354
+ # ]
355
+ get_test_rail_client.send_get("get_users")
356
+ end
357
+
358
+ # Given an email address, gets the user json data
359
+ def self.get_test_rail_user_by_email(email)
360
+ # The response looks like this:
361
+ # {
362
+ # "email": "alexis@example.com",
363
+ # "id": 1,
364
+ # "is_active": true,
365
+ # "name": "Alexis Gonzalez"
366
+ # }
367
+ get_test_rail_client.send_get("get_user_by_email&email=#{email}")
368
+ end
369
+ end
@@ -0,0 +1,108 @@
1
+ require_relative "testrail_operations"
2
+
3
+ # =================================================================================
4
+ #
5
+ # Test case printing and inspections
6
+ #
7
+ # =================================================================================
8
+
9
+ module TestRailQueries
10
+ # Prints to the console, the test cases sorted by priority (ascending).
11
+ def self.print_priority_sorted_test_cases
12
+ test_cases = TestRailOperations.get_test_rail_cases
13
+ sorted_cases = test_cases.values.sort_by do |tc|
14
+ tc.priority
15
+ end
16
+
17
+ automated_count = 0
18
+ sorted_cases.each do |tc|
19
+ tc.print
20
+ automated_count += 1 if tc.automated
21
+ end
22
+
23
+ puts "Number Test Cases: #{test_cases.size}"
24
+ puts "Number Test Cases Automated: #{automated_count}"
25
+ percentage = (automated_count / test_cases.size.to_f) * 100.0
26
+ puts "Percentage Automated #{percentage.round(1)}%"
27
+ end
28
+
29
+ # Prints to the console, the test cases that work on phone devices. (Sorted by test ID)
30
+ def self.print_phone_test_cases
31
+ test_cases = TestRailOperations.get_test_rail_cases
32
+
33
+ phones = []
34
+ test_cases.values.each do |tc|
35
+ phones << tc if tc.screen_size == "Phone"
36
+ end
37
+
38
+ sorted_ids = phones.each do |tc|
39
+ tc.id
40
+ end
41
+
42
+ sorted_ids.each do |tc|
43
+ tc.print
44
+ end
45
+
46
+ puts "Number Test Cases: #{test_cases.size}"
47
+ puts "Number Test Cases Phone: #{phones.size}"
48
+ percentage = (phones.size / test_cases.size.to_f) * 100.0
49
+ puts "Percentage Phone #{percentage.round(1)}%"
50
+ end
51
+
52
+ # Prints to the console, all the test case ID's and the minimum screen size they work on
53
+ def self.print_test_case_devices
54
+ test_cases = TestRailOperations.get_test_rail_cases
55
+
56
+ test_cases.each do |key, value|
57
+ puts "ID: #{key}, #{value.screen_size}"
58
+ end
59
+ end
60
+
61
+ # Prints to the console, all the test runs
62
+ def self.print_all_test_runs
63
+ test_runs = TestRailOperations.get_test_rail_runs
64
+ count_runs = 0
65
+ count_open = 0
66
+ count_close = 0
67
+ test_runs.each do |test_run|
68
+ puts "Run: #{test_run["name"]}, id: #{test_run["id"]} complete: #{test_run["is_completed"]} "
69
+ if test_run["is_completed"]
70
+ count_close += 1
71
+ else
72
+ count_open += 1
73
+ end
74
+
75
+ count_runs += 1
76
+ end
77
+ puts "========================================"
78
+ puts "Total Test Runs: #{count_runs}"
79
+ puts "Total Open: #{count_open}"
80
+ puts "Total Closed: #{count_close}"
81
+ end
82
+
83
+ # Prints to the console all the test plans in bridge
84
+ def self.print_all_test_plans
85
+ test_plans = TestRailOperations.get_test_rail_plans
86
+ count_plans = 0
87
+ test_plans.each do |plan|
88
+ id = plan["id"]
89
+ puts "Plan: ID: #{id}, #{plan["name"]}"
90
+ count_plans += 1
91
+ pjson = TestRailOperations.get_test_rail_plan(id)
92
+ puts " passed: #{pjson["passed_count"]}, failed: #{pjson["failed_count"]}, retest: #{pjson["retest_count"]}, blocked: #{pjson["blocked_count"]}"
93
+ puts " entries count: #{pjson["entries"].count}"
94
+ pjson["entries"].each do |entry|
95
+ puts " entry: #{entry["id"]} - #{entry["name"]}"
96
+ end
97
+ end
98
+ puts "========================================"
99
+ puts "Total Test Plans: #{count_plans}"
100
+ end
101
+
102
+ def self.print_all_users
103
+ users = TestRailOperations.get_test_rail_users
104
+ users.each do |user|
105
+ puts user
106
+ end
107
+ end
108
+ end