trail_marker 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6fa914ab38fc9f73fade971a9e1e17dc73e33ef783d5e3f9af270ba3286f3c55
4
+ data.tar.gz: 08400303f17caa576dd2b1407270d0b6f35e7ac732adfdbf63a8b6cb5b3dce99
5
+ SHA512:
6
+ metadata.gz: 1794d8f73ad47fd2b3e0bc018e543648e55fe2c0b8b7a15205d89430320cf4ca9903e3b6df1488c326885e05c2e593aa0062031e542b2d6eedb82edcca2aa110
7
+ data.tar.gz: 538c4eeaa7ea4a96bb14db0cb70a8abaf39634dd42d6dd58144e9ddbef0c47e7fbee426896eaf0dceb1bf0406041cc61179670ca2fdb7ab5d2a51dcecea51719
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Rspec to TestRail Gem
2
+
3
+ TestRail (http://www.gurock.com/testrail/) is one of the best test case management software available. It has available APIs which can be used to mark your automated test results. If you label your RSPEC tests with TestRail testcase numbers, then you can automatically mark the test results via API calls.
4
+
5
+ ![Instructions](/workflow.jpg)
6
+
7
+ This gem installs a command line tool that parses through all your RSPEC XML results file or Squish results file and marks all the test cases (Passed, Failed, ...) via API calls. This is a very useful tool to mark your test cases after running your automation tests using RSpec or Squish tests.
8
+
9
+ ## Installation
10
+
11
+ Install it yourself as:
12
+
13
+ $ gem install trail_marker
14
+
15
+ ##Usage
16
+
17
+ To Use:
18
+
19
+ $ testrail_marker.rb -p Test Project Name -r test_run_auto -x ../some/directory/results
20
+
21
+
22
+ Arguments required:
23
+
24
+ -p Name of Project
25
+
26
+ -r or -t, Name of test run or test plan to mark
27
+
28
+ -x Directory path where XML test results are located
29
+
30
+
31
+ For RSPEC files:
32
+ Tag all the tests with the correct test case
33
+
34
+ Ex:
35
+
36
+ it “should login to Server as a regular user (TestRail: C27)” do
37
+ => This would mark TestRail cases number 27
38
+
39
+ it “should logout of server (TestRail: C11, C12 )” do
40
+ => This would mark two test cases, number 11 and 12, at the same time
41
+
42
+ For SquishReport (Not sure how this is formatted - please edit):
43
+ Tag all verification name with the correct test case
44
+
45
+ Ex (results XML should be):
46
+
47
+ <verification line="114" type="" name=“Transfer (TestRail: C76, C92) " file="C:/ancd/aaa/suite_connections/tst_clone/test.rb">
48
+ <result type="PASS" time="2015-07-06T11:20:58-07:00">
49
+ <description>Comparison</description>
50
+ </result>
51
+ </verification>
52
+
53
+ NOTE: You can associate multiple Test Cases to a single automated test if needed by separating each test case number by a comma (TestRail: C111, C222, …)
54
+
55
+ <b>Other Options</b>
56
+
57
+ -h, Show HELP
58
+ -p *, name of project (e.g. Production Push) (required parameter)
59
+ -r or -t *, name of test run (-r) or test plan (-t) (required parameter)
60
+ -m, milestone name (can be used when creating a test run)
61
+ -s, test suite name (* required when creating a test run)
62
+ -u, user (e.g. ibarra@gmail.com)
63
+ -pw, password or token (recommended)
64
+ -url, URL of TestRail (e.g. https://test.mycompany.com/testrail)
65
+ -d, debug mode (set to false to suppresses most messages)
66
+ -x or -f *, path (-x, Directory) or specific file (-f) for results to parse
67
+ -com, comment to put on each test
68
+
69
+ '-cm', '-cr', '-ct' => Creates milestones, runs, or test plan
70
+ '-dm', '-dr', '-dt' => Deletes milestones, runs, test plan
71
+
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "testrail_marker"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,44 @@
1
+ ##################################################################################
2
+ # TestRail is a test case/suite management tool. It has available API in order for
3
+ # automated tests to mark cases as passed or failed.
4
+ # This tool can be used via command line or called inside your script.
5
+ #
6
+ # unix$ testrail_marker -h
7
+ #
8
+ #
9
+ # HISTORY: 4/11/2016 Created - ibarra.alfonso@gmail.com
10
+ # 2/19/2018 Packaged as executable ruby GEM
11
+ #
12
+ #
13
+ # TODO: Add option to overwrite config file
14
+ #
15
+ require 'testrail_marker'
16
+ #require_relative '../lib/trail_marker'
17
+
18
+ #require_relative 'argument'
19
+ #require_relative 'response'
20
+ #require_relative 'request'
21
+ #require_relative 'api_testrail'
22
+ #require_relative 'results_parser'
23
+
24
+ # Test Token = Epf.32h4wbdzBzZwoJZc-qOOoSfYHbWtVfaj2S5IN
25
+
26
+ ############################ MAIN ###############################
27
+
28
+ full_config_path = File.expand_path(File.dirname(__FILE__)) + '/' + 'trail_config.yml'
29
+ argument = Argument.new(ARGV)
30
+
31
+ if argument.has_argument?('-cf')
32
+ cf = ConfigFile.new(full_config_path)
33
+ cf.create_configfile
34
+ exit(0)
35
+ else
36
+ mark_tests = MarkTests.new(argument, full_config_path)
37
+ mark_tests.setup
38
+ mark_tests.check_create
39
+ mark_tests.markoff_all_results
40
+ mark_tests.show_exit_msg
41
+ end
42
+
43
+
44
+
@@ -0,0 +1,45 @@
1
+ ##################################################################################
2
+ # TestRail is a test case/suite management tool. It has available API in order for
3
+ # automated tests to mark cases as passed or failed.
4
+ # This tool can be used via command line or called inside your script.
5
+ #
6
+ # unix$ testrail_marker -h
7
+ #
8
+ #
9
+ # HISTORY: 4/11/2016 Created - ibarra.alfonso@gmail.com
10
+ # 2/19/2018 Packaged as executable ruby GEM
11
+ #
12
+ #
13
+ # TODO: Add option to overwrite config file
14
+ #
15
+ require 'trail_marker'
16
+ #require_relative '../lib/trail_marker'
17
+
18
+ #require_relative 'argument'
19
+ #require_relative 'response'
20
+ #require_relative 'request'
21
+ #require_relative 'api_testrail'
22
+ #require_relative 'results_parser'
23
+
24
+ # Test Token = Epf.32h4wbdzBzZwoJZc-qOOoSfYHbWtVfaj2S5IN
25
+
26
+ ############################ MAIN ###############################
27
+
28
+ full_config_path = File.expand_path(File.dirname(__FILE__)) + '/' + 'trail_config.yml'
29
+ argument = Argument.new(ARGV)
30
+
31
+ puts "ConfigFile: #{full_config_path}"
32
+ if argument.has_argument?('-cf')
33
+ cf = ConfigFile.new(full_config_path)
34
+ cf.create_configfile
35
+ exit(0)
36
+ else
37
+ mark_tests = MarkTests.new(argument, full_config_path)
38
+ mark_tests.setup
39
+ mark_tests.check_create
40
+ mark_tests.markoff_all_results
41
+ mark_tests.show_exit_msg
42
+ end
43
+
44
+
45
+
@@ -0,0 +1,364 @@
1
+ # TODO: CLEAN UP or DRY testruns and testplans methods since can be combined.
2
+ # Refactor attr_accessor variables to be class variables
3
+ # Implement other API calls
4
+ #
5
+ class ApiTestRail
6
+ attr_accessor :project_id, :suite_id, :run_id, :test_case_id, :section_id
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ @projects = get_projects()
11
+ @project = nil
12
+ @suites = nil
13
+ @suite = nil
14
+ @plans = nil
15
+ @plan = nil
16
+ @runs = nil
17
+ @run = nil
18
+ @test_cases = nil
19
+ @test_case = nil
20
+ @milestones = nil
21
+ @milestone = nil
22
+ @statuses = get_statuses()
23
+ end
24
+
25
+ # Returns the project ID of the project name passed.
26
+ #
27
+ def get_project_id(project_name)
28
+ if @projects.nil?
29
+ get_projects()
30
+ end
31
+ project_id = search_array_kv(@projects, 'name', project_name, 'id')
32
+ if project_id.nil?
33
+ puts "\nProject '#{project_name}' WAS NOT FOUND, select from available projects."
34
+ resp_projects = Response.new(@projects)
35
+ project_name = resp_projects.picker("name")
36
+ project_id = search_array_kv(@projects, 'name', project_name, 'id')
37
+ end
38
+ return project_id
39
+ end
40
+
41
+ def get_milestone_id(project_id, milestone_name)
42
+ ms_id = nil
43
+ if ! milestone_exists?(project_id, milestone_name)
44
+ puts "\nMilestone '#{milestone_name}' WAS NOT FOUND, select from available milestones."
45
+ resp_ms = Response.new(@milestones)
46
+ milestone_name = resp_ms.picker("name")
47
+ #ms_id = search_array_kv(@milestones, 'name', milestone_name, 'id')
48
+ end
49
+ ms_id = search_array_kv(@milestones, 'name', milestone_name, 'id')
50
+ return ms_id
51
+ end
52
+
53
+ def get_test_runplan_id(project_id, runplan_name)
54
+ if @runs.nil?
55
+ get_runs(project_id)
56
+ end
57
+ run_id = search_array_kv(@runs, 'name', runplan_name, 'id')
58
+ if run_id.nil?
59
+ puts "\nTest Run WAS NOT FOUND, select from available."
60
+ resp_runs = Response.new(@runs)
61
+ runplan_name = resp_runs.picker("name")
62
+ run_id = search_array_kv(@runs, 'name', runplan_name, 'id')
63
+ end
64
+ return run_id
65
+ end
66
+
67
+ def get_testplan_id(project_id, testplan_name)
68
+ if @plans.nil?
69
+ get_plans(project_id)
70
+ end
71
+ plan_id = search_array_kv(@plans, 'name', testplan_name, 'id')
72
+ if plan_id.nil?
73
+ puts "\nTestPlan #{testplan_name} WAS NOT FOUND, select from available."
74
+ resp_plans = Response.new(@plans)
75
+ plan_name = resp_plans.picker("name")
76
+ plan_id = search_array_kv(@plans, 'name', plan_name, 'id')
77
+ end
78
+ return plan_id
79
+ end
80
+
81
+ def get_suite_id(proj_id, suite_name)
82
+ suite_id = nil
83
+ if suite_exists?(proj_id, suite_name)
84
+ suite_id = search_array_kv(@suites, 'name', suite_name, 'id')
85
+ end
86
+ return suite_id
87
+ end
88
+
89
+ def get_projects()
90
+ @projects = request_get('get_projects')
91
+ return @projects
92
+ end
93
+
94
+ def get_milestones(proj_id)
95
+ ms_req = "get_milestones/" + proj_id.to_s
96
+ @milestones = request_get(ms_req)
97
+ end
98
+
99
+ def get_runs(proj_id)
100
+ runs_req = "get_runs/" + proj_id.to_s
101
+ @runs = request_get(runs_req)
102
+ end
103
+
104
+ def get_plans(proj_id)
105
+ plans_req = "get_plans/" + proj_id.to_s
106
+ @plans = request_get(plans_req)
107
+ end
108
+
109
+ def get_plan(plan_id)
110
+ plan_req = "get_plan/" + plan_id.to_s
111
+ @plan = request_get(plan_req)
112
+ end
113
+
114
+ def get_suites(proj_id)
115
+ suite_req = "get_suites/" + proj_id.to_s
116
+ @suites = request_get(suite_req)
117
+ end
118
+
119
+ ######################## VERIFY
120
+
121
+ def milestone_exists?(project_id, milestone_name)
122
+ it_exists = false
123
+ if @milestones.nil?
124
+ get_milestones(project_id)
125
+ end
126
+ puts "ALL MILES: #{@milestones}"
127
+ ms_id = search_array_kv(@milestones, 'name', milestone_name, 'id')
128
+ if ! ms_id.nil?
129
+ it_exists = true
130
+ end
131
+ return it_exists
132
+ end
133
+
134
+ def run_exists?(proj_id, run_name)
135
+ it_exists = false
136
+ if @runs.nil?
137
+ @runs = get_runs(proj_id)
138
+ end
139
+ run_id = search_array_kv(@runs, 'name', run_name, 'id')
140
+ if ! run_id.nil?
141
+ it_exists = true
142
+ end
143
+ return it_exists
144
+ end
145
+
146
+ def suite_exists?(proj_id, suite_name)
147
+ it_exists = false
148
+ if @suites.nil?
149
+ @suites = get_suites(proj_id)
150
+ end
151
+ suite_id = search_array_kv(@suites, 'name', suite_name, 'id')
152
+ if ! suite_id.nil?
153
+ it_exists = true
154
+ end
155
+ return it_exists
156
+ end
157
+
158
+ #############
159
+
160
+ # Makes an API call to get all possible results status. Currently has 5
161
+ # passed, blocked, untested, retest, failed.
162
+ # Puts the name and status in @statuses array.
163
+ #
164
+ def get_statuses()
165
+ @statuses = []
166
+ status_req = request_get('get_statuses')
167
+ status_req.each do |status|
168
+ status_hash ={}
169
+ status_hash['id'] = status['id']
170
+ status_hash['name'] = status['name']
171
+ @statuses.push(status_hash)
172
+ end
173
+ return @statuses
174
+ end
175
+
176
+
177
+
178
+ ######################## TEST PLANS #########################
179
+
180
+ # Returns an array of testrun IDs that is inside a testplan.
181
+ #
182
+ def get_testplan_testruns(testplan_id)
183
+ run_ids = []
184
+ plan_resp = get_plan(testplan_id)
185
+ tp_entries = plan_resp['entries']
186
+ tp_entries.each do |entry|
187
+ entry_runs = entry['runs']
188
+ entry_runs.each do |erun|
189
+ run_ids.push(erun['id'])
190
+ end
191
+ end
192
+ return run_ids
193
+ end
194
+
195
+ # Returns array of id for testruns inside a testplan
196
+ def get_testplan_run_ids(project_id, testplan_name)
197
+ testplan_id = get_testplan_id(project_id, testplan_name)
198
+ get_testplan_testruns(testplan_id)
199
+ end
200
+
201
+ # NOTE - NOT USED RIGHT NOW.
202
+ # Marks a test case inside a testplan. Testplans adds extra API calls
203
+ # because testruns are inside the testplans and are not named.
204
+ # See note below MARK_TESTPLAN
205
+ def markoff_testplan(case_id, testplan_id, pass_status)
206
+ status_id = search_array_kv(@statuses, 'name', 'failed', 'id')
207
+ defect_txt = ""
208
+ if pass_status
209
+ status_id = search_array_kv(@statuses, 'name', 'passed', 'id')
210
+ defect_txt = ""
211
+ end
212
+ equiv_json = {:status_id => status_id, :comment => 'Auto marker.', :defects => defect_txt}
213
+ add_result_req = "add_result_for_case/" + run_id.to_s + "/" + case_id.to_s
214
+ request_post(add_result_req, equiv_json)
215
+ end
216
+
217
+ def get_testid(run_id, case_id)
218
+ puts "SEARCH FOR TESTID: #{run_id} :: #{case_id}"
219
+ tests_req = 'get_tests/' + run_id.to_s
220
+ tests_resp = request_get(tests_req)
221
+ puts "GET_TESTS: #{tests_resp}"
222
+ id_equiv = search_array_kv(tests_resp, 'case_id', case_id.to_i, 'id')
223
+ return id_equiv
224
+ end
225
+
226
+
227
+
228
+ # TODO: Parse XML for failed reason and add to comment(?)
229
+ #
230
+ def markoff_test(case_id, run_id, pass_status, comment_txt)
231
+ status_id = search_array_kv(@statuses, 'name', 'failed', 'id')
232
+ defect_txt = ""
233
+ if pass_status
234
+ status_id = search_array_kv(@statuses, 'name', 'passed', 'id')
235
+ defect_txt = ""
236
+ end
237
+ equiv_json = {:status_id => status_id, :comment => comment_txt, :defects => defect_txt}
238
+ add_result_req = "add_result_for_case/" + run_id.to_s + "/" + case_id.to_s
239
+ request_post(add_result_req, equiv_json)
240
+ end
241
+
242
+ # Makes a post call to create a new milestone
243
+ def create_milestone(proj_name, msname)
244
+ proj_id = get_project_id(proj_name)
245
+ if ! milestone_exists?(proj_id, msname)
246
+ puts "Create Milestones #{msname} in Project #{proj_name} "
247
+ unix_timestamp = Time.now.to_i
248
+ req_field = {:name => msname, :due_on => unix_timestamp}
249
+ create_milestone_req = "add_milestone/" + proj_id.to_s
250
+ request_post(create_milestone_req, req_field)
251
+ sleep(2)
252
+ get_milestones(proj_id)
253
+ end
254
+ end
255
+
256
+ def delete_milestone(proj_name, msname)
257
+ proj_id = get_project_id(proj_name)
258
+ ms_id = get_milestone_id(proj_id, msname)
259
+ del_ms_req = "delete_milestone/" + ms_id.to_s
260
+ request_post(del_ms_req, nil)
261
+ exit
262
+ end
263
+
264
+ def create_testrun(proj_name, msname, trname, tsname)
265
+ proj_id = get_project_id(proj_name)
266
+ if ! run_exists?(proj_id, trname)
267
+ if suite_exists?(proj_id, tsname)
268
+ ms_id = nil
269
+ if ! msname.nil? && msname != ""
270
+ ms_id = get_milestone_id(proj_id, msname)
271
+ end
272
+ puts "MSID: #{msname} #{ms_id}"
273
+ ts_id = get_suite_id(proj_id, tsname)
274
+ req_field = {:name => trname, :suite_id => ts_id, :description => "AutoCreated"}
275
+ if ! ms_id.nil? && ms_id != ""
276
+ req_field[:milestone_id] = ms_id
277
+ end
278
+ add_run_req = "add_run/" + proj_id.to_s
279
+ request_post(add_run_req, req_field)
280
+ puts "CREATING RUN under #{proj_name} #{req_field}"
281
+ sleep(2)
282
+ get_runs(proj_id)
283
+ else
284
+ puts "CANNOT Create New TestRun, (-s) test suite name needed."
285
+ end
286
+ else
287
+ puts "CANNOT Create RUN #{trname}, already exists."
288
+ end
289
+ end
290
+
291
+ private
292
+
293
+ def request_get(api_cmd)
294
+ req = Request.new(@client)
295
+ resp = req.exec_get(api_cmd)
296
+ return resp
297
+ end
298
+
299
+ def request_post(api_cmd, data)
300
+ req = Request.new(@client)
301
+ resp = req.exec_post(api_cmd, data)
302
+ return resp
303
+ end
304
+
305
+ # Searched an array of hashes for a key and value to match
306
+ # and returns a field of that hash.
307
+ # * *Args* :
308
+ # - +rdata+ -> Array of hash data (e.g)
309
+ # - +k+ -> key (e.g. "name")
310
+ # - +v+ -> value to find (e.g. "Test Project")
311
+ # - +key_return+ -> name of another field to return (e.g. "id")
312
+ # * *Returns* :
313
+ # - Value of a field in the hash
314
+ # - nil if none found
315
+ #
316
+ # Example: rdata: [{'id' => 12, 'name' => 'Project-Files, 'owner' => 'Serban', 'run_name' => 'Sprint 2'},
317
+ # {'id' => 22, 'name' => 'Faspex, 'owner' => 'Ajanta', 'run_name' => 'Marathon 10'}]
318
+ #
319
+ # search_array_kv(rdata, "name", "Faspex", "owner")
320
+ # => Calling this find the hash that has 'Faspex' for name,
321
+ # then return the value of 'owner' in that hash 'Ajanta'
322
+ #
323
+ def search_array_kv(rdata, k, v, key_return)
324
+ retval = nil
325
+ fnd = rdata.detect {|unhash| unhash[k] == v}
326
+ if ! fnd.nil?
327
+ retval = fnd[key_return]
328
+ end
329
+ return retval
330
+ end
331
+
332
+
333
+ # NOTE: MARK_TEST_PLAN
334
+ # User Input: Project Name, TestRun Name
335
+ # Project Name > Get project_id
336
+ # Call API get_plans/project_id to get all test plans for the project
337
+ # Get testplan_id of testplan with the given name
338
+ # Call API get_plan/testplan_id to get testruns inside this testplan
339
+ #
340
+
341
+
342
+
343
+
344
+
345
+ ############### DELETE THESE NOT USED
346
+
347
+ # TODO: Parse XML for failed reason and add to comment(?)
348
+ #
349
+ # def markoff_test(case_id, run_id, pass_status)
350
+ # status_id = search_array_kv(@statuses, 'name', 'failed', 'id')
351
+ # defect_txt = ""
352
+ # if pass_status
353
+ # status_id = search_array_kv(@statuses, 'name', 'passed', 'id')
354
+ # defect_txt = ""
355
+ # end
356
+ # equiv_json = {:status_id => status_id, :comment => 'Auto marker.', :defects => defect_txt}
357
+ # add_result_req = "add_result_for_case/" + run_id.to_s + "/" + case_id.to_s
358
+ # request_post(add_result_req, equiv_json)
359
+ # end
360
+ #
361
+
362
+
363
+
364
+ end