rtrail 0.0.1

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.
Files changed (61) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +21 -0
  6. data/README.md +96 -0
  7. data/lib/rtrail.rb +19 -0
  8. data/lib/rtrail/api.rb +42 -0
  9. data/lib/rtrail/case.rb +8 -0
  10. data/lib/rtrail/client.rb +113 -0
  11. data/lib/rtrail/entity.rb +65 -0
  12. data/lib/rtrail/exceptions.rb +4 -0
  13. data/lib/rtrail/helpers.rb +32 -0
  14. data/lib/rtrail/plan.rb +7 -0
  15. data/lib/rtrail/project.rb +83 -0
  16. data/lib/rtrail/result.rb +9 -0
  17. data/lib/rtrail/run.rb +39 -0
  18. data/lib/rtrail/section.rb +7 -0
  19. data/lib/rtrail/suite.rb +26 -0
  20. data/lib/rtrail/test.rb +22 -0
  21. data/mock/app.rb +55 -0
  22. data/mock/views/add_result/1.yajl +4 -0
  23. data/mock/views/add_run/1.yajl +7 -0
  24. data/mock/views/error.yajl +3 -0
  25. data/mock/views/get_case/1.yajl +4 -0
  26. data/mock/views/get_cases/1.yajl +3 -0
  27. data/mock/views/get_plan/1.yajl +4 -0
  28. data/mock/views/get_plans/1.yajl +3 -0
  29. data/mock/views/get_project/1.yajl +4 -0
  30. data/mock/views/get_project/2.yajl +4 -0
  31. data/mock/views/get_projects.yajl +4 -0
  32. data/mock/views/get_result/1.yajl +4 -0
  33. data/mock/views/get_results/1.yajl +3 -0
  34. data/mock/views/get_run/1.yajl +7 -0
  35. data/mock/views/get_run/2.yajl +7 -0
  36. data/mock/views/get_runs/1.yajl +4 -0
  37. data/mock/views/get_section/1.yajl +9 -0
  38. data/mock/views/get_section/2.yajl +9 -0
  39. data/mock/views/get_sections/1.yajl +4 -0
  40. data/mock/views/get_suite/1.yajl +6 -0
  41. data/mock/views/get_suite/2.yajl +5 -0
  42. data/mock/views/get_suite/3.yajl +6 -0
  43. data/mock/views/get_suites/1.yajl +4 -0
  44. data/mock/views/get_suites/2.yajl +4 -0
  45. data/mock/views/get_test/1.yajl +4 -0
  46. data/mock/views/get_test/2.yajl +4 -0
  47. data/mock/views/get_tests/1.yajl +5 -0
  48. data/rtrail.gemspec +41 -0
  49. data/spec/api_spec.rb +46 -0
  50. data/spec/case_spec.rb +12 -0
  51. data/spec/client_spec.rb +43 -0
  52. data/spec/entity_spec.rb +12 -0
  53. data/spec/helpers_spec.rb +52 -0
  54. data/spec/plan_spec.rb +12 -0
  55. data/spec/project_spec.rb +132 -0
  56. data/spec/result_spec.rb +12 -0
  57. data/spec/run_spec.rb +61 -0
  58. data/spec/spec_helper.rb +19 -0
  59. data/spec/suite_spec.rb +29 -0
  60. data/spec/test_spec.rb +34 -0
  61. metadata +258 -0
@@ -0,0 +1,83 @@
1
+ require_relative 'entity'
2
+ require_relative 'suite'
3
+ require_relative 'run'
4
+ require_relative 'plan'
5
+
6
+ module RTrail
7
+ class Project < Entity
8
+ def self.all
9
+ return client.get("get_projects").map do |project|
10
+ self.new(project)
11
+ end
12
+ end
13
+
14
+ def self.by_name(project_name)
15
+ result = Project.all.find do |project|
16
+ project.name == project_name
17
+ end
18
+
19
+ if result.nil?
20
+ raise RTrail::NotFound.new("Project '#{project_name}' not found in TestRail")
21
+ else
22
+ return self.new(result)
23
+ end
24
+ end
25
+
26
+ # Return a suite with the given name in the current project.
27
+ def suite_by_name(suite_name)
28
+ suite = self.suites.find do |s|
29
+ s.name == suite_name
30
+ end
31
+ if suite.nil?
32
+ raise RTrail::NotFound.new(
33
+ "Suite '#{suite_name}' not found in project '#{self.data.name}'")
34
+ end
35
+ return suite
36
+ end
37
+
38
+ # Return a suite with the given name or id in the current project.
39
+ def suite(suite_name_or_id)
40
+ if is_id?(suite_name_or_id)
41
+ return Suite.new(suite_name_or_id)
42
+ else
43
+ return suite_by_name(suite_name_or_id)
44
+ end
45
+ end
46
+
47
+ def suite_id(suite_name_or_id)
48
+ return self.suite(suite_name_or_id).id
49
+ end
50
+
51
+ def plans
52
+ return get_entities(Plan, data.id)
53
+ end
54
+
55
+ def runs
56
+ return get_entities(Run, data.id)
57
+ end
58
+
59
+ def suites
60
+ return get_entities(Suite, data.id)
61
+ end
62
+
63
+ # Return an existing run with the given name, or create and
64
+ # return a new run.
65
+ def run(suite_name_or_id, run_name)
66
+ existing = runs.find {|r| r.name == run_name}
67
+ if existing
68
+ return existing
69
+ else
70
+ return add_run(suite_name_or_id, :name => run_name)
71
+ end
72
+ end
73
+
74
+ # Create a new Run in the given Suite in this project.
75
+ def add_run(suite_name_or_id, fields={})
76
+ run_data = fields.merge({
77
+ :suite_id => suite_id(suite_name_or_id),
78
+ })
79
+ return add_entity(Run, data.id, run_data)
80
+ end
81
+ end
82
+ end # module RTrail
83
+
@@ -0,0 +1,9 @@
1
+ require_relative 'entity'
2
+ require_relative 'helpers'
3
+
4
+ module RTrail
5
+ class Result < Entity
6
+ include HasCreateTime
7
+ end
8
+ end # module RTrail
9
+
@@ -0,0 +1,39 @@
1
+ require_relative 'entity'
2
+ require_relative 'test'
3
+ require_relative 'helpers'
4
+
5
+ module RTrail
6
+ class Run < Entity
7
+ include HasCreateTime
8
+
9
+ # Return a one-line summary of this Run
10
+ def summary
11
+ # TODO: Include these?
12
+ # self.untested_count
13
+ # self.blocked_count
14
+ # self.passed_count
15
+ # self.failed_count
16
+ result = "#{self.id}: #{self.name}"
17
+ if self.completed?
18
+ result += " [completed #{self.complete_time}]"
19
+ else
20
+ result += " [not completed]"
21
+ end
22
+ return result
23
+ end
24
+
25
+ def tests
26
+ return get_entities(Test, data.id)
27
+ end
28
+
29
+ def complete_time
30
+ return nil if !completed?
31
+ return Time.at(self[:completed_on].to_i).utc
32
+ end
33
+
34
+ def completed?
35
+ return !self[:completed_on].nil?
36
+ end
37
+ end
38
+ end # module RTrail
39
+
@@ -0,0 +1,7 @@
1
+ require_relative 'entity'
2
+
3
+ module RTrail
4
+ class Section < Entity
5
+ end
6
+ end # module RTrail
7
+
@@ -0,0 +1,26 @@
1
+ require_relative 'entity'
2
+ require_relative 'case'
3
+ require_relative 'section'
4
+
5
+ module RTrail
6
+ class Suite < Entity
7
+ def sections
8
+ return get_entities(
9
+ Section,
10
+ data.project_id,
11
+ :suite_id => data.id
12
+ )
13
+ end
14
+
15
+ def cases(section_id=nil)
16
+ return get_entities(
17
+ Case,
18
+ data.project_id,
19
+ :suite_id => data.id,
20
+ :section_id => section_id
21
+ )
22
+ end
23
+ end
24
+
25
+ end # module RTrail
26
+
@@ -0,0 +1,22 @@
1
+ require_relative 'entity'
2
+ require_relative 'result'
3
+
4
+ module RTrail
5
+ class Test < Entity
6
+ # Return all Results for this Test.
7
+ def results
8
+ return get_entities(Result, data.id)
9
+ end
10
+
11
+ # Return the most recently created Result for this Test.
12
+ def latest_result
13
+ return get_entities(Result, data.id, :limit => 1).first
14
+ end
15
+
16
+ # Add a new Result to this test.
17
+ def add_result(fields)
18
+ return add_entity(Result, data.id, fields)
19
+ end
20
+ end
21
+ end # module RTrail
22
+
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'sinatra/base'
5
+ require 'sinatra/reloader'
6
+ require 'yajl'
7
+
8
+ # Mock TestRail web application
9
+ class TestApp < Sinatra::Base
10
+ set :root, File.dirname(__FILE__)
11
+
12
+ configure do
13
+ register Sinatra::Reloader
14
+ end
15
+
16
+ helpers do
17
+ def parse(params)
18
+ path = ''
19
+ query = {}
20
+ params.each do |key, value|
21
+ if key.start_with?("/api/v2")
22
+ path = key.gsub('/api/v2/', '')
23
+ else
24
+ query[key] = value
25
+ end
26
+ end
27
+ return path, query
28
+ end
29
+ end
30
+
31
+ get '/index.php' do
32
+ # FIXME: Handle query (used for suite_id, section_id etc.)
33
+ path, query = parse(params)
34
+ begin
35
+ yajl(path.to_sym)
36
+ rescue => ex
37
+ halt 400, yajl(:error, :locals => {:error => ex.message})
38
+ end
39
+ end
40
+
41
+ post '/index.php' do
42
+ path, query = parse(params)
43
+ data = Yajl::Parser.parse(request.body.read)
44
+ begin
45
+ yajl(path.to_sym, :locals => data)
46
+ rescue => ex
47
+ halt 400, yajl(:error, :locals => {:error => ex.message})
48
+ end
49
+ end
50
+ end
51
+
52
+ if __FILE__ == $0
53
+ TestApp.run! :port => 8080
54
+ end
55
+
@@ -0,0 +1,4 @@
1
+ json = {
2
+ :id => 5,
3
+ :status_id => status_id
4
+ }
@@ -0,0 +1,7 @@
1
+ json = {
2
+ :id => 4,
3
+ :name => name,
4
+ :suite_id => suite_id,
5
+ :created_on => Time.now.to_i,
6
+ :completed_on => nil,
7
+ }
@@ -0,0 +1,3 @@
1
+ json = {
2
+ :error => error,
3
+ }
@@ -0,0 +1,4 @@
1
+ json = {
2
+ :id => 1,
3
+ :title => "First Case",
4
+ }
@@ -0,0 +1,3 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_case/1.yajl')),
3
+ ]
@@ -0,0 +1,4 @@
1
+ json = {
2
+ :id => 1,
3
+ :name => "First Plan",
4
+ }
@@ -0,0 +1,3 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_plan/1.yajl')),
3
+ ]
@@ -0,0 +1,4 @@
1
+ json = {
2
+ :id => 1,
3
+ :name => "First Project"
4
+ }
@@ -0,0 +1,4 @@
1
+ json = {
2
+ :id => 2,
3
+ :name => "Second Project"
4
+ }
@@ -0,0 +1,4 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_project/1.yajl')),
3
+ eval(File.read('mock/views/get_project/2.yajl')),
4
+ ]
@@ -0,0 +1,4 @@
1
+ json = {
2
+ :id => 1,
3
+ :test_id => 1,
4
+ }
@@ -0,0 +1,3 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_result/1.yajl')),
3
+ ]
@@ -0,0 +1,7 @@
1
+ json = {
2
+ :id => 1,
3
+ :name => "First Run",
4
+ :suite_id => 1,
5
+ :created_on => Time.utc(2014, 'jun', 5, 12, 34, 56).to_i,
6
+ :completed_on => Time.utc(2014, 'jun', 5, 13, 34, 56).to_i,
7
+ }
@@ -0,0 +1,7 @@
1
+ json = {
2
+ :id => 2,
3
+ :name => "Second Run",
4
+ :suite_id => 1,
5
+ :created_on => Time.utc(2014, 'jun', 6, 12, 34, 56).to_i,
6
+ :completed_on => nil,
7
+ }
@@ -0,0 +1,4 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_run/1.yajl')),
3
+ eval(File.read('mock/views/get_run/2.yajl')),
4
+ ]
@@ -0,0 +1,9 @@
1
+ json = {
2
+ :id => 1,
3
+ :name => "First Section",
4
+ :suite_id => 1,
5
+ :parent_id => 1,
6
+ :display_order => 1,
7
+ :depth => 0,
8
+ }
9
+
@@ -0,0 +1,9 @@
1
+ json = {
2
+ :id => 2,
3
+ :name => "Second Section",
4
+ :suite_id => 1,
5
+ :parent_id => 1,
6
+ :display_order => 2,
7
+ :depth => 0,
8
+ }
9
+
@@ -0,0 +1,4 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_section/1.yajl')),
3
+ eval(File.read('mock/views/get_section/2.yajl')),
4
+ ]
@@ -0,0 +1,6 @@
1
+ json = {
2
+ :id => 1,
3
+ :name => "First Suite",
4
+ :project_id => 1,
5
+ }
6
+
@@ -0,0 +1,5 @@
1
+ json = {
2
+ :id => 2,
3
+ :name => "Second Suite",
4
+ }
5
+
@@ -0,0 +1,6 @@
1
+ json = {
2
+ :id => 3,
3
+ :name => "Third Suite",
4
+ :project_id => 2,
5
+ }
6
+
@@ -0,0 +1,4 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_suite/1.yajl')),
3
+ eval(File.read('mock/views/get_suite/1.yajl')),
4
+ ]
@@ -0,0 +1,4 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_suite/3.yajl')),
3
+ ]
4
+
@@ -0,0 +1,4 @@
1
+ json = {
2
+ :id => 1,
3
+ }
4
+
@@ -0,0 +1,4 @@
1
+ json = {
2
+ :id => 2,
3
+ }
4
+
@@ -0,0 +1,5 @@
1
+ json = [
2
+ eval(File.read('mock/views/get_test/1.yajl')),
3
+ eval(File.read('mock/views/get_test/2.yajl')),
4
+ ]
5
+
@@ -0,0 +1,41 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "rtrail"
3
+ s.version = "0.0.1"
4
+ s.summary = "Ruby object wrapper for TestRail API"
5
+ s.description = <<-EOS
6
+ RTrail wraps the TestRail API v2.0 in Ruby objects
7
+ EOS
8
+ s.authors = ["Eric Pierce"]
9
+ s.email = "epierce@automation-excellence.com"
10
+ s.homepage = "http://github.com/a-e/rtrail"
11
+ s.platform = Gem::Platform::RUBY
12
+
13
+ s.add_dependency 'hashie'
14
+
15
+ # Basic utilities
16
+ s.add_development_dependency 'rake'
17
+ s.add_development_dependency 'pry'
18
+
19
+ # For testing
20
+ s.add_development_dependency 'rspec'
21
+
22
+ # Mock webapp to support testing
23
+ s.add_development_dependency 'sinatra'
24
+ s.add_development_dependency 'sinatra-contrib'
25
+ s.add_development_dependency 'thin'
26
+
27
+ # For test coverage
28
+ s.add_development_dependency 'simplecov'
29
+
30
+ # For documentation and markdown support
31
+ s.add_development_dependency 'yard'
32
+ s.add_development_dependency 'rdiscount'
33
+
34
+ # Others
35
+ s.add_development_dependency 'yajl-ruby'
36
+
37
+ # Files to distribute
38
+ s.files = `git ls-files`.split("\n")
39
+
40
+ s.require_path = 'lib'
41
+ end