rutema 2.0.0.pre5 → 2.0.0.pre6

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.
@@ -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
- @runner=instantiate_class(configuration.runner,configuration)
16
- else
17
- @runner=Rutema::Runners::Default.new(configuration.context,@queue)
18
- end
19
- raise RutemaError,"Could not instantiate parser" unless @parser
20
- @dispatcher=Dispatcher.new(@queue,configuration)
21
- @configuration=configuration
22
- end
23
- def run test_identifier=nil
24
- @dispatcher.run!
25
- #start
26
- message("start")
27
- check,setup,teardown,tests=*parse(test_identifier)
28
- if tests.empty?
29
- @dispatcher.exit
30
- raise RutemaError,"Did not parse any tests succesfully"
31
- else
32
- @runner.setup=setup
33
- @runner.teardown=teardown
34
- #running - at this point we've done any and all checks and we're stepping on the gas
35
- message("running")
36
- run_scenarios(tests,check)
37
- end
38
- message("end")
39
- @dispatcher.exit
40
- @dispatcher.report(tests)
41
- end
42
- def parse test_identifier=nil
43
- specs=[]
44
- #so, while we are parsing, we have a list of tests
45
- #we're either parsing all of the tests, or just one
46
- #make sure the one test is on the list
47
- if test_identifier
48
- if @configuration.tests.include?(File.expand_path(test_identifier))
49
- specs<<parse_specification(File.expand_path(test_identifier))
50
- else
51
- error(File.expand_path(test_identifier),"Does not exist in the configuration")
52
- end
53
- else
54
- specs=parse_specifications(@configuration.tests)
55
- end
56
- specs.compact!
57
- check,setup,teardown=parse_specials(@configuration)
58
- return [check,setup,teardown,specs]
59
- end
60
- private
61
- def parse_specifications tests
62
- tests.map{|t| parse_specification(t)}.compact
63
- end
64
- def parse_specification spec_identifier
65
- begin
66
- @parser.parse_specification(spec_identifier)
67
- rescue Rutema::ParserError
68
- error(spec_identifier,$!.message)
69
- nil
70
- end
71
- end
72
- def parse_specials configuration
73
- check=nil
74
- setup=nil
75
- teardown=nil
76
- if configuration.check
77
- check=parse_specification(configuration.check)
78
- end
79
- if configuration.setup
80
- setup=parse_specification(configuration.setup)
81
- end
82
- if configuration.teardown
83
- teardown=parse_specification(configuration.teardown)
84
- end
85
- return check,setup,teardown
86
- end
87
- def run_scenarios specs,check
88
- if specs.empty?
89
- error(nil,"No tests to run")
90
- else
91
- if check
92
- if run_test(check)==:success
93
- specs.each{|s| run_test(s)}
94
- else
95
- error(nil,"Check test failed")
96
- end
97
- else
98
- specs.each{|spec| run_test(spec)}
99
- end
100
- end
101
- end
102
- def run_test specification
103
- if specification.scenario
104
- status=@runner.run(specification)["status"]
105
- else
106
- status=:not_executed
107
- message(:test=>specification.name,:message=>"No scenario", :status=>status)
108
- end
109
- return status
110
- end
111
- def instantiate_class definition,configuration
112
- if definition[:class]
113
- klass=definition[:class]
114
- return klass.new(configuration)
115
- end
116
- return nil
117
- end
118
- end
119
- class Dispatcher
120
- INTERVAL=0.01
121
- def initialize queue,configuration
122
- @queue = queue
123
- @queues = {}
124
- @streaming_reporters=[]
125
- @block_reporters=[]
126
- @collector=Rutema::Reporters::Collector.new(nil,self)
127
- if configuration.reporters
128
- instances=configuration.reporters.values.map{|v| instantiate_reporter(v,configuration) if v[:class] != Reporters::Summary}.compact
129
- @streaming_reporters,_=instances.partition{|rep| rep.respond_to?(:update)}
130
- @block_reporters,_=instances.partition{|rep| rep.respond_to?(:report)}
131
- end
132
- @streaming_reporters<<@collector
133
- @configuration=configuration
134
- end
135
- def subscribe identifier
136
- @queues[identifier]=Queue.new
137
- return @queues[identifier]
138
- end
139
-
140
- def run!
141
- @streaming_reporters.each {|r| r.run!}
142
- @thread=Thread.new do
143
- while true do
144
- dispatch()
145
- sleep INTERVAL
146
- end
147
- end
148
- end
149
-
150
- def report specs
151
- @block_reporters.each do |r|
152
- r.report(specs,@collector.states,@collector.errors)
153
- end
154
- Reporters::Summary.new(@configuration,self).report(specs,@collector.states,@collector.errors)
155
- end
156
- def exit
157
- if @thread
158
- flush
159
- @streaming_reporters.each {|r| r.exit}
160
- Thread.kill(@thread)
161
- end
162
- end
163
- private
164
- def flush
165
- if @thread
166
- while @queue.size>0 do
167
- dispatch()
168
- sleep INTERVAL
169
- end
170
- end
171
- end
172
- def instantiate_reporter definition,configuration
173
- if definition[:class]
174
- klass=definition[:class]
175
- return klass.new(configuration,self)
176
- end
177
- return nil
178
- end
179
- def dispatch
180
- if @queue.size>0
181
- data=@queue.pop
182
- @queues.each{ |i,q| q.push(data) } if data
183
- end
184
- end
185
- end
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
- module Messaging
3
- def error identifier,message
4
- message(:test=>identifier,:error=>message)
5
- end
6
- def message message
7
- msg=message
8
- if message.is_a?(String)
9
- msg={:message=>message,:timestamp=>Time.now}
10
- elsif message.is_a?(Hash)
11
- msg[:timestamp]=Time.now
12
- end
13
- @queue.push(msg)
14
- end
15
- end
16
- #Generic error class for errors in the engine
17
- class RutemaError<RuntimeError
18
- end
19
- #Is raised when an error is found in a specification
20
- class ParserError<RutemaError
21
- end
22
- #Is raised on an unexpected error during execution
23
- class RunnerError<RutemaError
24
- end
25
- #Errors in reporters should use this class
26
- class ReportError<RutemaError
27
- end
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
@@ -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