rspec-teamcity 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,279 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2000-2012 JetBrains s.r.o.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ # @author: Roman Chernyatchik
18
+ ######################
19
+ #noinspection RubyResolve
20
+ require_relative "../rakerunner_consts"
21
+
22
+ module Rake
23
+ module TeamCity
24
+ module MessageFactory
25
+
26
+ MSG_BLOCK_TYPES = {
27
+ # :build => "Build" # BLOCK_TYPE_BUILD
28
+ :progress => "$BUILD_PROGRESS$", # BLOCK_TYPE_PROGRESS
29
+ :test => "$TEST_BLOCK$", # BLOCK_TYPE_TEST
30
+ :test_suite => "$TEST_SUITE$", # BLOCK_TYPE_TEST_SUITE
31
+ :compilation => "$COMPILATION_BLOCK$", # BLOCK_TYPE_COMPILATION
32
+ :target => "$TARGET_BLOCK$", # BLOCK_TYPE_TARGET
33
+ :task => "rakeTask"
34
+ }
35
+
36
+ MSG_STATUS_TYPES = {
37
+ :warning => "WARNING",
38
+ :error => "ERROR"
39
+ }
40
+
41
+ CUSTOM_MSG_TYPES = {
42
+ :started => 'testStarted',
43
+ :failed => 'testFailed'
44
+ }
45
+
46
+ MOCK_ATTRIBUTES_VALUES = {
47
+ :details => {:value => '##STACK_TRACE##', :enabled => ::Rake::TeamCity.is_fake_stacktrace_enabled?, :remove_empty => true},
48
+ :errorDetails => {:value => '##STACK_TRACE##', :enabled => ::Rake::TeamCity.is_fake_stacktrace_enabled?, :remove_empty => true},
49
+ :locationHint => {:value => '##LOCATION_URL##', :enabled => ::Rake::TeamCity.is_fake_location_url_enabled?, :remove_empty => true},
50
+ :duration => {:value => '##DURATION##', :enabled => ::Rake::TeamCity.is_fake_time_enabled?},
51
+ :time => {:value => '##TIME##', :enabled => ::Rake::TeamCity.is_fake_time_enabled?},
52
+ :error_msg => {:value => '##MESSAGE##', :enabled => ::Rake::TeamCity.is_fake_error_msg_enabled?}
53
+ }
54
+
55
+ def self.create_suite_started(suite_name, location_url = nil)
56
+ create_message :message_name => "testSuiteStarted",
57
+ :name => suite_name,
58
+ :locationHint => location_url
59
+ end
60
+
61
+ def self.create_suite_finished(suite_name)
62
+ create_message :message_name => "testSuiteFinished",
63
+ :name => suite_name
64
+ end
65
+
66
+ def self.create_tests_count(int_count)
67
+ create_message :message_name => "testCount",
68
+ :count => int_count
69
+ end
70
+
71
+ def self.create_test_started(test_name, location_url = nil)
72
+ create_message :message_name => "testStarted",
73
+ :name => test_name,
74
+ :captureStandardOutput => 'true',
75
+ :locationHint => location_url
76
+ end
77
+
78
+ # Duration in millisec
79
+ def self.create_test_finished(test_name, duration_ms, diagnostic_info=nil)
80
+ create_message :message_name => "testFinished",
81
+ :name => test_name,
82
+ :duration => [duration_ms, 0].max,
83
+ :diagnosticInfo => diagnostic_info
84
+ end
85
+
86
+ def self.create_test_output_message(test_name, is_std_out, out_text)
87
+ create_message :message_name => "testStd#{is_std_out ? "Out" : "Err"}",
88
+ :name => test_name,
89
+ :out => out_text
90
+ end
91
+
92
+ def self.create_test_failed(test_name, message, stacktrace)
93
+ stacktrace = format_stacktrace_if_needed(message, stacktrace)
94
+ create_message :message_name => 'testFailed',
95
+ :name => test_name,
96
+ :message => message,
97
+ :details => stacktrace
98
+ end
99
+
100
+ def self.create_test_error(test_name, message, stacktrace)
101
+ stacktrace = format_stacktrace_if_needed(message, stacktrace)
102
+ create_message :message_name => 'testFailed',
103
+ :name => test_name,
104
+ :message => message,
105
+ :details => stacktrace,
106
+ :error => 'true'
107
+ end
108
+
109
+ def self.create_test_ignored(test_name, message, stacktrace = nil)
110
+ create_message :message_name => 'testIgnored',
111
+ :name => test_name,
112
+ :message => message,
113
+ :details => stacktrace
114
+ end
115
+
116
+ # This message should show progress on buildserver and can be
117
+ # ignored by IDE tests runners
118
+ def self.create_progress_message(message)
119
+ # This kind of message doesn't support timestamp attribute
120
+ create_message :message_name => 'progressMessage',
121
+ :message_text => message
122
+ end
123
+
124
+ # This message should show custom build status on buildserver and can be
125
+ # ignored by IDE tests runners
126
+ def self.create_build_error_report(message)
127
+ create_message :message_name => 'buildStatus',
128
+ :status => MSG_STATUS_TYPES[:error],
129
+ :text => message
130
+ end
131
+
132
+ def self.create_msg_error(message, stacktrace = nil)
133
+ attrs = {
134
+ :message_name => 'message',
135
+ :text => message,
136
+ :status => MSG_STATUS_TYPES[:error],
137
+ :errorDetails => stacktrace
138
+ }
139
+ attrs[:text] &&= MOCK_ATTRIBUTES_VALUES[:error_msg][:value] if MOCK_ATTRIBUTES_VALUES[:error_msg][:enabled]
140
+
141
+ create_message attrs
142
+ end
143
+
144
+ def self.create_msg_warning(message, stacktrace = nil)
145
+ create_message :message_name => 'message',
146
+ :text => message,
147
+ :status => MSG_STATUS_TYPES[:warning],
148
+ :errorDetails => stacktrace
149
+ end
150
+
151
+ def self.create_open_target(message)
152
+ create_message :message_name => 'blockOpened',
153
+ :name => message,
154
+ :type => MSG_BLOCK_TYPES[:target]
155
+ end
156
+
157
+ def self.create_close_target(message)
158
+ create_message :message_name => 'blockClosed',
159
+ :name => message,
160
+ :type => MSG_BLOCK_TYPES[:target]
161
+ end
162
+
163
+ #noinspection RubyClassMethodNamingConvention
164
+ def self.create_custom_progress_tests_category(category_name, int_count = 0)
165
+ create_message :message_name => 'customProgressStatus',
166
+ :testsCategory => category_name,
167
+ :count => int_count
168
+ end
169
+
170
+ #noinspection RubyClassMethodNamingConvention
171
+ def self.create_custom_progress_test_status(status)
172
+ create_message :message_name => 'customProgressStatus',
173
+ :type => CUSTOM_MSG_TYPES[status]
174
+ end
175
+
176
+ def self.create_test_reported_attached
177
+ # Allows to distinguish 2 situations
178
+ # * nothing to test - no tests, suites
179
+ # * test reporter wasn't attached
180
+ # Can be reported several times
181
+ create_message :message_name => 'enteredTheMatrix'
182
+ end
183
+
184
+ ###################################################################
185
+ ###################################################################
186
+ ###################################################################
187
+
188
+ def self.replace_escaped_symbols(text)
189
+ copy_of_text = String.new(text)
190
+
191
+ copy_of_text.gsub!(/\|/, "||")
192
+
193
+ copy_of_text.gsub!(/'/, "|'")
194
+ copy_of_text.gsub!(/\n/, "|n")
195
+ copy_of_text.gsub!(/\r/, "|r")
196
+ copy_of_text.gsub!(/\]/, "|]")
197
+
198
+ copy_of_text.gsub!(/\[/, "|[")
199
+
200
+ begin
201
+ copy_of_text.encode!('UTF-8') if copy_of_text.respond_to? :encode!
202
+ copy_of_text.gsub!(/\u0085/, "|x") # next line
203
+ copy_of_text.gsub!(/\u2028/, "|l") # line separator
204
+ copy_of_text.gsub!(/\u2029/, "|p") # paragraph separator
205
+ rescue
206
+ # it is not an utf-8 compatible string :(
207
+ end
208
+
209
+ copy_of_text
210
+ end
211
+
212
+ private
213
+ def self.format_stacktrace_if_needed message, stacktrace
214
+ if Rake::TeamCity.is_in_buildserver_mode()
215
+ # At current moment TC doesn't extract message from corresponding attribute.
216
+ # see [TW-6270] http://jetbrains.net/tracker/workspace?currentIssueId=TW-6270
217
+ message + "\n\nStack trace:\n" + stacktrace
218
+ else
219
+ stacktrace
220
+ end
221
+ end
222
+
223
+ protected
224
+
225
+ def self.create_message(msg_attrs = {})
226
+ # message type:
227
+ message_name = msg_attrs.delete(:message_name)
228
+
229
+ # optional body
230
+ message_text = msg_attrs[:message_text]
231
+
232
+ # if diagnostic info is null - don't pass it'
233
+ diagnostic = msg_attrs[:diagnosticInfo]
234
+ unless diagnostic
235
+ msg_attrs.delete(:diagnosticInfo)
236
+ end
237
+
238
+ if message_text.nil?
239
+ # mock some attrs
240
+ [:details, :errorDetails, :locationHint, :duration].each do |key|
241
+ if msg_attrs[key].nil?
242
+ # if key is nil - don't include in msg attrs
243
+ msg_attrs.delete(key) if MOCK_ATTRIBUTES_VALUES[key][:remove_empty]
244
+ else
245
+ # if not nil & debug mode - mock it
246
+ msg_attrs[key] = MOCK_ATTRIBUTES_VALUES[key][:value] if MOCK_ATTRIBUTES_VALUES[key][:enabled]
247
+ end
248
+ end
249
+
250
+ # add auto timestamp
251
+ msg_attrs[:timestamp] ||= convert_time_to_java_simple_date(Time.now)
252
+
253
+ # message args
254
+ message_args = msg_attrs.map { |k, v| "#{k.to_s} = '#{v.nil? ? "" : replace_escaped_symbols(v.to_s)}'" }.join(" ")
255
+ else
256
+ message_args = "'#{message_text}'"
257
+ end
258
+
259
+ "##teamcity[#{message_name}#{message_args.empty? ? '' : " #{message_args}"}]"
260
+ end
261
+
262
+ #noinspection RubyClassMethodNamingConvention
263
+ def self.convert_time_to_java_simple_date(time)
264
+ if MOCK_ATTRIBUTES_VALUES[:time][:enabled]
265
+ return MOCK_ATTRIBUTES_VALUES[:time][:value]
266
+ end
267
+ gmt_offset = time.gmt_offset
268
+ gmt_sign = gmt_offset < 0 ? "-" : "+"
269
+ gmt_hours = gmt_offset.abs / 3600
270
+ gmt_minutes = gmt_offset.abs % 3600
271
+
272
+ millisec = time.usec == 0 ? 0 : time.usec / 1000
273
+
274
+ #Time string in Java SimpleDateFormat
275
+ sprintf("#{time.strftime("%Y-%m-%dT%H:%M:%S.")}%03d#{gmt_sign}%02d%02d", millisec, gmt_hours, gmt_minutes)
276
+ end
277
+ end
278
+ end
279
+ end
@@ -0,0 +1,103 @@
1
+ # Copyright 2000-2012 JetBrains s.r.o.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Created by IntelliJ IDEA.
16
+ #
17
+ # @author: Roman.Chernyatchik
18
+ # @date: 10.01.2008
19
+ require_relative '../rakerunner_consts'
20
+
21
+ module Rake
22
+ module TeamCity
23
+
24
+ # Captures STDOUT and STDERR
25
+ module StdCaptureHelper
26
+ require 'tempfile'
27
+
28
+ def isCaptureDisabled()
29
+ ENV[TEAMCITY_RAKERUNNER_LOG_OUTPUT_CAPTURER_ENABLED_KEY] != "true"
30
+ end
31
+
32
+ def capture_output_start_external
33
+ old_out, old_err = copy_stdout_stderr
34
+
35
+ if isCaptureDisabled()
36
+ return old_out, old_err, nil, nil
37
+ end
38
+
39
+ new_out = Tempfile.new("tempfile_out")
40
+ new_err = Tempfile.new("tempfile_err")
41
+
42
+ reopen_stdout_stderr(new_out, new_err)
43
+
44
+ return old_out, old_err, new_out, new_err
45
+ end
46
+
47
+ def copy_stdout_stderr
48
+ if isCaptureDisabled()
49
+ return STDOUT, STDERR
50
+ else
51
+ return STDOUT.dup, STDERR.dup
52
+ end
53
+ end
54
+
55
+ def reopen_stdout_stderr(sout, serr)
56
+ STDOUT.reopen(sout)
57
+ STDERR.reopen(serr)
58
+ nil
59
+ end
60
+
61
+ # returns STDOUT and STDERR content
62
+ def capture_output_end_external(old_out, old_err, new_out, new_err)
63
+ STDOUT.flush
64
+ STDERR.flush
65
+
66
+ if isCaptureDisabled()
67
+ return "", ""
68
+ end
69
+
70
+ reopen_stdout_stderr(old_out, old_err)
71
+
72
+ return get_redirected_stdout_stderr_from_files(new_out, new_err)
73
+ end
74
+
75
+ # Closes files' streams and gets its output.
76
+ def get_redirected_stdout_stderr_from_files(new_out, new_err)
77
+ if isCaptureDisabled()
78
+ return "", ""
79
+ end
80
+
81
+ begin
82
+ new_out.close
83
+ new_out.open
84
+ s_out = new_out.readlines.join
85
+ new_out.close
86
+ rescue Exception => ex
87
+ s_out = "Error: Teamcity agent is unable to capture STDOUT: #{ex}"
88
+ end
89
+
90
+ begin
91
+ new_err.close
92
+ new_err.open
93
+ s_err = new_err.readlines.join
94
+ new_err.close
95
+ rescue Exception => ex
96
+ s_err = "Error: Teamcity agent is unable to capture STDERR: #{ex}"
97
+ end
98
+
99
+ return s_out, s_err
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,28 @@
1
+ # Copyright 2000-2012 JetBrains s.r.o.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Created by IntelliJ IDEA.
16
+ #
17
+ # @author: Roman.Chernyatchik
18
+ # @date: 02.06.2007
19
+
20
+ class String
21
+ def starts_with? str
22
+ self[0...str.length] == str
23
+ end
24
+
25
+ def substring index
26
+ self[index..size - 1]
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright 2000-2012 JetBrains s.r.o.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # @author: Roman.Chernyatchik
16
+
17
+ module Rake
18
+ module TeamCity
19
+ module Utils
20
+ module UrlFormatter
21
+ # @Nullable
22
+ def location_from_link(path, line_str)
23
+ return nil if (path.nil? || line_str.nil?)
24
+ "file://#{path}:#{line_str}"
25
+ end
26
+
27
+ # @Nullable
28
+ def location_from_ruby_qualified_name(qualified_name)
29
+ return nil if (qualified_name.nil?)
30
+ "ruby_qn://#{qualified_name}"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end