test_linker 0.1.0

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/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.*
3
+ LICENSE.rdoc
data/.gemtest ADDED
File without changes
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.yardopts ADDED
@@ -0,0 +1,4 @@
1
+ --markup rdoc
2
+ --title "test_linker Documentation"
3
+ --protected
4
+ --private
data/ChangeLog.rdoc ADDED
@@ -0,0 +1,8 @@
1
+ === 0.1.0 / 2011-03-24
2
+
3
+ * Initial release:
4
+ * Basic wrapper around existing XMLRPC functions.
5
+ * Allow for calling methods via Ruby style (#projects) or XMLRPC style (#getProjects)
6
+ * Support for TestLink API versions 1.0 Beta 5 and 1.0
7
+ * Only one error/exception type: TestLinkClient::Error
8
+ * Limited set of helper methods, attempting to fill in gaps from the API
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+ gem 'versionomy', '~> 0.4.0'
5
+
6
+ group :development do
7
+ gem 'cucumber', '~> 0.10.0'
8
+ gem 'rake', '~> 0.8.7'
9
+ gem 'ore', '~> 0.7.2'
10
+ gem 'ore-core', '~> 0.1.4'
11
+ gem 'ore-tasks', '~> 0.5.0'
12
+ gem 'rspec', '~> 2.5'
13
+ gem 'simplecov', '>= 0.4.0', :require => false
14
+ gem 'jeweler', '~> 1.5.0'
15
+ gem 'yard', '~> 0.6.0'
16
+ end
data/LICENSE.rdoc ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 sloveless
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,128 @@
1
+ = test_linker
2
+
3
+ * {Homepage}[http://rubygems.org/gems/test_linker]
4
+ * {Documentation}[http://rubydoc.info/gems/test_linker/frames]
5
+ * {TestLink API Documentation}[http://testlink.org/api/phpdoc_generated/TestlinkAPI/TestlinkXMLRPCServer.html]
6
+
7
+ == Description
8
+
9
+ This is a Ruby wrapper around the TestLink XMLRPC API, thus allowing access to
10
+ your TestLink test projects, plans, cases, and results using Ruby. We've added
11
+ a few helper methods as well to allow for getting at more of your data a little
12
+ easier. This supports TestLink APIs 1.0 Beta 5 (from TestLink 1.8.x) and 1.0
13
+ (from TestLink 1.9.x).
14
+
15
+ == Features
16
+
17
+ * Basic wrapper around existing XMLRPC functions.
18
+ * Allow for calling methods via Ruby style (#projects) or XMLRPC style (#getProjects)
19
+ * Support for TestLink API versions 1.0 Beta 5 and 1.0
20
+ * Only one error/exception type: TestLinker::Error
21
+ * Limited set of helper methods, attempting to fill in gaps from the API
22
+
23
+ == Examples
24
+
25
+ require 'test_linker'
26
+
27
+ server = 'http://testlink.pelco.org'
28
+ dev_key = "90b7941411928ae0a84d19f365a01a63"
29
+ tl_project = "!SSW Auto-Smoke Testing"
30
+
31
+ csv_file_name = "mtrx_report.csv"
32
+ csv_file = File.new(csv_file_name, "w")
33
+ csv_file.write "Build,Passed,Failed,Blocked,Skipped,TOTAL,Overall %,Overall % (+B)\n"
34
+
35
+ tl = TestLinker.new(server, dev_key)
36
+
37
+ project_id = tl.test_project_id tl_project
38
+ test_plans = tl.find_test_plans(project_id, /NSM5200.+ISC West/)
39
+ puts "All test plans for project #{project_id}"
40
+ puts test_plans
41
+
42
+ builds = test_plans.collect do |test_plan|
43
+ tl.builds_for_test_plan(test_plan["id"])
44
+ end
45
+ builds.flatten!
46
+
47
+ overall = {}
48
+ overall[:pass] = 0
49
+ overall[:failed] = 0
50
+ overall[:blocked] = 0
51
+ overall[:pass_rates] =
52
+ results = {}
53
+
54
+ builds.each do |build|
55
+ results[:pass] = 0
56
+ results[:failed] = 0
57
+ results[:blocked] = 0
58
+ results[:skipped] = 0
59
+
60
+ test_cases = tl.test_cases_for_test_plan(build["testplan_id"],
61
+ { "buildid" => build["id"] })
62
+
63
+ test_cases.each_value do |test_case|
64
+ case test_case["exec_status"]
65
+ when "p"
66
+ results[:pass] += 1
67
+ when "f"
68
+ results[:failed] += 1
69
+ when "b"
70
+ results[:blocked] += 1
71
+ when "s"
72
+ results[:skipped] += 1
73
+ end
74
+ end
75
+
76
+ overall[:pass] += results[:pass]
77
+ overall[:failed] += results[:failed]
78
+ overall[:blocked] += results[:blocked]
79
+ build_total = results[:pass] + results[:failed] + results[:blocked] +
80
+ results[:skipped]
81
+ overall_rate = "%2.2f" % (overall[:pass] * 100 / (overall[:pass] +
82
+ overall[:failed]).to_f)
83
+ overall[:pass_rates] << overall_rate.to_f
84
+ overall_rate_plus_blocked = "%2.2f" % (overall[:pass] * 100 / (overall[:pass] +
85
+ overall[:failed] + overall[:blocked]).to_f)
86
+
87
+ result_array = [
88
+ ['Passed', 'Failed', 'Blocked', 'Skipped', 'TOTAL', 'Overall %', 'Overall % (+B)'],
89
+ [results[:pass], results[:failed], results[:blocked], results[:skipped],
90
+ build_total, overall_rate, overall_rate_plus_blocked]
91
+ ]
92
+
93
+ csv_line = "#{build["name"]},#{results[:pass]},#{results[:failed]},#{results[:blocked]},"
94
+ csv_line << "#{results[:skipped]},#{build_total},#{overall_rate},#{overall_rate_plus_blocked}\n"
95
+ csv_file.write csv_line
96
+ end
97
+
98
+ == Requirements
99
+
100
+ * Rubies (tested)
101
+ * 1.9.2
102
+ * Gems
103
+ * versionomy, ~> 0.4.0
104
+ * Gems (development)
105
+ * bundler, ~> 1.0.0
106
+ * cucumber, ~> 0.10.0
107
+ * jeweler, ~> 1.5.0
108
+ * ore, ~> 0.7.2
109
+ * ore-core, ~> 0.1.4
110
+ * rspec, ~> 2.5.0
111
+ * yard, ~> 0.6.0
112
+
113
+ Getting it all running (on the TestLink side):
114
+ 1. Enable automation in the TestLink config file:
115
+ config.inc.php => $tlCfg->api->enabled = TRUE;
116
+ 2. The user that needs to run the automated tests needs to generate a API key
117
+ that will be used in creating the connection. This is accomplished by logging
118
+ in to TestLink and going to "Personal -> API Key -> Generate a new key".
119
+
120
+ == Install
121
+
122
+ $ gem install test_linker
123
+
124
+ == Copyright
125
+
126
+ Copyright (c) 2011 sloveless
127
+
128
+ See LICENSE.rdoc for details.
data/Rakefile ADDED
@@ -0,0 +1,48 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ gem 'ore-tasks', '~> 0.4'
5
+ require 'ore/tasks'
6
+
7
+ Ore::Tasks.new
8
+ rescue LoadError => e
9
+ STDERR.puts e.message
10
+ STDERR.puts "Run `gem install ore-tasks` to install 'ore/tasks'."
11
+ end
12
+ begin
13
+ require 'bundler'
14
+ rescue LoadError => e
15
+ STDERR.puts e.message
16
+ STDERR.puts "Run `gem install bundler` to install Bundler."
17
+ exit e.status_code
18
+ end
19
+
20
+ begin
21
+ Bundler.setup(:development)
22
+ rescue Bundler::BundlerError => e
23
+ STDERR.puts e.message
24
+ STDERR.puts "Run `bundle install` to install missing gems."
25
+ exit e.status_code
26
+ end
27
+
28
+ begin
29
+ gem 'rspec', '~> 2.5'
30
+ require 'rspec/core/rake_task'
31
+
32
+ RSpec::Core::RakeTask.new
33
+ task :test => :spec
34
+ task :default => :spec
35
+ rescue LoadError => e
36
+ task :spec do
37
+ abort "Please run `gem install rspec` to install RSpec."
38
+ end
39
+ end
40
+
41
+ require 'ore/specification'
42
+ require 'jeweler'
43
+ Jeweler::Tasks.new(Ore::Specification.new)
44
+
45
+ require 'yard'
46
+ YARD::Rake::YardocTask.new
47
+ task :doc => :yard
48
+
@@ -0,0 +1,63 @@
1
+ Feature: Get info from TestLink
2
+ As a TestLink API user
3
+ I want to get info from the TestLink server
4
+ So that I can use the info in reports and such
5
+
6
+ Scenario Outline: Get a list of projects
7
+ Given I have a TestLink server with API version <version>
8
+ When I ask for the list of projects
9
+ Then I get a list of projects
10
+
11
+ Scenarios: Known API versions
12
+ | version |
13
+ | 1.0 Beta 5 |
14
+ | 1.0 |
15
+
16
+ Scenario Outline: Get a list of test plans
17
+ Given I have a TestLink server with API version <version>
18
+ When I ask for the list of projects
19
+ And I ask for the list of test plans
20
+ Then I get a list of test plans
21
+
22
+ Scenarios: Known API versions
23
+ | version |
24
+ | 1.0 Beta 5 |
25
+ | 1.0 |
26
+
27
+ Scenario Outline: Get a list of test cases in a test plan
28
+ Given I have a TestLink server with API version <version>
29
+ And I have the list of projects
30
+ And I know the name of a project
31
+ And I have a list of test plans
32
+ When I ask for the list of test cases in that test plan
33
+ Then I get a list of test cases in that test plan
34
+
35
+ Scenarios: Known API versions
36
+ | version |
37
+ | 1.0 Beta 5 |
38
+ | 1.0 |
39
+
40
+ Scenario: Get a test project by its name
41
+ Given I have a TestLink server with API version 1.0
42
+ And I know the name of a project
43
+ When I ask for that project by name
44
+ Then I get that project
45
+
46
+ Scenario: Get a test plan by its name
47
+ Given I have a TestLink server with API version 1.0
48
+ And I have the list of projects
49
+ And I know the name of a project
50
+ And I have a list of test plans
51
+ And I know the name of a test plan in that project
52
+ When I ask for that test plan by name
53
+ Then I get that test plan
54
+
55
+ Scenario: Get a test case by its ID
56
+ Given I have a TestLink server with API version 1.0
57
+ And I have the list of projects
58
+ And I know the name of a project
59
+ And I have a list of test plans
60
+ And I know the ID of a test case in that project
61
+ When I ask for that test case by ID
62
+ Then I get that test case
63
+
@@ -0,0 +1,78 @@
1
+ Given /^I know the name of a project$/ do
2
+ @test_project_name = @server.projects.last["name"]
3
+ @test_project_name.should_not be_nil
4
+ end
5
+
6
+ Given /^I know the name of a test plan in that project$/ do
7
+ @original_test_plan_name = @test_plans.last["name"]
8
+ @original_test_plan_name.should_not be_nil
9
+ end
10
+
11
+ Given /^I have the list of projects$/ do
12
+ #When "I ask for the list of projects"
13
+ @project_list = @server.projects
14
+ end
15
+
16
+ Given /^I have a list of test plans$/ do
17
+ #When "I ask for the list of test plans"
18
+ @test_plans = @server.project_test_plans(@project_list.last["id"])
19
+ end
20
+
21
+ When /^I ask for the list of projects$/ do
22
+ @project_list = @server.projects
23
+ end
24
+
25
+ When /^I ask for the list of test plans$/ do
26
+ @test_plans = @server.project_test_plans(@project_list.last["id"])
27
+ end
28
+
29
+ When /^I ask for that project by name$/ do
30
+ @requested_test_project_name = @server.test_project_by_name(@test_project_name)
31
+ end
32
+
33
+ When /^I ask for that test plan by name$/ do
34
+ @requested_test_plan_name = @server.test_plan_by_name(@original_test_plan_name,
35
+ @project_list.last["name"])
36
+ end
37
+
38
+ Then /^I get a list of projects$/ do
39
+ @project_list.is_a?(Array).should be_true
40
+ @project_list.last.is_a?(Hash).should be_true
41
+ end
42
+
43
+ Then /^I get a list of test plans$/ do
44
+ @test_plans.class.should == Array
45
+ @test_plans.last.class.should == Hash
46
+ end
47
+
48
+ Then /^I get that project$/ do
49
+ @requested_test_project_name.last["name"].should == @test_project_name
50
+ end
51
+
52
+ Then /^I get that test plan$/ do
53
+ @requested_test_plan_name.first["name"].should == @original_test_plan_name
54
+ end
55
+
56
+ Given /^I know the ID of a test case in that project$/ do
57
+ pending
58
+ @test_cases = @server.test_cases_for_test_plan(@test_plans.last["id"])
59
+ end
60
+
61
+ When /^I ask for that test case by ID$/ do
62
+ pending # express the regexp above with the code you wish you had
63
+ end
64
+
65
+ Then /^I get that test case$/ do
66
+ pending # express the regexp above with the code you wish you had
67
+ end
68
+
69
+ When /^I ask for the list of test cases in that test plan$/ do
70
+ @test_cases = @server.test_cases_for_test_plan(
71
+ @test_plans.last.values.last["id"])
72
+ end
73
+
74
+ Then /^I get a list of test cases in that test plan$/ do
75
+ @test_cases.should_not be_nil
76
+ @test_cases.class.should == Hash
77
+ @test_cases.each_value {|v| v["name"].class.should == String }
78
+ end
@@ -0,0 +1,13 @@
1
+ Given /^I have a TestLink server with API version (.+)$/ do |api_version|
2
+ if api_version == "1.0"
3
+ url = "http://ubuntu-desktop/testlink/"
4
+ dev_key = "b8c144a536f8233d24b04b8268bfac34"
5
+ else
6
+ url = "http://testlink/"
7
+ dev_key = "90b7941411928ae0a84d19f365a01a63"
8
+ end
9
+
10
+ @server = TestLinker.new(url, dev_key)
11
+ @server.api_version.should == api_version
12
+ @server.about.should match /#{api_version} /
13
+ end
@@ -0,0 +1,5 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_group "Library", "lib/"
4
+ end
5
+ require_relative '../../lib/test_linker'
data/gemspec.yml ADDED
@@ -0,0 +1,25 @@
1
+ name: test_linker
2
+ summary: "An interface to the TestLink XMLRPC API"
3
+ description:
4
+ This is a Ruby wrapper around the TestLink XMLRPC API, thus allowing access to
5
+ your TestLink test projects, plans, cases, and results using Ruby. We've added
6
+ a few helper methods as well to allow for getting at more of your data a little
7
+ easier. This supports TestLink APIs 1.0 Beta 5 (from TestLink 1.8.x) and 1.0
8
+ (from TestLink 1.9.x).
9
+ license: MIT
10
+ authors: Steve Loveless, Randy Stoller, Sujin Philip, Vikram Raina
11
+ email: steve.loveless@gmail.com
12
+ homepage: http://rubygems.org/gems/test_linker
13
+ has_yard: true
14
+ dependencies:
15
+ versionomy: ~> 0.4.0
16
+
17
+ development_dependencies:
18
+ bundler: ~> 1.0.0
19
+ cucumber: ~> 0.10.0
20
+ jeweler: ~> 1.5.0
21
+ ore: ~> 0.7.2
22
+ ore-core: ~> 0.1.4
23
+ rspec: ~> 2.5
24
+ simplecov: >= 0.4.0
25
+ yard: ~> 0.6.0
@@ -0,0 +1,130 @@
1
+ require_relative 'test_linker/wrapper'
2
+ require_relative 'test_linker/version'
3
+ require_relative 'test_linker/error'
4
+ require_relative 'test_linker/helpers'
5
+ require 'xmlrpc/client'
6
+ require 'logger'
7
+ require 'versionomy'
8
+
9
+ class TestLinker
10
+ include TestLinker::Wrapper
11
+ include TestLinker::Helpers
12
+
13
+ class << self
14
+
15
+ # @return [Boolean] Returns if logging is enabled or not.
16
+ def log?
17
+ @log ||= false
18
+ end
19
+
20
+ # @param [Boolean] do_logging false to turn logging off; true to turn it
21
+ # back on.
22
+ def log=(do_logging)
23
+ @log = do_logging
24
+ end
25
+
26
+ # @return [Logger,?] Returns a Logger unless you use a different type of
27
+ # logging object.
28
+ def logger
29
+ @logger ||= Logger.new STDOUT
30
+ end
31
+
32
+ # @param [?] logging_object Call this to use a different type of logger
33
+ # than Logger.
34
+ def logger=(logging_object)
35
+ @logger = logging_object
36
+ end
37
+
38
+ # @return [Symbol] The method name to send to the logging object in order to
39
+ # log messages.
40
+ def log_level
41
+ @log_level ||= :debug
42
+ end
43
+
44
+ # @param [Symbol] The method name to send to the logging object in order to
45
+ # log messages.
46
+ def log_level=(level)
47
+ @log_level = level
48
+ end
49
+
50
+ # @param [String] message The string to log.
51
+ def log message
52
+ logger.send(log_level, message) if log?
53
+ end
54
+ end
55
+
56
+ # Default value for timing out after not receiving an XMLRPC response from
57
+ # the server.
58
+ DEFAULT_TIMEOUT = 30
59
+
60
+ # Path the the XMLRPC interface (via the xmlrpc.php file) on the server.
61
+ DEFAULT_API_PATH = "/lib/api/xmlrpc.php"
62
+
63
+ # @param [String] server_url URL to access TestLink API
64
+ # @param [String] dev_key User key to access TestLink API
65
+ # @param [Hash] options
66
+ # @option options [String] api_path Alternate path to the xmlrpc.php file on
67
+ # the server.
68
+ # @option options [Fixnum] timeout Seconds to timeout after not receiving a
69
+ # response from the server.
70
+ # @option options [String] version Force a different API version.
71
+ def initialize(server_url, dev_key, options={})
72
+ api_path = options[:api_path] || DEFAULT_API_PATH
73
+ timeout = options[:timeout] || DEFAULT_TIMEOUT
74
+ @dev_key = dev_key
75
+ server_url = server_url + api_path
76
+ @server = XMLRPC::Client.new_from_uri(server_url, nil, timeout)
77
+ @version = Versionomy.parse(options[:version] || api_version)
78
+ end
79
+
80
+ # Makes the call to the server with the given arguments. Note that this also
81
+ # allows for calling XMLRPC methods on the server that haven't yet been
82
+ # implemented as Ruby methods here.
83
+ #
84
+ # @example Call a new method
85
+ # result = make_call("tl.getWidgets", { "testplanid" => 123 }, "1.5")
86
+ # raise TestLinker::Error, result["message"] if result["code"]
87
+ # return result
88
+ # @param [String] method_name The XMLRPC method to call.
89
+ # @param [Hash] arguments The arguments to send to the server.
90
+ # @param [String] method_supported_in_version The version of the API the
91
+ # method was added.
92
+ # @return The return type depends on the method call.
93
+ def make_call(method_name, arguments, method_supported_in_version)
94
+ ensure_version_is :greater_than_or_equal_to, method_supported_in_version
95
+ TestLinker.log "API Version: #{method_supported_in_version}"
96
+ TestLinker.log "Calling method: '#{method_name}' with args '#{arguments}'"
97
+ response = @server.call(method_name, arguments)
98
+ TestLinker.log "Received response:"
99
+ TestLinker.log response
100
+
101
+ if @version.nil?
102
+ return response
103
+ elsif response.is_a?(Array) && response.first['code']
104
+ raise TestLinker::Error, "#{response.first['code']}: #{response.first['message']}"
105
+ end
106
+
107
+ response
108
+ end
109
+
110
+ private
111
+
112
+ # Raises if the version set in @version doesn't meet the comparison with the
113
+ # passed-in version. Returns nil if @version isn't set, since there's
114
+ # nothing to do (and something might have called to set @version).
115
+ #
116
+ # @private
117
+ # @param [Symbol] comparison
118
+ # @param [String] version
119
+ def ensure_version_is(comparison, version)
120
+ message = "Method not supported in version #{@version}."
121
+
122
+ if @version.nil?
123
+ return
124
+ elsif comparison == :less_than && @version >= version
125
+ raise TestLinker::Error, message
126
+ elsif comparison == :greater_than_or_equal_to && @version < version
127
+ raise TestLinker::Error, message
128
+ end
129
+ end
130
+ end