<br><font size=2 face="sans-serif">Thanks a lot!</font>
<br>
<br><tt><font size=2>> Is this the appropriate way to submit patches?</font></tt>
<br><font size=2 face="sans-serif">Yes, until we have a more appropriate
way (aka a bug tracker).</font>
<br>
<br><font size=2 face="sans-serif">This submission raises a question that
was at the back of my mind ever since we had Test::Unit results formatter
in this codebase.</font>
<br><font size=2 face="sans-serif">Custom formatting of build log is going
to be in demand. How do we pluginize it? </font>
<br>
<br><font size=2 face="sans-serif">How about this solution:</font>
<br><font size=2 face="sans-serif">* Let's make formatting of build log
a builder's responsibility.</font>
<br><font size=2 face="sans-serif">* This can be done by a builder plugin
in response to :build_finished event</font>
<br>
<br><font size=2 face="sans-serif">Another question then arises: what do
we want to do with intermediate build products? We don't really want to
delete them (troubleshooting), but we also don't want to display links
to them on the dashboard. I think, use hidden files for that. </font>
<br>
<br><font size=2 face="sans-serif">I.e., you start with build.log file.
Format it and write the output into build.log.html (without html and body
tags though, because we are displaying it on the dashboard page). It's
also a good time to merge it with the changeset etc. Finally, hide the
originals from the dashboard by renaming build.log to .build.log and changeset.log
to .changeset.log.</font>
<br>
<br><font size=2 face="sans-serif">Thoughts?</font>
<br>
<br><font size=2 face="sans-serif">Best regards,</font>
<br><font size=2 face="sans-serif">Alex</font>
<br>
<br>
<br>
<br>
<br>
<br>
<table width=100%>
<tr valign=top>
<td width=40%><font size=1 face="sans-serif"><b>Randall Potter <rpotter@anl.gov></b>
</font>
<br><font size=1 face="sans-serif">Sent by: cruisecontrolrb-developers-bounces@rubyforge.org</font>
<p><font size=1 face="sans-serif">02/10/2007 12:23 AM</font>
<td width=59%>
<table width=100%>
<tr valign=top>
<td>
<div align=right><font size=1 face="sans-serif">To</font></div>
<td><font size=1 face="sans-serif">cruisecontrolrb-developers@rubyforge.org</font>
<tr valign=top>
<td>
<div align=right><font size=1 face="sans-serif">cc</font></div>
<td>
<tr valign=top>
<td>
<div align=right><font size=1 face="sans-serif">Subject</font></div>
<td><font size=1 face="sans-serif">[Cruisecontrolrb-developers] [patch]
rspec support (partial)</font></table>
<br>
<table>
<tr valign=top>
<td>
<td></table>
<br></table>
<br>
<br>
<br><tt><font size=2>story:<br>
As a Dev, I would like CC.rb to display rspec failures in
'Test <br>
Failures and Errors', so that I can use rspec.<br>
<br>
Is this the appropriate way to submit patches?<br>
<br>
Thank you in advance for your time,<br>
<br>
rpotter<br>
<br>
--- app/models/test_failure_parser.rb (revision 181)<br>
+++ app/models/test_failure_parser.rb (working copy)<br>
@@ -1,25 +1,51 @@<br>
class TestFailureParser <br>
- TEST_NAME_REGEX = /\S+/<br>
- MESSAGE_REGEX = /\]\:\n([\s\S]+)/<br>
- STACK_TRACE_REGEX = /\[([\s\S]*?)\]\:/<br>
- TEST_FAILURE_BLOCK_REGEX = /^\s+\d+\) Failure:\n([\S\s]*?)\n\n/<br>
+<br>
+ TEST_FAILURE_BLOCK_REGEX = /^\s+?\d+\)(( Failure:)?\n[\S\s]*?)\n\n/<br>
+ <br>
+ SPEC_FAILURE_FORMAT = /^'[\s\S]+'\sFAILED[\s\S]*?/<br>
+ TEST_UNIT_FAILURE_FORMAT = / <br>
Failure:\n(\S+)\n?\s+?\[([\s\S]*?)\]:\n([\s\S]+)/<br>
+ <br>
def get_test_failures(log)<br>
testFailures = Array.new<br>
<br>
log.gsub(TEST_FAILURE_BLOCK_REGEX) do |text|<br>
content = $1<br>
- <br>
- begin<br>
- test_name = content.match(TEST_NAME_REGEX).to_s
<br>
- message = content.match(MESSAGE_REGEX)[1]<br>
- stack_trace = content.match(STACK_TRACE_REGEX)[1]<br>
- <br>
- testFailures << TestErrorEntry.create_failure(test_name,
<br>
message, stack_trace)<br>
- rescue<br>
- # Do Nothing, Pattern does not match<br>
- end <br>
+ <br>
+ if content.match(TEST_UNIT_FAILURE_FORMAT)<br>
+ testFailures << parse_as_test_unit(content)<br>
+ elsif content.gsub("\n",'').match(SPEC_FAILURE_FORMAT)<br>
+ testFailures << parse_as_rspec(content)<br>
+ else<br>
+ # no failures or we don't recognize
it<br>
+ end<br>
+ <br>
end<br>
<br>
testFailures<br>
end<br>
-end<br>
\ No newline at end of file<br>
+ <br>
+ private<br>
+ <br>
+ # parse Test::Unit log message and return TestErrorEntry<br>
+ def parse_as_test_unit(content)<br>
+ <br>
+ test_name = content.match(TEST_UNIT_FAILURE_FORMAT)[1].to_s
<br>
+ message = content.match(TEST_UNIT_FAILURE_FORMAT)[3]<br>
+ stack_trace = content.match(TEST_UNIT_FAILURE_FORMAT)[2]<br>
+ <br>
+ TestErrorEntry.create_failure(test_name, message, stack_trace)<br>
+ end<br>
+ <br>
+ # parse rspec log message and return TestErrorEntry<br>
+ def parse_as_rspec(content)<br>
+ <br>
+ spec_arr = content.split("\n")<br>
+ <br>
+ test_name = spec_arr[1].match(/^'([\s\S]+)' FAILED$/)[1].to_s
<br>
+ message = spec_arr[2].to_s<br>
+ stack_trace = spec_arr.slice(3..spec_arr.length).join("\n")<br>
+ <br>
+ TestErrorEntry.create_failure(test_name, message, stack_trace)<br>
+ end<br>
+ <br>
+end<br>
<br>
--- test/unit/test_failure_parser_test.rb (revision 181)<br>
+++ working_copy/test/unit/test_failure_parser_test.rb (working
copy)<br>
@@ -77,6 +77,34 @@<br>
83 tests, 185 assertions, 2 failures, 0 errors<br>
EOF<br>
<br>
+LOG_OUTPUT_WITH_NO_SPEC_FAILURE = <<EOF<br>
+<br>
+.............................................................<br>
+<br>
+Finished in 1.199703 seconds<br>
+<br>
+61 specifications, 0 failures<br>
+EOF<br>
+<br>
+LOG_OUTPUT_WITH_SPEC_FAILURE = <<EOF<br>
+/usr/local/bin/spec:17:Warning: require_gem is obsolete. Use gem instead.<br>
+<br>
+....F....<br>
+<br>
+1)<br>
+'Given a request to edit with a week and year the controller should <br>
return a hash of one blank row if data ! found' FAILED<br>
+nil should be a kind of Array<br>
+./spec/controllers/consultant_controller_spec.rb:47:<br>
+/cruisecontrol/builds/ccs/work/config/../lib/tasks/cruise.rake:36:in `run'<br>
+/cruisecontrol/builds/ccs/work/config/../lib/tasks/cruise.rake:47:<br>
+/cruisecontrol/tasks/cc_build.rake:32:<br>
+-e:1:<br>
+<br>
+Finished in 0.484439 seconds<br>
+<br>
+9 specifications, 1 failure<br>
+EOF<br>
+<br>
def test_should_not_find_test_failures_with_a_build_with_test_errors<br>
testFailures = <br>
TestFailureParser.new.get_test_failures(LOG_OUTPUT_WITH_TEST_ERRORS)<br>
assert_equal 0, testFailures.length<br>
@@ -87,19 +115,30 @@<br>
assert_equal 0, testFailures.length
<br>
end<br>
<br>
+ def test_should_find_no_spec_failures_with_successful_build<br>
+ testFailures = <br>
TestFailureParser.new.get_test_failures(LOG_OUTPUT_WITH_NO_SPEC_FAILURE)<br>
+ assert_equal 0, testFailures.length
<br>
+ end<br>
+ <br>
def test_should_find_test_failures<br>
testFailures = <br>
TestFailureParser.new.get_test_failures(LOG_OUTPUT_WITH_TEST_FAILURE)<br>
assert_equal 2, testFailures.length<br>
assert_equal expected_first_test_failure, testFailures[0]<br>
assert_equal expected_second_test_failure, testFailures[1]<br>
end<br>
- <br>
+ <br>
+ def test_should_find_spec_failures<br>
+ testFailures = <br>
TestFailureParser.new.get_test_failures(LOG_OUTPUT_WITH_SPEC_FAILURE)<br>
+ assert_equal 1, testFailures.length<br>
+ assert_equal expected_first_spec_failure, testFailures[0]<br>
+ end<br>
+ <br>
def test_should_correctly_parse_mocha_test_failures<br>
testFailures = <br>
TestFailureParser.new.get_test_failures(LOG_OUTPUT_WITH_MOCK_TEST_FAILURE)<br>
assert_equal 1, testFailures.length<br>
assert_equal expected_mock_test_failure, testFailures[0]<br>
end<br>
- <br>
+ <br>
def expected_first_test_failure<br>
<br>
TestErrorEntry.create_failure("test_should_fail(SubversionLogParserTest)",<br>
"<1> expected
but was\n<\"abc\">.",<br>
@@ -121,5 +160,15 @@<br>
<br>
"#<Mocha::Mock:0x-245ec74a>.force_build_if_requested - expected
calls: <br>
1, actual calls: 2",<br>
<br>
"./test/unit/polling_scheduler_test.rb:44")<br>
end<br>
+<br>
+ def expected_first_spec_failure<br>
+ TestErrorEntry.create_failure("Given a request to edit
with a week <br>
and year the controller should return a hash of one blank row if data !
<br>
found",<br>
+
"nil should be a kind
of Array",<br>
+
<br>
"./spec/controllers/consultant_controller_spec.rb:47:\n" +<br>
+
<br>
"/cruisecontrol/builds/ccs/work/config/../lib/tasks/cruise.rake:36:in
<br>
`run'\n" +<br>
+
<br>
"/cruisecontrol/builds/ccs/work/config/../lib/tasks/cruise.rake:47:\n"
+<br>
+
<br>
"/cruisecontrol/tasks/cc_build.rake:32:\n" +<br>
+
"-e:1:")<br>
+ end<br>
<br>
end<br>
\ No newline at end of file<br>
<br>
<br>
_______________________________________________<br>
Cruisecontrolrb-developers mailing list<br>
Cruisecontrolrb-developers@rubyforge.org<br>
http://rubyforge.org/mailman/listinfo/cruisecontrolrb-developers<br>
</font></tt>
<br>