tphases 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +7 -0
- data/README.md +24 -6
- data/lib/tphases/config.rb +8 -2
- data/lib/tphases/initialization.rb +6 -1
- data/lib/tphases/modes/collect_mode.rb +40 -14
- data/lib/tphases/modes/exceptions_mode.rb +2 -0
- data/lib/tphases/modes/helpers/rails_helper.rb +41 -0
- data/lib/tphases/modes/helpers/transactional_violations_helper.rb +43 -89
- data/lib/tphases/modes/pass_through_mode.rb +6 -0
- data/lib/tphases/rails/no_transactions_in_controller.rb +15 -0
- data/lib/tphases/rails/no_transactions_in_controller_pass_through.rb +12 -0
- data/lib/tphases/version.rb +1 -1
- data/spec/fixtures/database.sqlite3 +0 -0
- data/spec/lib/tphases/modes/exceptions_mode_spec.rb +41 -0
- data/spec/lib/tphases/modes/helpers/transactional_violations_helper_spec.rb +55 -25
- metadata +6 -2
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# TPhases
|
2
2
|
|
3
|
+
[![Build Status](https://travis-ci.org/charleseff/tphases.png)](https://travis-ci.org/charleseff/tphases)
|
4
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/charleseff/tphases)
|
5
|
+
|
3
6
|
TPhases (Transactional Phases) is a support framework that helps you build your Rails request life cycles into read-only, write-only, and no-transaction-allowed phases.
|
4
7
|
|
5
8
|
The way it accomplishes this is with the methods `TPhases.read_phase`, `TPhases.write_phase` and `TPhases.no_transactions_phase` which take blocks. Here is a simple example inside of a controller action:
|
@@ -46,23 +49,38 @@ Somewhere in the initialization process of your app, call
|
|
46
49
|
|
47
50
|
## Usage
|
48
51
|
|
49
|
-
###
|
52
|
+
### Environments
|
53
|
+
|
54
|
+
#### In production:
|
50
55
|
The `read_phase`, `write_phase`, and `no_transaction_phase` methods simply yield to the block given.
|
51
56
|
|
52
|
-
|
57
|
+
#### In development:
|
53
58
|
|
54
|
-
|
59
|
+
##### `read_phase`
|
55
60
|
throws an exception if a database transaction is attempted within its block which is a write. This is known as a "read transactional violation".
|
56
61
|
|
57
|
-
|
62
|
+
##### `write_phase`
|
58
63
|
throws an exception if a database transaction is attempted within its block which is a read. This is a write transactional violation.
|
59
64
|
|
60
|
-
|
65
|
+
##### `no_transactions_phase`
|
61
66
|
throws an exception if any database transaction is attempted within its block.
|
62
67
|
|
63
|
-
|
68
|
+
#### In test:
|
64
69
|
If a transactional violation occurs in a TPhase, the code will continue to run, but the test will fail at the end citing the list of transactional violations that occurred.
|
65
70
|
|
71
|
+
### Methods
|
72
|
+
|
73
|
+
#### `ensure_no_transactions_on`
|
74
|
+
Call `ensure_no_transactions_on` on controllers to prevent DB transactions within the views of controller actions. e.g.:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
class BarsController < ApplicationController
|
78
|
+
|
79
|
+
ensure_no_transactions_on [:show,:update]
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
|
66
84
|
## Contributing
|
67
85
|
|
68
86
|
1. Fork it
|
data/lib/tphases/config.rb
CHANGED
@@ -8,10 +8,16 @@ module TPhases
|
|
8
8
|
yield config
|
9
9
|
end
|
10
10
|
|
11
|
-
private
|
12
11
|
# the config
|
12
|
+
# settings options are:
|
13
|
+
#
|
14
|
+
# - mode
|
15
|
+
# - collect_mode_failures_on - defaults to true, but can be turned off temporarily to disable failures on
|
16
|
+
# transaction violations
|
17
|
+
#
|
13
18
|
# sets default value `mode` value based on presence of Rails and environment type
|
14
19
|
# the default setting is the safest, :pass_through, which means TPhases does nothing.
|
20
|
+
#
|
15
21
|
def config
|
16
22
|
@config ||= begin
|
17
23
|
|
@@ -32,7 +38,7 @@ module TPhases
|
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
35
|
-
Struct.new(:mode).new(default_mode)
|
41
|
+
Struct.new(:mode, :collect_mode_failures_on).new(default_mode, true)
|
36
42
|
end
|
37
43
|
end
|
38
44
|
|
@@ -5,6 +5,12 @@ module TPhases
|
|
5
5
|
module ClassMethods
|
6
6
|
# initiates TPhases. Any overrides to config mode need to be made prior to running this.
|
7
7
|
def initiate!
|
8
|
+
add_mode_methods!
|
9
|
+
add_rails_methods! if defined? Rails
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def add_mode_methods!
|
8
14
|
case config.mode
|
9
15
|
when :pass_through
|
10
16
|
require 'tphases/modes/pass_through_mode'
|
@@ -18,7 +24,6 @@ module TPhases
|
|
18
24
|
else
|
19
25
|
raise "TPhases mode must be one of :pass_through, :exceptions, or :collect, but instead is #{config.mode}"
|
20
26
|
end
|
21
|
-
|
22
27
|
end
|
23
28
|
|
24
29
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'tphases/transactional_violation'
|
2
2
|
require 'tphases/modes/helpers/transactional_violations_helper'
|
3
|
+
require 'tphases/modes/helpers/rails_helper'
|
3
4
|
|
4
5
|
# the default 'test' mode, Collect Mode collects incidents of
|
5
6
|
# immediately inside of a TPhase block if a transactional violation occurs
|
@@ -8,9 +9,11 @@ module TPhases
|
|
8
9
|
module CollectMode
|
9
10
|
extend ActiveSupport::Concern
|
10
11
|
include Helpers::TransactionalViolationsHelper
|
12
|
+
include Helpers::RailsHelper if defined? Rails
|
11
13
|
|
12
14
|
included do
|
13
15
|
add_rspec_after! if defined?(RSpec)
|
16
|
+
add_cucumber_after! if defined?(Cucumber)
|
14
17
|
@violations = []
|
15
18
|
end
|
16
19
|
|
@@ -34,26 +37,49 @@ module TPhases
|
|
34
37
|
# adds an after block for all rspec tests that cause them to fail if any transactional violations are present
|
35
38
|
def add_rspec_after!
|
36
39
|
RSpec.configure do |config|
|
37
|
-
config.after(:each)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
40
|
+
config.after(:each, &after_test_fail_if_violations_proc)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_cucumber_after!
|
45
|
+
# todo: get me working
|
46
|
+
#require 'cucumber/rb_support/rb_dsl'
|
47
|
+
#Cucumber::RbSupport::RbDsl.register_rb_hook('after', [], after_test_fail_if_violations_proc)
|
48
|
+
end
|
49
|
+
|
50
|
+
# fails if there were any transactional violations
|
51
|
+
def after_test_fail_if_violations_proc
|
52
|
+
Proc.new do
|
53
|
+
begin
|
54
|
+
if TPhases.config.collect_mode_failures_on && !TPhases.violations.empty?
|
55
|
+
|
56
|
+
fail_message = "This spec had #{TPhases.violations.count} transactional violations:\n"
|
57
|
+
TPhases.violations.each_with_index.map do |violation, index|
|
58
|
+
fail_message << "*"*50 + "\n"
|
59
|
+
fail_message << "Violation ##{index+1}, type: #{violation[:type]}\n"
|
60
|
+
fail_message << "SQL: #{violation[:sql]}\n"
|
61
|
+
fail_message << "Call Stack: \n\t\t#{TPhases.cleaned_call_stack(violation[:call_stack]).join("\n\t\t")}\n"
|
48
62
|
end
|
49
|
-
|
50
|
-
|
51
|
-
TPhases.violations = []
|
63
|
+
|
64
|
+
fail fail_message
|
52
65
|
end
|
66
|
+
ensure
|
67
|
+
TPhases.violations = [] # reset violations list
|
53
68
|
end
|
54
69
|
end
|
70
|
+
|
55
71
|
end
|
56
72
|
|
73
|
+
public
|
74
|
+
# taken from https://github.com/rails/rails/blob/77977f34a5a4ea899f59e31ad869b582285fa5c1/actionpack/lib/action_dispatch/middleware/show_exceptions.rb#L148 :
|
75
|
+
# shows a cleaned stack for Rails apps by default
|
76
|
+
def cleaned_call_stack(call_stack)
|
77
|
+
defined?(Rails) && Rails.respond_to?(:backtrace_cleaner) ?
|
78
|
+
Rails.backtrace_cleaner.clean(call_stack, :silent) :
|
79
|
+
call_stack
|
80
|
+
end
|
81
|
+
|
82
|
+
|
57
83
|
end
|
58
84
|
end
|
59
85
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'tphases/transactional_violation'
|
2
2
|
require 'tphases/modes/helpers/transactional_violations_helper'
|
3
|
+
require 'tphases/modes/helpers/rails_helper'
|
3
4
|
|
4
5
|
# the default 'development' mode, Exceptions Mode means that an exception will be raised
|
5
6
|
# immediately inside of a TPhase block if a transactional violation occurs
|
@@ -8,6 +9,7 @@ module TPhases
|
|
8
9
|
module ExceptionsMode
|
9
10
|
extend ActiveSupport::Concern
|
10
11
|
include Helpers::TransactionalViolationsHelper
|
12
|
+
include Helpers::RailsHelper if defined? Rails
|
11
13
|
|
12
14
|
module ClassMethods
|
13
15
|
private
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module TPhases::Modes
|
2
|
+
module Helpers
|
3
|
+
module RailsHelper
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
module ClassMethods
|
6
|
+
def add_rails_methods!
|
7
|
+
add_render_alias_method_chain!
|
8
|
+
|
9
|
+
require 'tphases/rails/no_transactions_in_controller'
|
10
|
+
ActionController::Base.send :include, TPhases::Rails::NoTransactionsInController
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
def add_render_alias_method_chain!
|
15
|
+
unless Gem.loaded_specs.values.map { |value| value.full_gem_path }.any? { |n| n.include? "actionpack-3.0." }
|
16
|
+
raise "TPhases currently expects Rails version 3.0.* for patching ActionView template."
|
17
|
+
end
|
18
|
+
|
19
|
+
ActionView::Template.class_eval do
|
20
|
+
|
21
|
+
def render_with_tphases_no_transactions(view, locals, &block)
|
22
|
+
controller_class = view.controller.class
|
23
|
+
if controller_class.class_variable_defined?(:@@no_transaction_actions) &&
|
24
|
+
controller_class.class_variable_get(:@@no_transaction_actions).include?(view.action_name.to_sym)
|
25
|
+
TPhases.no_transactions_phase do
|
26
|
+
render_without_tphases_no_transactions(view, locals, &block)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
render_without_tphases_no_transactions(view, locals, &block)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method_chain :render, :tphases_no_transactions
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -13,121 +13,75 @@ module TPhases
|
|
13
13
|
|
14
14
|
included do
|
15
15
|
define_phase_methods!
|
16
|
+
|
17
|
+
# used to keep track of nested phases. a nested phase overrides any prior phase.
|
18
|
+
@phase_stack = []
|
16
19
|
end
|
17
20
|
|
18
|
-
private
|
19
21
|
module ClassMethods
|
20
22
|
|
21
|
-
# if version of activesupport is 3.2.1, it has the subscribed method. else, it doesn't
|
22
23
|
def define_phase_methods!
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
%w{read write no_transactions}.each do |phase_type|
|
25
|
+
define_singleton_method(:"#{phase_type}_phase") do |&block|
|
26
|
+
phase = Phase.new
|
27
|
+
@phase_stack << phase
|
28
|
+
begin
|
29
|
+
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record") do |name, date, date2, sha, args|
|
30
|
+
next unless @phase_stack.last == phase
|
31
|
+
if send(:"#{phase_type}_violation?", args[:sql])
|
32
|
+
send(:"#{phase_type}_violation_action", args[:sql], caller)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
block.call
|
37
|
+
ensure
|
38
|
+
ActiveSupport::Notifications.unsubscribe(subscriber)
|
39
|
+
@phase_stack.pop
|
33
40
|
end
|
34
|
-
else
|
35
|
-
define_phase_methods_without_subscribed_method!
|
36
41
|
end
|
37
|
-
else
|
38
|
-
define_phase_methods_without_subscribed_method!
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# adds methods using the subscribed method
|
43
|
-
def define_phase_methods_with_subscribed_method!
|
44
|
-
define_singleton_method(:read_phase) do |&block|
|
45
|
-
ActiveSupport::Notifications.subscribed(read_phase_subscription_callback, "sql.active_record", &block)
|
46
|
-
end
|
47
|
-
|
48
|
-
define_singleton_method(:write_phase) do |&block|
|
49
|
-
ActiveSupport::Notifications.subscribed(write_phase_subscription_callback, "sql.active_record", &block)
|
50
|
-
end
|
51
|
-
|
52
|
-
define_singleton_method(:no_transactions_phase) do |&block|
|
53
|
-
ActiveSupport::Notifications.subscribed(no_transactions_phase_subscription_callback, "sql.active_record", &block)
|
54
42
|
end
|
55
43
|
end
|
56
44
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
block.call
|
62
|
-
ensure
|
63
|
-
ActiveSupport::Notifications.unsubscribe(subscriber)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
define_singleton_method(:write_phase) do |&block|
|
68
|
-
begin
|
69
|
-
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record", &write_phase_subscription_callback)
|
70
|
-
block.call
|
71
|
-
ensure
|
72
|
-
ActiveSupport::Notifications.unsubscribe(subscriber)
|
73
|
-
end
|
74
|
-
end
|
45
|
+
private
|
46
|
+
READ_QUERIES = %w{show select describe}
|
47
|
+
WRITE_QUERIES = %w{update commit insert delete}
|
48
|
+
RAILS_IGNORABLE_QUERIES = %w{describe}
|
75
49
|
|
76
|
-
|
77
|
-
|
78
|
-
subscriber = ActiveSupport::Notifications.subscribe("sql.active_record", &no_transactions_phase_subscription_callback)
|
79
|
-
block.call
|
80
|
-
ensure
|
81
|
-
ActiveSupport::Notifications.unsubscribe(subscriber)
|
82
|
-
end
|
83
|
-
end
|
50
|
+
def rails_ignorable_read_queries
|
51
|
+
@rails_ignorable_read_queries ||= READ_QUERIES - RAILS_IGNORABLE_QUERIES
|
84
52
|
end
|
85
53
|
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
def write_phase_subscription_callback
|
90
|
-
Proc.new do |name, date, date2, sha, args|
|
91
|
-
if write_transactional_violation?(args[:sql])
|
92
|
-
write_violation_action(args[:sql], caller)
|
93
|
-
end
|
94
|
-
end
|
54
|
+
# determines if this query is a read transactional violation (if it is anything besides a read)
|
55
|
+
def read_violation?(sql)
|
56
|
+
WRITE_QUERIES.include?(first_word(sql))
|
95
57
|
end
|
96
58
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
102
|
-
end
|
59
|
+
# determines if this query is a write transactional violation (if it is anything besides a write)
|
60
|
+
def write_violation?(sql)
|
61
|
+
query_types = (Object.const_defined? :Rails) ? rails_ignorable_read_queries : READ_QUERIES
|
62
|
+
query_types.include?(first_word(sql))
|
103
63
|
end
|
104
64
|
|
105
|
-
|
106
|
-
|
107
|
-
|
65
|
+
# violation unless it's Rails and we are running an ignorable query
|
66
|
+
def no_transactions_violation?(sql)
|
67
|
+
if Object.const_defined? :Rails
|
68
|
+
!RAILS_IGNORABLE_QUERIES.include?(first_word(sql))
|
69
|
+
else
|
70
|
+
true
|
108
71
|
end
|
109
72
|
end
|
110
73
|
|
111
|
-
READ_QUERIES = %w{update commit insert delete}
|
112
|
-
WRITE_QUERIES = %w{show select}
|
113
|
-
|
114
|
-
# determines if this query is a read transactional violation (if it is anything besides a read)
|
115
|
-
def read_transactional_violation?(sql)
|
116
|
-
READ_QUERIES.include?(first_word(sql))
|
117
|
-
end
|
118
|
-
|
119
|
-
# determines if this query is a write transactional violation (if it is anything besides a write)
|
120
|
-
def write_transactional_violation?(sql)
|
121
|
-
WRITE_QUERIES.include?(first_word(sql))
|
122
|
-
end
|
123
|
-
|
124
74
|
def first_word(str)
|
125
75
|
str.split(' ').first.downcase
|
126
76
|
end
|
127
77
|
|
128
78
|
end
|
129
79
|
|
80
|
+
# simple class to represent a phase on the stack of phases. Used to determine which phase is active
|
81
|
+
class Phase;
|
82
|
+
end
|
83
|
+
|
130
84
|
end
|
131
85
|
end
|
132
86
|
end
|
133
|
-
end
|
87
|
+
end
|
@@ -16,6 +16,12 @@ module TPhases
|
|
16
16
|
def no_transactions_phase
|
17
17
|
yield
|
18
18
|
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def add_rails_methods!
|
22
|
+
require 'tphases/rails/no_transactions_in_controller_pass_through'
|
23
|
+
ActionController::Base.send :include, TPhases::Rails::NoTransactionsInControllerPassThrough
|
24
|
+
end
|
19
25
|
end
|
20
26
|
end
|
21
27
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module TPhases
|
2
|
+
module Rails
|
3
|
+
module NoTransactionsInController
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def ensure_no_transactions_on(actions)
|
8
|
+
class_variable_set(:@@no_transaction_actions, actions)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
data/lib/tphases/version.rb
CHANGED
Binary file
|
@@ -58,4 +58,45 @@ describe TPhases::Modes::ExceptionsMode do
|
|
58
58
|
|
59
59
|
end
|
60
60
|
end
|
61
|
+
|
62
|
+
describe "nested phases" do
|
63
|
+
context "read_phase inside of a no_transactions_phase" do
|
64
|
+
it "should allow read transactions" do
|
65
|
+
expect {
|
66
|
+
subject.no_transactions_phase do
|
67
|
+
subject.read_phase do
|
68
|
+
ActiveRecord::Base.connection.select_all(read_sql)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
}.to_not raise_error
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "no_transactions_phase inside a read_phase" do
|
77
|
+
it "should disallow read transactions" do
|
78
|
+
expect {
|
79
|
+
subject.read_phase do
|
80
|
+
subject.no_transactions_phase do
|
81
|
+
ActiveRecord::Base.connection.select_all(read_sql)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
}.to raise_error(ActiveRecord::StatementInvalid, "TransactionalViolation: #{read_sql} ran inside of a 'no_transactions_phase' block.: #{read_sql}")
|
85
|
+
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should have the right phase_stack sizes" do
|
91
|
+
subject.instance_variable_get("@phase_stack").should be_empty
|
92
|
+
subject.read_phase do
|
93
|
+
subject.instance_variable_get("@phase_stack").size.should == 1
|
94
|
+
subject.no_transactions_phase do
|
95
|
+
subject.instance_variable_get("@phase_stack").size.should == 2
|
96
|
+
end
|
97
|
+
subject.instance_variable_get("@phase_stack").size.should == 1
|
98
|
+
end
|
99
|
+
subject.instance_variable_get("@phase_stack").should be_empty
|
100
|
+
end
|
101
|
+
end
|
61
102
|
end
|
@@ -2,37 +2,67 @@ require 'spec_helper'
|
|
2
2
|
require 'tphases/modes/helpers/transactional_violations_helper'
|
3
3
|
|
4
4
|
describe TPhases::Modes::Helpers::TransactionalViolationsHelper do
|
5
|
-
|
6
|
-
subject { Module.new { include TPhases::Modes::Helpers::TransactionalViolationsHelper } }
|
5
|
+
subject { Module.new { include TPhases::Modes::Helpers::TransactionalViolationsHelper } }
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
7
|
+
let(:write_queries) {
|
8
|
+
[
|
9
|
+
"UPDATE `users` SET `email` = 'woifjwe@owiejf.com' WHERE `users`.`id` = 1",
|
10
|
+
"INSERT INTO tablename (col1, col2) VALUES('data1', 'data2' )",
|
11
|
+
"COMMIT",
|
12
|
+
"DELETE FROM example WHERE age='15'"
|
13
|
+
]
|
14
|
+
}
|
15
|
+
let(:read_queries) {
|
16
|
+
[
|
17
|
+
"select * from foobar",
|
18
|
+
"show variables like 'version'"
|
19
|
+
]
|
20
|
+
}
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
describe "#read_transactional_violation?" do
|
23
|
+
it "should detect correctly" do
|
24
|
+
read_queries.each { |read_query| expect(subject.send(:read_violation?, read_query)).to eq(false) }
|
25
|
+
write_queries.each { |write_query| expect(subject.send(:read_violation?, write_query)).to eq(true) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#write_violation?" do
|
30
|
+
it "should detect correctly" do
|
31
|
+
read_queries.each { |read_query| expect(subject.send(:write_violation?, read_query)).to be_true }
|
32
|
+
write_queries.each { |write_query| expect(subject.send(:write_violation?, write_query)).to be_false }
|
33
|
+
end
|
34
|
+
|
35
|
+
context "describe queries" do
|
36
|
+
context "when Rails is present" do
|
37
|
+
it "should detect correctly" do
|
38
|
+
Object.should_receive(:const_defined?).with(:Rails).and_return(true)
|
39
|
+
expect(subject.send(:write_violation?, "describe foo")).to be_false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
context "when Rails is not present" do
|
43
|
+
it "should detect correctly" do
|
44
|
+
Object.should_receive(:const_defined?).with(:Rails).and_return(false)
|
45
|
+
expect(subject.send(:write_violation?, "describe foo")).to be_true
|
46
|
+
end
|
27
47
|
end
|
28
48
|
end
|
29
49
|
|
30
|
-
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#no_transactions_violation?" do
|
53
|
+
context "when Rails is present" do
|
31
54
|
it "should detect correctly" do
|
32
|
-
|
33
|
-
|
55
|
+
Object.stub(:const_defined?).with(:Rails).and_return(true)
|
56
|
+
expect(subject.send(:no_transactions_violation?, "describe foo")).to be_false
|
57
|
+
expect(subject.send(:no_transactions_violation?, "select * from foo")).to be_true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
context "when Rails is not present" do
|
61
|
+
it "should detect correctly" do
|
62
|
+
Object.stub(:const_defined?).with(:Rails).and_return(false)
|
63
|
+
expect(subject.send(:no_transactions_violation?, "describe foo")).to be_true
|
64
|
+
expect(subject.send(:no_transactions_violation?, "select * from foo")).to be_true
|
34
65
|
end
|
35
66
|
end
|
36
|
-
|
37
67
|
end
|
38
|
-
end
|
68
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tphases
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -117,6 +117,7 @@ extra_rdoc_files: []
|
|
117
117
|
files:
|
118
118
|
- .gitignore
|
119
119
|
- .rspec
|
120
|
+
- .travis.yml
|
120
121
|
- Gemfile
|
121
122
|
- LICENSE.txt
|
122
123
|
- README.md
|
@@ -126,8 +127,11 @@ files:
|
|
126
127
|
- lib/tphases/initialization.rb
|
127
128
|
- lib/tphases/modes/collect_mode.rb
|
128
129
|
- lib/tphases/modes/exceptions_mode.rb
|
130
|
+
- lib/tphases/modes/helpers/rails_helper.rb
|
129
131
|
- lib/tphases/modes/helpers/transactional_violations_helper.rb
|
130
132
|
- lib/tphases/modes/pass_through_mode.rb
|
133
|
+
- lib/tphases/rails/no_transactions_in_controller.rb
|
134
|
+
- lib/tphases/rails/no_transactions_in_controller_pass_through.rb
|
131
135
|
- lib/tphases/transactional_violation.rb
|
132
136
|
- lib/tphases/version.rb
|
133
137
|
- spec/fixtures/database.sqlite3
|