rtrail 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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