activerecord_authorails 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3043 -0
- data/README +360 -0
- data/RUNNING_UNIT_TESTS +64 -0
- data/Rakefile +226 -0
- data/examples/associations.png +0 -0
- data/examples/associations.rb +87 -0
- data/examples/shared_setup.rb +15 -0
- data/examples/validation.rb +85 -0
- data/install.rb +30 -0
- data/lib/active_record.rb +85 -0
- data/lib/active_record/acts/list.rb +244 -0
- data/lib/active_record/acts/nested_set.rb +211 -0
- data/lib/active_record/acts/tree.rb +89 -0
- data/lib/active_record/aggregations.rb +191 -0
- data/lib/active_record/associations.rb +1637 -0
- data/lib/active_record/associations/association_collection.rb +190 -0
- data/lib/active_record/associations/association_proxy.rb +158 -0
- data/lib/active_record/associations/belongs_to_association.rb +56 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +169 -0
- data/lib/active_record/associations/has_many_association.rb +210 -0
- data/lib/active_record/associations/has_many_through_association.rb +247 -0
- data/lib/active_record/associations/has_one_association.rb +80 -0
- data/lib/active_record/attribute_methods.rb +75 -0
- data/lib/active_record/base.rb +2164 -0
- data/lib/active_record/calculations.rb +270 -0
- data/lib/active_record/callbacks.rb +367 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +279 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +58 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +343 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +310 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +161 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +228 -0
- data/lib/active_record/connection_adapters/firebird_adapter.rb +728 -0
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +414 -0
- data/lib/active_record/connection_adapters/openbase_adapter.rb +350 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +689 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +584 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +407 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +591 -0
- data/lib/active_record/connection_adapters/sybase_adapter.rb +662 -0
- data/lib/active_record/deprecated_associations.rb +104 -0
- data/lib/active_record/deprecated_finders.rb +44 -0
- data/lib/active_record/fixtures.rb +628 -0
- data/lib/active_record/locking/optimistic.rb +106 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +394 -0
- data/lib/active_record/observer.rb +178 -0
- data/lib/active_record/query_cache.rb +64 -0
- data/lib/active_record/reflection.rb +222 -0
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +149 -0
- data/lib/active_record/timestamp.rb +51 -0
- data/lib/active_record/transactions.rb +136 -0
- data/lib/active_record/validations.rb +843 -0
- data/lib/active_record/vendor/db2.rb +362 -0
- data/lib/active_record/vendor/mysql.rb +1214 -0
- data/lib/active_record/vendor/simple.rb +693 -0
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record/wrappers/yaml_wrapper.rb +15 -0
- data/lib/active_record/wrappings.rb +58 -0
- data/lib/active_record/xml_serialization.rb +308 -0
- data/test/aaa_create_tables_test.rb +59 -0
- data/test/abstract_unit.rb +77 -0
- data/test/active_schema_test_mysql.rb +31 -0
- data/test/adapter_test.rb +87 -0
- data/test/adapter_test_sqlserver.rb +81 -0
- data/test/aggregations_test.rb +95 -0
- data/test/all.sh +8 -0
- data/test/ar_schema_test.rb +33 -0
- data/test/association_inheritance_reload.rb +14 -0
- data/test/associations/callbacks_test.rb +126 -0
- data/test/associations/cascaded_eager_loading_test.rb +138 -0
- data/test/associations/eager_test.rb +393 -0
- data/test/associations/extension_test.rb +42 -0
- data/test/associations/join_model_test.rb +497 -0
- data/test/associations_test.rb +1809 -0
- data/test/attribute_methods_test.rb +49 -0
- data/test/base_test.rb +1586 -0
- data/test/binary_test.rb +37 -0
- data/test/calculations_test.rb +219 -0
- data/test/callbacks_test.rb +377 -0
- data/test/class_inheritable_attributes_test.rb +32 -0
- data/test/column_alias_test.rb +17 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +24 -0
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +23 -0
- data/test/connections/native_sqlite/connection.rb +34 -0
- data/test/connections/native_sqlite3/connection.rb +34 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sqlserver/connection.rb +23 -0
- data/test/connections/native_sqlserver_odbc/connection.rb +25 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/copy_table_sqlite.rb +64 -0
- data/test/datatype_test_postgresql.rb +52 -0
- data/test/default_test_firebird.rb +16 -0
- data/test/defaults_test.rb +60 -0
- data/test/deprecated_associations_test.rb +396 -0
- data/test/deprecated_finder_test.rb +151 -0
- data/test/empty_date_time_test.rb +25 -0
- data/test/finder_test.rb +504 -0
- data/test/fixtures/accounts.yml +28 -0
- data/test/fixtures/author.rb +99 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +7 -0
- data/test/fixtures/auto_id.rb +4 -0
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
- data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
- data/test/fixtures/bad_fixtures/blank_line +3 -0
- data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
- data/test/fixtures/bad_fixtures/missing_value +1 -0
- data/test/fixtures/binary.rb +2 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/category.rb +20 -0
- data/test/fixtures/column_name.rb +3 -0
- data/test/fixtures/comment.rb +23 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +55 -0
- data/test/fixtures/company.rb +107 -0
- data/test/fixtures/company_in_module.rb +59 -0
- data/test/fixtures/computer.rb +3 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/course.rb +3 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customer.rb +55 -0
- data/test/fixtures/customers.yml +17 -0
- data/test/fixtures/db_definitions/db2.drop.sql +32 -0
- data/test/fixtures/db_definitions/db2.sql +231 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +63 -0
- data/test/fixtures/db_definitions/firebird.sql +304 -0
- data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
- data/test/fixtures/db_definitions/firebird2.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +32 -0
- data/test/fixtures/db_definitions/frontbase.sql +268 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +32 -0
- data/test/fixtures/db_definitions/mysql.sql +234 -0
- data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql2.sql +5 -0
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +302 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/oracle.drop.sql +65 -0
- data/test/fixtures/db_definitions/oracle.sql +325 -0
- data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +37 -0
- data/test/fixtures/db_definitions/postgresql.sql +263 -0
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +5 -0
- data/test/fixtures/db_definitions/schema.rb +60 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +32 -0
- data/test/fixtures/db_definitions/sqlite.sql +215 -0
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +5 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +34 -0
- data/test/fixtures/db_definitions/sqlserver.sql +243 -0
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver2.sql +5 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +34 -0
- data/test/fixtures/db_definitions/sybase.sql +218 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/default.rb +2 -0
- data/test/fixtures/developer.rb +52 -0
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/developers_projects/david_action_controller +3 -0
- data/test/fixtures/developers_projects/david_active_record +3 -0
- data/test/fixtures/developers_projects/jamis_active_record +2 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrant.rb +3 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/joke.rb +6 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
- data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/mixed_case_monkey.rb +3 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixin.rb +63 -0
- data/test/fixtures/mixins.yml +127 -0
- data/test/fixtures/movie.rb +5 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/people.yml +3 -0
- data/test/fixtures/person.rb +4 -0
- data/test/fixtures/post.rb +58 -0
- data/test/fixtures/posts.yml +48 -0
- data/test/fixtures/project.rb +27 -0
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +37 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +6 -0
- data/test/fixtures/subscribers/first +2 -0
- data/test/fixtures/subscribers/second +2 -0
- data/test/fixtures/tag.rb +7 -0
- data/test/fixtures/tagging.rb +6 -0
- data/test/fixtures/taggings.yml +18 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/task.rb +3 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topic.rb +25 -0
- data/test/fixtures/topics.yml +22 -0
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +401 -0
- data/test/inheritance_test.rb +205 -0
- data/test/lifecycle_test.rb +137 -0
- data/test/locking_test.rb +190 -0
- data/test/method_scoping_test.rb +416 -0
- data/test/migration_test.rb +768 -0
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_nested_set_test.rb +196 -0
- data/test/mixin_test.rb +550 -0
- data/test/modules_test.rb +34 -0
- data/test/multiple_db_test.rb +60 -0
- data/test/pk_test.rb +104 -0
- data/test/readonly_test.rb +107 -0
- data/test/reflection_test.rb +159 -0
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +96 -0
- data/test/schema_test_postgresql.rb +64 -0
- data/test/synonym_test_oracle.rb +17 -0
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +48 -0
- data/test/transactions_test.rb +230 -0
- data/test/unconnected_test.rb +32 -0
- data/test/validations_test.rb +1097 -0
- data/test/xml_serialization_test.rb +125 -0
- metadata +365 -0
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/company'
|
3
|
+
require 'fixtures/project'
|
4
|
+
require 'fixtures/subscriber'
|
5
|
+
|
6
|
+
class InheritanceTest < Test::Unit::TestCase
|
7
|
+
fixtures :companies, :projects, :subscribers, :accounts
|
8
|
+
|
9
|
+
def test_a_bad_type_column
|
10
|
+
#SQLServer need to turn Identity Insert On before manually inserting into the Identity column
|
11
|
+
if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
12
|
+
Company.connection.execute "SET IDENTITY_INSERT companies ON"
|
13
|
+
end
|
14
|
+
Company.connection.insert "INSERT INTO companies (id, #{QUOTED_TYPE}, name) VALUES(100, 'bad_class!', 'Not happening')"
|
15
|
+
|
16
|
+
#We then need to turn it back Off before continuing.
|
17
|
+
if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
18
|
+
Company.connection.execute "SET IDENTITY_INSERT companies OFF"
|
19
|
+
end
|
20
|
+
assert_raises(ActiveRecord::SubclassNotFound) { Company.find(100) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_inheritance_find
|
24
|
+
assert Company.find(1).kind_of?(Firm), "37signals should be a firm"
|
25
|
+
assert Firm.find(1).kind_of?(Firm), "37signals should be a firm"
|
26
|
+
assert Company.find(2).kind_of?(Client), "Summit should be a client"
|
27
|
+
assert Client.find(2).kind_of?(Client), "Summit should be a client"
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_alt_inheritance_find
|
31
|
+
switch_to_alt_inheritance_column
|
32
|
+
test_inheritance_find
|
33
|
+
switch_to_default_inheritance_column
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_inheritance_find_all
|
37
|
+
companies = Company.find(:all, :order => 'id')
|
38
|
+
assert companies[0].kind_of?(Firm), "37signals should be a firm"
|
39
|
+
assert companies[1].kind_of?(Client), "Summit should be a client"
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_alt_inheritance_find_all
|
43
|
+
switch_to_alt_inheritance_column
|
44
|
+
test_inheritance_find_all
|
45
|
+
switch_to_default_inheritance_column
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_inheritance_save
|
49
|
+
firm = Firm.new
|
50
|
+
firm.name = "Next Angle"
|
51
|
+
firm.save
|
52
|
+
|
53
|
+
next_angle = Company.find(firm.id)
|
54
|
+
assert next_angle.kind_of?(Firm), "Next Angle should be a firm"
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_alt_inheritance_save
|
58
|
+
switch_to_alt_inheritance_column
|
59
|
+
test_inheritance_save
|
60
|
+
switch_to_default_inheritance_column
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_inheritance_condition
|
64
|
+
assert_equal 9, Company.count
|
65
|
+
assert_equal 2, Firm.count
|
66
|
+
assert_equal 3, Client.count
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_alt_inheritance_condition
|
70
|
+
switch_to_alt_inheritance_column
|
71
|
+
test_inheritance_condition
|
72
|
+
switch_to_default_inheritance_column
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_finding_incorrect_type_data
|
76
|
+
assert_raises(ActiveRecord::RecordNotFound) { Firm.find(2) }
|
77
|
+
assert_nothing_raised { Firm.find(1) }
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_alt_finding_incorrect_type_data
|
81
|
+
switch_to_alt_inheritance_column
|
82
|
+
test_finding_incorrect_type_data
|
83
|
+
switch_to_default_inheritance_column
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_update_all_within_inheritance
|
87
|
+
Client.update_all "name = 'I am a client'"
|
88
|
+
assert_equal "I am a client", Client.find(:all).first.name
|
89
|
+
assert_equal "37signals", Firm.find(:all).first.name
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_alt_update_all_within_inheritance
|
93
|
+
switch_to_alt_inheritance_column
|
94
|
+
test_update_all_within_inheritance
|
95
|
+
switch_to_default_inheritance_column
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_destroy_all_within_inheritance
|
99
|
+
Client.destroy_all
|
100
|
+
assert_equal 0, Client.count
|
101
|
+
assert_equal 2, Firm.count
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_alt_destroy_all_within_inheritance
|
105
|
+
switch_to_alt_inheritance_column
|
106
|
+
test_destroy_all_within_inheritance
|
107
|
+
switch_to_default_inheritance_column
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_find_first_within_inheritance
|
111
|
+
assert_kind_of Firm, Company.find(:first, :conditions => "name = '37signals'")
|
112
|
+
assert_kind_of Firm, Firm.find(:first, :conditions => "name = '37signals'")
|
113
|
+
assert_nil Client.find(:first, :conditions => "name = '37signals'")
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_alt_find_first_within_inheritance
|
117
|
+
switch_to_alt_inheritance_column
|
118
|
+
test_find_first_within_inheritance
|
119
|
+
switch_to_default_inheritance_column
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_complex_inheritance
|
123
|
+
very_special_client = VerySpecialClient.create("name" => "veryspecial")
|
124
|
+
assert_equal very_special_client, VerySpecialClient.find(:first, :conditions => "name = 'veryspecial'")
|
125
|
+
assert_equal very_special_client, SpecialClient.find(:first, :conditions => "name = 'veryspecial'")
|
126
|
+
assert_equal very_special_client, Company.find(:first, :conditions => "name = 'veryspecial'")
|
127
|
+
assert_equal very_special_client, Client.find(:first, :conditions => "name = 'veryspecial'")
|
128
|
+
assert_equal 1, Client.find(:all, :conditions => "name = 'Summit'").size
|
129
|
+
assert_equal very_special_client, Client.find(very_special_client.id)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_alt_complex_inheritance
|
133
|
+
switch_to_alt_inheritance_column
|
134
|
+
test_complex_inheritance
|
135
|
+
switch_to_default_inheritance_column
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_eager_load_belongs_to_something_inherited
|
139
|
+
account = Account.find(1, :include => :firm)
|
140
|
+
assert_not_nil account.instance_variable_get("@firm"), "nil proves eager load failed"
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_alt_eager_loading
|
144
|
+
switch_to_alt_inheritance_column
|
145
|
+
test_eager_load_belongs_to_something_inherited
|
146
|
+
switch_to_default_inheritance_column
|
147
|
+
ActiveRecord::Base.logger.debug "cocksucker"
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_inheritance_without_mapping
|
151
|
+
assert_kind_of SpecialSubscriber, SpecialSubscriber.find("webster132")
|
152
|
+
assert_nothing_raised { s = SpecialSubscriber.new("name" => "And breaaaaathe!"); s.id = 'roger'; s.save }
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
def switch_to_alt_inheritance_column
|
157
|
+
# we don't want misleading test results, so get rid of the values in the type column
|
158
|
+
Company.find(:all, :order => 'id').each do |c|
|
159
|
+
c['type'] = nil
|
160
|
+
c.save
|
161
|
+
end
|
162
|
+
[ Company, Firm, Client].each { |klass| klass.reset_column_information }
|
163
|
+
Company.set_inheritance_column('ruby_type')
|
164
|
+
end
|
165
|
+
def switch_to_default_inheritance_column
|
166
|
+
[ Company, Firm, Client].each { |klass| klass.reset_column_information }
|
167
|
+
Company.set_inheritance_column('type')
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
class InheritanceComputeTypeTest < Test::Unit::TestCase
|
173
|
+
fixtures :companies
|
174
|
+
|
175
|
+
def setup
|
176
|
+
Dependencies.log_activity = true
|
177
|
+
end
|
178
|
+
|
179
|
+
def teardown
|
180
|
+
Dependencies.log_activity = false
|
181
|
+
self.class.const_remove :FirmOnTheFly rescue nil
|
182
|
+
Firm.const_remove :FirmOnTheFly rescue nil
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_instantiation_doesnt_try_to_require_corresponding_file
|
186
|
+
foo = Firm.find(:first).clone
|
187
|
+
foo.ruby_type = foo.type = 'FirmOnTheFly'
|
188
|
+
foo.save!
|
189
|
+
|
190
|
+
# Should fail without FirmOnTheFly in the type condition.
|
191
|
+
assert_raise(ActiveRecord::RecordNotFound) { Firm.find(foo.id) }
|
192
|
+
|
193
|
+
# Nest FirmOnTheFly in the test case where Dependencies won't see it.
|
194
|
+
self.class.const_set :FirmOnTheFly, Class.new(Firm)
|
195
|
+
assert_raise(ActiveRecord::SubclassNotFound) { Firm.find(foo.id) }
|
196
|
+
|
197
|
+
# Nest FirmOnTheFly in Firm where Dependencies will see it.
|
198
|
+
# This is analogous to nesting models in a migration.
|
199
|
+
Firm.const_set :FirmOnTheFly, Class.new(Firm)
|
200
|
+
|
201
|
+
# And instantiate will find the existing constant rather than trying
|
202
|
+
# to require firm_on_the_fly.
|
203
|
+
assert_nothing_raised { assert_kind_of Firm::FirmOnTheFly, Firm.find(foo.id) }
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/topic'
|
3
|
+
require 'fixtures/developer'
|
4
|
+
require 'fixtures/reply'
|
5
|
+
|
6
|
+
class Topic; def after_find() end end
|
7
|
+
class Developer; def after_find() end end
|
8
|
+
class SpecialDeveloper < Developer; end
|
9
|
+
|
10
|
+
class TopicManualObserver
|
11
|
+
include Singleton
|
12
|
+
|
13
|
+
attr_reader :action, :object, :callbacks
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
Topic.add_observer(self)
|
17
|
+
@callbacks = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def update(callback_method, object)
|
21
|
+
@callbacks << { "callback_method" => callback_method, "object" => object }
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_been_notified?
|
25
|
+
!@callbacks.empty?
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class TopicaObserver < ActiveRecord::Observer
|
30
|
+
def self.observed_class() Topic end
|
31
|
+
|
32
|
+
attr_reader :topic
|
33
|
+
|
34
|
+
def after_find(topic)
|
35
|
+
@topic = topic
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class TopicObserver < ActiveRecord::Observer
|
40
|
+
attr_reader :topic
|
41
|
+
|
42
|
+
def after_find(topic)
|
43
|
+
@topic = topic
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class MultiObserver < ActiveRecord::Observer
|
48
|
+
attr_reader :record
|
49
|
+
|
50
|
+
def self.observed_class() [ Topic, Developer ] end
|
51
|
+
|
52
|
+
cattr_reader :last_inherited
|
53
|
+
@@last_inherited = nil
|
54
|
+
|
55
|
+
def observed_class_inherited_with_testing(subclass)
|
56
|
+
observed_class_inherited_without_testing(subclass)
|
57
|
+
@@last_inherited = subclass
|
58
|
+
end
|
59
|
+
|
60
|
+
alias_method_chain :observed_class_inherited, :testing
|
61
|
+
|
62
|
+
def after_find(record)
|
63
|
+
@record = record
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class LifecycleTest < Test::Unit::TestCase
|
68
|
+
fixtures :topics, :developers
|
69
|
+
|
70
|
+
def test_before_destroy
|
71
|
+
assert_equal 2, Topic.count
|
72
|
+
Topic.find(1).destroy
|
73
|
+
assert_equal 0, Topic.count
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_after_save
|
77
|
+
ActiveRecord::Base.observers = :topic_manual_observer
|
78
|
+
ActiveRecord::Base.instantiate_observers
|
79
|
+
|
80
|
+
topic = Topic.find(1)
|
81
|
+
topic.title = "hello"
|
82
|
+
topic.save
|
83
|
+
|
84
|
+
assert TopicManualObserver.instance.has_been_notified?
|
85
|
+
assert_equal :after_save, TopicManualObserver.instance.callbacks.last["callback_method"]
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_observer_update_on_save
|
89
|
+
ActiveRecord::Base.observers = TopicManualObserver
|
90
|
+
ActiveRecord::Base.instantiate_observers
|
91
|
+
|
92
|
+
topic = Topic.find(1)
|
93
|
+
assert TopicManualObserver.instance.has_been_notified?
|
94
|
+
assert_equal :after_find, TopicManualObserver.instance.callbacks.first["callback_method"]
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_auto_observer
|
98
|
+
topic_observer = TopicaObserver.instance
|
99
|
+
|
100
|
+
topic = Topic.find(1)
|
101
|
+
assert_equal topic.title, topic_observer.topic.title
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_inferred_auto_observer
|
105
|
+
topic_observer = TopicObserver.instance
|
106
|
+
|
107
|
+
topic = Topic.find(1)
|
108
|
+
assert_equal topic.title, topic_observer.topic.title
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_observing_two_classes
|
112
|
+
multi_observer = MultiObserver.instance
|
113
|
+
|
114
|
+
topic = Topic.find(1)
|
115
|
+
assert_equal topic.title, multi_observer.record.title
|
116
|
+
|
117
|
+
developer = Developer.find(1)
|
118
|
+
assert_equal developer.name, multi_observer.record.name
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_observing_subclasses
|
122
|
+
multi_observer = MultiObserver.instance
|
123
|
+
|
124
|
+
developer = SpecialDeveloper.find(1)
|
125
|
+
assert_equal developer.name, multi_observer.record.name
|
126
|
+
|
127
|
+
klass = Class.new(Developer)
|
128
|
+
assert_equal klass, multi_observer.last_inherited
|
129
|
+
|
130
|
+
developer = klass.find(1)
|
131
|
+
assert_equal developer.name, multi_observer.record.name
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_invalid_observer
|
135
|
+
assert_raise(ArgumentError) { Topic.observers = Object.new; Topic.instantiate_observers }
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/person'
|
3
|
+
require 'fixtures/legacy_thing'
|
4
|
+
|
5
|
+
class LockWithoutDefault < ActiveRecord::Base; end
|
6
|
+
|
7
|
+
class LockWithCustomColumnWithoutDefault < ActiveRecord::Base
|
8
|
+
set_table_name :lock_without_defaults_cust
|
9
|
+
set_locking_column :custom_lock_version
|
10
|
+
end
|
11
|
+
|
12
|
+
class OptimisticLockingTest < Test::Unit::TestCase
|
13
|
+
fixtures :people, :legacy_things
|
14
|
+
|
15
|
+
def test_lock_existing
|
16
|
+
p1 = Person.find(1)
|
17
|
+
p2 = Person.find(1)
|
18
|
+
assert_equal 0, p1.lock_version
|
19
|
+
assert_equal 0, p2.lock_version
|
20
|
+
|
21
|
+
p1.save!
|
22
|
+
assert_equal 1, p1.lock_version
|
23
|
+
assert_equal 0, p2.lock_version
|
24
|
+
|
25
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_lock_new
|
29
|
+
p1 = Person.new(:first_name => 'anika')
|
30
|
+
assert_equal 0, p1.lock_version
|
31
|
+
|
32
|
+
p1.save!
|
33
|
+
p2 = Person.find(p1.id)
|
34
|
+
assert_equal 0, p1.lock_version
|
35
|
+
assert_equal 0, p2.lock_version
|
36
|
+
|
37
|
+
p1.save!
|
38
|
+
assert_equal 1, p1.lock_version
|
39
|
+
assert_equal 0, p2.lock_version
|
40
|
+
|
41
|
+
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_lock_column_name_existing
|
45
|
+
t1 = LegacyThing.find(1)
|
46
|
+
t2 = LegacyThing.find(1)
|
47
|
+
assert_equal 0, t1.version
|
48
|
+
assert_equal 0, t2.version
|
49
|
+
|
50
|
+
t1.save!
|
51
|
+
assert_equal 1, t1.version
|
52
|
+
assert_equal 0, t2.version
|
53
|
+
|
54
|
+
assert_raises(ActiveRecord::StaleObjectError) { t2.save! }
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_lock_column_is_mass_assignable
|
58
|
+
p1 = Person.create(:first_name => 'bianca')
|
59
|
+
assert_equal 0, p1.lock_version
|
60
|
+
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
61
|
+
|
62
|
+
p1.save!
|
63
|
+
assert_equal 1, p1.lock_version
|
64
|
+
assert_equal p1.lock_version, Person.new(p1.attributes).lock_version
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_lock_without_default_sets_version_to_zero
|
68
|
+
t1 = LockWithoutDefault.new
|
69
|
+
assert_equal 0, t1.lock_version
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_lock_with_custom_column_without_default_sets_version_to_zero
|
73
|
+
t1 = LockWithCustomColumnWithoutDefault.new
|
74
|
+
assert_equal 0, t1.custom_lock_version
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# TODO: test against the generated SQL since testing locking behavior itself
|
80
|
+
# is so cumbersome. Will deadlock Ruby threads if the underlying db.execute
|
81
|
+
# blocks, so separate script called by Kernel#system is needed.
|
82
|
+
# (See exec vs. async_exec in the PostgreSQL adapter.)
|
83
|
+
|
84
|
+
# TODO: The SQL Server and Sybase adapters currently have no support for pessimistic locking
|
85
|
+
|
86
|
+
unless current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
87
|
+
class PessimisticLockingTest < Test::Unit::TestCase
|
88
|
+
self.use_transactional_fixtures = false
|
89
|
+
fixtures :people, :readers
|
90
|
+
|
91
|
+
def setup
|
92
|
+
# Avoid introspection queries during tests.
|
93
|
+
Person.columns; Reader.columns
|
94
|
+
|
95
|
+
@allow_concurrency = ActiveRecord::Base.allow_concurrency
|
96
|
+
ActiveRecord::Base.allow_concurrency = true
|
97
|
+
end
|
98
|
+
|
99
|
+
def teardown
|
100
|
+
ActiveRecord::Base.allow_concurrency = @allow_concurrency
|
101
|
+
end
|
102
|
+
|
103
|
+
# Test typical find.
|
104
|
+
def test_sane_find_with_lock
|
105
|
+
assert_nothing_raised do
|
106
|
+
Person.transaction do
|
107
|
+
Person.find 1, :lock => true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Test scoped lock.
|
113
|
+
def test_sane_find_with_scoped_lock
|
114
|
+
assert_nothing_raised do
|
115
|
+
Person.transaction do
|
116
|
+
Person.with_scope(:find => { :lock => true }) do
|
117
|
+
Person.find 1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# PostgreSQL protests SELECT ... FOR UPDATE on an outer join.
|
124
|
+
unless current_adapter?(:PostgreSQLAdapter)
|
125
|
+
# Test locked eager find.
|
126
|
+
def test_eager_find_with_lock
|
127
|
+
assert_nothing_raised do
|
128
|
+
Person.transaction do
|
129
|
+
Person.find 1, :include => :readers, :lock => true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Locking a record reloads it.
|
136
|
+
def test_sane_lock_method
|
137
|
+
assert_nothing_raised do
|
138
|
+
Person.transaction do
|
139
|
+
person = Person.find 1
|
140
|
+
old, person.first_name = person.first_name, 'fooman'
|
141
|
+
person.lock!
|
142
|
+
assert_equal old, person.first_name
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
|
148
|
+
def test_no_locks_no_wait
|
149
|
+
first, second = duel { Person.find 1 }
|
150
|
+
assert first.end > second.end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_second_lock_waits
|
154
|
+
assert [0.2, 1, 5].any? { |zzz|
|
155
|
+
first, second = duel(zzz) { Person.find 1, :lock => true }
|
156
|
+
second.end > first.end
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
protected
|
161
|
+
def duel(zzz = 5)
|
162
|
+
t0, t1, t2, t3 = nil, nil, nil, nil
|
163
|
+
|
164
|
+
a = Thread.new do
|
165
|
+
t0 = Time.now
|
166
|
+
Person.transaction do
|
167
|
+
yield
|
168
|
+
sleep zzz # block thread 2 for zzz seconds
|
169
|
+
end
|
170
|
+
t1 = Time.now
|
171
|
+
end
|
172
|
+
|
173
|
+
b = Thread.new do
|
174
|
+
sleep zzz / 2.0 # ensure thread 1 tx starts first
|
175
|
+
t2 = Time.now
|
176
|
+
Person.transaction { yield }
|
177
|
+
t3 = Time.now
|
178
|
+
end
|
179
|
+
|
180
|
+
a.join
|
181
|
+
b.join
|
182
|
+
|
183
|
+
assert t1 > t0 + zzz
|
184
|
+
assert t2 > t0
|
185
|
+
assert t3 > t2
|
186
|
+
[t0.to_f..t1.to_f, t2.to_f..t3.to_f]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|