rspec-teamcity 0.0.1

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.
@@ -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