devcreek 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.
- 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
|