devcreek 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +504 -0
- data/History.txt +4 -0
- data/Manifest.txt +17 -0
- data/README.txt +598 -0
- data/lib/devcreek.rb +10 -0
- data/lib/devcreek_core.rb +28 -0
- data/lib/devcreek_record_template.rb +67 -0
- data/lib/devcreek_testresult.rb +36 -0
- data/lib/devcreek_testrunnermediator.rb +80 -0
- data/lib/devcreek_testsuite.rb +58 -0
- data/lib/devcreek_transmitter.rb +35 -0
- data/lib/digest_auth.rb +37 -0
- data/test/test_fiction.rb +45 -0
- data/test/testcore_spec.rb +70 -0
- data/test/testresult_spec.rb +74 -0
- data/test/testsuite_spec.rb +152 -0
- data/test/testtransmitter_spec.rb +39 -0
- metadata +82 -0
data/lib/devcreek.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# devcreek_core.rb
|
2
|
+
#
|
3
|
+
# Copyright Caleb Powell 2007
|
4
|
+
#
|
5
|
+
# Licensed under the LGPL, see the file COPYING in the distribution
|
6
|
+
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
module DevCreek
|
10
|
+
class Core
|
11
|
+
require 'singleton'
|
12
|
+
require 'socket'
|
13
|
+
include Singleton
|
14
|
+
attr_accessor :principal, :project, :user, :password, :enabled
|
15
|
+
|
16
|
+
def load(attributes=Hash.new)
|
17
|
+
attributes.each do |key, val|
|
18
|
+
instance_variable_set("@#{key}", val)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_from_yaml(file_name)
|
23
|
+
load(YAML.load_file(file_name))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Core.instance.principal = Socket.gethostname
|
28
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# devcreek_record_template.rb
|
2
|
+
#
|
3
|
+
# Copyright Caleb Powell 2007
|
4
|
+
#
|
5
|
+
# Licensed under the LGPL, see the file COPYING in the distribution
|
6
|
+
|
7
|
+
module DevCreek
|
8
|
+
TRANSMISSION_RECORD_TEMPLATE = %{
|
9
|
+
<record>
|
10
|
+
<core.principal><%= DevCreek::Core.instance.principal %></core.principal>
|
11
|
+
<core.project><%= DevCreek::Core.instance.project %></core.project>
|
12
|
+
<core.sessionId><%= session_id %></core.sessionId>
|
13
|
+
<core.timeStamp><%= start.localtime.to_i * 1000 %></core.timeStamp>
|
14
|
+
<core.timeZoneOffset><%= start.localtime.gmt_offset * 1000 %></core.timeZoneOffset>
|
15
|
+
<core.type>unittest.TestRunStarted</core.type>
|
16
|
+
<unittest.testCount><%= run_count %></unittest.testCount>
|
17
|
+
<unittest.testFramework><%= framework %></unittest.testFramework>
|
18
|
+
<unittest.testLanguage>ruby</unittest.testLanguage>
|
19
|
+
<unittest.testRunLauncher>manual</unittest.testRunLauncher>
|
20
|
+
</record>
|
21
|
+
<% test_results.values.each do |test_result| %>
|
22
|
+
<record>
|
23
|
+
<core.principal><%= DevCreek::Core.instance.principal %></core.principal>
|
24
|
+
<core.project><%= DevCreek::Core.instance.project %></core.project>
|
25
|
+
<core.sessionId><%= session_id %></core.sessionId>
|
26
|
+
<core.timeStamp><%= test_result.start.localtime.to_i * 1000 %></core.timeStamp>
|
27
|
+
<core.timeZoneOffset><%= test_result.start.localtime.gmt_offset * 1000 %></core.timeZoneOffset>
|
28
|
+
<core.type>unittest.TestStarted</core.type>
|
29
|
+
<unittest.testClass><%= test_result.test_class %></unittest.testClass>
|
30
|
+
<unittest.testFramework><%= framework %></unittest.testFramework>
|
31
|
+
<unittest.testLanguage>ruby</unittest.testLanguage>
|
32
|
+
<unittest.testName><%= test_result.test_name %></unittest.testName>
|
33
|
+
<unittest.testRunLauncher>manual</unittest.testRunLauncher>
|
34
|
+
</record>
|
35
|
+
<record>
|
36
|
+
<core.principal><%= DevCreek::Core.instance.principal %></core.principal>
|
37
|
+
<core.project><%= DevCreek::Core.instance.project %></core.project>
|
38
|
+
<core.sessionId><%= session_id %></core.sessionId>
|
39
|
+
<core.timeStamp><%= test_result.finish.localtime.to_i * 1000 %></core.timeStamp>
|
40
|
+
<core.timeZoneOffset><%= test_result.finish.localtime.gmt_offset * 1000 %></core.timeZoneOffset>
|
41
|
+
<core.type>unittest.TestEnded</core.type>
|
42
|
+
<unittest.testClass><%= test_result.test_class %></unittest.testClass>
|
43
|
+
<unittest.testFramework><%= framework %></unittest.testFramework>
|
44
|
+
<unittest.testLanguage>ruby</unittest.testLanguage>
|
45
|
+
<unittest.testName><%= test_result.test_name %></unittest.testName>
|
46
|
+
<unittest.testRunLauncher>manual</unittest.testRunLauncher>
|
47
|
+
<unittest.testStatus><%= test_result.status %></unittest.testStatus>
|
48
|
+
</record>
|
49
|
+
<% end %>
|
50
|
+
<record>
|
51
|
+
<core.elapsedTime><%= elapsed_time %></core.elapsedTime>
|
52
|
+
<core.principal><%= DevCreek::Core.instance.principal %></core.principal>
|
53
|
+
<core.project><%= DevCreek::Core.instance.project %></core.project>
|
54
|
+
<core.sessionId><%= session_id %></core.sessionId>
|
55
|
+
<core.timeStamp><%= finish.localtime.to_i * 1000 %></core.timeStamp>
|
56
|
+
<core.timeZoneOffset><%= finish.localtime.gmt_offset * 1000 %></core.timeZoneOffset>
|
57
|
+
<core.type>unittest.TestRunEnded</core.type>
|
58
|
+
<unittest.errorTotal><%= error_count %></unittest.errorTotal>
|
59
|
+
<unittest.failureTotal><%= failure_count %></unittest.failureTotal>
|
60
|
+
<unittest.successTotal><%= success_count %></unittest.successTotal>
|
61
|
+
<unittest.testFramework><%= framework %></unittest.testFramework>
|
62
|
+
<unittest.testLanguage>ruby</unittest.testLanguage>
|
63
|
+
<unittest.testRunLauncher>manual</unittest.testRunLauncher>
|
64
|
+
<unittest.testRunStatus>ENDED</unittest.testRunStatus>
|
65
|
+
</record>
|
66
|
+
}.gsub(/^ /, '').freeze
|
67
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# devcreek_testresult.rb
|
2
|
+
#
|
3
|
+
# Copyright Caleb Powell 2007
|
4
|
+
#
|
5
|
+
# Licensed under the LGPL, see the file COPYING in the distribution
|
6
|
+
|
7
|
+
module DevCreek
|
8
|
+
class TestResult
|
9
|
+
OK = "OK"
|
10
|
+
FAILURE = "FAILURE"
|
11
|
+
ERROR = "ERROR"
|
12
|
+
|
13
|
+
attr_reader :test_name, :test_class, :start, :finish, :status
|
14
|
+
|
15
|
+
def initialize(test_name, test_class, status=OK, start=Time.now)
|
16
|
+
@test_name, @test_class, @status, @start = test_name, test_class, status, start
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_finished
|
20
|
+
raise ArgumentError, "The finish time cannot be set twice" unless @finish.nil?
|
21
|
+
@finish = Time.now
|
22
|
+
end
|
23
|
+
|
24
|
+
def elapsed_time
|
25
|
+
return finish - start unless finish.nil? or start.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_a_failure
|
29
|
+
@status = FAILURE
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_an_error
|
33
|
+
@status = ERROR
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# devcreek_testrunnermediator.rb
|
2
|
+
#
|
3
|
+
# Copyright Caleb Powell 2007
|
4
|
+
#
|
5
|
+
# Licensed under the LGPL, see the file COPYING in the distribution
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
require 'test/unit/util/observable'
|
9
|
+
require 'test/unit/testresult'
|
10
|
+
require 'devcreek_testresult'
|
11
|
+
require 'devcreek_testsuite'
|
12
|
+
require 'devcreek_transmitter'
|
13
|
+
require 'devcreek_core'
|
14
|
+
require 'rubygems'
|
15
|
+
require 'uuidtools'
|
16
|
+
require 'test/unit/ui/testrunnermediator'
|
17
|
+
|
18
|
+
#class Test::Unit::TestCase
|
19
|
+
# alias_method :old_run, :run
|
20
|
+
# def run(*args)
|
21
|
+
# puts "TestCase.run.start #{name}"
|
22
|
+
## result = old_run(*args, &block)
|
23
|
+
# puts "TestCase.run.start #{name}"
|
24
|
+
# end
|
25
|
+
#end
|
26
|
+
|
27
|
+
class Test::Unit::UI::TestRunnerMediator
|
28
|
+
alias_method :old_initialize, :initialize
|
29
|
+
def initialize(*args)
|
30
|
+
result = old_initialize(*args)
|
31
|
+
|
32
|
+
#DevCreek Modifications
|
33
|
+
@@dev_creek_test_suite = nil
|
34
|
+
@@dev_creek_reg = /([\w]*)\(([\w]*)\)/
|
35
|
+
|
36
|
+
add_listener(Test::Unit::UI::TestRunnerMediator::STARTED) do |test_result|
|
37
|
+
@@dev_creek_test_suite = DevCreek::TestSuite.new("Test::Unit")
|
38
|
+
end
|
39
|
+
|
40
|
+
add_listener(Test::Unit::TestCase::STARTED) do |name|
|
41
|
+
test_name = name.match(@@dev_creek_reg)[1]
|
42
|
+
test_class = name.match(@@dev_creek_reg)[2]
|
43
|
+
@@dev_creek_test_suite.test_results[name] = DevCreek::TestResult.new(test_name, test_class)
|
44
|
+
end
|
45
|
+
|
46
|
+
add_listener(Test::Unit::TestResult::FAULT) do |fault|
|
47
|
+
dc_test_result = @@dev_creek_test_suite.test_results[fault.test_name]
|
48
|
+
if fault.instance_of? Test::Unit::Failure
|
49
|
+
dc_test_result.has_a_failure
|
50
|
+
else
|
51
|
+
dc_test_result.has_an_error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
add_listener(Test::Unit::TestCase::FINISHED) do |test_name|
|
56
|
+
@@dev_creek_test_suite.test_results[test_name].has_finished
|
57
|
+
end
|
58
|
+
|
59
|
+
add_listener(Test::Unit::UI::TestRunnerMediator::FINISHED) do |elapsed_time|
|
60
|
+
if DevCreek::Core.instance().enabled != false
|
61
|
+
@@dev_creek_test_suite.has_finished
|
62
|
+
if @@dev_creek_test_suite.has_test_results?
|
63
|
+
session_id = UUID.timestamp_create().to_s
|
64
|
+
xml_data = @@dev_creek_test_suite.to_xml(session_id)
|
65
|
+
puts xml_data
|
66
|
+
p 'Attempting DevCreek transmission...'
|
67
|
+
response = DevCreek::Transmitter.submit(session_id, xml_data)
|
68
|
+
case response
|
69
|
+
when Net::HTTPSuccess
|
70
|
+
puts '...transmission successful.'
|
71
|
+
else
|
72
|
+
puts "...failure transmiting TestUnit results to DevCreek: ${response.error!}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
return result
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# devcreek_testsuite.rb
|
2
|
+
#
|
3
|
+
# Copyright Caleb Powell 2007
|
4
|
+
#
|
5
|
+
# Licensed under the LGPL, see the file COPYING in the distribution
|
6
|
+
|
7
|
+
require 'devcreek_core'
|
8
|
+
require 'devcreek_record_template'
|
9
|
+
require 'erb'
|
10
|
+
|
11
|
+
module DevCreek
|
12
|
+
class TestSuite
|
13
|
+
attr_accessor :test_results, :elapsed_time
|
14
|
+
attr_reader :start, :framework, :finish, :session_id
|
15
|
+
def initialize(framework)
|
16
|
+
@framework, @test_results, @start, @elapsed_time = framework, {}, Time.new, 0.0
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def sum_test_results_with_status(status)
|
21
|
+
success = 0
|
22
|
+
test_results.values.each do |test|
|
23
|
+
success = success + 1 if test.status == status;
|
24
|
+
end
|
25
|
+
return success
|
26
|
+
end
|
27
|
+
|
28
|
+
public
|
29
|
+
def run_count
|
30
|
+
return test_results.size
|
31
|
+
end
|
32
|
+
|
33
|
+
def has_test_results?
|
34
|
+
return run_count > 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def success_count
|
38
|
+
return sum_test_results_with_status("OK")
|
39
|
+
end
|
40
|
+
|
41
|
+
def failure_count
|
42
|
+
return sum_test_results_with_status("FAILURE")
|
43
|
+
end
|
44
|
+
|
45
|
+
def error_count
|
46
|
+
return sum_test_results_with_status("ERROR")
|
47
|
+
end
|
48
|
+
|
49
|
+
def has_finished
|
50
|
+
raise ArgumentError, "The finish time cannot be set twice" unless @finish.nil?
|
51
|
+
@finish = Time.now
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_xml(session_id)
|
55
|
+
ERB.new(DevCreek::TRANSMISSION_RECORD_TEMPLATE, 0, "%<>").result(binding).gsub(/^ /, '')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# devcreektansmitter_.rb
|
2
|
+
#
|
3
|
+
# Copyright Caleb Powell 2007
|
4
|
+
#
|
5
|
+
# Licensed under the LGPL, see the file COPYING in the distribution
|
6
|
+
|
7
|
+
require 'net/http'
|
8
|
+
require 'digest_auth'
|
9
|
+
require 'devcreek_core'
|
10
|
+
|
11
|
+
module DevCreek
|
12
|
+
module Transmitter
|
13
|
+
|
14
|
+
SUBMIT_URL = "http://devcreek.com/submitData/"
|
15
|
+
|
16
|
+
def Transmitter.submit(session_id, xml_data)
|
17
|
+
|
18
|
+
raise Exception.new("Invalid argument: session_id and xml_data cannot be nil") if session_id.nil? or xml_data.nil?
|
19
|
+
raise Exception.new("Core data not initialized") if DevCreek::Core.instance().project.nil? or
|
20
|
+
DevCreek::Core.instance().user.nil? or
|
21
|
+
DevCreek::Core.instance().password.nil?
|
22
|
+
|
23
|
+
url = URI.parse("#{SUBMIT_URL}#{DevCreek::Core.instance().project}/#{session_id}")
|
24
|
+
response = nil
|
25
|
+
Net::HTTP.start(url.host) do |http|
|
26
|
+
res = http.head(url.request_uri)
|
27
|
+
req = Net::HTTP::Post.new(url.path)
|
28
|
+
req.body= xml_data
|
29
|
+
req.digest_auth(DevCreek::Core.instance().user, DevCreek::Core.instance().password, res)
|
30
|
+
response = http.request(req)
|
31
|
+
end
|
32
|
+
return response
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/digest_auth.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Written by Eric Hodel <drbrain@segment7.net>
|
2
|
+
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module Net
|
7
|
+
module HTTPHeader
|
8
|
+
@@nonce_count = -1
|
9
|
+
CNONCE = Digest::MD5::hexdigest("%x" % (Time.now.to_i + rand(65535)))
|
10
|
+
def digest_auth(user, password, response) # based on http://segment7.net/projects/ruby/snippets/digest_auth.rb
|
11
|
+
@@nonce_count += 1
|
12
|
+
response['www-authenticate'] =~ /^(\w+) (.*)/
|
13
|
+
params = {}
|
14
|
+
$2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
|
15
|
+
a_1 = "#{user}:#{params['realm']}:#{password}"
|
16
|
+
a_2 = "#{@method}:#{@path}"
|
17
|
+
request_digest = ''
|
18
|
+
request_digest << Digest::MD5.hexdigest(a_1)
|
19
|
+
request_digest << ':' << params['nonce']
|
20
|
+
request_digest << ':' << ('%08x' % @@nonce_count)
|
21
|
+
request_digest << ':' << CNONCE
|
22
|
+
request_digest << ':' << params['qop']
|
23
|
+
request_digest << ':' << Digest::MD5.hexdigest(a_2)
|
24
|
+
header = []
|
25
|
+
header << "Digest username=\"#{user}\""
|
26
|
+
header << "realm=\"#{params['realm']}\""
|
27
|
+
header << "qop=#{params['qop']}"
|
28
|
+
header << "algorithm=MD5"
|
29
|
+
header << "uri=\"#{@path}\""
|
30
|
+
header << "nonce=\"#{params['nonce']}\""
|
31
|
+
header << "nc=#{'%08x' % @@nonce_count}"
|
32
|
+
header << "cnonce=\"#{CNONCE}\""
|
33
|
+
header << "response=\"#{Digest::MD5.hexdigest(request_digest)}\""
|
34
|
+
@header['Authorization'] = header
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# test_fiction.rb
|
2
|
+
#
|
3
|
+
# Copyright Caleb Powell 2007
|
4
|
+
#
|
5
|
+
# Licensed under the LGPL, see the file COPYING in the distribution
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
|
9
|
+
class TestFiction < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def test_success
|
12
|
+
assert(true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_fail
|
16
|
+
assert(false)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_error
|
20
|
+
raise "I just disagree"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class TestMoreFiction < Test::Unit::TestCase
|
26
|
+
|
27
|
+
def test_success
|
28
|
+
assert(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_just_for_fun
|
32
|
+
assert true
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_fail
|
36
|
+
assert(false)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_error
|
40
|
+
raise "I just disagree"
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# testcore_spec.rb
|
2
|
+
#
|
3
|
+
# Copyright Caleb Powell 2007
|
4
|
+
#
|
5
|
+
# Licensed under the LGPL, see the file COPYING in the distribution
|
6
|
+
|
7
|
+
$LOAD_PATH.push(FileUtils::pwd + '/lib')
|
8
|
+
require 'devcreek'
|
9
|
+
require 'socket'
|
10
|
+
|
11
|
+
describe DevCreek::Core do
|
12
|
+
|
13
|
+
before :each do
|
14
|
+
DevCreek::Core.instance().load(
|
15
|
+
:user => nil,
|
16
|
+
:password => nil,
|
17
|
+
:project => nil
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be a singleton" do
|
22
|
+
lambda{Core.new}.should raise_error(NameError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should have a principal attribute that defaults to the hostname" do
|
26
|
+
DevCreek::Core.instance().principal().should eql(Socket.gethostname)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should have a principal attribute that is mutable" do
|
30
|
+
DevCreek::Core.instance().principal().should_not eql("")
|
31
|
+
DevCreek::Core.instance().principal= "Mutable"
|
32
|
+
DevCreek::Core.instance().principal().should eql("Mutable")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "load method should parse a Hash and set the properties correctly" do
|
36
|
+
DevCreek::Core.instance().user().should be_nil
|
37
|
+
DevCreek::Core.instance().password().should be_nil
|
38
|
+
DevCreek::Core.instance().project().should be_nil
|
39
|
+
|
40
|
+
DevCreek::Core.instance().load(
|
41
|
+
:user => 'foo@bar.com',
|
42
|
+
:password => 'pass_it_on',
|
43
|
+
:project => 'fooProject'
|
44
|
+
)
|
45
|
+
|
46
|
+
DevCreek::Core.instance().user().should eql("foo@bar.com")
|
47
|
+
DevCreek::Core.instance().password().should eql("pass_it_on")
|
48
|
+
DevCreek::Core.instance().project().should eql("fooProject")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "load_from_yaml method should parse the file and set the properties correctly" do
|
52
|
+
DevCreek::Core.instance().user().should be_nil
|
53
|
+
DevCreek::Core.instance().password().should be_nil
|
54
|
+
DevCreek::Core.instance().project().should be_nil
|
55
|
+
|
56
|
+
|
57
|
+
def YAML.load_file(filename)
|
58
|
+
return {:user => 'foo@bar.com',
|
59
|
+
:password => 'pass_it_on',
|
60
|
+
:project => 'fooProject'}
|
61
|
+
end
|
62
|
+
|
63
|
+
DevCreek::Core.instance().load_from_yaml("props.yaml")
|
64
|
+
|
65
|
+
DevCreek::Core.instance().user().should eql("foo@bar.com")
|
66
|
+
DevCreek::Core.instance().password().should eql("pass_it_on")
|
67
|
+
DevCreek::Core.instance().project().should eql("fooProject")
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|