hoodoo 1.0.2
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.
- checksums.yaml +7 -0
- data/bin/hoodoo +5 -0
- data/lib/hoodoo.rb +27 -0
- data/lib/hoodoo/active.rb +32 -0
- data/lib/hoodoo/active/active_model/uuid_validator.rb +45 -0
- data/lib/hoodoo/active/active_record/base.rb +81 -0
- data/lib/hoodoo/active/active_record/creator.rb +134 -0
- data/lib/hoodoo/active/active_record/dated.rb +343 -0
- data/lib/hoodoo/active/active_record/error_mapping.rb +351 -0
- data/lib/hoodoo/active/active_record/finder.rb +606 -0
- data/lib/hoodoo/active/active_record/search_helper.rb +189 -0
- data/lib/hoodoo/active/active_record/secure.rb +431 -0
- data/lib/hoodoo/active/active_record/support.rb +106 -0
- data/lib/hoodoo/active/active_record/translated.rb +87 -0
- data/lib/hoodoo/active/active_record/uuid.rb +80 -0
- data/lib/hoodoo/active/active_record/writer.rb +321 -0
- data/lib/hoodoo/client.rb +23 -0
- data/lib/hoodoo/client/augmented_array.rb +29 -0
- data/lib/hoodoo/client/augmented_base.rb +168 -0
- data/lib/hoodoo/client/augmented_hash.rb +23 -0
- data/lib/hoodoo/client/client.rb +354 -0
- data/lib/hoodoo/client/endpoint/endpoint.rb +427 -0
- data/lib/hoodoo/client/endpoint/endpoints/amqp.rb +180 -0
- data/lib/hoodoo/client/endpoint/endpoints/auto_session.rb +194 -0
- data/lib/hoodoo/client/endpoint/endpoints/http.rb +203 -0
- data/lib/hoodoo/client/endpoint/endpoints/http_based.rb +367 -0
- data/lib/hoodoo/client/endpoint/endpoints/not_found.rb +59 -0
- data/lib/hoodoo/client/headers.rb +269 -0
- data/lib/hoodoo/communicators.rb +23 -0
- data/lib/hoodoo/communicators/fast.rb +44 -0
- data/lib/hoodoo/communicators/pool.rb +601 -0
- data/lib/hoodoo/communicators/slow.rb +84 -0
- data/lib/hoodoo/data.rb +51 -0
- data/lib/hoodoo/data/resources/caller.rb +39 -0
- data/lib/hoodoo/data/resources/errors.rb +28 -0
- data/lib/hoodoo/data/resources/log.rb +31 -0
- data/lib/hoodoo/data/resources/session.rb +26 -0
- data/lib/hoodoo/data/types/error_primitive.rb +27 -0
- data/lib/hoodoo/data/types/permissions.rb +40 -0
- data/lib/hoodoo/data/types/permissions_defaults.rb +32 -0
- data/lib/hoodoo/data/types/permissions_full.rb +28 -0
- data/lib/hoodoo/data/types/permissions_resources.rb +31 -0
- data/lib/hoodoo/discovery.rb +20 -0
- data/lib/hoodoo/errors.rb +19 -0
- data/lib/hoodoo/errors/error_descriptions.rb +229 -0
- data/lib/hoodoo/errors/errors.rb +322 -0
- data/lib/hoodoo/generator.rb +139 -0
- data/lib/hoodoo/logger.rb +23 -0
- data/lib/hoodoo/logger/fast_writer.rb +27 -0
- data/lib/hoodoo/logger/flattener_mixin.rb +36 -0
- data/lib/hoodoo/logger/logger.rb +387 -0
- data/lib/hoodoo/logger/slow_writer.rb +49 -0
- data/lib/hoodoo/logger/writer_mixin.rb +52 -0
- data/lib/hoodoo/logger/writers/file_writer.rb +45 -0
- data/lib/hoodoo/logger/writers/log_entries_dot_com_writer.rb +64 -0
- data/lib/hoodoo/logger/writers/stream_writer.rb +43 -0
- data/lib/hoodoo/middleware.rb +33 -0
- data/lib/hoodoo/presenters.rb +45 -0
- data/lib/hoodoo/presenters/base.rb +281 -0
- data/lib/hoodoo/presenters/base_dsl.rb +519 -0
- data/lib/hoodoo/presenters/common_resource_fields.rb +31 -0
- data/lib/hoodoo/presenters/embedding.rb +232 -0
- data/lib/hoodoo/presenters/types/array.rb +118 -0
- data/lib/hoodoo/presenters/types/boolean.rb +26 -0
- data/lib/hoodoo/presenters/types/date.rb +26 -0
- data/lib/hoodoo/presenters/types/date_time.rb +26 -0
- data/lib/hoodoo/presenters/types/decimal.rb +47 -0
- data/lib/hoodoo/presenters/types/enum.rb +55 -0
- data/lib/hoodoo/presenters/types/field.rb +158 -0
- data/lib/hoodoo/presenters/types/float.rb +26 -0
- data/lib/hoodoo/presenters/types/hash.rb +361 -0
- data/lib/hoodoo/presenters/types/integer.rb +26 -0
- data/lib/hoodoo/presenters/types/object.rb +117 -0
- data/lib/hoodoo/presenters/types/string.rb +53 -0
- data/lib/hoodoo/presenters/types/tags.rb +24 -0
- data/lib/hoodoo/presenters/types/text.rb +26 -0
- data/lib/hoodoo/presenters/types/uuid.rb +54 -0
- data/lib/hoodoo/services.rb +34 -0
- data/lib/hoodoo/services/discovery/discoverers/by_consul.rb +66 -0
- data/lib/hoodoo/services/discovery/discoverers/by_convention.rb +173 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +195 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server.rb +166 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server_start.rb +37 -0
- data/lib/hoodoo/services/discovery/discovery.rb +186 -0
- data/lib/hoodoo/services/discovery/results/for_amqp.rb +58 -0
- data/lib/hoodoo/services/discovery/results/for_http.rb +85 -0
- data/lib/hoodoo/services/discovery/results/for_local.rb +85 -0
- data/lib/hoodoo/services/discovery/results/for_remote.rb +57 -0
- data/lib/hoodoo/services/middleware/amqp_log_message.rb +186 -0
- data/lib/hoodoo/services/middleware/amqp_log_writer.rb +119 -0
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +130 -0
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +202 -0
- data/lib/hoodoo/services/middleware/exception_reporting/base_reporter.rb +105 -0
- data/lib/hoodoo/services/middleware/exception_reporting/exception_reporting.rb +115 -0
- data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +64 -0
- data/lib/hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter.rb +63 -0
- data/lib/hoodoo/services/middleware/interaction.rb +127 -0
- data/lib/hoodoo/services/middleware/middleware.rb +2705 -0
- data/lib/hoodoo/services/middleware/rack_monkey_patch.rb +73 -0
- data/lib/hoodoo/services/services/context.rb +153 -0
- data/lib/hoodoo/services/services/implementation.rb +132 -0
- data/lib/hoodoo/services/services/interface.rb +934 -0
- data/lib/hoodoo/services/services/permissions.rb +250 -0
- data/lib/hoodoo/services/services/request.rb +189 -0
- data/lib/hoodoo/services/services/response.rb +316 -0
- data/lib/hoodoo/services/services/service.rb +141 -0
- data/lib/hoodoo/services/services/session.rb +729 -0
- data/lib/hoodoo/utilities.rb +12 -0
- data/lib/hoodoo/utilities/string_inquirer.rb +54 -0
- data/lib/hoodoo/utilities/utilities.rb +380 -0
- data/lib/hoodoo/utilities/uuid.rb +44 -0
- data/lib/hoodoo/version.rb +17 -0
- data/spec/active/active_record/base_spec.rb +57 -0
- data/spec/active/active_record/creator_spec.rb +88 -0
- data/spec/active/active_record/dated_spec.rb +248 -0
- data/spec/active/active_record/error_mapping_spec.rb +360 -0
- data/spec/active/active_record/finder_spec.rb +744 -0
- data/spec/active/active_record/search_helper_spec.rb +384 -0
- data/spec/active/active_record/secure_spec.rb +435 -0
- data/spec/active/active_record/support_spec.rb +225 -0
- data/spec/active/active_record/translated_spec.rb +19 -0
- data/spec/active/active_record/uuid_spec.rb +72 -0
- data/spec/active/active_record/writer_spec.rb +272 -0
- data/spec/alchemy/alchemy-amq.rb +33 -0
- data/spec/client/augmented_array_spec.rb +15 -0
- data/spec/client/augmented_base_spec.rb +50 -0
- data/spec/client/augmented_hash_spec.rb +15 -0
- data/spec/client/client_spec.rb +955 -0
- data/spec/client/endpoint/endpoint_spec.rb +70 -0
- data/spec/client/endpoint/endpoints/amqp_spec.rb +16 -0
- data/spec/client/endpoint/endpoints/auto_session_spec.rb +9 -0
- data/spec/client/endpoint/endpoints/http_based_spec.rb +9 -0
- data/spec/client/endpoint/endpoints/http_spec.rb +103 -0
- data/spec/client/endpoint/endpoints/not_found_spec.rb +35 -0
- data/spec/client/headers_spec.rb +172 -0
- data/spec/communicators/fast_spec.rb +9 -0
- data/spec/communicators/pool_spec.rb +339 -0
- data/spec/communicators/slow_spec.rb +15 -0
- data/spec/data/resources/caller_spec.rb +156 -0
- data/spec/data/resources/errors_spec.rb +22 -0
- data/spec/data/resources/log_spec.rb +20 -0
- data/spec/data/resources/session_spec.rb +15 -0
- data/spec/data/types/error_primitive_spec.rb +15 -0
- data/spec/data/types/permissions_defaults_spec.rb +25 -0
- data/spec/data/types/permissions_full_spec.rb +44 -0
- data/spec/data/types/permissions_resources_spec.rb +34 -0
- data/spec/data/types/permissions_spec.rb +37 -0
- data/spec/errors/error_descriptions_spec.rb +98 -0
- data/spec/errors/errors_spec.rb +346 -0
- data/spec/integration/service_actions_spec.rb +112 -0
- data/spec/logger/fast_writer_spec.rb +18 -0
- data/spec/logger/logger_spec.rb +259 -0
- data/spec/logger/slow_writer_spec.rb +144 -0
- data/spec/logger/writers/file_writer_spec.rb +37 -0
- data/spec/logger/writers/log_entries_dot_com_writer_spec.rb +29 -0
- data/spec/logger/writers/stream_writer_spec.rb +38 -0
- data/spec/presenters/base_dsl_spec.rb +111 -0
- data/spec/presenters/base_spec.rb +871 -0
- data/spec/presenters/common_resource_fields_spec.rb +30 -0
- data/spec/presenters/embedding_spec.rb +87 -0
- data/spec/presenters/types/array_spec.rb +249 -0
- data/spec/presenters/types/boolean_spec.rb +51 -0
- data/spec/presenters/types/date_spec.rb +57 -0
- data/spec/presenters/types/date_time_spec.rb +59 -0
- data/spec/presenters/types/decimal_spec.rb +58 -0
- data/spec/presenters/types/enum_spec.rb +71 -0
- data/spec/presenters/types/field_spec.rb +77 -0
- data/spec/presenters/types/float_spec.rb +50 -0
- data/spec/presenters/types/hash_spec.rb +1069 -0
- data/spec/presenters/types/integer_spec.rb +50 -0
- data/spec/presenters/types/object_spec.rb +177 -0
- data/spec/presenters/types/string_spec.rb +65 -0
- data/spec/presenters/types/tags_spec.rb +56 -0
- data/spec/presenters/types/text_spec.rb +50 -0
- data/spec/presenters/types/uuid_spec.rb +46 -0
- data/spec/presenters/walk_spec.rb +198 -0
- data/spec/services/discovery/discoverers/by_consul_spec.rb +29 -0
- data/spec/services/discovery/discoverers/by_convention_spec.rb +67 -0
- data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +80 -0
- data/spec/services/discovery/discoverers/by_drb/drb_server_spec.rb +205 -0
- data/spec/services/discovery/discovery_spec.rb +73 -0
- data/spec/services/discovery/results/for_amqp_spec.rb +17 -0
- data/spec/services/discovery/results/for_http_spec.rb +37 -0
- data/spec/services/discovery/results/for_local_spec.rb +21 -0
- data/spec/services/discovery/results/for_remote_spec.rb +15 -0
- data/spec/services/middleware/amqp_log_message_spec.rb +60 -0
- data/spec/services/middleware/amqp_log_writer_spec.rb +95 -0
- data/spec/services/middleware/endpoints/inter_resource_local_spec.rb +9 -0
- data/spec/services/middleware/endpoints/inter_resource_remote_spec.rb +9 -0
- data/spec/services/middleware/exception_reporting/base_reporter_spec.rb +16 -0
- data/spec/services/middleware/exception_reporting/exception_reporting_spec.rb +92 -0
- data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +24 -0
- data/spec/services/middleware/exception_reporting/reporters/raygun_reporter_spec.rb +23 -0
- data/spec/services/middleware/middleware_cors_spec.rb +93 -0
- data/spec/services/middleware/middleware_create_update_spec.rb +489 -0
- data/spec/services/middleware/middleware_dated_at_spec.rb +186 -0
- data/spec/services/middleware/middleware_exotic_communication_spec.rb +560 -0
- data/spec/services/middleware/middleware_logging_spec.rb +356 -0
- data/spec/services/middleware/middleware_multi_local_spec.rb +1094 -0
- data/spec/services/middleware/middleware_multi_remote_spec.rb +1440 -0
- data/spec/services/middleware/middleware_permissions_spec.rb +1014 -0
- data/spec/services/middleware/middleware_public_spec.rb +238 -0
- data/spec/services/middleware/middleware_spec.rb +1569 -0
- data/spec/services/middleware/string_inquirer_spec.rb +30 -0
- data/spec/services/services/application_spec.rb +74 -0
- data/spec/services/services/context_spec.rb +48 -0
- data/spec/services/services/implementation_spec.rb +45 -0
- data/spec/services/services/interface_spec.rb +262 -0
- data/spec/services/services/permissions_spec.rb +249 -0
- data/spec/services/services/request_spec.rb +95 -0
- data/spec/services/services/response_spec.rb +250 -0
- data/spec/services/services/session_spec.rb +432 -0
- data/spec/spec_helper.rb +298 -0
- data/spec/utilities/utilities_spec.rb +537 -0
- data/spec/utilities/uuid_spec.rb +20 -0
- metadata +615 -0
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe Hoodoo::ActiveRecord::Support do
|
4
|
+
context '#self.process_to_map' do
|
5
|
+
it 'processes as expected' do
|
6
|
+
proc1 = Proc.new { puts "hello" }
|
7
|
+
proc2 = Proc.new { puts "world" }
|
8
|
+
|
9
|
+
hash = {
|
10
|
+
:foo => nil,
|
11
|
+
'bar' => nil,
|
12
|
+
:baz => proc1,
|
13
|
+
'boo' => proc2
|
14
|
+
}
|
15
|
+
|
16
|
+
map = described_class.process_to_map( hash )
|
17
|
+
|
18
|
+
# Ensure all keys become strings. The 'nil' values should become matcher
|
19
|
+
# Procs per Hoodoo::ActiveRecord::Finder::SearchHelper.cs_match, however
|
20
|
+
# you can't compare Proc instances; so instead run those Procs and check
|
21
|
+
# the expected results.
|
22
|
+
#
|
23
|
+
# Since a created Proc is supposed to encode the attribute name into the
|
24
|
+
# Proc via the key in the input hash, any run-time specification of an
|
25
|
+
# attribute name ought to be ignored if the mapping method is working as
|
26
|
+
# expected.
|
27
|
+
|
28
|
+
expect( map[ 'foo' ] ).to be_a( Proc )
|
29
|
+
expect( map[ 'foo' ].call( 'ignored', 'val1' ) ).to eq( [ 'foo = ? AND foo IS NOT NULL', 'val1' ] )
|
30
|
+
|
31
|
+
expect( map[ 'bar' ] ).to be_a( Proc )
|
32
|
+
expect( map[ 'bar' ].call( 'ignored', 'val2' ) ).to eq( [ 'bar = ? AND bar IS NOT NULL', 'val2' ] )
|
33
|
+
|
34
|
+
expect( map[ 'baz' ] ).to eq( proc1 )
|
35
|
+
|
36
|
+
expect( map[ 'boo' ] ).to eq( proc2 )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context '#full_scope_for' do
|
41
|
+
|
42
|
+
# Here we not only test the full scope generator with all mixins included,
|
43
|
+
# and test them all in a *deactivated* state, we also check that inheritance
|
44
|
+
# can then override that condition without disturbing the base class to
|
45
|
+
# ensure that "class attribute" style code, rather than "@@" class variable
|
46
|
+
# style code, is being maintained in the mixins. Then check the reverse -
|
47
|
+
# make sure things in the base class do get inherited by subclasses.
|
48
|
+
|
49
|
+
before :all do
|
50
|
+
@thtname1 = 'r_spec_full_scope_for_test_foo_history'
|
51
|
+
@thtname2 = 'r_spec_full_scope_for_test_with_directives_foo_history'
|
52
|
+
|
53
|
+
spec_helper_silence_stdout() do
|
54
|
+
ActiveRecord::Migration.create_table( :r_spec_full_scope_for_test_bases ) do | t |
|
55
|
+
t.timestamps :null => true
|
56
|
+
end
|
57
|
+
|
58
|
+
ActiveRecord::Migration.create_table( :r_spec_full_scope_for_test_subclasses ) do | t |
|
59
|
+
t.string :foo
|
60
|
+
t.timestamps :null => true
|
61
|
+
end
|
62
|
+
|
63
|
+
ActiveRecord::Migration.create_table( @thtname1 ) do | t |
|
64
|
+
t.string :foo
|
65
|
+
t.timestamps :null => true
|
66
|
+
end
|
67
|
+
|
68
|
+
ActiveRecord::Migration.create_table( :rspec_full_scope_for_test_base_with_directives_custom ) do | t |
|
69
|
+
t.string :bar
|
70
|
+
t.timestamps :null => true
|
71
|
+
end
|
72
|
+
|
73
|
+
ActiveRecord::Migration.create_table( @thtname2 ) do | t |
|
74
|
+
t.string :bar
|
75
|
+
t.timestamps :null => true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Note inheritance from plain ActiveRecord::Base, important for
|
80
|
+
# additional coverage. Module inclusions are thus done manually.
|
81
|
+
|
82
|
+
class RSpecFullScopeForTestBase < ActiveRecord::Base
|
83
|
+
include Hoodoo::ActiveRecord::Secure
|
84
|
+
include Hoodoo::ActiveRecord::Dated
|
85
|
+
include Hoodoo::ActiveRecord::Translated
|
86
|
+
end
|
87
|
+
|
88
|
+
class RSpecFullScopeForTestSubclass < RSpecFullScopeForTestBase
|
89
|
+
TEST_HISTORY_TABLE_NAME = 'r_spec_full_scope_for_test_foo_history'
|
90
|
+
|
91
|
+
self.table_name = :r_spec_full_scope_for_test_subclasses
|
92
|
+
secure_with( :foo => :foo )
|
93
|
+
dating_enabled( :history_table_name => TEST_HISTORY_TABLE_NAME )
|
94
|
+
end
|
95
|
+
|
96
|
+
# Note inheritance from Hoodoo::ActiveRecord::Base, important for
|
97
|
+
# additional coverage. Module inclusions are automatic.
|
98
|
+
|
99
|
+
class RSpecFullScopeForTestBaseWithDirectives < Hoodoo::ActiveRecord::Base
|
100
|
+
TEST_HISTORY_TABLE_NAME = 'r_spec_full_scope_for_test_with_directives_foo_history'
|
101
|
+
|
102
|
+
self.table_name = :rspec_full_scope_for_test_base_with_directives_custom
|
103
|
+
secure_with( :bar => :foo )
|
104
|
+
dating_enabled( :history_table_name => TEST_HISTORY_TABLE_NAME )
|
105
|
+
end
|
106
|
+
|
107
|
+
class RSpecFullScopeForTestBaseSubclassWithoutOverrides < RSpecFullScopeForTestBaseWithDirectives
|
108
|
+
# No overrides at all
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
before :each do
|
113
|
+
|
114
|
+
# Get a good-enough-for-test interaction and context.
|
115
|
+
|
116
|
+
@interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
|
117
|
+
@interaction.context = Hoodoo::Services::Context.new(
|
118
|
+
Hoodoo::Services::Session.new,
|
119
|
+
@interaction.context.request,
|
120
|
+
@interaction.context.response,
|
121
|
+
@interaction
|
122
|
+
)
|
123
|
+
|
124
|
+
@context = @interaction.context
|
125
|
+
@session = @interaction.context.session
|
126
|
+
|
127
|
+
# Now set up the data inside that context so that the tests generate
|
128
|
+
# predictable SQL output.
|
129
|
+
|
130
|
+
@test_time_value = DateTime.now
|
131
|
+
@context.request.dated_at = @test_time_value
|
132
|
+
|
133
|
+
@test_scoping_value = 23
|
134
|
+
@session.scoping = OpenStruct.new
|
135
|
+
@session.scoping.foo = [ @test_scoping_value ]
|
136
|
+
end
|
137
|
+
|
138
|
+
context '(with subclass overriding base class)' do
|
139
|
+
it 'prerequisites' do
|
140
|
+
expect( RSpecFullScopeForTestBase.all().to_sql() ).to_not eq( RSpecFullScopeForTestSubclass.all().to_sql() )
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'gets "all" scope in the base class' do
|
144
|
+
|
145
|
+
# There are no module activations in the base class so we expect to
|
146
|
+
# get the "all" context, the subclass's activations having not made
|
147
|
+
# any difference to it.
|
148
|
+
|
149
|
+
auto_scope = described_class.full_scope_for( RSpecFullScopeForTestBase, @context ).to_sql()
|
150
|
+
manual_scope = RSpecFullScopeForTestBase.all().to_sql()
|
151
|
+
|
152
|
+
expect( auto_scope ).to eq( manual_scope )
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'gets customised scope in the subclass:' do
|
156
|
+
|
157
|
+
# These first tests just make sure that the individual modules
|
158
|
+
# are generating expected scoping data, so that we aren't accidentally
|
159
|
+
# comparing malfunctioning scope inclusions against each other (e.g.
|
160
|
+
# empty strings).
|
161
|
+
|
162
|
+
it 'dated' do
|
163
|
+
manual_scope = RSpecFullScopeForTestSubclass.dated( @context ).to_sql()
|
164
|
+
|
165
|
+
expect( manual_scope ).to include( "FROM #{ @thtname1 }" )
|
166
|
+
expect( manual_scope ).to include( "effective_end > #{ RSpecFullScopeForTestSubclass.sanitize( @test_time_value ) }" )
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'secure' do
|
170
|
+
manual_scope = RSpecFullScopeForTestSubclass.secure( @context ).to_sql()
|
171
|
+
|
172
|
+
expect( manual_scope ).to include( "\"r_spec_full_scope_for_test_subclasses\".\"foo\" = '#{ @test_scoping_value }'" )
|
173
|
+
end
|
174
|
+
|
175
|
+
pending 'translated' do
|
176
|
+
raise "Scope verification for '\#translated'"
|
177
|
+
end
|
178
|
+
|
179
|
+
# In this last one, we actually check full_scope_for; activations are in
|
180
|
+
# the subclass so we drive the non-context versions directly to verify
|
181
|
+
# that the context chain worked.
|
182
|
+
|
183
|
+
it 'everything' do
|
184
|
+
auto_scope = described_class.full_scope_for( RSpecFullScopeForTestSubclass, @context ).to_sql()
|
185
|
+
manual_scope = RSpecFullScopeForTestSubclass.secure( @context ).dated( @context ).translated( @context ).to_sql()
|
186
|
+
|
187
|
+
expect( auto_scope ).to eq( manual_scope )
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context '(with base class definitions used by subclass)' do
|
193
|
+
it 'prerequisites' do
|
194
|
+
expect( RSpecFullScopeForTestBaseWithDirectives.all().to_sql ).to eq( RSpecFullScopeForTestBaseSubclassWithoutOverrides.all().to_sql() )
|
195
|
+
end
|
196
|
+
|
197
|
+
# As above - some tests to check individual scopes work (paranoia), then
|
198
|
+
# the actual #full_scope_for test which puts it all together.
|
199
|
+
|
200
|
+
it 'dated' do
|
201
|
+
manual_scope = RSpecFullScopeForTestBaseSubclassWithoutOverrides.dated( @context ).to_sql()
|
202
|
+
|
203
|
+
expect( manual_scope ).to include( "FROM #{ @thtname2 }" )
|
204
|
+
expect( manual_scope ).to include( "effective_end > #{ RSpecFullScopeForTestBaseSubclassWithoutOverrides.sanitize( @test_time_value ) }" )
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'secure' do
|
208
|
+
manual_scope = RSpecFullScopeForTestBaseSubclassWithoutOverrides.secure( @context ).to_sql()
|
209
|
+
|
210
|
+
expect( manual_scope ).to include( "\"rspec_full_scope_for_test_base_with_directives_custom\".\"bar\" = '#{ @test_scoping_value }'" )
|
211
|
+
end
|
212
|
+
|
213
|
+
pending 'translated' do
|
214
|
+
raise "Scope verification for '\#translated'"
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'yields the same SQL' do
|
218
|
+
auto_scope = described_class.full_scope_for( RSpecFullScopeForTestBaseSubclassWithoutOverrides, @context ).to_sql()
|
219
|
+
manual_scope = RSpecFullScopeForTestBaseSubclassWithoutOverrides.secure( @context ).dated( @context ).translated( @context ).to_sql()
|
220
|
+
|
221
|
+
expect( auto_scope ).to eq( manual_scope )
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
describe Hoodoo::ActiveRecord::Translated do
|
5
|
+
pending 'is tested' do
|
6
|
+
|
7
|
+
# For RCov only
|
8
|
+
|
9
|
+
class Test
|
10
|
+
include Hoodoo::ActiveRecord::Translated
|
11
|
+
def self.all; end
|
12
|
+
end
|
13
|
+
|
14
|
+
ignored = true
|
15
|
+
Test.translated( ignored )
|
16
|
+
|
17
|
+
raise "Replace with real test"
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
describe Hoodoo::ActiveRecord::UUID do
|
5
|
+
before :all do
|
6
|
+
spec_helper_silence_stdout() do
|
7
|
+
tblname = :r_spec_model_uuid_tests
|
8
|
+
|
9
|
+
ActiveRecord::Migration.create_table( tblname, :id => false ) do | t |
|
10
|
+
t.string( :id, :limit => 32, :null => false )
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveRecord::Migration.add_index( tblname, :id, :unique => true )
|
14
|
+
|
15
|
+
class RSpecModelUUIDTest < ActiveRecord::Base
|
16
|
+
include Hoodoo::ActiveRecord::UUID
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should gain a UUID' do
|
22
|
+
m = RSpecModelUUIDTest.new
|
23
|
+
m.save
|
24
|
+
|
25
|
+
expect( m.id ).to_not be_nil
|
26
|
+
expect( Hoodoo::UUID.valid?( m.id ) ).to eq( true )
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should complain about a bad UUID' do
|
30
|
+
m = RSpecModelUUIDTest.new
|
31
|
+
m.id = "hello"
|
32
|
+
|
33
|
+
expect( m.save ).to eq( false )
|
34
|
+
expect( Hoodoo::UUID.valid?( m.id ) ).to eq( false )
|
35
|
+
expect( m.errors ).to_not be_empty
|
36
|
+
expect( m.errors.messages ).to eq( { :id => [ 'is invalid' ] } )
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should not overwrite a good UUID' do
|
40
|
+
m = RSpecModelUUIDTest.new
|
41
|
+
uuid = Hoodoo::UUID.generate()
|
42
|
+
m.id = uuid
|
43
|
+
m.save
|
44
|
+
|
45
|
+
expect( m.id ).to eq( uuid )
|
46
|
+
expect( Hoodoo::UUID.valid?( m.id ) ).to eq( true )
|
47
|
+
end
|
48
|
+
|
49
|
+
# Accidental attribute assignment of "id" to "nil" on updates can cause
|
50
|
+
# really bad consequences if the UUID is then automatically assigned again;
|
51
|
+
# the resource primary key would change magically! Never allow this. If a
|
52
|
+
# primary key change is ever wanted, a new UUID must be explicitly given.
|
53
|
+
#
|
54
|
+
it 'should not update with a replacement UUID' do
|
55
|
+
m = RSpecModelUUIDTest.new
|
56
|
+
m.save!
|
57
|
+
id = m.id
|
58
|
+
|
59
|
+
# So it shouldn't save with a 'nil' ID...
|
60
|
+
|
61
|
+
m.assign_attributes( :id => nil )
|
62
|
+
|
63
|
+
expect( m.save ).to eq( false )
|
64
|
+
expect( m.errors.messages ).to eq( { :id => [ "can't be blank" ] } )
|
65
|
+
|
66
|
+
# ...and should be able to reload it with the original ID still.
|
67
|
+
|
68
|
+
m.id = id
|
69
|
+
m.reload
|
70
|
+
expect( m.id ).to eq( id )
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,272 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
describe Hoodoo::ActiveRecord::Writer do
|
5
|
+
|
6
|
+
context 'persist_in' do
|
7
|
+
|
8
|
+
###########################################################################
|
9
|
+
# DATABASE AND MODEL SETUP
|
10
|
+
###########################################################################
|
11
|
+
|
12
|
+
class RSpecModelWriterTestWithValidation < ActiveRecord::Base
|
13
|
+
self.primary_key = :id
|
14
|
+
self.table_name = :r_spec_model_writer_tests
|
15
|
+
|
16
|
+
include Hoodoo::ActiveRecord::Writer
|
17
|
+
include Hoodoo::ActiveRecord::ErrorMapping
|
18
|
+
|
19
|
+
validates :code, uniqueness: true
|
20
|
+
end
|
21
|
+
|
22
|
+
class RSpecModelWriterTestWithoutValidation < ActiveRecord::Base
|
23
|
+
self.primary_key = :id
|
24
|
+
self.table_name = :r_spec_model_writer_tests
|
25
|
+
|
26
|
+
include Hoodoo::ActiveRecord::Writer
|
27
|
+
include Hoodoo::ActiveRecord::ErrorMapping
|
28
|
+
end
|
29
|
+
|
30
|
+
before( :all ) do
|
31
|
+
spec_helper_silence_stdout() do
|
32
|
+
ActiveRecord::Migration.create_table(:r_spec_model_writer_tests, :id => false) do | t |
|
33
|
+
t.text :id
|
34
|
+
t.text :uuid
|
35
|
+
t.text :code
|
36
|
+
t.text :random_field
|
37
|
+
|
38
|
+
t.timestamps :null => false
|
39
|
+
end
|
40
|
+
|
41
|
+
ActiveRecord::Migration.add_index(:r_spec_model_writer_tests, :code, unique: true)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
###########################################################################
|
46
|
+
# TESTS
|
47
|
+
###########################################################################
|
48
|
+
|
49
|
+
def unique_attributes
|
50
|
+
{
|
51
|
+
:id => Hoodoo::UUID.generate(),
|
52
|
+
:code => Hoodoo::UUID.generate(),
|
53
|
+
:random_field => Hoodoo::UUID.generate()
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
before( :each ) do
|
58
|
+
@record_with_app_validation = RSpecModelWriterTestWithValidation.create(
|
59
|
+
:id => 'one',
|
60
|
+
:code => 'unique',
|
61
|
+
:random_field => 'sudo random value'
|
62
|
+
)
|
63
|
+
|
64
|
+
@record_without_app_validation = RSpecModelWriterTestWithoutValidation.create(
|
65
|
+
:id => 'two',
|
66
|
+
:code => 'unique - but only far as the db is concerned',
|
67
|
+
:random_field => 'sudo random value'
|
68
|
+
)
|
69
|
+
|
70
|
+
@interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
|
71
|
+
@interaction.context = Hoodoo::Services::Context.new(
|
72
|
+
Hoodoo::Services::Session.new,
|
73
|
+
@interaction.context.request,
|
74
|
+
@interaction.context.response,
|
75
|
+
@interaction
|
76
|
+
)
|
77
|
+
|
78
|
+
@context = @interaction.context
|
79
|
+
@session = @interaction.context.session
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'saves valid records' do
|
83
|
+
def expect_no_error( record )
|
84
|
+
expect( record.persisted? ).to eq( true )
|
85
|
+
@context.response.add_errors( record.platform_errors )
|
86
|
+
expect( @context.response.halt_processing? ).to eq( false )
|
87
|
+
end
|
88
|
+
|
89
|
+
shared_examples 'a persist_in-able model' do | klass |
|
90
|
+
it 'via class method' do
|
91
|
+
expect(
|
92
|
+
record = klass.persist_in( @context, unique_attributes() )
|
93
|
+
).to be_a( klass )
|
94
|
+
|
95
|
+
expect_no_error( record )
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'via instance method' do
|
99
|
+
record = klass.new( unique_attributes() )
|
100
|
+
result = record.persist_in( @context )
|
101
|
+
expect( result ).to eq( :success )
|
102
|
+
expect_no_error( record )
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'with AR validations present' do
|
107
|
+
it_behaves_like 'a persist_in-able model', RSpecModelWriterTestWithValidation
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with AR validations missing' do
|
111
|
+
it_behaves_like 'a persist_in-able model', RSpecModelWriterTestWithoutValidation
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'adds correct errors for invalid records' do
|
116
|
+
def expect_correct_error( record, reference )
|
117
|
+
expect( record.persisted? ).to eq( false )
|
118
|
+
@context.response.add_errors( record.platform_errors )
|
119
|
+
expect( @context.response.errors.errors[ 0 ] ).to eq(
|
120
|
+
{
|
121
|
+
'code' => 'generic.invalid_duplication',
|
122
|
+
'message' => 'has already been taken',
|
123
|
+
'reference' => reference
|
124
|
+
}
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
shared_examples 'an errant model' do | klass, error_reference |
|
129
|
+
it 'via class method' do
|
130
|
+
expect(
|
131
|
+
record = klass.persist_in( @context, record_to_copy().attributes() )
|
132
|
+
).to be_a( klass )
|
133
|
+
|
134
|
+
expect_correct_error( record, error_reference )
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'via instance method' do
|
138
|
+
record = klass.new( record_to_copy().attributes() )
|
139
|
+
result = record.persist_in( @context )
|
140
|
+
expect( result ).to eq( :failure )
|
141
|
+
expect_correct_error( record, error_reference )
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'with AR validations present' do
|
146
|
+
|
147
|
+
# Needed due to RSpec / scoping quirks; can't pass an instance variable
|
148
|
+
# to a shared example as a parameter; ends up 'nil' inside the example.
|
149
|
+
#
|
150
|
+
let( :record_to_copy ) { @record_with_app_validation }
|
151
|
+
|
152
|
+
it_behaves_like 'an errant model',
|
153
|
+
RSpecModelWriterTestWithValidation,
|
154
|
+
'code' # This being the name of a known duplication-violating field
|
155
|
+
end
|
156
|
+
|
157
|
+
context 'with AR validations missing' do
|
158
|
+
let( :record_to_copy ) { @record_without_app_validation }
|
159
|
+
it_behaves_like 'an errant model',
|
160
|
+
RSpecModelWriterTestWithoutValidation,
|
161
|
+
'model instance' # This being the default name for an unknown duplication-violation cause
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# This tries to check that, despite the nested transaction and rollback
|
166
|
+
# behaviour inside #persist_in, deep internal exceptions still propagate
|
167
|
+
# out correctly. It assumes database rollbacks happened OK (that's up to
|
168
|
+
# AR and the DB driver) and just makes sure the exception gets out.
|
169
|
+
#
|
170
|
+
context 'when internal exceptions occur' do
|
171
|
+
it 'reports them correctly' do
|
172
|
+
record = RSpecModelWriterTestWithValidation.new( @record_with_app_validation.attributes() )
|
173
|
+
|
174
|
+
# This is a method called deep inside ActiveRecord in its Transactions
|
175
|
+
# mixin. It is private, so this test is fragile.
|
176
|
+
|
177
|
+
expect( record ).to receive( :add_to_transaction ).and_raise( 'boo!' )
|
178
|
+
expect { result = record.persist_in( @context ) }.to raise_error( RuntimeError, 'boo!' )
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Prove that we handle the classic ActiveRecord validation of:
|
183
|
+
#
|
184
|
+
# Thread 1 Thread 2
|
185
|
+
# Check for dup? --
|
186
|
+
# No dupe Check for dup?
|
187
|
+
# => Save record No dupe
|
188
|
+
# OK => Save record
|
189
|
+
# Fails
|
190
|
+
#
|
191
|
+
# Two handler threads are set up to run through this scenario and each
|
192
|
+
# uses a Ruby Queue to talk to the other when it needs to pause and wait
|
193
|
+
# for the other thread to advance, in order to ensure the articial race
|
194
|
+
# condition is provoked every time without reliance on dubious 'sleep's.
|
195
|
+
#
|
196
|
+
context 'with race conditions' do
|
197
|
+
shared_examples 'a robust model' do | use_transaction |
|
198
|
+
it 'and handles duplicates correctly' do
|
199
|
+
attrs = unique_attributes()
|
200
|
+
|
201
|
+
record_1 = RSpecModelWriterTestWithValidation.new( attrs )
|
202
|
+
record_2 = RSpecModelWriterTestWithValidation.new( attrs )
|
203
|
+
|
204
|
+
queue_1 = Queue.new
|
205
|
+
queue_2 = Queue.new
|
206
|
+
|
207
|
+
thread_1 = Thread.new do
|
208
|
+
queue_1.pop() # Wait until thread 2 gets going
|
209
|
+
|
210
|
+
expect( record_1 ).to receive( :perform_validations ).once do
|
211
|
+
queue_2 << :go # Tell thread 2 to run validations
|
212
|
+
queue_1.pop() # Wait for thread 2 to run validations
|
213
|
+
true # Indicate successful validation, let save happen
|
214
|
+
end
|
215
|
+
|
216
|
+
result = if use_transaction
|
217
|
+
record_1.transaction do
|
218
|
+
record_1.persist_in( @context )
|
219
|
+
end
|
220
|
+
else
|
221
|
+
record_1.persist_in( @context )
|
222
|
+
end
|
223
|
+
|
224
|
+
expect( result ).to eq( :success )
|
225
|
+
|
226
|
+
queue_2 << :go # Tell thread 2 to save
|
227
|
+
end
|
228
|
+
|
229
|
+
thread_2 = Thread.new do
|
230
|
+
queue_1 << :go
|
231
|
+
queue_2.pop() # Wait for thread 1 to run validations, then tell us to go
|
232
|
+
|
233
|
+
expect( record_2 ).to receive( :perform_validations ).once do
|
234
|
+
queue_1 << :go # Now tell thread 1 to save
|
235
|
+
queue_2.pop() # Wait for thread 2 to do the same as the above
|
236
|
+
true # Indicate successful validation, let save happen
|
237
|
+
end
|
238
|
+
|
239
|
+
# Since the validation above will succeed but then try to save and that
|
240
|
+
# will fail, we expect the Writer module to re-query "valid?" and in the
|
241
|
+
# end to return ":failure".
|
242
|
+
|
243
|
+
expect( record_2 ).to receive( :valid? ).once.and_call_original
|
244
|
+
|
245
|
+
result = if use_transaction
|
246
|
+
record_2.transaction do
|
247
|
+
record_2.persist_in( @context )
|
248
|
+
end
|
249
|
+
else
|
250
|
+
record_2.persist_in( @context )
|
251
|
+
end
|
252
|
+
|
253
|
+
expect( result ).to eq( :failure )
|
254
|
+
end
|
255
|
+
|
256
|
+
thread_1.join()
|
257
|
+
thread_2.join()
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
context 'and no outer transaction' do
|
262
|
+
it_behaves_like 'a robust model', false
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'and an outer transaction' do
|
266
|
+
it_behaves_like 'a robust model', true
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|