testrailtagging 0.3.6.8

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.
@@ -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