tphases 0.1.2 → 0.2.0
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.
- 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
|
+
[](https://travis-ci.org/charleseff/tphases)
|
4
|
+
[](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
|