newrelic_rpm 3.0.1 → 3.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of newrelic_rpm might be problematic. Click here for more details.

Files changed (74) hide show
  1. data/CHANGELOG +2 -3
  2. data/README.rdoc +3 -3
  3. data/lib/new_relic/agent.rb +19 -7
  4. data/lib/new_relic/agent/agent.rb +83 -19
  5. data/lib/new_relic/agent/beacon_configuration.rb +8 -12
  6. data/lib/new_relic/agent/browser_monitoring.rb +8 -8
  7. data/lib/new_relic/agent/error_collector.rb +13 -13
  8. data/lib/new_relic/agent/instrumentation.rb +9 -0
  9. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +10 -2
  10. data/lib/new_relic/agent/instrumentation/metric_frame.rb +41 -35
  11. data/lib/new_relic/agent/instrumentation/metric_frame/pop.rb +92 -0
  12. data/lib/new_relic/agent/method_tracer.rb +0 -2
  13. data/lib/new_relic/agent/shim_agent.rb +2 -0
  14. data/lib/new_relic/agent/stats_engine/metric_stats.rb +89 -60
  15. data/lib/new_relic/agent/stats_engine/transactions.rb +1 -1
  16. data/lib/new_relic/agent/worker_loop.rb +1 -1
  17. data/lib/new_relic/collection_helper.rb +0 -2
  18. data/lib/new_relic/control/class_methods.rb +25 -12
  19. data/lib/new_relic/control/logging_methods.rb +30 -17
  20. data/lib/new_relic/data_serialization.rb +81 -0
  21. data/lib/new_relic/local_environment.rb +1 -1
  22. data/lib/new_relic/metric_data.rb +9 -5
  23. data/lib/new_relic/metric_spec.rb +7 -1
  24. data/lib/new_relic/rack/browser_monitoring.rb +1 -7
  25. data/lib/new_relic/stats.rb +4 -0
  26. data/lib/new_relic/transaction_analysis.rb +45 -88
  27. data/lib/new_relic/transaction_analysis/segment_summary.rb +47 -0
  28. data/lib/new_relic/transaction_sample.rb +15 -332
  29. data/lib/new_relic/transaction_sample/composite_segment.rb +27 -0
  30. data/lib/new_relic/transaction_sample/fake_segment.rb +9 -0
  31. data/lib/new_relic/transaction_sample/segment.rb +250 -0
  32. data/lib/new_relic/transaction_sample/summary_segment.rb +21 -0
  33. data/lib/new_relic/version.rb +3 -3
  34. data/newrelic.yml +3 -3
  35. data/newrelic_rpm.gemspec +27 -4
  36. data/test/active_record_fixtures.rb +31 -13
  37. data/test/new_relic/agent/agent/start_worker_thread_test.rb +1 -3
  38. data/test/new_relic/agent/agent_test.rb +73 -28
  39. data/test/new_relic/agent/agent_test_controller_test.rb +11 -10
  40. data/test/new_relic/agent/beacon_configuration_test.rb +37 -20
  41. data/test/new_relic/agent/browser_monitoring_test.rb +17 -28
  42. data/test/new_relic/agent/error_collector/notice_error_test.rb +9 -7
  43. data/test/new_relic/agent/error_collector_test.rb +6 -7
  44. data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +12 -5
  45. data/test/new_relic/agent/instrumentation/metric_frame/pop_test.rb +195 -0
  46. data/test/new_relic/agent/instrumentation/net_instrumentation_test.rb +60 -58
  47. data/test/new_relic/agent/instrumentation/queue_time_test.rb +14 -0
  48. data/test/new_relic/agent/instrumentation/rack_test.rb +35 -0
  49. data/test/new_relic/agent/instrumentation/task_instrumentation_test.rb +0 -1
  50. data/test/new_relic/agent/method_tracer_test.rb +8 -8
  51. data/test/new_relic/agent/sampler_test.rb +19 -0
  52. data/test/new_relic/agent/shim_agent_test.rb +20 -0
  53. data/test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb +150 -0
  54. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +1 -0
  55. data/test/new_relic/agent/stats_engine/samplers_test.rb +4 -3
  56. data/test/new_relic/agent/{stats_engine/stats_engine_test.rb → stats_engine_test.rb} +8 -8
  57. data/test/new_relic/agent/transaction_sampler_test.rb +1 -1
  58. data/test/new_relic/agent/worker_loop_test.rb +2 -2
  59. data/test/new_relic/control/class_methods_test.rb +62 -0
  60. data/test/new_relic/control/logging_methods_test.rb +157 -0
  61. data/test/new_relic/control_test.rb +10 -10
  62. data/test/new_relic/data_serialization_test.rb +50 -0
  63. data/test/new_relic/local_environment_test.rb +13 -13
  64. data/test/new_relic/metric_data_test.rb +125 -0
  65. data/test/new_relic/metric_spec_test.rb +8 -0
  66. data/test/new_relic/transaction_analysis/segment_summary_test.rb +77 -0
  67. data/test/new_relic/transaction_analysis_test.rb +121 -0
  68. data/test/new_relic/transaction_sample/composite_segment_test.rb +35 -0
  69. data/test/new_relic/transaction_sample/fake_segment_test.rb +17 -0
  70. data/test/new_relic/transaction_sample/segment_test.rb +454 -0
  71. data/test/new_relic/transaction_sample/summary_segment_test.rb +31 -0
  72. data/test/new_relic/transaction_sample_test.rb +51 -0
  73. data/test/test_helper.rb +4 -14
  74. metadata +32 -7
@@ -0,0 +1,9 @@
1
+ require 'new_relic/transaction_sample'
2
+ require 'new_relic/transaction_sample/segment'
3
+ module NewRelic
4
+ class TransactionSample
5
+ class FakeSegment < Segment
6
+ public :parent_segment=
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,250 @@
1
+ require 'new_relic/transaction_sample'
2
+ module NewRelic
3
+ class TransactionSample
4
+ class Segment
5
+ attr_reader :entry_timestamp
6
+ # The exit timestamp will be relative except for the outermost sample which will
7
+ # have a timestamp.
8
+ attr_reader :exit_timestamp
9
+ attr_reader :parent_segment
10
+ attr_reader :metric_name
11
+ attr_reader :segment_id
12
+
13
+ def initialize(timestamp, metric_name, segment_id)
14
+ @entry_timestamp = timestamp
15
+ @metric_name = metric_name || '<unknown>'
16
+ @segment_id = segment_id || object_id
17
+ end
18
+
19
+ def end_trace(timestamp)
20
+ @exit_timestamp = timestamp
21
+ end
22
+
23
+ def add_called_segment(s)
24
+ @called_segments ||= []
25
+ @called_segments << s
26
+ s.parent_segment = self
27
+ end
28
+
29
+ def to_s
30
+ to_debug_str(0)
31
+ end
32
+
33
+ def to_json
34
+ hash = {
35
+ :entry_timestamp => @entry_timestamp,
36
+ :exit_timestamp => @exit_timestamp,
37
+ :metric_name => @metric_name,
38
+ :segment_id => @segment_id,
39
+ }
40
+
41
+ hash[:called_segments] = called_segments if !called_segments.empty?
42
+ hash[:params] = @params if @params && !@params.empty?
43
+
44
+ hash.to_json
45
+ end
46
+
47
+ def path_string
48
+ "#{metric_name}[#{called_segments.collect {|segment| segment.path_string }.join('')}]"
49
+ end
50
+ def to_s_compact
51
+ str = ""
52
+ str << metric_name
53
+ if called_segments.any?
54
+ str << "{#{called_segments.map { | cs | cs.to_s_compact }.join(",")}}"
55
+ end
56
+ str
57
+ end
58
+ def to_debug_str(depth)
59
+ tab = " " * depth
60
+ s = tab.clone
61
+ s << ">> #{'%3i ms' % (@entry_timestamp*1000)} [#{self.class.name.split("::").last}] #{metric_name} \n"
62
+ unless params.empty?
63
+ params.each do |k,v|
64
+ s << "#{tab} -#{'%-16s' % k}: #{v.to_s[0..80]}\n"
65
+ end
66
+ end
67
+ called_segments.each do |cs|
68
+ s << cs.to_debug_str(depth + 1)
69
+ end
70
+ s << tab + "<< "
71
+ s << case @exit_timestamp
72
+ when nil then ' n/a'
73
+ when Numeric then '%3i ms' % (@exit_timestamp*1000)
74
+ else @exit_timestamp.to_s
75
+ end
76
+ s << " #{metric_name}\n"
77
+ end
78
+
79
+ def called_segments
80
+ @called_segments || []
81
+ end
82
+
83
+ # return the total duration of this segment
84
+ def duration
85
+ (@exit_timestamp - @entry_timestamp).to_f
86
+ end
87
+
88
+ # return the duration of this segment without
89
+ # including the time in the called segments
90
+ def exclusive_duration
91
+ d = duration
92
+
93
+ called_segments.each do |segment|
94
+ d -= segment.duration
95
+ end
96
+ d
97
+ end
98
+ def count_segments
99
+ count = 1
100
+ called_segments.each { | seg | count += seg.count_segments }
101
+ count
102
+ end
103
+ # Walk through the tree and truncate the segments
104
+ def truncate(max)
105
+ return 1 unless @called_segments
106
+ total, self.called_segments = truncate_each_child(max - 1)
107
+ total+1
108
+ end
109
+
110
+ def truncate_each_child(max)
111
+ total = 0
112
+ accumulator = []
113
+ called_segments.each { | s |
114
+ if total == max
115
+ true
116
+ else
117
+ total += s.truncate(max - total)
118
+ accumulator << s
119
+ end
120
+ }
121
+ total
122
+ [total, accumulator]
123
+ end
124
+
125
+ def []=(key, value)
126
+ # only create a parameters field if a parameter is set; this will save
127
+ # bandwidth etc as most segments have no parameters
128
+ params[key] = value
129
+ end
130
+
131
+ def [](key)
132
+ params[key]
133
+ end
134
+
135
+ def params
136
+ @params ||= {}
137
+ end
138
+
139
+ # call the provided block for this segment and each
140
+ # of the called segments
141
+ def each_segment(&block)
142
+ block.call self
143
+
144
+ if @called_segments
145
+ @called_segments.each do |segment|
146
+ segment.each_segment(&block)
147
+ end
148
+ end
149
+ end
150
+
151
+ def find_segment(id)
152
+ return self if @segment_id == id
153
+ called_segments.each do |segment|
154
+ found = segment.find_segment(id)
155
+ return found if found
156
+ end
157
+ nil
158
+ end
159
+
160
+ # perform this in the runtime environment of a managed
161
+ # application, to explain the sql statement(s) executed within a
162
+ # segment of a transaction sample. returns an array of
163
+ # explanations (which is an array rows consisting of an array of
164
+ # strings for each column returned by the the explain query)
165
+ # Note this happens only for statements whose execution time
166
+ # exceeds a threshold (e.g. 500ms) and only within the slowest
167
+ # transaction in a report period, selected for shipment to RPM
168
+ def explain_sql
169
+ sql = params[:sql]
170
+ return nil unless sql && params[:connection_config]
171
+ statements = sql.split(";\n")
172
+ statements.map! do |statement|
173
+ # a small sleep to make sure we yield back to the parent
174
+ # thread regularly, if there are many explains
175
+ sleep(0.0001)
176
+ explain_statement(statement, params[:connection_config])
177
+ end
178
+ statements.compact!
179
+ statements
180
+ end
181
+
182
+ def explain_statement(statement, config)
183
+ if is_select?(statement)
184
+ handle_exception_in_explain do
185
+ connection = NewRelic::TransactionSample.get_connection(config)
186
+ process_resultset(connection.execute("EXPLAIN #{statement}")) if connection
187
+ end
188
+ end
189
+ end
190
+
191
+ def is_select?(statement)
192
+ # split the string into at most two segments on the
193
+ # system-defined field separator character
194
+ first_word, rest_of_statement = statement.split($;, 2)
195
+ (first_word.upcase == 'SELECT')
196
+ end
197
+
198
+ def process_resultset(items)
199
+ # The resultset type varies for different drivers. Only thing you can count on is
200
+ # that it implements each. Also: can't use select_rows because the native postgres
201
+ # driver doesn't know that method.
202
+
203
+ if items.respond_to?(:each)
204
+ rows = []
205
+ items.each do |row|
206
+ columns = []
207
+ row.each do |column|
208
+ columns << column.to_s
209
+ end
210
+ rows << columns
211
+ end
212
+ rows
213
+ else
214
+ [items]
215
+ end
216
+ end
217
+
218
+
219
+ def handle_exception_in_explain
220
+ yield
221
+ rescue Exception => e
222
+ begin
223
+ # guarantees no throw from explain_sql
224
+ NewRelic::Control.instance.log.error("Error getting explain plan: #{e.message}")
225
+ NewRelic::Control.instance.log.debug(e.backtrace.join("\n"))
226
+ rescue Exception
227
+ # double exception. throw up your hands
228
+ end
229
+ end
230
+
231
+
232
+ def params=(p)
233
+ @params = p
234
+ end
235
+
236
+ def obfuscated_sql
237
+ TransactionSample.obfuscate_sql(params[:sql])
238
+ end
239
+
240
+ def called_segments=(segments)
241
+ @called_segments = segments
242
+ end
243
+
244
+ protected
245
+ def parent_segment=(s)
246
+ @parent_segment = s
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,21 @@
1
+ require 'new_relic/transaction_sample'
2
+ require 'new_relic/transaction_sample/segment'
3
+ module NewRelic
4
+ class TransactionSample
5
+ class SummarySegment < Segment
6
+ def initialize(segment)
7
+ super segment.entry_timestamp, segment.metric_name, nil
8
+
9
+ add_segments segment.called_segments
10
+
11
+ end_trace segment.exit_timestamp
12
+ end
13
+
14
+ def add_segments(segments)
15
+ segments.collect do |segment|
16
+ SummarySegment.new(segment)
17
+ end.each {|segment| add_called_segment(segment)}
18
+ end
19
+ end
20
+ end
21
+ end
@@ -2,9 +2,9 @@
2
2
  module NewRelic
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 3
5
- MINOR = 0
6
- TINY = 1
7
- BUILD = nil #'0' # Set to nil for a release, 'beta1', 'alpha', etc for prerelease builds
5
+ MINOR = 1
6
+ TINY = 0
7
+ BUILD = 'beta1' #'0' # Set to nil for a release, 'beta1', 'alpha', etc for prerelease builds
8
8
  STRING = [MAJOR, MINOR, TINY, BUILD].compact.join('.')
9
9
  end
10
10
 
data/newrelic.yml CHANGED
@@ -138,8 +138,8 @@ common: &default_settings
138
138
  transaction_tracer:
139
139
 
140
140
  # Transaction tracer is enabled by default. Set this to false to
141
- # turn it off. This feature is only available at the Professional
142
- # and above product levels.
141
+ # turn it off. This feature is only available at the Silver and
142
+ # above product levels.
143
143
  enabled: true
144
144
 
145
145
  # Threshold in seconds for when to collect a transaction
@@ -176,7 +176,7 @@ common: &default_settings
176
176
  error_collector:
177
177
 
178
178
  # Error collector is enabled by default. Set this to false to turn
179
- # it off. This feature is only available at the Professional and above
179
+ # it off. This feature is only available at the Silver and above
180
180
  # product levels
181
181
  enabled: true
182
182
 
data/newrelic_rpm.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{newrelic_rpm}
8
- s.version = "3.0.1"
8
+ s.version = "3.1.0.beta1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Bill Kayser", "Justin George"]
12
- s.date = %q{2011-05-20}
12
+ s.date = %q{2011-05-11}
13
13
  s.description = %q{New Relic RPM is a Ruby performance management system, developed by
14
14
  New Relic, Inc (http://www.newrelic.com). RPM provides you with deep
15
15
  information about the performance of your Ruby on Rails or Merb
@@ -45,6 +45,7 @@ http://github.com/newrelic/rpm/tree/master.
45
45
  "lib/new_relic/agent/busy_calculator.rb",
46
46
  "lib/new_relic/agent/chained_call.rb",
47
47
  "lib/new_relic/agent/error_collector.rb",
48
+ "lib/new_relic/agent/instrumentation.rb",
48
49
  "lib/new_relic/agent/instrumentation/active_merchant.rb",
49
50
  "lib/new_relic/agent/instrumentation/acts_as_solr.rb",
50
51
  "lib/new_relic/agent/instrumentation/authlogic.rb",
@@ -55,6 +56,7 @@ http://github.com/newrelic/rpm/tree/master.
55
56
  "lib/new_relic/agent/instrumentation/merb/controller.rb",
56
57
  "lib/new_relic/agent/instrumentation/merb/errors.rb",
57
58
  "lib/new_relic/agent/instrumentation/metric_frame.rb",
59
+ "lib/new_relic/agent/instrumentation/metric_frame/pop.rb",
58
60
  "lib/new_relic/agent/instrumentation/net.rb",
59
61
  "lib/new_relic/agent/instrumentation/passenger_instrumentation.rb",
60
62
  "lib/new_relic/agent/instrumentation/queue_time.rb",
@@ -101,6 +103,7 @@ http://github.com/newrelic/rpm/tree/master.
101
103
  "lib/new_relic/control/logging_methods.rb",
102
104
  "lib/new_relic/control/profiling.rb",
103
105
  "lib/new_relic/control/server_methods.rb",
106
+ "lib/new_relic/data_serialization.rb",
104
107
  "lib/new_relic/delayed_job_injection.rb",
105
108
  "lib/new_relic/histogram.rb",
106
109
  "lib/new_relic/local_environment.rb",
@@ -119,7 +122,12 @@ http://github.com/newrelic/rpm/tree/master.
119
122
  "lib/new_relic/stats.rb",
120
123
  "lib/new_relic/timer_lib.rb",
121
124
  "lib/new_relic/transaction_analysis.rb",
125
+ "lib/new_relic/transaction_analysis/segment_summary.rb",
122
126
  "lib/new_relic/transaction_sample.rb",
127
+ "lib/new_relic/transaction_sample/composite_segment.rb",
128
+ "lib/new_relic/transaction_sample/fake_segment.rb",
129
+ "lib/new_relic/transaction_sample/segment.rb",
130
+ "lib/new_relic/transaction_sample/summary_segment.rb",
123
131
  "lib/new_relic/url_rule.rb",
124
132
  "lib/new_relic/version.rb",
125
133
  "lib/newrelic_rpm.rb",
@@ -147,9 +155,11 @@ http://github.com/newrelic/rpm/tree/master.
147
155
  "test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb",
148
156
  "test/new_relic/agent/instrumentation/controller_instrumentation_test.rb",
149
157
  "test/new_relic/agent/instrumentation/instrumentation_test.rb",
158
+ "test/new_relic/agent/instrumentation/metric_frame/pop_test.rb",
150
159
  "test/new_relic/agent/instrumentation/metric_frame_test.rb",
151
160
  "test/new_relic/agent/instrumentation/net_instrumentation_test.rb",
152
161
  "test/new_relic/agent/instrumentation/queue_time_test.rb",
162
+ "test/new_relic/agent/instrumentation/rack_test.rb",
153
163
  "test/new_relic/agent/instrumentation/task_instrumentation_test.rb",
154
164
  "test/new_relic/agent/memcache_instrumentation_test.rb",
155
165
  "test/new_relic/agent/method_tracer/class_methods/add_method_tracer_test.rb",
@@ -157,19 +167,32 @@ http://github.com/newrelic/rpm/tree/master.
157
167
  "test/new_relic/agent/method_tracer_test.rb",
158
168
  "test/new_relic/agent/mock_scope_listener.rb",
159
169
  "test/new_relic/agent/rpm_agent_test.rb",
170
+ "test/new_relic/agent/sampler_test.rb",
171
+ "test/new_relic/agent/shim_agent_test.rb",
172
+ "test/new_relic/agent/stats_engine/metric_stats/harvest_test.rb",
160
173
  "test/new_relic/agent/stats_engine/metric_stats_test.rb",
161
174
  "test/new_relic/agent/stats_engine/samplers_test.rb",
162
- "test/new_relic/agent/stats_engine/stats_engine_test.rb",
175
+ "test/new_relic/agent/stats_engine_test.rb",
163
176
  "test/new_relic/agent/transaction_sample_builder_test.rb",
164
177
  "test/new_relic/agent/transaction_sampler_test.rb",
165
178
  "test/new_relic/agent/worker_loop_test.rb",
166
179
  "test/new_relic/collection_helper_test.rb",
167
180
  "test/new_relic/command/deployments_test.rb",
181
+ "test/new_relic/control/class_methods_test.rb",
182
+ "test/new_relic/control/logging_methods_test.rb",
168
183
  "test/new_relic/control_test.rb",
184
+ "test/new_relic/data_serialization_test.rb",
169
185
  "test/new_relic/local_environment_test.rb",
186
+ "test/new_relic/metric_data_test.rb",
170
187
  "test/new_relic/metric_spec_test.rb",
171
188
  "test/new_relic/rack/episodes_test.rb",
172
189
  "test/new_relic/stats_test.rb",
190
+ "test/new_relic/transaction_analysis/segment_summary_test.rb",
191
+ "test/new_relic/transaction_analysis_test.rb",
192
+ "test/new_relic/transaction_sample/composite_segment_test.rb",
193
+ "test/new_relic/transaction_sample/fake_segment_test.rb",
194
+ "test/new_relic/transaction_sample/segment_test.rb",
195
+ "test/new_relic/transaction_sample/summary_segment_test.rb",
173
196
  "test/new_relic/transaction_sample_subtest_test.rb",
174
197
  "test/new_relic/transaction_sample_test.rb",
175
198
  "test/new_relic/version_number_test.rb",
@@ -275,7 +298,7 @@ Refer to the README.md file for more information.
275
298
 
276
299
  Please see http://support.newrelic.com/faqs/docs/ruby-agent-release-notes
277
300
  for a complete description of the features and enhancements available
278
- in version 3.0 of the Ruby Agent.
301
+ in version 3.1 of the Ruby Agent.
279
302
 
280
303
  For details on this specific release, refer to the CHANGELOG file.
281
304
 
@@ -19,19 +19,29 @@ module ActiveRecordFixtures
19
19
  self.table_name = 'newrelic_test_orders'
20
20
  has_and_belongs_to_many :shipments, :class_name => 'ActiveRecordFixtures::Shipment'
21
21
  def self.setup
22
- connection.create_table self.table_name, :force => true do |t|
23
- t.column :name, :string
22
+ unless check_for_table
23
+ connection.create_table self.table_name, :force => true do |t|
24
+ t.column :name, :string
25
+ end
26
+ else
27
+ connection.execute("delete from #{self.table_name}")
24
28
  end
25
29
  end
30
+
31
+ def self.check_for_table
32
+ connection.table_exists?(self.table_name)
33
+ rescue Exception => e
34
+ false
35
+ end
36
+
26
37
  def self.add_delay
27
- # Introduce a 500 ms delay into db operations on Orders
38
+ # Introduce a 5 ms delay into db operations on Orders
28
39
  def connection.log_info *args
29
- sleep 0.5
40
+ sleep 0.005
30
41
  super *args
31
42
  end
32
43
  end
33
44
  def self.teardown
34
- connection.drop_table table_name
35
45
  def connection.log_info *args
36
46
  super *args
37
47
  end
@@ -42,18 +52,26 @@ module ActiveRecordFixtures
42
52
  self.table_name = 'newrelic_test_shipment'
43
53
  has_and_belongs_to_many :orders, :class_name => 'ActiveRecordFixtures::Order'
44
54
  def self.setup
45
- connection.create_table self.table_name, :force => true do |t|
46
- # no other columns
47
- end
48
- connection.create_table 'orders_shipments', :force => true, :id => false do |t|
49
- t.column :order_id, :integer
50
- t.column :shipment_id, :integer
55
+ unless check_for_table
56
+ connection.create_table self.table_name, :force => true do |t|
57
+ # no other columns
58
+ end
59
+ connection.create_table 'orders_shipments', :force => true, :id => false do |t|
60
+ t.column :order_id, :integer
61
+ t.column :shipment_id, :integer
62
+ end
63
+ else
64
+ connection.execute("delete from #{self.table_name}")
51
65
  end
52
66
  end
67
+ def self.check_for_table
68
+ connection.table_exists?(self.table_name)
69
+ rescue Exception => e
70
+ false
71
+ end
53
72
 
73
+
54
74
  def self.teardown
55
- connection.drop_table 'orders_shipments'
56
- connection.drop_table self.table_name
57
75
  end
58
76
  end
59
77
  end