Class: Polytrix::Challenge
Overview
rubocop:disable ClassLength
Defined Under Namespace
Classes: FSM
Constant Summary
collapse
- KEYS_TO_PERSIST =
[:result, :spy_data]
Instance Method Summary
collapse
#code_block, #highlighted_code, #snippet_after, #snippet_between, #source, #source?
included
#ansi2html, #escape_html, #highlight, #slugify
#find_file, #relativize
Constructor Details
#initialize(hash) ⇒ Challenge
Returns a new instance of Challenge.
30
31
32
33
|
# File 'lib/polytrix/challenge.rb', line 30
def initialize(hash)
super
refresh
end
|
Instance Method Details
#absolute_source_file ⇒ Object
58
59
60
61
62
|
# File 'lib/polytrix/challenge.rb', line 58
def absolute_source_file
return nil if source_file.nil?
File.expand_path source_file, basedir
end
|
#action(what, &block) ⇒ Object
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
|
# File 'lib/polytrix/challenge.rb', line 148
def action(what, &block)
@state ||= state_file.read
@state['last_attempted_action'] = what.to_s
elapsed = Benchmark.measure do
block.call(@state)
end
@state['last_completed_action'] = what.to_s
elapsed
rescue Polytrix::FeatureNotImplementedError => e
raise e
rescue ActionFailed => e
log_failure(what, e)
raise(ChallengeFailure, failure_message(what) +
" Please see .polytrix/logs/#{name}.log for more details",
e.backtrace)
rescue Exception => e log_failure(what, e)
raise ActionFailed,
"Failed to complete ##{what} action: [#{e.message}]", e.backtrace
ensure
KEYS_TO_PERSIST.each do |key|
@state[key] = public_send(key)
end
state_file.write(@state) unless what == :destroy
end
|
#destroy ⇒ Object
93
94
95
|
# File 'lib/polytrix/challenge.rb', line 93
def destroy
transition_to :destroy
end
|
#destroy_action ⇒ Object
111
112
113
114
115
116
117
118
|
# File 'lib/polytrix/challenge.rb', line 111
def destroy_action
perform_action(:destroy, 'Destroying') do
@state_file.destroy
@state_file = nil
@state = {}
refresh
end
end
|
#detect ⇒ Object
64
65
66
|
# File 'lib/polytrix/challenge.rb', line 64
def detect
transition_to :detect
end
|
#exec ⇒ Object
76
77
78
|
# File 'lib/polytrix/challenge.rb', line 76
def exec
transition_to :exec
end
|
#exec_action ⇒ Object
80
81
82
83
84
85
86
87
|
# File 'lib/polytrix/challenge.rb', line 80
def exec_action
perform_action(:exec, 'Executing') do
fail FeatureNotImplementedError, "Implementor #{name} has not been cloned" unless implementor.cloned?
fail FeatureNotImplementedError, name if source_file.nil?
fail FeatureNotImplementedError, name unless File.exist?(absolute_source_file)
self.result = challenge_runner.run_challenge self
end
end
|
#failed? ⇒ Boolean
175
176
177
|
# File 'lib/polytrix/challenge.rb', line 175
def failed?
last_attempted_action != last_completed_action
end
|
#failure_message(what) ⇒ String
This method is part of a private API.
You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a string explaining what action failed, at a high level. Used for displaying to end user.
279
280
281
|
# File 'lib/polytrix/challenge.rb', line 279
def failure_message(what)
"#{what.capitalize} failed for test #{slug}."
end
|
#last_attempted_action ⇒ String
Returns the last successfully completed action state of the instance.
236
237
238
|
# File 'lib/polytrix/challenge.rb', line 236
def last_attempted_action
state_file.read['last_attempted_action']
end
|
#last_completed_action ⇒ Object
240
241
242
|
# File 'lib/polytrix/challenge.rb', line 240
def last_completed_action
state_file.read['last_completed_action']
end
|
#log_failure(what, _e) ⇒ Object
266
267
268
269
270
271
|
# File 'lib/polytrix/challenge.rb', line 266
def log_failure(what, _e)
return if logger.logdev.nil?
logger.logdev.error(failure_message(what))
end
|
#logger ⇒ Object
50
51
52
|
# File 'lib/polytrix/challenge.rb', line 50
def logger
implementor.logger
end
|
138
139
140
141
142
143
144
145
146
|
# File 'lib/polytrix/challenge.rb', line 138
def perform_action(verb, output_verb)
banner "#{output_verb} #{slug}..."
elapsed = action(verb) { yield }
info("Finished #{output_verb.downcase} #{slug}" \
" #{Util.duration(elapsed.real)}.")
self
end
|
#refresh ⇒ Object
39
40
41
42
43
44
|
# File 'lib/polytrix/challenge.rb', line 39
def refresh
@state = state_file.read
KEYS_TO_PERSIST.each do |key|
public_send("#{key}=".to_sym, @state[key]) if @state[key]
end
end
|
#sample? ⇒ Boolean
183
184
185
|
# File 'lib/polytrix/challenge.rb', line 183
def sample?
!source_file.nil?
end
|
#skipped? ⇒ Boolean
179
180
181
|
# File 'lib/polytrix/challenge.rb', line 179
def skipped?
result.nil?
end
|
#slug ⇒ Object
54
55
56
|
# File 'lib/polytrix/challenge.rb', line 54
def slug
slugify(suite, name, implementor.name)
end
|
#state_file ⇒ Object
35
36
37
|
# File 'lib/polytrix/challenge.rb', line 35
def state_file
@state_file ||= StateFile.new(Dir.pwd, slug)
end
|
#status ⇒ Object
187
188
189
190
|
# File 'lib/polytrix/challenge.rb', line 187
def status
status = last_attempted_action
failed? ? "#{status}_failed" : status
end
|
#status_color ⇒ Object
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
# File 'lib/polytrix/challenge.rb', line 216
def status_color
case status_description
when '<Not Found>' then :white
when 'Cloned' then :magenta
when 'Bootstrapped' then :magenta
when 'Sample Found' then :cyan
when 'Executed' then :blue
when /Verified/
if status_description =~ /Fully/
:green
else
:yellow
end
else :red
end
end
|
#status_description ⇒ Object
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
# File 'lib/polytrix/challenge.rb', line 192
def status_description
case status
when 'clone' then 'Cloned'
when 'clone_failed' then 'Clone Failed'
when 'detect' then 'Sample Found'
when 'detect_failed', nil then '<Not Found>'
when 'bootstrap' then 'Bootstrapped'
when 'bootstrap_failed' then 'Bootstrap Failed'
when 'detect' then 'Detected'
when 'exec' then 'Executed'
when 'exec_failed' then 'Execution Failed'
when 'verify', 'verify_failed'
validator_count = validators.count
validation_count = validations.values.select { |v| v['result'] == :passed }.count
if validator_count == validation_count
"Fully Verified (#{validation_count} of #{validator_count})"
else
"Partially Verified (#{validation_count} of #{validator_count})"
end
else "<Unknown (#{status})>"
end
end
|
#test(_destroy_mode = :passing) ⇒ Object
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/polytrix/challenge.rb', line 97
def test(_destroy_mode = :passing)
elapsed = Benchmark.measure do
banner "Cleaning up any prior instances of #{slug}"
destroy
banner "Testing #{slug}"
verify
end
info "Finished testing #{slug} #{Util.duration(elapsed.real)}."
self
end
|
#transition_to(desired) ⇒ Object
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
|
# File 'lib/polytrix/challenge.rb', line 249
def transition_to(desired)
transition_result = nil
begin
FSM.actions(last_completed_action, desired).each do |transition|
transition_result = send("#{transition}_action")
end
rescue Polytrix::FeatureNotImplementedError
warn("#{slug} is not implemented")
rescue ActionFailed => e
Polytrix.handle_error(e)
raise(ChallengeFailure, e.message, e.backtrace)
end
transition_result
end
|
#validations ⇒ Object
244
245
246
247
|
# File 'lib/polytrix/challenge.rb', line 244
def validations
return nil if result.nil?
result.validations
end
|
#verify ⇒ Object
89
90
91
|
# File 'lib/polytrix/challenge.rb', line 89
def verify
transition_to :verify
end
|
#verify_action ⇒ Object
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
# File 'lib/polytrix/challenge.rb', line 120
def verify_action
perform_action(:verify, 'Verifying') do
validators.each do |validator|
validation = validator.validate(self)
status = case validation.result
when :passed
Polytrix::Color.colorize("\u2713 Passed", :green)
when :failed
Polytrix::Color.colorize('x Failed', :red)
Polytrix.handle_validation_failure(validation.error)
else
Polytrix::Color.colorize(validation.result, :yellow)
end
info format('%-50s %s', validator.description, status)
end
end
end
|