rutema 2.0.0.pre5 → 2.0.0.pre6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.txt +220 -213
- data/Manifest.txt +17 -18
- data/README.md +55 -55
- data/bin/rutema +7 -7
- data/lib/rutema/application.rb +61 -60
- data/lib/rutema/core/configuration.rb +207 -194
- data/lib/rutema/core/engine.rb +192 -185
- data/lib/rutema/core/framework.rb +88 -27
- data/lib/rutema/core/objectmodel.rb +0 -0
- data/lib/rutema/core/parser.rb +34 -34
- data/lib/rutema/core/reporter.rb +133 -129
- data/lib/rutema/core/runner.rb +93 -83
- data/lib/rutema/elements/minimal.rb +47 -47
- data/lib/rutema/parsers/xml.rb +156 -154
- data/lib/rutema/reporters/json.rb +34 -34
- data/lib/rutema/reporters/junit.rb +101 -97
- data/lib/rutema/version.rb +8 -8
- metadata +5 -7
- data/.gemtest +0 -0
- data/lib/rutema/reporters/nunit.rb +0 -103
data/lib/rutema/core/engine.rb
CHANGED
@@ -1,186 +1,193 @@
|
|
1
|
-
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
2
|
-
require 'thread'
|
3
|
-
require_relative 'parser'
|
4
|
-
require_relative 'reporter'
|
5
|
-
require_relative 'runner'
|
6
|
-
require_relative '../version'
|
7
|
-
|
8
|
-
module Rutema
|
9
|
-
class Engine
|
10
|
-
include Messaging
|
11
|
-
def initialize configuration
|
12
|
-
@queue=Queue.new
|
13
|
-
@parser=instantiate_class(configuration.parser,configuration) if configuration.parser
|
14
|
-
if configuration.runner
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@dispatcher.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
@
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
@
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
@
|
137
|
-
|
138
|
-
end
|
139
|
-
|
140
|
-
|
141
|
-
@
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
end
|
179
|
-
def
|
180
|
-
if
|
181
|
-
|
182
|
-
|
183
|
-
end
|
184
|
-
|
185
|
-
|
1
|
+
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
2
|
+
require 'thread'
|
3
|
+
require_relative 'parser'
|
4
|
+
require_relative 'reporter'
|
5
|
+
require_relative 'runner'
|
6
|
+
require_relative '../version'
|
7
|
+
|
8
|
+
module Rutema
|
9
|
+
class Engine
|
10
|
+
include Messaging
|
11
|
+
def initialize configuration
|
12
|
+
@queue=Queue.new
|
13
|
+
@parser=instantiate_class(configuration.parser,configuration) if configuration.parser
|
14
|
+
if configuration.runner
|
15
|
+
if configuration.runner[:class]
|
16
|
+
@runner=configuration.runner[:class].new(configuration.context,@queue)
|
17
|
+
else
|
18
|
+
raise RutemaError,"Runner settting overriden, but missing :class"
|
19
|
+
end
|
20
|
+
else
|
21
|
+
@runner=Rutema::Runners::Default.new(configuration.context,@queue)
|
22
|
+
end
|
23
|
+
raise RutemaError,"Could not instantiate parser" unless @parser
|
24
|
+
@dispatcher=Dispatcher.new(@queue,configuration)
|
25
|
+
@configuration=configuration
|
26
|
+
end
|
27
|
+
def run test_identifier=nil
|
28
|
+
@dispatcher.run!
|
29
|
+
#start
|
30
|
+
message("start")
|
31
|
+
check,setup,teardown,tests=*parse(test_identifier)
|
32
|
+
if tests.empty?
|
33
|
+
@dispatcher.exit
|
34
|
+
raise RutemaError,"Did not parse any tests succesfully"
|
35
|
+
else
|
36
|
+
@runner.setup=setup
|
37
|
+
@runner.teardown=teardown
|
38
|
+
#running - at this point we've done any and all checks and we're stepping on the gas
|
39
|
+
message("running")
|
40
|
+
run_scenarios(tests,check)
|
41
|
+
end
|
42
|
+
message("end")
|
43
|
+
@dispatcher.exit
|
44
|
+
@dispatcher.report(tests)
|
45
|
+
end
|
46
|
+
def parse test_identifier=nil
|
47
|
+
specs=[]
|
48
|
+
#so, while we are parsing, we have a list of tests
|
49
|
+
#we're either parsing all of the tests, or just one
|
50
|
+
#make sure the one test is on the list
|
51
|
+
if test_identifier
|
52
|
+
if @configuration.tests.include?(File.expand_path(test_identifier))
|
53
|
+
specs<<parse_specification(File.expand_path(test_identifier))
|
54
|
+
else
|
55
|
+
error(File.expand_path(test_identifier),"Does not exist in the configuration")
|
56
|
+
end
|
57
|
+
else
|
58
|
+
specs=parse_specifications(@configuration.tests)
|
59
|
+
end
|
60
|
+
specs.compact!
|
61
|
+
check,setup,teardown=parse_specials(@configuration)
|
62
|
+
return [check,setup,teardown,specs]
|
63
|
+
end
|
64
|
+
private
|
65
|
+
def parse_specifications tests
|
66
|
+
tests.map{|t| parse_specification(t)}.compact
|
67
|
+
end
|
68
|
+
def parse_specification spec_identifier
|
69
|
+
begin
|
70
|
+
@parser.parse_specification(spec_identifier)
|
71
|
+
rescue Rutema::ParserError
|
72
|
+
error(spec_identifier,$!.message)
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
end
|
76
|
+
def parse_specials configuration
|
77
|
+
check=nil
|
78
|
+
setup=nil
|
79
|
+
teardown=nil
|
80
|
+
if configuration.check
|
81
|
+
check=parse_specification(configuration.check)
|
82
|
+
end
|
83
|
+
if configuration.setup
|
84
|
+
setup=parse_specification(configuration.setup)
|
85
|
+
end
|
86
|
+
if configuration.teardown
|
87
|
+
teardown=parse_specification(configuration.teardown)
|
88
|
+
end
|
89
|
+
return check,setup,teardown
|
90
|
+
end
|
91
|
+
def run_scenarios specs,check
|
92
|
+
if specs.empty?
|
93
|
+
error(nil,"No tests to run")
|
94
|
+
else
|
95
|
+
if check
|
96
|
+
if run_test(check)==:success
|
97
|
+
specs.each{|s| run_test(s)}
|
98
|
+
else
|
99
|
+
error(nil,"Check test failed")
|
100
|
+
end
|
101
|
+
else
|
102
|
+
specs.each{|spec| run_test(spec)}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
def run_test specification
|
107
|
+
if specification.scenario
|
108
|
+
status=@runner.run(specification)["status"]
|
109
|
+
else
|
110
|
+
status=:not_executed
|
111
|
+
message(:test=>specification.name,:text=>"No scenario", :status=>status)
|
112
|
+
end
|
113
|
+
return status
|
114
|
+
end
|
115
|
+
def instantiate_class definition,configuration
|
116
|
+
if definition[:class]
|
117
|
+
klass=definition[:class]
|
118
|
+
return klass.new(configuration)
|
119
|
+
end
|
120
|
+
return nil
|
121
|
+
end
|
122
|
+
end
|
123
|
+
class Dispatcher
|
124
|
+
INTERVAL=0.01
|
125
|
+
def initialize queue,configuration
|
126
|
+
@queue = queue
|
127
|
+
@queues = {}
|
128
|
+
@streaming_reporters=[]
|
129
|
+
@block_reporters=[]
|
130
|
+
@collector=Rutema::Reporters::Collector.new(nil,self)
|
131
|
+
if configuration.reporters
|
132
|
+
instances=configuration.reporters.values.map{|v| instantiate_reporter(v,configuration) if v[:class] != Reporters::Summary}.compact
|
133
|
+
@streaming_reporters,_=instances.partition{|rep| rep.respond_to?(:update)}
|
134
|
+
@block_reporters,_=instances.partition{|rep| rep.respond_to?(:report)}
|
135
|
+
end
|
136
|
+
@streaming_reporters<<@collector
|
137
|
+
@configuration=configuration
|
138
|
+
end
|
139
|
+
def subscribe identifier
|
140
|
+
@queues[identifier]=Queue.new
|
141
|
+
return @queues[identifier]
|
142
|
+
end
|
143
|
+
|
144
|
+
def run!
|
145
|
+
puts "Running #{@streaming_reporters.size} streaming reporters" if $DEBUG
|
146
|
+
@streaming_reporters.each {|r| r.run!}
|
147
|
+
@thread=Thread.new do
|
148
|
+
while true do
|
149
|
+
dispatch()
|
150
|
+
sleep INTERVAL
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def report specs
|
156
|
+
@block_reporters.each do |r|
|
157
|
+
r.report(specs,@collector.states,@collector.errors)
|
158
|
+
end
|
159
|
+
Reporters::Summary.new(@configuration,self).report(specs,@collector.states,@collector.errors)
|
160
|
+
end
|
161
|
+
def exit
|
162
|
+
puts "Exiting main dispatcher" if $DEBUG
|
163
|
+
if @thread
|
164
|
+
flush
|
165
|
+
@streaming_reporters.each {|r| r.exit}
|
166
|
+
Thread.kill(@thread)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
private
|
170
|
+
def flush
|
171
|
+
puts "Flushing queues" if $DEBUG
|
172
|
+
if @thread
|
173
|
+
while @queue.size>0 do
|
174
|
+
dispatch()
|
175
|
+
sleep INTERVAL
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
def instantiate_reporter definition,configuration
|
180
|
+
if definition[:class]
|
181
|
+
klass=definition[:class]
|
182
|
+
return klass.new(configuration,self)
|
183
|
+
end
|
184
|
+
return nil
|
185
|
+
end
|
186
|
+
def dispatch
|
187
|
+
if @queue.size>0
|
188
|
+
data=@queue.pop
|
189
|
+
@queues.each{ |i,q| q.push(data) } if data
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
186
193
|
end
|
@@ -1,28 +1,89 @@
|
|
1
|
-
module Rutema
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
1
|
+
module Rutema
|
2
|
+
#Represents the data beeing shunted between the components in lieu of logging.
|
3
|
+
#
|
4
|
+
#This is the primary type passed to the event reporters
|
5
|
+
class Message
|
6
|
+
attr_accessor :test,:text,:timestamp
|
7
|
+
#Keys used:
|
8
|
+
# test - the test id/name
|
9
|
+
# text - the text of the message
|
10
|
+
# timestamp
|
11
|
+
def initialize params
|
12
|
+
@test=params.fetch(:test,"")
|
13
|
+
@text=params.fetch(:text,"")
|
14
|
+
@timestamp=params.fetch(:timestamp,0)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
msg=""
|
19
|
+
msg<<"#{@test} " unless @test.empty?
|
20
|
+
msg<<@text
|
21
|
+
return msg
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ErrorMessage<Message
|
26
|
+
def to_s
|
27
|
+
msg="ERROR - "
|
28
|
+
msg<<"#{@test} " unless @test.empty?
|
29
|
+
msg<<@text
|
30
|
+
return msg
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class RunnerMessage<Message
|
35
|
+
attr_accessor :duration,:status,:number,:out,:err
|
36
|
+
def initialize params
|
37
|
+
super(params)
|
38
|
+
@duration=params.fetch("duration",0)
|
39
|
+
@status=params.fetch("status",:none)
|
40
|
+
@number=params.fetch("number",1)
|
41
|
+
@out=params.fetch("out","")
|
42
|
+
@err=params.fetch("err","")
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
msg="#{@test}:"
|
47
|
+
msg<<"#{@text}." unless @text.empty?
|
48
|
+
outpt=output()
|
49
|
+
msg<<" Output:\n#{outpt}" unless outpt.empty? || @status!=:error
|
50
|
+
return msg
|
51
|
+
end
|
52
|
+
|
53
|
+
def output
|
54
|
+
msg=""
|
55
|
+
msg<<"#{@out}\n" unless @out.empty?
|
56
|
+
msg<<@err unless @err.empty?
|
57
|
+
return msg.chomp
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module Messaging
|
62
|
+
def error identifier,message
|
63
|
+
@queue.push(ErrorMessage.new(:test=>identifier,:text=>message,:timestamp=>Time.now))
|
64
|
+
end
|
65
|
+
def message message
|
66
|
+
case message
|
67
|
+
when String
|
68
|
+
Message.new(:text=>message,:timestamp=>Time.now)
|
69
|
+
when Hash
|
70
|
+
hm=Message.new(message)
|
71
|
+
hm=RunnerMessage.new(message) if message[:test] && message["status"]
|
72
|
+
hm.timestamp=Time.now
|
73
|
+
@queue.push(hm)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
#Generic error class for errors in the engine
|
78
|
+
class RutemaError<RuntimeError
|
79
|
+
end
|
80
|
+
#Is raised when an error is found in a specification
|
81
|
+
class ParserError<RutemaError
|
82
|
+
end
|
83
|
+
#Is raised on an unexpected error during execution
|
84
|
+
class RunnerError<RutemaError
|
85
|
+
end
|
86
|
+
#Errors in reporters should use this class
|
87
|
+
class ReportError<RutemaError
|
88
|
+
end
|
28
89
|
end
|
File without changes
|
data/lib/rutema/core/parser.rb
CHANGED
@@ -1,35 +1,35 @@
|
|
1
|
-
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
2
|
-
require_relative 'framework'
|
3
|
-
|
4
|
-
module Rutema
|
5
|
-
module Parsers
|
6
|
-
#Base class that bombs out when used.
|
7
|
-
#
|
8
|
-
#Derive your parser class from this class and implement parse_specification and validate_configuration
|
9
|
-
class SpecificationParser
|
10
|
-
attr_reader :configuration
|
11
|
-
def initialize configuration
|
12
|
-
@configuration=configuration
|
13
|
-
@configuration||={}
|
14
|
-
validate_configuration
|
15
|
-
end
|
16
|
-
#parses a specification
|
17
|
-
def parse_specification param
|
18
|
-
raise ParserError,"not implemented. You should derive a parser implementation from SpecificationParser!"
|
19
|
-
end
|
20
|
-
#parses the setup script. By default calls parse_specification
|
21
|
-
def parse_setup param
|
22
|
-
parse_specification(param)
|
23
|
-
end
|
24
|
-
#parses the teardown script. By default calls parse_specification
|
25
|
-
def parse_teardown param
|
26
|
-
parse_specification(param)
|
27
|
-
end
|
28
|
-
#The parser stores it's configuration in @configuration
|
29
|
-
#
|
30
|
-
#To avoid validating the configuration in element_* methods repeatedly, do all configuration validation here
|
31
|
-
def validate_configuration
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
2
|
+
require_relative 'framework'
|
3
|
+
|
4
|
+
module Rutema
|
5
|
+
module Parsers
|
6
|
+
#Base class that bombs out when used.
|
7
|
+
#
|
8
|
+
#Derive your parser class from this class and implement parse_specification and validate_configuration
|
9
|
+
class SpecificationParser
|
10
|
+
attr_reader :configuration
|
11
|
+
def initialize configuration
|
12
|
+
@configuration=configuration
|
13
|
+
@configuration||={}
|
14
|
+
validate_configuration
|
15
|
+
end
|
16
|
+
#parses a specification
|
17
|
+
def parse_specification param
|
18
|
+
raise ParserError,"not implemented. You should derive a parser implementation from SpecificationParser!"
|
19
|
+
end
|
20
|
+
#parses the setup script. By default calls parse_specification
|
21
|
+
def parse_setup param
|
22
|
+
parse_specification(param)
|
23
|
+
end
|
24
|
+
#parses the teardown script. By default calls parse_specification
|
25
|
+
def parse_teardown param
|
26
|
+
parse_specification(param)
|
27
|
+
end
|
28
|
+
#The parser stores it's configuration in @configuration
|
29
|
+
#
|
30
|
+
#To avoid validating the configuration in element_* methods repeatedly, do all configuration validation here
|
31
|
+
def validate_configuration
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
35
|
end
|