right_support 2.5.5 → 2.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/right_support/ci/junit_cucumber_formatter.rb +31 -0
- data/lib/right_support/ci/junit_rspec_formatter.rb +170 -0
- data/lib/right_support/ci/rake_task.rb +73 -0
- data/lib/right_support/ci.rb +11 -0
- data/lib/right_support/net/request_balancer.rb +2 -2
- data/lib/right_support/net/s3_helper.rb +18 -5
- data/lib/right_support.rb +5 -4
- data/right_support.gemspec +2 -2
- metadata +9 -5
@@ -0,0 +1,31 @@
|
|
1
|
+
module RightSupport::CI
|
2
|
+
if require_succeeds?('cucumber/formatter/junit')
|
3
|
+
class JUnitCucumberFormatter < Cucumber::Formatter::Junit
|
4
|
+
private
|
5
|
+
|
6
|
+
def build_testcase(duration, status, exception = nil, suffix = "")
|
7
|
+
@time += duration
|
8
|
+
# Use "cucumber" as a pseudo-package, and the feature name as a pseudo-class
|
9
|
+
classname = "cucumber.#{@feature_name}"
|
10
|
+
name = "#{@scenario}#{suffix}"
|
11
|
+
pending = [:pending, :undefined].include?(status)
|
12
|
+
passed = (status == :passed || (pending && !@options[:strict]))
|
13
|
+
|
14
|
+
@builder.testcase(:classname => classname, :name => name, :time => "%.6f" % duration) do
|
15
|
+
unless passed
|
16
|
+
@builder.failure(:message => "#{status.to_s} #{name}", :type => status.to_s) do
|
17
|
+
@builder.cdata! @output
|
18
|
+
@builder.cdata!(format_exception(exception)) if exception
|
19
|
+
end
|
20
|
+
@failures += 1
|
21
|
+
end
|
22
|
+
if passed and (status == :skipped || pending)
|
23
|
+
@builder.skipped
|
24
|
+
@skipped += 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
@tests += 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
# Copyright (c) 2009-2011 RightScale, Inc, All Rights Reserved Worldwide.
|
2
|
+
#
|
3
|
+
# THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE
|
4
|
+
# AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use,
|
5
|
+
# reproduction, modification, or disclosure of this program is
|
6
|
+
# strictly prohibited. Any use of this program by an authorized
|
7
|
+
# licensee is strictly subject to the terms and conditions,
|
8
|
+
# including confidentiality obligations, set forth in the applicable
|
9
|
+
# License Agreement between RightScale.com, Inc. and the licensee.
|
10
|
+
|
11
|
+
require 'time'
|
12
|
+
|
13
|
+
module RightSupport::CI
|
14
|
+
if require_succeeds?('spec/runner/formatter/base_text_formatter')
|
15
|
+
# RSpec 1.x
|
16
|
+
class JUnitRSpecFormatter < Spec::Runner::Formatter::BaseTextFormatter
|
17
|
+
def initialize(*args)
|
18
|
+
begin
|
19
|
+
require 'builder'
|
20
|
+
rescue LoadError => e
|
21
|
+
raise NotImplementedError, "Your Gemfile or gemspec must include builder (~> 3.0) in order to use this class"
|
22
|
+
end
|
23
|
+
super(*args)
|
24
|
+
@current_example_group = nil
|
25
|
+
@test_times = {}
|
26
|
+
@test_groups = {}
|
27
|
+
@test_results = {}
|
28
|
+
@test_failures = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def example_group_started(example)
|
32
|
+
@current_example_group = example
|
33
|
+
end
|
34
|
+
|
35
|
+
def example_started(example)
|
36
|
+
@test_groups[example] = @current_example_group
|
37
|
+
@example_started_at = Time.now
|
38
|
+
end
|
39
|
+
|
40
|
+
def example_passed(example)
|
41
|
+
@test_times[example] = Time.now - @example_started_at
|
42
|
+
@test_results[example] = 'passed'
|
43
|
+
end
|
44
|
+
|
45
|
+
def example_failed(example, counter, failure)
|
46
|
+
@test_times[example] = Time.now - @example_started_at
|
47
|
+
@test_results[example] = 'failed'
|
48
|
+
@test_failures[example] = failure
|
49
|
+
end
|
50
|
+
|
51
|
+
def example_pending(example)
|
52
|
+
@test_times[example] = Time.now - @example_started_at
|
53
|
+
@test_results[example] = 'pending'
|
54
|
+
end
|
55
|
+
|
56
|
+
def dump_summary(duration, example_count, failure_count, pending_count)
|
57
|
+
builder = Builder::XmlMarkup.new :indent => 2
|
58
|
+
builder.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
|
59
|
+
builder.testsuite :errors => 0, :failures => failure_count, :skipped => pending_count, :tests => example_count, :time => duration, :timestamp => Time.now.iso8601 do
|
60
|
+
builder.properties
|
61
|
+
@test_results.each_pair do |test, result|
|
62
|
+
classname = classname_for(test)
|
63
|
+
full_description = test.description
|
64
|
+
|
65
|
+
# The full description always begins with the classname, but this is useless info when
|
66
|
+
# generating the XML report.
|
67
|
+
if full_description.start_with?(classname)
|
68
|
+
full_description = full_description[classname.length..-1].strip
|
69
|
+
end
|
70
|
+
|
71
|
+
builder.testcase(:classname => classname, :name => full_description, :time => @test_times[test]) do
|
72
|
+
case result
|
73
|
+
when "failed"
|
74
|
+
builder.failure :message => "failed #{full_description}", :type => "failed" do
|
75
|
+
builder.cdata! failure_details_for(test)
|
76
|
+
end
|
77
|
+
when "pending" then
|
78
|
+
builder.skipped
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
output.puts builder.target!
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def failure_details_for(example)
|
89
|
+
exception = @test_failures[example].exception
|
90
|
+
exception.nil? ? "" : "#{exception.message}\n#{format_backtrace(exception.backtrace, example).join("\n")}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def classname_for(example)
|
94
|
+
# Take our best guess, by looking at the description of the example group
|
95
|
+
# and assuming the first word is a class name
|
96
|
+
group = @test_groups[example]
|
97
|
+
klass = group.description.split(/\s+/).first
|
98
|
+
"rspec.#{klass}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
elsif require_succeeds?('rspec/core/formatters/base_formatter')
|
102
|
+
# RSpec 2.x
|
103
|
+
class JUnitRSpecFormatter < RSpec::Core::Formatters::BaseFormatter
|
104
|
+
def initialize(*args)
|
105
|
+
begin
|
106
|
+
require 'builder'
|
107
|
+
rescue LoadError => e
|
108
|
+
raise NotImplementedError, "Your Gemfile or gemspec must include builder (~> 3.0) in order to use this class"
|
109
|
+
end
|
110
|
+
super(*args)
|
111
|
+
@test_results = []
|
112
|
+
end
|
113
|
+
|
114
|
+
def example_passed(example)
|
115
|
+
@test_results << example
|
116
|
+
end
|
117
|
+
|
118
|
+
def example_failed(example)
|
119
|
+
@test_results << example
|
120
|
+
end
|
121
|
+
|
122
|
+
def example_pending(example)
|
123
|
+
@test_results << example
|
124
|
+
end
|
125
|
+
|
126
|
+
def failure_details_for(example)
|
127
|
+
exception = example.exception
|
128
|
+
exception.nil? ? "" : "#{exception.message}\n#{format_backtrace(exception.backtrace, example).join("\n")}"
|
129
|
+
end
|
130
|
+
|
131
|
+
def classname_for(example)
|
132
|
+
eg = example.metadata[:example_group]
|
133
|
+
eg = eg[:example_group] while eg.key?(:example_group)
|
134
|
+
klass = eg[:description_args].to_s
|
135
|
+
"rspec.#{klass}"
|
136
|
+
end
|
137
|
+
|
138
|
+
def dump_summary(duration, example_count, failure_count, pending_count)
|
139
|
+
builder = Builder::XmlMarkup.new :indent => 2
|
140
|
+
builder.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
|
141
|
+
builder.testsuite :errors => 0, :failures => failure_count, :skipped => pending_count, :tests => example_count, :time => duration, :timestamp => Time.now.iso8601 do
|
142
|
+
builder.properties
|
143
|
+
@test_results.each do |test|
|
144
|
+
classname = classname_for(test)
|
145
|
+
full_description = test.full_description
|
146
|
+
time = test.metadata[:execution_result][:run_time]
|
147
|
+
|
148
|
+
# The full description always begins with the classname, but this is useless info when
|
149
|
+
# generating the XML report.
|
150
|
+
if full_description.start_with?(classname)
|
151
|
+
full_description = full_description[classname.length..-1].strip
|
152
|
+
end
|
153
|
+
|
154
|
+
builder.testcase(:classname => classname, :name => full_description, :time => time) do
|
155
|
+
case test.metadata[:execution_result][:status]
|
156
|
+
when "failed"
|
157
|
+
builder.failure :message => "failed #{full_description}", :type => "failed" do
|
158
|
+
builder.cdata! failure_details_for test
|
159
|
+
end
|
160
|
+
when "pending" then
|
161
|
+
builder.skipped
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
output.puts builder.target!
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rake/tasklib'
|
2
|
+
|
3
|
+
# Make sure the rest of RightSupport is required, since this file can be
|
4
|
+
# required directly.
|
5
|
+
require 'right_support'
|
6
|
+
|
7
|
+
module RightSupport::CI
|
8
|
+
# A Rake task definition that creates a CI namespace with appropriate
|
9
|
+
# tests.
|
10
|
+
class RakeTask < ::Rake::TaskLib
|
11
|
+
include ::Rake::DSL if defined?(::Rake::DSL)
|
12
|
+
|
13
|
+
# The namespace in which to define the continuous integration tasks.
|
14
|
+
#
|
15
|
+
# Default :ci
|
16
|
+
attr_accessor :ci_namespace
|
17
|
+
|
18
|
+
# The base directory for output files.
|
19
|
+
#
|
20
|
+
# Default 'measurement'
|
21
|
+
attr_accessor :output_path
|
22
|
+
|
23
|
+
def initialize(*args)
|
24
|
+
@ci_namespace = args.shift || :ci
|
25
|
+
|
26
|
+
yield self if block_given?
|
27
|
+
|
28
|
+
@output_path ||= 'measurement'
|
29
|
+
|
30
|
+
namespace @ci_namespace do
|
31
|
+
task :prep do
|
32
|
+
FileUtils.mkdir_p('measurement')
|
33
|
+
|
34
|
+
# Tweak RUBYOPT so RubyGems and RightSupport are automatically required.
|
35
|
+
# This is necessary because Cucumber doesn't have a -r equivalent we can
|
36
|
+
# use to inject ourselves into its process. (There is an -r, but it disables
|
37
|
+
# auto-loading.)
|
38
|
+
rubyopt = '-rright_support'
|
39
|
+
if ENV.key?('RUBYOPT')
|
40
|
+
rubyopt = ENV['RUBYOPT'] + ' ' + rubyopt
|
41
|
+
rubyopt = '-rrubygems ' + rubyopt unless (rubyopt =~ /ubygems/)
|
42
|
+
end
|
43
|
+
ENV['RUBYOPT'] = rubyopt
|
44
|
+
end
|
45
|
+
|
46
|
+
if require_succeeds?('rspec/core/rake_task')
|
47
|
+
# RSpec 2
|
48
|
+
desc "Run RSpec examples"
|
49
|
+
RSpec::Core::RakeTask.new(:spec => :prep) do |t|
|
50
|
+
t.rspec_opts = ['-f', JUnitRSpecFormatter.name,
|
51
|
+
'-o', File.join(@output_path, 'rspec', 'rspec.xml')]
|
52
|
+
end
|
53
|
+
elsif require_succeeds?('spec/rake/spectask')
|
54
|
+
# RSpec 1
|
55
|
+
Spec::Rake::SpecTask.new(:spec => :prep) do |t|
|
56
|
+
desc "Run RSpec Examples"
|
57
|
+
t.spec_opts = ['-f', JUnitRSpecFormatter.name + ":" + File.join(@output_path, 'rspec', 'rspec.xml')]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if require_succeeds?('cucumber/rake/task')
|
62
|
+
desc "Run Cucumber features"
|
63
|
+
Cucumber::Rake::Task.new do |t|
|
64
|
+
t.cucumber_opts = ['--no-color',
|
65
|
+
'--format', JUnitCucumberFormatter.name,
|
66
|
+
'--out', File.join(@output_path, 'cucumber')]
|
67
|
+
end
|
68
|
+
task :cucumber => [:prep]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module RightSupport
|
2
|
+
module CI
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'right_support/ci/junit_cucumber_formatter'
|
7
|
+
require 'right_support/ci/junit_rspec_formatter'
|
8
|
+
|
9
|
+
# Don't auto-require the Rake task; it mixes the Rake DSL into everything!
|
10
|
+
# Must defer loading of the Rake task to the Rakefiles
|
11
|
+
#require 'right_support/ci/rake_task'
|
@@ -63,10 +63,10 @@ module RightSupport::Net
|
|
63
63
|
# reflection to handle ALL RSpec-related exceptions.
|
64
64
|
spec_namespaces = if require_succeeds?('rspec')
|
65
65
|
# RSpec 2.x
|
66
|
-
[RSpec::Mocks, RSpec::Expectations]
|
66
|
+
[::RSpec::Mocks, ::RSpec::Expectations]
|
67
67
|
elsif require_succeeds?('spec')
|
68
68
|
# RSpec 1.x
|
69
|
-
[Spec::Expectations]
|
69
|
+
[::Spec::Expectations]
|
70
70
|
else
|
71
71
|
# RSpec is not present
|
72
72
|
[]
|
@@ -23,6 +23,8 @@ module RightSupport::Net
|
|
23
23
|
# RightSupport::Net::S3Helper.init(s3_config, Rightscale::S3, Encryptor)
|
24
24
|
# s3_health = RightSupport::Net::S3Helper.health_check
|
25
25
|
class S3Helper
|
26
|
+
class BucketNotFound < Exception; end
|
27
|
+
|
26
28
|
# Init() is the first method which must be called.
|
27
29
|
# This is configuration and integration with S3 and Encryptor
|
28
30
|
#
|
@@ -36,12 +38,22 @@ module RightSupport::Net
|
|
36
38
|
# @param [Class] encryptor Class which will be used to encrypt data
|
37
39
|
# encrypt() and decrypt() methods must be implemented
|
38
40
|
#
|
39
|
-
#
|
41
|
+
# @raise BucketNotFound if bucket name specified in config["bucket_name"] does not exist
|
42
|
+
#
|
43
|
+
# @return [true] always returns true
|
40
44
|
def self.init(config, s3, encryptor)
|
41
45
|
@config = config
|
42
46
|
@s3class = s3
|
43
47
|
@encryptor = encryptor
|
48
|
+
|
49
|
+
# Reset any S3 objects we'd been caching, since config may have changed
|
50
|
+
@s3 = @bucket = nil
|
51
|
+
# Make sure our bucket exists -- better to do it now than on first access!
|
52
|
+
self.bucket
|
53
|
+
|
54
|
+
true
|
44
55
|
end
|
56
|
+
|
45
57
|
# Checks S3 credentials syntax in config parameter
|
46
58
|
#
|
47
59
|
# @return [Boolean] true if s3 creadentials are ok or false if not
|
@@ -56,15 +68,16 @@ module RightSupport::Net
|
|
56
68
|
def self.config
|
57
69
|
@config
|
58
70
|
end
|
59
|
-
#
|
71
|
+
# Create (if does not exist) and return S3 object
|
60
72
|
def self.s3
|
61
73
|
@s3 ||= @s3class.new config["creds"]["aws_access_key_id"], config["creds"]["aws_secret_access_key"]
|
62
74
|
end
|
63
|
-
#
|
75
|
+
# Create Bucket object using S3 object
|
76
|
+
# @raise BucketNotFound if bucket name specified in config["bucket_name"] does not exist
|
64
77
|
def self.bucket
|
65
|
-
#TO DISCUSS: second param 'true' means 'create new bucket'
|
66
|
-
#@bucket ||= s3.bucket(config["bucket_name"], true)
|
67
78
|
@bucket ||= s3.bucket(config["bucket_name"])
|
79
|
+
raise BucketNotFound, "Bucket #{config["bucket_name"]} does not exist" if @bucket.nil?
|
80
|
+
@bucket
|
68
81
|
end
|
69
82
|
# Returns Master secret from config
|
70
83
|
def self.master_secret
|
data/lib/right_support.rb
CHANGED
@@ -2,12 +2,13 @@
|
|
2
2
|
require 'thread'
|
3
3
|
|
4
4
|
require 'right_support/ruby'
|
5
|
+
require 'right_support/log'
|
5
6
|
require 'right_support/data'
|
7
|
+
require 'right_support/validation'
|
6
8
|
require 'right_support/crypto'
|
7
|
-
require 'right_support/
|
9
|
+
require 'right_support/rack'
|
8
10
|
require 'right_support/db'
|
9
|
-
require 'right_support/log'
|
10
11
|
require 'right_support/net'
|
11
|
-
require 'right_support/
|
12
|
+
require 'right_support/config'
|
12
13
|
require 'right_support/stats'
|
13
|
-
require 'right_support/
|
14
|
+
require 'right_support/ci'
|
data/right_support.gemspec
CHANGED
@@ -7,8 +7,8 @@ spec = Gem::Specification.new do |s|
|
|
7
7
|
s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
|
8
8
|
|
9
9
|
s.name = 'right_support'
|
10
|
-
s.version = '2.
|
11
|
-
s.date = '2012-
|
10
|
+
s.version = '2.6.1'
|
11
|
+
s.date = '2012-11-07'
|
12
12
|
|
13
13
|
s.authors = ['Tony Spataro', 'Sergey Sergyenko', 'Ryan Williamson', 'Lee Kirchhoff', 'Sergey Enin', 'Alexey Karpik']
|
14
14
|
s.email = 'support@rightscale.com'
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_support
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 2.
|
8
|
+
- 6
|
9
|
+
- 1
|
10
|
+
version: 2.6.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tony Spataro
|
@@ -20,7 +20,7 @@ autorequire:
|
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
22
|
|
23
|
-
date: 2012-
|
23
|
+
date: 2012-11-07 00:00:00 -08:00
|
24
24
|
default_executable:
|
25
25
|
dependencies: []
|
26
26
|
|
@@ -36,6 +36,10 @@ files:
|
|
36
36
|
- LICENSE
|
37
37
|
- README.rdoc
|
38
38
|
- lib/right_support.rb
|
39
|
+
- lib/right_support/ci.rb
|
40
|
+
- lib/right_support/ci/junit_cucumber_formatter.rb
|
41
|
+
- lib/right_support/ci/junit_rspec_formatter.rb
|
42
|
+
- lib/right_support/ci/rake_task.rb
|
39
43
|
- lib/right_support/config.rb
|
40
44
|
- lib/right_support/config/feature_set.rb
|
41
45
|
- lib/right_support/config/recursive_true_class.rb
|